From f34208aaae8841f318e2e302b75f4c6ce514c869 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 24 Aug 2021 15:14:27 +0100 Subject: [PATCH 1/4] Quality of Life update for Holmes --- packages/holmes/config/index.js | 19 ++++++--- packages/holmes/src/{brim.js => bill.js} | 49 +++++++++++++++++------- packages/holmes/src/ear.js | 41 ++++++++++++++------ packages/holmes/src/gore.js | 23 +++++++---- packages/holmes/src/index.js | 4 +- 5 files changed, 95 insertions(+), 41 deletions(-) rename packages/holmes/src/{brim.js => bill.js} (53%) diff --git a/packages/holmes/config/index.js b/packages/holmes/config/index.js index 3fe30549f41..033f6bfa3eb 100644 --- a/packages/holmes/config/index.js +++ b/packages/holmes/config/index.js @@ -4,24 +4,31 @@ import { version } from '../package.json' export default { name: 'holmes', - version, + version: "2.17.5", design: 'Erica Alcusa Sáez', - code: 'Erica Alcusa Sáez', + code: 'Erica Alcusa Sáez, bobgeorgethe3rd', department: 'accessories', type: 'pattern', difficulty: 3, optionGroups: { - style: ['lengthRatio', 'goreNumber', 'brimAngle', 'brimWidth'], + fit: ['head_ease'], + style: ['lengthRatio', 'goreNumber', 'billAngle', 'billWidth','ear_length','ear_width','buttonhole'], + advanced:['bill_length'], }, measurements: ['head'], dependencies: {}, inject: {}, hide: [], - parts: ['gore', 'brim', 'ear'], + parts: ['gore', 'bill', 'ear'], options: { + head_ease: { mm: 19, min: 0, max: 50 }, lengthRatio: { pct: 55, min: 40, max: 60 }, goreNumber: { count: 6, min: 4, max: 20 }, - brimAngle: { deg: 45, min: 10, max: 90 }, - brimWidth: { mm: 30, min: 5, max: 100 }, + billAngle: { deg: 45, min: 10, max: 90 }, + billWidth: { mm: 30, min: 5, max: 100 }, + ear_length: { pct: 100, min: 80, max: 150 }, + ear_width: { pct: 100, min: 80, max: 150 }, + bill_length: { pct: 100, min: 80, max: 150 }, + buttonhole: {bool: false} }, } diff --git a/packages/holmes/src/brim.js b/packages/holmes/src/bill.js similarity index 53% rename from packages/holmes/src/brim.js rename to packages/holmes/src/bill.js index 52dcff0ccb1..2d0a2490ae8 100644 --- a/packages/holmes/src/brim.js +++ b/packages/holmes/src/bill.js @@ -12,30 +12,36 @@ export default function (part) { macro, } = part.shorthand() - let headRadius = measurements.head / 2 / Math.PI - let brimRadius = headRadius / Math.sin((options.brimAngle * Math.PI) / 180) - let sectorAngle = Math.PI / 3 - let brimSectorAngle = (sectorAngle * headRadius) / brimRadius + let headCircumference = measurements.head + options.head_ease + let headRadius = headCircumference / 2 / Math.PI + let billRadius = (headRadius / Math.sin((options.billAngle * Math.PI) / 180)) + let sectorAngle = (Math.PI / 3)*options.bill_length + let billSectorAngle = (sectorAngle * headRadius) / billRadius let cpDistance = - ((4 / 3) * brimRadius * (1 - Math.cos(brimSectorAngle / 2))) / Math.sin(brimSectorAngle / 2) + ((4 / 3) * billRadius * (1 - Math.cos(billSectorAngle / 2))) / Math.sin(billSectorAngle / 2) points.origin = new Point(0, 0) points.in1 = new Point(0, 0) points.in2 = points.in1.shift( - (90 / Math.PI) * brimSectorAngle, - 2 * brimRadius * Math.sin(brimSectorAngle / 2) + ((90 / Math.PI) * billSectorAngle), + 2 * billRadius * Math.sin(billSectorAngle / 2) ) + //test circle + //points.circleCentre = points.in1.shift(90,headRadius) + //.attr("data-circle",headRadius) + //points.circle60 = points.circleCentre.shift(-30,headRadius) + // points.in1C = points.in1.shift(0, cpDistance) - points.in2C = points.in2.shift(180 + (180 / Math.PI) * brimSectorAngle, cpDistance) + points.in2C = points.in2.shift(180 + (180 / Math.PI) * billSectorAngle, cpDistance) points.in1CFlipped = points.in1C.flipX() points.in2Flipped = points.in2.flipX() points.in2CFlipped = points.in2C.flipX() - points.ex1 = points.in1.shift(-90, options.brimWidth) + points.ex1 = points.in1.shift(-90, options.billWidth) points.ex1C = points.ex1.shift(0, 0.5 * points.in2.x) points.ex2C = points.in2.shift( -90, - (points.ex1.y - points.in2.y) * (2 / (1 + Math.exp(-options.brimWidth / 15)) - 1) + (points.ex1.y - points.in2.y) * (2 / (1 + Math.exp(-options.billWidth / 15)) - 1) ) points.ex1CFlipped = points.ex1C.flipX() points.ex2CFlipped = points.ex2C.flipX() @@ -47,16 +53,33 @@ export default function (part) { .curve(points.ex2C, points.ex1C, points.ex1) .curve(points.ex1CFlipped, points.ex2CFlipped, points.in2Flipped) .close() - // Complete? if (complete) { macro('grainline', { from: points.in1, to: points.ex1 }) - macro('title', { at: points.ex1.shift(45, 20), nr: 2, title: 'brim', scale: 0.4 }) + macro('title', { at: points.ex1.shift(45, 20), nr: 2, title: 'bill', scale: 0.4 }) if (sa) { - paths.sa = paths.seam.offset(sa * -1).attr('class', 'fabric sa') + paths.saInner = new Path () + .move(points.in2Flipped) + .curve(points.in2CFlipped, points.in1CFlipped, points.in1) + .curve(points.in1C, points.in2C, points.in2) + .offset(sa*-2) + .attr('class', 'fabric sa') + points.sa1 = new Point(points.in2Flipped.x-sa, paths.saInner.start().y) + points.sa2 = new Point(points.in2.x+sa, paths.saInner.start().y) + paths.sa = new Path() + .move(points.in2) + .curve(points.ex2C, points.ex1C, points.ex1) + .curve(points.ex1CFlipped, points.ex2CFlipped, points.in2Flipped) + .offset(sa*-1) + .line(points.sa1) + .join(paths .saInner) + .line(points.sa2) + .close() + .attr('class', 'fabric sa') } + // Paperless? if (paperless) { macro('hd', { diff --git a/packages/holmes/src/ear.js b/packages/holmes/src/ear.js index 0c771b56043..e74fb29bbc2 100644 --- a/packages/holmes/src/ear.js +++ b/packages/holmes/src/ear.js @@ -15,33 +15,43 @@ export default function (part) { } = part.shorthand() // Design pattern here - +let headCircumference = measurements.head + options.head_ease +let earFlapLength = ((options.lengthRatio * headCircumference) / 2)*options.ear_length +let earFlapWidth = (headCircumference / 12)*options.ear_width points.top = new Point(0, 0) - points.bottom = new Point(measurements.head / 12, (options.lengthRatio * measurements.head) / 2) + points.bottom = new Point(earFlapWidth, earFlapLength) points.topC = points.top.shift(0, points.bottom.x) points.bottomC = points.bottom.shift(90, points.bottom.y - points.bottom.x) points.topCFlipped = points.topC.flipX() points.bottomFlipped = points.bottom.flipX() points.bottomCFlipped = points.bottomC.flipX() - - paths.seam = new Path() - .move(points.top) + paths.seam = new Path() + .move(points.bottom) + .curve(points.bottomC, points.topC, points.top) .curve(points.topCFlipped, points.bottomCFlipped, points.bottomFlipped) - .line(points.bottom) - .curve(points.bottomC, points.topC, points.top) - .close() - + + paths.hem = new Path() + .move(points.bottomFlipped) + .line(points.bottom) + // Complete? if (complete) { macro('grainline', { from: points.top, to: new Point(0, points.bottom.y) }) points.logo = new Point(-0.5 * points.bottom.x, 0.75 * points.bottom.y) snippets.logo = new Snippet('logo', points.logo).attr('data-scale', 0.7) points.title = new Point(0.3 * points.bottom.x, 0.75 * points.bottom.y) - macro('title', { at: points.title, nr: 3, title: 'ear', scale: 0.5 }) + macro('title', { at: points.title, nr: 3, title: 'ear flap', scale: 0.5 }) macro('miniscale', { at: new Point(0, points.bottom.y * 0.3) }) - + if (options.buttonhole){ + let buttonholeDistance = (options.lengthRatio * headCircumference) / 2 + points.buttonhole = new Point (points.top.x, points.bottom.y - buttonholeDistance) + snippets.buttonhole = new Snippet('buttonhole-start', points.buttonhole).attr('data-scale', 2) + } if (sa) { - paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa') + paths.sa = paths.seam.offset(sa) + .join(paths.hem.offset(sa*2)) + .attr('class', 'fabric sa') + .close() } // Paperless? @@ -56,6 +66,13 @@ export default function (part) { to: points.top, x: points.bottomFlipped.x - 15 - sa, }) + if (options.buttonhole){ + macro('vd', { + from: points.bottom, + to: points.buttonhole, + x: points.bottom.x + 15 + sa, + }) + } } } return part diff --git a/packages/holmes/src/gore.js b/packages/holmes/src/gore.js index ce5592340aa..63eaed314db 100644 --- a/packages/holmes/src/gore.js +++ b/packages/holmes/src/gore.js @@ -15,7 +15,8 @@ export default function (part) { // Design pattern here //Radius of the head - let headRadius = measurements.head / 2 / Math.PI + let headCircumference = measurements.head + options.head_ease + let headRadius = headCircumference / 2 / Math.PI points.p0 = new Point(0, 0) @@ -23,7 +24,7 @@ export default function (part) { from: points.p0, radius: headRadius, goreNumber: options.goreNumber, - extraLength: ((options.lengthRatio - 0.5) * measurements.head) / 2, + extraLength: ((options.lengthRatio - 0.5) * headCircumference) / 2, prefix: 'gore_', render: true, }) @@ -31,7 +32,7 @@ export default function (part) { // Complete? if (complete) { points.title = new Point(points.gore_p1.x / 10, points.gore_p2.y / 1.8) - macro('title', { at: points.title, nr: 1, title: 'gore', scale: 0.5 }) + macro('title', { at: points.title, nr: 1, title: 'crown', scale: 0.5 }) macro('cutonfold', { from: points.p0, @@ -41,18 +42,24 @@ export default function (part) { }) if (sa) { - paths.saBase = new Path() + paths.saCurve = new Path() .move(points.gore_p1) .curve(points.gore_Cp1, points.gore_Cp2, points.gore_p2) - .line(points.gore_p3) - .line(points.p0) .offset(sa) .setRender(false) + points.sa1 = new Point(points.gore_p3.x - (sa*2), points.gore_p3.y - sa) + paths.saBase = new Path() + .move(points.gore_p3) + .line(points.p0) + .offset(sa*2) + .setRender(false) paths.sa = new Path() .move(points.gore_p1) .line(points.gore_p1.shift(0, sa)) - .line(paths.saBase.start()) - .join(paths.saBase) + .line(paths.saCurve.start()) + .join(paths.saCurve) + .line(points.sa1) + .join(paths.saBase) .line(points.p0) .attr('class', 'fabric sa') } diff --git a/packages/holmes/src/index.js b/packages/holmes/src/index.js index 398a186276d..ba0a136e411 100644 --- a/packages/holmes/src/index.js +++ b/packages/holmes/src/index.js @@ -4,7 +4,7 @@ import gorePlugin from '@freesewing/plugin-gore' import config from '../config' import draftGore from './gore' -import draftBrim from './brim' +import draftBill from './bill' import draftEar from './ear' // Create new design @@ -12,7 +12,7 @@ const Pattern = new freesewing.Design(config, [plugins, gorePlugin]) // Attach the draft methods to the prototype Pattern.prototype.draftGore = draftGore -Pattern.prototype.draftBrim = draftBrim +Pattern.prototype.draftBill = draftBill Pattern.prototype.draftEar = draftEar export default Pattern From a45e1a1db88a8b4f56e55b708146206a92e1ec01 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 24 Aug 2021 15:37:35 +0100 Subject: [PATCH 2/4] format and camelCase changes --- packages/holmes/config/index.js | 14 +++++++------- packages/holmes/src/bill.js | 2 +- packages/holmes/src/ear.js | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/holmes/config/index.js b/packages/holmes/config/index.js index 033f6bfa3eb..7174987fc1f 100644 --- a/packages/holmes/config/index.js +++ b/packages/holmes/config/index.js @@ -4,16 +4,16 @@ import { version } from '../package.json' export default { name: 'holmes', - version: "2.17.5", + version, design: 'Erica Alcusa Sáez', - code: 'Erica Alcusa Sáez, bobgeorgethe3rd', + code: ['Erica Alcusa Sáez', 'bobgeorgethe3rd'], department: 'accessories', type: 'pattern', difficulty: 3, optionGroups: { fit: ['head_ease'], - style: ['lengthRatio', 'goreNumber', 'billAngle', 'billWidth','ear_length','ear_width','buttonhole'], - advanced:['bill_length'], + style: ['lengthRatio', 'goreNumber', 'billAngle', 'billWidth','earLength','earWidth','buttonhole'], + advanced:['billLength'], }, measurements: ['head'], dependencies: {}, @@ -26,9 +26,9 @@ export default { goreNumber: { count: 6, min: 4, max: 20 }, billAngle: { deg: 45, min: 10, max: 90 }, billWidth: { mm: 30, min: 5, max: 100 }, - ear_length: { pct: 100, min: 80, max: 150 }, - ear_width: { pct: 100, min: 80, max: 150 }, - bill_length: { pct: 100, min: 80, max: 150 }, + earLength: { pct: 100, min: 80, max: 150 }, + earWidth: { pct: 100, min: 80, max: 150 }, + billLength: { pct: 100, min: 80, max: 150 }, buttonhole: {bool: false} }, } diff --git a/packages/holmes/src/bill.js b/packages/holmes/src/bill.js index 2d0a2490ae8..1ba35d12b28 100644 --- a/packages/holmes/src/bill.js +++ b/packages/holmes/src/bill.js @@ -15,7 +15,7 @@ export default function (part) { let headCircumference = measurements.head + options.head_ease let headRadius = headCircumference / 2 / Math.PI let billRadius = (headRadius / Math.sin((options.billAngle * Math.PI) / 180)) - let sectorAngle = (Math.PI / 3)*options.bill_length + let sectorAngle = (Math.PI / 3)*options.billLength let billSectorAngle = (sectorAngle * headRadius) / billRadius let cpDistance = ((4 / 3) * billRadius * (1 - Math.cos(billSectorAngle / 2))) / Math.sin(billSectorAngle / 2) diff --git a/packages/holmes/src/ear.js b/packages/holmes/src/ear.js index e74fb29bbc2..bbbed79d202 100644 --- a/packages/holmes/src/ear.js +++ b/packages/holmes/src/ear.js @@ -16,8 +16,8 @@ export default function (part) { // Design pattern here let headCircumference = measurements.head + options.head_ease -let earFlapLength = ((options.lengthRatio * headCircumference) / 2)*options.ear_length -let earFlapWidth = (headCircumference / 12)*options.ear_width +let earFlapLength = ((options.lengthRatio * headCircumference) / 2)*options.earLength +let earFlapWidth = (headCircumference / 12)*options.earWidth points.top = new Point(0, 0) points.bottom = new Point(earFlapWidth, earFlapLength) points.topC = points.top.shift(0, points.bottom.x) From 2b0a7707a4bc05c873c1508692de5b56650131b8 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 24 Aug 2021 16:15:04 +0100 Subject: [PATCH 3/4] headEase!!! You always forget one --- packages/holmes/config/index.js | 4 ++-- packages/holmes/src/bill.js | 2 +- packages/holmes/src/ear.js | 2 +- packages/holmes/src/gore.js | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/holmes/config/index.js b/packages/holmes/config/index.js index 7174987fc1f..a696205d87a 100644 --- a/packages/holmes/config/index.js +++ b/packages/holmes/config/index.js @@ -11,7 +11,7 @@ export default { type: 'pattern', difficulty: 3, optionGroups: { - fit: ['head_ease'], + fit: ['headEase'], style: ['lengthRatio', 'goreNumber', 'billAngle', 'billWidth','earLength','earWidth','buttonhole'], advanced:['billLength'], }, @@ -21,7 +21,7 @@ export default { hide: [], parts: ['gore', 'bill', 'ear'], options: { - head_ease: { mm: 19, min: 0, max: 50 }, + headEase: { mm: 19, min: 0, max: 50 }, lengthRatio: { pct: 55, min: 40, max: 60 }, goreNumber: { count: 6, min: 4, max: 20 }, billAngle: { deg: 45, min: 10, max: 90 }, diff --git a/packages/holmes/src/bill.js b/packages/holmes/src/bill.js index 1ba35d12b28..7f4b21449bd 100644 --- a/packages/holmes/src/bill.js +++ b/packages/holmes/src/bill.js @@ -12,7 +12,7 @@ export default function (part) { macro, } = part.shorthand() - let headCircumference = measurements.head + options.head_ease + let headCircumference = measurements.head + options.headEase let headRadius = headCircumference / 2 / Math.PI let billRadius = (headRadius / Math.sin((options.billAngle * Math.PI) / 180)) let sectorAngle = (Math.PI / 3)*options.billLength diff --git a/packages/holmes/src/ear.js b/packages/holmes/src/ear.js index bbbed79d202..ced78b3dd0d 100644 --- a/packages/holmes/src/ear.js +++ b/packages/holmes/src/ear.js @@ -15,7 +15,7 @@ export default function (part) { } = part.shorthand() // Design pattern here -let headCircumference = measurements.head + options.head_ease +let headCircumference = measurements.head + options.headEase let earFlapLength = ((options.lengthRatio * headCircumference) / 2)*options.earLength let earFlapWidth = (headCircumference / 12)*options.earWidth points.top = new Point(0, 0) diff --git a/packages/holmes/src/gore.js b/packages/holmes/src/gore.js index 63eaed314db..11c50df0014 100644 --- a/packages/holmes/src/gore.js +++ b/packages/holmes/src/gore.js @@ -15,7 +15,7 @@ export default function (part) { // Design pattern here //Radius of the head - let headCircumference = measurements.head + options.head_ease + let headCircumference = measurements.head + options.headEase let headRadius = headCircumference / 2 / Math.PI points.p0 = new Point(0, 0) From dffbb0ea108b85befd9316101dda3cc646a87dc9 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 24 Aug 2021 16:40:15 +0100 Subject: [PATCH 4/4] Chaging BIll to Visor --- packages/holmes/config/index.js | 12 ++++++------ packages/holmes/src/index.js | 4 ++-- packages/holmes/src/{bill.js => visor.js} | 20 ++++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) rename packages/holmes/src/{bill.js => visor.js} (81%) diff --git a/packages/holmes/config/index.js b/packages/holmes/config/index.js index a696205d87a..1d1e886f40d 100644 --- a/packages/holmes/config/index.js +++ b/packages/holmes/config/index.js @@ -12,23 +12,23 @@ export default { difficulty: 3, optionGroups: { fit: ['headEase'], - style: ['lengthRatio', 'goreNumber', 'billAngle', 'billWidth','earLength','earWidth','buttonhole'], - advanced:['billLength'], + style: ['lengthRatio', 'goreNumber', 'visorAngle', 'visorWidth','earLength','earWidth','buttonhole'], + advanced:['visorLength'], }, measurements: ['head'], dependencies: {}, inject: {}, hide: [], - parts: ['gore', 'bill', 'ear'], + parts: ['gore', 'visor', 'ear'], options: { headEase: { mm: 19, min: 0, max: 50 }, lengthRatio: { pct: 55, min: 40, max: 60 }, goreNumber: { count: 6, min: 4, max: 20 }, - billAngle: { deg: 45, min: 10, max: 90 }, - billWidth: { mm: 30, min: 5, max: 100 }, + visorAngle: { deg: 45, min: 10, max: 90 }, + visorWidth: { mm: 30, min: 5, max: 100 }, earLength: { pct: 100, min: 80, max: 150 }, earWidth: { pct: 100, min: 80, max: 150 }, - billLength: { pct: 100, min: 80, max: 150 }, + visorLength: { pct: 100, min: 80, max: 150 }, buttonhole: {bool: false} }, } diff --git a/packages/holmes/src/index.js b/packages/holmes/src/index.js index ba0a136e411..caa78d97a40 100644 --- a/packages/holmes/src/index.js +++ b/packages/holmes/src/index.js @@ -4,7 +4,7 @@ import gorePlugin from '@freesewing/plugin-gore' import config from '../config' import draftGore from './gore' -import draftBill from './bill' +import draftVisor from './visor' import draftEar from './ear' // Create new design @@ -12,7 +12,7 @@ const Pattern = new freesewing.Design(config, [plugins, gorePlugin]) // Attach the draft methods to the prototype Pattern.prototype.draftGore = draftGore -Pattern.prototype.draftBill = draftBill +Pattern.prototype.draftVisor = draftVisor Pattern.prototype.draftEar = draftEar export default Pattern diff --git a/packages/holmes/src/bill.js b/packages/holmes/src/visor.js similarity index 81% rename from packages/holmes/src/bill.js rename to packages/holmes/src/visor.js index 7f4b21449bd..46f142f2541 100644 --- a/packages/holmes/src/bill.js +++ b/packages/holmes/src/visor.js @@ -14,17 +14,17 @@ export default function (part) { let headCircumference = measurements.head + options.headEase let headRadius = headCircumference / 2 / Math.PI - let billRadius = (headRadius / Math.sin((options.billAngle * Math.PI) / 180)) - let sectorAngle = (Math.PI / 3)*options.billLength - let billSectorAngle = (sectorAngle * headRadius) / billRadius + let visorRadius = (headRadius / Math.sin((options.visorAngle * Math.PI) / 180)) + let sectorAngle = (Math.PI / 3)*options.visorLength + let visorSectorAngle = (sectorAngle * headRadius) / visorRadius let cpDistance = - ((4 / 3) * billRadius * (1 - Math.cos(billSectorAngle / 2))) / Math.sin(billSectorAngle / 2) + ((4 / 3) * visorRadius * (1 - Math.cos(visorSectorAngle / 2))) / Math.sin(visorSectorAngle / 2) points.origin = new Point(0, 0) points.in1 = new Point(0, 0) points.in2 = points.in1.shift( - ((90 / Math.PI) * billSectorAngle), - 2 * billRadius * Math.sin(billSectorAngle / 2) + ((90 / Math.PI) * visorSectorAngle), + 2 * visorRadius * Math.sin(visorSectorAngle / 2) ) //test circle //points.circleCentre = points.in1.shift(90,headRadius) @@ -32,16 +32,16 @@ export default function (part) { //points.circle60 = points.circleCentre.shift(-30,headRadius) // points.in1C = points.in1.shift(0, cpDistance) - points.in2C = points.in2.shift(180 + (180 / Math.PI) * billSectorAngle, cpDistance) + points.in2C = points.in2.shift(180 + (180 / Math.PI) * visorSectorAngle, cpDistance) points.in1CFlipped = points.in1C.flipX() points.in2Flipped = points.in2.flipX() points.in2CFlipped = points.in2C.flipX() - points.ex1 = points.in1.shift(-90, options.billWidth) + points.ex1 = points.in1.shift(-90, options.visorWidth) points.ex1C = points.ex1.shift(0, 0.5 * points.in2.x) points.ex2C = points.in2.shift( -90, - (points.ex1.y - points.in2.y) * (2 / (1 + Math.exp(-options.billWidth / 15)) - 1) + (points.ex1.y - points.in2.y) * (2 / (1 + Math.exp(-options.visorWidth / 15)) - 1) ) points.ex1CFlipped = points.ex1C.flipX() points.ex2CFlipped = points.ex2C.flipX() @@ -56,7 +56,7 @@ export default function (part) { // Complete? if (complete) { macro('grainline', { from: points.in1, to: points.ex1 }) - macro('title', { at: points.ex1.shift(45, 20), nr: 2, title: 'bill', scale: 0.4 }) + macro('title', { at: points.ex1.shift(45, 20), nr: 2, title: 'visor', scale: 0.4 }) if (sa) { paths.saInner = new Path ()