+
+
+
+
+
+
+This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
+
diff --git a/designs/noble/build.js b/designs/noble/build.js
new file mode 100644
index 00000000000..c77d47c1637
--- /dev/null
+++ b/designs/noble/build.js
@@ -0,0 +1,55 @@
+/* This script will build the package with esbuild */
+const esbuild = require('esbuild')
+const pkg = require('./package.json')
+
+// Create banner based on package info
+const banner = `/**
+ * ${pkg.name} | v${pkg.version}
+ * ${pkg.description}
+ * (c) ${new Date().getFullYear()} ${pkg.author}
+ * @license ${pkg.license}
+ */`
+
+// Shared esbuild options
+const options = {
+ banner: { js: banner },
+ bundle: true,
+ entryPoints: ['src/index.js'],
+ external: ["@freesewing"],
+ metafile: process.env.VERBOSE ? true : false,
+ minify: process.env.NO_MINIFY ? false : true,
+ sourcemap: true,
+}
+
+// Different formats
+const formats = {
+ cjs: "dist/index.js",
+ esm: "dist/index.mjs",
+}
+
+// Let esbuild generate different formats
+let result
+(async () => {
+ for (const [format, outfile] of Object.entries(formats)) {
+ result = await esbuild
+ .build({ ...options, outfile, format })
+ .catch(() => process.exit(1))
+ }
+
+ if (process.env.VERBOSE) {
+ const info = await esbuild.analyzeMetafile(result.metafile)
+ console.log(info)
+ }
+
+ // Also build a version that has all dependencies bundled
+ // This makes it easy to run tests
+ await esbuild
+ .build({
+ ...options,
+ outfile: 'tests/dist/index.mjs',
+ format: 'esm',
+ external: [],
+ })
+ .catch(() => process.exit(1))
+
+})()
diff --git a/designs/noble/config/index.js b/designs/noble/config/index.js
new file mode 100644
index 00000000000..4bedaf3b7b9
--- /dev/null
+++ b/designs/noble/config/index.js
@@ -0,0 +1,111 @@
+// import { version } from '../package.json'
+import Bella from '@freesewing/bella'
+
+import { version } from '../package.json'
+import configHelpers from '@freesewing/config-helpers'
+const { pctBasedOn } = configHelpers
+
+export default {
+ ...Bella.config,
+ name: 'noble',
+ version,
+ design: 'Noble Incognito',
+ code: 'Wouter van Wageningen',
+ department: 'tops',
+ type: 'block',
+ difficulty: 3,
+ optionGroups: {
+ type: ['dartPosition'],
+ fit: ['chestEase', 'waistEase', 'bustSpanEase'],
+ darts: ['backDartHeight', 'waistDartLength', 'shoulderDartPosition','upperDartLength','dartOutsideCP','armholeDartPosition'],
+ armhole: [
+ 'armholeDepth',
+ 'backArmholeSlant',
+ 'backArmholeCurvature',
+ 'frontArmholePitchDepth',
+ 'backArmholePitchDepth',
+ ],
+ advanced: ['backNeckCutout', 'backHemSlope', 'frontShoulderWidth', 'highBustWidth', 'shoulderToShoulderEase'],
+ },
+ measurements: [
+ 'chest',
+ 'waist',
+ 'waistBack',
+ 'neck',
+ 'hpsToWaistFront',
+ 'hpsToWaistBack',
+ 'shoulderToShoulder',
+ 'shoulderSlope',
+ // ],
+ // optionalMeasurements: [
+ 'highBust',
+ 'underbust',
+ 'bustSpan',
+ 'hpsToBust',
+ ],
+ hide: ['bellaFrontSideDart', 'bellaBack', 'backPoints', 'frontPoints',],
+ inject: {
+ ...Bella.config.inject,
+ backPoints: 'bellaBack',
+ backInside: 'backPoints',
+ backOutside: 'backPoints',
+ frontPoints: 'bellaFrontSideDart',
+ frontInside: 'frontPoints',
+ frontOutside: 'frontPoints',
+ },
+ dependencies: {
+ // The inheritance makes this a bit messy
+ bellaFrontSideDart: 'bellaBack',
+ backPoints: 'bellaBack',
+ backInside: 'backPoints',
+ backOutside: 'backPoints',
+ frontPoints: 'bellaBack',
+ frontInside: 'frontPoints',
+ frontOutside: ['frontPoints','frontInside'],
+ },
+ parts: [
+ 'backPoints',
+ 'backInside',
+ 'backOutside',
+ 'frontPoints',
+ 'frontInside',
+ 'frontOutside',
+ ],
+ options: {
+ // Constants
+ acrossBackFactor: 0.925,
+ shoulderSlopeBack: 1.23,
+ neckWidthBack: 0.197,
+ neckWidthFront: 0.17,
+ shoulderToShoulderCorrection: 0.995,
+ backDartLocation: 0.145,
+ backCenterWaistReduction: 0.35,
+ collarFactor: 0.19,
+
+ // Percentages
+ backNeckCutout: { pct: 6, min: 3, max: 9 },
+ waistEase: { pct: 5, min: 1, max: 20 },
+ chestEase: { pct: 11, min: 5, max: 20 },
+ bustSpanEase: { pct: 0, min: -5, max: 20 },
+ shoulderToShoulderEase: { pct: -0.5, min: -1, max: 5 },
+ backDartHeight: { pct: 46, min: 38, max: 54 },
+ armholeDepth: { pct: 44, min: 38, max: 46 },
+ backHemSlope: { deg: 2.5, min: 0, max: 5 },
+ backArmholeSlant: { deg: 5, min: 1, max: 9 },
+ backArmholeCurvature: { pct: 63, min: 50, max: 85 },
+ frontArmholeCurvature: { pct: 63, min: 50, max: 85 },
+ fullChestEaseReduction: { pct: 4, min: 0, max: 8 },
+ frontShoulderWidth: { pct: 95, max: 98, min: 92 },
+ frontArmholePitchDepth: { pct: 29, max: 31, min: 27 },
+ backArmholePitchDepth: { pct: 35, max: 40, min: 30 },
+ highBustWidth: { pct: 86, max: 92, min: 80 },
+ bustDartLength: { pct: 90, min: 75, max: 100 },
+ waistDartLength: { pct: 90, min: 75, max: 95 },
+ bustDartCurve: { pct: 100, min: 0, max: 100 },
+ shoulderDartPosition: { pct: 50, min: 10, max: 90, hide: function(settings) {(settings.options.dartPosition != 'shoulder')} },
+ upperDartLength: { pct: 90, min: 80, max: 95 },
+ armholeDartPosition: { pct: 50, min: 10, max: 90, hide: function(settings) {(settings.options.dartPosition != 'shoulder')} },
+ dartPosition: { dflt: 'shoulder', list: ['shoulder','armhole'] },
+ }
+
+}
diff --git a/designs/noble/package.json b/designs/noble/package.json
new file mode 100644
index 00000000000..a26c6d83d31
--- /dev/null
+++ b/designs/noble/package.json
@@ -0,0 +1,65 @@
+{
+ "name": "@freesewing/noble",
+ "version": "2.21.0-rc.0",
+ "description": "FIXME: A FreeSewing pattern that needs a description",
+ "author": "Joost De Cock (https://github.com/joostdecock)",
+ "homepage": "https://freesewing.org/",
+ "repository": "github:freesewing/freesewing",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/freesewing/freesewing/issues"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://freesewing.org/patrons/join"
+ },
+ "keywords": [
+ "freesewing",
+ "design",
+ "diy",
+ "fashion",
+ "made to measure",
+ "parametric design",
+ "pattern",
+ "sewing",
+ "sewing pattern"
+ ],
+ "main": "dist/index.js",
+ "module": "dist/index.mjs",
+ "scripts": {
+ "build": "node build.js",
+ "clean": "rimraf dist",
+ "mbuild": "NO_MINIFY=1 node build.js",
+ "symlink": "mkdir -p ./node_modules/@freesewing && cd ./node_modules/@freesewing && ln -s -f ../../../* . && cd -",
+ "test": "BABEL_ENV=production npx mocha tests/*.test.mjs --require @babel/register",
+ "vbuild": "VERBOSE=1 node build.js",
+ "lab": "cd ../../sites/lab && yarn start",
+ "tips": "node ../../scripts/help.mjs",
+ "prettier": "npx prettier --write 'src/*.js' 'config/*.js'",
+ "testci": "BABEL_ENV=production npx mocha tests/*.test.mjs --require @babel/register --reporter ../../tests/reporters/terse.js",
+ "cibuild_step5": "node build.js"
+ },
+ "peerDependencies": {
+ "@freesewing/core": "^2.21.0-rc.0",
+ "@freesewing/plugin-bundle": "^2.21.0-rc.0",
+ "@freesewing/config-helpers": "^2.21.0-rc.0"
+ },
+ "dependencies": {},
+ "devDependencies": {
+ "mocha": "^9.1.1",
+ "chai": "^4.2.0"
+ },
+ "files": [
+ "dist/*",
+ "README.md",
+ "package.json"
+ ],
+ "publishConfig": {
+ "access": "public",
+ "tag": "next"
+ },
+ "engines": {
+ "node": ">=14.0.0",
+ "npm": ">=6"
+ }
+}
diff --git a/designs/noble/src/backInside.js b/designs/noble/src/backInside.js
new file mode 100644
index 00000000000..b449317dfc1
--- /dev/null
+++ b/designs/noble/src/backInside.js
@@ -0,0 +1,157 @@
+export default function (part) {
+ let {
+ utils,
+ store,
+ sa,
+ Point,
+ points,
+ Path,
+ paths,
+ Snippet,
+ snippets,
+ options,
+ measurements,
+ complete,
+ paperless,
+ macro,
+ } = part.shorthand()
+
+
+ if( options.dartPosition != 'shoulder' ) {
+ paths.insideSeam = paths.seam.clone().setRender(true)
+ } else {
+ // Hide Bella paths
+ for (let key of Object.keys(paths)) paths[key].render = false
+ for (let i in snippets) delete snippets[i]
+
+ paths.insideSeam = new Path()
+ .move(points.cbNeck)
+ .curve_(points.cbNeckCp2, points.waistCenter)
+ .line(points.dartBottomLeft)
+ .curve(points.dartLeftCp, points.shoulderDartCpDown, points.dartTip)
+ .curve(points.shoulderDartCpUp, points.shoulderDart, points.shoulderDart)
+ .line(points.hps)
+ ._curve(points.cbNeckCp1, points.cbNeck)
+ .close()
+ .attr('class', 'fabric')
+ }
+
+ if (complete) {
+ snippets.dartTip = new Snippet('notch', points.dartTip)
+
+ macro('title', {
+ at: points.titleAnchor,
+ nr: 3,
+ title: ( options.dartPosition != 'shoulder' ? 'Back' : 'Inside Back' )
+ })
+ macro("grainline", {
+ from: points.grainlineFrom,
+ to: points.grainlineTo,
+ })
+
+ if (sa) paths.sa = paths.insideSeam.offset(sa).attr('class', 'fabric sa')
+
+ if( paperless ) {
+ if( options.dartPosition == 'shoulder' ) {
+ points.shoulderPoint = points.shoulderDart.clone()
+ } else {
+ points.shoulderPoint = points.shoulder.clone()
+ }
+ macro('hd', {
+ from: points.waistCenter,
+ to: points.shoulderPoint,
+ y: points.waistCenter.y +sa + 15,
+ })
+ macro('hd', {
+ from: points.waistCenter,
+ to: points.dartTip,
+ y: points.waistCenter.y +sa + 25,
+ })
+ macro('hd', {
+ from: points.waistCenter,
+ to: points.dartBottomLeft,
+ y: points.waistCenter.y +sa + 35,
+ })
+ macro('hd', {
+ from: points.cbNeck,
+ to: points.dartBottomLeft,
+ y: points.waistCenter.y +sa + 45,
+ })
+ macro('hd', {
+ from: points.cbNeck,
+ to: points.hps,
+ y: points.hps.y -sa - 15,
+ })
+ macro('hd', {
+ from: points.hps,
+ to: points.shoulderPoint,
+ y: points.hps.y -sa - 15,
+ })
+ if( options.dartPosition != 'shoulder' ) {
+ macro('hd', {
+ from: points.dartTip,
+ to: points.waistSide,
+ y: points.waistCenter.y +sa + 25,
+ })
+ macro('hd', {
+ from: points.dartBottomRight,
+ to: points.waistSide,
+ y: points.waistCenter.y +sa + 35,
+ })
+ macro('hd', {
+ from: points.dartBottomRight,
+ to: points.armhole,
+ y: points.waistCenter.y +sa + 45,
+ })
+ }
+
+ let extraOffset = 0
+ if( options.dartPosition != 'shoulder' ) {
+ macro('vd', {
+ from: points.shoulderPoint,
+ to: points.waistSide,
+ x: points.shoulderPoint.x +sa + 25,
+ })
+ macro('vd', {
+ from: points.armhole,
+ to: points.waistSide,
+ x: points.shoulderPoint.x +sa + 15,
+ })
+ extraOffset = 10
+ }
+
+ macro('vd', {
+ from: points.shoulderPoint,
+ to: points.dartTip,
+ x: points.shoulderPoint.x +sa + 15,
+ })
+ macro('vd', {
+ from: points.shoulderPoint,
+ to: points.dartBottomLeft,
+ x: points.shoulderPoint.x +sa + 25 +extraOffset,
+ })
+ macro('vd', {
+ from: points.shoulderPoint,
+ to: points.waistCenter,
+ x: points.shoulderPoint.x +sa + 35 +extraOffset,
+ })
+ macro('vd', {
+ from: points.hps,
+ to: points.waistCenter,
+ x: points.shoulderPoint.x +sa + 45 +extraOffset,
+ })
+ macro('vd', {
+ from: points.waistCenter,
+ to: points.cbNeck,
+ x: points.cbNeck.x -sa - 15,
+ })
+ macro('vd', {
+ from: points.waistCenter,
+ to: points.hps,
+ x: points.cbNeck.x -sa - 25,
+ })
+ }
+ }
+
+ return part
+}
diff --git a/designs/noble/src/backOutside.js b/designs/noble/src/backOutside.js
new file mode 100644
index 00000000000..1f80f5d2741
--- /dev/null
+++ b/designs/noble/src/backOutside.js
@@ -0,0 +1,125 @@
+export default function (part) {
+ let {
+ utils,
+ store,
+ sa,
+ Point,
+ points,
+ Path,
+ paths,
+ Snippet,
+ snippets,
+ options,
+ measurements,
+ complete,
+ paperless,
+ macro,
+ } = part.shorthand()
+
+ if( options.dartPosition != 'shoulder' ) {
+ return part
+ }
+
+ paths.dart = new Path()
+ .move(points.shoulderDart)
+ .curve(points.shoulderDart, points.shoulderDartCpUp, points.dartTip)
+ .curve(points.shoulderDartCpDown, points.dartRightCp, points.dartBottomRight)
+ .setRender(false)
+
+ paths.outsideSeam = new Path()
+ .move(points.dartBottomRight)
+ .line(points.waistSide)
+ .curve_(points.waistSideCp2, points.armhole)
+ .curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
+ .curve_(points.armholePitchCp2, points.shoulder)
+ .line(points.shoulderDart)
+ .join(paths.dart)
+ .close()
+ .attr('class', 'fabric')
+
+ if (complete) {
+ snippets.dartTip = new Snippet('notch', points.dartTip)
+
+ points.titleAnchor = points.dartBottomRight.shiftFractionTowards( points.waistSide, .1 ).shiftFractionTowards( points.shoulder, .3 )
+ macro('title', {
+ at: points.titleAnchor,
+ nr: 4,
+ title: 'Outside Back',
+ })
+ points.grainlineFrom.x = points.shoulderDart.x
+ points.grainlineTo.x = points.shoulderDart.x
+
+ macro("grainline", {
+ from: points.grainlineFrom,
+ to: points.grainlineTo,
+ })
+
+ if (sa) paths.sa = paths.outsideSeam.offset(sa).attr('class', 'fabric sa')
+ if( paperless ) {
+ let pLeft = paths.dart.edge('left')
+ macro('hd', {
+ from: pLeft,
+ to: points.waistSide,
+ y: points.waistCenter.y +sa + 15,
+ })
+ macro('hd', {
+ from: points.dartBottomRight,
+ to: points.armhole,
+ y: points.waistCenter.y +sa + 25,
+ })
+ macro('hd', {
+ from: points.dartTip,
+ to: points.waistSide,
+ y: points.waistCenter.y +sa + 35,
+ })
+ macro('hd', {
+ from: points.dartBottomRight,
+ to: points.waistSide,
+ y: points.waistCenter.y +sa + 45,
+ })
+ macro('hd', {
+ from: pLeft,
+ to: points.shoulder,
+ y: points.shoulderDart.y -sa - 15,
+ })
+ macro('hd', {
+ from: points.shoulderDart,
+ to: points.shoulder,
+ y: points.shoulderDart.y -sa - 25,
+ })
+ macro('hd', {
+ from: points.shoulderDart,
+ to: points.armhole,
+ y: points.shoulderDart.y -sa - 35,
+ })
+
+ macro('vd', {
+ from: points.shoulder,
+ to: points.dartTip,
+ x: points.armhole.x +sa + 15,
+ })
+ macro('vd', {
+ from: points.armhole,
+ to: points.waistSide,
+ x: points.armhole.x +sa + 15,
+ })
+ macro('vd', {
+ from: points.shoulder,
+ to: points.waistSide,
+ x: points.armhole.x +sa + 25,
+ })
+ macro('vd', {
+ from: points.shoulder,
+ to: points.dartBottomRight,
+ x: points.armhole.x +sa + 35,
+ })
+ macro('vd', {
+ from: points.shoulderDart,
+ to: points.dartBottomRight,
+ x: points.armhole.x +sa + 45,
+ })
+ }
+ }
+
+ return part
+}
diff --git a/designs/noble/src/backPoints.js b/designs/noble/src/backPoints.js
new file mode 100644
index 00000000000..03c68c4d184
--- /dev/null
+++ b/designs/noble/src/backPoints.js
@@ -0,0 +1,74 @@
+export default function (part) {
+ let {
+ points,
+ Path,
+ paths,
+ options,
+ snippets,
+ } = part.shorthand()
+
+ // Hide Bella paths
+ for (let key of Object.keys(paths)) paths[key].render = false
+ for (let i in snippets) delete snippets[i]
+
+ delete points.__titleNr
+ delete points.__titleName
+ delete points.__titlePattern
+ delete points.scaleboxAnchor
+ delete points.__scaleboxImperialBottomLeft
+ delete points.__scaleboxMetricBottomLeft
+ delete points.__scaleboxImperialTopLeft
+ delete points.__scaleboxMetricTopLeft
+ delete points.__scaleboxImperialTopRight
+ delete points.__scaleboxMetricTopRight
+ delete points.__scaleboxImperialBottomRight
+ delete points.__scaleboxMetricBottomRight
+ delete points.__scaleboxLead
+ delete points.__scaleboxTitle
+ delete points.__scaleboxText
+ delete points.__scaleboxLink
+ delete points.__scaleboxImperial
+ delete points.__scaleboxMetric
+ delete points.bustDartLeft
+ delete points.bustDartLeftCp
+
+ points.shoulderDart = points.hps.shiftFractionTowards( points.shoulder, options.shoulderDartPosition )
+
+ let aUp = points.dartTip.angle( points.shoulderDart )
+ let aDown = points.dartBottomRight.angle( points.dartTip )
+ let aDiff = Math.abs( aUp - aDown )
+
+ // let dartCpAdjustment = Math.abs( options.shoulderDartPosition -.5) +.05
+ let dartCpAdjustment = aDiff /50
+
+ points.shoulderDartCpUp = points.shoulderDart.shiftFractionTowards( points.dartTip, 1 - dartCpAdjustment)
+ points.shoulderDartCpDown = points.shoulderDart.shiftFractionTowards( points.dartTip, 1 +dartCpAdjustment )
+
+ let iLength = (new Path()
+ .move(points.dartBottomLeft)
+ .curve(points.dartLeftCp, points.shoulderDartCpDown, points.dartTip)
+ .curve(points.shoulderDartCpUp, points.shoulderDart, points.shoulderDart)).length();
+
+ let iteration = 0
+ let diff = 0
+ let angle = 0
+ do {
+ angle = diff*( oLength > iLength ? -.1 : .1 )
+
+ points.dartBottomRight = points.dartBottomRight.rotate( angle, points.waistSide )
+
+ let oLength = (new Path()
+ .move(points.shoulderDart)
+ .curve(points.shoulderDart, points.shoulderDartCpUp, points.dartTip)
+ .curve(points.shoulderDartCpDown, points.dartRightCp, points.dartBottomRight)).length();
+
+ diff = oLength -iLength
+ iteration ++
+
+ } while( diff < -.5 || diff > .5 && iteration < 100 )
+ if( iteration >= 100 ) {
+ raise.error('Something is not quite right here!')
+ }
+
+ return part
+}
\ No newline at end of file
diff --git a/designs/noble/src/frontInside.js b/designs/noble/src/frontInside.js
new file mode 100644
index 00000000000..949e417321c
--- /dev/null
+++ b/designs/noble/src/frontInside.js
@@ -0,0 +1,178 @@
+export default function (part) {
+ let {
+ utils,
+ store,
+ sa,
+ Point,
+ points,
+ Path,
+ paths,
+ Snippet,
+ snippets,
+ options,
+ measurements,
+ complete,
+ paperless,
+ macro,
+ } = part.shorthand()
+
+ delete points.waistDartHem
+ delete points.waistDartRight
+ delete points.waistDartRightCp
+ delete points.waistDartCpBottom
+ delete points.bustDartBottom
+ delete points.bustDartCpBottom
+ delete points.bustDartTip
+ delete points.bustDartTop
+ delete points.shoulderDartTipCpDownOutside
+ delete points.ex
+ delete points.bustB
+ delete points.shoulder
+ delete points.shoulderDartShoulder
+ delete points.shoulderDartOutside
+ delete points.pitchMax
+ delete points.armholeCpTarget
+ delete points.armholePitch
+ delete points.armholePitchCp1
+ delete points.armholePitchCp2
+ delete points.armhole
+ delete points.armholeCp2
+ delete points.bustDartCpTop
+ delete points.bustSide
+ delete points.bustDartMiddle
+ delete points.bustDartEdge
+
+ if( options.dartPosition == 'shoulder' ) {
+ paths.insideSeam = new Path()
+ .move(points.cfHem)
+ .line(points.waistDartLeft)
+ .curve(points.waistDartLeftCp, points.shoulderDartTipCpDownInside, points.shoulderDartTip)
+ .line(points.shoulderDartInside)
+ .line(points.hps)
+ .curve(points.hpsCp2, points.cfNeckCp1, points.cfNeck)
+
+ paths.seam = paths.insideSeam.join( new Path().move(points.cfNeck).line(points.cfHem))
+ .close()
+ .attr('class', 'fabric')
+
+ store.set( 'shoulderDartTipNotch', (new Path()
+ .move(points.waistDartLeft)
+ .curve(points.waistDartLeftCp, points.shoulderDartTipCpDownInside, points.shoulderDartTip)).length())
+
+ } else {
+ paths.insideSeam = new Path()
+ .move(points.cfHem)
+ .line(points.waistDartLeft)
+ .curve(points.waistDartLeftCp, points.armholeDartTipCpDownInside, points.armholeDartTipInside)
+ .curve(points.waistCircleInsideCp1, points.armholeCircleInsideCp1, points.armholeDartInside)
+ .join(paths.armholeInside)
+ .line(points.hps)
+ .curve(points.hpsCp2, points.cfNeckCp1, points.cfNeck)
+
+ paths.seam = paths.insideSeam.join( new Path().move(points.cfNeck).line(points.cfHem))
+ .close()
+ .attr('class', 'fabric')
+
+ store.set( 'shoulderDartTipNotch', (new Path()
+ .move(points.waistDartLeft)
+ .curve(points.waistDartLeftCp, points.armholeDartTipCpDownInside, points.armholeDartTipInside)).length())
+ }
+
+ if (complete) {
+ if( options.dartPosition == 'shoulder' ) {
+ snippets.shoulderDartTip = new Snippet('notch', points.shoulderDartTip)
+ } else {
+ snippets.shoulderDartTip = new Snippet('notch', points.armholeDartTipInside)
+ }
+ points.titleAnchor = new Point(points.hpsCp2.x *.75, points.cfNeckCp1.y *1.5)
+ macro('title', {
+ at: points.titleAnchor,
+ nr: 1,
+ title: 'Inside Front',
+ })
+ points.scaleboxAnchor = points.titleAnchor.shift(-90, 90).shift(0,10)
+ macro('scalebox', { at: points.scaleboxAnchor, rotate: 270 })
+
+ macro('cutonfold', {
+ from: points.cfNeck,
+ to: points.cfHem,
+ grainline: true,
+ })
+
+ if (sa) {
+ paths.sa = paths.insideSeam.offset(sa).line(points.cfNeck).attr('class', 'fabric sa')
+ paths.sa = paths.sa.move(points.cfHem).line(paths.sa.start())
+ }
+
+ if (paperless) {
+ let extraOffset = 0
+ if( options.dartPosition == 'shoulder' ) {
+ macro('hd', {
+ from: points.cfNeck,
+ to: points.shoulderDartInside,
+ y: points.hps.y - 25,
+ })
+ macro('vd', {
+ from: points.cfHem,
+ to: points.shoulderDartInside,
+ x: 0 -30,
+ })
+ } else {
+ extraOffset = 10
+ macro('hd', {
+ from: points.cfNeck,
+ to: points.shoulderCp1,
+ y: points.hps.y - 35,
+ })
+ macro('hd', {
+ from: points.cfNeck,
+ to: points.armholeDartInsideCp2,
+ y: points.hps.y - 25,
+ })
+ macro('vd', {
+ from: points.cfHem,
+ to: points.armholeDartInsideCp2,
+ x: 0 -20,
+ })
+ macro('vd', {
+ from: points.cfHem,
+ to: points.shoulderCp1,
+ x: 0 -40,
+ })
+ }
+
+ macro('vd', {
+ from: points.cfHem,
+ to: points.armholeDartTipInside,
+ x: 0 - 10,
+ })
+ macro('vd', {
+ from: points.cfHem,
+ to: points.cfNeck,
+ x: 0 - 20 -extraOffset,
+ })
+ macro('vd', {
+ from: points.cfHem,
+ to: points.hps,
+ x: 0 - 40 -extraOffset,
+ })
+ macro('hd', {
+ from: points.cfBust,
+ to: points.armholeDartTipInside,
+ y: points.cfHem.y + sa + 25,
+ })
+ macro('hd', {
+ from: points.cfHem,
+ to: points.waistDartLeft,
+ y: points.cfHem.y + sa + 15,
+ })
+ macro('hd', {
+ from: points.cfNeck,
+ to: points.hps,
+ y: points.hps.y - sa - 15,
+ })
+ }
+ }
+
+ return part
+}
diff --git a/designs/noble/src/frontOutside.js b/designs/noble/src/frontOutside.js
new file mode 100644
index 00000000000..c94d12fb6dc
--- /dev/null
+++ b/designs/noble/src/frontOutside.js
@@ -0,0 +1,211 @@
+export default function (part) {
+ let {
+ utils,
+ store,
+ sa,
+ Point,
+ points,
+ Path,
+ paths,
+ Snippet,
+ snippets,
+ options,
+ measurements,
+ complete,
+ paperless,
+ macro,
+ } = part.shorthand()
+
+ delete points.bustDartTop
+ delete points.bustSide
+ delete points.bustDartMiddle
+ delete points.bustDartBottom
+ delete points.bustDartCpBottom
+ delete points.bustB
+ delete points.bustDartEdge
+
+ if( options.dartPosition == 'shoulder' ) {
+ paths.princessSeam = new Path()
+ .move(points.shoulderDartOutside)
+ .curve(points.shoulderDartTipCpDownOutside, points.waistUpDartRightCpUp, points.waistUpDartRight)
+ .curve(points.waistUpDartRightCpDown, points.waistCpUp, points.waistDartRight)
+ .setRender(false)
+ paths.armhole = new Path()
+ .move(points.armhole)
+ .curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
+ .curve_(points.armholePitchCp2, points.shoulder)
+ .setRender(false)
+
+ paths.seam = new Path()
+ .move(points.waistDartRight)
+ .line(points.sideHem)
+ .line(points.armhole)
+ .join(paths.armhole)
+ .line(points.shoulderDartOutside)
+ .join(paths.princessSeam)
+ .close()
+ .attr('class', 'fabric')
+ } else {
+ paths.princessSeam = new Path()
+ .move(points.armholeDartOutside)
+ .curve(points.armholeCircleOutsideCp1, points.waistCircleOutsideCp1, points.waistUpDartRight)
+ .curve(points.waistUpDartRightCpDown, points.waistCpUp, points.waistDartRight)
+ .setRender(false)
+
+ paths.seam = new Path()
+ .move(points.waistDartRight)
+ .line(points.sideHem)
+ .line(points.armhole)
+ .join(paths.armholeOutside.reverse())
+ .join(paths.princessSeam)
+ .close()
+ .attr('class', 'fabric')
+ }
+
+ if (complete) {
+ points.snippet = paths.princessSeam.shiftAlong(paths.princessSeam.length() -store.get('shoulderDartTipNotch'))
+ snippets.shoulderDartTip = new Snippet('notch', points.snippet)
+
+ points.titleAnchor = points.waistDartRight
+ .shiftFractionTowards(points.armhole, 0.3)
+ .shiftFractionTowards(points.shoulderDartOutside, 0.2)
+ macro('title', {
+ at: points.titleAnchor,
+ nr: 2,
+ title: 'Outside Front',
+ })
+ points.grainTop = points.armhole.shift(225, 20)
+ points.grainBottom = points.sideHemInitial.shift(135, 20)
+
+ macro('grainline', {
+ from: points.grainBottom,
+ to: points.grainTop,
+ })
+
+ if (sa) paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
+
+ if(paperless) {
+ let pLeft = paths.princessSeam.edge('left')
+ macro('hd', {
+ from: points.waistDartRight,
+ to: points.armholeOutsidePitchCp1,
+ y: points.sideHemInitial.y +sa + 35,
+ })
+ macro('hd', {
+ from: points.waistDartRight,
+ to: points.sideHemInitial,
+ y: points.sideHemInitial.y +sa + 25,
+ })
+ macro('hd', {
+ from: pLeft,
+ to: points.sideHemInitial,
+ y: points.sideHemInitial.y +sa + 15,
+ })
+
+ macro('vd', {
+ from: points.armholeOutsidePitchCp1,
+ to: points.sideHemInitial,
+ x: points.sideHemInitial.x +sa + 15,
+ })
+ macro('vd', {
+ from: points.waistDartRight,
+ to: pLeft,
+ x: pLeft.x -sa - 15,
+ })
+
+ if( options.dartPosition == 'shoulder' ) {
+ macro('hd', {
+ from: points.shoulderDartOutside,
+ to: points.shoulder,
+ y: points.shoulderDartOutside.y -sa - 15,
+ })
+ macro('hd', {
+ from: points.snippet,
+ to: points.shoulder,
+ y: points.shoulderDartOutside.y -sa - 25,
+ })
+ macro('hd', {
+ from: pLeft,
+ to: points.shoulder,
+ y: points.shoulderDartOutside.y -sa - 35,
+ })
+ macro('hd', {
+ from: points.waistDartRight,
+ to: points.shoulder,
+ y: points.sideHemInitial.y +sa + 45,
+ })
+ macro('vd', {
+ from: points.shoulder,
+ to: points.sideHemInitial,
+ x: points.shoulder.x //+sa + 15,
+ })
+ macro('vd', {
+ from: points.shoulderDartOutside,
+ to: points.sideHemInitial,
+ x: points.shoulder.x +sa + 15,
+ })
+ macro('vd', {
+ from: points.waistDartRight,
+ to: points.shoulderDartOutside,
+ x: pLeft.x -sa - 25,
+ })
+ macro('vd', {
+ from: points.snippet,
+ to: points.shoulderDartOutside,
+ x: pLeft.x -sa - 15,
+ })
+
+ let pArmholeLeft = paths.armhole.edge('left')
+ macro('hd', {
+ from: points.waistDartRight,
+ to: pArmholeLeft,
+ y: points.sideHemInitial.y +sa +5,
+ })
+ macro('vd', {
+ from: pArmholeLeft,
+ to: points.sideHemInitial,
+ x: points.sideHemInitial.x +sa + 25,
+ })
+ } else {
+ let pTop = paths.princessSeam.edge('top')
+ macro('hd', {
+ from: pLeft,
+ to: points.armholeOutsidePitchCp1,
+ y: pTop.y -sa - 35,
+ })
+ macro('hd', {
+ from: pLeft,
+ to: points.armholeDartOutside,
+ y: pTop.y -sa - 25,
+ })
+ macro('hd', {
+ from: pLeft,
+ to: pTop,
+ y: pTop.y -sa - 15,
+ })
+ macro('vd', {
+ from: points.waistDartRight,
+ to: pTop,
+ x: pLeft.x -sa - 25,
+ })
+ macro('vd', {
+ from: points.snippet,
+ to: pTop,
+ x: pLeft.x -sa - 15,
+ })
+ macro('vd', {
+ from: points.armholeDartOutside,
+ to: points.sideHemInitial,
+ x: points.sideHemInitial.x +sa + 25,
+ })
+ macro('vd', {
+ from: pTop,
+ to: points.sideHemInitial,
+ x: points.sideHemInitial.x +sa + 35,
+ })
+ }
+ }
+ }
+
+ return part
+}
diff --git a/designs/noble/src/frontPoints.js b/designs/noble/src/frontPoints.js
new file mode 100644
index 00000000000..84d12245946
--- /dev/null
+++ b/designs/noble/src/frontPoints.js
@@ -0,0 +1,335 @@
+export default function (part) {
+ let {
+ utils,
+ store,
+ sa,
+ Point,
+ points,
+ Path,
+ paths,
+ Snippet,
+ snippets,
+ options,
+ measurements,
+ complete,
+ paperless,
+ macro,
+ } = part.shorthand()
+
+ const bCircle = 0.552284749831
+
+ // Hide Bella paths
+ for (let key of Object.keys(paths)) paths[key].render = false
+ for (let i in snippets) delete snippets[i]
+
+ //removing macros not required from Bella
+ delete points.titleAnchor
+ delete points.__titleNr
+ delete points.__titleName
+ delete points.__titlePattern
+ delete points.scaleboxAnchor
+ delete points.__scaleboxImperialBottomLeft
+ delete points.__scaleboxMetricBottomLeft
+ delete points.__scaleboxImperialTopLeft
+ delete points.__scaleboxMetricTopLeft
+ delete points.__scaleboxImperialTopRight
+ delete points.__scaleboxMetricTopRight
+ delete points.__scaleboxImperialBottomRight
+ delete points.__scaleboxMetricBottomRight
+ delete points.__scaleboxLead
+ delete points.__scaleboxTitle
+ delete points.__scaleboxText
+ delete points.__scaleboxLink
+ delete points.__scaleboxImperial
+ delete points.__scaleboxMetric
+
+ points.shoulderDartInside = points.hps.shiftFractionTowards(
+ points.shoulder,
+ (options.dartPosition == 'shoulder' ? options.shoulderDartPosition : .5)
+ )
+ points.orgShoulder = points.shoulder.clone()
+ points.orgArmhole = points.armhole.clone()
+ points.orgArmholeCp2 = points.armholeCp2.clone()
+ points.orgArmholePitch = points.armholePitch.clone()
+ points.orgArmholePitchCp1 = points.armholePitchCp1.clone()
+ points.orgArmholePitchCp2 = points.armholePitchCp2.clone()
+ let armholePath = new Path()
+ .move(points.shoulder)
+ ._curve(points.armholePitchCp2, points.armholePitch)
+ .curve(points.armholePitchCp1, points.armholeCp2, points.armhole)
+
+ points.armholeDartInside = armholePath.shiftFractionAlong(options.armholeDartPosition)
+ points.armholeDartOutside = points.armholeDartInside.clone()
+
+ // paths.armholeTemp = armholePath.clone().setRender(true).attr('class', 'lining')
+ let armholePaths = armholePath.split(points.armholeDartInside)
+
+ let armholePathInside = armholePaths[0].clone().setRender(false)
+ let armholePathOutside = armholePaths[1].clone().setRender(false)
+ let armholeDartAngle =
+ armholePathInside.reverse().shiftAlong(1).angle(armholePathOutside.shiftAlong(1)) - 90
+
+ points.armholeDartArmhole = points.armholeDartInside.shiftFractionTowards(
+ points.armholeDartOutside,
+ 0.5
+ )
+ points.armholeDartTip = points.armholeDartArmhole.shiftFractionTowards(
+ points.bust,
+ options.upperDartLength
+ )
+
+ points.armholeCircleInsideCp1 = points.armholeDartInside.shift(
+ armholeDartAngle,
+ bCircle * points.armholeDartInside.dist(points.armholeDartTip)
+ )
+ points.armholeCircleOutsideCp1 = points.armholeCircleInsideCp1.clone()
+
+ points.shoulderCp1 = armholePathInside.ops[1].cp1.clone()
+ points.armholeInsidePitch = armholePathInside.ops[1].to.clone()
+ points.armholeInsidePitchCp2 = armholePathInside.ops[1].cp2.clone()
+ if (armholePathInside.ops.length == 2) {
+ points.armholeInsidePitchCp1 = points.armholeDartInside.clone()
+ points.armholeDartInsideCp2 = points.armholeDartInside.clone()
+ } else {
+ points.armholeInsidePitchCp1 = armholePathInside.ops[2].cp1.clone()
+ points.armholeDartInsideCp2 = armholePathInside.ops[2].cp2.clone()
+ }
+ points.armholeDartOutsideCp1 = armholePathOutside.ops[1].cp1.clone()
+ points.armholeOutsidePitch = armholePathOutside.ops[1].to.clone()
+ points.armholeOutsidePitchCp2 = armholePathOutside.ops[1].cp2.clone()
+ if (armholePathOutside.ops.length == 2) {
+ points.armholeOutsidePitchCp1 = points.armhole.clone()
+ points.armholeCp2 = points.armhole.clone()
+ } else {
+ points.armholeOutsidePitchCp1 = armholePathOutside.ops[2].cp1.clone()
+ points.armholeCp2 = armholePathOutside.ops[2].cp2.clone()
+ }
+
+ if( points.armholeDartInside.sitsRoughlyOn( points.armholeInsidePitch ) ) {
+ paths.armholeInside = new Path()
+ .move(points.armholeDartInside)
+ .curve(points.armholeInsidePitchCp2, points.shoulderCp1, points.shoulder)
+ .setRender(false)
+ } else {
+ paths.armholeInside = new Path()
+ .move(points.armholeDartInside)
+ .curve(points.armholeDartInsideCp2, points.armholeInsidePitchCp1, points.armholeInsidePitch)
+ .curve(points.armholeInsidePitchCp2, points.shoulderCp1, points.shoulder)
+ .setRender(false)
+ }
+
+ let rotateAngle =
+ points.shoulderDartInside.angle(points.bustA) - points.bustDartTop.angle(points.bustA)
+ if (rotateAngle < 0) {
+ rotateAngle += 360
+ }
+ if (rotateAngle > 360) {
+ rotateAngle -= 360
+ }
+
+ points.shoulderDartCpTop = points.bustDartCpTop.rotate(rotateAngle, points.bustA)
+ points.shoulderDartCpBottom = points.bustDartCpBottom.rotate(rotateAngle, points.bustA)
+
+ rotateAngle =
+ points.armholeDartInside.angle(points.bustA) - points.bustDartTop.angle(points.bustA)
+ if (rotateAngle < 0) {
+ rotateAngle += 360
+ }
+ if (rotateAngle > 360) {
+ rotateAngle -= 360
+ }
+
+ points.armholeDartCpTop = points.bustDartCpTop.rotate(rotateAngle, points.bustA)
+ points.armholeDartCpBottom = points.bustDartCpBottom.rotate(rotateAngle, points.bustA)
+
+ let spreadAngle =
+ /*360 -*/ points.bustA.angle(points.bustDartBottom) - points.bustA.angle(points.bustDartTop)
+
+ points.shoulderDartOutside = points.shoulderDartInside.rotate(spreadAngle, points.bustA)
+ points.shoulderDartShoulder = points.shoulderDartInside.shiftFractionTowards(
+ points.shoulderDartOutside,
+ 0.5
+ )
+
+ points.shoulderDartTip = points.shoulderDartShoulder.shiftFractionTowards(
+ points.bust,
+ options.upperDartLength
+ )
+ let dartRatio =
+ new Path().move(points.waistDartHem).line(points.waistDartTip).length() /
+ new Path().move(points.shoulderDartShoulder).line(points.shoulderDartTip).length()
+
+ points.shoulder = points.shoulder.rotate(spreadAngle, points.bustA)
+ points.armhole = points.armhole.rotate(spreadAngle, points.bustA)
+ points.armholeCp2 = points.armholeCp2.rotate(spreadAngle, points.bustA)
+ points.armholePitch = points.armholePitch.rotate(spreadAngle, points.bustA)
+ points.armholePitchCp1 = points.armholePitchCp1.rotate(spreadAngle, points.bustA)
+ points.armholePitchCp2 = points.armholePitchCp2.rotate(spreadAngle, points.bustA)
+ points.armholeCircleOutsideCp1 = points.armholeCircleOutsideCp1.rotate(spreadAngle, points.bustA)
+ points.armholeDartOutside = points.armholeDartOutside.rotate(spreadAngle, points.bustA)
+ points.armholeDartOutsideCp1 = points.armholeDartOutsideCp1.rotate(spreadAngle, points.bustA)
+ points.armholeOutsidePitchCp2 = points.armholeOutsidePitchCp2.rotate(spreadAngle, points.bustA)
+ points.armholeOutsidePitch = points.armholeOutsidePitch.rotate(spreadAngle, points.bustA)
+ points.armholeOutsidePitchCp1 = points.armholeOutsidePitchCp1.rotate(spreadAngle, points.bustA)
+
+ if( points.armhole.sitsRoughlyOn( points.armholeOutsidePitch ) ) {
+ paths.armholeOutside = new Path()
+ .move(points.armholeDartOutside)
+ .curve(points.armholeDartOutsideCp1, points.armholeOutsidePitchCp2, points.armhole)
+ .setRender(false)
+ } else {
+ paths.armholeOutside = new Path()
+ .move(points.armholeDartOutside)
+ .curve(points.armholeDartOutsideCp1, points.armholeOutsidePitchCp2, points.armholeOutsidePitch)
+ .curve(points.armholeOutsidePitchCp1, points.armholeCp2, points.armhole)
+ .setRender(false)
+ }
+
+ paths.armholeTempDart = new Path()
+ .move(points.armholeDartOutside)
+ ._curve(points.armholeDartCpBottom, points.armholeDartTip)
+ .curve_(points.armholeDartCpTop, points.armholeDartInside)
+ .setRender(false)
+
+ points.shoulderDartTipCpDownOutside = points.shoulderDartOutside.shiftFractionTowards(
+ points.bust,
+ 1 + (1 - options.upperDartLength) + (1 - options.waistDartLength) * dartRatio
+ )
+ // points.shoulderDartTipCpDownOutside = points.shoulderDartTipCpDownOutside.rotate( options.dartOutsideCP *10, points.shoulderDartOutside )
+
+ points.shoulderDartTipCpDownInside = points.shoulderDartInside.shiftFractionTowards(
+ points.shoulderDartTip,
+ 1 + (1 - options.upperDartLength) + (1 - options.waistDartLength) * dartRatio
+ )
+ points.armholeDartTipCpDownInside = points.armholeDartTip.shiftFractionTowards(
+ // points.waistDartHem,
+ points.waistDartLeft,
+ 1 - options.upperDartLength + (1 - options.waistDartLength) * dartRatio
+ )
+
+ points.bustAcp = points.waistDartRight.shiftOutwards(points.bustA, 10)
+
+ paths.shoulderInsideSeam = new Path()
+ .move(points.waistDartLeft)
+ .curve(points.waistDartLeftCp, points.shoulderDartTipCpDownInside, points.shoulderDartTip)
+ .line(points.shoulderDartInside)
+ .setRender(false)
+
+ paths.armholeInsideSeam = new Path()
+ .move(points.waistDartLeft)
+ .curve(points.waistDartLeftCp, points.armholeDartTipCpDownInside, points.armholeDartTip)
+ .setRender(false)
+
+ paths.sOutsideSeam = new Path()
+ .move(points.waistDartRight)
+ .curve(points.bustAcp, points.shoulderDartTipCpDownOutside, points.shoulderDartOutside)
+ .setRender(false)
+
+ points.waistDartRightCp = points.bustAcp.clone()
+
+ let shoulderInsideSeam = new Path()
+ .move(points.waistDartLeft)
+ .curve(points.waistDartLeftCp, points.shoulderDartTipCpDownInside, points.shoulderDartTip)
+ .line(points.shoulderDartInside)
+ .setRender(false)
+
+ points.waistUpDartLeft = paths.armholeInsideSeam.shiftAlong(
+ points.waistDartLeft.dist(points.armholeDartTip) * 0.5
+ )
+ points.waistCircleInsideCp1 = points.waistUpDartLeft.shiftTowards(
+ points.waistDartLeft,
+ -0.5 * bCircle * points.armholeDartOutside.dist(points.armholeDartTip)
+ )
+ points.shoulderDartTipCpDownOutside = points.shoulderDartTipCpDownOutside
+ .rotate(-2.5, points.shoulderDartOutside)
+ .shiftFractionTowards(points.shoulderDartOutside, 0.2)
+
+ let lInside = shoulderInsideSeam.length()
+ let iteration = 1
+ let diff = 0
+ do {
+ points.waistDartRight = points.waistDartRight.rotate(diff * 0.1, points.sideHemInitial)
+
+ let outsideSeam = new Path()
+ .move(points.waistDartRight)
+ .curve(points.bustAcp, points.shoulderDartTipCpDownOutside, points.shoulderDartOutside)
+
+ points.waistUpDartRight = outsideSeam.shiftAlong(
+ points.waistDartRight.dist(points.waistDartRightCp) * 0.5
+ )
+ points.waistUpDartRightCpDown = points.waistUpDartRight.shiftFractionTowards(
+ points.waistDartRight,
+ 0.25
+ )
+ // points.waistUpDartRightCpUp = points.waistUpDartRight.shiftFractionTowards( points.waistDartRight, -.25 )
+ points.waistUpDartRightCpUp = points.waistUpDartRight.shiftFractionTowards(
+ points.waistDartRight,
+ -0.6
+ )
+ points.waistCpUp = points.waistDartRight
+ .shiftTowards(
+ points.sideHemInitial,
+ points.waistDartRight.dist(points.waistUpDartRight) * 0.25
+ )
+ .rotate(90, points.waistDartRight)
+ points.waistCircleInsideCp1 = points.armholeDartTip.shiftTowards(
+ points.armholeDartTipCpDownInside,
+ -0.5 * bCircle * points.armholeDartInside.dist(points.armholeDartTip)
+ )
+
+ outsideSeam = new Path()
+ .move(points.waistDartRight)
+ .curve(points.waistCpUp, points.waistUpDartRightCpDown, points.waistUpDartRight)
+ .curve(
+ points.waistUpDartRightCpUp,
+ points.shoulderDartTipCpDownOutside,
+ points.shoulderDartOutside
+ )
+
+ diff = shoulderInsideSeam.length() - outsideSeam.length()
+ iteration++
+ } while ((diff > 1 || diff < -1) && iteration < 200)
+ if (iteration >= 200) {
+ raise.error('Something is not quite right here!')
+ }
+ points.waistDartRightCp = points.bustAcp.clone()
+ points.armholeDartTipInside = points.armholeDartTip.clone()
+ points.waistCircleOutsideCp1 = points.waistUpDartRight.shiftTowards(
+ points.waistDartRight,
+ -1 * bCircle * points.armholeDartOutside.dist(points.armholeDartTip)
+ )
+
+ diff = 0
+ iteration = 0
+ do {
+ let dist = points.armholeDartTipInside.dist(points.armholeDartTipCpDownInside)
+ if( points.armholeDartTipInside.x > points.waistCircleOutsideCp1 ) {
+ points.armholeDartTipInside.x = points.armholeDartTipInside.x -.5
+ points.armholeDartTipInside.y = points.armholeDartTipInside.y +.5
+ } else {
+ points.waistCircleOutsideCp1 = points.waistCircleOutsideCp1.shiftTowards( points.waistUpDartRight, diff > 0 ? 1 :-1 )
+ }
+ points.armholeDartTipCpDownInside = points.waistCircleInsideCp1.shiftOutwards(points.armholeDartTipInside, dist)
+
+ paths.armholeTempCircleOutside = new Path()
+ .move(points.armholeDartOutside)
+ .curve(points.armholeCircleOutsideCp1, points.waistCircleOutsideCp1, points.waistUpDartRight)
+ .curve(points.waistUpDartRightCpDown, points.waistCpUp, points.waistDartRight)
+ .setRender(false)
+ .attr('class', 'lining')
+ paths.armholeTempCircleInside = new Path()
+ .move(points.armholeDartInside)
+ .curve(points.armholeCircleInsideCp1, points.waistCircleInsideCp1, points.armholeDartTipInside)
+ .curve(points.armholeDartTipCpDownInside, points.waistDartLeftCp, points.waistDartLeft)
+ .setRender(false)
+ .attr('class', 'lining')
+
+ diff = paths.armholeTempCircleOutside.length() - paths.armholeTempCircleInside.length()
+ iteration ++
+ } while( (diff < -1 || diff > 1) && iteration < 200 )
+ if (iteration >= 200) {
+ raise.error('Something is not quite right here!')
+ }
+
+ return part
+}
diff --git a/designs/noble/src/index.js b/designs/noble/src/index.js
new file mode 100644
index 00000000000..f6a2400d722
--- /dev/null
+++ b/designs/noble/src/index.js
@@ -0,0 +1,33 @@
+import freesewing from '@freesewing/core'
+import Bella from '@freesewing/bella'
+import bundle from '@freesewing/plugin-bundle'
+import config from '../config'
+// Parts
+import draftBackPoints from './backPoints'
+import draftBackInside from './backInside'
+import draftBackOutside from './backOutside'
+import draftFrontPoints from './frontPoints'
+import draftFrontInside from './frontInside'
+import draftFrontOutside from './frontOutside'
+
+// Create design
+const Noble = new freesewing.Design(config, bundle)
+
+// Attach draft methods to prototype
+Noble.prototype.draftBellaBack = function (part) {
+ return new Bella(this.settings).draftBack(part)
+}
+Noble.prototype.draftBellaFrontSideDart = function (part) {
+ return new Bella(this.settings).draftFrontSideDart(part)
+}
+
+Noble.prototype.draftBackPoints = draftBackPoints
+Noble.prototype.draftBackInside = draftBackInside
+Noble.prototype.draftBackOutside = draftBackOutside
+Noble.prototype.draftFrontPoints = draftFrontPoints
+Noble.prototype.draftFrontInside = draftFrontInside
+Noble.prototype.draftFrontOutside = draftFrontOutside
+
+export { config, Noble }
+
+export default Noble
diff --git a/markdown/org/docs/patterns/hi/cutting/de.md b/markdown/org/docs/patterns/hi/cutting/de.md
new file mode 100644
index 00000000000..75e5239d2b5
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/cutting/de.md
@@ -0,0 +1,14 @@
+---
+title: "Hi shark plush toy: Cutting Instructions"
+---
+
+- **Main fabric**
+ - Cut **2 Body (color 1)**
+ - Cut **1 Belly (color 2)**
+ - Cut **2 Tail (color 1)**
+ - Cut **1 Mouth (color 3)**
+ - Cut **2 Above Mouth (color 2)**
+ - Cut **2 Top Fin (color 1)**
+ - Cut **2 Bottom Fin (color 1)**
+ - Cut **1 Upper Teeth (fabric 2)**
+ - Cut **1 Lower Teeth (fabric 2)**
diff --git a/markdown/org/docs/patterns/hi/cutting/es.md b/markdown/org/docs/patterns/hi/cutting/es.md
new file mode 100644
index 00000000000..75e5239d2b5
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/cutting/es.md
@@ -0,0 +1,14 @@
+---
+title: "Hi shark plush toy: Cutting Instructions"
+---
+
+- **Main fabric**
+ - Cut **2 Body (color 1)**
+ - Cut **1 Belly (color 2)**
+ - Cut **2 Tail (color 1)**
+ - Cut **1 Mouth (color 3)**
+ - Cut **2 Above Mouth (color 2)**
+ - Cut **2 Top Fin (color 1)**
+ - Cut **2 Bottom Fin (color 1)**
+ - Cut **1 Upper Teeth (fabric 2)**
+ - Cut **1 Lower Teeth (fabric 2)**
diff --git a/markdown/org/docs/patterns/hi/cutting/fr.md b/markdown/org/docs/patterns/hi/cutting/fr.md
new file mode 100644
index 00000000000..75e5239d2b5
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/cutting/fr.md
@@ -0,0 +1,14 @@
+---
+title: "Hi shark plush toy: Cutting Instructions"
+---
+
+- **Main fabric**
+ - Cut **2 Body (color 1)**
+ - Cut **1 Belly (color 2)**
+ - Cut **2 Tail (color 1)**
+ - Cut **1 Mouth (color 3)**
+ - Cut **2 Above Mouth (color 2)**
+ - Cut **2 Top Fin (color 1)**
+ - Cut **2 Bottom Fin (color 1)**
+ - Cut **1 Upper Teeth (fabric 2)**
+ - Cut **1 Lower Teeth (fabric 2)**
diff --git a/markdown/org/docs/patterns/hi/cutting/nl.md b/markdown/org/docs/patterns/hi/cutting/nl.md
new file mode 100644
index 00000000000..75e5239d2b5
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/cutting/nl.md
@@ -0,0 +1,14 @@
+---
+title: "Hi shark plush toy: Cutting Instructions"
+---
+
+- **Main fabric**
+ - Cut **2 Body (color 1)**
+ - Cut **1 Belly (color 2)**
+ - Cut **2 Tail (color 1)**
+ - Cut **1 Mouth (color 3)**
+ - Cut **2 Above Mouth (color 2)**
+ - Cut **2 Top Fin (color 1)**
+ - Cut **2 Bottom Fin (color 1)**
+ - Cut **1 Upper Teeth (fabric 2)**
+ - Cut **1 Lower Teeth (fabric 2)**
diff --git a/markdown/org/docs/patterns/hi/de.md b/markdown/org/docs/patterns/hi/de.md
new file mode 100644
index 00000000000..a82acb3f955
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/de.md
@@ -0,0 +1,5 @@
+---
+title: "Hi shark plush toy"
+---
+
+
diff --git a/markdown/org/docs/patterns/hi/es.md b/markdown/org/docs/patterns/hi/es.md
new file mode 100644
index 00000000000..a82acb3f955
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/es.md
@@ -0,0 +1,5 @@
+---
+title: "Hi shark plush toy"
+---
+
+
diff --git a/markdown/org/docs/patterns/hi/fabric/de.md b/markdown/org/docs/patterns/hi/fabric/de.md
new file mode 100644
index 00000000000..7de74c74214
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/fabric/de.md
@@ -0,0 +1,15 @@
+---
+title: "Hi shark plush toy: Fabric Options"
+---
+
+This plush toy is intended to have two different coloured fabrics, one for the upper body, and one for the belly. The mouth should probably have its own colour fabric. Most plush toys have some sort of a faux fur fabric.
+
+Fabrics with a two-way stretch work better than wovens. The stretch should be perpendicular to the grainline.
+
+## Teeth
+
+The teeth have untreated ends, so should be made from a fabric that does not unravel.
+
+## Stuffing
+
+Since this is a pluch toy, it wil need to be stuffed with material.
\ No newline at end of file
diff --git a/markdown/org/docs/patterns/hi/fabric/es.md b/markdown/org/docs/patterns/hi/fabric/es.md
new file mode 100644
index 00000000000..7de74c74214
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/fabric/es.md
@@ -0,0 +1,15 @@
+---
+title: "Hi shark plush toy: Fabric Options"
+---
+
+This plush toy is intended to have two different coloured fabrics, one for the upper body, and one for the belly. The mouth should probably have its own colour fabric. Most plush toys have some sort of a faux fur fabric.
+
+Fabrics with a two-way stretch work better than wovens. The stretch should be perpendicular to the grainline.
+
+## Teeth
+
+The teeth have untreated ends, so should be made from a fabric that does not unravel.
+
+## Stuffing
+
+Since this is a pluch toy, it wil need to be stuffed with material.
\ No newline at end of file
diff --git a/markdown/org/docs/patterns/hi/fabric/fr.md b/markdown/org/docs/patterns/hi/fabric/fr.md
new file mode 100644
index 00000000000..7de74c74214
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/fabric/fr.md
@@ -0,0 +1,15 @@
+---
+title: "Hi shark plush toy: Fabric Options"
+---
+
+This plush toy is intended to have two different coloured fabrics, one for the upper body, and one for the belly. The mouth should probably have its own colour fabric. Most plush toys have some sort of a faux fur fabric.
+
+Fabrics with a two-way stretch work better than wovens. The stretch should be perpendicular to the grainline.
+
+## Teeth
+
+The teeth have untreated ends, so should be made from a fabric that does not unravel.
+
+## Stuffing
+
+Since this is a pluch toy, it wil need to be stuffed with material.
\ No newline at end of file
diff --git a/markdown/org/docs/patterns/hi/fabric/nl.md b/markdown/org/docs/patterns/hi/fabric/nl.md
new file mode 100644
index 00000000000..7de74c74214
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/fabric/nl.md
@@ -0,0 +1,15 @@
+---
+title: "Hi shark plush toy: Fabric Options"
+---
+
+This plush toy is intended to have two different coloured fabrics, one for the upper body, and one for the belly. The mouth should probably have its own colour fabric. Most plush toys have some sort of a faux fur fabric.
+
+Fabrics with a two-way stretch work better than wovens. The stretch should be perpendicular to the grainline.
+
+## Teeth
+
+The teeth have untreated ends, so should be made from a fabric that does not unravel.
+
+## Stuffing
+
+Since this is a pluch toy, it wil need to be stuffed with material.
\ No newline at end of file
diff --git a/markdown/org/docs/patterns/hi/fr.md b/markdown/org/docs/patterns/hi/fr.md
new file mode 100644
index 00000000000..a82acb3f955
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/fr.md
@@ -0,0 +1,5 @@
+---
+title: "Hi shark plush toy"
+---
+
+
diff --git a/markdown/org/docs/patterns/hi/instructions/de.md b/markdown/org/docs/patterns/hi/instructions/de.md
new file mode 100644
index 00000000000..0383e04a384
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/instructions/de.md
@@ -0,0 +1,28 @@
+---
+title: "Hi shark plush toy: Sewing Instructions"
+---
+
+## Notes and tips
+
+When you're using fabric with some stretch in it, it is a good idea to stabilize the seams that go along the whole body, and between the body and the belly, with some stabilizing ribbon.
+
+### Body
+
+Sew the darts on the front of the body closed. Trim away any excess fabric. Sew the tail pieces to the body, matching the notches. Sew the topFin pieces to the body. Sew both parts together, leaving an area below the tail open for stuffing the shark later.
+
+### Belly
+
+Sew the two aboveMouth pieces together along the larger straight side. Sew the teeth to the mouth, matching notches. Sew the darts on the belly, trim away any excess fabric. Sew the aboveMouth pieces to the mouth, matching notches. Sew all of this to the belly piece, matching notches. Sew the bottomFin pieces to the belly, matching notches.
+
+### Completing
+
+Sew the belly to the body, matching the front, back, and fins.
+
+### Filling
+
+Fill the plush toy with stuffing through the opening you left in the tail. Make sure to fill the tail and fins well before adding too much stuffing in the body itself.
+
+Close the toy by hand stitching.
+
+
+
diff --git a/markdown/org/docs/patterns/hi/instructions/es.md b/markdown/org/docs/patterns/hi/instructions/es.md
new file mode 100644
index 00000000000..0383e04a384
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/instructions/es.md
@@ -0,0 +1,28 @@
+---
+title: "Hi shark plush toy: Sewing Instructions"
+---
+
+## Notes and tips
+
+When you're using fabric with some stretch in it, it is a good idea to stabilize the seams that go along the whole body, and between the body and the belly, with some stabilizing ribbon.
+
+### Body
+
+Sew the darts on the front of the body closed. Trim away any excess fabric. Sew the tail pieces to the body, matching the notches. Sew the topFin pieces to the body. Sew both parts together, leaving an area below the tail open for stuffing the shark later.
+
+### Belly
+
+Sew the two aboveMouth pieces together along the larger straight side. Sew the teeth to the mouth, matching notches. Sew the darts on the belly, trim away any excess fabric. Sew the aboveMouth pieces to the mouth, matching notches. Sew all of this to the belly piece, matching notches. Sew the bottomFin pieces to the belly, matching notches.
+
+### Completing
+
+Sew the belly to the body, matching the front, back, and fins.
+
+### Filling
+
+Fill the plush toy with stuffing through the opening you left in the tail. Make sure to fill the tail and fins well before adding too much stuffing in the body itself.
+
+Close the toy by hand stitching.
+
+
+
diff --git a/markdown/org/docs/patterns/hi/instructions/fr.md b/markdown/org/docs/patterns/hi/instructions/fr.md
new file mode 100644
index 00000000000..0383e04a384
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/instructions/fr.md
@@ -0,0 +1,28 @@
+---
+title: "Hi shark plush toy: Sewing Instructions"
+---
+
+## Notes and tips
+
+When you're using fabric with some stretch in it, it is a good idea to stabilize the seams that go along the whole body, and between the body and the belly, with some stabilizing ribbon.
+
+### Body
+
+Sew the darts on the front of the body closed. Trim away any excess fabric. Sew the tail pieces to the body, matching the notches. Sew the topFin pieces to the body. Sew both parts together, leaving an area below the tail open for stuffing the shark later.
+
+### Belly
+
+Sew the two aboveMouth pieces together along the larger straight side. Sew the teeth to the mouth, matching notches. Sew the darts on the belly, trim away any excess fabric. Sew the aboveMouth pieces to the mouth, matching notches. Sew all of this to the belly piece, matching notches. Sew the bottomFin pieces to the belly, matching notches.
+
+### Completing
+
+Sew the belly to the body, matching the front, back, and fins.
+
+### Filling
+
+Fill the plush toy with stuffing through the opening you left in the tail. Make sure to fill the tail and fins well before adding too much stuffing in the body itself.
+
+Close the toy by hand stitching.
+
+
+
diff --git a/markdown/org/docs/patterns/hi/instructions/nl.md b/markdown/org/docs/patterns/hi/instructions/nl.md
new file mode 100644
index 00000000000..0383e04a384
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/instructions/nl.md
@@ -0,0 +1,28 @@
+---
+title: "Hi shark plush toy: Sewing Instructions"
+---
+
+## Notes and tips
+
+When you're using fabric with some stretch in it, it is a good idea to stabilize the seams that go along the whole body, and between the body and the belly, with some stabilizing ribbon.
+
+### Body
+
+Sew the darts on the front of the body closed. Trim away any excess fabric. Sew the tail pieces to the body, matching the notches. Sew the topFin pieces to the body. Sew both parts together, leaving an area below the tail open for stuffing the shark later.
+
+### Belly
+
+Sew the two aboveMouth pieces together along the larger straight side. Sew the teeth to the mouth, matching notches. Sew the darts on the belly, trim away any excess fabric. Sew the aboveMouth pieces to the mouth, matching notches. Sew all of this to the belly piece, matching notches. Sew the bottomFin pieces to the belly, matching notches.
+
+### Completing
+
+Sew the belly to the body, matching the front, back, and fins.
+
+### Filling
+
+Fill the plush toy with stuffing through the opening you left in the tail. Make sure to fill the tail and fins well before adding too much stuffing in the body itself.
+
+Close the toy by hand stitching.
+
+
+
diff --git a/markdown/org/docs/patterns/hi/measurements/de.md b/markdown/org/docs/patterns/hi/measurements/de.md
new file mode 100644
index 00000000000..01f880d9bff
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/measurements/de.md
@@ -0,0 +1,5 @@
+---
+title: "Hi shark plush toy: Required Measurements"
+---
+
+
diff --git a/markdown/org/docs/patterns/hi/measurements/es.md b/markdown/org/docs/patterns/hi/measurements/es.md
new file mode 100644
index 00000000000..01f880d9bff
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/measurements/es.md
@@ -0,0 +1,5 @@
+---
+title: "Hi shark plush toy: Required Measurements"
+---
+
+
diff --git a/markdown/org/docs/patterns/hi/measurements/fr.md b/markdown/org/docs/patterns/hi/measurements/fr.md
new file mode 100644
index 00000000000..01f880d9bff
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/measurements/fr.md
@@ -0,0 +1,5 @@
+---
+title: "Hi shark plush toy: Required Measurements"
+---
+
+
diff --git a/markdown/org/docs/patterns/hi/measurements/nl.md b/markdown/org/docs/patterns/hi/measurements/nl.md
new file mode 100644
index 00000000000..01f880d9bff
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/measurements/nl.md
@@ -0,0 +1,5 @@
+---
+title: "Hi shark plush toy: Required Measurements"
+---
+
+
diff --git a/markdown/org/docs/patterns/hi/needs/de.md b/markdown/org/docs/patterns/hi/needs/de.md
new file mode 100644
index 00000000000..87dbb0364ea
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/needs/de.md
@@ -0,0 +1,12 @@
+---
+title: "Hi shark plush toy: What You Need"
+---
+
+To make Hi, you will need the following:
+
+- Basic sewing supplies
+- About 1 meters of a suitable fabric in color 1 (body)
+- About 0.5 meters of a suitable fabric in color 2 (belly)
+- Small piece for the mouth
+- Suitable, unraveling, fabric for the teeth
+- Stuffing
diff --git a/markdown/org/docs/patterns/hi/needs/es.md b/markdown/org/docs/patterns/hi/needs/es.md
new file mode 100644
index 00000000000..87dbb0364ea
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/needs/es.md
@@ -0,0 +1,12 @@
+---
+title: "Hi shark plush toy: What You Need"
+---
+
+To make Hi, you will need the following:
+
+- Basic sewing supplies
+- About 1 meters of a suitable fabric in color 1 (body)
+- About 0.5 meters of a suitable fabric in color 2 (belly)
+- Small piece for the mouth
+- Suitable, unraveling, fabric for the teeth
+- Stuffing
diff --git a/markdown/org/docs/patterns/hi/needs/fr.md b/markdown/org/docs/patterns/hi/needs/fr.md
new file mode 100644
index 00000000000..87dbb0364ea
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/needs/fr.md
@@ -0,0 +1,12 @@
+---
+title: "Hi shark plush toy: What You Need"
+---
+
+To make Hi, you will need the following:
+
+- Basic sewing supplies
+- About 1 meters of a suitable fabric in color 1 (body)
+- About 0.5 meters of a suitable fabric in color 2 (belly)
+- Small piece for the mouth
+- Suitable, unraveling, fabric for the teeth
+- Stuffing
diff --git a/markdown/org/docs/patterns/hi/needs/nl.md b/markdown/org/docs/patterns/hi/needs/nl.md
new file mode 100644
index 00000000000..87dbb0364ea
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/needs/nl.md
@@ -0,0 +1,12 @@
+---
+title: "Hi shark plush toy: What You Need"
+---
+
+To make Hi, you will need the following:
+
+- Basic sewing supplies
+- About 1 meters of a suitable fabric in color 1 (body)
+- About 0.5 meters of a suitable fabric in color 2 (belly)
+- Small piece for the mouth
+- Suitable, unraveling, fabric for the teeth
+- Stuffing
diff --git a/markdown/org/docs/patterns/hi/nl.md b/markdown/org/docs/patterns/hi/nl.md
new file mode 100644
index 00000000000..a82acb3f955
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/nl.md
@@ -0,0 +1,5 @@
+---
+title: "Hi shark plush toy"
+---
+
+
diff --git a/markdown/org/docs/patterns/hi/options/aggressive/de.md b/markdown/org/docs/patterns/hi/options/aggressive/de.md
new file mode 100644
index 00000000000..10babd72eca
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/aggressive/de.md
@@ -0,0 +1,5 @@
+---
+title: "Aggressive"
+---
+
+Your Hi can come in the default sweet form, or in a more aggressive version with more authentic teeth, and a mean look.
\ No newline at end of file
diff --git a/markdown/org/docs/patterns/hi/options/aggressive/es.md b/markdown/org/docs/patterns/hi/options/aggressive/es.md
new file mode 100644
index 00000000000..10babd72eca
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/aggressive/es.md
@@ -0,0 +1,5 @@
+---
+title: "Aggressive"
+---
+
+Your Hi can come in the default sweet form, or in a more aggressive version with more authentic teeth, and a mean look.
\ No newline at end of file
diff --git a/markdown/org/docs/patterns/hi/options/aggressive/fr.md b/markdown/org/docs/patterns/hi/options/aggressive/fr.md
new file mode 100644
index 00000000000..10babd72eca
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/aggressive/fr.md
@@ -0,0 +1,5 @@
+---
+title: "Aggressive"
+---
+
+Your Hi can come in the default sweet form, or in a more aggressive version with more authentic teeth, and a mean look.
\ No newline at end of file
diff --git a/markdown/org/docs/patterns/hi/options/aggressive/nl.md b/markdown/org/docs/patterns/hi/options/aggressive/nl.md
new file mode 100644
index 00000000000..10babd72eca
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/aggressive/nl.md
@@ -0,0 +1,5 @@
+---
+title: "Aggressive"
+---
+
+Your Hi can come in the default sweet form, or in a more aggressive version with more authentic teeth, and a mean look.
\ No newline at end of file
diff --git a/markdown/org/docs/patterns/hi/options/de.md b/markdown/org/docs/patterns/hi/options/de.md
new file mode 100644
index 00000000000..e51f491e2e5
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/de.md
@@ -0,0 +1,5 @@
+---
+title: "Hi shark plush toy: Design Options"
+---
+
+
diff --git a/markdown/org/docs/patterns/hi/options/es.md b/markdown/org/docs/patterns/hi/options/es.md
new file mode 100644
index 00000000000..e51f491e2e5
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/es.md
@@ -0,0 +1,5 @@
+---
+title: "Hi shark plush toy: Design Options"
+---
+
+
diff --git a/markdown/org/docs/patterns/hi/options/fr.md b/markdown/org/docs/patterns/hi/options/fr.md
new file mode 100644
index 00000000000..e51f491e2e5
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/fr.md
@@ -0,0 +1,5 @@
+---
+title: "Hi shark plush toy: Design Options"
+---
+
+
diff --git a/markdown/org/docs/patterns/hi/options/hungry/de.md b/markdown/org/docs/patterns/hi/options/hungry/de.md
new file mode 100644
index 00000000000..3a6d6df2648
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/hungry/de.md
@@ -0,0 +1,5 @@
+---
+title: "Hungry"
+---
+
+This setting determins how long it has been since your Hi has had something to eat. More hungry results in a leaner shark.
\ No newline at end of file
diff --git a/markdown/org/docs/patterns/hi/options/hungry/es.md b/markdown/org/docs/patterns/hi/options/hungry/es.md
new file mode 100644
index 00000000000..3a6d6df2648
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/hungry/es.md
@@ -0,0 +1,5 @@
+---
+title: "Hungry"
+---
+
+This setting determins how long it has been since your Hi has had something to eat. More hungry results in a leaner shark.
\ No newline at end of file
diff --git a/markdown/org/docs/patterns/hi/options/hungry/fr.md b/markdown/org/docs/patterns/hi/options/hungry/fr.md
new file mode 100644
index 00000000000..3a6d6df2648
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/hungry/fr.md
@@ -0,0 +1,5 @@
+---
+title: "Hungry"
+---
+
+This setting determins how long it has been since your Hi has had something to eat. More hungry results in a leaner shark.
\ No newline at end of file
diff --git a/markdown/org/docs/patterns/hi/options/hungry/nl.md b/markdown/org/docs/patterns/hi/options/hungry/nl.md
new file mode 100644
index 00000000000..3a6d6df2648
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/hungry/nl.md
@@ -0,0 +1,5 @@
+---
+title: "Hungry"
+---
+
+This setting determins how long it has been since your Hi has had something to eat. More hungry results in a leaner shark.
\ No newline at end of file
diff --git a/markdown/org/docs/patterns/hi/options/nl.md b/markdown/org/docs/patterns/hi/options/nl.md
new file mode 100644
index 00000000000..e51f491e2e5
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/nl.md
@@ -0,0 +1,5 @@
+---
+title: "Hi shark plush toy: Design Options"
+---
+
+
diff --git a/markdown/org/docs/patterns/hi/options/nosePointiness/de.md b/markdown/org/docs/patterns/hi/options/nosePointiness/de.md
new file mode 100644
index 00000000000..791624f2df8
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/nosePointiness/de.md
@@ -0,0 +1,5 @@
+---
+title: "Pointiness of the nose"
+---
+
+The shark can be made with a more blunt, or sharper nose, depending on your preference.
diff --git a/markdown/org/docs/patterns/hi/options/nosePointiness/es.md b/markdown/org/docs/patterns/hi/options/nosePointiness/es.md
new file mode 100644
index 00000000000..791624f2df8
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/nosePointiness/es.md
@@ -0,0 +1,5 @@
+---
+title: "Pointiness of the nose"
+---
+
+The shark can be made with a more blunt, or sharper nose, depending on your preference.
diff --git a/markdown/org/docs/patterns/hi/options/nosePointiness/fr.md b/markdown/org/docs/patterns/hi/options/nosePointiness/fr.md
new file mode 100644
index 00000000000..791624f2df8
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/nosePointiness/fr.md
@@ -0,0 +1,5 @@
+---
+title: "Pointiness of the nose"
+---
+
+The shark can be made with a more blunt, or sharper nose, depending on your preference.
diff --git a/markdown/org/docs/patterns/hi/options/nosePointiness/nl.md b/markdown/org/docs/patterns/hi/options/nosePointiness/nl.md
new file mode 100644
index 00000000000..791624f2df8
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/nosePointiness/nl.md
@@ -0,0 +1,5 @@
+---
+title: "Pointiness of the nose"
+---
+
+The shark can be made with a more blunt, or sharper nose, depending on your preference.
diff --git a/markdown/org/docs/patterns/hi/options/size/de.md b/markdown/org/docs/patterns/hi/options/size/de.md
new file mode 100644
index 00000000000..e295f842304
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/size/de.md
@@ -0,0 +1,5 @@
+---
+title: "Size"
+---
+
+Hi can be made in different sizes. The default is about a meter in length. This is a percentage of this default length.
diff --git a/markdown/org/docs/patterns/hi/options/size/es.md b/markdown/org/docs/patterns/hi/options/size/es.md
new file mode 100644
index 00000000000..e295f842304
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/size/es.md
@@ -0,0 +1,5 @@
+---
+title: "Size"
+---
+
+Hi can be made in different sizes. The default is about a meter in length. This is a percentage of this default length.
diff --git a/markdown/org/docs/patterns/hi/options/size/fr.md b/markdown/org/docs/patterns/hi/options/size/fr.md
new file mode 100644
index 00000000000..e295f842304
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/size/fr.md
@@ -0,0 +1,5 @@
+---
+title: "Size"
+---
+
+Hi can be made in different sizes. The default is about a meter in length. This is a percentage of this default length.
diff --git a/markdown/org/docs/patterns/hi/options/size/nl.md b/markdown/org/docs/patterns/hi/options/size/nl.md
new file mode 100644
index 00000000000..e295f842304
--- /dev/null
+++ b/markdown/org/docs/patterns/hi/options/size/nl.md
@@ -0,0 +1,5 @@
+---
+title: "Size"
+---
+
+Hi can be made in different sizes. The default is about a meter in length. This is a percentage of this default length.
diff --git a/markdown/org/docs/patterns/noble/cutting/en.md b/markdown/org/docs/patterns/noble/cutting/en.md
new file mode 100644
index 00000000000..fa1a872a523
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/cutting/en.md
@@ -0,0 +1,36 @@
+---
+title: "Noble body block: Cutting Instructions"
+---
+
+**Main fabric**
+
+- Cut **1 Front Inside** part on the fold.
+- Cut **2 Front Outside** part.
+
+### Shoulder dart
+
+- Cut **2 Back Inside** part.
+- Cut **2 Back Outside** part.
+
+### Armhole dart
+
+- Cut **2 Back** part.
+
+These cutting instructions are just for the default Noble block. Adjust your cutting accordingly if you have/are making changes to the block.
+
+
+
+If you do not have someone to help pin you into Noble then you may find it easier to Cut 2 Front Inside parts with seam allowance and sew the backs up when constructing so you can pin in the front.
+
+
+
+
+
+###### Noble is a block, not a pattern
+
+A block is a basic shape on which other patterns are based.
+They are sometimes also called slopers, although purists will argue that a block and a sloper are different things.
+
+Blocks are typically not made as-is but rather serve as a basis for other patterns.
+
+
diff --git a/markdown/org/docs/patterns/noble/en.md b/markdown/org/docs/patterns/noble/en.md
new file mode 100644
index 00000000000..c531609f8ec
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/en.md
@@ -0,0 +1,5 @@
+---
+title: "Noble body block"
+---
+
+
diff --git a/markdown/org/docs/patterns/noble/fabric/en.md b/markdown/org/docs/patterns/noble/fabric/en.md
new file mode 100644
index 00000000000..731e8fab313
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/fabric/en.md
@@ -0,0 +1,18 @@
+---
+title: "Noble body block: Fabric Options"
+---
+
+If you are making a default Noble to see how it fits we recommend a fabric such as **Calico (Muslin)** or a cheaper fabric that matches the drape and stretch of the fabric you intend to make a finalised version of Noble with.
+
+You can use scraps of fabrics from your stash so don't worry about buying fabric specifically for Noble.
+
+
+
+###### Noble is a block, not a pattern
+
+A block is a basic shape on which other patterns are based.
+They are sometimes also called slopers, although purists will argue that a block and a sloper are different things.
+
+Blocks are typically not made as-is but rather serve as a basis for other patterns.
+
+
diff --git a/markdown/org/docs/patterns/noble/instructions/en.md b/markdown/org/docs/patterns/noble/instructions/en.md
new file mode 100644
index 00000000000..6d64c8808d7
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/instructions/en.md
@@ -0,0 +1,80 @@
+---
+title: "Noble body block: Sewing Instructions"
+---
+
+
+
+###### Noble is a block, not a pattern
+
+A block is a basic shape on which other patterns are based.
+They are sometimes also called slopers, although purists will argue that a block and a sloper are different things.
+
+Blocks are typically not made as-is but rather serve as a basis for other patterns so the instructions below will not go in depth about closures or finishes and are for the default Noble block.
+
+Noble is based on the Bella body block
+
+
+
+### Step 1: Mock-up Construction
+
+- Sew the front inside to the front outside, good sides together.
+
+### Shoulder seam
+
+- Sew the back inside to the back outside, good sides together.
+
+### Armhole seam
+
+- Close the back darts.
+
+### Both
+
+- Sew the front to the backs at the shoulders, good sides together.
+- Sew the front to the backs at the side seams, good sides together.
+
+
+
+If you are making adjustments you may wish to sew the seams wrong sides together to make them easier to adjust.
+
+
+
+### Step 2: Try it on
+
+- Try it on and check the fit by pinning the back closed whilst wearing it.
+- Make any alterations and try it on again.
+- Repeat until you are happy.
+
+
+
+If you do not have someone to help with pinning, you may find it easier to cut the front part in two with seam allowance rather than on a fold and sew the back seam up so that you can pin in the front when trying on.
+
+Keep an eye out for anything you keep doing whilst wearing the mock-up, are you pulling it down? Constantly adjusting the shoulder? etc. Things like these are signs of where the pattern may need adjusting.
+
+Sometimes you may need to wear the mock-up for an extended amount of time to get a better sense of the fit so don't be afraid to walk around in it for a couple of hours.
+
+
+
+
+
+Remember to treat Noble as a basis rather than a final product, so adjust what you need to get the desired look.
+For instance:
+
+- Change the neck line
+- Add/change the closure allowances
+- Alter the dart placements
+- Add a collar
+
+It is all up to you! Experiment and go forth!
+
+
+
+### Step 3: Make a paper pattern
+
+- Once happy with all your changes unpick your mockup and make a paper pattern based off of it.
+- Now you have a pattern you can use to produce a garment.
+
+
+
+It is best practice to make a paper pattern from the mock-up if you have made any alterations, as this will allow you to clean up any lines but also means you have a pattern that you can keep producing garments from.
+
+
diff --git a/markdown/org/docs/patterns/noble/measurements/en.md b/markdown/org/docs/patterns/noble/measurements/en.md
new file mode 100644
index 00000000000..008efce20e2
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/measurements/en.md
@@ -0,0 +1,5 @@
+---
+title: "Noble body block: Required Measurements"
+---
+
+
diff --git a/markdown/org/docs/patterns/noble/needs/en.md b/markdown/org/docs/patterns/noble/needs/en.md
new file mode 100644
index 00000000000..8c538112332
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/needs/en.md
@@ -0,0 +1,21 @@
+---
+title: "Noble body block: What You Need"
+---
+
+To make Noble, you will need the following:
+
+- Basic sewing supplies
+- About 0.5 metres (0.6 yards) of a suitable fabric ([see Noble Fabric options](/docs/patterns/noble/fabric/))
+
+This list is for a default Noble Block. If you have/are making changes to the block you may need to get additional items such as closures, binding etc.
+
+
+
+###### Noble is a block, not a pattern
+
+A block is a basic shape on which other patterns are based.
+They are sometimes also called slopers, although purists will argue that a block and a sloper are different things.
+
+Blocks are typically not made as-is but rather serve as a basis for other patterns.
+
+
diff --git a/markdown/org/docs/patterns/noble/options/armholedartposition/en.md b/markdown/org/docs/patterns/noble/options/armholedartposition/en.md
new file mode 100644
index 00000000000..1a0c11580f4
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/armholedartposition/en.md
@@ -0,0 +1,9 @@
+---
+title: "Armhole Dart Position"
+---
+
+---
+
+The **Armhole Dart Position** option allows you to move the position of the dart/princess seam.
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/armholedepth/en.md b/markdown/org/docs/patterns/noble/options/armholedepth/en.md
new file mode 100644
index 00000000000..428f856226d
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/armholedepth/en.md
@@ -0,0 +1,9 @@
+---
+title: "Armhole depth"
+---
+
+---
+
+The **armhole depth** option controls the depth of the armhole.
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/backarmholecurvature/en.md b/markdown/org/docs/patterns/noble/options/backarmholecurvature/en.md
new file mode 100644
index 00000000000..163088b2943
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/backarmholecurvature/en.md
@@ -0,0 +1,9 @@
+---
+title: "Back armhole curvature"
+---
+
+---
+
+The **back armhole curvature** option controls how much the armhole is scooped at out the bottom in the back.
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/backarmholepitchdepth/en.md b/markdown/org/docs/patterns/noble/options/backarmholepitchdepth/en.md
new file mode 100644
index 00000000000..24108f65bda
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/backarmholepitchdepth/en.md
@@ -0,0 +1,9 @@
+---
+title: "Back armhole pitch depth"
+---
+
+---
+
+The **back armhole pitch depth** option controls the vertical position of the armhole pitch point at the back.
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/backarmholeslant/en.md b/markdown/org/docs/patterns/noble/options/backarmholeslant/en.md
new file mode 100644
index 00000000000..59479228432
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/backarmholeslant/en.md
@@ -0,0 +1,9 @@
+---
+title: "Back armhole slant"
+---
+
+---
+
+The **back armhole slant** slightly rotates the armhole around the back pitch point.
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/backdartheight/en.md b/markdown/org/docs/patterns/noble/options/backdartheight/en.md
new file mode 100644
index 00000000000..15a443f28d8
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/backdartheight/en.md
@@ -0,0 +1,9 @@
+---
+title: "Back dart height"
+---
+
+---
+
+The **back dart height** option controls the height (length if you will) of the back dart.
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/backhemslope/en.md b/markdown/org/docs/patterns/noble/options/backhemslope/en.md
new file mode 100644
index 00000000000..eff831b263a
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/backhemslope/en.md
@@ -0,0 +1,9 @@
+---
+title: "Back hem slope"
+---
+
+---
+
+The **back hem slope** option controls the slope of the hem at the back.
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/backneckcutout/en.md b/markdown/org/docs/patterns/noble/options/backneckcutout/en.md
new file mode 100644
index 00000000000..749d3e90c6e
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/backneckcutout/en.md
@@ -0,0 +1,10 @@
+---
+title: "Back neck cutout"
+---
+
+---
+
+The **back neck cutout** option controls how far the neck opening is scooped out at the back.
+
+## Effect of this option on the pattern
+
diff --git a/markdown/org/docs/patterns/noble/options/bustdartcurve/en.md b/markdown/org/docs/patterns/noble/options/bustdartcurve/en.md
new file mode 100644
index 00000000000..6504bd99308
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/bustdartcurve/en.md
@@ -0,0 +1,10 @@
+---
+title: "Bust dart curve"
+---
+
+---
+
+The **bust dart curve** option controls the curvature of the bust dart.
+From straight to slightly curved.
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/bustdartlength/en.md b/markdown/org/docs/patterns/noble/options/bustdartlength/en.md
new file mode 100644
index 00000000000..40871394120
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/bustdartlength/en.md
@@ -0,0 +1,10 @@
+---
+title: "Bust dart length"
+---
+
+---
+
+The **bust dart length** option controls the length of the bust dart.
+The maximum length brings the dart all the way to the bust apex.
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/bustspanease/en.md b/markdown/org/docs/patterns/noble/options/bustspanease/en.md
new file mode 100644
index 00000000000..4e82fecb5e4
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/bustspanease/en.md
@@ -0,0 +1,11 @@
+---
+title: "Bust span ease"
+---
+
+---
+
+The **bust span ease** option controls how much ease is applied to the bust span.
+
+This will not add ease to the garment, but merely influence the bust point
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/chestease/en.md b/markdown/org/docs/patterns/noble/options/chestease/en.md
new file mode 100644
index 00000000000..dc88c6634cf
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/chestease/en.md
@@ -0,0 +1,9 @@
+---
+title: "Chest ease"
+---
+
+---
+
+The **chest ease** option controls the amount of ease at the fullest part of your chest.
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/en.md b/markdown/org/docs/patterns/noble/options/en.md
new file mode 100644
index 00000000000..ecdc9bbb1e4
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/en.md
@@ -0,0 +1,5 @@
+---
+title: "Bella body block: Design Options"
+---
+
+
diff --git a/markdown/org/docs/patterns/noble/options/frontarmholecurvature/en.md b/markdown/org/docs/patterns/noble/options/frontarmholecurvature/en.md
new file mode 100644
index 00000000000..d14ad8128e6
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/frontarmholecurvature/en.md
@@ -0,0 +1,9 @@
+---
+title: "Front armhole curvature"
+---
+
+---
+
+Controls how deep the armhole is scooped out at the front bottom
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/frontarmholepitchdepth/en.md b/markdown/org/docs/patterns/noble/options/frontarmholepitchdepth/en.md
new file mode 100644
index 00000000000..c513394b6e9
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/frontarmholepitchdepth/en.md
@@ -0,0 +1,9 @@
+---
+title: "Front armhole pitch depth"
+---
+
+---
+
+The **front armhole pitch depth** option controls the vertical position of the armhole pitch point at the front.
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/frontshoulderwidth/en.md b/markdown/org/docs/patterns/noble/options/frontshoulderwidth/en.md
new file mode 100644
index 00000000000..2eabe58a351
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/frontshoulderwidth/en.md
@@ -0,0 +1,9 @@
+---
+title: "Front shoulder width"
+---
+
+---
+
+The **front shoulder width** option controls the width of the shoulders at the front, relative to the back.
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/fullchesteasereduction/en.md b/markdown/org/docs/patterns/noble/options/fullchesteasereduction/en.md
new file mode 100644
index 00000000000..d912c4f27a7
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/fullchesteasereduction/en.md
@@ -0,0 +1,10 @@
+---
+title: "Full chest ease reduction"
+---
+
+---
+
+Allows you to independently reduce the ease around the chest to make it fit tight(er) in that area
+
+## Effect of this option on the pattern
+
diff --git a/markdown/org/docs/patterns/noble/options/highbustwidth/en.md b/markdown/org/docs/patterns/noble/options/highbustwidth/en.md
new file mode 100644
index 00000000000..f18b9cdb68f
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/highbustwidth/en.md
@@ -0,0 +1,9 @@
+---
+title: "High bust width"
+---
+
+---
+
+The **high bust width** option allows you to tweak the high bust width at the front.
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/shoulderdartposition/en.md b/markdown/org/docs/patterns/noble/options/shoulderdartposition/en.md
new file mode 100644
index 00000000000..3d9b9bbcf76
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/shoulderdartposition/en.md
@@ -0,0 +1,9 @@
+---
+title: "Shoulder Dart Position"
+---
+
+---
+
+The **Shoulder Dart Position** option allows you to move the position of the dart/princess seam.
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/shouldertoshoulderease/en.md b/markdown/org/docs/patterns/noble/options/shouldertoshoulderease/en.md
new file mode 100644
index 00000000000..ea161d3eeec
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/shouldertoshoulderease/en.md
@@ -0,0 +1,9 @@
+---
+title: "Shoulder to Shoulder Ease"
+---
+
+---
+
+The **Shoulder to Shoulder Ease** option allows you to add ease between the shoulders.
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/upperdartlength/en.md b/markdown/org/docs/patterns/noble/options/upperdartlength/en.md
new file mode 100644
index 00000000000..7c503656308
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/upperdartlength/en.md
@@ -0,0 +1,9 @@
+---
+title: "Upper Dart Length"
+---
+
+---
+
+The **Upper Dart Length** controls the length of the upper dart, 100% is all teh way to the bust point.
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/waistdartlength/en.md b/markdown/org/docs/patterns/noble/options/waistdartlength/en.md
new file mode 100644
index 00000000000..0eca8850cce
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/waistdartlength/en.md
@@ -0,0 +1,9 @@
+---
+title: "Waist dart length"
+---
+
+---
+
+The **waist dart length** option controls the length of the waist dart towards the bust.
+
+## Effect of this option on the pattern
diff --git a/markdown/org/docs/patterns/noble/options/waistease/en.md b/markdown/org/docs/patterns/noble/options/waistease/en.md
new file mode 100644
index 00000000000..f4143bcc2cb
--- /dev/null
+++ b/markdown/org/docs/patterns/noble/options/waistease/en.md
@@ -0,0 +1,9 @@
+---
+title: "Waist ease"
+---
+
+---
+
+The **waist ease** option controls the amount of ease at your waist.
+
+## Effect of this option on the pattern
diff --git a/packages/i18n/src/locales/de/components/common.yaml b/packages/i18n/src/locales/de/components/common.yaml
index 25219d0a365..139be3da822 100644
--- a/packages/i18n/src/locales/de/components/common.yaml
+++ b/packages/i18n/src/locales/de/components/common.yaml
@@ -10,3 +10,5 @@ requiredMeasurements: Required measurements
showcase: Showcase
sloganCome: Komm fΓΌr die Schnittmuster
sloganStay: Bleib fΓΌr die Community
+support: Support
+
diff --git a/packages/i18n/src/locales/de/components/patrons.yaml b/packages/i18n/src/locales/de/components/patrons.yaml
index a83ae66ffab..57432af8a77 100644
--- a/packages/i18n/src/locales/de/components/patrons.yaml
+++ b/packages/i18n/src/locales/de/components/patrons.yaml
@@ -1,3 +1,6 @@
---
becomeAPatron: Become a patron
supportFreesewing: Support FreeSewing
+patronLead: FreeSewing is fuelled by a voluntary subscription model
+patronPitch: If you think what we do is worthwhile, and if you can spare a few coins each month without hardship, please support our work
+
diff --git a/packages/i18n/src/locales/es/components/common.yaml b/packages/i18n/src/locales/es/components/common.yaml
index 9682d5861bd..d1b5752dca2 100644
--- a/packages/i18n/src/locales/es/components/common.yaml
+++ b/packages/i18n/src/locales/es/components/common.yaml
@@ -10,3 +10,5 @@ requiredMeasurements: Required measurements
showcase: Showcase
sloganCome: Come for the sewing patterns
sloganStay: Stay for the community
+support: Support
+
diff --git a/packages/i18n/src/locales/es/components/patrons.yaml b/packages/i18n/src/locales/es/components/patrons.yaml
index a83ae66ffab..57432af8a77 100644
--- a/packages/i18n/src/locales/es/components/patrons.yaml
+++ b/packages/i18n/src/locales/es/components/patrons.yaml
@@ -1,3 +1,6 @@
---
becomeAPatron: Become a patron
supportFreesewing: Support FreeSewing
+patronLead: FreeSewing is fuelled by a voluntary subscription model
+patronPitch: If you think what we do is worthwhile, and if you can spare a few coins each month without hardship, please support our work
+
diff --git a/packages/i18n/src/locales/fr/components/common.yaml b/packages/i18n/src/locales/fr/components/common.yaml
index 9682d5861bd..d1b5752dca2 100644
--- a/packages/i18n/src/locales/fr/components/common.yaml
+++ b/packages/i18n/src/locales/fr/components/common.yaml
@@ -10,3 +10,5 @@ requiredMeasurements: Required measurements
showcase: Showcase
sloganCome: Come for the sewing patterns
sloganStay: Stay for the community
+support: Support
+
diff --git a/packages/i18n/src/locales/fr/components/patrons.yaml b/packages/i18n/src/locales/fr/components/patrons.yaml
index a83ae66ffab..57432af8a77 100644
--- a/packages/i18n/src/locales/fr/components/patrons.yaml
+++ b/packages/i18n/src/locales/fr/components/patrons.yaml
@@ -1,3 +1,6 @@
---
becomeAPatron: Become a patron
supportFreesewing: Support FreeSewing
+patronLead: FreeSewing is fuelled by a voluntary subscription model
+patronPitch: If you think what we do is worthwhile, and if you can spare a few coins each month without hardship, please support our work
+
diff --git a/packages/i18n/src/locales/nl/components/common.yaml b/packages/i18n/src/locales/nl/components/common.yaml
index 9682d5861bd..d1b5752dca2 100644
--- a/packages/i18n/src/locales/nl/components/common.yaml
+++ b/packages/i18n/src/locales/nl/components/common.yaml
@@ -10,3 +10,5 @@ requiredMeasurements: Required measurements
showcase: Showcase
sloganCome: Come for the sewing patterns
sloganStay: Stay for the community
+support: Support
+
diff --git a/packages/i18n/src/locales/nl/components/patrons.yaml b/packages/i18n/src/locales/nl/components/patrons.yaml
index a83ae66ffab..57432af8a77 100644
--- a/packages/i18n/src/locales/nl/components/patrons.yaml
+++ b/packages/i18n/src/locales/nl/components/patrons.yaml
@@ -1,3 +1,6 @@
---
becomeAPatron: Become a patron
supportFreesewing: Support FreeSewing
+patronLead: FreeSewing is fuelled by a voluntary subscription model
+patronPitch: If you think what we do is worthwhile, and if you can spare a few coins each month without hardship, please support our work
+
diff --git a/packages/utils/src/measurementAsMm/index.js b/packages/utils/src/measurementAsMm/index.js
index 17f090ec7d6..c19d9273ca2 100644
--- a/packages/utils/src/measurementAsMm/index.js
+++ b/packages/utils/src/measurementAsMm/index.js
@@ -1,6 +1,10 @@
const measurementAsMm = (value, units = "metric") => {
if (typeof value === "number")
return value * (units === "imperial" ? 25.4 : 10);
+
+ if (value.endsWith('.'))
+ return false;
+
if (units === "metric") {
value = Number(value);
if (isNaN(value)) return false;
diff --git a/sites/shared/components/workbench/inputs/measurement.js b/sites/shared/components/workbench/inputs/measurement.js
index f426c21a84a..d7167dbe74f 100644
--- a/sites/shared/components/workbench/inputs/measurement.js
+++ b/sites/shared/components/workbench/inputs/measurement.js
@@ -1,6 +1,7 @@
-import React, { useState, useEffect } from 'react'
+import React, { useState, useEffect, useMemo, useCallback, useRef } from 'react'
import { useTranslation } from 'next-i18next'
import { isDegreeMeasurement } from '../../../config/measurements'
+import measurementAsMm from 'pkgs/utils/src/measurementAsMm'
/*
* This is a single input for a measurements
@@ -14,30 +15,62 @@ const MeasurementInput = ({ m, gist, app, updateMeasurements }) => {
const { t } = useTranslation(['app', 'measurements'])
const prefix = (app.site === 'org') ? '' : 'https://freesewing.org'
const title = t(`measurements:${m}`)
- const factor = isDegreeMeasurement(m) ? 1 : 10
+
+ const isDegree = isDegreeMeasurement(m);
+ const factor = useMemo(() => (isDegree ? 1 : (gist?.units == 'imperial' ? 25.4 : 10)), [gist?.units])
const isValValid = val => (typeof val === 'undefined' || val === '')
? null
- : !isNaN(val)
+ : val !== false && !isNaN(val)
const isValid = (newVal) => (typeof newVal === 'undefined')
- ? isValValid(gist?.measurements?.[m])
+ ? isValValid(val)
: isValValid(newVal)
- const update = evt => {
- setVal(evt.target.value)
- const ok = isValid(evt.target.value)
- if (ok) updateMeasurements(evt.target.value*factor, m)
- }
+ const [val, setVal] = useState(gist?.measurements?.[m] / factor || '')
- const [val, setVal] = useState(gist?.measurements?.[m] || '')
+ // keep a single reference to a debounce timer
+ const debounceTimeout = useRef(null);
+ // onChange
+ const update = useCallback((evt) => {
+ evt.stopPropagation();
+ let evtVal = evt.target.value;
+ // set Val immediately so that the input reflects it
+ setVal(evtVal)
+
+ let useVal = isDegree ? evtVal : measurementAsMm(evtVal, gist?.units);
+ const ok = isValid(useVal)
+ // only set to the gist if it's valid
+ if (ok) {
+ // debounce in case it's still changing
+ if (debounceTimeout.current !== null) { clearTimeout(debounceTimeout.current); }
+ debounceTimeout.current = setTimeout(() => {
+ // clear the timeout reference
+ debounceTimeout.current = null;
+ updateMeasurements(useVal, m)
+ }, 500);
+ }
+ }, [gist?.units])
+
+ // use this for better update efficiency
+ const memoVal = useMemo(() => gist?.measurements?.[m], [gist])
+ // track validity against the value and the units
+ const valid = useMemo(() => isValid(isDegree ? val : measurementAsMm(val, gist?.units)), [val, gist?.units])
+
+ // hook to update the value or format when the gist changes
useEffect(() => {
- if (gist?.measurements?.[m]) setVal(gist.measurements[m]/factor)
- }, [gist])
+ // set the value to the proper value and format
+ if (memoVal) {
+ let gistVal = +(memoVal / factor).toFixed(2);
+ setVal(gistVal)
+ }
+ }, [memoVal, factor])
+
+ // cleanup
+ useEffect(() => clearTimeout(debounceTimeout.current), [])
if (!m) return null
- const valid = isValid()
return (
diff --git a/sites/shared/components/workbench/measurements/index.js b/sites/shared/components/workbench/measurements/index.js
index 71642cc3ebb..faaf89e9e72 100644
--- a/sites/shared/components/workbench/measurements/index.js
+++ b/sites/shared/components/workbench/measurements/index.js
@@ -5,6 +5,8 @@ import nonHuman from './non-human.js'
import WithBreastsIcon from 'shared/components/icons/with-breasts.js'
import WithoutBreastsIcon from 'shared/components/icons/without-breasts.js'
import { useTranslation } from 'next-i18next'
+import Setting from '../menu/core-settings/setting';
+import {settings} from '../menu/core-settings/index';
const groups = {
people: {
@@ -70,7 +72,7 @@ const WorkbenchMeasurements = ({ app, design, gist, updateGist }) => {
{icons[type]}
{t('size')}
{ group === 'people'
- ? m.slice(-2)
+ ? m.replace('size', '')
: m
}
@@ -87,6 +89,7 @@ const WorkbenchMeasurements = ({ app, design, gist, updateGist }) => {