From 44bb09e4c37631a5305df6d4372e0923e7fc7f4c Mon Sep 17 00:00:00 2001 From: Jonathan Haas Date: Fri, 19 Apr 2024 12:04:46 +0200 Subject: [PATCH] add(bibi): Add Bibi, a FreeSewing pattern for a knit top body block --- config/software/designs.json | 19 + designs/bibi/.prettierignore | 1 + designs/bibi/CHANGELOG.md | 17 + designs/bibi/README.md | 162 +++++++ designs/bibi/build.mjs | 35 ++ designs/bibi/data.mjs | 4 + designs/bibi/i18n/de.json | 50 ++ designs/bibi/i18n/en.json | 109 +++++ designs/bibi/i18n/es.json | 50 ++ designs/bibi/i18n/fr.json | 50 ++ designs/bibi/i18n/index.mjs | 8 + designs/bibi/i18n/nl.json | 50 ++ designs/bibi/i18n/uk.json | 50 ++ designs/bibi/package.json | 72 +++ designs/bibi/src/back.mjs | 267 ++++++++++ designs/bibi/src/front.mjs | 336 +++++++++++++ designs/bibi/src/index.mjs | 49 ++ designs/bibi/src/shared.mjs | 454 ++++++++++++++++++ designs/bibi/src/sleeve.mjs | 146 ++++++ designs/bibi/tests/shared.test.mjs | 20 + sites/lab/hooks/use-design.mjs | 2 + sites/org/hooks/use-design.mjs | 2 + sites/shared/i18n/designs.mjs | 2 + .../prebuild/data/design-measurements.mjs | 2 +- sites/shared/prebuild/data/designs.mjs | 2 +- 25 files changed, 1957 insertions(+), 2 deletions(-) create mode 100644 designs/bibi/.prettierignore create mode 100644 designs/bibi/CHANGELOG.md create mode 100644 designs/bibi/README.md create mode 100644 designs/bibi/build.mjs create mode 100644 designs/bibi/data.mjs create mode 100644 designs/bibi/i18n/de.json create mode 100644 designs/bibi/i18n/en.json create mode 100644 designs/bibi/i18n/es.json create mode 100644 designs/bibi/i18n/fr.json create mode 100644 designs/bibi/i18n/index.mjs create mode 100644 designs/bibi/i18n/nl.json create mode 100644 designs/bibi/i18n/uk.json create mode 100644 designs/bibi/package.json create mode 100644 designs/bibi/src/back.mjs create mode 100644 designs/bibi/src/front.mjs create mode 100644 designs/bibi/src/index.mjs create mode 100644 designs/bibi/src/shared.mjs create mode 100644 designs/bibi/src/sleeve.mjs create mode 100644 designs/bibi/tests/shared.test.mjs diff --git a/config/software/designs.json b/config/software/designs.json index 66cfa3d8fdc..0d40f83fe31 100644 --- a/config/software/designs.json +++ b/config/software/designs.json @@ -103,6 +103,25 @@ "setSleeve" ] }, + "bibi": { + "code": "Jonathan Haas", + "description": "A FreeSewing pattern for a knit top body block", + "design": [ + "Jonathan Haas" + ], + "difficulty": 2, + "lab": true, + "org": true, + "tags": [ + "blocks", + "tops" + ], + "techniques": [ + "curvedSeam", + "hem", + "flatSleeve" + ] + }, "bob": { "code": "Joost De Cock", "description": "A FreeSewing pattern for a bib", diff --git a/designs/bibi/.prettierignore b/designs/bibi/.prettierignore new file mode 100644 index 00000000000..0df7141f7d5 --- /dev/null +++ b/designs/bibi/.prettierignore @@ -0,0 +1 @@ +config/config.js diff --git a/designs/bibi/CHANGELOG.md b/designs/bibi/CHANGELOG.md new file mode 100644 index 00000000000..fd38619ed40 --- /dev/null +++ b/designs/bibi/CHANGELOG.md @@ -0,0 +1,17 @@ +# Change log for: @freesewing/bibi + + +## 3.0.0 (2023-09-30) + +### Changed + + - All FreeSewing packages are now ESM only. + - All FreeSewing packages now use named exports. + - Dropped support for NodeJS 14. NodeJS 18 (LTS/hydrogen) or more recent is now required. + + +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/designs/bibi/README.md b/designs/bibi/README.md new file mode 100644 index 00000000000..796f0db02b2 --- /dev/null +++ b/designs/bibi/README.md @@ -0,0 +1,162 @@ +

@freesewing/bibi on NPM + License: MIT + Code quality on DeepScan + Open issues tagged pkg:bibi + All Contributors +

Follow @freesewing_org on Twitter + Chat with us on Discord + Become a FreeSewing Patron + Follow @freesewing_org on Twitter +

+ +# @freesewing/bibi + +A FreeSewing pattern for overlap top + + + +# FreeSewing + +> [!TIP] +>#### Support FreeSewing: Become a patron, or make a one-time donation 🥰 +> +> FreeSewing is an open source project maintained by Joost De Cock and financially supported by the FreeSewing patrons. +> +> If you feel FreeSewing is worthwhile, and you can spend a few coins without +hardship, then you should [join us and become a patron](https://freesewing.org/community/join). + +## What am I looking at? 🤔 + +This repository is the FreeSewing *monorepo* holding all FreeSewing's websites, documentation, designs, plugins, and other NPM packages. + +This folder holds: @freesewing/bibi + +If you're not entirely sure what to do or how to start, type this command: + +``` +npm run tips +``` + +> [!NOTE] +> If you don't want to set up a dev environment, you can run it in your browser: +> +> [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/freesewing/freesewing) +> +> We recommend that you fork our repository and then +> put `gitpod.io/# to start up a browser-based dev environment of your own. + +## 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 +sewing patterns adapted to your measurements. + +If you're a developer, the FreeSewing documentation lives at [freesewing.dev](https://freesewing.dev/). +The FreeSewing [core library](https://freesewing.dev/reference/api/) is a *batteries-included* toolbox +for parametric design of sewing patterns. But FreeSewing also provides 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 @freesewing/new-design +``` + +Getting started guides are available for: +- [Linux](https://freesewing.dev/tutorials/getting-started-linux/) +- [MacOS](https://freesewing.dev/tutorials/getting-started-mac/) +- [Windows](https://freesewing.dev/tutorials/getting-started-windows/) + +The [pattern design tutorial](https://freesewing.dev/tutorials/pattern-design/) will +show you how to create your first parametric design. + +## Getting started ⚡ + +To get started with FreeSewing, you can spin up our development environment with: + +```bash +npx @freesewing/new-design +``` + +To work with FreeSewing's monorepo, you'll need [NodeJS v18](https://nodejs.org), [lerna](https://lerna.js.org/) and [yarn](https://yarnpkg.com/) on your system. +Once you have those, clone (or fork) this repo and run `yarn kickstart`: + +```bash +git clone git@github.com:freesewing/freesewing.git +cd freesewing +yarn kickstart +``` + +## Links 👩‍💻 + +**Official channels** + + - 💻 Makers website: [FreeSewing.org](https://freesewing.org) + - 💻 Developers website: [FreeSewing.dev](https://freesewing.dev) + - ✅ [Support](https://github.com/freesewing/freesewing/issues/new/choose), + [Issues](https://github.com/freesewing/freesewing/issues) & + [Discussions](https://github.com/freesewing/freesewing/discussions) on + [GitHub](https://github.com/freesewing/freesewing) + +**Social media** + + - 🐦 Twitter: [@freesewing_org](https://twitter.com/freesewing_org) + - 📷 Instagram: [@freesewing_org](https://instagram.com/freesewing_org) + +**Places the FreeSewing community hangs out** + + - 💬 [Discord](https://discord.freesewing.org/) + - 💬 [Facebook](https://www.facebook.com/groups/627769821272714/) + - 💬 [Reddit](https://www.reddit.com/r/freesewing/) + +## 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 🤯 + +For [Support](https://github.com/freesewing/freesewing/issues/new/choose), +please use the [Issues](https://github.com/freesewing/freesewing/issues) & +[Discussions](https://github.com/freesewing/freesewing/discussions) on +[GitHub](https://github.com/freesewing/freesewing). + diff --git a/designs/bibi/build.mjs b/designs/bibi/build.mjs new file mode 100644 index 00000000000..99ace216bc8 --- /dev/null +++ b/designs/bibi/build.mjs @@ -0,0 +1,35 @@ +/* This script will build the package with esbuild */ +import esbuild from 'esbuild' +import pkg from './package.json' assert { type: '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.mjs'], + format: 'esm', + outfile: 'dist/index.mjs', + external: ['@freesewing'], + metafile: process.env.VERBOSE ? true : false, + minify: process.env.NO_MINIFY ? false : true, + sourcemap: true, +} + +// Let esbuild generate the build +const build = async () => { + const result = await esbuild.build(options).catch(() => process.exit(1)) + + if (process.env.VERBOSE) { + const info = await esbuild.analyzeMetafile(result.metafile) + console.log(info) + } +} +build() diff --git a/designs/bibi/data.mjs b/designs/bibi/data.mjs new file mode 100644 index 00000000000..74c5e2f4766 --- /dev/null +++ b/designs/bibi/data.mjs @@ -0,0 +1,4 @@ +// This file is auto-generated | All changes you make will be overwritten. +export const name = '@freesewing/bibi' +export const version = '3.2.0' +export const data = { name, version } diff --git a/designs/bibi/i18n/de.json b/designs/bibi/i18n/de.json new file mode 100644 index 00000000000..6aa01adedfc --- /dev/null +++ b/designs/bibi/i18n/de.json @@ -0,0 +1,50 @@ +{ + "t": "Teagan, das T-Shirt", + "d": "Teagan ist ein Schnittmuster für ein passgenaues T-Shirt.", + "p": { + "back": "Rückseite", + "front": "Vorderseite", + "sleeve": "Ärmel" + }, + "s": { + "fullLengthFromHps": "Volle Länge (vom höchsten Schulterpunkt)" + }, + "o": { + "draftForHighBust": { + "t": "Entwurf für hohe Büste", + "d": "Zeichnen Sie das Muster für die hohe Büstenmessung (falls vorhanden) statt der (vollen) Truhe. Dies wird zu einem besser angepassten Kleidungsstück für Brustkleidung führen." + }, + "sleeveEase": { + "t": "Bequemlichkeitszugabe Ärmel", + "d": "Größe der Bequemlichkeitszugabe an den Ärmeln" + }, + "sleeveLength": { + "t": "Ärmellänge", + "d": "Steuert die Länge deiner Ärmel" + }, + "necklineBend": { + "t": "Krümmung Halsausschnitt", + "d": "Steuert die Krümmung des Halsausschnitts." + }, + "necklineDepth": { + "t": "Ausschnitttiefe", + "d": "Steuert, wie tief der Halsausschnitt fällt." + }, + "necklineWidth": { + "t": "Ausschnittbreite", + "d": "Steuert die Breite des Halsausschnitts." + }, + "curveToWaist": { + "t": "Fit the waist", + "d": "Whether or not to fit the waist or rahter only fit chest and hips." + }, + "curvedWaistEase": { + "t": "Waist ease", + "d": "Ease at the waist (only applies when the waist is fitted)." + }, + "hipsEase": { + "t": "Hips ease", + "d": "Ease at the hips." + } + } +} diff --git a/designs/bibi/i18n/en.json b/designs/bibi/i18n/en.json new file mode 100644 index 00000000000..5e3966a12e1 --- /dev/null +++ b/designs/bibi/i18n/en.json @@ -0,0 +1,109 @@ +{ + "t": "Bibi block body", + "d": "Bibi is a multifunctional building block for tops", + "p": { + "back": "Back", + "front": "Front", + "sleeve": "Sleeve" + }, + "s": { + "dartNo.t": "No bust dart", + "dartNo.d": "Gather fabric instead", + "dartYes.t": "Create a bust dart", + "dartYes.d": "If necessary, draft a bust dart to match side seam lengths", + "sleevesNo.t": "Sleeveless", + "sleevesNo.d": "Draft the pattern without sleeves", + "sleevesYes.t": "With sleeves", + "sleevesYes.d": "Draft the pattern with sleeves", + "fitWaistNo.t": "Don't fit the waist", + "fitWaistNo.d": "Create a loose fit and a more rectangular shape", + "fitWaistYes.t": "Fit the waist", + "fitWaistYes.d": "Create a more body-fitting shape", + "length.underbust.t": "Underbust", + "length.underbust.d": "Create a bralette top that only covers the bust.", + "length.waist.t": "Waist", + "length.waist.d": "Create a crop top.", + "length.hips.t": "Hips", + "length.hips.d": "Create a hip-length top.", + "length.seat.t": "Seat", + "length.seat.d": "Create a seat-length top.", + "length.knee.t": "Knee", + "length.knee.d": "Create a knee-length dress.", + "length.floor.t": "Floor", + "length.floor.d": "Create a floor-length dress. Use a negative length bonus to prevent the garment from actually dragging on the floor." + }, + "o": { + "draftForHighBust": { + "t": "Bust adjustment", + "d": "If the pattern should be drafted with a basic full bust adjustment (FBA). This will result in a more fitted garment for people with breasts." + }, + "draftForHighBustYes": { + "t": "Draft with bust adjustment", + "d": "Suggested for most people with breasts. This option only has an effect if the optional bust-related measurements are available." + }, + "draftForHighBustNo": { + "t": "Draft without bust adjustment", + "d": "Drafts a pattern using the chest measurement only." + }, + "cuffEase": { + "t": "Sleeve fullness", + "d": "Controls how wide the sleeves are." + }, + "sleeveLength": { + "t": "Sleeve length", + "d": "Controls the length of your sleeves" + }, + "necklineBend": { + "t": "Neckline curvature", + "d": "Controls the curvature of the neckline." + }, + "necklineDepth": { + "t": "Neckline depth", + "d": "Controls how deep the neck opening plunges down." + }, + "necklineWidth": { + "t": "Neckline width", + "d": "Controls the width of the neck opening." + }, + "fitWaist": { + "t": "Fit the waist", + "d": "Whether or not to fit the waist." + }, + "waistEase": { + "t": "Waist ease", + "d": "Ease at the waist (only applies when the waist is fitted)." + }, + "hipsEase": { + "t": "Hips ease", + "d": "Ease at the hips." + }, + "seatEase": { + "t": "Seat ease", + "d": "Ease at the seat." + }, + "bustEase": { + "t": "Bust ease", + "d": "Ease at the bust. Only applies when bust adjustment is enabled." + }, + "flare": { + "t": "Flare", + "d": "How much fabric to use at the bottom hem of the design. Only applies when the design goes below the seat." + }, + "dart": { + "t": "Allow bust dart", + "d": "Allow creating a bust dart if this is necessary" + }, + "sleeves": { + "t": "Sleeves", + "d": "Draft the pattern with sleeves" + }, + "strapWidth": { + "t": "Strap width", + "d": "How wide the shoulder straps are. Only applies when sleeves are disabled." + }, + "length": { + "t": "Length", + "d": "Which measurement line to use for the bottom hem. You can do fine adjustments using the bonus length option." + } + } +} diff --git a/designs/bibi/i18n/es.json b/designs/bibi/i18n/es.json new file mode 100644 index 00000000000..381ab9391b8 --- /dev/null +++ b/designs/bibi/i18n/es.json @@ -0,0 +1,50 @@ +{ + "t": "Teagan, camiseta", + "d": "Teagan es un patrón de camiseta entallada.", + "p": { + "back": "Atrás", + "front": "Frente", + "sleeve": "Manga" + }, + "s": { + "fullLengthFromHps": "Longitud completa (de HPS)" + }, + "o": { + "draftForHighBust": { + "t": "Borrador para alta caída", + "d": "Borra el patrón para la medición alta del polvo (si está disponible) en lugar del cofre (completo). Esto dará lugar a una prenda más ajustada para las personas con senos." + }, + "sleeveEase": { + "t": "Manga fácil", + "d": "Cantidad de facilidad de sus mangas" + }, + "sleeveLength": { + "t": "Longitud de la manga", + "d": "Controla la longitud de las mangas" + }, + "necklineBend": { + "t": "Curvatura neckline", + "d": "Controla la curvatura del cuello." + }, + "necklineDepth": { + "t": "Profundidad del cuello", + "d": "Controla la profundidad de la abertura del cuello." + }, + "necklineWidth": { + "t": "Neckline width", + "d": "Controla el ancho de la abertura del cuello." + }, + "curveToWaist": { + "t": "Fit the waist", + "d": "Whether or not to fit the waist or rahter only fit chest and hips." + }, + "curvedWaistEase": { + "t": "Waist ease", + "d": "Ease at the waist (only applies when the waist is fitted)." + }, + "hipsEase": { + "t": "Hips ease", + "d": "Ease at the hips." + } + } +} diff --git a/designs/bibi/i18n/fr.json b/designs/bibi/i18n/fr.json new file mode 100644 index 00000000000..15507133df6 --- /dev/null +++ b/designs/bibi/i18n/fr.json @@ -0,0 +1,50 @@ +{ + "t": "T-shirt Teagan", + "d": "Teagan est un T-shirt ajusté.", + "p": { + "back": "Retour", + "front": "Avant", + "sleeve": "Manche" + }, + "s": { + "fullLengthFromHps": "Longueur complète (à partir du haut de l'épaule)" + }, + "o": { + "draftForHighBust": { + "t": "Tracé pour le buste supérieur", + "d": "Tracer le patron pour la mesure de tour de poitrine supérieure (si disponible) plutôt que la poitrine (pleine). Il en résultera un vêtement plus ajusté pour les personnes qui ont des seins." + }, + "sleeveEase": { + "t": "Aisance des manches", + "d": "Quantité d'aisance de vos manches" + }, + "sleeveLength": { + "t": "Longueur des manches", + "d": "Contrôle la longueur de vos manches" + }, + "necklineBend": { + "t": "Courbure de l'encolure", + "d": "Contrôle la courbure de l'encolure." + }, + "necklineDepth": { + "t": "Profondeur de l'encolure", + "d": "Contrôle la profondeur de l'encolure." + }, + "necklineWidth": { + "t": "Largeur d'encolure", + "d": "Contrôle la largeur de l'encolure." + }, + "curveToWaist": { + "t": "Fit the waist", + "d": "Whether or not to fit the waist or rahter only fit chest and hips." + }, + "curvedWaistEase": { + "t": "Waist ease", + "d": "Ease at the waist (only applies when the waist is fitted)." + }, + "hipsEase": { + "t": "Hips ease", + "d": "Ease at the hips." + } + } +} diff --git a/designs/bibi/i18n/index.mjs b/designs/bibi/i18n/index.mjs new file mode 100644 index 00000000000..36aac928b67 --- /dev/null +++ b/designs/bibi/i18n/index.mjs @@ -0,0 +1,8 @@ +import en from './en.json' assert { type: 'json' } +import de from './de.json' assert { type: 'json' } +import es from './es.json' assert { type: 'json' } +import fr from './fr.json' assert { type: 'json' } +import nl from './nl.json' assert { type: 'json' } +import uk from './uk.json' assert { type: 'json' } + +export const i18n = { en, de, es, fr, nl, uk } diff --git a/designs/bibi/i18n/nl.json b/designs/bibi/i18n/nl.json new file mode 100644 index 00000000000..6ae4ae5ba5e --- /dev/null +++ b/designs/bibi/i18n/nl.json @@ -0,0 +1,50 @@ +{ + "t": "Teagan T-shirt", + "d": "Teagan is een patroon voor een aansluitend t-shirt.", + "p": { + "back": "Achterzijde", + "front": "Voorzijde", + "sleeve": "Mouw" + }, + "s": { + "fullLengthFromHps": "Afgewerkte lengte (vanaf HPS)" + }, + "o": { + "draftForHighBust": { + "t": "Teken voor hoge buste", + "d": "Teken het patroon voor de hoge bustemaat (indien beschikbaar) in plaats van de volle borstomtrek. Dit heeft een aansluitender kledingstuk als resultaat voor mensen met borsten." + }, + "sleeveEase": { + "t": "Overwijdte mouw", + "d": "De hoeveelheid extra ruimte in je mouwen" + }, + "sleeveLength": { + "t": "Mouwlengte", + "d": "Bepaalt de lengte van je mouwen" + }, + "necklineBend": { + "t": "Curve halslijn", + "d": "Bepaalt de curve van de halsuitsnijding." + }, + "necklineDepth": { + "t": "Diepte halsuitsnijding", + "d": "Bepaalt hoe diep de halsopening is." + }, + "necklineWidth": { + "t": "Breedte halsuitsnijding", + "d": "Bepaalt hoe breed de halsopening is." + }, + "curveToWaist": { + "t": "Fit the waist", + "d": "Whether or not to fit the waist or rahter only fit chest and hips." + }, + "curvedWaistEase": { + "t": "Waist ease", + "d": "Ease at the waist (only applies when the waist is fitted)." + }, + "hipsEase": { + "t": "Hips ease", + "d": "Ease at the hips." + } + } +} diff --git a/designs/bibi/i18n/uk.json b/designs/bibi/i18n/uk.json new file mode 100644 index 00000000000..689205eff60 --- /dev/null +++ b/designs/bibi/i18n/uk.json @@ -0,0 +1,50 @@ +{ + "t": "Teagan T-shirt", + "d": "Teagan is a fitted T-shirt pattern.", + "p": { + "back": "Back", + "front": "Front", + "sleeve": "Sleeve" + }, + "s": { + "fullLengthFromHps": "Full length (from HPS)" + }, + "o": { + "draftForHighBust": { + "t": "Draft for high bust", + "d": "Draft the pattern for the high bust measurement (if available) rather than the (full) chest. This will result in a more fitted garment for people with breasts." + }, + "sleeveEase": { + "t": "Sleeve ease", + "d": "Amount of ease of your sleeves" + }, + "sleeveLength": { + "t": "Sleeve length", + "d": "Controls the length of your sleeves" + }, + "necklineBend": { + "t": "Neckline curvature", + "d": "Controls the curvature of the neckline." + }, + "necklineDepth": { + "t": "Neckline depth", + "d": "Controls how deep the neck opening plunges down." + }, + "necklineWidth": { + "t": "Neckline width", + "d": "Controls the width of the neck opening." + }, + "curveToWaist": { + "t": "Fit the waist", + "d": "Whether or not to fit the waist or rahter only fit chest and hips." + }, + "curvedWaistEase": { + "t": "Waist ease", + "d": "Ease at the waist (only applies when the waist is fitted)." + }, + "hipsEase": { + "t": "Hips ease", + "d": "Ease at the hips." + } + } +} diff --git a/designs/bibi/package.json b/designs/bibi/package.json new file mode 100644 index 00000000000..57a3911fa2b --- /dev/null +++ b/designs/bibi/package.json @@ -0,0 +1,72 @@ +{ + "name": "@freesewing/bibi", + "version": "3.2.0", + "description": "A FreeSewing pattern for overlap top", + "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" + ], + "type": "module", + "module": "dist/index.mjs", + "exports": { + ".": { + "internal": "./src/index.mjs", + "default": "./dist/index.mjs" + } + }, + "scripts": { + "build": "node build.mjs", + "build:all": "yarn build", + "clean": "rimraf dist", + "mbuild": "NO_MINIFY=1 node build.mjs", + "symlink": "mkdir -p ./node_modules/@freesewing && cd ./node_modules/@freesewing && ln -s -f ../../../* . && cd -", + "test": "npx mocha tests/*.test.mjs", + "vbuild": "VERBOSE=1 node build.mjs", + "lab": "cd ../../sites/lab && yarn start", + "tips": "node ../../scripts/help.mjs", + "lint": "npx eslint 'src/**' 'tests/*.mjs'", + "prettier": "npx prettier --write 'src/*.mjs' 'tests/*.mjs'", + "testci": "NODE_OPTIONS=\"--conditions=internal\" npx mocha tests/*.test.mjs --reporter ../../tests/reporters/terse.js", + "wbuild": "node build.mjs", + "wbuild:all": "yarn wbuild" + }, + "peerDependencies": { + "@freesewing/brian": "3.2.0", + "@freesewing/core": "3.2.0" + }, + "devDependencies": { + "@freesewing/models": "3.2.0", + "@freesewing/plugin-timing": "3.2.0", + "chai": "5.1.0", + "mocha": "10.3.0" + }, + "files": [ + "dist/*", + "README.md" + ], + "publishConfig": { + "access": "public", + "tag": "latest" + }, + "engines": { + "node": ">= 18.17.0 <22" + } +} diff --git a/designs/bibi/src/back.mjs b/designs/bibi/src/back.mjs new file mode 100644 index 00000000000..46747d6eced --- /dev/null +++ b/designs/bibi/src/back.mjs @@ -0,0 +1,267 @@ +import { base } from '@freesewing/brian' +import { + adjustSidePoints, + constructBackHem, + constructBackPoints, + correctArmHole, + createArmHoles, + plotSideLineMeasurements, +} from './shared.mjs' +import { sleeve } from './sleeve.mjs' + +export const back = { + name: 'bibi.back', + from: base, + measurements: ['hips', 'waist', 'hpsToWaistBack', 'chest', 'seat', 'seatBack', 'waistToSeat'], + optionalMeasurements: ['bustSpan', 'highBust', 'waistToUnderbust', 'waistToKnee', 'waistToFloor'], + hide: { from: true }, + after: sleeve, + options: { + // Brian overrides + s3Collar: 0, + s3Armhole: 0, + brianFitSleeve: true, + brianFitCollar: false, + bicepsEase: 0.05, + collarEase: 0, + shoulderSlopeReduction: 0, + sleeveWidthGuarantee: 0.85, + frontArmholeDeeper: 0.01, + legacyArmholeDepth: false, + shoulderEase: { pct: 0, min: -2, max: 6, menu: 'fit' }, + // Note: we reuse Brian's cuff ease as "armhole fullness" + cuffEase: { + pct: 20, + min: 0, + max: 200, + menu: (settings, mergedOptions) => + mergedOptions.sleeves === false ? false : 'style.sleeves', + }, + armholeDepth: { + pct: 2, + min: -10, + max: 50, + menu: (settings, mergedOptions) => + mergedOptions?.legacyArmholeDepth ? false : 'style.sleeves', + }, + lengthBonus: { pct: 0, min: -30, max: 30, menu: 'style.length' }, + draftForHighBust: { bool: true, menu: 'fit' }, + // Bibi specific + fitWaist: { bool: true, menu: 'fit', order: 'EBA' }, + waistEase: { + pct: 1, + min: -10, + max: 20, + menu: (settings, mergedOptions) => (mergedOptions.fitWaist ? 'fit' : false), + order: 'EBB', + }, + hipsEase: { pct: 2, min: -5, max: 50, menu: 'fit', order: 'ECA' }, + seatEase: { pct: 2, min: -5, max: 50, menu: 'fit', order: 'EDA' }, + chestEase: { pct: 2, min: -5, max: 25, menu: 'fit', order: 'EAB' }, + + length: { + dflt: 'seat', + list: ['underbust', 'waist', 'hips', 'seat', 'knee', 'floor'], + menu: 'style.length', + }, + flare: { + pct: 5, + min: 0, + max: 150, + menu: (settings, mergedOptions) => + (mergedOptions.length === 'seat' && mergedOptions.lengthBonus > 0) || + mergedOptions.length === 'knee' || + mergedOptions.length === 'floor' + ? 'style.length' + : false, + }, + strapWidth: { + pct: 40, + min: 5, + max: 100, + menu: (settings, mergedOptions) => (mergedOptions.sleeves ? false : 'style.sleeves'), + }, + sleeves: { bool: true, menu: 'style.sleeves' }, + + backNeckCutout: { pct: 10, min: 6, max: 30, menu: 'style' }, + }, + draft: bibiBack, +} + +function bibiBack({ + store, + sa, + Point, + points, + Path, + paths, + Snippet, + snippets, + options, + measurements, + macro, + complete, + utils, + part, +}) { + // Hide Brian paths + for (let key of Object.keys(paths)) paths[key].hide() + + // Re-use points for deeper armhole at the front + points.armholePitchCp1 = points.backArmholePitchCp1 + points.armholePitch = points.backArmholePitch + points.armholePitchCp2 = points.backArmholePitchCp2 + + // clean up some unnecessary points + delete points.frontArmholePitchCp1 + delete points.frontArmholePitch + delete points.frontArmholePitchCp2 + delete points.backArmholePitchCp1 + delete points.backArmholePitch + delete points.backArmholePitchCp2 + + constructBackPoints(points, Point, measurements, options) + + adjustSidePoints(points, options) + + correctArmHole(points, paths, Path, options, utils) + // + // points.cfNeck = new Point(0, options.necklineDepth * measurements.hpsToWaistFront) + // points.cfNeckCp1 = points.cfNeck.shift(0, points.neck.x * options.necklineBend * 2) + // points.neck = points.hps.shiftFractionTowards( + // points.shoulder, + // options.necklineWidth * (1 - options.strapWidth) + // ) + // points.neckCp2 = points.neck + // .shiftTowards(points.shoulder, points.neck.dy(points.cfNeck) * (0.2 + options.necklineBend)) + // .rotate(-90, points.neck) + // + // paths.frontNeck = new Path() + // .move(points.neck) + // .curve(points.neckCp2, points.cfNeckCp1, points.cfNeck) + + points.cbHem = new Point(0, points.cbWaist.y + measurements.waistToHips * options.lengthBonus) + + constructBackHem(points, measurements, options, Point, paths, Path) + + store.set('backSideSeamLength', paths.sideSeam.length()) + + let strapWidth = options.sleeves ? 0 : options.strapWidth + points.neck = points.hps.shiftFractionTowards( + points.shoulder, + options.necklineWidth * (1 - strapWidth) + ) + + points.cbNeck = new Point( + 0, + points.neck.y + options.backNeckCutout * points.neck.dy(points.armhole) + ) + + // points.cbNeckCp1 = points.cfNeck.shift(0, points.neck.x * options.necklineBend * 2) + // points.neckCp2 = points.neck + // .shiftTowards(points.shoulder, points.neck.dy(points.cfNeck) * (0.2 + options.necklineBend)) + // .rotate(-90, points.neck) + + points.neckCp2 = points.neck.shiftTowards(points.shoulder, 10).rotate(-90, points.neck) + points.neckCp2 = utils.beamIntersectsY(points.neck, points.neckCp2, points.cbNeck.y) + + points.neckCp1 = new Point(points.neck.x / 3, points.cbNeck.y) + + paths.backNeck = new Path() + .move(points.neck) + .curve(points.neckCp2, points.neckCp1, points.cbNeck) + .addClass('fabric') + createArmHoles(options, store, points, paths, Path, snippets, Snippet, strapWidth, 'bnotch') + + paths.centerLine = new Path().move(points.cbNeck).line(points.cbHem).addClass('fabric') + + store.set( + 'gatherAreaStart', + Math.min(points.armhole.dy(points.cbWaist) / 10, paths.sideSeam.length() * 0.1) + ) + store.set( + 'gatherAreaLength', + Math.min(paths.sideSeam.length() * 0.8, points.armhole.dy(points.cbWaist) * 0.5) + ) + + const reverse = paths.sideSeam.reverse() + snippets.gatherAreaStart = new Snippet('notch', reverse.shiftAlong(store.get('gatherAreaStart'))) + snippets.gatherAreaBack = new Snippet( + 'notch', + reverse.shiftAlong(store.get('gatherAreaStart') + store.get('gatherAreaLength')) + ) + + if (sa) { + paths.sa = new Path() + .move(points.cbHem) + .join(paths.hem.offset(sa * 3)) + .join(paths.sideSeam.offset(sa)) + .join(paths.armhole.offset(sa)) + .join(paths.shoulder.offset(sa)) + .join(paths.backNeck.offset(sa)) + .line(points.cbNeck) + .attr('class', 'fabric sa') + } + + macro('cutonfold', { + from: points.cfNeck, + to: points.cbHem, + grainline: true, + }) + + points.scaleboxAnchor = points.logo.shift(-90, 10) + + macro('scalebox', { + at: points.scaleboxAnchor, + }) + + snippets.logo = new Snippet('logo', points.logo) + + macro('title', { at: points.title, nr: 2, title: 'back' }) + + if (complete && points.hem.y > points.waist.y) + paths.waist = new Path().move(points.cbWaist).line(points.waist).attr('class', 'help') + + macro('pd', { + id: 'pArmhole', + path: paths.armhole.reverse(), + d: -1 * sa - 15, + }) + + macro('pd', { + id: 'pNeck', + path: paths.backNeck.reverse(), + d: -1 * sa - 15, + }) + + macro('pd', { + id: 'pShoulder', + path: paths.shoulder.reverse(), + d: -1 * sa - 15, + }) + + macro('hd', { + id: 'wAtHem', + from: points.cbHem, + to: points.hem, + y: points.cbHem.y + sa * 2.5 + 15, + }) + + macro('vd', { + id: 'hHemToNeck', + from: points.cbHem, + to: points.cbNeck, + x: points.cbHem.x - sa - 15, + }) + + macro('vd', { + id: 'hNeckToArmhole', + from: points.neck, + to: points.armhole, + x: points.armhole.x + sa + 15, + }) + + plotSideLineMeasurements(points, paths.sideSeam, utils, macro) + + return part +} diff --git a/designs/bibi/src/front.mjs b/designs/bibi/src/front.mjs new file mode 100644 index 00000000000..93a74cbdae7 --- /dev/null +++ b/designs/bibi/src/front.mjs @@ -0,0 +1,336 @@ +import { base } from '@freesewing/brian' +import { back } from './back.mjs' +import { + adjustSidePoints, + calculateFba, + constructFrontHem, + constructFrontPoints, + correctArmHole, + createArmHoles, + plotSideLineMeasurements, +} from './shared.mjs' + +export const front = { + name: 'bibi.front', + from: base, + measurements: [ + 'hips', + 'waist', + 'hpsToWaistBack', + 'chest', + 'hpsToWaistFront', + 'seat', + 'seatBack', + 'waistToSeat', + 'hpsToBust', + ], + optionalMeasurements: ['bustSpan', 'highBust', 'waistToUnderbust', 'waistToKnee', 'waistToFloor'], + hide: { from: true }, + plugins: [], + after: back, + options: { + dart: { bool: false, menu: 'fit' }, + bustEase: { + pct: 0, + min: 0, + max: 10, + menu: (settings, mergedOptions) => (mergedOptions.draftForHighBust ? 'fit' : false), + order: 'EAA', + }, + + necklineDepth: { pct: 25, min: 20, max: 60, menu: 'style' }, + necklineWidth: { pct: 50, min: 10, max: 90, menu: 'style' }, + necklineBend: { pct: 50, min: 0, max: 70, menu: 'style' }, + }, + draft: bibiFront, +} + +function bibiFront({ + store, + sa, + Point, + points, + Path, + paths, + Snippet, + snippets, + options, + measurements, + macro, + complete, + utils, + part, +}) { + // Hide Brian paths + for (let key of Object.keys(paths)) paths[key].hide() + + // Re-use points for deeper armhole at the front + points.armholePitchCp1 = points.frontArmholePitchCp1 + points.armholePitch = points.frontArmholePitch + points.armholePitchCp2 = points.frontArmholePitchCp2 + + // clean up some unnecessary points + delete points.frontArmholePitchCp1 + delete points.frontArmholePitch + delete points.frontArmholePitchCp2 + delete points.backArmholePitchCp1 + delete points.backArmholePitch + delete points.backArmholePitchCp2 + delete points.cbHem + + constructFrontPoints(points, Point, measurements, options) + + // FBA + points.originalChest = points.chest + points.originalArmhole = points.armhole + points.originalArmholeCp2 = points.armholeCp2 + let fba + if (options.draftForHighBust && measurements.bustSpan && measurements.highBust) { + fba = calculateFba( + points.neck.shiftFractionTowards(points.shoulder, 0.5), + points.bust, + points.armholeHollow, + (measurements.bust * (1 + options.bustEase) - measurements.chest) / 2, + Point + ) + points.bustOffset = fba.bustOffset + points.sideOffset0 = fba.sideOffset0 + points.sideOffset1 = fba.sideOffset1 + points.chest = fba.rotateLower(points.chest) + points.armhole = fba.rotateUpper(points.armhole) + points.armholeCp2 = fba.rotateUpper(points.armholeCp2) + points.armholeHollowCp1 = fba.rotateUpper(points.armholeHollowCp1) + points.armholeHollow = fba.rotateUpper(points.armholeHollow) + points.armholeHollowCp2 = fba.rotateUpper(points.armholeHollowCp2) + points.armholePitchCp1 = fba.rotateUpper(points.armholePitchCp1) + points.armholePitch = fba.rotateUpper(points.armholePitch) + points.armholePitchCp2 = fba.rotateUpper(points.armholePitchCp2) + points.shoulderCp1 = fba.rotateUpper(points.shoulderCp1) + points.shoulder = fba.rotateUpper(points.shoulder) + } + adjustSidePoints(points, options) + + correctArmHole(points, paths, Path, options, utils) + + points.cfNeck = new Point(0, options.necklineDepth * measurements.hpsToWaistFront) + points.cfNeckCp1 = points.cfNeck.shift(0, points.neck.x * options.necklineBend * 2) + let strapWidth = options.sleeves ? 0 : options.strapWidth + points.neck = points.hps.shiftFractionTowards( + points.shoulder, + options.necklineWidth * (1 - strapWidth) + ) + points.neckCp2 = points.neck + .shiftTowards(points.shoulder, points.neck.dy(points.cfNeck) * (0.2 + options.necklineBend)) + .rotate(-90, points.neck) + + paths.frontNeck = new Path() + .move(points.neck) + .curve(points.neckCp2, points.cfNeckCp1, points.cfNeck) + .addClass('fabric') + constructFrontHem(points, measurements, options, Point, paths, Path) + + store.set('frontSideSeamLength', paths.sideSeam.length()) + let frontLength = store.get('frontSideSeamLength') + let backLength = store.get('backSideSeamLength') ?? 0 + let dartLength = frontLength - backLength + const constructDart = (path, tip, dartLength) => { + let length = path.length() + + dartLength = Math.max(0, Math.min(dartLength, length / 2)) + + let gatherArea = (store.get('gatherAreaLength') ?? 0) + dartLength + let offset = length - (store.get('gatherAreaStart') ?? 0) - gatherArea + + let startSplit = path.shiftAlong(offset) + let startDartAlpha = path.shiftAlong(offset + (gatherArea - dartLength) * 0.5) + let endDartAlpha = path.shiftAlong(offset + (gatherArea + dartLength) * 0.5) + let endSplit = path.shiftAlong(offset + gatherArea) + + let tmp = path.split(startSplit) + let pathBefore = tmp[0] + tmp = tmp[1].split(endSplit) + let pathGather = tmp[0] + let pathAfter = tmp[1] + let angleBefore = path.angleAt(startSplit) + let angleAfter = path.angleAt(endSplit) + let cpBefore = startSplit.shift(angleBefore, dartLength / 3) + let cpAfter = endSplit.shift(angleAfter, -dartLength / 3) + + let dartDist = Math.max(tip.dist(startDartAlpha), tip.dist(endDartAlpha)) + + let startDart = tip.shiftTowards(startDartAlpha, dartDist) + let endDart = tip.shiftTowards(endDartAlpha, dartDist) + let dartMid = startDart.shiftFractionTowards(endDart, 0.5) + let tipShifted = tip.shiftFractionTowards(dartMid, 0.25) + let dartCpStart = tipShifted + .shiftFractionTowards(dartMid, 0.25) + .shiftFractionTowards(startDart, 0.25) + let dartCpEnd = tipShifted + .shiftFractionTowards(dartMid, 0.25) + .shiftFractionTowards(endDart, 0.25) + + const dartAngleMain = startDart.angle(endDart) + const dartAngleBefore = startDartAlpha.angle(endDartAlpha) + const dartAngle = dartAngleBefore * 2 - dartAngleMain + let dartInnerAngle = tipShifted.angle(endDart) - tipShifted.angle(startDart) + if (dartInnerAngle < -180) dartInnerAngle += 360 + let cpSplitStart = startDart.shift(dartAngle - dartInnerAngle / 2, -dartLength / 4) + let cpSplitEnd = endDart.shift(dartAngle + dartInnerAngle / 2, dartLength / 4) + + return { + beforeDart: pathBefore.clone().curve(cpBefore, cpSplitStart, startDart), + dart: new Path().move(startDart)._curve(dartCpStart, tipShifted).curve_(dartCpEnd, endDart), + afterDart: new Path().move(endDart).curve(cpSplitEnd, cpAfter, endSplit).join(pathAfter), + dartMiddle: new Path().move(dartMid).line(tipShifted), + startGather: startSplit, + endGather: endSplit, + startDart: startDart, + endDart: endDart, + dartTip: tipShifted, + gatherArea: gatherArea, + gatherPath: pathGather, + dartLength: dartLength, + offset: offset, + } + } + + const dart = constructDart(paths.sideSeam, points.bust, dartLength) + + store.set('dart', dart) + + points.startGather = dart.startGather + points.endGather = dart.endGather + points.startDart = dart.startDart + points.endDart = dart.endDart + points.dartTip = dart.dartTip + + paths.sideSeamWithDart = paths.originalSideSeam = paths.sideSeam.clone().hide() + if (options.dart && dartLength > dart.gatherArea / 5) { + paths.sideSeam1 = dart.beforeDart.hide() + paths.dart = dart.dart.addClass('fabric') + paths.sideSeam2 = dart.afterDart.hide() + if (complete) { + paths.dartMiddle = dart.dartMiddle.addClass('help') + } + paths.sideSeam = paths.sideSeam1.clone().combine(paths.sideSeam2).addClass('fabric') + paths.sideSeamWithDart = paths.sideSeam1.clone().join(paths.dart).join(paths.sideSeam2).hide() + } + if (complete) { + snippets.startGather = new Snippet('notch', points.startGather) + snippets.endGather = new Snippet('notch', points.endGather) + if (dartLength > dart.gatherArea / 10 && !paths.dart) { + paths.gatherPath = new Path() + .move(points.startGather) + .join(dart.gatherPath.offset(-20)) + .line(points.endGather) + .addClass('dashed various') + .addText('gather', 'center various help') + } + } + createArmHoles(options, store, points, paths, Path, snippets, Snippet, strapWidth) + + paths.centerLine = new Path().move(points.cfNeck).line(points.cfHem).addClass('fabric') + + macro('title', { at: points.title, nr: 1, title: 'front' }) + + macro('cutonfold', { + from: points.cfNeck, + to: points.cfHem, + grainline: true, + }) + + if (sa) { + if (paths.sideSeam1) + paths.sa = new Path() + .move(points.cfHem) + .join(paths.hem.offset(sa * 3)) + .join(paths.sideSeam1.offset(sa)) + .join(paths.sideSeam2.offset(sa)) + .join(paths.armhole.offset(sa)) + .join(paths.shoulder.offset(sa)) + .join(paths.frontNeck.offset(sa)) + .line(points.cfNeck) + .attr('class', 'fabric sa') + else + paths.sa = new Path() + .move(points.cfHem) + .join(paths.hem.offset(sa * 3)) + .join(paths.sideSeam.offset(sa)) + .join(paths.armhole.offset(sa)) + .join(paths.shoulder.offset(sa)) + .join(paths.frontNeck.offset(sa)) + .line(points.cfNeck) + .attr('class', 'fabric sa') + } + + // Waist line + if (complete && points.hem.y > points.waist.y) + paths.waist = new Path().move(points.cfWaist).line(points.waist).attr('class', 'help') + + macro('pd', { + id: 'pArmhole', + path: paths.armhole.reverse(), + d: -1 * sa - 15, + }) + + macro('pd', { + id: 'pNeck', + path: paths.frontNeck.reverse(), + d: -1 * sa - 15, + }) + + macro('pd', { + id: 'pShoulder', + path: paths.shoulder.reverse(), + d: -1 * sa - 15, + }) + + macro('hd', { + id: 'wAtHem', + from: points.cfHem, + to: points.hem, + y: points.hem.y + sa * 2.5 + 15, + }) + + macro('vd', { + id: 'hHemToNeck', + from: points.cfHem, + to: points.cfNeck, + x: points.cfHem.x - sa - 15, + }) + + macro('vd', { + id: 'hNeckToArmhole', + from: points.neck, + to: points.armhole, + x: points.armhole.x + sa + 15, + }) + + if (paths.dart) { + macro('vd', { + id: 'hDart', + from: points.endDart, + to: points.startDart, + x: points.endDart.x + sa + 15, + }) + + macro('ld', { + id: 'pDartStart', + from: points.dartTip, + to: points.startDart, + d: -sa - 15, + }) + macro('ld', { + id: 'pDartEnd', + from: points.dartTip, + to: points.endDart, + d: sa + 15, + }) + + snippets.bustPoint = new Snippet('notch', points.bust) + } + + plotSideLineMeasurements(points, paths.sideSeamWithDart, utils, macro) + + return part +} diff --git a/designs/bibi/src/index.mjs b/designs/bibi/src/index.mjs new file mode 100644 index 00000000000..7770e7c28a5 --- /dev/null +++ b/designs/bibi/src/index.mjs @@ -0,0 +1,49 @@ +import { Design, mergeI18n } from '@freesewing/core' +import { data } from '../data.mjs' +import { i18n as brianI18n } from '@freesewing/brian' +import { i18n as bibiI18n } from '../i18n/index.mjs' +import { front } from './front.mjs' +import { back } from './back.mjs' +import { sleeve } from './sleeve.mjs' +import { + constructFrontPoints, + constructBackPoints, + calculateFba, + correctArmHole, + constructSideSeam, + adjustSidePoints, + constructBackHem, + constructFrontHem, + createArmHoles, + plotSideLineMeasurements, +} from './shared.mjs' + +// Setup our new design +const Bibi = new Design({ + data, + parts: [sleeve, back, front], +}) + +// Merge translations +const i18n = mergeI18n([brianI18n, bibiI18n], { + o: { drop: ['sleeveLengthBonus'] }, +}) + +// Named exports +export { + front, + back, + sleeve, + constructFrontPoints, + constructBackPoints, + calculateFba, + correctArmHole, + constructSideSeam, + adjustSidePoints, + constructBackHem, + constructFrontHem, + createArmHoles, + plotSideLineMeasurements, + Bibi, + i18n, +} diff --git a/designs/bibi/src/shared.mjs b/designs/bibi/src/shared.mjs new file mode 100644 index 00000000000..491078fa66c --- /dev/null +++ b/designs/bibi/src/shared.mjs @@ -0,0 +1,454 @@ +function createLowerPoints(points, measurements, options, prefix) { + // These lengths are typically not critical, so use a rough estimate if not given + // We don't want the user to need these measurements, as this design can also be used for shorter tops + if (typeof measurements.waistToKnee !== 'undefined') { + points[prefix + 'Knee'] = points[prefix + 'Waist'].translate(0, measurements.waistToKnee) + } else { + points[prefix + 'Knee'] = points[prefix + 'Waist'].translate( + 0, + measurements.hpsToWaistBack * 1.5 + ) + } + if (typeof measurements.waistToFloor !== 'undefined') { + points[prefix + 'Floor'] = points[prefix + 'Waist'].translate(0, measurements.waistToFloor) + } else { + points[prefix + 'Floor'] = points[prefix + 'Waist'].translate( + 0, + measurements.hpsToWaistBack * 2.5 + ) + } + points.sideTarget = points[prefix + 'Knee'].translate(points.seatBase.x * (1 + options.flare), 0) +} + +export function constructFrontPoints(points, Point, measurements, options) { + points.cfBust = new Point(0, measurements.hpsToBust) + if (measurements.bustSpan) { + points.bust = new Point(measurements.bustSpan / 2, measurements.hpsToBust) + } else { + // Very rough estimate, but only used for potential dart construction + points.bust = new Point(measurements.chest / 8, measurements.hpsToBust) + } + points.chest = new Point( + (measurements.chest * (1 + options.chestEase)) / 4, + measurements.hpsToBust + ) + points.cbWaist = new Point(0, measurements.hpsToWaistBack) + points.cfWaist = new Point(0, measurements.hpsToWaistFront) + points.waist = new Point((measurements.waist * (1 + options.waistEase)) / 4, points.cfWaist.y) + points.cfArmhole = new Point( + 0, + points.cbWaist.y - + measurements.waistToArmpit * (1 - options.armholeDepth - options.bicepsEase / 2) + ) + points.armhole = new Point(points.armhole.x, points.cfArmhole.y) + points.armholeCp2 = points.armhole.shift(180, points._tmp1.dx(points.armhole) / 4) + + points.cfUnderbust = new Point( + 0, + points.cfWaist.y - (measurements.waistToUnderbust ?? measurements.hpsToWaistBack / 6) + ) + points.underbust = new Point( + (measurements.chest * (1 + options.chestEase)) / 4, + points.cfUnderbust.y + ) + points.cfHips = new Point(0, points.cfWaist.y + measurements.waistToHips) + points.hips = new Point((measurements.hips * (1 + options.hipsEase)) / 4, points.cfHips.y) + + const seatFront = measurements.seat - measurements.seatBack + const seatExtra = (measurements.seatBack - seatFront) / 4 + points.cfSeat = new Point(0, points.cfWaist.y + measurements.waistToSeat) + points.seatBase = new Point((measurements.seat * (1 + options.seatEase)) / 4, points.cfSeat.y) + points.seat = seatAdjustment(points.seatBase, points.hips, -seatExtra) + // points.cfSeat = points.cfSeat.shift(-90, -seatExtra * 2) + + createLowerPoints(points, measurements, options, 'cf') +} + +export function constructBackPoints(points, Point, measurements, options) { + points.chest = new Point( + (measurements.chest * (1 + options.chestEase)) / 4, + measurements.hpsToBust + ) + points.cbWaist = new Point(0, measurements.hpsToWaistBack) + points.waist = new Point((measurements.waist * (1 + options.waistEase)) / 4, points.cbWaist.y) + points.cbUnderbust = new Point( + 0, + points.cbWaist.y - (measurements.waistToUnderbust ?? measurements.hpsToWaistBack / 6) + ) + points.underbust = new Point( + (measurements.chest * (1 + options.chestEase)) / 4, + points.cbUnderbust.y + ) + points.cbHips = new Point(0, points.cbWaist.y + measurements.waistToHips) + points.hips = new Point((measurements.hips * (1 + options.hipsEase)) / 4, points.cbHips.y) + + points.cbSeat = new Point(0, points.cbWaist.y + measurements.waistToSeat) + const seatFront = measurements.seat - measurements.seatBack + const seatExtra = (measurements.seatBack - seatFront) / 4 + points.seatBase = new Point((measurements.seat * (1 + options.seatEase)) / 4, points.cbSeat.y) + points.seat = seatAdjustment(points.seatBase, points.hips, seatExtra) + // points.cbSeat = points.cbSeat.shift(-90, seatExtra * 2) + + createLowerPoints(points, measurements, options, 'cb') +} + +function seatAdjustment(seatBase, anchor, seatExtra) { + const r = anchor.dist(seatBase) + return seatBase.rotate((seatExtra / r) * 90, anchor) +} + +export function calculateFba(anchor, bust, side, dx, Point) { + const r = anchor.dist(bust) + + const a0 = Math.asin((bust.x - anchor.x) / r) + let a1 = Math.asin((bust.x - anchor.x + dx) / r) + + if (isNaN(a1)) { + a1 = Math.PI / 2 + } + + const bustOffset = new Point(anchor.x + r * Math.sin(a1), anchor.y + r * Math.cos(a1)) + + const dy = bustOffset.y - bust.y + + const b = a1 - a0 + + const rotateUpper = (point) => point.rotate((b / Math.PI) * 180, anchor) + + const sideOffset0 = rotateUpper(side) + const sideOffset1 = side.translate(dx, dy) + + const c = sideOffset1.angle(bust) - sideOffset0.angle(bust) + + const rotateLower = (point) => point.translate(dx, dy).rotate(-c, bust) + + return { + dx: dx, + dy: dy, + rotateUpper: rotateUpper, + rotateLower: rotateLower, + bustOffset: bustOffset, + sideOffset0: sideOffset0, + sideOffset1: sideOffset1, + } +} + +export function correctArmHole(points, paths, Path, options, utils) { + points.armholeCp1 = points.chest + + if (!options.sleeves && points.armhole.y > points.chest.y) { + points.armhole = utils.beamIntersectsY(points.chest, points.waist, points.armhole.y) + points.armholeCp2 = points.armhole.shift(180, points._tmp1.dx(points.armhole) / 4) + } + + if (points.armhole.y > points.armholeCp1.y * 0.8) { + const frac = Math.min( + 1, + (points.armhole.y - points.armholeCp1.y * 0.8) / (0.2 * points.armholeCp1.y) + ) + points.armholeCp1 = points.chest.shiftFractionTowards( + points.armholeCp2.rotate(90, points.armhole), + frac + ) + } +} + +function extendSideLine(points, intersectionY) { + const fraction = (intersectionY - points.seat.y) / points.seat.dy(points.sideTarget) + return points.seat.shiftFractionTowards(points.sideTarget, fraction) +} + +export function constructSideSeam(Path, Point, points, height, bottomSmoothness) { + const base = new Path() + .move(points.armhole) + .curve(points.armholeCp1, points.waistCp2, points.waist) + .smurve(points.hipsCp2, points.hips) + .smurve(points.seatCp2, points.seat) + const intersectionY = Math.min(height, points.seat.y) - bottomSmoothness + let bottom = base.intersectsY(height)[0] + if (!bottom) { + // below seat + bottom = extendSideLine(points, height) + } + points.hem = bottom + let intersection = base.intersectsY(intersectionY)[0] + + if (!intersection) { + if (intersectionY >= points.seat.y) { + // below seat + intersection = extendSideLine(points, intersectionY) + } else { + //above armhole + intersection = points.armhole + } + } + + bottom.x = (bottom.x + intersection.x) / 2 // creates a smoother bottom as the bottom is vertical + + points.intersection = intersection + + const angle = base.angleAt(intersection) + if (!angle) { + return base + } + const intersectionCp1 = intersection.shift(angle, bottomSmoothness * 0.3) + const intersectionCp2 = new Point(bottom.x, bottom.y - bottomSmoothness * 0.3) + + points.intersectionCp1 = intersectionCp1 + points.intersectionCp2 = intersectionCp2 + + let result = base.split(intersection)[0] + if (!result.curve) { + result = new Path().move(points.armhole) + } + return result.curve(intersectionCp1, intersectionCp2, bottom).reverse() +} + +export function adjustSidePoints(points, options) { + // Remove waist fitting if option is disabled + if (!options.fitWaist || points.waist.x > points.armhole.x) { + if (points.waist.x < points.armhole.x) { + points.waist.x = points.armhole.x + } + points.waistCp2 = points.waist.shiftFractionTowards(points.armhole, 0.2) + if (points.hips.x < points.waist.x) { + points.hips.x = points.waist.x + } + } + + // prevent barrel shape + if (points.hips.x < points.waist.x) { + points.hips.x = points.waist.x + } + // prevent excessive hips narrowing + if (points.hips.x < (points.waist.x + points.seat.x) / 2) { + points.hips.x = (points.waist.x + points.seat.x) / 2 + } + // prevent smaller seat than hips + if (points.seat.x < points.hips.x) { + points.seat.x = points.hips.x + } + // prevent excessive waist narrowing + if (points.waist.x < 2 * points.hips.x - points.seat.x) { + points.waist.x = 2 * points.hips.x - points.seat.x + } + + // curve points + points.waistCp2 = points.waist.shift(90, points.armhole.dy(points.waist) * 0.2) + points.seatCp2 = points.seat.shift(90, points.hips.dy(points.seat) * 0.3) + points.hipsCp2 = points.waist.shiftFractionTowards(points.hips, 0.6) +} + +function getBottomSmoothness(bottom, points) { + return (Math.min(bottom, points.seat.y) - points.armhole.y) * 0.3 +} + +export function constructBackHem(points, measurements, options, Point, paths, Path) { + let centerPoint + + // Extra length for butt + let extraBackLength = 0 + let bonusLengthMeasurement = measurements.hpsToWaistBack + switch (options.length) { + case 'underbust': + centerPoint = points.cbUnderbust + bonusLengthMeasurement = measurements.waistToUnderbust + break + case 'waist': + centerPoint = points.cbWaist + break + case 'hips': + centerPoint = points.cbHips + break + case 'seat': + centerPoint = points.cbSeat + extraBackLength = (measurements.seatBack - measurements.seat / 2) / 2 + bonusLengthMeasurement *= 2 + break + case 'knee': + centerPoint = points.cbKnee + extraBackLength = (measurements.seatBack - measurements.seat / 2) / 2 + bonusLengthMeasurement *= 3 + break + case 'floor': + centerPoint = points.cbFloor + extraBackLength = (measurements.seatBack - measurements.seat / 2) / 2 + bonusLengthMeasurement *= 3 + } + + if (!centerPoint) { + centerPoint = points.cbSeat + } + + const hemBottom = centerPoint.y + bonusLengthMeasurement * options.lengthBonus + points.cbHem = new Point( + 0, + centerPoint.y + bonusLengthMeasurement * options.lengthBonus + extraBackLength + ) + points.midHem = new Point(points.hem.x * 0.66, points.cbHem.y) + paths.sideSeam = constructSideSeam( + Path, + Point, + points, + hemBottom, + getBottomSmoothness(hemBottom, points) + ).addClass('fabric') + + paths.hem = new Path() + .move(points.cbHem) + .curve(points.midHem, points.midHem, points.hem) + .addClass('fabric') +} + +export function constructFrontHem(points, measurements, options, Point, paths, Path) { + let centerPoint + let bonusLengthMeasurement = measurements.hpsToWaistBack + switch (options.length) { + case 'underbust': + centerPoint = points.cfUnderbust + bonusLengthMeasurement = measurements.waistToUnderbust + break + case 'waist': + centerPoint = points.cfWaist + break + case 'hips': + centerPoint = points.cfHips + break + case 'seat': + centerPoint = points.cfSeat + bonusLengthMeasurement *= 2 + break + case 'knee': + centerPoint = points.cfKnee + bonusLengthMeasurement *= 3 + break + case 'floor': + centerPoint = points.cfFloor + bonusLengthMeasurement *= 3 + } + + if (!centerPoint) { + centerPoint = points.cfSeat + } + + const hemBottom = centerPoint.y + bonusLengthMeasurement * options.lengthBonus + points.cfHem = new Point(0, centerPoint.y + bonusLengthMeasurement * options.lengthBonus) + points.midHem = new Point(points.hem.x * 0.66, points.cfHem.y) + paths.sideSeam = constructSideSeam( + Path, + Point, + points, + hemBottom, + getBottomSmoothness(hemBottom, points) + ).addClass('fabric') + + paths.hem = new Path() + .move(points.cfHem) + .curve(points.midHem, points.midHem, points.hem) + .addClass('fabric') +} + +export function createArmHoles( + options, + store, + points, + paths, + Path, + snippets, + Snippet, + strapWidth, + notchType = 'notch' +) { + if (options.sleeves) { + if (store.get('capSleeves')) { + const sleeveCapFactor = (options.sleeveLength + 0.2) * 4 + const capLength = sleeveCapFactor * store.get('sleeveCapHeight') + console.log('caplength', capLength) + points.sleeveCap = points.shoulder.shift(points.neck.angle(points.shoulder) - 15, capLength) + points.sleeveCapStart = points.shoulder.shift( + points.neck.angle(points.shoulder), + capLength * -0.2 + ) + points.sleeveCapCp = points.sleeveCap + .shiftTowards(points.armholePitchCp1, capLength * 0.2) + .rotate(-90, points.sleeveCap) + paths.shoulder = new Path() + .move(points.sleeveCap) + .curve(points.sleeveCapCp, points.shoulder, points.sleeveCapStart) + .line(points.neck) + .addClass('fabric') + paths.armhole = new Path() + .move(points.armhole) + .curve(points.armholeCp2, points.armholeHollowCp1, points.armholeHollow) + .curve(points.armholeHollowCp2, points.armholePitchCp1, points.sleeveCap) + .addClass('fabric') + } else { + paths.shoulder = new Path().move(points.shoulder).line(points.neck).addClass('fabric') + paths.armhole = new Path() + .move(points.armhole) + .curve(points.armholeCp2, points.armholeHollowCp1, points.armholeHollow) + .curve(points.armholeHollowCp2, points.armholePitchCp1, points.armholePitch) + .curve(points.armholePitchCp2, points.shoulderCp1, points.shoulder) + .addClass('fabric') + snippets.armholePitchNotch = new Snippet(notchType, points.armholePitch) + } + } else { + points.strapTop = points.neck.shift( + points.shoulder.angle(points.hps), + -strapWidth * points.shoulder.dist(points.hps) + ) + points.strapTopCp1 = points.strapTop + .shiftTowards( + points.hps, + 0.8 * points.strapTop.dy(points.armhole) * (0.2 + options.necklineBend) + ) + .rotate(90, points.strapTop) + paths.armhole = new Path() + .move(points.armhole) + .curve(points.armholeCp2, points.armholeHollowCp1, points.armholeHollow) + .curve(points.armholeHollowCp2, points.strapTopCp1, points.strapTop) + .addClass('fabric') + paths.shoulder = new Path().move(points.strapTop).line(points.neck).addClass('fabric') + } +} + +export function plotSideLineMeasurements(points, sideSeam, utils, macro) { + const offsets = { + seat: points.seat.y, + hips: points.hips.y, + waist: points.waist.y, + underbust: points.underbust.y, + dart: points.dartTip?.y, + armhole: points.armhole.y + 0.01, + } + let prevY = (points.cfHem ?? points.cbHem).y + const strings = Object.keys(offsets) + for (let i = 0; i < strings.length; i++) { + const key = strings[i] + const y = offsets[key] + if (!y || y > points.hem.y) { + continue + } + let intersects = sideSeam.intersectsY(y) + if (intersects.length > 0) { + const sidePoint = intersects[0] + const centerPoint = sidePoint.clone() + centerPoint.x = 0 + const prevPoint = centerPoint.clone() + prevPoint.y = prevY + prevY = y + macro('hd', { + id: 'wAt' + utils.capitalize(key), + from: centerPoint, + to: sidePoint, + y: y, + }) + macro('vd', { + id: 'hBelow' + utils.capitalize(key), + from: centerPoint, + to: prevPoint, + x: 30, + }) + } + } +} diff --git a/designs/bibi/src/sleeve.mjs b/designs/bibi/src/sleeve.mjs new file mode 100644 index 00000000000..d1a075246b1 --- /dev/null +++ b/designs/bibi/src/sleeve.mjs @@ -0,0 +1,146 @@ +import { sleevecap as brianSleeveCap } from '@freesewing/brian' +import { hidePresets } from '@freesewing/core' + +export const sleeve = { + name: 'bibi.sleeve', + from: brianSleeveCap, + hide: hidePresets.HIDE_TREE, + options: { + sleeveLength: { + pct: 20, + min: -20, + max: 110, + menu: (settings, mergedOptions) => + mergedOptions.sleeves === false ? false : 'style.sleeves', + }, + cuffEase: { + pct: 20, + min: 0, + max: 200, + menu: (settings, mergedOptions) => + mergedOptions.sleeves === false ? false : 'style.sleeves', + }, + }, + measurements: ['shoulderToWrist', 'wrist'], + draft: bibiSleeve, +} + +function bibiSleeve({ + options, + store, + measurements, + points, + paths, + Point, + Path, + sa, + macro, + snippets, + Snippet, + part, +}) { + points.sleeveTip = paths.sleevecap.edge('top') + points.sleeveTop = new Point(0, points.sleeveTip.y) // Always in center + + // Determine the sleeve length + store.set('sleeveLength', measurements.shoulderToWrist * options.sleeveLength) + + store.set('capSleeves', options.sleeveLength < 0.05) + + store.set('sleeveCapHeight', -points.sleeveTop.y) + if (store.get('capSleeves')) { + return part.hide() + } + + if (!options.sleeves) { + store.set('sleeveLength', 0) + return part.hide() + } + + // Wrist + points.centerWrist = points.sleeveTop.shift(-90, measurements.shoulderToWrist) + points.wristRight = points.centerWrist.shift(0, (measurements.wrist * (1 + options.cuffEase)) / 2) + points.wristLeft = points.wristRight.rotate(180, points.centerWrist) + + points.cuffRight = points.bicepsRight.shiftFractionTowards( + points.wristRight, + options.sleeveLength + ) + points.cuffLeft = points.bicepsLeft.shiftFractionTowards(points.wristLeft, options.sleeveLength) + points.centerCuff = points.cuffRight.shiftFractionTowards(points.cuffLeft, 0.5) + + // Paths + paths.sleevecap.hide() + paths.seam = new Path() + .move(points.bicepsLeft) + .move(points.cuffLeft) + .move(points.cuffRight) + .line(points.bicepsRight) + .join(paths.sleevecap) + .close() + .attr('class', 'fabric') + + if (sa) paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa') + + /* + * Annotations + */ + + // Anchor point for sampling + points.gridAnchor = new Point(0, 0) + + // Grainline + macro('grainline', { + from: points.centerCuff, + to: points.centerBiceps, + }) + + // Cut list + store.cutlist.addCut({ cut: 2, from: 'fabric' }) + + // Logo + points.logo = points.centerBiceps.shiftFractionTowards(points.centerCuff, 0.3) + snippets.logo = new Snippet('logo', points.logo) + + // Title + macro('title', { at: points.centerBiceps, nr: 3, title: 'sleeve' }) + + // Notches + points.frontNotch = paths.sleevecap.shiftAlong(store.get('frontArmholeToArmholePitch')) + points.backNotch = paths.sleevecap.reverse().shiftAlong(store.get('backArmholeToArmholePitch')) + snippets.frontNotch = new Snippet('notch', points.frontNotch) + snippets.backNotch = new Snippet('bnotch', points.backNotch) + + // Dimensions + macro('vd', { + id: 'hCuffToArmhole', + from: points.cuffLeft, + to: points.bicepsLeft, + x: points.bicepsLeft.x - sa - 15, + }) + macro('vd', { + id: 'hFull', + from: points.cuffLeft, + to: points.sleeveTip, + x: points.bicepsLeft.x - sa - 30, + }) + macro('hd', { + id: 'wFull', + from: points.bicepsLeft, + to: points.bicepsRight, + y: points.sleeveTip.y - sa - 30, + }) + macro('hd', { + id: 'wCuff', + from: points.cuffLeft, + to: points.cuffRight, + y: points.cuffLeft.y + sa + 30, + }) + macro('pd', { + id: 'lSleevevap', + path: paths.sleevecap.reverse(), + d: -1 * sa - 15, + }) + + return part +} diff --git a/designs/bibi/tests/shared.test.mjs b/designs/bibi/tests/shared.test.mjs new file mode 100644 index 00000000000..5a6830c127e --- /dev/null +++ b/designs/bibi/tests/shared.test.mjs @@ -0,0 +1,20 @@ +// This file is auto-generated | Any changes you make will be overwritten. +import { Bibi, i18n } from '../src/index.mjs' + +// Shared tests +import { testPatternConfig } from '../../../tests/designs/config.mjs' +import { testPatternI18n } from '../../../tests/designs/i18n.mjs' +import { testPatternDrafting } from '../../../tests/designs/drafting.mjs' +import { testPatternSampling } from '../../../tests/designs/sampling.mjs' + +// Test config +testPatternConfig(Bibi) + +// Test translation +testPatternI18n(Bibi, i18n) + +// Test drafting - Change the second parameter to `true` to log errors +testPatternDrafting(Bibi, false) + +// Test sampling - Change the second parameter to `true` to log errors +testPatternSampling(Bibi, false) diff --git a/sites/lab/hooks/use-design.mjs b/sites/lab/hooks/use-design.mjs index 280d21acf42..fca27f1477e 100644 --- a/sites/lab/hooks/use-design.mjs +++ b/sites/lab/hooks/use-design.mjs @@ -8,6 +8,7 @@ import { Bee as bee } from '@freesewing/bee' import { Bella as bella } from '@freesewing/bella' import { Benjamin as benjamin } from '@freesewing/benjamin' import { Bent as bent } from '@freesewing/bent' +import { Bibi as bibi } from '@freesewing/bibi' import { Bob as bob } from '@freesewing/bob' import { Breanna as breanna } from '@freesewing/breanna' import { Brian as brian } from '@freesewing/brian' @@ -66,6 +67,7 @@ const designs = { bella, benjamin, bent, + bibi, bob, breanna, brian, diff --git a/sites/org/hooks/use-design.mjs b/sites/org/hooks/use-design.mjs index de6c7f2e460..8db552d77fb 100644 --- a/sites/org/hooks/use-design.mjs +++ b/sites/org/hooks/use-design.mjs @@ -8,6 +8,7 @@ import { Bee as bee } from '@freesewing/bee' import { Bella as bella } from '@freesewing/bella' import { Benjamin as benjamin } from '@freesewing/benjamin' import { Bent as bent } from '@freesewing/bent' +import { Bibi as bibi } from '@freesewing/bibi' import { Bob as bob } from '@freesewing/bob' import { Breanna as breanna } from '@freesewing/breanna' import { Brian as brian } from '@freesewing/brian' @@ -63,6 +64,7 @@ const designs = { bella, benjamin, bent, + bibi, bob, breanna, brian, diff --git a/sites/shared/i18n/designs.mjs b/sites/shared/i18n/designs.mjs index d8d7bb41782..104187d8a25 100644 --- a/sites/shared/i18n/designs.mjs +++ b/sites/shared/i18n/designs.mjs @@ -8,6 +8,7 @@ import { i18n as bee } from '@freesewing/bee' import { i18n as bella } from '@freesewing/bella' import { i18n as benjamin } from '@freesewing/benjamin' import { i18n as bent } from '@freesewing/bent' +import { i18n as bibi } from '@freesewing/bibi' import { i18n as bob } from '@freesewing/bob' import { i18n as breanna } from '@freesewing/breanna' import { i18n as brian } from '@freesewing/brian' @@ -69,6 +70,7 @@ export const designs = { bella, benjamin, bent, + bibi, bob, breanna, brian, diff --git a/sites/shared/prebuild/data/design-measurements.mjs b/sites/shared/prebuild/data/design-measurements.mjs index 5dce375afa4..935eaa98103 100644 --- a/sites/shared/prebuild/data/design-measurements.mjs +++ b/sites/shared/prebuild/data/design-measurements.mjs @@ -1,3 +1,3 @@ // __SDEFILE__ - This file is a dependency for the stand-alone environment // This file is auto-generated by the prebuild script | Any changes will be overwritten -export const measurements = {"aaron":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips"],"albert":["chest","hpsToWaistBack","waist","waistToKnee","hips"],"bee":["highBust","chest","underbust","waist","waistBack","bustSpan","neck","hpsToBust","hpsToWaistFront","hpsToWaistBack","shoulderToShoulder","shoulderSlope","bustPointToUnderbust"],"bella":["highBust","chest","underbust","waist","waistBack","bustSpan","neck","hpsToBust","hpsToWaistFront","hpsToWaistBack","shoulderToShoulder","shoulderSlope"],"benjamin":["neck"],"bent":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","shoulderToElbow","shoulderToWrist","wrist"],"bob":[],"breanna":["biceps","bustFront","bustSpan","highBust","highBustFront","hpsToBust","hpsToWaistBack","hpsToWaistFront","waist","waistToHips","neck","shoulderToShoulder","shoulderSlope","shoulderToWrist","wrist"],"brian":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","shoulderToWrist","wrist"],"bruce":["hips","upperLeg","waistToHips","waistToUpperLeg"],"carlita":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","waist","waistToFloor","waistToSeat","seat","highBust","bustSpan","shoulderToElbow","shoulderToWrist","wrist"],"carlton":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","waist","waistToFloor","waistToSeat","seat","shoulderToElbow","shoulderToWrist","wrist"],"cathrin":["underbust","waist","hips","waistToUnderbust","waistToHips"],"charlie":["crossSeam","crossSeamFront","knee","seat","seatBack","waist","waistBack","waistToFloor","waistToKnee","waistToHips","waistToSeat","waistToUpperLeg"],"cornelius":["waist","hips","inseam","seat","waistToKnee","waistToHips","waistToFloor","knee"],"diana":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips","waist","shoulderToWrist","wrist"],"examples":["head"],"florence":["head"],"florent":["head"],"gozer":["hpsToWaistBack","waistToFloor","head"],"hi":[],"holmes":["head"],"hortensia":[],"huey":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips","shoulderToWrist","wrist","head"],"hugo":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips","shoulderToWrist","wrist","head"],"jaeger":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips","waist","shoulderToElbow","shoulderToWrist","wrist"],"legend":[],"lucy":[],"lumina":["waist","waistBack","hips","seat","seatBack","inseam","waistToSeat","waistToUpperLeg","waistToKnee","waistToHips","waistToFloor","knee","ankle","crossSeam","crossSeamFront","heel","upperLeg"],"lumira":["waist","waistBack","hips","seat","seatBack","upperLeg","knee","ankle","heel","inseam","crossSeam","crossSeamFront","waistToFloor","waistToKnee","waistToUpperLeg","waistToSeat","waistToHips"],"lunetius":["waistToKnee","waistToUpperLeg","waistToFloor","hpsToWaistBack","neck","shoulderToShoulder","shoulderToElbow","waistToHips"],"magde":[],"naomiwu":["hips","seat","waistToHips","waistToSeat","waistToUpperLeg"],"noble":["highBust","chest","underbust","waist","waistBack","bustSpan","neck","hpsToBust","hpsToWaistFront","hpsToWaistBack","shoulderToShoulder","shoulderSlope"],"octoplushy":[],"onyx":["biceps","neck","chest","waist","hips","seat","waistToHips","hpsToWaistBack","hpsToWaistFront","waistToSeat","crossSeam","waistToArmpit","inseam","upperLeg","waistToUpperLeg","ankle","wrist","shoulderToWrist","head"],"otis":["waist"],"paco":["crossSeam","crossSeamFront","knee","seat","seatBack","waist","waistBack","waistToFloor","waistToKnee","waistToHips","waistToSeat","waistToUpperLeg","heel"],"penelope":["waist","seat","waistToHips","waistToSeat","waistToKnee"],"plugintest":["seat","seatBack","waist","waistBack","crossSeam","crossSeamFront"],"rendertest":[],"sandy":["waist","waistToFloor","waistToHips","hips"],"shelly":["biceps","neck","chest","hips","waistToHips","hpsToWaistBack","waistToArmpit","wrist","shoulderToWrist"],"shin":["hips","upperLeg","waistToUpperLeg","waistToHips"],"simon":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","waist","hips","shoulderToWrist","wrist"],"simone":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","waist","hips","highBust","bustSpan","shoulderToWrist","wrist"],"skully":[],"sven":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips","waist","shoulderToWrist","wrist"],"tamiko":["shoulderToShoulder","chest","hpsToWaistBack","shoulderSlope","waistToHips"],"teagan":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips","waist"],"tiberius":["head","shoulderToElbow","shoulderToShoulder","biceps","hpsToWaistBack","waistToKnee","waist","chest","seat","hips","waistToFloor","waistToUpperLeg"],"titan":["crossSeam","crossSeamFront","knee","seat","seatBack","waist","waistBack","waistToFloor","waistToKnee","waistToHips","waistToSeat","waistToUpperLeg"],"trayvon":["hpsToWaistBack","waistToHips","neck"],"tristan":["highBust","chest","underbust","waist","waistBack","bustSpan","neck","hpsToBust","hpsToWaistFront","hpsToWaistBack","shoulderToShoulder","shoulderSlope"],"uma":["waist","seat","waistToSeat","waistToUpperLeg"],"wahid":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips","waist"],"walburga":["head","shoulderToShoulder","hpsToWaistBack","waistToKnee","waistToHips","waistToFloor","waistToUpperLeg","neck"],"waralee":["seat","inseam","crotchDepth","waistToHips"],"yuri":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips","shoulderToWrist","wrist","head"]} +export const measurements = {"aaron":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips"],"albert":["chest","hpsToWaistBack","waist","waistToKnee","hips"],"bee":["highBust","chest","underbust","waist","waistBack","bustSpan","neck","hpsToBust","hpsToWaistFront","hpsToWaistBack","shoulderToShoulder","shoulderSlope","bustPointToUnderbust"],"bella":["highBust","chest","underbust","waist","waistBack","bustSpan","neck","hpsToBust","hpsToWaistFront","hpsToWaistBack","shoulderToShoulder","shoulderSlope"],"benjamin":["neck"],"bent":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","shoulderToElbow","shoulderToWrist","wrist"],"bibi":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips","waist","seat","waistToSeat","bustSpan","shoulderToWrist","wrist"],"bob":[],"breanna":["biceps","bustFront","bustSpan","highBust","highBustFront","hpsToBust","hpsToWaistBack","hpsToWaistFront","waist","waistToHips","neck","shoulderToShoulder","shoulderSlope","shoulderToWrist","wrist"],"brian":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","shoulderToWrist","wrist"],"bruce":["hips","upperLeg","waistToHips","waistToUpperLeg"],"carlita":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","waist","waistToFloor","waistToSeat","seat","highBust","bustSpan","shoulderToElbow","shoulderToWrist","wrist"],"carlton":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","waist","waistToFloor","waistToSeat","seat","shoulderToElbow","shoulderToWrist","wrist"],"cathrin":["underbust","waist","hips","waistToUnderbust","waistToHips"],"charlie":["crossSeam","crossSeamFront","knee","seat","seatBack","waist","waistBack","waistToFloor","waistToKnee","waistToHips","waistToSeat","waistToUpperLeg"],"cornelius":["waist","hips","inseam","seat","waistToKnee","waistToHips","waistToFloor","knee"],"diana":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips","waist","shoulderToWrist","wrist"],"examples":["head"],"florence":["head"],"florent":["head"],"gozer":["hpsToWaistBack","waistToFloor","head"],"hi":[],"holmes":["head"],"hortensia":[],"huey":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips","shoulderToWrist","wrist","head"],"hugo":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips","shoulderToWrist","wrist","head"],"jaeger":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips","waist","shoulderToElbow","shoulderToWrist","wrist"],"legend":[],"lucy":[],"lumina":["waist","waistBack","hips","seat","seatBack","inseam","waistToSeat","waistToUpperLeg","waistToKnee","waistToHips","waistToFloor","knee","ankle","crossSeam","crossSeamFront","heel","upperLeg"],"lumira":["waist","waistBack","hips","seat","seatBack","upperLeg","knee","ankle","heel","inseam","crossSeam","crossSeamFront","waistToFloor","waistToKnee","waistToUpperLeg","waistToSeat","waistToHips"],"lunetius":["waistToKnee","waistToUpperLeg","waistToFloor","hpsToWaistBack","neck","shoulderToShoulder","shoulderToElbow","waistToHips"],"magde":[],"naomiwu":["hips","seat","waistToHips","waistToSeat","waistToUpperLeg"],"noble":["highBust","chest","underbust","waist","waistBack","bustSpan","neck","hpsToBust","hpsToWaistFront","hpsToWaistBack","shoulderToShoulder","shoulderSlope"],"octoplushy":[],"onyx":["biceps","neck","chest","waist","hips","seat","waistToHips","hpsToWaistBack","hpsToWaistFront","waistToSeat","crossSeam","waistToArmpit","inseam","upperLeg","waistToUpperLeg","ankle","wrist","shoulderToWrist","head"],"otis":["waist"],"paco":["crossSeam","crossSeamFront","knee","seat","seatBack","waist","waistBack","waistToFloor","waistToKnee","waistToHips","waistToSeat","waistToUpperLeg","heel"],"penelope":["waist","seat","waistToHips","waistToSeat","waistToKnee"],"plugintest":["seat","seatBack","waist","waistBack","crossSeam","crossSeamFront"],"rendertest":[],"sandy":["waist","waistToFloor","waistToHips","hips"],"shelly":["biceps","neck","chest","hips","waistToHips","hpsToWaistBack","waistToArmpit","wrist","shoulderToWrist"],"shin":["hips","upperLeg","waistToUpperLeg","waistToHips"],"simon":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","waist","hips","shoulderToWrist","wrist"],"simone":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","waist","hips","highBust","bustSpan","shoulderToWrist","wrist"],"skully":[],"sven":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips","waist","shoulderToWrist","wrist"],"tamiko":["shoulderToShoulder","chest","hpsToWaistBack","shoulderSlope","waistToHips"],"teagan":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips","waist"],"tiberius":["head","shoulderToElbow","shoulderToShoulder","biceps","hpsToWaistBack","waistToKnee","waist","chest","seat","hips","waistToFloor","waistToUpperLeg"],"titan":["crossSeam","crossSeamFront","knee","seat","seatBack","waist","waistBack","waistToFloor","waistToKnee","waistToHips","waistToSeat","waistToUpperLeg"],"trayvon":["hpsToWaistBack","waistToHips","neck"],"tristan":["highBust","chest","underbust","waist","waistBack","bustSpan","neck","hpsToBust","hpsToWaistFront","hpsToWaistBack","shoulderToShoulder","shoulderSlope"],"uma":["waist","seat","waistToSeat","waistToUpperLeg"],"wahid":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips","waist"],"walburga":["head","shoulderToShoulder","hpsToWaistBack","waistToKnee","waistToHips","waistToFloor","waistToUpperLeg","neck"],"waralee":["seat","inseam","crotchDepth","waistToHips"],"yuri":["biceps","chest","hpsToBust","hpsToWaistBack","neck","shoulderToShoulder","shoulderSlope","waistToArmpit","waistToHips","hips","shoulderToWrist","wrist","head"]} diff --git a/sites/shared/prebuild/data/designs.mjs b/sites/shared/prebuild/data/designs.mjs index cd5a54e8286..6cc46e2f1d7 100644 --- a/sites/shared/prebuild/data/designs.mjs +++ b/sites/shared/prebuild/data/designs.mjs @@ -1,3 +1,3 @@ // __SDEFILE__ - This file is a dependency for the stand-alone environment // This file is auto-generated by the prebuild script | Any changes will be overwritten -export const designs = ["aaron","albert","bee","bella","benjamin","bent","bob","breanna","brian","bruce","carlita","carlton","cathrin","charlie","cornelius","diana","examples","florence","florent","gozer","hi","holmes","hortensia","huey","hugo","jaeger","legend","lucy","lumina","lumira","lunetius","magde","naomiwu","noble","octoplushy","onyx","otis","paco","penelope","plugintest","rendertest","sandy","shelly","shin","simon","simone","skully","sven","tamiko","teagan","tiberius","titan","trayvon","tristan","uma","wahid","walburga","waralee","yuri"] +export const designs = ["aaron","albert","bee","bella","benjamin","bent","bibi","bob","breanna","brian","bruce","carlita","carlton","cathrin","charlie","cornelius","diana","examples","florence","florent","gozer","hi","holmes","hortensia","huey","hugo","jaeger","legend","lucy","lumina","lumira","lunetius","magde","naomiwu","noble","octoplushy","onyx","otis","paco","penelope","plugintest","rendertest","sandy","shelly","shin","simon","simone","skully","sven","tamiko","teagan","tiberius","titan","trayvon","tristan","uma","wahid","walburga","waralee","yuri"]