diff --git a/packages/hi/CHANGELOG.md b/packages/hi/CHANGELOG.md
new file mode 100644
index 00000000000..a215f923908
--- /dev/null
+++ b/packages/hi/CHANGELOG.md
@@ -0,0 +1,51 @@
+# Change log for: @freesewing/benjamin
+
+
+## 2.20.0 (2022-01-24)
+
+### Changed
+
+ - Switched to default import for version from package.json
+
+## 2.16.1 (2021-05-30)
+
+### Changed
+
+ - Changed `department` setting in config in line with new grouping
+
+## 2.8.1 (2020-08-16)
+
+### Fixed
+
+ - Fixed issue with (length of) band
+
+## 2.8.0 (2020-08-10)
+
+### Fixed
+
+ - Fix for incorrect length of the ribbon
+
+## 2.7.0 (2020-07-12)
+
+### Changed
+
+ - Removed `Circumference` suffix from measurement names
+
+## 2.0.2 (2019-09-06)
+
+### Fixed
+
+ - Added bandLength option to fit optiongroup (it was missing)
+
+## 2.0.0 (2019-08-25)
+
+### Added
+
+ - Initial release
+
+
+This is the **initial release**, and the start of this change log.
+
+> Prior to version 2, FreeSewing was not a JavaScript project.
+> As such, that history is out of scope for this change log.
+
diff --git a/packages/hi/README.md b/packages/hi/README.md
new file mode 100644
index 00000000000..7665c3d9d70
--- /dev/null
+++ b/packages/hi/README.md
@@ -0,0 +1,253 @@
+
+
+
+
+
+
+
+
+
+
+
+
+# @freesewing/benjamin
+
+A FreeSewing pattern for a bow tie
+
+
+
+## What am I looking at? π€
+
+This repository is our *monorepo*
+holding [all our NPM packages](https://freesewing.dev/reference/packages/).
+
+This folder holds: @freesewing/benjamin
+
+## About FreeSewing π
+
+Where the world of makers and developers collide, that's where you'll find FreeSewing.
+
+If you're a maker, checkout [freesewing.org](https://freesewing.org/) where you can generate
+our sewing patterns adapted to your measurements.
+
+If you're a developer, our documentation is on [freesewing.dev](https://freesewing.dev/).
+Our [core library](https://freesewing.dev/reference/api/) is a *batteries-included* toolbox
+for parametric design of sewing patterns. But we also provide a range
+of [plugins](https://freesewing.dev/reference/plugins/) that further extend the
+functionality of the platform.
+
+If you have NodeJS installed, you can try it right now by running:
+
+```bash
+npx create-freesewing-pattern
+```
+
+Or, consult our getting started guides
+for [Linux](https://freesewing.dev/tutorials/getting-started-linux/),
+[MacOS](https://freesewing.dev/tutorials/getting-started-mac/),
+or [Windows](https://freesewing.dev/tutorials/getting-started-windows/).
+
+We also have a [pattern design tutorial](https://freesewing.dev/tutorials/pattern-design/) that
+walks you through your first parametric design,
+and [a friendly community](https://freesewing.org/community/where/) with
+people who can help you when you get stuck.
+
+## Support FreeSewing: Become a patron π₯°
+
+FreeSewing is an open source project run by a community,
+and financially supported by our patrons.
+
+If you feel what we do is worthwhile, and you can spend a few coind without
+hardship, then you should [join us and become a patron](https://freesewing.org/community/join).
+
+## Links π©βπ»
+
+ - π» Makers website: [freesewing.org](https://freesewing.org)
+ - π» Developers website: [freesewing.dev](https://freesewing.dev)
+ - π¬ Chat: On Discord via [discord.freesewing.org](https://discord.freesewing.org/)
+ - β
Todo list/Kanban board: On Github via [todo.freesewing.org](https://todo.freesewing.org/)
+ - π¦ Twitter: [@freesewing_org](https://twitter.com/freesewing_org)
+ - π· Instagram: [@freesewing_org](https://instagram.com/freesewing_org)
+
+## License: MIT π€
+
+Β© [Joost De Cock](https://github.com/joostdecock).
+See [the license file](https://github.com/freesewing/freesewing/blob/develop/LICENSE) for details.
+
+## Where to get help π€―
+
+Our [chatrooms on Discord](https://chat.freesewing.org/) are the best place to ask questions,
+share your feedback, or just hang out.
+
+If you want to report a problem, please [create an issue](https://github.com/freesewing/freesewing/issues/new).
+
+
+
+## Contributors β¨
+
+Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
+
+
+
+
+
+
+
+
+
+
+
+This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
+
diff --git a/packages/hi/config/index.js b/packages/hi/config/index.js
new file mode 100644
index 00000000000..0a4d8ac4e3b
--- /dev/null
+++ b/packages/hi/config/index.js
@@ -0,0 +1,30 @@
+import { version } from '../package.json'
+
+export default {
+ name: 'hi',
+ version: version,
+ design: 'Wouter Van Wageningen',
+ code: 'Wouter Van Wageningen',
+ department: 'accessories',
+ type: 'pattern',
+ difficulty: 4,
+ optionGroups: {
+ style: ['size','nosePointiness','aggressive'],
+ },
+ measurements: ['neck'],
+ parts: ['body','tail','aboveMouth','belly','topFin','bottomFin','mouth'],
+ dependencies: {
+ tail: 'body',
+ aboveMouth: ['body','mouth'],
+ topFin: 'body',
+ belly: ['body','aboveMouth'],
+ bottomFin: ['body','belly','aboveMouth'],
+ },
+ inject: {},
+ hide: [],
+ options: {
+ nosePointiness: {pct: 0, min: -5,max: +10},
+ aggressive: {bool: false},
+ size: {pct: 33, min: 5, max: 500 },
+ },
+}
diff --git a/packages/hi/package.json b/packages/hi/package.json
new file mode 100644
index 00000000000..c63547672e3
--- /dev/null
+++ b/packages/hi/package.json
@@ -0,0 +1,92 @@
+{
+ "name": "@freesewing/hi",
+ "version": "2.20.8",
+ "description": "A FreeSewing pattern for a shark",
+ "author": "woutervdub (https://github.com/woutervdub)",
+ "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": {
+ "clean": "rimraf dist",
+ "build": "rollup -c",
+ "cibuild_step1": "rollup -c",
+ "test": "BABEL_ENV=production npx mocha tests/*.test.mjs --require @babel/register",
+ "pubtest": "npm publish --registry http://localhost:6662",
+ "pubforce": "npm publish",
+ "symlink": "mkdir -p ./node_modules/@freesewing && cd ./node_modules/@freesewing && ln -s -f ../../../* . && cd -",
+ "start": "rollup -c -w",
+ "netlify": "echo \"Not configured yet\"",
+ "testci": "BABEL_ENV=production npx mocha tests/*.test.mjs --require @babel/register --reporter ../../tests/reporters/terse.js"
+ },
+ "peerDependencies": {
+ "@freesewing/core": "^2.20.8",
+ "@freesewing/plugin-bundle": "^2.20.8"
+ },
+ "dependencies": {},
+ "devDependencies": {
+ "react": "^17.0.2",
+ "react-dom": "^17.0.2",
+ "@babel/plugin-proposal-class-properties": "^7.13.0",
+ "@freesewing/components": "^2.20.8",
+ "@freesewing/css-theme": "^2.20.8",
+ "@freesewing/i18n": "^2.20.8",
+ "@freesewing/mui-theme": "^2.20.8",
+ "@freesewing/plugin-bust": "^2.20.8",
+ "@freesewing/plugin-buttons": "^2.20.8",
+ "@freesewing/plugin-flip": "^2.20.8",
+ "@freesewing/utils": "^2.20.8",
+ "react-scripts": "^5.0.0",
+ "webpack": "^5.67.0",
+ "rollup": "^2.66.1",
+ "@rollup/plugin-babel": "^5.3.0",
+ "@rollup/plugin-commonjs": "^21.0.1",
+ "@rollup/plugin-json": "^4.1.0",
+ "@rollup/plugin-node-resolve": "^13.1.3",
+ "rollup-plugin-peer-deps-external": "^2.2.4",
+ "@material-ui/core": "^4.12.3",
+ "@material-ui/icons": "^4.11.2",
+ "@material-ui/lab": "^v4.0.0-alpha.60",
+ "axios": "^0.25.0",
+ "react-intl": "^5.24.4",
+ "prop-types": "^15.8.1",
+ "mocha": "^9.1.1",
+ "chai": "^4.2.0",
+ "@babel/register": "^7.10.5"
+ },
+ "files": [
+ "dist/*",
+ "README.md",
+ "package.json"
+ ],
+ "publishConfig": {
+ "access": "public",
+ "tag": "latest"
+ },
+ "engines": {
+ "node": ">=12.0.0",
+ "npm": ">=6"
+ },
+ "rollup": {
+ "exports": "default"
+ }
+}
diff --git a/packages/hi/rollup.config.js b/packages/hi/rollup.config.js
new file mode 100644
index 00000000000..83bc5ef0eec
--- /dev/null
+++ b/packages/hi/rollup.config.js
@@ -0,0 +1,29 @@
+import resolve from '@rollup/plugin-node-resolve'
+import commonjs from '@rollup/plugin-commonjs'
+import json from '@rollup/plugin-json'
+import peerDepsExternal from 'rollup-plugin-peer-deps-external'
+import { name, version, description, author, license, main, module, rollup } from './package.json'
+
+const banner = `/**\n * ${name} | v${version}\n * ${description}\n * (c) ${new Date().getFullYear()} ${author}\n * @license ${license}\n */`
+const output = [
+ {
+ banner,
+ file: main,
+ format: 'cjs',
+ sourcemap: true,
+ exports: rollup.exports,
+ },
+]
+if (typeof module !== 'undefined')
+ output.push({
+ banner,
+ file: module,
+ format: 'es',
+ sourcemap: true,
+ })
+
+export default {
+ input: 'src/index.js',
+ output,
+ plugins: [peerDepsExternal(), resolve({ modulesOnly: true }), commonjs(), json()],
+}
diff --git a/packages/hi/src/aboveMouth.js b/packages/hi/src/aboveMouth.js
new file mode 100644
index 00000000000..43dbd3ec183
--- /dev/null
+++ b/packages/hi/src/aboveMouth.js
@@ -0,0 +1,114 @@
+export default function (part) {
+ let {
+ store,
+ sa,
+ Point,
+ points,
+ Path,
+ paths,
+ Snippet,
+ snippets,
+ options,
+ measurements,
+ complete,
+ paperless,
+ macro,
+ } = part.shorthand()
+
+
+ let aboveMouth01_02d = 266.7238454769277 * options.size
+ let aboveMouth01_02a = 353.4089695458119
+ let aboveMouth02_03d = 28.348200101593726 * options.size
+ let aboveMouth02_03a = 233.13495309848912
+ let aboveMouth01_04d = 57.858419828059574 * options.size
+ let aboveMouth01_04a = 208.91023166349467
+ let aboveMouth01cp1d = 62.927189989701574 * options.size
+ let aboveMouth01cp1a = 298.7196048714283
+ let aboveMouth02cp2d = 169.53367533325053 * options.size
+ let aboveMouth02cp2a = 195.1209034747764
+ let aboveMouth03cp1d = 172.36585117998288 * options.size
+ let aboveMouth03cp1a = 197.87876803095696
+ let aboveMouth04cp2d = 66.94005927693816 * options.size
+ let aboveMouth04cp2a = 308.8121959753343
+
+
+ let faceTopLength = store.get('faceTopLength')
+
+ let diff = 0
+ let iteration = 0
+ do {
+ points.aboveMouth01 = new Point(0, 0)
+ points.aboveMouth02 = points.aboveMouth01.shift(aboveMouth01_02a, aboveMouth01_02d)
+ points.aboveMouth03 = points.aboveMouth02.shift(aboveMouth02_03a, aboveMouth02_03d)
+ points.aboveMouth04 = points.aboveMouth01.shift(aboveMouth01_04a, aboveMouth01_04d)
+
+ points.aboveMouth01cp1 = points.aboveMouth01.shift(aboveMouth01cp1a, aboveMouth01cp1d)
+ points.aboveMouth02cp2 = points.aboveMouth02.shift(aboveMouth02cp2a, aboveMouth02cp2d)
+ points.aboveMouth03cp1 = points.aboveMouth03.shift(aboveMouth03cp1a, aboveMouth03cp1d)
+ points.aboveMouth04cp2 = points.aboveMouth04.shift(aboveMouth04cp2a, aboveMouth04cp2d)
+ diff =
+ faceTopLength -
+ new Path()
+ .move(points.aboveMouth03)
+ .curve(points.aboveMouth03cp1, points.aboveMouth04cp2, points.aboveMouth04)
+ .length()
+
+ aboveMouth01_02d = aboveMouth01_02d + diff
+ aboveMouth01_04d = aboveMouth01_04d + diff
+ iteration++
+ } while ((diff < -1 || diff > 1) && iteration < 100)
+
+ console.log({ iteration: iteration })
+
+ paths.seam = new Path()
+ .move(points.aboveMouth01)
+ .line(points.aboveMouth04)
+ .curve(points.aboveMouth04cp2, points.aboveMouth03cp1, points.aboveMouth03)
+ .line(points.aboveMouth02)
+ .curve(points.aboveMouth02cp2, points.aboveMouth01cp1, points.aboveMouth01)
+ .close()
+
+ console.log({ faceTopLength1: store.get('faceTopLength') })
+ console.log({
+ faceTopLength2: new Path()
+ .move(points.aboveMouth03)
+ .curve(points.aboveMouth03cp1, points.aboveMouth04cp2, points.aboveMouth04)
+ .length(),
+ })
+
+ store.set(
+ 'aboveMouthTopLength',
+ new Path()
+ .move(points.aboveMouth03)
+ .curve(points.aboveMouth03cp1, points.aboveMouth04cp2, points.aboveMouth04)
+ .length()
+ )
+ store.set(
+ 'aboveMouthBottomLength',
+ new Path()
+ .move(points.aboveMouth01)
+ .curve(points.aboveMouth01cp1, points.aboveMouth02cp2, points.aboveMouth02)
+ .length()
+ )
+ store.set('aboveMouthFinLength', points.aboveMouth02.dist(points.aboveMouth03))
+ console.log({ aboveMouthFinLength: store.get('aboveMouthFinLength') })
+
+ console.log({ mouthTopLength: store.get('mouthTopLength') })
+
+ points.aboveMouthSnippet = new Path()
+ .move(points.aboveMouth01)
+ .curve(points.aboveMouth01cp1, points.aboveMouth02cp2, points.aboveMouth02)
+ .shiftAlong(store.get('mouthTopLength'))
+ console.log({ aboveMouthSnippet: points.aboveMouthSnippet })
+
+ snippets.mouth = new Snippet('bnotch', points.aboveMouthSnippet)
+
+ // Complete?
+ if (complete) {
+ if (sa) {
+ paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
+ }
+ }
+
+ return part
+}
diff --git a/packages/hi/src/belly.js b/packages/hi/src/belly.js
new file mode 100644
index 00000000000..5c0f23f65cb
--- /dev/null
+++ b/packages/hi/src/belly.js
@@ -0,0 +1,202 @@
+export default function (part) {
+ let {
+ store,
+ sa,
+ Point,
+ points,
+ Path,
+ paths,
+ Snippet,
+ snippets,
+ options,
+ measurements,
+ complete,
+ paperless,
+ macro,
+ } = part.shorthand()
+
+ let belly01_02d = 224.8451041 * options.size
+ let belly02_03d = 108.1988389 * options.size
+ let belly03_04d = 216.7485605 * options.size
+ let belly04_05d = 164.7592153 * options.size
+ let belly01_10d = 129.2449198 * options.size
+ let belly01_02a = 25.7020193
+ let belly02_03a = 2.2164353
+ let belly03_04a = 338.0869319
+
+ let belly04_05a = 198.1877729
+ let belly01_10a = 163.4959859
+ let belly10_05d = 231.4386252 * options.size
+ let belly10_05a = 0
+
+ let belly01cp1d = 65.65512143 * options.size
+ let belly01cp2d = 38.20949996 * options.size
+ let belly02cp1d = 37.73513423 * options.size
+ let belly02cp2d = 118.64531230 * options.size
+ let belly03cp1d = 54.50254779 * options.size
+ let belly03cp2d = 40.68278830 * options.size
+ let belly04cp1d = 52.08589469 * options.size
+ let belly04cp2d = 62.46560129 * options.size
+ let belly05cp1d = 48.20828587 * options.size
+ // let belly05cp2d = 48.20828587 * options.size
+ let belly05cp2d = 68 * options.size
+ let belly10cp1d = 45.42602302 * options.size
+ // let belly10cp2d = 45.42602302 * options.size
+ let belly10cp2d = 65.42602302 * options.size
+
+ let belly01cp1a = 60.1172330
+ let belly01cp2a = 327.4394109
+ let belly02cp1a = 331.7898702
+ let belly02cp2a = 182.9449647
+ let belly03cp1a = 349.8613970
+ let belly03cp2a = 200.1533738
+ let belly04cp1a = 204.8857575
+ let belly04cp2a = 145.9357065
+ // let belly05cp1a = 8.1545383
+ let belly05cp1a = 8.1545383
+ // let belly05cp2a = 8.1545383
+ let belly05cp2a = 5
+ let belly10cp1a = 169.9644604
+ let belly10cp2a = 175.9644604
+
+ points.belly10 = new Point(0, 0)
+ points.belly01 = points.belly10.shift(belly01_10a, belly01_10d)
+ points.belly02 = points.belly01.shift(belly01_02a, belly01_02d)
+ points.belly03 = points.belly02.shift(belly02_03a, belly02_03d)
+ points.belly04 = points.belly03.shift(belly03_04a, belly03_04d)
+ points.belly05 = points.belly10.shift(belly10_05a, belly10_05d)
+ points.belly01cp1 = points.belly01.shift(belly01cp1a, belly01cp1d)
+ points.belly02cp1 = points.belly02.shift(belly02cp1a, belly02cp1d)
+ points.belly03cp1 = points.belly03.shift(belly03cp1a, belly03cp1d)
+ points.belly04cp1 = points.belly04.shift(belly04cp1a, belly04cp1d)
+ points.belly05cp1 = points.belly05.shift(belly05cp1a, belly05cp1d)
+ points.belly01cp2 = points.belly01.shift(belly01cp2a, belly01cp2d)
+ points.belly02cp2 = points.belly02.shift(belly02cp2a, belly02cp2d)
+ points.belly03cp2 = points.belly03.shift(belly03cp2a, belly03cp2d)
+ points.belly04cp2 = points.belly04.shift(belly04cp2a, belly04cp2d)
+ points.belly05cp2 = points.belly05.shift(belly05cp2a, belly05cp2d)
+ points.belly10cp1 = points.belly10.shift(belly10cp2a, belly10cp2d)
+
+ console.log({ belly10_05d: points.belly10.dist(points.belly05) })
+
+ let mouthPartLength =
+ store.get('aboveMouthBottomLength') -
+ store.get('mouthTopLength') +
+ store.get('mouthBottomLength')
+
+ console.log({ calc: mouthPartLength })
+ console.log({
+ actual: new Path()
+ .move(points.belly01)
+ .curve(points.belly01cp1, points.belly02cp2, points.belly02)
+ .length(),
+ })
+
+ let diff = 0
+ let iteration = 0
+ do {
+ points.belly01.x -= diff
+ points.belly01cp1.x -= diff
+ points.belly01cp2.x -= diff
+
+ iteration++
+ diff =
+ mouthPartLength -
+ new Path()
+ .move(points.belly01)
+ .curve(points.belly01cp1, points.belly02cp2, points.belly02)
+ .length()
+ } while ((diff < -1 || diff > 1) && iteration < 100)
+
+ let bellyTailLength = store.get('bellyTailLength')
+ console.log({ bellyTailLength: store.get('bellyTailLength') })
+ console.log({
+ first: new Path()
+ .move(points.belly03)
+ .curve(points.belly03cp1, points.belly04cp2, points.belly04)
+ .length(),
+ })
+
+ diff = 0
+ iteration = 0
+ do {
+ points.belly04.x -= diff
+ points.belly04cp1.x -= diff
+ points.belly04cp2.x -= diff
+ points.belly05.x -= diff
+ points.belly05cp2.x -= diff
+
+ iteration++
+ diff =
+ bellyTailLength -
+ new Path()
+ .move(points.belly03)
+ .curve(points.belly03cp1, points.belly04cp2, points.belly04)
+ .length()
+ } while ((diff < -1 || diff > 1) && iteration < 100)
+
+ console.log({
+ actual: new Path()
+ .move(points.belly03)
+ .curve(points.belly03cp1, points.belly04cp2, points.belly04)
+ .length(),
+ })
+
+ points.belly05cp1 = points.belly05cp2.flipY()
+ points.belly06 = points.belly04.flipY()
+ points.belly06cp1 = points.belly04cp2.flipY()
+ points.belly06cp2 = points.belly04cp1.flipY()
+ points.belly07 = points.belly03.flipY()
+ points.belly07cp1 = points.belly03cp2.flipY()
+ points.belly07cp2 = points.belly03cp1.flipY()
+ points.belly08 = points.belly02.flipY()
+ points.belly08cp1 = points.belly02cp2.flipY()
+ points.belly08cp2 = points.belly02cp1.flipY()
+ points.belly09 = points.belly01.flipY()
+ points.belly09cp1 = points.belly01cp2.flipY()
+ points.belly09cp2 = points.belly01cp1.flipY()
+ points.belly10cp2 = points.belly10cp1.flipY()
+
+ paths.seam = new Path()
+ .move(points.belly01)
+ .curve(points.belly01cp2, points.belly10cp1, points.belly10)
+ .curve(points.belly10cp2, points.belly09cp1, points.belly09)
+ .curve(points.belly09cp2, points.belly08cp1, points.belly08)
+ .curve(points.belly08cp2, points.belly07cp1, points.belly07)
+ .curve(points.belly07cp2, points.belly06cp1, points.belly06)
+ .curve(points.belly06cp2, points.belly05cp1, points.belly05)
+ .curve(points.belly05cp2, points.belly04cp1, points.belly04)
+ .curve(points.belly04cp2, points.belly03cp1, points.belly03)
+ .curve(points.belly03cp2, points.belly02cp1, points.belly02)
+ .curve(points.belly02cp2, points.belly01cp1, points.belly01)
+ .close()
+
+ store.set(
+ 'bellyFinLength',
+ new Path()
+ .move(points.belly02)
+ .curve(points.belly02cp1, points.belly03cp2, points.belly03)
+ .length()
+ )
+ console.log({ bellyFinLength: store.get('bellyFinLength') })
+
+ points.bellyMouthSnippet1 = new Path()
+ .move(points.belly01)
+ .curve(points.belly01cp1, points.belly02cp2, points.belly02)
+ .shiftAlong(store.get('mouthBottomLength'))
+ points.bellyMouthSnippet2 = points.bellyMouthSnippet1.flipY()
+
+ console.log({ aboveMouthSnippet: points.aboveMouthSnippet })
+
+ snippets.mouth1 = new Snippet('bnotch', points.bellyMouthSnippet1)
+ snippets.mouth2 = new Snippet('bnotch', points.bellyMouthSnippet2)
+
+ // Complete?
+ if (complete) {
+ if (sa) {
+ paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
+ }
+ }
+
+ return part
+}
diff --git a/packages/hi/src/body.js b/packages/hi/src/body.js
new file mode 100644
index 00000000000..32f01e8d83a
--- /dev/null
+++ b/packages/hi/src/body.js
@@ -0,0 +1,459 @@
+export default function (part) {
+ let {
+ store,
+ sa,
+ Point,
+ points,
+ Path,
+ paths,
+ Snippet,
+ snippets,
+ options,
+ measurements,
+ complete,
+ paperless,
+ macro,
+ } = part.shorthand()
+
+
+ let body01_02d = 117.67274991262845 * options.size
+ let body02_03d = 124.91298035032229 * options.size
+ // let body02_03d = body01_02d
+ let body03_04d = 255.92397474640785 * options.size
+ let body04_05d = 201.01260719168837 * options.size
+ let body05_06d = 134.89080971660005 * options.size
+ let body06_07d = 49.03860703568160 * options.size
+ let body07_08d = 225.86340480918992 * options.size
+ let body08_09d = 66.84760000179512 * options.size
+ let body09_10d = 40.72782003741420 * options.size
+ let body10_11d = 23.78799421977402 * options.size
+ let body11_12d = 57.68530918700182 * options.size
+ let body12_13d = 98.06623978209830 * options.size
+ let body13_14d = 91.32736600274856 * options.size
+ let body14_15d = 295.10977066828880 * options.size
+ let body15_16d = 209.42633350581770 * options.size
+ let body16_17d = 152.51537318250902 * options.size
+ let body17_18d = 255.15294373571314 * options.size
+ let body18_19d = 71.90453921693678 * options.size
+ let body19_01d = 61.33021195137026 * options.size
+
+ let body01cp1d = 42.13103487929059 * options.size
+ body01cp1d = 32.13103487929059 * options.size
+ let body01cp2d = 23.72518967258217 * options.size
+ let body02cp1d = 44.99353642469105 * options.size
+ let body02cp2d = 42.33568754608812 * options.size
+ let body03cp1d = 62.59332758369697 * options.size
+ let body03cp2d = 40.89285869195256 * options.size
+ let body04cp1d = 176.21501525125487 * options.size
+ let body04cp2d = 130.11389715553065 * options.size
+ let body05cp1d = 29.56689479806765 * options.size
+ let body05cp2d = 104.66860665930352 * options.size
+ let body06cp1d = 8.03497915367552 * options.size
+ let body06cp2d = 34.57808908832297 * options.size
+ let body07cp1d = 89.11908088619404 * options.size
+ let body07cp2d = 25.54827831772624 * options.size
+ let body08cp1d = 41.24120086757895 * options.size
+ let body08cp2d = 158.23693200387828 * options.size
+ let body09cp1d = 4.87663090668135 * options.size
+ let body09cp2d = 25.76988630165065 * options.size
+ let body10cp1d = 4.13950105689086 * options.size
+ let body10cp2d = 13.27508493381490 * options.size
+ let body11cp1d = 17.66659910678904 * options.size
+ let body11cp2d = 17.66533107530116 * options.size
+ let body12cp1d = 14.46914569005365 * options.size
+ let body12cp2d = 39.51915145850176 * options.size
+ let body13cp1d = 35.66832366400192 * options.size
+ let body13cp2d = 48.53828530139895 * options.size
+ let body14cp1d = 77.26036056089820 * options.size
+ let body14cp2d = 37.42741381661305 * options.size
+ let body15cp1d = 74.89746640634775 * options.size
+ let body15cp2d = 101.16048880857042 * options.size
+ let body16cp1d = 36.21092864039804 * options.size
+ let body16cp2d = 63.69410844026312 * options.size
+ let body17cp1d = 97.90988675818191 * options.size
+ let body17cp2d = 62.08991689477443 * options.size
+ let body18cp1d = 22.74982929606286 * options.size
+ let body18cp2d = 16.57960183478481 * options.size
+ let body19cp1d = 23.95674278778315 * options.size
+ let body19cp2d = 24.49741270011998 * options.size
+
+ let eyeBigDist = 180.18315182058507 *options.size
+ let eyeSmallDist = 2.3629811679317316 *options.size
+
+ let gillLength = 41.01907104018812 *options.size
+
+/*
+ let body01_02a = 350.1382392835908
+ let body02_03a = 219.2280235992150
+ let body03_04a = 339.6914424367389
+ let body04_05a = 327.5949161262267
+ let body05_06a = 308.0581973147166
+ let body06_07a = 73.6604388249373
+ let body07_08a = 45.7462208380377
+ let body08_09a = 337.5894682731302
+ let body09_10a = 305.1280145118106
+ let body10_11a = 62.0485099186233
+ let body11_12a = 31.5926663325278
+ let body12_13a = 351.3547159587854
+ let body13_14a = 65.2915054300727
+ let body14_15a = 146.7578208812976
+ let body15_16a = 179.0692249048048
+ let body16_17a = 173.6138831920282
+ let body17_18a = 182.5463896677164
+ let body18_19a = 168.3450180715549
+ let body19_01a = 239.6348252240278
+
+ let body01cp1a = 341.5263465356924
+ let body01cp2a = 75.6503959063636
+ let body02cp1a = 211.9535499171619
+ let body02cp2a = 179.4884199670842
+ let body03cp1a = 322.8538439425170
+ let body03cp2a = 45.3745027878966
+ let body04cp1a = 349.1071045662215
+ let body04cp2a = 170.7775897297436
+ let body05cp1a = 285.1596014648055
+ let body05cp2a = 108.5890112443549
+ let body06cp1a = 41.1852543570561
+ let body06cp2a = 164.1413220186340
+ let body07cp1a = 87.2041495377715
+ let body07cp2a = 267.0316498407170
+ let body08cp1a = 357.4386948546150
+ let body08cp2a = 178.5040422857397
+ let body09cp1a = 299.4140745661390
+ let body09cp2a = 119.4139505554426
+ let body10cp1a = 39.0878163024596
+ let body10cp2a = 131.9955535201102
+ let body11cp1a = 71.2799386715762
+ let body11cp2a = 251.2819695388968
+ let body12cp1a = 355.0877186628186
+ let body12cp2a = 175.0877829918719
+ let body13cp1a = 80.2392635965701
+ let body13cp2a = 171.4909473733658
+ let body14cp1a = 140.9298470364624
+ let body14cp2a = 236.9514886304476
+ let body15cp1a = 202.5529871921231
+ let body15cp2a = 333.1212843908838
+ let body16cp1a = 193.8904149121820
+ let body16cp2a = 321.0219904969430
+ let body17cp1a = 191.0428733832995
+ let body17cp2a = 318.4852423703768
+ let body18cp1a = 176.9688130385547
+ let body18cp2a = 358.1542838646098
+ let body19cp1a = 231.3360831292815
+ let body19cp2a = 338.5586388459373
+
+ let eyeBigAngle = 4.84999368439876
+ let eyeSmallAngle = 331.26569123319354
+
+ let gillAngle = 283.9416746517148
+*/
+
+ let body01_02a = 170.1382393
+let body02_03a = 39.2280236
+let body03_04a = 159.6914424
+let body04_05a = 147.5949161
+let body05_06a = 128.0581973
+let body06_07a = 253.6604388
+let body07_08a = 225.7462208
+let body08_09a = 157.5894683
+let body09_10a = 125.1280145
+let body10_11a = 242.0485099
+let body11_12a = 211.5926663
+let body12_13a = 171.354716
+let body13_14a = 245.2915054
+let body14_15a = 326.7578209
+let body15_16a = 359.0692249
+let body16_17a = 353.6138832
+let body17_18a = 2.546389668
+let body18_19a = 348.3450181
+let body19_01a = 59.63482522
+
+let body01cp1a = 161.5263465
+let body01cp2a = 255.6503959
+let body02cp1a = 31.95354992
+//let body02cp2a = 359.48842
+// let body02cp2a = 2.48842
+let body02cp2a = 10
+
+let body03cp1a = 142.8538439
+let body03cp2a = 225.3745028
+let body04cp1a = 169.1071046
+let body04cp2a = 350.7775897
+let body05cp1a = 105.1596015
+let body05cp2a = 288.5890112
+let body06cp1a = 221.1852544
+let body06cp2a = 344.141322
+let body07cp1a = 267.2041495
+let body07cp2a = 87.03164984
+let body08cp1a = 177.4386949
+let body08cp2a = 358.5040423
+let body09cp1a = 119.4140746
+let body09cp2a = 299.4139506
+let body10cp1a = 219.0878163
+let body10cp2a = 311.9955535
+let body11cp1a = 251.2799387
+let body11cp2a = 71.28196954
+let body12cp1a = 175.0877187
+let body12cp2a = 355.087783
+let body13cp1a = 260.2392636
+let body13cp2a = 351.4909474
+let body14cp1a = 320.929847
+let body14cp2a = 56.95148863
+let body15cp1a = 22.55298719
+let body15cp2a = 153.1212844
+let body16cp1a = 13.89041491
+let body16cp2a = 141.0219905
+let body17cp1a = 11.04287338
+let body17cp2a = 138.4852424
+let body18cp1a = 356.968813
+let body18cp2a = 178.1542839
+let body19cp1a = 51.33608313
+let body19cp2a = 158.5586388
+
+let eyeBigAngle = 184.8499937
+let eyeSmallAngle = 151.2656912
+
+let gillAngle = 103.9416747
+
+ points.body01 = new Point(0, 0)
+ points.body02 = points.body01.shift(body01_02a, body01_02d)
+ points.body03 = points.body02.shift(body02_03a, body02_03d)
+ points.body04 = points.body03.shift(body03_04a, body03_04d)
+ points.body05 = points.body04.shift(body04_05a, body04_05d)
+ points.body06 = points.body05.shift(body05_06a, body05_06d)
+ points.body07 = points.body06.shift(body06_07a, body06_07d)
+ points.body08 = points.body07.shift(body07_08a, body07_08d)
+ points.body09 = points.body08.shift(body08_09a, body08_09d)
+ points.body10 = points.body09.shift(body09_10a, body09_10d)
+ points.body11 = points.body10.shift(body10_11a, body10_11d)
+ points.body12 = points.body11.shift(body11_12a, body11_12d)
+ points.body13 = points.body12.shift(body12_13a, body12_13d)
+ points.body14 = points.body13.shift(body13_14a, body13_14d)
+ points.body15 = points.body14.shift(body14_15a, body14_15d)
+ points.body16 = points.body15.shift(body15_16a, body15_16d)
+ points.body17 = points.body16.shift(body16_17a, body16_17d)
+ points.body18 = points.body17.shift(body17_18a, body17_18d)
+ points.body19 = points.body18.shift(body18_19a, body18_19d)
+
+ points.body01cp1 = points.body01.shift(body01cp1a, body01cp1d)
+ points.body02cp1 = points.body02.shift(body02cp1a, body02cp1d)
+ points.body03cp1 = points.body03.shift(body03cp1a, body03cp1d)
+ points.body04cp1 = points.body04.shift(body04cp1a, body04cp1d)
+ points.body05cp1 = points.body05.shift(body05cp1a, body05cp1d)
+ points.body06cp1 = points.body06.shift(body06cp1a, body06cp1d)
+ points.body07cp1 = points.body07.shift(body07cp1a, body07cp1d)
+ points.body08cp1 = points.body08.shift(body08cp1a, body08cp1d)
+ points.body09cp1 = points.body09.shift(body09cp1a, body09cp1d)
+ points.body10cp1 = points.body10.shift(body10cp1a, body10cp1d)
+ points.body11cp1 = points.body11.shift(body11cp1a, body11cp1d)
+ points.body12cp1 = points.body12.shift(body12cp1a, body12cp1d)
+ points.body13cp1 = points.body13.shift(body13cp1a, body13cp1d)
+ points.body14cp1 = points.body14.shift(body14cp1a, body14cp1d)
+ points.body15cp1 = points.body15.shift(body15cp1a, body15cp1d)
+ points.body16cp1 = points.body16.shift(body16cp1a, body16cp1d)
+ points.body17cp1 = points.body17.shift(body17cp1a, body17cp1d)
+ points.body18cp1 = points.body18.shift(body18cp1a, body18cp1d)
+ points.body19cp1 = points.body19.shift(body19cp1a, body19cp1d)
+
+ points.body01cp2 = points.body01.shift(body01cp2a, body01cp2d)
+ points.body02cp2 = points.body02.shift(body02cp2a, body02cp2d)
+ points.body03cp2 = points.body03.shift(body03cp2a, body03cp2d)
+ points.body04cp2 = points.body04.shift(body04cp2a, body04cp2d)
+ points.body05cp2 = points.body05.shift(body05cp2a, body05cp2d)
+ points.body06cp2 = points.body06.shift(body06cp2a, body06cp2d)
+ points.body07cp2 = points.body07.shift(body07cp2a, body07cp2d)
+ points.body08cp2 = points.body08.shift(body08cp2a, body08cp2d)
+ points.body09cp2 = points.body09.shift(body09cp2a, body09cp2d)
+ points.body10cp2 = points.body10.shift(body10cp2a, body10cp2d)
+ points.body11cp2 = points.body11.shift(body11cp2a, body11cp2d)
+ points.body12cp2 = points.body12.shift(body12cp2a, body12cp2d)
+ points.body13cp2 = points.body13.shift(body13cp2a, body13cp2d)
+ points.body14cp2 = points.body14.shift(body14cp2a, body14cp2d)
+ points.body15cp2 = points.body15.shift(body15cp2a, body15cp2d)
+ points.body16cp2 = points.body16.shift(body16cp2a, body16cp2d)
+ points.body17cp2 = points.body17.shift(body17cp2a, body17cp2d)
+ points.body18cp2 = points.body18.shift(body18cp2a, body18cp2d)
+ points.body19cp2 = points.body19.shift(body19cp2a, body19cp2d)
+
+ //Adjust dart point:
+ points.body02 = points.body01.shift(body01_02a - 1.7, body01_02d)
+
+ // Front dart adjustments:
+ points.body01cp2 = points.body01.shift(
+ points.body01.angle(points.body19) +
+ (points.body19.angle(points.body01) - points.body19.angle(points.body19cp1)),
+ body01cp2d
+ )
+ body01cp1a = Math.min(
+ points.body01.angle(points.body01cp2) + 90 * (-1 + options.nosePointiness),
+ points.body01.angle(points.body02) - 5
+ )
+ console.log({pointiness: options.nosePointiness})
+ console.log({pointiness_a: points.body01.angle(points.body01cp2)})
+ console.log({pointiness_a: points.body01.angle(points.body01cp2) +90 * (-1 + options.nosePointiness)})
+ console.log({pointiness_m: points.body01.angle(points.body02) - 5})
+
+ points.body01cp1 = points.body01.shift(body01cp1a, body01cp1d)
+
+ // Make both sides of the dart equal:
+ points.body03 = points.body02.shift(body02_03a, body01_02d)
+
+ points.body02cp1 = points.body02.shift(
+ points.body02.angle(points.body03) -
+ (points.body02.angle(points.body02cp2) - points.body02.angle(points.body01)),
+ body02cp2d
+ )
+ points.body03cp2 = points.body03.shift(
+ points.body03.angle(points.body02) +
+ (points.body01.angle(points.body02) - points.body01.angle(points.body01cp1)),
+ body01cp1d
+ )
+
+ // Nose adjustment:
+ points.body03cp1 = points.body03.shift(
+ body03cp1a + Math.max(-10, 50 * options.nosePointiness),
+ body03cp1d
+ )
+
+ // Tail adjustment:
+ console.log(points.body13.angle(points.body13cp1) - points.body13.angle(points.body14))
+ console.log(points.body14.angle(points.body13) - points.body14.angle(points.body14cp2))
+
+ let tailCpAngle =
+ (points.body13.angle(points.body13cp1) -
+ points.body13.angle(points.body14) +
+ (points.body14.angle(points.body13) - points.body14.angle(points.body14cp2))) /
+ 2
+ points.body14cp2 = points.body14.shift(
+ points.body14.angle(points.body13) - tailCpAngle,
+ body13cp1d
+ )
+ points.body13cp1 = points.body13.shift(
+ points.body13.angle(points.body14) + tailCpAngle,
+ body13cp1d
+ )
+
+ points.eyeBig = points.body01.shift( eyeBigAngle, eyeBigDist )
+ points.eyeSmall = points.eyeBig.shift( eyeSmallAngle, eyeSmallDist *(-2+(options.aggressive ? 0 : 1)))
+
+ let c = 0.55191502449351
+ let eyeBigX = 18.7757 * options.size
+ let eyeBigY = 11.6262 * options.size
+ points.eyeBigT = points.eyeBig.shift(90, eyeBigY / 2)
+ points.eyeBigB = points.eyeBig.shift(270, eyeBigY / 2).shift(
+ 0,
+ options.aggressive ? eyeBigX / 3 : 0
+ )
+ points.eyeBigR = points.eyeBig.shift(0, eyeBigX / 2).shift(
+ 270,
+ options.aggressive ? eyeBigY / 3 : 0
+ )
+ points.eyeBigL = points.eyeBig.shift(180, eyeBigX / 2)
+ points.eyeBigTcp1 = points.eyeBigT.shift(0, (eyeBigY / 2) * c)
+ points.eyeBigTcp2 = points.eyeBigT.shift(180, (eyeBigY / 2) * c)
+ points.eyeBigBcp1 = points.eyeBigB.shift(180, (eyeBigY / 2) * c)
+ points.eyeBigBcp2 = points.eyeBigB.shift(0, (eyeBigY / 2) * c)
+ points.eyeBigRcp1 = points.eyeBigR.shift(270, (eyeBigX / (options.aggressive ? 3 : 2)) * c)
+ points.eyeBigRcp2 = points.eyeBigR.shift(90, (eyeBigX / 2) * c)
+ points.eyeBigLcp1 = points.eyeBigL.shift(90, (eyeBigX / 2) * c)
+ points.eyeBigLcp2 = points.eyeBigL.shift(270, (eyeBigX / 2) * c)
+
+ paths.eyeBig = new Path()
+ .move(points.eyeBigT)
+ .curve(points.eyeBigTcp2, points.eyeBigLcp1, points.eyeBigL)
+ .curve(points.eyeBigLcp2, points.eyeBigBcp1, points.eyeBigB)
+ .curve(points.eyeBigBcp2, points.eyeBigRcp1, points.eyeBigR)
+ .curve(points.eyeBigRcp2, points.eyeBigTcp1, points.eyeBigT)
+
+ let eyeSmallX = 1.87089 * options.size *((options.aggressive ? 1.5 : 1))
+ let eyeSmallY = 1.5368 * options.size *((options.aggressive ? 1.5 : 1))
+ points.eyeSmallT = points.eyeSmall.shift(270, eyeSmallY / 2)
+ points.eyeSmallB = points.eyeSmall.shift(90, eyeSmallY / 2)
+ points.eyeSmallR = points.eyeSmall.shift(0, eyeSmallX / 2)
+ points.eyeSmallL = points.eyeSmall.shift(180, eyeSmallX / 2)
+ points.eyeSmallTcp1 = points.eyeSmallT.shift(0, (eyeSmallY / 2) * c)
+ points.eyeSmallTcp2 = points.eyeSmallT.shift(180, (eyeSmallY / 2) * c)
+ points.eyeSmallBcp1 = points.eyeSmallB.shift(180, (eyeSmallY / 2) * c)
+ points.eyeSmallBcp2 = points.eyeSmallB.shift(0, (eyeSmallY / 2) * c)
+ points.eyeSmallRcp1 = points.eyeSmallR.shift(270, (eyeSmallX / 2) * c)
+ points.eyeSmallRcp2 = points.eyeSmallR.shift(90, (eyeSmallX / 2) * c)
+ points.eyeSmallLcp1 = points.eyeSmallL.shift(90, (eyeSmallX / 2) * c)
+ points.eyeSmallLcp2 = points.eyeSmallL.shift(270, (eyeSmallX / 2) * c)
+
+ paths.eyeSmall = new Path()
+ .move(points.eyeSmallT)
+ .curve(points.eyeSmallTcp2, points.eyeSmallLcp1, points.eyeSmallL)
+ .curve(points.eyeSmallLcp2, points.eyeSmallBcp1, points.eyeSmallB)
+ .curve(points.eyeSmallBcp2, points.eyeSmallRcp1, points.eyeSmallR)
+ .curve(points.eyeSmallRcp2, points.eyeSmallTcp1, points.eyeSmallT)
+
+ paths.seam = new Path()
+ .move(points.body01)
+ .curve(points.body01cp1, points.body02cp2, points.body02)
+ .curve(points.body02cp1, points.body03cp2, points.body03)
+ .curve(points.body03cp1, points.body04cp2, points.body04)
+ .curve(points.body04cp1, points.body05cp2, points.body05)
+ .curve(points.body05cp1, points.body06cp2, points.body06)
+ .curve(points.body06cp1, points.body07cp2, points.body07)
+ .curve(points.body07cp1, points.body08cp2, points.body08)
+ .curve(points.body08cp1, points.body09cp2, points.body09)
+ .curve(points.body09cp1, points.body10cp2, points.body10)
+ .curve(points.body10cp1, points.body11cp2, points.body11)
+ .curve(points.body11cp1, points.body12cp2, points.body12)
+ .curve(points.body12cp1, points.body13cp2, points.body13)
+ .curve(points.body13cp1, points.body14cp2, points.body14)
+ .curve(points.body14cp1, points.body15cp2, points.body15)
+ .curve(points.body15cp1, points.body16cp2, points.body16)
+ .curve(points.body16cp1, points.body17cp2, points.body17)
+ .curve(points.body17cp1, points.body18cp2, points.body18)
+ .curve(points.body18cp1, points.body19cp2, points.body19)
+ .curve(points.body19cp1, points.body01cp2, points.body01)
+
+
+ let gillPath = new Path()
+ .move(points.body17)
+ .curve(points.body17cp1, points.body18cp2, points.body18)
+ points.gill1s = gillPath.shiftFractionAlong(0.018)
+ points.gill2s = gillPath.shiftFractionAlong(0.08 * 1 + 0.018)
+ points.gill3s = gillPath.shiftFractionAlong(0.08 * 2 + 0.018)
+ points.gill4s = gillPath.shiftFractionAlong(0.08 * 3 + 0.018)
+ points.gill5s = gillPath.shiftFractionAlong(0.08 * 4 + 0.018)
+ points.gill1e = points.gill1s.shift(gillAngle, gillLength *(1 +(0 * 0.08)))
+ points.gill2e = points.gill2s.shift(gillAngle, gillLength *(1 +(1 * 0.08)))
+ points.gill3e = points.gill3s.shift(gillAngle, gillLength *(1 +(2 * 0.08)))
+ points.gill4e = points.gill4s.shift(gillAngle, gillLength *(1 +(3 * 0.08)))
+ points.gill5e = points.gill5s.shift(gillAngle, gillLength *(1 +(4 * 0.08)))
+
+ paths.gill1 = new Path().move(points.gill1s).line(points.gill1e)
+ paths.gill2 = new Path().move(points.gill2s).line(points.gill2e)
+ paths.gill3 = new Path().move(points.gill3s).line(points.gill3e)
+ paths.gill4 = new Path().move(points.gill4s).line(points.gill4e)
+ paths.gill5 = new Path().move(points.gill5s).line(points.gill5e)
+
+ store.set( 'tailWidth', points.body13.dist( points.body14 ) )
+ store.set( 'tailCpAngle', points.body13.angle(points.body13cp1) - points.body13.angle(points.body14) )
+ store.set( 'tailCpDist', body13cp1d )
+
+ store.set( 'topFinOpening', points.body16.dist( points.body17 ))
+ store.set( 'topFinOpeningLength', (new Path().move(points.body16).curve(points.body16cp1, points.body17cp2, points.body17)).length())
+
+ store.set( 'faceTopLength', (new Path().move(points.body17).curve(points.body17cp1, points.body18cp2, points.body18).curve(points.body18cp1, points.body19cp2, points.body19)).length())
+
+ store.set( 'bellyLength', (new Path().move(points.body17).curve(points.body17cp1, points.body18cp2, points.body18).curve(points.body18cp1, points.body19cp2, points.body19)).length())
+ store.set( 'bellyTailLength', (new Path().move(points.body15).curve(points.body15cp1, points.body16cp2, points.body16)).length())
+
+ // Complete?
+ if (complete) {
+ if( sa ) {
+ paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
+ }
+
+ macro('ld', {
+ from: points.body13,
+ to: points.body01,
+ d: -5,
+ })
+ }
+
+ return part
+}
diff --git a/packages/hi/src/bottomFin.js b/packages/hi/src/bottomFin.js
new file mode 100644
index 00000000000..4e6562b7e0b
--- /dev/null
+++ b/packages/hi/src/bottomFin.js
@@ -0,0 +1,131 @@
+export default function (part) {
+ let {
+ store,
+ sa,
+ Point,
+ points,
+ Path,
+ paths,
+ Snippet,
+ snippets,
+ options,
+ measurements,
+ complete,
+ paperless,
+ macro,
+ } = part.shorthand()
+
+
+ let bottomFin01_02d = 250.63638754690027 * options.size
+ let bottomFin01_02a = 119.34849371430543
+ let bottomFin01_03d = 137.70322741678933 * options.size
+ let bottomFin01_03a = 175.11970494988498
+ let bottomFin01cp1d = 133.21819413653674 * options.size
+ let bottomFin01cp2d = 51.94197687805115 * options.size
+ let bottomFin01cp1a = 95.20910872095476
+ let bottomFin01cp2a = 158.66090918215986
+ let bottomFin02cp1d = 29.25974733588791 * options.size
+ let bottomFin02cp2d = 31.28292571739416 * options.size
+ let bottomFin02cp1a = 208.55316756249104
+ let bottomFin02cp2a = 28.113642612639804
+ let bottomFin03cp1d = 53.31550082293142 * options.size
+ let bottomFin03cp2d = 177.65809391356197 * options.size
+ let bottomFin03cp1a = 9.79694130335566
+ let bottomFin03cp2a = 80.81868300891519
+
+ let finLength = store.get('aboveMouthFinLength') + store.get('bellyFinLength')
+ let finCircumference = store.get('topFinCircumference')
+
+ console.log({ bellyFinLength: store.get('bellyFinLength') })
+ console.log({ finCircumference: store.get('topFinCircumference') })
+
+ let diff = 0
+ let iteration = 0
+ do {
+ points.bottomFin01 = new Point(0, 0)
+ points.bottomFin02 = points.bottomFin01.shift(bottomFin01_02a, bottomFin01_02d)
+ points.bottomFin03 = points.bottomFin01.shift(bottomFin01_03a, bottomFin01_03d)
+
+ points.bottomFin01cp1 = points.bottomFin01.shift(bottomFin01cp1a, bottomFin01cp1d)
+ points.bottomFin01cp2 = points.bottomFin01.shift(bottomFin01cp2a, bottomFin01cp2d)
+ points.bottomFin02cp1 = points.bottomFin02.shift(bottomFin02cp1a, bottomFin02cp1d)
+ points.bottomFin02cp2 = points.bottomFin02.shift(bottomFin02cp2a, bottomFin02cp2d)
+ points.bottomFin03cp1 = points.bottomFin03.shift(bottomFin03cp1a, bottomFin03cp1d)
+ points.bottomFin03cp2 = points.bottomFin03.shift(bottomFin03cp2a, bottomFin03cp2d)
+ diff =
+ finLength -
+ new Path()
+ .move(points.bottomFin03)
+ .curve(points.bottomFin03cp1, points.bottomFin01cp2, points.bottomFin01)
+ .length()
+
+ bottomFin01_03d = bottomFin01_03d + diff
+ iteration++
+ } while ((diff < -1 || diff > 1) && iteration < 100)
+ console.log({ iteration1: iteration })
+
+ diff = 0
+ iteration = 0
+ do {
+ points.bottomFin01 = new Point(0, 0)
+ points.bottomFin02 = points.bottomFin01.shift(bottomFin01_02a, bottomFin01_02d)
+ points.bottomFin03 = points.bottomFin01.shift(bottomFin01_03a, bottomFin01_03d)
+
+ points.bottomFin01cp1 = points.bottomFin01.shift(bottomFin01cp1a, bottomFin01cp1d)
+ points.bottomFin01cp2 = points.bottomFin01.shift(bottomFin01cp2a, bottomFin01cp2d)
+ points.bottomFin02cp1 = points.bottomFin02.shift(bottomFin02cp1a, bottomFin02cp1d)
+ points.bottomFin02cp2 = points.bottomFin02.shift(bottomFin02cp2a, bottomFin02cp2d)
+ points.bottomFin03cp1 = points.bottomFin03.shift(bottomFin03cp1a, bottomFin03cp1d)
+ points.bottomFin03cp2 = points.bottomFin03.shift(bottomFin03cp2a, bottomFin03cp2d)
+ diff =
+ finCircumference -
+ new Path()
+ .move(points.bottomFin01)
+ .curve(points.bottomFin01cp1, points.bottomFin02cp2, points.bottomFin02)
+ .curve(points.bottomFin02cp1, points.bottomFin03cp2, points.bottomFin03)
+ .length()
+
+ bottomFin01_02d = bottomFin01_02d + diff
+ iteration++
+ } while ((diff < -1 || diff > 1) && iteration < 100)
+
+ console.log({ iteration2: iteration })
+
+ console.log({ finLength: finLength })
+ console.log({
+ actual: new Path()
+ .move(points.bottomFin03)
+ .curve(points.bottomFin03cp1, points.bottomFin01cp2, points.bottomFin01)
+ .length(),
+ })
+
+ paths.seam = new Path()
+ .move(points.bottomFin01)
+ .curve(points.bottomFin01cp1, points.bottomFin02cp2, points.bottomFin02)
+ .curve(points.bottomFin02cp1, points.bottomFin03cp2, points.bottomFin03)
+ .curve(points.bottomFin03cp1, points.bottomFin01cp2, points.bottomFin01)
+ .close()
+
+ console.log({
+ bottomFinCirc: new Path()
+ .move(points.bottomFin01)
+ .curve(points.bottomFin01cp1, points.bottomFin02cp2, points.bottomFin02)
+ .curve(points.bottomFin02cp1, points.bottomFin03cp2, points.bottomFin03)
+ .length(),
+ })
+
+ points.bottomFinSnippet = new Path()
+ .move(points.bottomFin01)
+ .curve(points.bottomFin01cp2, points.bottomFin03cp1, points.bottomFin03)
+ .shiftAlong(store.get('aboveMouthFinLength'))
+ snippets.bottomFin = new Snippet('bnotch', points.bottomFinSnippet)
+
+ // Complete?
+ if (complete) {
+ if (sa) {
+ paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
+ }
+ }
+
+ return part
+}
diff --git a/packages/hi/src/index.js b/packages/hi/src/index.js
new file mode 100644
index 00000000000..e52e69247f1
--- /dev/null
+++ b/packages/hi/src/index.js
@@ -0,0 +1,23 @@
+import freesewing from '@freesewing/core'
+import plugins from '@freesewing/plugin-bundle'
+import config from '../config'
+import draftBody from './body'
+import draftTail from './tail'
+import draftMouth from './mouth'
+import draftAboveMouth from './aboveMouth'
+import draftBelly from './belly'
+import draftTopFin from './topFin'
+import draftBottomFin from './bottomFin'
+
+// Create design
+const Pattern = new freesewing.Design(config, plugins)
+
+Pattern.prototype.draftBody = draftBody
+Pattern.prototype.draftTail = draftTail
+Pattern.prototype.draftMouth = draftMouth
+Pattern.prototype.draftAboveMouth = draftAboveMouth
+Pattern.prototype.draftBelly = draftBelly
+Pattern.prototype.draftTopFin = draftTopFin
+Pattern.prototype.draftBottomFin = draftBottomFin
+
+export default Pattern
diff --git a/packages/hi/src/mouth.js b/packages/hi/src/mouth.js
new file mode 100644
index 00000000000..6699a243e1b
--- /dev/null
+++ b/packages/hi/src/mouth.js
@@ -0,0 +1,94 @@
+export default function (part) {
+ let {
+ store,
+ sa,
+ Point,
+ points,
+ Path,
+ paths,
+ Snippet,
+ snippets,
+ options,
+ measurements,
+ complete,
+ paperless,
+ macro,
+ } = part.shorthand()
+
+ let mouth01_02d = 141.93684055893488 * options.size
+ let mouth01_02a = 312.8254216093024
+ let mouth01_03d = 42.496 * options.size
+ let mouth01_03a = 270
+ let mouth01cp1d = 38.6204 * options.size
+ let mouth01cp1a = 0
+ let mouth02cp1d = 59.58739935676417 * options.size
+ let mouth02cp2d = 73.53520117766728 * options.size
+ let mouth02cp1a = 128.07726051101747
+ let mouth02cp2a = 95.21339058299296
+ let mouth03cp2d = 33.142 * options.size
+ let mouth03cp2a = 0
+
+ points.mouth01 = new Point(0, 0)
+ points.mouth02 = points.mouth01.shift(mouth01_02a, mouth01_02d)
+ points.mouth03 = points.mouth01.shift(mouth01_03a, mouth01_03d)
+
+ points.mouth01cp1 = points.mouth01.shift(mouth01cp1a, mouth01cp1d)
+ points.mouth02cp1 = points.mouth02.shift(mouth02cp1a, mouth02cp1d)
+ points.mouth02cp2 = points.mouth02.shift(mouth02cp2a, mouth02cp2d)
+ points.mouth03cp2 = points.mouth03.shift(mouth03cp2a, mouth03cp2d)
+
+ points.mouth04 = points.mouth02.flipX()
+
+ points.mouth01cp2 = points.mouth01cp1.flipX()
+ points.mouth04cp2 = points.mouth02cp1.flipX()
+ points.mouth04cp1 = points.mouth02cp2.flipX()
+ points.mouth03cp1 = points.mouth03cp2.flipX()
+
+ console.log({ mouth01_02d: points.mouth01.dist(points.mouth02) })
+ console.log({ mouth01_02a: points.mouth01.angle(points.mouth02) })
+ console.log({ mouth01_03d: points.mouth01.dist(points.mouth03) })
+ console.log({ mouth01_03a: points.mouth01.angle(points.mouth03) })
+
+ console.log({ mouth01cp1d: points.mouth01.dist(points.mouth01cp1) })
+ console.log({ mouth01cp1a: points.mouth01.angle(points.mouth01cp1) })
+ console.log({ mouth02cp1d: points.mouth02.dist(points.mouth02cp1) })
+ console.log({ mouth02cp2d: points.mouth02.dist(points.mouth02cp2) })
+ console.log({ mouth02cp1a: points.mouth02.angle(points.mouth02cp1) })
+ console.log({ mouth02cp2a: points.mouth02.angle(points.mouth02cp2) })
+ console.log({ mouth03cp2d: points.mouth03.dist(points.mouth03cp2) })
+ console.log({ mouth03cp2a: points.mouth03.angle(points.mouth03cp2) })
+
+ paths.seam = new Path()
+ .move(points.mouth01)
+ .curve(points.mouth01cp2, points.mouth04cp1, points.mouth04)
+ .curve(points.mouth04cp2, points.mouth03cp1, points.mouth03)
+ .curve(points.mouth03cp2, points.mouth02cp1, points.mouth02)
+ .curve(points.mouth02cp2, points.mouth01cp1, points.mouth01)
+
+ store.set(
+ 'mouthTopLength',
+ new Path()
+ .move(points.mouth01)
+ .curve(points.mouth01cp1, points.mouth02cp2, points.mouth02)
+ .length()
+ )
+ store.set(
+ 'mouthBottomLength',
+ new Path()
+ .move(points.mouth03)
+ .curve(points.mouth03cp1, points.mouth04cp2, points.mouth04)
+ .length()
+ )
+
+ snippets.mouthMidTop = new Snippet('bnotch', points.mouth01)
+ snippets.mouthMidBottom = new Snippet('bnotch', points.mouth03)
+
+ // Complete?
+ if (complete) {
+ if (sa) {
+ paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
+ }
+ }
+
+ return part
+}
diff --git a/packages/hi/src/tail.js b/packages/hi/src/tail.js
new file mode 100644
index 00000000000..37af71f3e15
--- /dev/null
+++ b/packages/hi/src/tail.js
@@ -0,0 +1,93 @@
+export default function (part) {
+ let {
+ store,
+ sa,
+ Point,
+ points,
+ Path,
+ paths,
+ Snippet,
+ snippets,
+ options,
+ measurements,
+ complete,
+ paperless,
+ macro,
+ } = part.shorthand()
+
+
+ let tail01_02d = 192.0129724628 * options.size
+ let tail01_02a = 53.242955551234914
+ let tail01_03d = 115.38057785000036 * options.size
+ let tail01_03a = 106.95066736265407
+ let tail01_04d = 230.05210782342334 * options.size
+ let tail01_04a = 138.66344842617497
+ let tail01_05d = 95.12771141996424 * options.size
+ let tail01_05a = 173.38284569091573
+ let tail01cp1d = 156.52907796955816 * options.size
+ let tail01cp2d = 33.33694275124821 * options.size
+ let tail01cp1a = 40.69161792982998
+ let tail01cp2a = 150.8191939475001
+ let tail02cp1d = 20.1307852802616 * options.size
+ let tail02cp2d = 26.418081118809575 * options.size
+ let tail02cp1a = 129.66709301725697
+ let tail02cp2a = 303.9168409570558
+ let tail03cp1d = 41.577 * options.size
+ let tail03cp2d = 41.575999999999965 * options.size
+ let tail03cp1a = 180
+ let tail03cp2a = -0
+ let tail04cp1d = 18.83137554720844 * options.size
+ let tail04cp2d = 18.830271479721173 * options.size
+ let tail04cp1a = 218.47354143777738
+ let tail04cp2a = 38.483984913053284
+ let tail05cp1d = 38.59528397356339 * options.size
+ let tail05cp2d = 126.7372982195849 * options.size
+ let tail05cp1a = 14.169822482118544
+ let tail05cp2a = 128.3396902984
+
+ points.tail01 = new Point(0, 0)
+ points.tail02 = points.tail01.shift(tail01_02a, tail01_02d)
+ points.tail03 = points.tail01.shift(tail01_03a, tail01_03d)
+ points.tail04 = points.tail01.shift(tail01_04a, tail01_04d)
+ points.tail05 = points.tail01.shift(tail01_05a, tail01_05d)
+
+ points.tail01cp1 = points.tail01.shift(tail01cp1a, tail01cp1d)
+ points.tail01cp2 = points.tail01.shift(tail01cp2a, tail01cp2d)
+ points.tail02cp1 = points.tail02.shift(tail02cp1a, tail02cp1d)
+ points.tail02cp2 = points.tail02.shift(tail02cp2a, tail02cp2d)
+ points.tail03cp1 = points.tail03.shift(tail03cp1a, tail03cp1d)
+ points.tail03cp2 = points.tail03.shift(tail03cp2a, tail03cp2d)
+ points.tail04cp1 = points.tail04.shift(tail04cp1a, tail04cp1d)
+ points.tail04cp2 = points.tail04.shift(tail04cp2a, tail04cp2d)
+ points.tail05cp1 = points.tail05.shift(tail05cp1a, tail05cp1d)
+ points.tail05cp2 = points.tail05.shift(tail05cp2a, tail05cp2d)
+
+ // Adjust tail opening:
+ points.tail05 = points.tail01.shift(points.tail01.angle(points.tail05), store.get('tailWidth'))
+ points.tail01cp2 = points.tail01.shift(
+ points.tail01.angle(points.tail05) - store.get('tailCpAngle'),
+ store.get('tailCpDist')
+ )
+ points.tail05cp1 = points.tail05.shift(
+ points.tail05.angle(points.tail01) + store.get('tailCpAngle'),
+ store.get('tailCpDist')
+ )
+
+ paths.seam = new Path()
+ .move(points.tail01)
+ .curve(points.tail01cp1, points.tail02cp2, points.tail02)
+ .curve(points.tail02cp1, points.tail03cp2, points.tail03)
+ .curve(points.tail03cp1, points.tail04cp2, points.tail04)
+ .curve(points.tail04cp1, points.tail05cp2, points.tail05)
+ .curve(points.tail05cp1, points.tail01cp2, points.tail01)
+ .close()
+
+ // Complete?
+ if (complete) {
+ if (sa) {
+ paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
+ }
+ }
+
+ return part
+}
diff --git a/packages/hi/src/topFin.js b/packages/hi/src/topFin.js
new file mode 100644
index 00000000000..6ae745d1da4
--- /dev/null
+++ b/packages/hi/src/topFin.js
@@ -0,0 +1,105 @@
+export default function (part) {
+ let {
+ store,
+ sa,
+ Point,
+ points,
+ Path,
+ paths,
+ Snippet,
+ snippets,
+ options,
+ measurements,
+ complete,
+ paperless,
+ macro,
+ } = part.shorthand()
+
+
+ let topFinOpening = store.get('topFinOpening')
+ let topFinOpeningLength = store.get('topFinOpeningLength')
+
+ let topFin01_02d = 256.9537569065251 * options.size
+ let topFin01_02a = 325.46697637215823
+ let topFin01_03d = 149.5416276819869 * options.size
+ let topFin01_03a = 275.4353725228365
+ let topFin01cp1d = 178.52481158058 * options.size
+ let topFin01cp2d = 27.240286624072077 * options.size
+ let topFin01cp1a = 346.31732410079576
+ let topFin01cp2a = 254.05347154462484
+ let topFin02cp1d = 25.871054481794893 * options.size
+ let topFin02cp2d = 12.154549189501026 * options.size
+ let topFin02cp1a = 236.80010054081936
+ let topFin02cp2a = 56.66685795767527
+ let topFin03cp1d = 39.024661651837555 * options.size
+ let topFin03cp2d = 76.08965682877273 * options.size
+ let topFin03cp1a = 113.40393219481112
+ let topFin03cp2a = 22.511206474810457
+
+ let diff = 0
+ let iteration = 0
+ do {
+ points.topFin01 = new Point(0, 0)
+ points.topFin02 = points.topFin01.shift(topFin01_02a, topFin01_02d)
+ points.topFin03 = points.topFin01.shift(topFin01_03a, topFinOpening) // topFin01_03d
+
+ points.topFin01cp1 = points.topFin01.shift(topFin01cp1a, topFin01cp1d)
+ points.topFin01cp2 = points.topFin01.shift(topFin01cp2a, topFin01cp2d)
+ points.topFin02cp1 = points.topFin02.shift(topFin02cp1a, topFin02cp1d)
+ points.topFin02cp2 = points.topFin02.shift(topFin02cp2a, topFin02cp2d)
+ points.topFin03cp1 = points.topFin03.shift(topFin03cp1a, topFin03cp1d)
+ points.topFin03cp2 = points.topFin03.shift(topFin03cp2a, topFin03cp2d)
+ diff =
+ topFinOpeningLength -
+ new Path()
+ .move(points.topFin03)
+ .curve(points.topFin03cp1, points.topFin01cp2, points.topFin01)
+ .length()
+
+ topFinOpening = topFinOpening + diff
+ iteration++
+ } while ((diff < -1 || diff > 1) && iteration < 100)
+
+ console.log({ iteration: iteration })
+
+ paths.seam = new Path()
+ .move(points.topFin01)
+ .curve(points.topFin01cp2, points.topFin03cp1, points.topFin03)
+ .curve(points.topFin03cp2, points.topFin02cp1, points.topFin02)
+ .curve(points.topFin02cp2, points.topFin01cp1, points.topFin01)
+ .close()
+
+ console.log({ topFinLength1: store.get('topFinOpeningLength') })
+ console.log({
+ topFinLength2: new Path()
+ .move(points.topFin03)
+ .curve(points.topFin03cp1, points.topFin01cp2, points.topFin01)
+ .length(),
+ })
+
+ store.set(
+ 'topFinCircumference',
+ new Path()
+ .move(points.topFin01)
+ .curve(points.topFin01cp1, points.topFin02cp2, points.topFin02)
+ .curve(points.topFin02cp1, points.topFin03cp2, points.topFin03)
+ .length()
+ )
+
+ console.log({
+ topFinCirc: new Path()
+ .move(points.topFin01)
+ .curve(points.topFin01cp1, points.topFin02cp2, points.topFin02)
+ .curve(points.topFin02cp1, points.topFin03cp2, points.topFin03)
+ .length(),
+ })
+
+ // Complete?
+ if (complete) {
+ if (sa) {
+ paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
+ }
+ }
+
+ return part
+}