add(bibi): Add Bibi, a FreeSewing pattern for a knit top body block
This commit is contained in:
parent
9f593d2eb7
commit
44bb09e4c3
25 changed files with 1957 additions and 2 deletions
|
@ -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",
|
||||
|
|
1
designs/bibi/.prettierignore
Normal file
1
designs/bibi/.prettierignore
Normal file
|
@ -0,0 +1 @@
|
|||
config/config.js
|
17
designs/bibi/CHANGELOG.md
Normal file
17
designs/bibi/CHANGELOG.md
Normal file
|
@ -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.
|
||||
|
162
designs/bibi/README.md
Normal file
162
designs/bibi/README.md
Normal file
|
@ -0,0 +1,162 @@
|
|||
<p align='center'><a
|
||||
href="https://www.npmjs.com/package/@freesewing/bibi"
|
||||
title="@freesewing/bibi on NPM"
|
||||
><img src="https://img.shields.io/npm/v/@freesewing/bibi.svg"
|
||||
alt="@freesewing/bibi on NPM"/>
|
||||
</a><a
|
||||
href="https://opensource.org/licenses/MIT"
|
||||
title="License: MIT"
|
||||
><img src="https://img.shields.io/npm/l/@freesewing/bibi.svg?label=License"
|
||||
alt="License: MIT"/>
|
||||
</a><a
|
||||
href="https://deepscan.io/dashboard#view=project&tid=2114&pid=2993&bid=23256"
|
||||
title="Code quality on DeepScan"
|
||||
><img src="https://deepscan.io/api/teams/2114/projects/2993/branches/23256/badge/grade.svg"
|
||||
alt="Code quality on DeepScan"/>
|
||||
</a><a
|
||||
href="https://github.com/freesewing/freesewing/issues?q=is%3Aissue+is%3Aopen+label%3Apkg%3Atina"
|
||||
title="Open issues tagged pkg:bibi"
|
||||
><img src="https://img.shields.io/github/issues/freesewing/freesewing/pkg:bibi.svg?label=Issues"
|
||||
alt="Open issues tagged pkg:bibi"/>
|
||||
</a><a
|
||||
href="#contributors-"
|
||||
title="All Contributors"
|
||||
><img src="https://img.shields.io/badge/all_contributors-127-pink.svg"
|
||||
alt="All Contributors"/>
|
||||
</a></p><p align='center'><a
|
||||
href="https://twitter.com/freesewing_org"
|
||||
title="Follow @freesewing_org on Twitter"
|
||||
><img src="https://img.shields.io/badge/%F3%A0%80%A0-Follow%20us-blue.svg?logo=twitter&logoColor=white&logoWidth=15"
|
||||
alt="Follow @freesewing_org on Twitter"/>
|
||||
</a><a
|
||||
href="https://chat.freesewing.org"
|
||||
title="Chat with us on Discord"
|
||||
><img src="https://img.shields.io/discord/698854858052075530?label=Chat%20on%20Discord"
|
||||
alt="Chat with us on Discord"/>
|
||||
</a><a
|
||||
href="https://freesewing.org/patrons/join"
|
||||
title="Become a FreeSewing Patron"
|
||||
><img src="https://img.shields.io/badge/%F3%A0%80%A0-Support%20us-blueviolet.svg?logo=cash-app&logoColor=white&logoWidth=15"
|
||||
alt="Become a FreeSewing Patron"/>
|
||||
</a><a
|
||||
href="https://instagram.com/freesewing_org"
|
||||
title="Follow @freesewing_org on Twitter"
|
||||
><img src="https://img.shields.io/badge/%F3%A0%80%A0-Follow%20us-E4405F.svg?logo=instagram&logoColor=white&logoWidth=15"
|
||||
alt="Follow @freesewing_org on Twitter"/>
|
||||
</a></p>
|
||||
|
||||
# @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:
|
||||
>
|
||||
> [](https://gitpod.io/#https://github.com/freesewing/freesewing)
|
||||
>
|
||||
> We recommend that you fork our repository and then
|
||||
> put `gitpod.io/#<entire-url-of-your-fork` into a browser
|
||||
> 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).
|
||||
|
35
designs/bibi/build.mjs
Normal file
35
designs/bibi/build.mjs
Normal file
|
@ -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()
|
4
designs/bibi/data.mjs
Normal file
4
designs/bibi/data.mjs
Normal file
|
@ -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 }
|
50
designs/bibi/i18n/de.json
Normal file
50
designs/bibi/i18n/de.json
Normal file
|
@ -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."
|
||||
}
|
||||
}
|
||||
}
|
109
designs/bibi/i18n/en.json
Normal file
109
designs/bibi/i18n/en.json
Normal file
|
@ -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."
|
||||
}
|
||||
}
|
||||
}
|
50
designs/bibi/i18n/es.json
Normal file
50
designs/bibi/i18n/es.json
Normal file
|
@ -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."
|
||||
}
|
||||
}
|
||||
}
|
50
designs/bibi/i18n/fr.json
Normal file
50
designs/bibi/i18n/fr.json
Normal file
|
@ -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."
|
||||
}
|
||||
}
|
||||
}
|
8
designs/bibi/i18n/index.mjs
Normal file
8
designs/bibi/i18n/index.mjs
Normal file
|
@ -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 }
|
50
designs/bibi/i18n/nl.json
Normal file
50
designs/bibi/i18n/nl.json
Normal file
|
@ -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."
|
||||
}
|
||||
}
|
||||
}
|
50
designs/bibi/i18n/uk.json
Normal file
50
designs/bibi/i18n/uk.json
Normal file
|
@ -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."
|
||||
}
|
||||
}
|
||||
}
|
72
designs/bibi/package.json
Normal file
72
designs/bibi/package.json
Normal file
|
@ -0,0 +1,72 @@
|
|||
{
|
||||
"name": "@freesewing/bibi",
|
||||
"version": "3.2.0",
|
||||
"description": "A FreeSewing pattern for overlap top",
|
||||
"author": "Joost De Cock <joost@joost.at> (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"
|
||||
}
|
||||
}
|
267
designs/bibi/src/back.mjs
Normal file
267
designs/bibi/src/back.mjs
Normal file
|
@ -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
|
||||
}
|
336
designs/bibi/src/front.mjs
Normal file
336
designs/bibi/src/front.mjs
Normal file
|
@ -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
|
||||
}
|
49
designs/bibi/src/index.mjs
Normal file
49
designs/bibi/src/index.mjs
Normal file
|
@ -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,
|
||||
}
|
454
designs/bibi/src/shared.mjs
Normal file
454
designs/bibi/src/shared.mjs
Normal file
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
146
designs/bibi/src/sleeve.mjs
Normal file
146
designs/bibi/src/sleeve.mjs
Normal file
|
@ -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
|
||||
}
|
20
designs/bibi/tests/shared.test.mjs
Normal file
20
designs/bibi/tests/shared.test.mjs
Normal file
|
@ -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)
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -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"]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue