diff --git a/.all-contributorsrc b/.all-contributorsrc
index b675311ba4b..7d90e5a423f 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -1167,6 +1167,33 @@
"contributions": [
"doc"
]
+ },
+ {
+ "login": "karlnippoldt",
+ "name": "Karl Nippoldt",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7821608?v=4",
+ "profile": "https://karlnippoldt.com",
+ "contributions": [
+ "doc"
+ ]
+ },
+ {
+ "login": "RockerKitten",
+ "name": "Corey",
+ "avatar_url": "https://avatars.githubusercontent.com/u/84648053?v=4",
+ "profile": "https://github.com/RockerKitten",
+ "contributions": [
+ "question"
+ ]
+ },
+ {
+ "login": "GeniaHarrietBoeing",
+ "name": "Niabon",
+ "avatar_url": "https://avatars.githubusercontent.com/u/73827848?v=4",
+ "profile": "https://github.com/GeniaHarrietBoeing",
+ "contributions": [
+ "doc"
+ ]
}
],
"skipCi": true,
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e11cb5c4fa0..1f2d9c50f47 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,8 +9,25 @@
- Always load plugin-bust due to its changes in how it handle conditionality.
+### cathrin
+
+#### Changed
+
+ - Allow negative values in backDrop option. Fixes
+ - Allow negative values for the frontRise options. Fixes
+
+### charlie
+
+#### Fixed
+
+ - Fix cut instructions for fly facing, only 1 to be cut. Fixes
+
### huey
+#### Changed
+
+ - The lengthBonus option default was changed from 0% to 15%. Fixes
+
#### Fixed
- Fixed an issue where ribbing height would distort the pocket under certain conditions. Fixes
@@ -23,6 +40,13 @@
- Add missing dimension id attributes
+### noble
+
+#### Fixed
+
+ - Fix 'cutonfold' text for Noble's back part. Fixes
+ - Improve dart shaping. Fixes
+
### onyx
#### Changed
@@ -35,12 +59,30 @@
- Always load plugin-bust due to its changes in how it handle conditionality.
+### simon
+
+#### Changed
+
+ - Allow negative values for the buttonFreeLength option. Fixes
+
+### simone
+
+#### Fixed
+
+ - Added missing translation for various options
+
### tamiko
#### Changed
- Always load plugin-bust due to its changes in how it handle conditionality.
+### teagan
+
+#### Fixed
+
+ - Fix side seam when length is cropped. Fixes
+
### uma
#### Fixed
@@ -65,6 +107,12 @@
- The `withCondition` named export is deprecated and will always return true.
+### core
+
+#### Added
+
+ - The `Path.rotate()` method was added to the core API.
+
## 3.2.0 (2024-02-11)
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index d4a465bbda1..e4fa39027f7 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -29,143 +29,148 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Cathy Zoller 📖
Chantal Lapointe 🌍
+ Corey 💬
Damien PIQUET 💻
Darigov Research 📖 🤔
David Clegg 🎨 💻
Elena FdR 📖 📝
- Emmanuel Nyachoke 💻 📖
+ Emmanuel Nyachoke 💻 📖
Enoch Riese 💻
EvEkSwed 🌍
Fantastik-Maman 🌍
Forrest O. 📖
Frédéric 🌍
Glenn Matthews 📖
- Greg Sadetsky 📖
+ Greg Sadetsky 📖
Himanshu Singh 📖
Igor Couto 🐛
Ikko Ashimine 📖
Irapeke 🌍
Ivo Bek 📖
Jacek Sawoszczuk 📖
- Jason Williams 📖
+ Jason Williams 📖
Jeremy Jackson 💻
Jeroen Hoek 📖
Joe Schofield 📖
Joebidido 🌍
Jonathan Haas 💻
Joost De Cock 🚧
- Josh Essman 📖
+ Josh Essman 📖
Josh Munic 🐛
Kake 📖
Kapunahele Wong 📖
Karen 📖 📋
+ Karl Nippoldt 📖
Katie McGinley 📖
- Kieran Klaassen 💻
- Kittycatou 🌍
+ Kieran Klaassen 💻
+ Kittycatou 🌍
Kris 📖
Kristin Ruben 💻
Lin 💻
Loudepeuter 🌍
Lucian 📋
- Luiz Saggioro 💻
- MA-TATAS 📖
+ Luiz Saggioro 💻
+ MA-TATAS 📖
Marcus 🌍
Martin Tribo 📖
Nadege Michel ⚠️ 📖
Natalia 💻 🎨 📝
Nathan Yergler 📖
- Nick Dower 📖 💻 🐛
- Nikhil Chelliah 📖
+ Niabon 📖
+ Nick Dower 📖 💻 🐛
+ Nikhil Chelliah 📖
OysteinHoiby 💻
Patrick Forringer 🔌
Paul 📖 📝 🌍
Paula Vidas 💻
+
+
Phillip Thelen 💻
Pixieish 📖
Prof. dr. Sorcha Ní Dhubhghaill 📖
-
-
Quentin FELIX 💻 🎨
Rachel Ostic 📖
Rik Hekker 🐛
Sam Livingston-Gray 📖
+
+
Sanne 💻 📖
Sara Latorre 🌍
SeaZeeZee 📖 💻
-
-
SimonbJohnson 🐛
SirCharlotte 🌍
Slylele 📖 🌍
Soazillon 🌍
+
+
Soham Tembhurne 💻
SoneaTheBest 🌍
Sophia 💻
-
-
Stefan Sydow 🌍 📖 💻
Stefano 📖
Sushmita Biswas 💻
Tanay Toshniwal 💻
+
+
Trent Trama 💻
Tríona 📖
Unmutual 📖
-
-
Vili Sinervä 💻
Vili Sinervä 💻
Wouter van Wageningen 💻 🎨 🔧
Yash Anil Ambekar 📖
+
+
amysews 📖
anna-puk 💻
beautifulsummermoon 🌍
-
-
berce 📖
biou 💻
bobgeorgethe3rd 💻 📖 🎨
brmlyklr 📖
+
+
chri5b 💻 ⚠️
dingcycle 🌍
drowned-in-books 💬
-
-
econo202 📖
ericamattos 🌍
evilrobotfromouterspace 🐛
fightingrabbit 💻
+
+
gaylyndie 📖
grimlokason 💻
hellgy 🎨
-
-
jackseye 📖
marckiesel 🌍
marpants 💻
mergerg 📖
+
+
mesil 🐛
starfetch 💻 📖 🌍 🎨
timorl 💻
-
-
ttimearl 🖋
tuesgloomsday 📖
valadaptive 💻
viocky 🌍
+
+
woolishboy 💻
yc 🌍
diff --git a/README.md b/README.md
index 03c2bb9b506..12346947168 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@
Cathy Zoller 📖
Chantal Lapointe 🌍
+ Corey 💬
Damien PIQUET 💻
Darigov Research 📖 🤔
David Clegg 🎨 💻
Elena FdR 📖 📝
- Emmanuel Nyachoke 💻 📖
+ Emmanuel Nyachoke 💻 📖
Enoch Riese 💻
EvEkSwed 🌍
Fantastik-Maman 🌍
Forrest O. 📖
Frédéric 🌍
Glenn Matthews 📖
- Greg Sadetsky 📖
+ Greg Sadetsky 📖
Himanshu Singh 📖
Igor Couto 🐛
Ikko Ashimine 📖
Irapeke 🌍
Ivo Bek 📖
Jacek Sawoszczuk 📖
- Jason Williams 📖
+ Jason Williams 📖
Jeremy Jackson 💻
Jeroen Hoek 📖
Joe Schofield 📖
Joebidido 🌍
Jonathan Haas 💻
Joost De Cock 🚧
- Josh Essman 📖
+ Josh Essman 📖
Josh Munic 🐛
Kake 📖
Kapunahele Wong 📖
Karen 📖 📋
+ Karl Nippoldt 📖
Katie McGinley 📖
- Kieran Klaassen 💻
- Kittycatou 🌍
+ Kieran Klaassen 💻
+ Kittycatou 🌍
Kris 📖
Kristin Ruben 💻
Lin 💻
Loudepeuter 🌍
Lucian 📋
- Luiz Saggioro 💻
- MA-TATAS 📖
+ Luiz Saggioro 💻
+ MA-TATAS 📖
Marcus 🌍
Martin Tribo 📖
Nadege Michel ⚠️ 📖
Natalia 💻 🎨 📝
Nathan Yergler 📖
- Nick Dower 📖 💻 🐛
- Nikhil Chelliah 📖
+ Niabon 📖
+ Nick Dower 📖 💻 🐛
+ Nikhil Chelliah 📖
OysteinHoiby 💻
Patrick Forringer 🔌
Paul 📖 📝 🌍
Paula Vidas 💻
+
+
Phillip Thelen 💻
Pixieish 📖
Prof. dr. Sorcha Ní Dhubhghaill 📖
-
-
Quentin FELIX 💻 🎨
Rachel Ostic 📖
Rik Hekker 🐛
Sam Livingston-Gray 📖
+
+
Sanne 💻 📖
Sara Latorre 🌍
SeaZeeZee 📖 💻
-
-
SimonbJohnson 🐛
SirCharlotte 🌍
Slylele 📖 🌍
Soazillon 🌍
+
+
Soham Tembhurne 💻
SoneaTheBest 🌍
Sophia 💻
-
-
Stefan Sydow 🌍 📖 💻
Stefano 📖
Sushmita Biswas 💻
Tanay Toshniwal 💻
+
+
Trent Trama 💻
Tríona 📖
Unmutual 📖
-
-
Vili Sinervä 💻
Vili Sinervä 💻
Wouter van Wageningen 💻 🎨 🔧
Yash Anil Ambekar 📖
+
+
amysews 📖
anna-puk 💻
beautifulsummermoon 🌍
-
-
berce 📖
biou 💻
bobgeorgethe3rd 💻 📖 🎨
brmlyklr 📖
+
+
chri5b 💻 ⚠️
dingcycle 🌍
drowned-in-books 💬
-
-
econo202 📖
ericamattos 🌍
evilrobotfromouterspace 🐛
fightingrabbit 💻
+
+
gaylyndie 📖
grimlokason 💻
hellgy 🎨
-
-
jackseye 📖
marckiesel 🌍
marpants 💻
mergerg 📖
+
+
mesil 🐛
starfetch 💻 📖 🌍 🎨
timorl 💻
-
-
ttimearl 🖋
tuesgloomsday 📖
valadaptive 💻
viocky 🌍
+
+
woolishboy 💻
yc 🌍
diff --git a/config/changelog.yaml b/config/changelog.yaml
index 5b3a7efc9c5..811a68637f0 100644
--- a/config/changelog.yaml
+++ b/config/changelog.yaml
@@ -1,7 +1,16 @@
Unreleased:
+ Added:
+ core:
+ - The `Path.rotate()` method was added to the core API.
+
Changed:
brian:
- Always load plugin-bust due to its changes in how it handle conditionality.
+ cathrin:
+ - Allow negative values in backDrop option. Fixes #6563
+ - Allow negative values for the frontRise options. Fixes #6563
+ huey:
+ - The lengthBonus option default was changed from 0% to 15%. Fixes #6596
onyx:
- Always load plugin-bust due to its changes in how it handle conditionality.
plugin-bust:
@@ -10,6 +19,8 @@ Unreleased:
- The plugin will now always be loaded, but will check for each drafted set whether it should make any changes.
shelly:
- Always load plugin-bust due to its changes in how it handle conditionality.
+ simon:
+ - Allow negative values for the buttonFreeLength option. Fixes #6508
tamiko:
- Always load plugin-bust due to its changes in how it handle conditionality.
wahid:
@@ -20,12 +31,21 @@ Unreleased:
- The `withCondition` named export is deprecated and will always return true.
Fixed:
+ charlie:
+ - Fix cut instructions for fly facing, only 1 to be cut. Fixes #6392
huey:
- Fixed an issue where ribbing height would distort the pocket under certain conditions. Fixes #6238
- Adding missing translation for ribbing option
- Hide unused ribbing parts when ribbing option is disabled
hugo:
- Add missing dimension id attributes
+ noble:
+ - Fix 'cutonfold' text for Noble's back part. Fixes #6447
+ - Improve dart shaping. Fixes #64547
+ simone:
+ - Added missing translation for various options
+ teagan:
+ - Fix side seam when length is cropped. Fixes #6480
uma:
- Fix back exposure when expand is off. Fixes #6239
diff --git a/config/dependencies.yaml b/config/dependencies.yaml
index d37f466095b..62f1a73c519 100644
--- a/config/dependencies.yaml
+++ b/config/dependencies.yaml
@@ -85,6 +85,10 @@ jaeger:
'@freesewing/brian': *freesewing
'@freesewing/bent': *freesewing
'@freesewing/plugin-bust': *freesewing
+lily:
+ peer:
+ '@freesewing/titan': *freesewing
+ '@freesewing/paco': *freesewing
new-design:
_:
'axios': &axios '1.6.8'
@@ -192,9 +196,9 @@ backend:
'passport': '0.7.0'
'passport-http': '0.3.0'
'passport-jwt': '4.0.1'
- 'pino': '8.19.0'
+ 'pino': '9.0.0'
'qrcode': '1.5.3'
- 'swagger-ui-dist': '5.12.0'
+ 'swagger-ui-dist': '5.17.2'
'swagger-ui-express': '5.0.0'
dev:
'chai': *chai
@@ -218,12 +222,12 @@ dev:
'lodash.orderby': &_orderby '4.6.0'
'lodash.set': *_set
'next': *next
- 'react': &react '18.2.0'
+ 'react': &react '18.3.1'
'react-copy-to-clipboard': &reactCopyToClipboard '5.1.0'
'react-dom': *react
'react-hotkeys-hook': &reactHotkeysHook '4.5.0'
'react-instantsearch-dom': &reactInstantsearchDom '6.40.4'
- 'react-instantsearch-hooks-web': '6.47.3'
+ 'react-instantsearch-hooks-web': &reactInstantsearchHooksWeb '6.47.3'
'react-swipeable': &reactSwipeable '7.0.1'
'react-timeago': &reactTimeago '7.2.0'
'rehype-autolink-headings': &rehypeAutolinkHeadings '7.1.0'
@@ -256,7 +260,7 @@ lab:
'd3-drag': &d3drag '3.0.0'
'd3-selection': &d3selection '3.0.0'
'daisyui': *daisyui
- 'i18next': &i18next '23.10.1'
+ 'i18next': &i18next '23.11.2'
'lodash.get': *_get
'lodash.orderby': *_orderby
'lodash.set': *_set
@@ -302,12 +306,18 @@ org:
'lodash.set': *_set
'luxon': '3.4.4'
'next': *next
+ 'next-i18next': *nextI18next
'ora': *ora
+ 'react': *react
+ 'react-dom': *react
'react-dropzone': &dropzone '14.2.3'
'react-hotkeys-hook': *reactHotkeysHook
+ "react-i18next": *reactI18next
'react-instantsearch-dom': *reactInstantsearchDom
+ 'react-instantsearch-hooks-web': *reactInstantsearchHooksWeb
'react-swipeable': *reactSwipeable
'react-timeago': *reactTimeago
+ 'react-zoom-pan-pinch': &zoompanpinch '3.4.3'
'rehype-autolink-headings': *rehypeAutolinkHeadings
'rehype-highlight': *rehypeHighlight
'rehype-sanitize': *rehypeSanitize
@@ -352,7 +362,7 @@ shared:
'react': *react
'react-dom': *react
'react-timeago': *reactTimeago
- 'react-zoom-pan-pinch': &zoompanpinch '3.4.3'
+ 'react-zoom-pan-pinch': *zoompanpinch
'rehype-autolink-headings': *rehypeAutolinkHeadings
'rehype-highlight': *rehypeHighlight
'remark-frontmatter': &remarkfrontmatter '5.0.0'
diff --git a/config/exceptions.yaml b/config/exceptions.yaml
index 0164d285beb..fd9f119bdb5 100644
--- a/config/exceptions.yaml
+++ b/config/exceptions.yaml
@@ -36,6 +36,8 @@ packageJson:
author: SeaZeeZee (https://github.com/SeaZeeZee)
lab:
private: true
+ lily:
+ author: Anna Puk (https://github.com/anna-puk)
lucy:
author: SeaZeeZee (https://github.com/SeaZeeZee)
lunetius: &starf
diff --git a/config/software/designs.json b/config/software/designs.json
index d1de8c56e80..6dfae93edd2 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",
@@ -936,6 +955,22 @@
"curvedSeam"
]
},
+ "umbra": {
+ "code": "Joost De Cock, Jonathan Haas",
+ "description": "A FreeSewing pattern for a basic, highly-customizable underwear pattern",
+ "design": "Joost De Cock, Jonathan Haas",
+ "difficulty": 2,
+ "lab": true,
+ "org": true,
+ "tags": [
+ "bottoms",
+ "underwear"
+ ],
+ "techniques": [
+ "elastic",
+ "curvedSeam"
+ ]
+ },
"wahid": {
"code": "Joost De Cock",
"description": "A FreeSewing pattern for a classic fitted waistcoat",
@@ -1003,6 +1038,21 @@
"hem",
"button"
]
+ },
+ "lily": {
+ "code": "Anna Puk, Joost De Cock",
+ "description": "A FreeSewing pattern for basic leggings",
+ "design": "Anna Puk",
+ "difficulty": 2,
+ "lab": true,
+ "org": true,
+ "tags": [
+ "bottoms"
+ ],
+ "techniques": [
+ "elastic",
+ "curvedSeam",
+ "hem"
+ ]
}
-
}
\ No newline at end of file
diff --git a/config/trustees.mjs b/config/trustees.mjs
new file mode 100644
index 00000000000..652f6bdf21e
--- /dev/null
+++ b/config/trustees.mjs
@@ -0,0 +1,35 @@
+/*
+ * This defines the FreeSewing web of trust
+ * See: https://FreeSewing.dev/reference/trust
+ */
+export const trustees = {
+ 1: {
+ x: 1306,
+ y: 319,
+ title: 'joost',
+ in: 'Antwerp',
+ },
+ 132: {
+ x: 457,
+ y: 345,
+ title: 'woutervdub',
+ in: 'Seattle',
+ },
+ 13050: {
+ x: 668,
+ y: 399,
+ title: 'karen',
+ in: 'Chicago',
+ },
+}
+
+/*
+ * These are the connections between the trustees
+ * See: https://FreeSewing.dev/reference/trust
+ */
+export const connections = [
+ [1, 132],
+ [1, 13050],
+]
+
+export const lastUpdate = '20240402'
diff --git a/designs/aaron/README.md b/designs/aaron/README.md
index e61e8239fdd..7bbc33fa334 100644
--- a/designs/aaron/README.md
+++ b/designs/aaron/README.md
@@ -21,7 +21,7 @@
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..76612126a13
--- /dev/null
+++ b/designs/bibi/README.md
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
+
+
+
+# @freesewing/bibi
+
+A FreeSewing pattern for a knit top body block
+
+
+
+# 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/# 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..e44015cf695
--- /dev/null
+++ b/designs/bibi/i18n/en.json
@@ -0,0 +1,129 @@
+{
+ "t": "Bibi body block",
+ "d": "Bibi is a multifunctional building block for knit tops and dresses.",
+ "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": "Front Neckline curvature",
+ "d": "Controls the curvature of the front neckline."
+ },
+ "backNeckBend": {
+ "t": "Back Neckline curvature",
+ "d": "Controls the curvature of the back neckline."
+ },
+ "necklineDepth": {
+ "t": "Front Neckline depth",
+ "d": "Controls how deep the neck opening plunges down at the front."
+ },
+ "backNeckCutout": {
+ "t": "Back Neckline depth",
+ "d": "Controls how deep the neck opening plunges down on the back."
+ },
+ "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."
+ },
+ "armholeCurveFront": {
+ "t": "Armhole curve front",
+ "d": "How round the armhole curve is at the front. Higher options expose more skin."
+ },
+ "armholeCurveBack": {
+ "t": "Armhole curve back",
+ "d": "How round the armhole curve is at the back. Higher options leave the shoulder blades free."
+ },
+ "armholeDropBack": {
+ "t": "Armhole drop back",
+ "d": "How much the back armhole curves towards the bottom."
+ },
+ "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..729dce02142
--- /dev/null
+++ b/designs/bibi/package.json
@@ -0,0 +1,72 @@
+{
+ "name": "@freesewing/bibi",
+ "version": "3.2.0",
+ "description": "A FreeSewing pattern for a knit top body block",
+ "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/core": "3.2.0"
+ },
+ "dependencies": {},
+ "devDependencies": {
+ "mocha": "10.3.0",
+ "chai": "5.1.0",
+ "@freesewing/models": "3.2.0",
+ "@freesewing/plugin-timing": "3.2.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..e40354e5b58
--- /dev/null
+++ b/designs/bibi/src/back.mjs
@@ -0,0 +1,273 @@
+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',
+ },
+ armholeCurveBack: {
+ pct: 30,
+ min: -10,
+ max: 120,
+ menu: (settings, mergedOptions) => (mergedOptions.sleeves ? false : 'style.sleeves'),
+ },
+ armholeDropBack: {
+ pct: 20,
+ min: -50,
+ max: 50,
+ menu: (settings, mergedOptions) => (mergedOptions.sleeves ? 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,
+ },
+ necklineWidth: { pct: 30, min: 10, max: 90, menu: 'style' },
+ strapWidth: {
+ pct: 40,
+ min: 5,
+ max: 100,
+ menu: (settings, mergedOptions) => (mergedOptions.sleeves ? false : 'style.sleeves'),
+ },
+ sleeves: { bool: true, menu: 'style.sleeves' },
+
+ backNeckCutout: { pct: 15, min: 6, max: 110, menu: 'style' },
+ backNeckBend: { pct: 50, min: 0, max: 70, menu: 'style' },
+ },
+ draft: bibiBack,
+}
+
+function bibiBack({
+ store,
+ sa,
+ Point,
+ points,
+ Path,
+ paths,
+ Snippet,
+ snippets,
+ options,
+ measurements,
+ macro,
+ complete,
+ utils,
+ part,
+}) {
+ // Hide Brian paths
+ for (const 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/confusing points
+ delete points.frontArmholePitchCp1
+ delete points.frontArmholePitch
+ delete points.frontArmholePitchCp2
+ delete points.backArmholePitchCp1
+ delete points.backArmholePitch
+ delete points.backArmholePitchCp2
+ delete points.cfNeck
+ delete points.cfNeckCp1
+
+ constructBackPoints(points, Point, measurements, options)
+
+ adjustSidePoints(points, options)
+
+ correctArmHole(points, paths, Path, options, utils)
+
+ 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())
+
+ const 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.cbChest)
+ )
+ points.cbNeckCp1 = points.cbNeck.shift(0, points.hps.x * options.backNeckBend * 2)
+ points.neckCp2 = points.neck
+ .shiftTowards(points.shoulder, points.neck.dy(points.cbNeck) * (0.2 + options.backNeckBend))
+ .rotate(-90, points.neck)
+
+ paths.backNeck = new Path()
+ .move(points.neck)
+ .curve(points.neckCp2, points.cbNeckCp1, points.cbNeck)
+ .addClass('fabric')
+ createArmHoles(
+ options,
+ store,
+ points,
+ paths,
+ Path,
+ snippets,
+ Snippet,
+ strapWidth,
+ options.armholeCurveBack,
+ options.armholeDropBack,
+ utils,
+ '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.cbNeck,
+ to: points.cbHem,
+ grainline: true,
+ })
+
+ delete snippets.logo
+
+ points.title = points.cbHem.shift(45, 60)
+
+ 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..12ae2d43e09
--- /dev/null
+++ b/designs/bibi/src/front.mjs
@@ -0,0 +1,359 @@
+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: 110, menu: 'style' },
+ necklineBend: { pct: 50, min: 0, max: 70, menu: 'style' },
+ armholeCurveFront: {
+ pct: 15,
+ min: -10,
+ max: 30,
+ menu: (settings, mergedOptions) => (mergedOptions.sleeves ? false : 'style.sleeves'),
+ },
+ },
+ draft: bibiFront,
+}
+
+function bibiFront({
+ store,
+ sa,
+ Point,
+ points,
+ Path,
+ paths,
+ Snippet,
+ snippets,
+ options,
+ measurements,
+ macro,
+ complete,
+ utils,
+ part,
+}) {
+ // Hide Brian paths
+ for (const 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/confusing points
+ delete points.frontArmholePitchCp1
+ delete points.frontArmholePitch
+ delete points.frontArmholePitchCp2
+ delete points.backArmholePitchCp1
+ delete points.backArmholePitch
+ delete points.backArmholePitchCp2
+ delete points.cbHem
+ delete points.cbNeck
+
+ 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)
+
+ const strapWidth = options.sleeves ? 0 : options.strapWidth
+ points.neck = points.hps.shiftFractionTowards(
+ points.shoulder,
+ options.necklineWidth * (1 - strapWidth)
+ )
+
+ points.cfNeck = new Point(
+ 0,
+ points.neck.y + options.necklineDepth * points.neck.dy(points.cfBust)
+ )
+ points.cfNeckCp1 = points.cfNeck.shift(0, points.hps.x * options.necklineBend * 2)
+ 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())
+ const frontLength = store.get('frontSideSeamLength')
+ const backLength = store.get('backSideSeamLength') ?? 0
+ const dartLength = frontLength - backLength
+ const constructDart = (path, tip, dartLength) => {
+ const length = path.length()
+
+ dartLength = Math.max(0, Math.min(dartLength, length / 2))
+
+ const gatherArea = (store.get('gatherAreaLength') ?? 0) + dartLength
+ const offset = length - (store.get('gatherAreaStart') ?? 0) - gatherArea
+
+ const startSplit = path.shiftAlong(offset)
+ const startDartAlpha = path.shiftAlong(offset + (gatherArea - dartLength) * 0.5)
+ const endDartAlpha = path.shiftAlong(offset + (gatherArea + dartLength) * 0.5)
+ const endSplit = path.shiftAlong(offset + gatherArea)
+
+ let tmp = path.split(startSplit)
+ const pathBefore = tmp[0]
+ tmp = tmp[1].split(endSplit)
+ const pathGather = tmp[0]
+ const pathAfter = tmp[1]
+ const angleBefore = path.angleAt(startSplit)
+ const angleAfter = path.angleAt(endSplit)
+ const cpBefore = startSplit.shift(angleBefore, dartLength / 3)
+ const cpAfter = endSplit.shift(angleAfter, -dartLength / 3)
+
+ const dartDist = Math.max(tip.dist(startDartAlpha), tip.dist(endDartAlpha))
+
+ const startDart = tip.shiftTowards(startDartAlpha, dartDist)
+ const endDart = tip.shiftTowards(endDartAlpha, dartDist)
+ const dartMid = startDart.shiftFractionTowards(endDart, 0.5)
+ const tipShifted = tip.shiftFractionTowards(dartMid, 0.25)
+ const dartCpStart = tipShifted
+ .shiftFractionTowards(dartMid, 0.25)
+ .shiftFractionTowards(startDart, 0.25)
+ const 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
+ const cpSplitStart = startDart.shift(dartAngle - dartInnerAngle / 2, -dartLength / 4)
+ const 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,
+ options.armholeCurveFront,
+ 0,
+ utils
+ )
+
+ paths.centerLine = new Path().move(points.cfNeck).line(points.cfHem).addClass('fabric')
+
+ points.title = points.bust.shift(0, 5)
+
+ 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..afc3f8648c1
--- /dev/null
+++ b/designs/bibi/src/shared.mjs
@@ -0,0 +1,485 @@
+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, Math.max(measurements.hpsToWaistBack, 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,
+ armholeCurve,
+ armholeDrop,
+ utils,
+ notchType = 'notch'
+) {
+ if (options.sleeves) {
+ if (store.get('capSleeves')) {
+ const sleeveCapFactor = (options.sleeveLength + 0.2) * 4
+ const capLength = sleeveCapFactor * store.get('sleeveCapHeight')
+ points.sleeveCap = points.shoulder.shift(
+ points.neck.angle(points.shoulder) - 15 + options.cuffEase * 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.2 * points.strapTop.dy(points.armhole))
+ .rotate(90, points.strapTop)
+
+ // Increase weight of armhole control points because we don't use armholeHollow here anymore
+ points.armholeCp2 = points.armhole.shiftFractionTowards(points.armholeCp2, 3)
+
+ points.armholeIntersection = utils.beamsIntersect(
+ points.strapTop,
+ points.strapTopCp1,
+ points.armhole,
+ points.armholeCp2
+ )
+ points.armholeIntersectionDrop = points.armholeIntersection.shiftFractionTowards(
+ points.strapTop,
+ -armholeDrop
+ )
+
+ points.armholeCp2 = points.armholeCp2.shiftFractionTowards(
+ points.armholeIntersection,
+ armholeCurve
+ )
+ points.strapTopCp1 = points.strapTopCp1.shiftFractionTowards(
+ points.armholeIntersectionDrop,
+ armholeCurve
+ )
+
+ paths.armhole = new Path()
+ .move(points.armhole)
+ .curve(points.armholeCp2, 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]
+ let y = offsets[key]
+ if (!y || y > points.hem.y) {
+ continue
+ }
+ let intersects = sideSeam.intersectsY(y)
+ if (intersects.length === 0) {
+ // Intersecting the path exactly on the corner points sometimes doesn't work
+ // See issue #3367
+ y += 0.001
+ 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/designs/bob/README.md b/designs/bob/README.md
index 1aedebfb356..762d94604a3 100644
--- a/designs/bob/README.md
+++ b/designs/bob/README.md
@@ -21,7 +21,7 @@
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/lily/README.md b/designs/lily/README.md
new file mode 100644
index 00000000000..c95b8710c5b
--- /dev/null
+++ b/designs/lily/README.md
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
+
+
+
+# @freesewing/lily
+
+A FreeSewing pattern for basic leggings
+
+
+
+# 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/lily
+
+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/# 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/lily/build.mjs b/designs/lily/build.mjs
new file mode 100644
index 00000000000..99ace216bc8
--- /dev/null
+++ b/designs/lily/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/lily/data.mjs b/designs/lily/data.mjs
new file mode 100644
index 00000000000..ff5d4a4d600
--- /dev/null
+++ b/designs/lily/data.mjs
@@ -0,0 +1,4 @@
+// This file is auto-generated | All changes you make will be overwritten.
+export const name = '@freesewing/lily'
+export const version = '3.2.0'
+export const data = { name, version }
diff --git a/designs/lily/i18n/de.json b/designs/lily/i18n/de.json
new file mode 100644
index 00000000000..185dfb452be
--- /dev/null
+++ b/designs/lily/i18n/de.json
@@ -0,0 +1,7 @@
+{
+ "t": "Lily",
+ "d": "A FreeSewing pattern that needs a description",
+ "p": { },
+ "s": { },
+ "o": { }
+}
diff --git a/designs/lily/i18n/en.json b/designs/lily/i18n/en.json
new file mode 100644
index 00000000000..ad820c3445d
--- /dev/null
+++ b/designs/lily/i18n/en.json
@@ -0,0 +1,24 @@
+{
+ "t": "Lily",
+ "d": "A FreeSewing pattern for basic leggings",
+ "p": {
+ "back": "Back",
+ "front": "Front",
+ "waistband": "Waistband"
+ },
+ "s": {
+ "adjustEase.t": "Adjust ease settings to match fabric stretch",
+ "adjustEase.d": "Knee, seat and waist ease should be set to fabric stretch * -1/10; click the button to adjust all three.",
+ "adjustEase": "adjust ease"
+ },
+ "o": {
+ "lengthReduction": {
+ "t": "Length reduction",
+ "d": "Controls how much the leggings are shortened with respect to ankle length"
+ },
+ "fabricStretch": {
+ "t": "Fabric stretch",
+ "d": "How much the fabric can stretch horizontally; this is used to calculate ease"
+ }
+ }
+}
diff --git a/designs/lily/i18n/es.json b/designs/lily/i18n/es.json
new file mode 100644
index 00000000000..185dfb452be
--- /dev/null
+++ b/designs/lily/i18n/es.json
@@ -0,0 +1,7 @@
+{
+ "t": "Lily",
+ "d": "A FreeSewing pattern that needs a description",
+ "p": { },
+ "s": { },
+ "o": { }
+}
diff --git a/designs/lily/i18n/fr.json b/designs/lily/i18n/fr.json
new file mode 100644
index 00000000000..185dfb452be
--- /dev/null
+++ b/designs/lily/i18n/fr.json
@@ -0,0 +1,7 @@
+{
+ "t": "Lily",
+ "d": "A FreeSewing pattern that needs a description",
+ "p": { },
+ "s": { },
+ "o": { }
+}
diff --git a/designs/lily/i18n/index.mjs b/designs/lily/i18n/index.mjs
new file mode 100644
index 00000000000..36aac928b67
--- /dev/null
+++ b/designs/lily/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/lily/i18n/nl.json b/designs/lily/i18n/nl.json
new file mode 100644
index 00000000000..185dfb452be
--- /dev/null
+++ b/designs/lily/i18n/nl.json
@@ -0,0 +1,7 @@
+{
+ "t": "Lily",
+ "d": "A FreeSewing pattern that needs a description",
+ "p": { },
+ "s": { },
+ "o": { }
+}
diff --git a/designs/lily/i18n/uk.json b/designs/lily/i18n/uk.json
new file mode 100644
index 00000000000..185dfb452be
--- /dev/null
+++ b/designs/lily/i18n/uk.json
@@ -0,0 +1,7 @@
+{
+ "t": "Lily",
+ "d": "A FreeSewing pattern that needs a description",
+ "p": { },
+ "s": { },
+ "o": { }
+}
diff --git a/designs/lily/package.json b/designs/lily/package.json
new file mode 100644
index 00000000000..34552f353c8
--- /dev/null
+++ b/designs/lily/package.json
@@ -0,0 +1,74 @@
+{
+ "name": "@freesewing/lily",
+ "version": "3.2.0",
+ "description": "A FreeSewing pattern for basic leggings",
+ "author": "Anna Puk (https://github.com/anna-puk)",
+ "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/core": "3.2.0",
+ "@freesewing/titan": "3.2.0",
+ "@freesewing/paco": "3.2.0"
+ },
+ "dependencies": {},
+ "devDependencies": {
+ "mocha": "10.3.0",
+ "chai": "5.1.0",
+ "@freesewing/models": "3.2.0",
+ "@freesewing/plugin-timing": "3.2.0"
+ },
+ "files": [
+ "dist/*",
+ "README.md"
+ ],
+ "publishConfig": {
+ "access": "public",
+ "tag": "latest"
+ },
+ "engines": {
+ "node": ">= 18.17.0 <22"
+ }
+}
diff --git a/designs/lily/src/back.mjs b/designs/lily/src/back.mjs
new file mode 100644
index 00000000000..fc290e894d9
--- /dev/null
+++ b/designs/lily/src/back.mjs
@@ -0,0 +1,590 @@
+import { back as titanBack } from '@freesewing/titan'
+
+function draftLilyBack({
+ points,
+ Point,
+ paths,
+ Path,
+ measurements,
+ options,
+ complete,
+ paperless,
+ store,
+ macro,
+ utils,
+ snippets,
+ Snippet,
+ sa,
+ absoluteOptions,
+ part,
+ log,
+ units,
+}) {
+ //TODO: implement stretch setting to replace ease
+ // work-around: flag it
+ const stretchAsEase = -options.fabricStretch / 10
+ const easeTol = 0.005
+ if (
+ Math.abs(options.waistEase - stretchAsEase) > easeTol ||
+ Math.abs(options.seatEase - stretchAsEase) > easeTol ||
+ Math.abs(options.kneeEase - stretchAsEase) > easeTol
+ ) {
+ store.flag.note({
+ msg: `lily:adjustEase`,
+ replace: {
+ stretch: units(options.fabricStretch),
+ ease: stretchAsEase,
+ },
+ suggest: {
+ text: 'adjustEase',
+ icon: 'options',
+ update: {
+ settings: [
+ 'options',
+ {
+ ...options,
+ waistEase: stretchAsEase,
+ seatEase: stretchAsEase,
+ kneeEase: stretchAsEase,
+ },
+ ],
+ },
+ },
+ })
+ }
+
+ /*
+ * Helper method to draw the inseam path
+ */
+ const drawInseam = () =>
+ new Path()
+ .move(points.fork)
+ .curve(points.forkCp2, points.kneeInCp1, points.kneeIn)
+ .curve(points.kneeInCp2, points.floorInCp2, points.floorIn)
+ /*
+ * Helper method to draw the outseam path
+ */
+ const drawOutseam = () => {
+ const waistOut = points.styleWaistOutLily || points.waistOut
+ if (points.waistOut.x > points.seatOut.x)
+ return new Path()
+ .move(points.floorOut)
+ .curve(points.floorOutCp2, points.kneeOutCp1, points.kneeOut)
+ .curve(points.kneeOutCp2, points.seatOut, waistOut)
+ else
+ return new Path()
+ .move(points.floorOut)
+ .curve(points.floorOutCp2, points.kneeOutCp1, points.kneeOut)
+ .curve(points.kneeOutCp2, points.seatOutCp1, points.seatOut)
+ .curve_(points.seatOutCp2, waistOut)
+ }
+ /*
+ * Helper method to draw the outline path
+ */
+ const drawPath = () => {
+ const waistIn = points.styleWaistInLily || points.waistIn
+ return drawInseam()
+ .line(points.floorOut)
+ .join(drawOutseam())
+ .line(waistIn)
+ .line(points.crossSeamCurveStart)
+ .curve(points.crossSeamCurveCp1, points.crossSeamCurveCp2, points.fork)
+ .close()
+ }
+ /*
+ * Helper method to calculate the length of the cross seam
+ */
+ const crossSeamDelta = () =>
+ new Path()
+ .move(points.waistIn)
+ .line(points.crossSeamCurveStart)
+ .curve(points.crossSeamCurveCp1, points.crossSeamCurveCp2, points.fork)
+ .length() - measurements.crossSeamBack
+ /*
+ * Helper method to (re)draw the cross seam
+ */
+ const drawCrossSeam = () => {
+ points.crossSeamCurveStart = points.waistIn.shiftFractionTowards(
+ points.cbSeat,
+ options.crossSeamCurveStart
+ )
+ points.crossSeamCurveMax = utils.beamsIntersect(
+ points.waistIn,
+ points.cbSeat,
+ points.fork,
+ points.fork.shift(0, 1) // beams have infinite length anyway
+ )
+ points.crossSeamCurveCp1 = points.crossSeamCurveStart.shiftFractionTowards(
+ points.crossSeamCurveMax,
+ options.crossSeamCurveBend
+ )
+ points.crossSeamCurveCp2 = points.fork
+ .shiftFractionTowards(points.crossSeamCurveMax, options.crossSeamCurveBend)
+ .rotate(options.crossSeamCurveAngle, points.fork)
+ }
+
+ // NOTE: majority of points re-used from titan
+
+ // shape at the ankle (unlike titan)
+ const halfAnkle =
+ measurements.ankle * (1 + options.fabricStretch) > measurements.heel
+ ? (1 - options.fabricStretch / 10) * (measurements.ankle / 4)
+ : measurements.heel / 4 / (1 + options.fabricStretch)
+ // NOTE: for shortened leggings, this may not have been necessary...
+
+ points.floorOut = points.floor.shift(0, halfAnkle)
+ points.floorIn = points.floorOut.flipX(points.floor)
+
+ store.set('halfAnkle', halfAnkle)
+
+ points.floorInCp2 = points.floorIn.shift(90, points.knee.dy(points.floor) / 3)
+ points.kneeInCp2 = points.kneeIn.shift(90, -points.knee.dy(points.floor) / 3)
+ points.floorOutCp2 = points.floorOut.shift(90, points.knee.dy(points.floor) / 3)
+ points.kneeOutCp1 = points.kneeOut.shift(90, -points.knee.dy(points.floor) / 3)
+
+ // other control points have already been calculated in titan:
+ // Control points to shape the legs towards the seat
+ // Balance the waist
+
+ // Cross seam
+ drawCrossSeam()
+
+ //Uncomment the line below to see the seam prior to fitting the cross seam
+ // paths.seam1 = drawPath().attr('class', 'dashed lining')
+
+ // Should we fit the cross seam?
+ if (options.fitCrossSeam && options.fitCrossSeamBack) {
+ let delta = crossSeamDelta()
+ let run = 0
+ do {
+ run++
+ // Remedy A: Slash and spread
+ for (const i of ['waistIn', 'waistOut'])
+ points[i] = points[i].rotate(delta / 15, points.seatOut)
+ // Remedy B: Nudge the fork inwards/outwards
+ points.fork = points.fork.shift(0, delta / 5)
+ points.forkCp2 = points.crossSeamCurveCp2.rotate(-90, points.fork)
+ drawCrossSeam()
+ delta = crossSeamDelta()
+ // Uncomment the line beloe this to see all iterations
+ // paths[`try${run}`] = drawPath().attr('class', 'dotted')
+ } while (Math.abs(delta) > 1 && run < 15)
+ }
+
+ // Store inseam & outseam length
+ store.set('inseamBack', drawInseam().length())
+ store.set('outseamBack', drawOutseam().length())
+
+ // Only now style the waist lower if requested
+ // Note: redo this for lily even though it was already done for titan;
+ // calculation for titan happened using its own seam lengths
+ store.set('waistbandWidth', absoluteOptions.waistbandWidth) // used in lilyWaistband
+ if (options.waistHeight < 1 || absoluteOptions.waistbandWidth > 0) {
+ points.styleWaistOutLily = drawOutseam()
+ .reverse()
+ .shiftAlong(
+ measurements.waistToHips * (1 - options.waistHeight) + absoluteOptions.waistbandWidth
+ )
+ points.styleWaistInLily = utils.beamsIntersect(
+ points.styleWaistOutLily,
+ points.styleWaistOutLily.shift(points.waistOut.angle(points.waistIn), 10),
+ points.waistIn,
+ points.crossSeamCurveStart
+ )
+ } else {
+ points.styleWaistInLily = points.waistIn.clone()
+ points.styleWaistOutLily = points.waistOut.clone()
+ }
+ // Adapt the vertical placement of the seat control point to the lowered waist
+ points.seatOutCp2.y = points.seatOut.y - points.styleWaistOutLily.dy(points.seatOut) / 2
+ let test = points.styleWaistInLily.dist(points.styleWaistOutLily)
+ console.log('back waist length', test)
+ store.set('backWaist', points.styleWaistInLily.dist(points.styleWaistOutLily))
+
+ // Paths
+ paths.seam = drawPath().attr('class', 'fabric')
+
+ // adjust the length (at the bottom)
+ let extendBeyondKnee = 1
+ if (options.lengthReduction > 0) {
+ let requestedLength = (1 - options.lengthReduction) * measurements.waistToFloor
+ // leggings must reach to fork at least, so define a minimum
+ const waistToFork = points.waistX.dy(points.fork)
+ if (waistToFork >= 0.999 * requestedLength) {
+ log.warn('length reduction capped; cutting off at fork')
+ // add one percent to waistToFork to ensure that path length is nonzero
+ requestedLength = waistToFork * 1.01
+ }
+
+ // work-around to avoid splitting exactly at the knee
+ // (due to a bug, splitting a path at a node is not possible)
+ if (
+ 0.999 < requestedLength / measurements.waistToKnee &&
+ requestedLength / measurements.waistToKnee < 1.001
+ ) {
+ requestedLength = 1.001 * measurements.waistToKnee
+ }
+ points.bottom = points.waistX.shift(270, requestedLength)
+ let upperPoint, upperCp
+ if (requestedLength < measurements.waistToKnee) {
+ extendBeyondKnee = 0
+
+ // 'cut' between fork and knee
+ if (points.waistOut.x > points.seatOut.x) {
+ upperPoint = points.styleWaistOutLily
+ upperCp = points.seatOut
+ } else {
+ upperPoint = points.seatOut
+ upperCp = points.seatOutCp1
+ }
+ points.bottomOut = utils.beamIntersectsCurve(
+ points.bottom.shift(0, 999),
+ points.bottom.shift(180, 999),
+ points.kneeOut,
+ points.kneeOutCp2,
+ upperCp,
+ upperPoint
+ )
+
+ points.bottomIn = utils.beamIntersectsCurve(
+ points.bottom.shift(0, 999),
+ points.bottom.shift(180, 999),
+ points.kneeIn,
+ points.kneeInCp1,
+ points.forkCp2,
+ points.fork
+ )
+ } else {
+ // 'cut' between knee and 'floor'
+ points.bottomOut = utils.beamIntersectsCurve(
+ points.bottom.shift(0, 999),
+ points.bottom.shift(180, 999),
+ points.kneeOut,
+ points.kneeOutCp1,
+ points.floorOutCp2,
+ points.floorOut
+ )
+
+ points.bottomIn = utils.beamIntersectsCurve(
+ points.bottom.shift(0, 999),
+ points.bottom.shift(180, 999),
+ points.kneeIn,
+ points.kneeInCp2,
+ points.floorInCp2,
+ points.floorIn
+ )
+ }
+
+ // define the three parts of the path, then combine
+ paths.bottom = new Path().move(points.bottomIn).line(points.bottomOut)
+
+ const halves = paths.seam.split(points.bottomIn)
+ paths.upperInseam = halves[0]
+ const halves2 = halves[1].split(points.bottomOut)
+ paths.upperOutseam = halves2[1]
+
+ paths.seam = paths.upperInseam.join(paths.bottom).join(paths.upperOutseam)
+
+ // store requestedLength for use in front part
+ store.set('requestedLength', requestedLength)
+ } else {
+ // define the same three parts of the path as when length reduction is enabled, then combine
+
+ // first define the points (also used for paperless)
+ points.bottom = points.floor
+ points.bottomIn = points.floorIn
+ points.bottomOut = points.floorOut
+
+ paths.bottom = new Path().move(points.bottomIn).line(points.bottomOut)
+
+ // note: upperOutseam contains waist and cross seam as well
+ paths.upperInseam = drawInseam()
+ paths.upperOutseam = drawOutseam().join(
+ new Path()
+ .move(points.styleWaistOutLily)
+ .line(points.styleWaistInLily)
+ .line(points.crossSeamCurveStart)
+ .curve(points.crossSeamCurveCp1, points.crossSeamCurveCp2, points.fork)
+ )
+ paths.bottom.hide()
+ paths.upperInseam.hide()
+ paths.upperOutseam.hide()
+ }
+
+ points.grainlineTop.y = points.styleWaistOutLily.y
+ points.grainlineBottom.y = points.bottom.y
+ macro('grainline', {
+ from: points.grainlineTop,
+ to: points.grainlineBottom,
+ })
+ points.logoAnchor = new Point(points.crossSeamCurveStart.x / 2, points.fork.y)
+ snippets.logo = new Snippet('logo', points.logoAnchor)
+ points.scalebox = points.logoAnchor.shiftFractionTowards(
+ points.styleWaistOutLily.shiftFractionTowards(points.styleWaistInLily, 0.5),
+ 0.5
+ )
+ macro('scalebox', { at: points.scalebox })
+ points.titleAnchor = points.logoAnchor.shift(-90, 60)
+ macro('title', {
+ nr: 1,
+ title: 'back',
+ at: points.titleAnchor,
+ })
+
+ //notches
+ if (options.fitGuides) {
+ points.waistMid = points.waistOut.shiftFractionTowards(points.waistIn, 0.5)
+ // shift + rotate (below) is equivalent to shifting measurements.waistToSeat perpendicular to the waistIn-waistMid line
+ points.seatMid = points.waistMid
+ .shiftTowards(points.waistIn, measurements.waistToSeat)
+ .rotate(90, points.waistMid)
+ points.seatInTarget = points.seatOut.shiftOutwards(points.seatMid, measurements.seat / 4)
+ points.seatOutTarget = points.seatMid.shiftTowards(points.seatOut, measurements.seat / 4)
+ // shift + rotate (below) is equivalent to shifting measurements.waistToHips perpendicular to the waistIn-waistOut line
+ points.hipsInTarget = points.waistIn
+ .shiftTowards(points.waistOut, measurements.waistToHips)
+ .rotate(-90, points.waistIn)
+ points.hipsOutTarget = points.waistOut
+ .shiftTowards(points.waistIn, measurements.waistToHips)
+ .rotate(90, points.waistOut)
+ points.hipsIn = utils.beamsIntersect(
+ points.hipsOutTarget,
+ points.hipsInTarget,
+ points.waistIn,
+ points.crossSeamCurveStart
+ )
+ points.crossSeamCurveStartMid = utils.beamsIntersect(
+ points.crossSeamCurveStart,
+ points.crossSeamCurveStart.shift(points.waistIn.angle(points.waistOut), 1),
+ points.waistMid,
+ points.seatMid
+ )
+ if (points.seatMid.y > points.crossSeamCurveStartMid.y) {
+ points.seatIn = utils.lineIntersectsCurve(
+ points.seatMid,
+ points.seatInTarget,
+ points.crossSeamCurveStart,
+ points.crossSeamCurveCp1,
+ points.crossSeamCurveCp2,
+ points.fork
+ )
+ } else {
+ points.seatIn = utils.beamsIntersect(
+ points.seatMid,
+ points.seatInTarget,
+ points.waistIn,
+ points.crossSeamCurveStart
+ )
+ }
+ if (points.waistOut.x > points.seatOut.x) {
+ points.hipsOut = utils.lineIntersectsCurve(
+ points.hipsIn,
+ points.hipsIn.rotate(180, points.hipsOutTarget),
+ points.kneeOut,
+ points.kneeOutCp2,
+ points.seatOut,
+ points.waistOut
+ )
+ points.seatOutNotch = utils.lineIntersectsCurve(
+ points.seatMid,
+ points.seatOutTarget,
+ points.kneeOut,
+ points.kneeOutCp2,
+ points.seatOut,
+ points.waistOut
+ )
+ } else {
+ points.hipsOut = utils.lineIntersectsCurve(
+ points.hipsIn,
+ points.hipsIn.rotate(180, points.hipsOutTarget),
+ points.seatOut,
+ points.seatOutCp2,
+ points.waistOut,
+ points.waistOut
+ )
+ points.seatOutNotch = points.seatOut
+ }
+ points.kneeOutNotch = points.kneeOut
+ points.kneeInNotch = points.kneeIn
+ macro('sprinkle', {
+ snippet: 'notch',
+ on: ['seatOutNotch'],
+ })
+ if (extendBeyondKnee) {
+ macro('sprinkle', {
+ snippet: 'notch',
+ on: ['kneeInNotch', 'kneeOutNotch'],
+ })
+ }
+ macro('sprinkle', {
+ snippet: 'bnotch',
+ on: ['crossSeamCurveStart', 'seatIn'],
+ })
+
+ if (complete) {
+ paths.seatline = new Path()
+ .move(points.seatIn)
+ .line(points.seatOutNotch)
+ .addClass('fabric help')
+ .addText('Seat Line', 'center')
+ if (
+ measurements.waistToHips * (1 - options.waistHeight) + absoluteOptions.waistbandWidth <
+ measurements.waistToHips
+ ) {
+ snippets.hipsIn = new Snippet('bnotch', points.hipsIn)
+ snippets.hipsOut = new Snippet('notch', points.hipsOut)
+ paths.hipline = new Path()
+ .move(points.hipsIn)
+ .line(points.hipsOut)
+ .addClass('fabric help')
+ .addText('Hip Line', 'center')
+ }
+ }
+ }
+
+ if (sa) {
+ paths.saBase = paths.upperOutseam.join(paths.upperInseam).hide()
+ paths.hemBase = paths.bottom.hide()
+ paths.sa = paths.hemBase
+ .offset(sa * 3)
+ .join(paths.saBase.offset(sa))
+ .close()
+ .addClass('fabric sa')
+ }
+
+ if (paperless) {
+ // Help construct cross seam
+ paths.hint = new Path()
+ .move(points.crossSeamCurveStart)
+ .line(points.crossSeamCurveMax)
+ .line(points.fork)
+ .addClass('note lashed')
+ macro('hd', {
+ id: 'wHem',
+ from: points.bottomIn,
+ to: points.bottomOut,
+ y: points.bottomIn.y - 30,
+ })
+ macro('hd', {
+ id: 'wHemLeft',
+ from: points.bottomIn,
+ to: points.bottom,
+ y: points.bottomIn.y - 15,
+ })
+ macro('hd', {
+ id: 'wHemRight',
+ from: points.bottom,
+ to: points.bottomOut,
+ y: points.bottomIn.y - 15,
+ })
+ macro('vd', {
+ id: 'hHemToSideWaist',
+ from: points.bottomOut,
+ to: points.styleWaistOutLily,
+ x:
+ (points.seatOut.x > points.styleWaistOutLily.x
+ ? points.seatOut.x
+ : points.styleWaistOutLily.x) +
+ sa +
+ 15,
+ })
+ macro('vd', {
+ id: 'hHemToFork',
+ from: points.bottomIn,
+ to: points.fork,
+ x: points.fork.x - sa - 15,
+ })
+ macro('vd', {
+ id: 'hForkToCbWaist',
+ from: points.fork,
+ to: points.styleWaistInLily,
+ x: points.fork.x - sa - 15,
+ })
+ macro('vd', {
+ id: 'hFull',
+ from: points.bottomIn,
+ to: points.styleWaistInLily,
+ x: points.fork.x - sa - 30,
+ })
+ macro('vd', {
+ id: 'hStartCrotchCurveToCbWaist',
+ from: points.crossSeamCurveStart,
+ to: points.styleWaistInLily,
+ x: points.crossSeamCurveStart.x - sa - 15,
+ })
+ macro('hd', {
+ id: 'wCbWaistToPleat',
+ from: points.styleWaistInLily,
+ to: points.grainlineTop,
+ y: points.styleWaistInLily.y - sa - 15,
+ })
+ macro('hd', {
+ id: 'wStartCrotchCurveToPleat',
+ from: points.crossSeamCurveStart,
+ to: points.grainlineTop,
+ y: points.styleWaistInLily.y - sa - 30,
+ })
+ macro('hd', {
+ id: 'wForkProjectionToPleat',
+ from: points.crossSeamCurveMax,
+ to: points.grainlineTop,
+ y: points.styleWaistInLily.y - sa - 45,
+ })
+ macro('hd', {
+ id: 'wForkToPleat',
+ from: points.fork,
+ to: points.grainlineTop,
+ y: points.styleWaistInLily.y - sa - 60,
+ })
+ macro('hd', {
+ id: 'wPleatToSideWaist',
+ from: points.grainlineTop,
+ to: points.styleWaistOutLily,
+ y: points.styleWaistInLily.y - sa - 15,
+ })
+ if (points.seatOut.x > points.styleWaistOutLily.x) {
+ macro('hd', {
+ id: 'wPleatToSideWaistAlt',
+ from: points.grainlineTop,
+ to: points.seatOut,
+ y: points.styleWaistInLily.y - sa - 30,
+ })
+ }
+ }
+
+ return part
+}
+
+export const back = {
+ name: 'lily.back',
+ from: titanBack,
+ //after: titanFront,
+ measurements: [
+ 'ankle',
+ 'heel', // secondary measurement, used instead of ankle
+ ],
+ options: {
+ fitGuides: { bool: false, menu: 'advanced' },
+ fitKnee: { bool: true, hide: true },
+ legBalance: 0.5, // between back and front parts
+ waistBalance: 0.5,
+ crotchDrop: { pct: 0, min: 0, max: 15, menu: 'advanced' }, // 'downgrade' to advanced menu
+ waistHeight: { ...titanBack.options.waistHeight, pct: 50 }, // halfway between waist and hips
+ fabricStretch: { pct: 40, min: 0, max: 50, menu: 'fit' },
+ waistEase: { pct: -4, min: -20, max: 0, menu: 'fit' }, // -fabricStretch/10,
+ seatEase: { pct: -4, min: -20, max: 0, menu: 'fit' }, // -fabricStretch/10,
+ kneeEase: { pct: -4, min: -20, max: 0, menu: 'fit' }, // -fabricStretch/10,
+ //test: {pct: back.options.fabricStretch/2, min: 0, max: 50, menu: 'fit'},
+ lengthBonus: 0,
+ lengthReduction: {
+ pct: 0,
+ min: 0,
+ max: 100,
+ toAbs: (pct, { measurements }) => measurements.waistToFloor * pct,
+ menu: 'style',
+ },
+ waistbandWidth: { ...titanBack.options.waistbandWidth, menu: 'style' },
+ },
+ hide: 'HIDE_TREE',
+ draft: draftLilyBack,
+}
diff --git a/designs/lily/src/front.mjs b/designs/lily/src/front.mjs
new file mode 100644
index 00000000000..d4e4cbb5e13
--- /dev/null
+++ b/designs/lily/src/front.mjs
@@ -0,0 +1,602 @@
+import { front as titanFront } from '@freesewing/titan'
+import { back } from './back.mjs'
+
+function draftLilyFront({
+ points,
+ Point,
+ paths,
+ Path,
+ measurements,
+ options,
+ complete,
+ paperless,
+ store,
+ macro,
+ utils,
+ snippets,
+ Snippet,
+ sa,
+ absoluteOptions,
+ log,
+ part,
+}) {
+ /*
+ * Helper method to draw the inseam path
+ */
+ const drawInseam = () =>
+ new Path()
+ .move(points.floorIn)
+ .curve(points.floorInCp2, points.kneeInCp1, points.kneeIn)
+ .curve(points.kneeInCp2, points.forkCp1, points.fork)
+ /*
+ * Helper method to draw the outseam path
+ */
+ const drawOutseam = () => {
+ const waistOut = points.styleWaistOutLily || points.waistOut
+ return points.waistOut.x < points.seatOut.x
+ ? new Path()
+ .move(waistOut)
+ .curve(points.seatOut, points.kneeOutCp1, points.kneeOut)
+ .curve(points.kneeOutCp2, points.floorOutCp2, points.floorOut)
+ : new Path()
+ .move(waistOut)
+ ._curve(points.seatOutCp1, points.seatOut)
+ .curve(points.seatOutCp2, points.kneeOutCp1, points.kneeOut)
+ .curve(points.kneeOutCp2, points.floorOutCp2, points.floorOut)
+ }
+ /*
+ * Helper method to draw the outline path
+ */
+ const drawPath = () => {
+ const waistIn = points.styleWaistInLily || points.waistIn
+ const waistOut = points.styleWaistOutLily || points.waistOut
+ return drawOutseam()
+ .line(points.floorIn)
+ .join(drawInseam())
+ .curve(points.crotchSeamCurveCp1, points.crotchSeamCurveCp2, points.crotchSeamCurveStart)
+ .line(waistIn)
+ .line(waistOut)
+ .close()
+ }
+ /*
+ * Helper method to calculate the length of the crotch seam
+ */
+ const crotchSeamDelta = () =>
+ new Path()
+ .move(points.waistIn)
+ .line(points.crotchSeamCurveStart)
+ .curve(points.crotchSeamCurveCp2, points.crotchSeamCurveCp1, points.fork)
+ .length() - measurements.crossSeamFront
+ /*
+ * Helper method to (re)draw the crotch seam
+ */
+ const drawCrotchSeam = () => {
+ points.crotchSeamCurveStart = points.waistIn.shiftFractionTowards(
+ points.cfSeat,
+ options.crotchSeamCurveStart
+ )
+ points.crotchSeamCurveMax = utils.beamsIntersect(
+ points.waistIn,
+ points.cfSeat,
+ points.fork,
+ points.fork.shift(0, 666)
+ )
+ points.crotchSeamCurveCp1 = points.fork
+ .shiftFractionTowards(points.crotchSeamCurveMax, options.crotchSeamCurveBend)
+ .rotate(options.crotchSeamCurveAngle * -1, points.fork)
+ points.crotchSeamCurveCp2 = points.crotchSeamCurveStart.shiftFractionTowards(
+ points.crotchSeamCurveMax,
+ options.crotchSeamCurveBend
+ )
+ points.forkCp1 = points.crotchSeamCurveCp1.rotate(90, points.fork)
+ }
+ /*
+ * Helper method to calculate the inseam delta
+ */
+ const inseamDelta = () => drawInseam().length() - store.get('inseamBack')
+ /*
+ * Helper method to calculate the outseam delta
+ */
+ const outseamDelta = () => drawOutseam().length() - store.get('outseamBack')
+ /*
+ * Helper method to lengthen/shorten both inseam and outseam
+ */
+ const adaptInseamAndOutseam = () => {
+ const shift = [
+ 'kneeInCp1',
+ 'kneeInCp2',
+ 'kneeOutCp1',
+ 'kneeOutCp2',
+ 'kneeIn',
+ 'kneeOut',
+ 'knee',
+ 'floorInCp2',
+ 'floorIn',
+ 'floorOutCp2',
+ 'floorOut',
+ 'floor',
+ 'grainlineBottom',
+ ]
+ let delta = seamDelta()
+ let run = 0
+ do {
+ run++
+ for (const i of shift) points[i] = points[i].shift(90, delta)
+ delta = seamDelta()
+ } while (Math.abs(delta) > 1 && run < 10)
+ }
+ /*
+ * Helper method to determine the delta common when both inseam and outseam
+ * are either too long or too short
+ */
+ const seamDelta = () => {
+ const inseam = inseamDelta()
+ const outseam = outseamDelta()
+ return Math.abs(inseam) > Math.abs(outseam) ? outseam : inseam
+ }
+ /*
+ * Helper method that can fit either inseam or outseam
+ */
+ const adaptSeam = (side) => {
+ const out = side === 'out' ? true : false
+ const rotate = [
+ 'cfSeat',
+ 'crotchSeamCurveCp1',
+ 'crotchSeamCurveCp2',
+ 'crotchSeamCurveStart',
+ 'waistIn',
+ 'cfWaist',
+ 'waistOut',
+ ]
+ rotate.push(out ? 'seatOut' : 'fork')
+ const deltaMethod = out ? outseamDelta : inseamDelta
+ let run = 0
+ let delta = deltaMethod()
+ do {
+ for (const i of rotate)
+ points[i] = points[i].rotate(
+ (delta / 10) * (out ? 1 : -1),
+ points[out ? 'fork' : 'seatOut']
+ )
+ run++
+ delta = deltaMethod()
+ } while (Math.abs(delta) > 1 && run < 20)
+ }
+ const adaptOutseam = () => adaptSeam('out')
+ const adaptInseam = () => adaptSeam('in')
+
+ // NOTE: majority of points re-used from titan
+
+ // shape at the ankle (unlike titan)
+ points.floorOut = points.floor.shift(180, store.get('halfAnkle'))
+ points.floorIn = points.floorOut.flipX(points.floor)
+
+ // Control points between knee and ankle
+ points.floorInCp2 = points.floorIn.shift(90, points.knee.dy(points.floor) / 3)
+ points.kneeInCp1 = points.kneeIn.shift(90, -points.knee.dy(points.floor) / 3)
+ points.floorOutCp2 = points.floorOut.shift(90, points.knee.dy(points.floor) / 3)
+ points.kneeOutCp2 = points.kneeOut.shift(90, -points.knee.dy(points.floor) / 3)
+
+ // other control points have already been calculated in titan
+ // Control points to shape the legs towards the seat
+ // Balance the waist
+
+ // Draw initial crotch seam
+ drawCrotchSeam()
+
+ // Uncomment this to see the outline prior to fitting the crotch seam
+ //paths.seam1 = drawPath().attr('class', 'dashed lining')
+
+ if (options.fitCrossSeam && options.fitCrossSeamFront) {
+ let delta = crotchSeamDelta()
+ let run = 0
+ do {
+ run++
+ // Remedy A: Slash and spread
+ for (const i of ['waistIn', 'waistOut', 'cfWaist'])
+ points[i] = points[i].rotate(delta / -15, points.seatOut)
+ // Remedy B: Nudge the fork inwards/outwards
+ points.fork = points.fork.shift(180, delta / 5)
+ drawCrotchSeam()
+ delta = crotchSeamDelta()
+ // Uncomment the line below this to see all iterations
+ //paths[`try${run}`] = drawPath().attr('class', 'dotted')
+ } while (Math.abs(delta) > 1 && run < 15)
+ }
+
+ // Uncomment this to see the outline prior to fitting the inseam & outseam
+ //paths.seam2 = drawPath().attr('class', 'dotted interfacing')
+
+ /*
+ * With the cross seams matched back and front,
+ * all that's left is to match the inseam and outseam
+ */
+
+ // When both are too short/long, adapt the leg length
+ if ((inseamDelta() < 0 && outseamDelta() < 0) || (inseamDelta() > 0 && outseamDelta() > 0))
+ adaptInseamAndOutseam()
+
+ // Now one is ok, the other will be adapted
+ adaptOutseam()
+ adaptInseam()
+
+ // Changing one will ever so slightly impact the other, so let's run both again to be sure
+ adaptOutseam()
+ adaptInseam()
+
+ // Only now style the waist lower if requested
+ // Note: redo this for lily even though it was already done for titan;
+ // calculation for titan happened using its own seam lengths
+ if (options.waistHeight < 1 || absoluteOptions.waistbandWidth > 0) {
+ points.styleWaistOutLily = drawOutseam().shiftAlong(
+ measurements.waistToHips * (1 - options.waistHeight) + absoluteOptions.waistbandWidth
+ )
+ points.styleWaistInLily = utils.beamsIntersect(
+ points.styleWaistOutLily,
+ points.styleWaistOutLily.shift(points.waistOut.angle(points.waistIn), 10),
+ points.waistIn,
+ points.crotchSeamCurveStart
+ )
+ } else {
+ points.styleWaistInLily = points.waistIn.clone()
+ points.styleWaistOutLily = points.waistOut.clone()
+ }
+ store.set('frontWaist', points.styleWaistInLily.dist(points.styleWaistOutLily))
+
+ // Now that the top of the garment has been lowered, adjust the
+ // crotchSeamCurveStart so it doesn't start above the top of the garment.
+ if (points.crotchSeamCurveStart.y < points.styleWaistInLily.y) {
+ points.crotchSeamCurveStart = points.styleWaistInLily.clone()
+ }
+
+ // Seamline
+ paths.seam = drawPath().attr('class', 'fabric')
+
+ // adjust the length (at the bottom)
+ let extendBeyondKnee = 1
+ if (options.lengthReduction > 0) {
+ let requestedLength = store.get('requestedLength')
+ // leggings must reach to fork at least, so define a minimum
+ let waistToFork = points.waistX.dy(points.fork)
+ let waistToKnee = points.waistX.dy(points.knee) // adapting the seams may have shifted the knee up or down
+ if (waistToFork > requestedLength) {
+ //log.warning('length reduction capped; cutting off at fork') // log only for back part
+ // add one percent to waistToFork to ensure that path length is nonzero
+ requestedLength = waistToFork * 1.01
+ }
+
+ // work-around to avoid splitting exactly at the knee
+ // (due to a bug, splitting a path at a node is not possible)
+ if (0.999 < requestedLength / waistToKnee && requestedLength / waistToKnee < 1.001) {
+ requestedLength = 1.001 * waistToKnee
+ }
+ points.bottom = points.waistX.shift(270, requestedLength)
+ let upperPoint, upperCp
+ if (requestedLength < waistToKnee) {
+ extendBeyondKnee = 0
+
+ // 'cut' between fork and knee
+ if (points.waistOut.x < points.seatOut.x) {
+ upperPoint = points.styleWaistOutLily
+ upperCp = points.seatOut
+ } else {
+ upperPoint = points.seatOut
+ upperCp = points.seatOutCp2
+ }
+ points.bottomOut = utils.lineIntersectsCurve(
+ points.bottom.shift(0, 999),
+ points.bottom.shift(180, 999),
+ points.kneeOut,
+ points.kneeOutCp1,
+ upperCp,
+ upperPoint
+ )
+
+ points.bottomIn = utils.lineIntersectsCurve(
+ points.bottom.shift(0, 999),
+ points.bottom.shift(180, 999),
+ points.kneeIn,
+ points.kneeInCp2,
+ points.forkCp1,
+ points.fork
+ )
+ } else {
+ // 'cut' between knee and 'floor'
+ points.bottomOut = utils.lineIntersectsCurve(
+ points.bottom.shift(0, 999),
+ points.bottom.shift(180, 999),
+ points.kneeOut,
+ points.kneeOutCp2,
+ points.floorOutCp2,
+ points.floorOut
+ )
+
+ points.bottomIn = utils.lineIntersectsCurve(
+ points.bottom.shift(0, 999),
+ points.bottom.shift(180, 999),
+ points.kneeIn,
+ points.kneeInCp1,
+ points.floorInCp2,
+ points.floorIn
+ )
+ }
+
+ // define the three parts of the path, then combine
+ paths.bottom = new Path().move(points.bottomOut).line(points.bottomIn)
+
+ const halves = paths.seam.split(points.bottomOut)
+ paths.upperOutseam = halves[0]
+ const halves2 = halves[1].split(points.bottomIn)
+ paths.upperInseam = halves2[1]
+
+ paths.seam = paths.upperOutseam.join(paths.bottom).join(paths.upperInseam)
+ } else {
+ // define the same three parts of the path as when length reduction is enabled, then combine
+
+ // first define the points (also used for paperless)
+ points.bottom = points.floor
+ points.bottomIn = points.floorIn
+ points.bottomOut = points.floorOut
+
+ paths.bottom = new Path().move(points.bottomOut).line(points.bottomIn)
+
+ // note: upperInseam contains waist and cross seam as well
+ paths.upperInseam = drawInseam()
+ .curve(points.crotchSeamCurveCp1, points.crotchSeamCurveCp2, points.crotchSeamCurveStart)
+ .line(points.styleWaistInLily)
+ .line(points.styleWaistOutLily)
+ paths.upperOutseam = drawOutseam()
+ paths.bottom.hide()
+ paths.upperInseam.hide()
+ paths.upperOutseam.hide()
+ }
+
+ if (complete) {
+ points.grainlineTop.y = points.styleWaistInLily.y
+ points.grainlineBottom.y = points.bottom.y
+ macro('grainline', {
+ from: points.grainlineTop,
+ to: points.grainlineBottom,
+ })
+ points.logoAnchor = new Point(points.crotchSeamCurveStart.x / 2, points.fork.y)
+ snippets.logo = new Snippet('logo', points.logoAnchor)
+ points.titleAnchor = points.logoAnchor.shift(-90, 60)
+ macro('title', {
+ nr: 2,
+ title: 'front',
+ at: points.titleAnchor,
+ })
+
+ //notches
+ if (options.fitGuides) {
+ points.waistMid = points.waistOut.shiftFractionTowards(points.waistIn, 0.5)
+ points.seatMid = points.waistMid
+ .shiftTowards(points.waistOut, measurements.waistToSeat)
+ .rotate(90, points.waistMid)
+ points.seatInTarget = points.seatOut.shiftOutwards(points.seatMid, measurements.seat / 4)
+ points.seatOutTarget = points.seatMid.shiftTowards(points.seatOut, measurements.seat / 4)
+ points.hipsInTarget = points.waistIn
+ .shiftTowards(points.waistOut, measurements.waistToHips)
+ .rotate(90, points.waistIn)
+ points.hipsOutTarget = points.waistOut
+ .shiftTowards(points.waistIn, measurements.waistToHips)
+ .rotate(-90, points.waistOut)
+ points.hipsIn = utils.beamsIntersect(
+ points.hipsOutTarget,
+ points.hipsInTarget,
+ points.waistIn,
+ points.crotchSeamCurveStart
+ )
+ // intersection between the vertical line from waistMid to seatMid and a line parallel to waistIn-waistOut that goes through crotchSeamCurveStart
+ points.crotchSeamCurveStartMid = utils.beamsIntersect(
+ points.crotchSeamCurveStart,
+ points.crotchSeamCurveStart.shift(points.waistIn.angle(points.waistOut), 1),
+ points.waistMid,
+ points.seatMid
+ )
+ // check whether intersection occurs above or below crotch seam curve start
+ points.seatInTemp = utils.beamsIntersect(
+ points.seatMid,
+ points.seatInTarget,
+ points.crotchSeamCurveStart,
+ points.waistIn
+ ) // NOTE: guaranteed to return a Point since the lines cannot be parallel
+ if (points.seatInTemp.y <= points.crotchSeamCurveStartMid.y) {
+ // intersection is above the crotch seam curve start, so on the line segment
+ points.seatIn = points.seatInTemp.clone()
+ } else if (points.seatInTemp.y > points.fork.y) {
+ // seat appears to be below crotch
+ log.warn('seat estimated to be below crotch; this is probably not accurate')
+ points.seatIn = points.fork.clone()
+ } else {
+ points.seatIn = utils.beamIntersectsCurve(
+ points.seatMid,
+ points.seatInTarget,
+ points.crotchSeamCurveStart,
+ points.crotchSeamCurveCp2,
+ points.crotchSeamCurveCp1,
+ points.fork
+ )
+ }
+ if (points.waistOut.x < points.seatOut.x) {
+ //log.info('waist to the left of seat')
+ points.hipsOut = utils.lineIntersectsCurve(
+ points.hipsIn,
+ points.hipsIn.rotate(180, points.hipsOutTarget),
+ points.waistOut,
+ points.seatOut,
+ points.kneeOutCp1,
+ points.kneeOut
+ )
+ points.seatOutNotch = utils.lineIntersectsCurve(
+ points.seatMid,
+ points.seatOutTarget,
+ points.waistOut,
+ points.seatOut,
+ points.kneeOutCp1,
+ points.kneeOut
+ )
+ } else {
+ //log.info('waist to the right of seat')
+ points.hipsOut = utils.lineIntersectsCurve(
+ points.hipsIn,
+ points.hipsIn.rotate(180, points.hipsOutTarget),
+ points.waistOut,
+ points.waistOut,
+ points.seatOutCp1,
+ points.seatOut
+ )
+ points.seatOutNotch = points.seatOut
+ }
+ points.kneeOutNotch = points.kneeOut
+ points.kneeInNotch = points.kneeIn
+ macro('sprinkle', {
+ snippet: 'notch',
+ on: ['crotchSeamCurveStart', 'seatIn', 'seatOutNotch'],
+ })
+ if (extendBeyondKnee) {
+ macro('sprinkle', {
+ snippet: 'notch',
+ on: ['kneeInNotch', 'kneeOutNotch'],
+ })
+ }
+ paths.seatline = new Path()
+ .move(points.seatOutNotch)
+ .line(points.seatIn)
+ .addClass('fabric help')
+ .addText('Seat Line', 'center')
+ if (
+ measurements.waistToHips * (1 - options.waistHeight) + absoluteOptions.waistbandWidth <
+ measurements.waistToHips
+ ) {
+ macro('sprinkle', {
+ snippet: 'notch',
+ on: ['hipsIn', 'hipsOut'],
+ })
+ paths.hipline = new Path()
+ .move(points.hipsOut)
+ .line(points.hipsIn)
+ .addClass('fabric help')
+ .addText('Hip Line', 'center')
+ }
+ }
+
+ if (sa) {
+ paths.saBase = paths.upperInseam.join(paths.upperOutseam).hide()
+ paths.hemBase = paths.bottom.hide()
+ paths.sa = paths.hemBase
+ .offset(sa * 3)
+ .join(paths.saBase.offset(sa))
+ .close()
+ .addClass('fabric sa')
+ }
+
+ // Delete Titan's old hint path (which could start above the top
+ // of the garment)
+ // delete paths.hint
+
+ if (paperless) {
+ // Help construct crotch seam
+ paths.hint = new Path()
+ .move(points.crotchSeamCurveStart)
+ .line(points.crotchSeamCurveMax)
+ .line(points.fork)
+ .addClass('note lashed')
+ macro('hd', {
+ id: 'wHemLeftToPleat',
+ from: points.bottomOut,
+ to: points.bottom,
+ y: points.bottomIn.y - 15,
+ })
+ macro('hd', {
+ id: 'wHemRightToPleat',
+ from: points.bottom,
+ to: points.bottomIn,
+ y: points.bottomIn.y - 15,
+ })
+ macro('hd', {
+ id: 'wHem',
+ from: points.bottomOut,
+ to: points.bottomIn,
+ y: points.bottomIn.y - 30,
+ })
+ macro('vd', {
+ id: 'hHemToFork',
+ from: points.bottomOut,
+ to: points.fork,
+ x: points.fork.x + sa + 15,
+ })
+ macro('vd', {
+ id: 'hForkToCfWaist',
+ from: points.fork,
+ to: points.styleWaistInLily,
+ x: points.fork.x + sa + 15,
+ })
+ macro('vd', {
+ id: 'hHemToSideWaist',
+ from: points.bottomIn,
+ to: points.styleWaistOutLily,
+ x:
+ (points.seatOut.x < points.styleWaistOutLily.x
+ ? points.seatOut.x
+ : points.styleWaistOutLily.x) -
+ sa -
+ 15,
+ })
+ macro('vd', {
+ id: 'hStartCrotchCurveToCfWaist',
+ from: points.crotchSeamCurveStart,
+ to: points.styleWaistInLily,
+ x: points.crotchSeamCurveStart.x + sa + 15,
+ })
+ macro('hd', {
+ id: 'wSideWaistToPleat',
+ from: points.seatOut,
+ to: points.grainlineTop,
+ y: points.styleWaistInLily.y - sa - 15,
+ })
+ if (points.styleWaistOutLily.x < points.seatOut.x) {
+ macro('hd', {
+ id: 'wSideWaistToPleatAlt',
+ from: points.styleWaistOutLily,
+ to: points.grainlineTop,
+ y: points.styleWaistInLily.y - sa - 30,
+ })
+ }
+ macro('hd', {
+ id: 'wPleatToCfWaist',
+ from: points.grainlineTop,
+ to: points.styleWaistInLily,
+ y: points.styleWaistInLily.y - sa - 15,
+ })
+ macro('hd', {
+ id: 'wPleatToStartCrotchCurve',
+ from: points.grainlineTop,
+ to: points.crotchSeamCurveStart,
+ y: points.styleWaistInLily.y - sa - 30,
+ })
+ macro('hd', {
+ id: 'wPleatToCrotchProjection',
+ from: points.grainlineTop,
+ to: points.crotchSeamCurveMax,
+ y: points.styleWaistInLily.y - sa - 45,
+ })
+ macro('hd', {
+ id: 'wPleatToFork',
+ from: points.grainlineTop,
+ to: points.fork,
+ y: points.styleWaistInLily.y - sa - 60,
+ })
+ }
+ }
+
+ return part
+}
+
+export const front = {
+ name: 'lily.front',
+ from: titanFront,
+ after: back,
+ hide: 'HIDE_TREE',
+ draft: draftLilyFront,
+}
diff --git a/designs/lily/src/index.mjs b/designs/lily/src/index.mjs
new file mode 100644
index 00000000000..1a831522031
--- /dev/null
+++ b/designs/lily/src/index.mjs
@@ -0,0 +1,16 @@
+import { Design } from '@freesewing/core'
+import { i18n } from '../i18n/index.mjs'
+import { data } from '../data.mjs'
+// Parts
+import { front } from './front.mjs'
+import { back } from './back.mjs'
+import { waistband } from './waistband.mjs'
+
+// Create new design
+const Lily = new Design({
+ data,
+ parts: [front, back, waistband],
+})
+
+// Named exports
+export { front, back, waistband, i18n, Lily }
diff --git a/designs/lily/src/waistband.mjs b/designs/lily/src/waistband.mjs
new file mode 100644
index 00000000000..b6deb052d44
--- /dev/null
+++ b/designs/lily/src/waistband.mjs
@@ -0,0 +1,18 @@
+import { back } from './back.mjs'
+import { front } from './front.mjs'
+import { waistband as pacoWaistband } from '@freesewing/paco'
+
+export const waistband = {
+ name: 'lily.waistband',
+ after: [back, front],
+ hide: 'HIDE_TREE',
+ draft: (sh) => {
+ const { snippets, part } = sh
+ //draft
+ pacoWaistband.draft(sh)
+ //delete eyelets
+ for (let s in snippets) delete snippets[s]
+
+ return part
+ },
+}
diff --git a/designs/lily/tests/shared.test.mjs b/designs/lily/tests/shared.test.mjs
new file mode 100644
index 00000000000..e587224479e
--- /dev/null
+++ b/designs/lily/tests/shared.test.mjs
@@ -0,0 +1,20 @@
+// This file is auto-generated | Any changes you make will be overwritten.
+import { Lily, 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(Lily)
+
+// Test translation
+testPatternI18n(Lily, i18n)
+
+// Test drafting - Change the second parameter to `true` to log errors
+testPatternDrafting(Lily, false)
+
+// Test sampling - Change the second parameter to `true` to log errors
+testPatternSampling(Lily, false)
diff --git a/designs/lucy/README.md b/designs/lucy/README.md
index 5d66293487c..c304952cfb9 100644
--- a/designs/lucy/README.md
+++ b/designs/lucy/README.md
@@ -21,7 +21,7 @@
{
+ draft: ({ sa, Point, points, Path, paths, Snippet, snippets, options, macro, store, part }) => {
if (options.dartPosition != 'shoulder') {
paths.insideSeam = paths.seam.clone().unhide()
} else {
@@ -32,6 +32,8 @@ export const backInside = {
snippets.dartTip = new Snippet('notch', points.dartTip)
+ store.cutlist.removeCut()
+ store.cutlist.addCut({ onFold: false })
macro('title', {
at: points.titleAnchor,
nr: 3,
diff --git a/designs/noble/src/backoutside.mjs b/designs/noble/src/backoutside.mjs
index e581a9070cb..e10db7a7757 100644
--- a/designs/noble/src/backoutside.mjs
+++ b/designs/noble/src/backoutside.mjs
@@ -3,7 +3,7 @@ import { backPoints } from './backpoints.mjs'
export const backOutside = {
name: 'noble.backOutside',
from: backPoints,
- draft: ({ sa, Point, points, Path, paths, Snippet, snippets, options, macro, part }) => {
+ draft: ({ sa, Point, points, Path, paths, Snippet, snippets, options, macro, store, part }) => {
if (options.dartPosition != 'shoulder') {
return part
}
@@ -41,6 +41,8 @@ export const backOutside = {
snippets.dartTip = new Snippet('notch', points.dartTip)
+ store.cutlist.removeCut()
+ store.cutlist.addCut({ onFold: false })
points.titleAnchor = points.dartBottomRight
.shiftFractionTowards(points.waistSide, 0.1)
.shiftFractionTowards(points.shoulder, 0.3)
diff --git a/designs/noble/src/frontoutside.mjs b/designs/noble/src/frontoutside.mjs
index be39115b46d..118bc4b3b25 100644
--- a/designs/noble/src/frontoutside.mjs
+++ b/designs/noble/src/frontoutside.mjs
@@ -17,15 +17,6 @@ export const frontOutside = {
macro('rmcutonfold')
if (options.dartPosition == 'shoulder') {
- paths.princessSeam = new Path()
- .move(points.shoulderDartOutside)
- .curve(
- points.shoulderDartTipCpDownOutside,
- points.waistUpDartRightCpUp,
- points.waistUpDartRight
- )
- .curve(points.waistUpDartRightCpDown, points.waistCpUp, points.waistDartRight)
- .hide()
paths.armhole = new Path()
.move(points.armhole)
.curve(points.armholeCp2, points.armholePitchCp1, points.armholePitch)
diff --git a/designs/noble/src/frontpoints.mjs b/designs/noble/src/frontpoints.mjs
index 5d02fdf988a..d8d36c927e4 100644
--- a/designs/noble/src/frontpoints.mjs
+++ b/designs/noble/src/frontpoints.mjs
@@ -2,7 +2,66 @@ import { frontSideDart as bellaFront } from '@freesewing/bella'
import { cbqc, hidePresets } from '@freesewing/core'
import * as options from './options.mjs'
-const createRightDartPoints = (points, Path, diff, utils) => {
+const createTopRightDartPoints = (points, Path, options) => {
+ const topPath = new Path()
+ .move(points.waistUpDartRight)
+ .curve(
+ points.waistUpDartRightCpUp,
+ points.shoulderDartTipCpDownOutside,
+ points.shoulderDartOutside
+ )
+
+ const split1 = topPath.shiftFractionAlong(0.15 + options.shoulderDartCurvature * -1)
+ const split2 = topPath.shiftFractionAlong(0.5 + options.shoulderDartCurvature * -1)
+ const split3 = topPath.shiftFractionAlong(0.9 + options.shoulderDartCurvature * -0.5)
+
+ const splitPath1 = topPath.split(split1)
+ const splitPath2 = splitPath1[1].split(split2)
+ const splitPath3 = splitPath2[1].split(split3)
+
+ const splittedPath1 = splitPath1[0].clone()
+ const splittedPath2 = splitPath2[0].clone()
+ const splittedPath3 = splitPath3[0].clone()
+ const splittedPath4 = splitPath3[1].clone()
+
+ points.shoulderDartPart1from = splittedPath1.ops[0].to.copy()
+ points.shoulderDartPart1cp1 = splittedPath1.ops[1].cp1.copy()
+ points.shoulderDartPart1cp2 = splittedPath1.ops[1].cp2.copy()
+ points.shoulderDartPart1to = splittedPath1.ops[1].to.copy()
+ points.shoulderDartPart2from = splittedPath2.ops[0].to.copy()
+ points.shoulderDartPart2cp1 = splittedPath2.ops[1].cp1.copy()
+ points.shoulderDartPart2cp2 = splittedPath2.ops[1].cp2.copy()
+ points.shoulderDartPart2to = splittedPath2.ops[1].to.copy()
+ points.shoulderDartPart3from = splittedPath3.ops[0].to.copy()
+ points.shoulderDartPart3cp1 = splittedPath3.ops[1].cp1.copy()
+ points.shoulderDartPart3cp2 = splittedPath3.ops[1].cp2.copy()
+ points.shoulderDartPart3to = splittedPath3.ops[1].to.copy()
+ points.shoulderDartPart4from = splittedPath4.ops[0].to.copy()
+ points.shoulderDartPart4cp1 = splittedPath4.ops[1].cp1.copy()
+ points.shoulderDartPart4cp2 = splittedPath4.ops[1].cp2.copy()
+ points.shoulderDartPart4to = splittedPath4.ops[1].to.copy()
+
+ const sp2cp2a = points.shoulderDartPart2to.angle(points.shoulderDartPart2cp2)
+ const sp2cp2d = points.shoulderDartPart2to.dist(points.shoulderDartPart2cp2)
+ const sp3cp1a = points.shoulderDartPart3from.angle(points.shoulderDartPart3cp1)
+ const sp3cp1d = points.shoulderDartPart3from.dist(points.shoulderDartPart3cp1)
+ points.shoulderDartPart2to = points.shoulderDartPart2to.rotate(
+ options.shoulderDartCurvature * 100,
+ points.shoulderDartPart2from
+ )
+ points.shoulderDartPart3from = points.shoulderDartPart2to.copy()
+ points.shoulderDartPart2cp2 = points.shoulderDartPart2to.shift(sp2cp2a, sp2cp2d)
+ points.shoulderDartPart3cp1 = points.shoulderDartPart3from.shift(sp3cp1a, sp3cp1d)
+
+ return new Path()
+ .move(points.shoulderDartPart1from)
+ .curve(points.shoulderDartPart1cp1, points.shoulderDartPart1cp2, points.shoulderDartPart1to)
+ .curve(points.shoulderDartPart2cp1, points.shoulderDartPart2cp2, points.shoulderDartPart2to)
+ .curve(points.shoulderDartPart3cp1, points.shoulderDartPart3cp2, points.shoulderDartPart3to)
+ .curve(points.shoulderDartPart4cp1, points.shoulderDartPart4cp2, points.shoulderDartPart4to)
+}
+
+const createRightDartPoints = (points, Path, paths, diff, utils, options) => {
const radius = points.waistDartRight.dist(points.sideHemInitial)
points.waistDartRight = points.waistDartRight.rotate(
@@ -33,15 +92,13 @@ const createRightDartPoints = (points, Path, diff, utils) => {
-0.5 * cbqc * points.armholeDartInside.dist(points.armholeDartTip)
)
- return new Path()
+ paths.princessSeam = new Path()
.move(points.waistDartRight)
.curve(points.waistCpUp, points.waistUpDartRightCpDown, points.waistUpDartRight)
- .curve(
- points.waistUpDartRightCpUp,
- points.shoulderDartTipCpDownOutside,
- points.shoulderDartOutside
- )
- .length()
+ .join(createTopRightDartPoints(points, Path, options))
+ .reverse()
+ .hide()
+ return paths.princessSeam.length()
}
const createArmholeDartPoints = (points, paths, Path, direction) => {
@@ -121,7 +178,6 @@ export const frontPoints = {
points.bust,
options.upperDartLength
)
-
points.armholeCircleInsideCp1 = points.armholeDartInside.shift(
armholeDartAngle,
cbqc * points.armholeDartInside.dist(points.armholeDartTip)
@@ -290,15 +346,15 @@ export const frontPoints = {
-0.5 * cbqc * points.armholeDartOutside.dist(points.armholeDartTip)
)
points.shoulderDartTipCpDownOutside = points.shoulderDartTipCpDownOutside
- .rotate(-2.5, points.shoulderDartOutside)
+ .rotate(2.5, points.shoulderDartOutside)
.shiftFractionTowards(points.shoulderDartOutside, 0.2)
let iteration = 1
let diff = 0
- let rightDartLength = createRightDartPoints(points, Path, diff, utils)
+ let rightDartLength = createRightDartPoints(points, Path, paths, diff, utils, options)
do {
- rightDartLength = createRightDartPoints(points, Path, diff, utils)
+ rightDartLength = createRightDartPoints(points, Path, paths, diff, utils, options)
diff = shoulderInsideSeam.length() - rightDartLength
iteration++
diff --git a/designs/noble/src/options.mjs b/designs/noble/src/options.mjs
index 012fea26ae8..55649ccf375 100644
--- a/designs/noble/src/options.mjs
+++ b/designs/noble/src/options.mjs
@@ -10,15 +10,24 @@ export const backHemSlope = { deg: 2.5, min: 0, max: 5, menu: 'advanced' }
export const upperDartLength = { pct: 90, min: 80, max: 95, menu: 'darts' }
export const dartPosition = { dflt: 'shoulder', list: ['shoulder', 'armhole'], menu: 'darts' }
export const waistdartposition = { pct: 0, min: -100, max: 100, menu: 'darts' }
+export const shoulderDartCurvature = {
+ pct: 0,
+ min: -5,
+ max: 2.5,
+ // eslint-disable-next-line no-unused-vars
+ menu: (settings, mergedOptions) => (mergedOptions.dartPosition === 'shoulder' ? 'darts' : false),
+}
export const shoulderDartPosition = {
pct: 50,
min: 10,
max: 90,
+ // eslint-disable-next-line no-unused-vars
menu: (settings, mergedOptions) => (mergedOptions.dartPosition === 'shoulder' ? 'darts' : false),
}
export const armholeDartPosition = {
pct: 50,
min: 10,
max: 90,
+ // eslint-disable-next-line no-unused-vars
menu: (settings, mergedOptions) => (mergedOptions.dartPosition === 'armhole' ? 'darts' : false),
}
diff --git a/designs/octoplushy/README.md b/designs/octoplushy/README.md
index 0ab3acd2cf0..1b520d3614b 100644
--- a/designs/octoplushy/README.md
+++ b/designs/octoplushy/README.md
@@ -21,7 +21,7 @@
points.bicepsRight.x * 2) width = points.bicepsRight.x * 2
diff --git a/designs/tiberius/README.md b/designs/tiberius/README.md
index bca5eaa09fd..7d089238269 100644
--- a/designs/tiberius/README.md
+++ b/designs/tiberius/README.md
@@ -21,7 +21,7 @@
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/umbra/README.md b/designs/umbra/README.md
new file mode 100644
index 00000000000..82bd51f47a5
--- /dev/null
+++ b/designs/umbra/README.md
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
+
+
+
+# @freesewing/umbra
+
+A FreeSewing pattern for a basic, highly-customizable underwear pattern
+
+
+
+# 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/umbra
+
+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/# 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/umbra/build.mjs b/designs/umbra/build.mjs
new file mode 100644
index 00000000000..99ace216bc8
--- /dev/null
+++ b/designs/umbra/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/umbra/data.mjs b/designs/umbra/data.mjs
new file mode 100644
index 00000000000..e0312d58946
--- /dev/null
+++ b/designs/umbra/data.mjs
@@ -0,0 +1,4 @@
+// This file is auto-generated | All changes you make will be overwritten.
+export const name = '@freesewing/umbra'
+export const version = '3.2.0'
+export const data = { name, version }
diff --git a/designs/umbra/i18n/de.json b/designs/umbra/i18n/de.json
new file mode 100644
index 00000000000..264e56d9460
--- /dev/null
+++ b/designs/umbra/i18n/de.json
@@ -0,0 +1,56 @@
+{
+ "t": "Umbra, die Unterwäsche",
+ "d": "Umbra ist ein elementares, stark anpassbares Schnittmuster für Unterwäsche.",
+ "p": {
+ "back": "Rückseite",
+ "elastic": "Elastic",
+ "front": "Vorderseite",
+ "gusset": "Zwickel"
+ },
+ "s": {
+ "cutTwoPiecesOfElasticToFinishTheLegOpenings": "Schneide zwei Stücke Gummiband um die Beinöffnungen zu versäubern",
+ "cutOnePieceOfElasticToFinishTheWaistBand": "Schneide ein Stück Gummiband um das Taillenband zu versäubern"
+ },
+ "o": {
+ "fabricStretch": {
+ "t": "Stoffdehnbarkeit",
+ "d": "Passe dies für mehr oder weniger dehnbaren Stoff an"
+ },
+ "gussetWidth": {
+ "t": "Zwickelbreite",
+ "d": "Steuert die Breite des Zwickels"
+ },
+ "gussetLength": {
+ "t": "Zwickellänge",
+ "d": "Steuert die Länge des Zwickels"
+ },
+ "elasticStretch": {
+ "t": "Dehnbarkeit des Gummis",
+ "d": "Passe dies für mehr oder weniger dehnbaren Gummi an"
+ },
+ "rise": {
+ "t": "Sitz",
+ "d": "Steuert die Höhe der Taille"
+ },
+ "legOpening": {
+ "t": "Beinöffnung",
+ "d": "Legt fest, wie hoch das Bein ausgeschnitten wird"
+ },
+ "frontDip": {
+ "t": "Absenkung der vorderen Taille",
+ "d": "Steuert, wie stark die vordere Taille gekümmt ist (legt dadurch mehr oder weniger Haut frei)"
+ },
+ "backDip": {
+ "t": "Absenkung hintere Taille",
+ "d": "Steuert, wie stark die hintere Taille gekümmt ist (legt dadurch mehr oder weniger Haut frei)"
+ },
+ "taperToGusset": {
+ "t": "Vordere Freilegung",
+ "d": "Steuert die Menge an freigelegter Haut auf der vorderen Seite"
+ },
+ "backExposure": {
+ "t": "Hintere Freilegung",
+ "d": "Steuert die Menge an freigelegter Haut auf der hinteren Seite"
+ }
+ }
+}
diff --git a/designs/umbra/i18n/en.json b/designs/umbra/i18n/en.json
new file mode 100644
index 00000000000..33cf22f785c
--- /dev/null
+++ b/designs/umbra/i18n/en.json
@@ -0,0 +1,123 @@
+{
+ "t": "Umbra undies",
+ "d": "Umbra is a basic, highly-customizable underwear pattern.",
+ "p": {
+ "back": "Back",
+ "elastic": "Elastic",
+ "front": "Front",
+ "base": "Base"
+ },
+ "s": {
+ "legElasticLength.t": "You need 2x {{{ length }}} elastic to finish the legs (optional)",
+ "legElasticLength.d": "If you want to add elastic to your legs, you need two times {{{ length }}}.",
+ "legMeasure": "Leg elastic: 2x ",
+ "waistbandElasticLength.t": "You need 1x {{{ length }}} elastic to finish the waistband",
+ "waistbandElasticLength.d": "You need {{{ length }}} of elastic to finish the waistband opening.",
+ "waistbandMeasure": "Waistband elastic: ",
+ "minStretch.t": "You need fabric with a minimum stretch of {{ pct }}",
+ "minStretch.d": "Your waistband and fabric needs a minimum stretch of {{ pct }} so that you can comfortably fit through the waistband opening.",
+ "flipBackYes.t": "Flip upright",
+ "flipBackYes.d": "Flips the back part, which is constructed upside down, to an upright orientation",
+ "flipBackNo.t": "Keep upside down",
+ "flipBackNo.d": "Keeps the back part in its original orientation, which might help in the pattern inspector view",
+ "pockets.none.t": "No Pockets",
+ "pockets.none.d": "Create the design without any pockets (default)",
+ "pockets.inside.t": "Inside Pockets",
+ "pockets.inside.d": "Create two secret pockets on the insides and a center front pouch",
+ "pockets.zipper.t": "Front pockets with zippers",
+ "pockets.zipper.d": "Create two front pockets with zippers",
+ "foldLining": "Fold lining",
+ "pocketSeam": "Pocket seam",
+ "zipper": "Zipper"
+ },
+ "o": {
+ "bulge": {
+ "t": "Bulge",
+ "d": "Increase the bugle angle to create more room in the front pouch. Doesn't kick in below 2 degrees."
+ },
+ "bulgeFullness": {
+ "t": "Bulge fullness",
+ "d": "Determines the roundness of the bulge. Doesn't have an effect if the bulge is disabled."
+ },
+ "splitPosition": {
+ "t": "Crotch seam",
+ "d": "Determines the position of the crotch seam"
+ },
+ "gussetPosition": {
+ "t": "Gusset position",
+ "d": "Shift the gusset (crotch position with the smallest width) forwards or backwards. The default position equals the cross seam front measurement."
+ },
+ "gussetWidth": {
+ "t": "Gusset width",
+ "d": "Controls the minimum width in the crotch area"
+ },
+ "xStretch": {
+ "t": "Horizontal fabric stretch",
+ "d": "Adjust this for more or less stretchy fabric in the horizontal direction"
+ },
+ "yStretch": {
+ "t": "Vertical fabric stretch",
+ "d": "Adjust this for more or less stretchy fabric in the vertical direction"
+ },
+ "elasticStretch": {
+ "t": "Elastic stretch",
+ "d": "Adjust how much the elastics are stretched relative to the fabric"
+ },
+ "rise": {
+ "t": "Rise",
+ "d": "Controls the height of the waist. A value of 100% puts the waistband onto the measured hip line."
+ },
+ "legRise": {
+ "t": "Leg rise",
+ "d": "Controls how high the leg is cut out"
+ },
+ "frontDip": {
+ "t": "Front waist dip",
+ "d": "Controls how much the front waist curves (revealing more or less skin)"
+ },
+ "frontDipShape": {
+ "t": "Front waist dip shape",
+ "d": "Controls the shape of the front waist dip. Doesn't have much effect if the front waist dip is zero."
+ },
+ "backDip": {
+ "t": "Back waist dip",
+ "d": "Controls how much the back waist curves (revealing more or less skin)"
+ },
+ "backDipShape": {
+ "t": "Back waist dip shape",
+ "d": "Controls the shape of the back waist dip. Doesn't have much effect if the back waist dip is zero."
+ },
+ "frontExposure": {
+ "t": "Front exposure",
+ "d": "Controls the amount of exposed skin on the front"
+ },
+ "frontReduction": {
+ "t": "Front narrowing",
+ "d": "Controls by how much the front part is slimmer than the back part"
+ },
+ "pockets": {
+ "t": "Pockets",
+ "d": "Choose if you want pockets"
+ },
+ "pocketHeight": {
+ "t": "Pocket height",
+ "d": "Controls the position of the pocket hem or the zippers. Increasing this option results in shorter pockets. Only has an effect with pockets enabled."
+ },
+ "pocketGap": {
+ "t": "Pocket gap",
+ "d": "Controls how much space is left in the front between both pockets. Only has an effect with pockets enabled."
+ },
+ "backExposure": {
+ "t": "Back exposure",
+ "d": "Controls the amount of exposed skin on the back"
+ },
+ "minFabricWidth":{
+ "t": "Minimum fabric width",
+ "d": "Controls the minimum width of the thong strip and side band. Does not have an effect if the back exposure and the leg rise is low."
+ },
+ "flipBack": {
+ "t": "Flip back",
+ "d": "Determines if the back part should be rendered upside down"
+ }
+ }
+}
diff --git a/designs/umbra/i18n/es.json b/designs/umbra/i18n/es.json
new file mode 100644
index 00000000000..16b35cda164
--- /dev/null
+++ b/designs/umbra/i18n/es.json
@@ -0,0 +1,56 @@
+{
+ "t": "Umbra, braguitas",
+ "d": "Umbra es un patrón básico de braguitas altamente personalizable.",
+ "p": {
+ "back": "Atrás",
+ "elastic": "Elastic",
+ "front": "Frente",
+ "gusset": "Gusset"
+ },
+ "s": {
+ "cutTwoPiecesOfElasticToFinishTheLegOpenings": "Corta dos trozos de elástico para acabar la abertura de las perneras",
+ "cutOnePieceOfElasticToFinishTheWaistBand": "Corta un trozo de elástico para acabar la cintura"
+ },
+ "o": {
+ "fabricStretch": {
+ "t": "estiramiento de tela",
+ "d": "Ajustar esto para más o menos tela estirada"
+ },
+ "gussetWidth": {
+ "t": "Gusset width",
+ "d": "Controla el ancho del set de ráfaga"
+ },
+ "gussetLength": {
+ "t": "Longitud del Gusset",
+ "d": "Controla la longitud del set de ráfaga"
+ },
+ "elasticStretch": {
+ "t": "Estiramiento elástico",
+ "d": "Ajustar esto para elástico más o menos estirado"
+ },
+ "rise": {
+ "t": "Elevación de la cintura",
+ "d": "Controla la altura de la cintura"
+ },
+ "legOpening": {
+ "t": "Apertura de la pierna",
+ "d": "Controla hasta qué punto se corta la pierna"
+ },
+ "frontDip": {
+ "t": "Buceo de cintura frontal",
+ "d": "Controla cuánto son las curvas de la cintura frontal (revelando más o menos la piel)"
+ },
+ "backDip": {
+ "t": "Buceo de cintura trasera",
+ "d": "Controla cuánto son las curvas de la cintura trasera (revelando más o menos la piel)"
+ },
+ "taperToGusset": {
+ "t": "Exposición frontal",
+ "d": "Controla la cantidad de piel expuesta en la parte frontal"
+ },
+ "backExposure": {
+ "t": "Exposición trasera",
+ "d": "Controla la cantidad de piel expuesta en la espalda"
+ }
+ }
+}
diff --git a/designs/umbra/i18n/fr.json b/designs/umbra/i18n/fr.json
new file mode 100644
index 00000000000..dc5a3b5eb35
--- /dev/null
+++ b/designs/umbra/i18n/fr.json
@@ -0,0 +1,56 @@
+{
+ "t": "Unités d'Umbra",
+ "d": "Umbra est un motif basique et hautement personnalisable.",
+ "p": {
+ "back": "Retour",
+ "elastic": "Elastic",
+ "front": "Avant",
+ "gusset": "Soufflet"
+ },
+ "s": {
+ "cutTwoPiecesOfElasticToFinishTheLegOpenings": "Couper deux élastiques pour finir les ouvertures des jambes",
+ "cutOnePieceOfElasticToFinishTheWaistBand": "Couper une pièce d'élastique pour finir la bande de taille"
+ },
+ "o": {
+ "fabricStretch": {
+ "t": "Étendue en tissu",
+ "d": "Ajuster ceci pour des tissus plus ou moins extensifs"
+ },
+ "gussetWidth": {
+ "t": "Gusset width",
+ "d": "Contrôle la largeur du gusset"
+ },
+ "gussetLength": {
+ "t": "Longueur du Gusset",
+ "d": "Contrôle la longueur du gusset"
+ },
+ "elasticStretch": {
+ "t": "Etendue élastique",
+ "d": "Ajuster ceci pour un élastique plus ou moins extensif"
+ },
+ "rise": {
+ "t": "Élévation de ceinture",
+ "d": "Contrôle la hauteur de la taille"
+ },
+ "legOpening": {
+ "t": "Ouverture des jambes",
+ "d": "Contrôle la hauteur de la jambe découpée"
+ },
+ "frontDip": {
+ "t": "tremper la taille de la taille avant",
+ "d": "Contrôle la quantité de courbes de la taille avant (révélant plus ou moins la peau)"
+ },
+ "backDip": {
+ "t": "trempette à taille arrière",
+ "d": "Contrôle la quantité de courbes de la taille arrière (révélant plus ou moins la peau)"
+ },
+ "taperToGusset": {
+ "t": "Exposition frontale",
+ "d": "Contrôle la quantité de peau exposée à l'avant"
+ },
+ "backExposure": {
+ "t": "Exposition au dos",
+ "d": "Contrôle la quantité de peau exposée au dos"
+ }
+ }
+}
diff --git a/designs/umbra/i18n/index.mjs b/designs/umbra/i18n/index.mjs
new file mode 100644
index 00000000000..36aac928b67
--- /dev/null
+++ b/designs/umbra/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/umbra/i18n/nl.json b/designs/umbra/i18n/nl.json
new file mode 100644
index 00000000000..bf706ea3331
--- /dev/null
+++ b/designs/umbra/i18n/nl.json
@@ -0,0 +1,56 @@
+{
+ "t": "Umbra undies",
+ "d": "Umbra is een fundamenteel, zeer aanpasbaar ondergoed patroon.",
+ "p": {
+ "back": "Achterzijde",
+ "elastic": "Elastic",
+ "front": "Voorzijde",
+ "gusset": "Gusset"
+ },
+ "s": {
+ "cutTwoPiecesOfElasticToFinishTheLegOpenings": "Cut two pieces of elastic to finish the leg openings",
+ "cutOnePieceOfElasticToFinishTheWaistBand": "Cut one piece of elastic to finish the waist band"
+ },
+ "o": {
+ "fabricStretch": {
+ "t": "Stof stretch",
+ "d": "Pas dit aan voor meer of minder elastische stoffen"
+ },
+ "gussetWidth": {
+ "t": "Gusset width",
+ "d": "Bepaalt de breedte van de gusset"
+ },
+ "gussetLength": {
+ "t": "Gusset lengte",
+ "d": "Bepaalt de lengte van de gusset"
+ },
+ "elasticStretch": {
+ "t": "Elastische stretch",
+ "d": "Pas dit aan voor meer of minder elastische elastiek"
+ },
+ "rise": {
+ "t": "Hoogte",
+ "d": "Bepaalt de hoogte van de taille"
+ },
+ "legOpening": {
+ "t": "Been opening",
+ "d": "Bepaalt hoe hoog de broekspijp wordt uitgeknipt"
+ },
+ "frontDip": {
+ "t": "Voorste taille dip",
+ "d": "Bepaalt hoeveel de taillecurven vooraan tonen (min of meer skin)"
+ },
+ "backDip": {
+ "t": "Achterste dip taille",
+ "d": "Bepaalt hoeveel de omgekeerde golfcurves (min of meer skin onthullen)"
+ },
+ "taperToGusset": {
+ "t": "Blootstelling voorzijde",
+ "d": "Bepaalt de hoeveelheid blootgestelde huid aan de voorkant"
+ },
+ "backExposure": {
+ "t": "Blootstelling rug",
+ "d": "Bepaalt de hoeveelheid gelekte huid aan de achterkant"
+ }
+ }
+}
diff --git a/designs/umbra/i18n/uk.json b/designs/umbra/i18n/uk.json
new file mode 100644
index 00000000000..db8921f3faf
--- /dev/null
+++ b/designs/umbra/i18n/uk.json
@@ -0,0 +1,56 @@
+{
+ "t": "Umbra undies",
+ "d": "Umbra is a basic, highly-customizable underwear pattern.",
+ "p": {
+ "back": "Back",
+ "elastic": "Elastic",
+ "front": "Front",
+ "gusset": "Gusset"
+ },
+ "s": {
+ "cutTwoPiecesOfElasticToFinishTheLegOpenings": "Cut two pieces of elastic to finish the leg openings",
+ "cutOnePieceOfElasticToFinishTheWaistBand": "Cut one piece of elastic to finish the waist band"
+ },
+ "o": {
+ "fabricStretch": {
+ "t": "Fabric stretch",
+ "d": "Adjust this for more or less stretchy fabrics"
+ },
+ "gussetWidth": {
+ "t": "Gusset width",
+ "d": "Controls the width of the gusset"
+ },
+ "gussetLength": {
+ "t": "Gusset length",
+ "d": "Controls the length of the gusset"
+ },
+ "elasticStretch": {
+ "t": "Elastic stretch",
+ "d": "Adjust this for more or less stretchy elastic"
+ },
+ "rise": {
+ "t": "Rise",
+ "d": "Controls the height of the waist"
+ },
+ "legOpening": {
+ "t": "Leg opening",
+ "d": "Controls how high the leg is cut out"
+ },
+ "frontDip": {
+ "t": "Front waist dip",
+ "d": "Controls how much the front waist curves (revealing more or less skin)"
+ },
+ "backDip": {
+ "t": "Back waist dip",
+ "d": "Controls how much the back waist curves (revealing more or less skin)"
+ },
+ "taperToGusset": {
+ "t": "Front exposure",
+ "d": "Controls the amount of exposed skin on the front"
+ },
+ "backExposure": {
+ "t": "Back exposure",
+ "d": "Controls the amount of exposed skin on the back"
+ }
+ }
+}
diff --git a/designs/umbra/package.json b/designs/umbra/package.json
new file mode 100644
index 00000000000..087c4cf56b4
--- /dev/null
+++ b/designs/umbra/package.json
@@ -0,0 +1,71 @@
+{
+ "name": "@freesewing/umbra",
+ "version": "3.2.0",
+ "description": "A FreeSewing pattern for a basic, highly-customizable underwear pattern",
+ "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/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/umbra/src/back.mjs b/designs/umbra/src/back.mjs
new file mode 100644
index 00000000000..b4a76f22707
--- /dev/null
+++ b/designs/umbra/src/back.mjs
@@ -0,0 +1,233 @@
+import { base } from './base.mjs'
+
+export const back = {
+ name: 'umbra.back',
+ from: base,
+ draft: draftUmbraBack,
+}
+
+/*
+ * This drafts the back of Umbra, or rather recycles what's needed from base
+ */
+function draftUmbraBack({
+ Point,
+ Path,
+ points,
+ paths,
+ store,
+ sa,
+ Snippet,
+ snippets,
+ options,
+ expand,
+ macro,
+ part,
+}) {
+ /*
+ * We'll use this list later
+ */
+ const toFlip = [
+ 'cfWaistbandDipCp1Back',
+ 'cfWaistbandDipCp2Back',
+ 'sideWaistbandBack',
+ 'sideLegBack',
+ 'backGussetSplit',
+ ]
+
+ /*
+ * Depending on the expand setting, we'll draw a full back
+ * or one to be cut on the fold
+ */
+ if (expand) {
+ /*
+ * Expand is on, show the entire part
+ */
+
+ if (options.flipBack) {
+ /*
+ * We need the flip these points to construct the left half
+ */
+ for (const pid of toFlip) {
+ // Flip existing points along Y-axis
+ points[pid] = points[pid].flipY()
+ }
+ // Also Y-flip these central points
+ points.cfWaistbandDipBack = points.cfWaistbandDipBack.flipY()
+ points.cfBackGusset = points.cfBackGusset.flipY()
+ }
+
+ /*
+ * Draw the path
+ */
+ if (options.flipBack) {
+ macro('mirror', {
+ mirror: [new Point(0, 0), new Point(100, 0)],
+ paths: ['back'],
+ clone: true,
+ })
+ } else {
+ paths.mirroredBack = paths.back.reverse()
+ }
+ macro('mirror', {
+ mirror: [new Point(0, 0), new Point(0, 100)],
+ paths: ['mirroredBack'],
+ clone: true,
+ })
+ paths.seam = paths.mirroredBack.join(paths.mirroredMirroredBack.reverse()).addClass('fabric')
+ paths.mirroredBack.hide()
+ paths.mirroredMirroredBack.hide()
+
+ if (sa) paths.sa = paths.seam.offset(sa * -1).addClass('fabric sa')
+
+ /*
+ * Set the cutlist info
+ */
+ store.cutlist.setCut({ cut: 1, from: 'fabric' })
+
+ /*
+ * Add grainline
+ */
+ macro('grainline', {
+ from: new Point(0, points.backGussetSplit.y),
+ to: points.cfWaistbandDipBack,
+ })
+ } else {
+ if (options.flipBack) {
+ /*
+ * Expand is off, cut on fold
+ */
+ for (const pid of toFlip) {
+ // Flip existing points along Y-axis
+ points[pid] = points[pid].flipY()
+ }
+ // Also Y-flip these central points
+ points.cfWaistbandDipBack = points.cfWaistbandDipBack.flipY()
+ points.cfBackGusset = points.cfBackGusset.flipY()
+
+ macro('mirror', {
+ mirror: [new Point(0, 0), new Point(100, 0)],
+ paths: ['back'],
+ clone: true,
+ })
+ paths.mirroredBack.hide()
+ paths.saBase = paths.mirroredBack.reverse().hide()
+ } else {
+ paths.saBase = paths.back
+ }
+
+ paths.seam = paths.saBase
+ .clone()
+ .line(points.cfWaistbandDipBack)
+ .close()
+ .unhide()
+ .addClass('fabric')
+
+ if (sa) {
+ paths.sa = new Path()
+ .move(points.cfBackGusset)
+ .join(paths.saBase.offset(sa))
+ .line(paths.saBase.end())
+ .addClass('fabric sa')
+ }
+
+ /*
+ * Set the cutlist info
+ */
+ store.cutlist.setCut({ cut: 1, from: 'fabric', onFold: true })
+
+ /*
+ * Add cut on fold indicator
+ */
+ macro('cutonfold', {
+ from: points.cfWaistbandDipBack,
+ to: points.cfBackGusset,
+ grainline: true,
+ })
+ }
+
+ /*
+ * Dimensions
+ */
+ macro('hd', {
+ id: 'wAtBottom',
+ from: points.cfBackGusset,
+ to: points.backGussetSplit,
+ y: points.cfBackGusset.y + sa + 15,
+ })
+ macro('hd', {
+ id: 'wAtLeg',
+ from: points.cfBackGusset,
+ to: points.sideLegBack,
+ y: points.cfBackGusset.y + sa + 30,
+ })
+ macro('hd', {
+ id: 'wAtTop',
+ from: points.cfWaistbandDipBack,
+ to: points.sideWaistbandBack,
+ y: points.sideWaistbandBack.y - sa - 15,
+ })
+ macro('vd', {
+ id: 'hToLeg',
+ from: points.backGussetSplit,
+ to: points.sideLegBack,
+ x: points.sideLegBack.x + sa + 15,
+ })
+ macro('vd', {
+ id: 'hToCfWaistband',
+ from: points.backGussetSplit,
+ to: points.cfWaistbandDipBack,
+ x: points.sideLegBack.x + sa + 30,
+ })
+ if (options.backDip !== 0) {
+ macro('vd', {
+ id: 'hToSideWaistband',
+ from: points.backGussetSplit,
+ to: points.sideWaistbandBack,
+ x: points.sideLegBack.x + sa + 45,
+ })
+ }
+
+ let backCenter = points.sideWaistbandBack.shiftFractionTowards(points.sideLegBack, 0.5)
+ snippets.sideBackCenter = new Snippet('notch', backCenter)
+ if (expand) {
+ snippets.sideBackCenterMirrored = new Snippet('notch', new Point(-backCenter.x, backCenter.y))
+ }
+
+ /*
+ * Clean up paths from base
+ */
+ delete paths.back
+ delete paths.front
+ delete paths.gusset
+ delete paths.frontAndGusset
+ delete paths.bulge
+ delete paths.pocketHeight
+ delete paths.saBase
+ delete paths.pocketShape
+ delete paths.zipper
+ delete paths.mirroredZipper
+ delete paths.zipperCut
+
+ /*
+ * Title
+ */
+ if (options.flipBack) {
+ points.title = points.cfWaistbandDipBack.shift(0, 20).shift(-90, 50)
+ } else {
+ points.title = points.cfWaistbandDipBack.shift(0, 20).shift(90, 50)
+ }
+
+ macro('title', {
+ at: points.title,
+ nr: 2,
+ title: 'back',
+ })
+
+ /*
+ * Logo
+ */
+ points.logo = points.title.shiftFractionTowards(points.sideLegBack, 0.6).shift(-90, 20)
+ snippets.logo = new Snippet('logo', points.logo)
+
+ return part
+}
diff --git a/designs/umbra/src/base.mjs b/designs/umbra/src/base.mjs
new file mode 100644
index 00000000000..e8d443cd73a
--- /dev/null
+++ b/designs/umbra/src/base.mjs
@@ -0,0 +1,819 @@
+import { stretchToScale } from '@freesewing/core'
+
+function draftUmbraBase({
+ options,
+ Point,
+ Path,
+ points,
+ paths,
+ measurements,
+ complete,
+ store,
+ utils,
+ expand,
+ units,
+ macro,
+ part,
+}) {
+ /*
+ * Helper Functions
+ */
+ /**
+ * Interpolates between 3 given values.
+ * A factor of 0 will return `v1`, a factor of 0.5 will return `v2` and a factor of 1 will return `v3`.
+ * In between factors will interpolate linearly between the neighbouring values.
+ * Factors outside the range 0..1 are unsupported.
+ *
+ * @param v1 {number} First value
+ * @param v2 {number} Second value
+ * @param v3 {number} Third value
+ * @param factor {number} factor
+ * @return {number}
+ */
+ function interpolateValue(v1, v2, v3, factor) {
+ if (factor < 0.5) {
+ return 2 * (v2 * factor + v1 * (0.5 - factor))
+ }
+ return 2 * (v3 * (factor - 0.5) + v2 * (1 - factor))
+ }
+
+ /**
+ * Interpolates between 3 given points.
+ * A factor of 0 will return `p1`, a factor of 0.5 will return `p2` and a factor of 1 will return `p3`.
+ * In between factors will interpolate linearly between the neighbouring points.
+ *
+ * @param p1 {Point} First point
+ * @param p2 {Point} Second point
+ * @param p3 {Point} Third point
+ * @param factor {number} factor
+ * @return {Point}
+ */
+ function interpolatePoint(p1, p2, p3, factor) {
+ return new Point(
+ interpolateValue(p1.x, p2.x, p3.x, factor),
+ interpolateValue(p1.y, p2.y, p3.y, factor)
+ )
+ }
+
+ /*
+ * Calculate stretch for easy access
+ */
+ const stretch = {
+ x: utils.stretchToScale(options.xStretch),
+ y: utils.stretchToScale(options.yStretch),
+ elastic: utils.stretchToScale(options.elasticStretch),
+ }
+
+ let minFabricWidth = options.minFabricWidth * measurements.seat
+
+ /*
+ * Create points
+ * All center front (cf) points have x=0
+ * All side points have positive Y-coordinate
+ * Note that we're only drafting half of the shape as it's symmetric
+ */
+
+ /*
+ * Waist line
+ */
+ points.cfWaist = new Point(0, 0)
+ points.sideWaist = new Point((measurements.waist / 4) * stretch.x, 0)
+
+ /*
+ * Hip line
+ */
+ points.cfHips = new Point(0, measurements.waistToHips * stretch.y)
+ points.sideHips = new Point((measurements.hips / 4) * stretch.x, points.cfHips.y)
+
+ /*
+ * Seat line
+ */
+ points.cfSeat = new Point(0, measurements.waistToSeat * stretch.y)
+ points.sideSeat = new Point((measurements.seat / 4) * stretch.x, points.cfSeat.y)
+
+ /*
+ * The absolute middle, will be used to mirror the waistline to the back
+ */
+ const waistToMiddle = measurements.crossSeam / 2
+ points.cfMiddle = new Point(0, stretch.y * waistToMiddle)
+
+ /*
+ * The gusset position (slimmest part in the crotch)
+ */
+ points.cfGusset = new Point(
+ 0,
+ stretch.y *
+ interpolateValue(
+ measurements.waistToSeat,
+ measurements.crossSeamFront,
+ waistToMiddle,
+ options.gussetPosition
+ )
+ )
+ points.sideGusset = new Point(waistToMiddle * options.gussetWidth * stretch.x, points.cfGusset.y)
+
+ /*
+ * This path plots the width of the body from the waist to the seat to position the waistband according to height
+ */
+ paths.bodySide = new Path()
+ .move(points.sideWaist)
+ .line(points.sideHips)
+ .line(points.sideSeat)
+ .hide()
+
+ /*
+ * Waistband line
+ */
+ points.cfWaistband = points.cfSeat.shiftFractionTowards(points.cfHips, options.rise)
+ const intersection = paths.bodySide.intersectsY(points.cfWaistband.y)
+ if (intersection == null || intersection.length === 0) {
+ // If the waistband is somehow above the waistline, continue to use the waist measurement
+ // This is mostly to prevent errors when the user entered an abnormally low distance between waist and hips
+ // together with a very high rise
+ points.sideWaistbandBase = new Point(points.sideWaist.x, points.cfWaistband.y)
+ } else {
+ points.sideWaistbandBase = intersection[0]
+ }
+
+ /*
+ * Start of the leg opening
+ */
+ points.sideLegBase = points.sideSeat.shiftTowards(
+ points.sideWaistbandBase,
+ options.legRise * points.cfGusset.dist(points.cfHips)
+ )
+
+ // Enforce minimum fabric width above leg opening
+ if (
+ points.sideLegBase.dist(points.sideWaistbandBase) < minFabricWidth ||
+ points.sideLegBase.y < points.sideWaistbandBase.y
+ ) {
+ points.sideLegBase = points.sideWaistbandBase.shiftTowards(points.sideSeat, minFabricWidth)
+ }
+
+ /*
+ * Determine crotch seam split position
+ */
+ points.cfMaxSplit = new Point(0, 2 * stretch.y * waistToMiddle - points.sideLegBase.y)
+ points.cfBackGusset = points.cfGusset.shiftFractionTowards(
+ points.cfMaxSplit,
+ options.splitPosition
+ )
+
+ /*
+ * Now add the front gusset control point
+ */
+ points.gussetFrontCp = points.sideGusset.shift(
+ 90,
+ points.sideLegBase.dy(points.sideGusset) * options.frontExposure
+ )
+
+ /*
+ * Flip front side waistband positions to back
+ */
+ for (const flip of ['cfWaist', 'cfWaistband', 'sideWaistbandBase', 'sideLegBase']) {
+ points[`${flip}Back`] = points[flip].flipY(points.cfMiddle)
+ }
+
+ // Make the front smaller by options.frontReduction
+ points.sideWaistbandFront = new Point(
+ points.sideWaistbandBase.x * (1 - options.frontReduction),
+ points.sideWaistbandBase.y
+ )
+ points.sideLegFront = new Point(
+ points.sideLegBase.x * (1 - options.frontReduction),
+ points.sideLegBase.y
+ )
+
+ // Add the reduced distance to the back part
+ points.sideWaistbandBack = points.sideWaistbandBaseBack.shift(
+ 0,
+ points.sideWaistbandFront.dist(points.sideWaistbandBase)
+ )
+ points.sideLegBack = points.sideLegBaseBack.shift(0, points.sideLegFront.dist(points.sideLegBase))
+ // correct for different length
+ points.sideLegBack = points.sideWaistbandBack.shiftTowards(
+ points.sideLegBack,
+ points.sideWaistbandFront.dist(points.sideLegFront)
+ )
+
+ /*
+ * Dip the waistband at the front
+ */
+ points.cfWaistbandDipCp1Front = utils.beamIntersectsX(
+ points.sideWaistbandFront,
+ points.sideLegFront.rotate(-90, points.sideWaistbandFront),
+ points.sideWaistbandFront.x / 2
+ )
+ points.cfWaistbandDipFront = new Point(
+ 0,
+ points.cfWaistbandDipCp1Front.y + waistToMiddle * options.frontDip
+ )
+ points.cfWaistbandDipCp2Front = new Point(
+ points.cfWaistbandDipCp1Front.x * options.frontDipShape,
+ points.cfWaistbandDipFront.y
+ )
+ points.cfWaistbandDipCp1Front = points.cfWaistbandDipCp1Front.shiftFractionTowards(
+ points.sideWaistbandFront,
+ options.frontDipShape
+ )
+
+ /*
+ * Dip the waistband at the back
+ */
+ points.cfWaistbandDipCp1Back = utils.beamIntersectsX(
+ points.sideWaistbandBack,
+ points.sideLegBack.rotate(-90, points.sideWaistbandBack),
+ points.sideWaistbandBack.x / 2
+ )
+ points.cfWaistbandDipBack = new Point(
+ 0,
+ points.cfWaistbandDipCp1Back.y - waistToMiddle * options.backDip
+ )
+ points.cfWaistbandDipCp2Back = new Point(
+ points.cfWaistbandDipCp1Back.x * options.backDipShape,
+ points.cfWaistbandDipBack.y
+ )
+ points.cfWaistbandDipCp1Back = points.cfWaistbandDipCp1Back.shiftFractionTowards(
+ points.sideWaistbandBack,
+ options.backDipShape
+ )
+
+ /*
+ * We curve at the same angle as the front waistband dip here.
+ * Not doing so would mean that when the front exposure is high,
+ * and thus the fabric at the side gets narrow,
+ * Both curves would not be parallel which looks messy.
+ */
+ const dipAngle = points.sideLegFront.angle(points.sideWaistbandFront) + 90
+ points.sideLegCpFront = points.sideLegFront.shift(
+ dipAngle,
+ (points.sideGusset.dx(points.sideLegFront) / 3) * (1 - options.frontReduction)
+ )
+ points.sideLegCp1Back = points.sideLegBack.shift(
+ -dipAngle,
+ points.sideGusset.dx(points.sideLegBack) * 0.25
+ )
+
+ /*
+ * Now add the back gusset control point
+ */
+ points.gussetBackCp2 = points.sideGusset.shift(
+ 90,
+ points.sideLegCp1Back.dy(points.sideGusset) * 0.25
+ )
+
+ /*
+ * Make checking for bulge easy
+ */
+ store.set('bulge', options.bulge >= 2)
+
+ /*
+ * Construct the control points for the back curve.
+ * First create a simple back curve that mimics the one from Uma
+ */
+ paths.simpleBackCurve = new Path()
+ .move(points.sideLegBaseBack)
+ .curve(points.sideLegCp1Back, points.gussetBackCp2, points.sideGusset)
+ .hide()
+
+ const backMaxY = points.cfWaistbandDipBack.y - points.sideLegBase.dist(points.sideWaistbandBase)
+
+ /*
+ * Determine the default back curve center point and angle by probing a fraction along that curve
+ */
+ const curvePointFraction = 0.6
+ const epsilon = 0.01
+ points.backCurveCenterDefault = paths.simpleBackCurve.shiftFractionAlong(curvePointFraction)
+ const curvePointAngle = paths.simpleBackCurve
+ .shiftFractionAlong(curvePointFraction - epsilon)
+ .angle(paths.simpleBackCurve.shiftFractionAlong(curvePointFraction + epsilon))
+
+ /*
+ * Determine control point for maximum coverage
+ */
+ points.backCurveCenterMax = new Point(
+ points.sideLegBase.x * 0.7,
+ points.cfMiddle.shiftFractionTowards(points.sideLegBaseBack, 0.3).y
+ )
+ /*
+ * Determine control point for minimum coverage (thong-like)
+ */
+ points.backCurveCenterMin = points.cfWaistbandBack
+ .shiftFractionTowards(points.cfMiddle, 0.5)
+ .shift(0, minFabricWidth / 2)
+
+ /* This is the additional point */
+ points.sideFullnessBack = interpolatePoint(
+ points.backCurveCenterMax,
+ points.backCurveCenterDefault,
+ points.backCurveCenterMin,
+ options.backExposure
+ )
+
+ if (points.sideFullnessBack.y > backMaxY) {
+ points.sideFullnessBack = new Point(points.sideFullnessBack.x, backMaxY)
+ }
+
+ /* Determine the angle for the line at that point */
+ const shiftAngle = interpolateValue(160, curvePointAngle, 90, options.backExposure)
+ const shiftAmount =
+ points.cfSeat.dist(points.sideSeat) * interpolateValue(0.5, 0.1, 0.5, options.backExposure)
+
+ /* Determine control points */
+ points.sideLegCp2Back = points.sideFullnessBack.shift(shiftAngle, -shiftAmount)
+ if (points.sideLegCp2Back.y > backMaxY) {
+ points.sideLegCp2Back = new Point(points.sideLegCp2Back.x, backMaxY)
+ }
+ points.gussetBackCp1 = points.sideFullnessBack.shift(shiftAngle, shiftAmount)
+ points.gussetBackCp2 = points.sideGusset.shift(
+ 90,
+ points.sideFullnessBack.dy(points.sideGusset) / 4
+ )
+ points.gussetFrontCp = points.sideGusset.shift(
+ 90,
+ points.sideLegCpFront.dy(points.sideGusset) * options.frontExposure
+ )
+
+ /*
+ * Construct leg curve for the back part
+ */
+ paths.backCurve = new Path()
+ .move(points.sideLegBack)
+ .curve(points.sideLegCp1Back, points.sideLegCp2Back, points.sideFullnessBack)
+ .curve(points.gussetBackCp1, points.gussetBackCp2, points.sideGusset)
+ .hide()
+
+ /*
+ * Determine split point for crotch seam
+ */
+ const intersectsY = paths.backCurve.intersectsY(points.cfBackGusset.y)[0]
+
+ let backCurveParts = []
+ if (intersectsY && !Array.isArray(intersectsY)) {
+ points.backGussetSplit = intersectsY
+ backCurveParts = paths.backCurve.split(points.backGussetSplit)
+ }
+ if (!(backCurveParts && backCurveParts.length > 1)) {
+ points.backGussetSplit = points.sideGusset
+ backCurveParts = [paths.backCurve]
+ }
+
+ /*
+ * This is the part of the back curve that will be used for the back part
+ */
+ paths.elasticLegBack = backCurveParts[0].hide()
+
+ paths.back = new Path()
+ .move(points.cfWaistbandDipBack)
+ .curve(points.cfWaistbandDipCp2Back, points.cfWaistbandDipCp1Back, points.sideWaistbandBack)
+ .join(paths.elasticLegBack)
+ .line(points.cfBackGusset)
+ .hide()
+
+ // Determine center position of bulge
+ // TODO: Add measurement or make adjustable?
+ points.cfBulgeSplit = points.cfMiddle.shiftFractionTowards(points.cfHips, 0.5)
+
+ // Enforce minimum fabric width above bulge split
+ if (points.cfBulgeSplit.y < points.cfWaistbandDipFront.y + minFabricWidth) {
+ points.cfBulgeSplit = points.cfWaistbandDipFront.shift(-90, minFabricWidth)
+ }
+
+ points.rotationOrigin = new Point(points.sideGusset.x, points.cfBulgeSplit.y)
+
+ for (const pid of [
+ 'backGussetSplit',
+ 'cfMiddle',
+ 'cfGusset',
+ 'cfBackGusset',
+ 'sideGusset',
+ 'gussetFrontCp',
+ ]) {
+ if (store.get('bulge')) {
+ points[`${pid}Bulge`] = points[pid].rotate(options.bulge, points.rotationOrigin)
+ } else {
+ points[`${pid}Bulge`] = points[pid]
+ }
+ }
+
+ points.bulgeCp = points.cfBulgeSplit.shift(
+ -90,
+ points.cfBulgeSplit.dy(points.cfGussetBulge) * options.bulgeFullness
+ )
+
+ points.cfGussetBulgeCp = points.cfGussetBulge.shift(
+ 90 + options.bulge,
+ points.cfGussetBulge.dist(points.cfBulgeSplit) * 0.5
+ )
+
+ points.gussetFrontCpBulge = points.gussetFrontCpBulge.shiftFractionTowards(
+ points.sideGussetBulge,
+ options.bulge / 200
+ )
+
+ /*
+ * Rotate control points and bottom part of the back curve around the rotationOrigin to create the bulge
+ */
+ if (store.get('bulge')) {
+ points[`bulgeCpBulge`] = points['bulgeCp'].rotate(options.bulge, points.rotationOrigin)
+ } else {
+ points[`bulgeCpBulge`] = points['bulgeCp']
+ }
+
+ points.bulgeCpBottom = points.bulgeCpBulge
+ .shiftFractionTowards(points.bulgeCp, options.bulgeFullness)
+ .shiftFractionTowards(points.cfBulgeSplit, 0.5)
+
+ let rotatedPath
+ if (backCurveParts.length <= 1) {
+ rotatedPath = null
+ } else if (store.get('bulge')) {
+ rotatedPath = backCurveParts[1].rotate(options.bulge, points.rotationOrigin)
+ } else {
+ rotatedPath = backCurveParts[1]
+ }
+
+ paths.elasticLegFront = new Path().move(points.backGussetSplitBulge)
+
+ if (rotatedPath) {
+ paths.elasticLegFront = paths.elasticLegFront.join(rotatedPath)
+ }
+
+ paths.elasticLegFront
+ .curve(points.gussetFrontCpBulge, points.sideLegCpFront, points.sideLegFront)
+ .hide()
+
+ /*
+ * Construct pockets if desired
+ */
+ if (options.pockets !== 'none') {
+ points.sidePocketHeight = points.sideWaistbandFront.shiftTowards(
+ points.sideLegFront,
+ Math.min(
+ options.pocketHeight * points.cfHips.dist(points.cfSeat),
+ points.sideWaistbandFront.dist(points.sideLegFront) / 3
+ )
+ )
+ points.cfPocketHeight = points.cfWaistbandDipFront.shiftTowards(
+ points.cfMiddle,
+ points.sidePocketHeight.dist(points.sideWaistbandFront)
+ )
+ points.cfPocketHeightCp = new Point(
+ (points.sidePocketHeight.x / 2) * options.frontDipShape,
+ points.cfPocketHeight.y
+ )
+ if (expand) {
+ macro('mirror', {
+ mirror: [new Point(0, 0), new Point(0, 100)],
+ points: ['cfPocketHeightCp', 'sidePocketHeight'],
+ clone: true,
+ })
+
+ paths.pocketHeight = new Path()
+ .move(points.sidePocketHeight)
+ ._curve(points.cfPocketHeightCp, points.cfPocketHeight)
+ .curve_(points.mirroredCfPocketHeightCp, points.mirroredSidePocketHeight)
+ .reverse()
+ .addClass('help lining')
+ .addText('umbra:foldLining', 'center lining')
+ } else {
+ paths.pocketHeight = new Path()
+ .move(points.sidePocketHeight)
+ ._curve(points.cfPocketHeightCp, points.cfPocketHeight)
+ .reverse()
+ .addClass('help lining')
+ .addText('umbra:foldLining', 'center lining')
+ }
+ if (!complete) {
+ paths.pocketHeight.hide()
+ }
+
+ const pocketSeamX = points.sideHips.x * options.pocketGap
+ points.pocketSeamTop = new Path()
+ .move(points.sideWaistbandFront)
+ .curve(
+ points.cfWaistbandDipCp1Front,
+ points.cfWaistbandDipCp2Front,
+ points.cfWaistbandDipFront
+ )
+ .intersectsX(pocketSeamX)[0]
+
+ paths.pocketPilotPath = new Path()
+ .move(points.pocketSeamTop)
+ .curve_(
+ points.pocketSeamTop.shift(-80, measurements.crossSeamFront / 2),
+ new Point(points.sideLegFront.x, points.sideGussetBulge.y)
+ )
+ .setClass('mark')
+ .hide()
+
+ const intersects = paths.elasticLegFront.intersects(paths.pocketPilotPath)
+ if (intersects.length > 0) {
+ points.pocketSeamBottom = intersects[0]
+ paths.pocketPilotPath2 = new Path()
+ .move(points.pocketSeamBottom)
+ .line(points.pocketSeamBottom.shift(125, measurements.crossSeam))
+ .hide()
+ points.pocketSeamMiddle = paths.pocketPilotPath2.intersectsX(pocketSeamX)[0]
+
+ points.pocketSeamBottomCp = new Point(
+ pocketSeamX,
+ (points.pocketSeamBottom.y * 2 + points.pocketSeamMiddle.y) / 3
+ )
+
+ if (complete) {
+ paths.pocketShape = new Path()
+ .move(points.pocketSeamTop)
+ .line(points.pocketSeamMiddle)
+ .curve_(points.pocketSeamBottomCp, points.pocketSeamBottom)
+ .addClass('mark dashed')
+ .addText('umbra:pocketseam', 'center mark')
+ }
+
+ if (options.pockets === 'zipper') {
+ // Construct zipper path. This uses some absolute mm values as zipper widths are standardized.
+ // Let's assume a 5 mm zipper.
+ const zipperLeft = pocketSeamX + 10
+ const zipperRight = Math.min(
+ points.sidePocketHeight.x - 10,
+ zipperLeft + measurements.hips / 10
+ )
+ const a = paths.pocketHeight.intersectsX(zipperLeft)[0]
+ const b = paths.pocketHeight.intersectsX(zipperRight)[0]
+
+ const angle = a.angle(b)
+
+ points.leftZipperTop = a.shift(angle + 90, 2.5)
+ points.leftZipperBottom = points.leftZipperTop.shift(angle - 90, 5)
+ points.rightZipperTop = b.shift(angle + 90, 2.5)
+ points.rightZipperBottom = points.rightZipperTop.shift(angle - 90, 5)
+
+ if (complete) {
+ paths.zipper = new Path()
+ .move(points.leftZipperBottom)
+ .line(points.rightZipperBottom)
+ .line(points.rightZipperTop)
+ .line(points.leftZipperTop)
+ .close()
+ .reverse()
+ .addClass('mark dashed')
+ .addText('umbra:zipper', 'mark')
+
+ if (expand) {
+ macro('mirror', {
+ mirror: [new Point(0, 0), new Point(0, 100)],
+ points: ['leftZipperBottom', 'rightZipperBottom', 'rightZipperTop', 'leftZipperTop'],
+ clone: true,
+ })
+
+ paths.mirroredZipper = new Path()
+ .move(points.mirroredRightZipperTop)
+ .line(points.mirroredLeftZipperTop)
+ .line(points.mirroredLeftZipperBottom)
+ .line(points.mirroredRightZipperBottom)
+ .close()
+ .addClass('mark dashed')
+ .addText('umbra:zipper', 'mark')
+ }
+ }
+ paths.zipperCut = new Path()
+ .move(points.leftZipperBottom)
+ .line(points.leftZipperTop)
+ .move(points.rightZipperTop)
+ .line(points.rightZipperBottom)
+ .move(a)
+ .line(b)
+ .addClass('fabric')
+ paths.pocketHeight.hide()
+ }
+ }
+ }
+
+ // Compute elastic lengths
+ store.set(
+ 'waistbandElasticLength',
+ new Path()
+ .move(points.cfWaistbandDipBack)
+ .curve(points.cfWaistbandDipCp2Back, points.cfWaistbandDipCp1Back, points.sideWaistbandBack)
+ .move(points.cfWaistbandDipFront)
+ .curve(
+ points.cfWaistbandDipCp2Front,
+ points.cfWaistbandDipCp1Front,
+ points.sideWaistbandFront
+ )
+ .hide()
+ .length() *
+ 2 *
+ stretch.elastic
+ )
+
+ store.set(
+ 'legElasticLength',
+ (paths.elasticLegBack.length() + paths.elasticLegFront.length()) * stretch.elastic
+ )
+
+ /*
+ * Also flag this to the user, as well as the expand possibility
+ */
+ if (!expand) {
+ store.flag.preset('expandIsOff')
+ } else {
+ store.flag.preset('expandIsOn')
+ }
+ store.flag.note({
+ msg: `umbra:waistbandElasticLength`,
+ replace: { length: units(store.get('waistbandElasticLength')) },
+ })
+ store.flag.note({
+ msg: `umbra:legElasticLength`,
+ replace: { length: units(store.get('legElasticLength')) },
+ })
+ store.flag.note({
+ msg: `umbra:minStretch`,
+ replace: {
+ pct: Math.round(100 * (measurements.seat / store.get('waistbandElasticLength') - 1)) + '%',
+ },
+ })
+
+ /*
+ * Hide this part, others will extend it
+ */
+ return part
+}
+
+export const base = {
+ name: 'umbra.base',
+ measurements: [
+ 'waist',
+ 'seat',
+ 'waistToSeat',
+ 'crossSeam',
+ 'crossSeamFront',
+ 'waistToHips',
+ 'hips',
+ ],
+ options: {
+ // Fit options
+
+ /*
+ * xStretch is for the horizontal fabric stretch
+ */
+ xStretch: { pct: 15, min: 0, max: 75, menu: 'fit' },
+
+ /*
+ * yStretch is for the vertical fabric stretch
+ */
+ yStretch: { pct: 5, min: 0, max: 50, menu: 'fit' },
+
+ /*
+ * additional stretch factor for the elastics
+ */
+ elasticStretch: { pct: 5, min: 0, max: 10, menu: 'fit' },
+
+ /*
+ * gussetPosition allows you to shift the gusset towards the front or back
+ */
+ gussetPosition: { pct: 50, min: 20, max: 100, menu: 'fit' },
+
+ /*
+ * The gusset width, based on the crossSeam measurement
+ */
+ gussetWidth: {
+ pct: 12,
+ min: 3,
+ max: 20,
+ menu: 'fit',
+ toAbs: (val, { measurements }, mergedOptions) =>
+ measurements.crossSeam * mergedOptions.gussetWidth * stretchToScale(mergedOptions.xStretch),
+ },
+
+ /*
+ * splitPosition allows you to shift the split towards the front or back
+ */
+ splitPosition: { pct: 11, min: 0, max: 45, menu: 'fit' },
+
+ /*
+ * The bulge option allows you to create room in the front
+ * to keep for a snack, or other things you might want to carry there.
+ */
+ bulge: { deg: 0, min: 0, max: 30, menu: 'fit' },
+
+ /*
+ * This option allows you to create extra room in the bulge
+ */
+ bulgeFullness: {
+ pct: 75,
+ min: 25,
+ max: 100,
+ menu: (settings, mergedOptions) => (mergedOptions?.bulge < 2 ? false : 'fit'),
+ },
+
+ // Style options
+
+ /*
+ * The minimum fabric width of the thong and waistband part.
+ * Only has an effect when the back exposure is low or the leg rise is high.
+ */
+ minFabricWidth: {
+ pct: 2,
+ min: 0.5,
+ max: 5,
+ menu: 'style',
+ toAbs: (val, { measurements }) => measurements.seat * val,
+ },
+
+ /*
+ * frontReduction determines how much less wide the front part is compared to the back part
+ * This can improve fit and make the appearance slimmer, but potentially reduces the size of pockets
+ */
+ frontReduction: { pct: 10, min: 0, max: 30, menu: 'style' },
+
+ /*
+ * Rise controls the waist height
+ */
+ rise: {
+ pct: 75,
+ min: 20,
+ max: 150,
+ menu: 'style',
+ toAbs: (val, { measurements }, mergedOptions) =>
+ (measurements.crossSeam / 2 -
+ measurements.waistToSeat +
+ (measurements.waistToSeat - measurements.waistToHips) * mergedOptions.rise) *
+ stretchToScale(mergedOptions.xStretch),
+ },
+
+ /*
+ * legRise controls how high the leg opening is cut out
+ */
+ legRise: { pct: 0, min: -20, max: 40, menu: 'style' },
+
+ /*
+ * Front dip dips the front waistband
+ */
+ frontDip: { pct: 2.5, min: -5, max: 15, menu: 'style' },
+
+ /*
+ * Determines the shape of the front dip
+ */
+ frontDipShape: { pct: 75, min: 0, max: 95, menu: 'style' },
+
+ /*
+ * frontExposure determines how much skin is on display at the front
+ * Note that frontDip will also influence this
+ */
+ frontExposure: { pct: 70, min: 5, max: 100, menu: 'style' },
+
+ /*
+ * Front dip dips the back waistband
+ */
+ backDip: { pct: -2.5, min: -15, max: 10, menu: 'style' },
+
+ /*
+ * Determines the shape of the back dip
+ */
+ backDipShape: { pct: 80, min: 0, max: 95, menu: 'style' },
+
+ /*
+ * backExposure determines how much skin is on display at the back
+ * Note that backDip will also influence this
+ */
+ backExposure: { pct: 15, min: 0, max: 100, menu: 'style' },
+
+ pockets: {
+ dflt: 'none',
+ list: ['none', 'inside', 'zipper'],
+ menu: 'style',
+ extraNote: 'Select if you want pockets',
+ },
+
+ pocketGap: {
+ pct: 25,
+ min: 15,
+ max: 35,
+ menu: (settings, mergedOptions) => (mergedOptions?.pockets === 'none' ? false : 'style'),
+ toAbs: (val, { measurements }, mergedOptions) =>
+ (measurements.hips / 2) * mergedOptions.pocketGap * stretchToScale(mergedOptions.xStretch),
+ },
+
+ pocketHeight: {
+ pct: 20,
+ min: 10,
+ max: 30,
+ menu: (settings, mergedOptions) => (mergedOptions?.pockets === 'none' ? false : 'style'),
+ },
+
+ /*
+ * If the back part should be flipped
+ */
+ flipBack: {
+ menu: 'advanced',
+ bool: true,
+ extraNote:
+ 'Select if the back part should be flipped into upright orientation, set to false for development and easier debugging of control points',
+ },
+ },
+ draft: draftUmbraBase,
+ hide: { self: true },
+}
diff --git a/designs/umbra/src/front.mjs b/designs/umbra/src/front.mjs
new file mode 100644
index 00000000000..07afd2d66ee
--- /dev/null
+++ b/designs/umbra/src/front.mjs
@@ -0,0 +1,232 @@
+import { base } from './base.mjs'
+
+export const front = {
+ name: 'umbra.front',
+ from: base,
+ draft: draftUmbraFront,
+}
+
+/*
+ * This drafts the front of Umbra, or rather recycles what's needed from base
+ */
+function draftUmbraFront({
+ Point,
+ Path,
+ points,
+ paths,
+ store,
+ sa,
+ Snippet,
+ snippets,
+ options,
+ expand,
+ macro,
+ units,
+ part,
+}) {
+ if (store.get('bulge')) {
+ paths.seamBase = new Path()
+ .move(points.cfBulgeSplit)
+ .curve(points.bulgeCpBottom, points.cfGussetBulgeCp, points.cfGussetBulge)
+ .line(points.cfBackGussetBulge)
+ } else {
+ paths.seamBase = new Path().move(points.cfBackGussetBulge)
+ }
+ paths.seamBase = paths.seamBase
+ .line(points.backGussetSplitBulge)
+ .join(paths.elasticLegFront)
+ .line(points.sideWaistbandFront)
+ .curve(points.cfWaistbandDipCp1Front, points.cfWaistbandDipCp2Front, points.cfWaistbandDipFront)
+ .hide()
+ if (expand) {
+ macro('mirror', {
+ mirror: [new Point(0, 0), new Point(0, 100)],
+ paths: ['seamBase'],
+ clone: true,
+ })
+ paths.seam = paths.seamBase.join(paths.mirroredSeamBase.reverse())
+ paths.mirroredSeamBase.hide()
+
+ macro('mirror', {
+ mirror: [new Point(0, 0), new Point(0, 100)],
+ paths: ['pocketShape', 'zipperCut'],
+ points: ['pocketTop'],
+ clone: true,
+ })
+ } else {
+ paths.seam = paths.seamBase.clone().close()
+ }
+ paths.seam.unhide().addClass('fabric')
+ if (sa) {
+ paths.saBase = new Path()
+ .move(points.cfBackGussetBulge)
+ .line(points.backGussetSplitBulge)
+ .join(paths.elasticLegFront)
+ .line(points.sideWaistbandFront)
+ .curve(
+ points.cfWaistbandDipCp1Front,
+ points.cfWaistbandDipCp2Front,
+ points.cfWaistbandDipFront
+ )
+ .hide()
+
+ if (expand) {
+ macro('mirror', {
+ mirror: [new Point(0, 0), new Point(0, 100)],
+ paths: ['saBase'],
+ clone: true,
+ })
+ paths.saBase = paths.saBase.join(paths.mirroredSaBase.reverse()).close().hide()
+ paths.sa = paths.saBase.offset(sa).setClass('fabric sa').unhide()
+ } else {
+ paths.sa = paths.saBase
+ .offset(sa)
+ .reverse()
+ .line(new Point(0, points.cfBackGussetBulge.y))
+ .line(points.cfBulgeSplit)
+ .reverse()
+ .line(points.cfWaistbandDipFront)
+ .setClass('fabric sa')
+ .unhide()
+ }
+ }
+ store.cutlist.setCut({ cut: 1, from: 'fabric', onFold: !expand })
+ store.cutlist.addCut({ cut: 1, from: 'lining', onFold: !expand })
+ points.title = points.cfWaistbandDipFront.shift(-45, 20).shift(-90, 40)
+ if (expand) {
+ macro('grainline', {
+ to: store.get('bulge') ? points.cfBulgeSplit : points.cfBackGusset,
+ from: points.cfWaistbandDipFront,
+ })
+ } else {
+ macro('cutonfold', {
+ to: store.get('bulge') ? points.cfBulgeSplit : points.cfBackGusset,
+ from: points.cfWaistbandDipFront,
+ grainline: true,
+ })
+ }
+ macro('hd', {
+ id: 'wAtWaistband',
+ from: points.cfWaistbandDipFront,
+ to: points.sideWaistbandFront,
+ y: points.sideWaistbandFront.y - sa - 15,
+ })
+
+ macro('vd', {
+ id: 'grainline',
+ from: points.cfWaistbandDipFront,
+ to: points.cfBackGussetBulge,
+ x: -30,
+ })
+
+ if (store.get('bulge')) {
+ macro('vd', {
+ id: 'grainline2',
+ from: points.cfWaistbandDipFront,
+ to: points.cfBulgeSplit,
+ x: -15,
+ })
+ }
+
+ macro('vd', {
+ id: 'outer',
+ from: points.sideWaistbandFront,
+ to: points.sideLegFront,
+ x: points.sideSeat.x + 15,
+ })
+
+ if (options.frontDip !== 0) {
+ macro('vd', {
+ id: 'outer2',
+ from: points.cfWaistbandDipFront,
+ to: points.sideLegFront,
+ x: points.sideSeat.x,
+ })
+ }
+
+ macro('vd', {
+ id: 'waistbandDip',
+ from: points.cfWaistbandDipFront,
+ to: points.sideWaistbandFront,
+ x: -15,
+ })
+
+ macro('vd', {
+ id: 'heightToWaist',
+ from: points.cfWaistbandDipFront,
+ to: points.backGussetSplitBulge,
+ x: points.backGussetSplitBulge.x,
+ })
+
+ macro('hd', {
+ id: 'heightToSideLeg',
+ from: points.backGussetSplitBulge,
+ to: points.sideLegFront,
+ y: points.backGussetSplitBulge.y,
+ })
+
+ if (options.bulge >= 2) {
+ macro('hd', {
+ id: 'bulgeHeight',
+ from: points.cfBulgeSplit,
+ to: points.cfBackGussetBulge,
+ y: points.cfBackGussetBulge.y + 15,
+ })
+ }
+
+ macro('hd', {
+ id: 'backGusset',
+ to: points.backGussetSplitBulge,
+ from: points.cfBackGussetBulge,
+ y: points.cfBackGussetBulge.y + 15,
+ })
+
+ let frontCenter = points.sideWaistbandFront.shiftFractionTowards(points.sideLegFront, 0.5)
+ snippets.sideFrontCenter = new Snippet('notch', frontCenter)
+ if (expand) {
+ snippets.sideFrontCenterMirrored = new Snippet(
+ 'notch',
+ new Point(-frontCenter.x, frontCenter.y)
+ )
+ }
+
+ if (points.pocketSeamBottom) {
+ snippets.pocketTop = new Snippet('notch', points.pocketSeamTop)
+ snippets.pocketBottom = new Snippet('notch', points.pocketSeamBottom)
+ if (expand) {
+ snippets.pocketTopMirrored = new Snippet(
+ 'notch',
+ new Point(-points.pocketSeamTop.x, points.pocketSeamTop.y)
+ )
+ snippets.pocketBottomMirrored = new Snippet(
+ 'notch',
+ new Point(-points.pocketSeamBottom.x, points.pocketSeamBottom.y)
+ )
+ }
+ }
+
+ /*
+ * Clean up paths from base
+ */
+ delete paths.back
+ delete paths.front
+ delete paths.saBase
+
+ /*
+ * Title
+ */
+ macro('title', {
+ at: points.title,
+ nr: 1,
+ title: 'front',
+ notes: [
+ 'umbra:waistbandMeasure',
+ units(store.get('waistbandElasticLength')),
+ '\n',
+ 'umbra:legMeasure',
+ units(store.get('legElasticLength')),
+ ],
+ })
+
+ return part
+}
diff --git a/designs/umbra/src/index.mjs b/designs/umbra/src/index.mjs
new file mode 100644
index 00000000000..faf32fbca8f
--- /dev/null
+++ b/designs/umbra/src/index.mjs
@@ -0,0 +1,28 @@
+import { Design } from '@freesewing/core'
+import { i18n } from '../i18n/index.mjs'
+import { base } from './base.mjs'
+import { back } from './back.mjs'
+import { front } from './front.mjs'
+import { data } from '../data.mjs'
+
+/*
+ * Let core bake a new design for us
+ */
+const Umbra = new Design({
+ data,
+ parts: [base, back, front],
+})
+
+/*
+ * Named exports
+ */
+export {
+ // Individual parts
+ base,
+ back,
+ front,
+ // The Umbra design itself
+ Umbra,
+ // Translations
+ i18n,
+}
diff --git a/designs/umbra/tests/shared.test.mjs b/designs/umbra/tests/shared.test.mjs
new file mode 100644
index 00000000000..77dd2467aa0
--- /dev/null
+++ b/designs/umbra/tests/shared.test.mjs
@@ -0,0 +1,20 @@
+// This file is auto-generated | Any changes you make will be overwritten.
+import { Umbra, 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(Umbra)
+
+// Test translation
+testPatternI18n(Umbra, i18n)
+
+// Test drafting - Change the second parameter to `true` to log errors
+testPatternDrafting(Umbra, false)
+
+// Test sampling - Change the second parameter to `true` to log errors
+testPatternSampling(Umbra, false)
diff --git a/designs/wahid/README.md b/designs/wahid/README.md
index 0b4fdea3511..4ac563d312f 100644
--- a/designs/wahid/README.md
+++ b/designs/wahid/README.md
@@ -21,7 +21,7 @@
+```js
+({ Point, points, Path, paths, snippets, Snippet, part }) => {
+
+points.A = new Point(45, 60)
+points.B = new Point(10, 30)
+points.BCp2 = new Point(40, 20)
+points.C = new Point(90, 30)
+points.CCp1 = new Point(50, -30)
+points.D = new Point(50, 80)
+points.DCp1 = new Point(70, 30)
+
+paths.demo = new Path()
+.move(points.D)
+.curve(points.DCp1, points.DCp1, points.C)
+.curve(points.CCp1, points.BCp2, points.B)
+.line(points.A)
+
+points.testPoint = paths.demo.shiftFractionAlong(0.55)
+snippets.point = new Snippet("notch", points.testPoint)
+
+let angle = paths.demo.angleAt(points.testPoint)
+//draw a tangent path
+paths.tangent = new Path()
+ .move(points.testPoint.shift(angle, -30))
+ .line(points.testPoint.shift(angle, 30))
+ .attr("class", "lining dashed")
+
+return part
+}
+```
+
+
+## Notes
+
+Keep in mind that calculations with Bézier curves are often approximations.
diff --git a/markdown/dev/reference/api/path/rotate/en.md b/markdown/dev/reference/api/path/rotate/en.md
new file mode 100644
index 00000000000..ef89eaf18bf
--- /dev/null
+++ b/markdown/dev/reference/api/path/rotate/en.md
@@ -0,0 +1,53 @@
+---
+title: Path.rotate()
+---
+
+The `Path.rotate()` returns a path that is a rotated copy of this path.
+This method behaves like calling [Point.rotate](/reference/api/point/rotate) on all nodes of this path.
+
+## Signature
+
+```js
+Path path.rotate(number deg, Point rotationOrigin, cloneAttributes = false)
+```
+
+If you pass a truthy value to the cloneAttributes parameter, it will return a deep clone of the
+path, including its attributes. By default, it will return a shallow
+copy, without the attributes.
+
+## Example
+
+
+
+```js
+({ Point, points, Path, Snippet, paths, snippets, part }) => {
+
+ points.B = new Point(10, 30)
+ points.BCp2 = new Point(40, 20)
+ points.C = new Point(90, 30)
+ points.CCp1 = new Point(50, -30)
+ points.origin = new Point(6, 34)
+ snippets.origin = new Snippet('notch', points.origin)
+
+ paths.example = new Path()
+ .move(points.B)
+ .curve(points.BCp2, points.CCp1, points.C)
+ .setText("FreeSewing rocks", "text-xs fill-note center")
+
+ paths.rotated = paths.example
+ .rotate(180, points.origin, true)
+ .attr("class", "dotted")
+
+ return part
+}
+```
+
+
+## Notes
+
+The rotated path is a shallow copy.
+It will in other words not inherit the attributes of the original path.
+
+If you want a deep copy, including the attributes, set the third parameter to true:
+
+`Path.rotate(deg, origin, true)`
diff --git a/markdown/dev/reference/api/utils/curveparameterfrompoint/en.md b/markdown/dev/reference/api/utils/curveparameterfrompoint/en.md
new file mode 100644
index 00000000000..b1346a3d342
--- /dev/null
+++ b/markdown/dev/reference/api/utils/curveparameterfrompoint/en.md
@@ -0,0 +1,77 @@
+---
+title: utils.curveParameterFromPoint()
+---
+
+The `utils.curveParameterFromPoint()` function calculates where the point `check` lies on a
+curve described by points `start`, `cp1`, `cp2`, and `end`.
+
+For example a return value of 0 indicates that the given point is the start of the curve, a return value
+of 1 indicated that the given point is identical to the end of the curve.
+
+A return value of 0.5 indicates that the start point and the first control point had the same influence
+as the end point and the second control point, to create the checked point, but this doesn't necessarily mean
+that the point lies exactly half-way on the curve.
+
+This method returns `false` if the point isn't (approximately) located on the curve.
+
+## Signature
+
+```js
+number|false utils.curveParameterFromPoint(
+ Point start,
+ Point cp1,
+ Point cp2,
+ Point end,
+ Point check
+)
+```
+
+## Example
+
+
+```js
+({ Point, points, Path, paths, Snippet, snippets, getId, utils, part }) => {
+
+ points.start = new Point(10, 10)
+ points.cp1 = new Point(90, 30)
+ points.cp2 = new Point(10, 40)
+ points.end = new Point(90, 60)
+
+ const scatter = []
+ for (let i = 1; i < 19; i++) {
+ for (let j = 1; j < 14; j++) {
+ scatter.push(new Point(i * 10, j * 10))
+ }
+ }
+ let snippet
+ for (let point of scatter) {
+ let t = utils.curveParameterFromPoint(
+ points.start,
+ points.cp1,
+ points.cp2,
+ points.end,
+ point
+ )
+ if(t !== false) {
+ points[getId()] = point.addText(` ${Math.round(t * 100) / 100}`, 'text-sm')
+ snippets[getId()] = new Snippet('notch', point)
+ }
+ }
+ paths.curve = new Path()
+ .move(points.start)
+ .curve(points.cp1, points.cp2, points.end)
+ .addClass("fabric stroke-lg")
+
+ return part
+}
+```
+
+
+
+## Notes
+
+Keep in mind that calculations with Bézier curves are often approximations.
+
+This method is mostly used as internal building block for methods like
+`utils.pointOnCurve()`, `Path.split()` or `Path.angleAt()` and probably is not very relevant
+for direct usage from pattern code.
diff --git a/markdown/dev/reference/trust/en.md b/markdown/dev/reference/trust/en.md
new file mode 100644
index 00000000000..a7315972fc5
--- /dev/null
+++ b/markdown/dev/reference/trust/en.md
@@ -0,0 +1,62 @@
+---
+title: Web of Trust
+---
+
+In the wake of [the March 2024 supply-chain attack on XZ
+Utils](https://www.wired.com/story/xz-backdoor-everything-you-need-to-know/) --
+which attempted to smuggle a backdoor into Linux distributions -- FreeSewing has
+taken steps to guard against the attack vector where a contributor gains trust
+over a long period of time, with the end goal to smuggle malicious code into the project.
+
+__Elevated permissions or access will only be granted to people who are in FreeSewing's web of trust__.
+
+We have established an initial web of trust (more on this below) and have
+revoked elevated permissions from all other contributors.
+
+
+
+##### Paranoia much?
+
+We appreciate that -- given to the nature of software FreeSewing provides -- the chances of a supply chain attack by an adversary willing to invest months or even years to gain our trust are vanishingly small.
+
+Still, we are a small part of the larger open source ecosystem, and we cannot foresee the ways in which others may end up using our software.
+In addition, we want to help normalize this approach, and help raise awareness of the risks involved in trusting pseudo-anonymous contributions.
+
+
+
+## Defining trust
+
+To understand what we mean by a _web of trust_, we need to keep in mind what we want to guard against.
+In other words, the web of trust should prevent:
+
+**Someone attempting to gain our trust -- possibly over a prolonged period of time -- to achieve a malicious goal.**
+
+Right from the start, you can see that this is impossible. There is no real way to know people's true intentions, so we cannot guard against that.
+However, if we assume people try to pull this off without giving up their real identity, we can instead just focus on identity instead.
+
+The FreeSewing community exists almost exclusively online.
+In contrast, **FreeSewing's web of trust is made up of people who know and have verified each others _real_ identities**.
+
+In other words, to gain elevated permissions or access in FreeSewing, we need to know who you are and where you live.
+
+## Joining the web of trust
+
+To join FreeSewing's web of trust, you should:
+
+- Be a contributor
+- Reach out to one of the current trustees
+- Meet up with them -- physically, in the real world -- and verify each other's identities.
+- Once the current trustee vouches for your identity, you can be added to the web of trust
+
+
+Being a trustee is a requirement to be granted elevated privileges. It ddoes not automatically grant them.
+
+
+## FreeSewing's web of trust
+
+
+
+## Trustees
+
+
+
diff --git a/markdown/org/blog/email-breakdown-post-mortem/uk.md b/markdown/org/blog/email-breakdown-post-mortem/uk.md
index 67360308fc9..53a733c49cc 100644
--- a/markdown/org/blog/email-breakdown-post-mortem/uk.md
+++ b/markdown/org/blog/email-breakdown-post-mortem/uk.md
@@ -6,7 +6,7 @@ intro: From the end of 29 October 2023 until 2 January 2024, some emails sent to
author: 1
---
-Between the 29th of October 2023 until the 2nd of January 2024, emails sent to joost\@joost.at (my personal email) or various @freesewing.org email addresses went unnoticed. Since noticing the issue today I have gone through the backlog and set aside any messages that I need to deal with.
+Between the 29th of October 2023 until the 2nd of January 2024, emails sent to joost@joost.at (my personal email) or various @freesewing.org email addresses went unnoticed. Since noticing the issue today I have gone through the backlog and set aside any messages that I need to deal with.
However, this is a manual and tedious process so it's possible that I'll miss a few. In addition, it's also very possible that emails sent to me 2 months ago required a speedier response.
@@ -18,7 +18,7 @@ I'd like to apologize to all those who I should have been in touch with but didn
To understand what happened, I should start by explaining my email setup.
-I have historically used joost\@decock.org as my personal email. It's tied to Google in the way that is no longer possible today, using one of those grandfathered-in domain setups that they don't allow you to have any longer.
+I have historically used joost@decock.org as my personal email. It's tied to Google in the way that is no longer possible today, using one of those grandfathered-in domain setups that they don't allow you to have any longer.
I don't trust Google as far as I can throw them, but Gmail is the best mail client for my needs because I don't want to spend my time carefully organizing email, I just want to search and find what I'm looking for. Nothing comes close to Gmail when it comes to that.
Furthermore, as an Android user, this primary not-really-gmail-but-still-a-bit Google account is also tied to my phone, and a host of other things that are important. In other words, I need to have _some_ Google account, so this is it.
diff --git a/markdown/org/blog/open-backend-api/es.md b/markdown/org/blog/open-backend-api/es.md
index 1396125ae02..3d73b00dddd 100644
--- a/markdown/org/blog/open-backend-api/es.md
+++ b/markdown/org/blog/open-backend-api/es.md
@@ -20,7 +20,7 @@ Supongo que, al menos al principio, será una función muy especializada. Sin em
Por lo menos, sé que lo haré.
-La [documentación de referencia de la API REST vive aquí](https://freesewing.dev/reference/backend), si buscas la Especificación OpenAPI, entonces ve a https\://backend3.freesewing.org/docs/
+La [documentación de referencia de la API REST vive aquí](https://freesewing.dev/reference/backend), si buscas la Especificación OpenAPI, entonces ve a https://backend3.freesewing.org/docs/
## Usa, no abuses
diff --git a/markdown/org/blog/open-backend-api/uk.md b/markdown/org/blog/open-backend-api/uk.md
index f9ef07d2a5a..f05637e1bc8 100644
--- a/markdown/org/blog/open-backend-api/uk.md
+++ b/markdown/org/blog/open-backend-api/uk.md
@@ -20,7 +20,7 @@ author: 1
Принаймні, я знаю, що так і буде.
-Довідкова документація [REST API знаходиться тут] (https\://freesewing.dev/reference/backend), якщо ви шукаєте специфікацію OpenAPI, то перейдіть на https\://backend3.freesewing.org/docs/
+Довідкова документація [REST API знаходиться тут] (https://freesewing.dev/reference/backend), якщо ви шукаєте специфікацію OpenAPI, то перейдіть на https://backend3.freesewing.org/docs/
## Використовуйте, але не зловживайте
diff --git a/markdown/org/docs/about/faq/measurements-issues/fr.md b/markdown/org/docs/about/faq/measurements-issues/fr.md
index 3afdf04ab7e..6ee3d81643f 100644
--- a/markdown/org/docs/about/faq/measurements-issues/fr.md
+++ b/markdown/org/docs/about/faq/measurements-issues/fr.md
@@ -1,12 +1,12 @@
---
-title: J'ai des difficultés avec les mesures. Que faut-il pour que je vérifie?
+title: J'ai des difficultés avec les mesures. Que faut-il que je vérifie?
---
Chacune de nos [mesures] (https\://freesewing.org/docs/measurements) est documentée par une description et deux visuels. S'y référer résout la plupart des problèmes.
Nous travaillons sur une fonctionnalité d'assurance qualité qui détecte les problèmes éventuels et les porte à l'attention de l'utilisateur d'une manière qui _a du sens_.
-En attendant, voici quelques endroits pour commencer à chercher si tu as des problèmes avec tes mesures.
+En attendant, voici quelques endroits où commencer à chercher si tu as des problèmes avec tes mesures.
### Remarques générales
@@ -20,46 +20,46 @@ Nous avons remarqué que certaines mesures ont tendance à poser des problèmes.
#### De la taille à l'aisselle
-La mesure [de la taille à l'aisselle] (https\://freesewing.org/docs/measurements/waisttoarmpit) est une mesure verticale droite, et non curviligne (qui suit la courbe du corps). It should be at the bottom edge of your armpit, only as high as a shirt would be comfortable sitting (not digging in).
+La mesure [de la taille à l'aisselle] (https\://freesewing.org/docs/measurements/waisttoarmpit) est une mesure verticale droite, et non curviligne (qui suit la courbe du corps). Il doit se situer au niveau du bord inférieur de ton aisselle, pas plus haut que le max qu'une chemise peux l'être (sans s'enfoncer).
-
+
-#### High point shoulder (HPS)
+#### Point Haut de l'Épaule (ou PHE)
-[HPS](https://freesewing.org/docs/sewing/hps), which is used in several measurements, is one of the harder spots to get perfect.
+[PHE](https://freesewing.org/docs/sewing/hps), qui est utilisé dans plusieurs mesures, est l'un des points les plus difficiles à perfectionner.
-Here are two approaches.
+Voici deux approches.
-One way is to take a pencil, pen, or small dowel to find the point where your neck meets your shoulder, as well as the highest point as that's where the pencil or dowel will touch the shoulder. If you use that method, you ideally want the tool you're using to be parallel with the floor so you can find that high point.
+Une façon de procéder consiste à prendre un crayon, un stylo ou une petite cheville pour trouver le point où ton cou rencontre ton épaule, ainsi que le point le plus élevé car c'est là que le crayon ou la cheville touchera l'épaule. Si tu utilises cette méthode, l'idéal est que l'outil que tu utilises soit parallèle au sol pour que tu puisses trouver ce point haut.
-
+[Point haut de l'épaule avec cheville](hps2.jpg)
-Another way is with a ribbon. Take a longer ribbon and put it over your neck/shoulder like a cross body bag. It helps to be able to feel where the neck ends and the shoulder begins with a small amount of pressure on the ribbon. You'll need to determine where the shoulder seam should sit, but the ribbon will tell you where the HPS should sit once you have the shoulder seam determined as it will be where the two lines cross.
+Tu peux aussi utiliser un ruban. Prends un ruban plus long et mets-le autour de ton cou/de tes épaules comme une sacoche. Il est utile de pouvoir sentir où se termine le cou et où commence l'épaule en exerçant une petite pression sur le ruban. Tu devras déterminer l'emplacement de la couture de l'épaule, mais le ruban t'indiquera l'emplacement du PHE une fois que tu auras déterminé la couture de l'épaule, car ce sera l'endroit où les deux lignes se croisent.
-
+[Point haut de l'épaule avec ruban](hps2.jpg)
#### Tour de buste supérieur
-[High bust](https://freesewing.org/docs/measurements/highbust) is a horizontal measurement that does not need to be perfectly horizontal. It should go around your torso at the narrowest part of the upper chest, over the bust, under the arms, and across the back, but does not need to be parallel to the ground all the way around.
+Le [buste haut] (https://freesewing.org/docs/measurements/highbust) est une mesure horizontale qui n'a pas besoin d'être parfaitement horizontale. Elle doit faire le tour de ton torse au niveau de la partie la plus étroite du haut de la poitrine, passer sur le buste, sous les bras et dans le dos, mais il n'est pas nécessaire qu'elle soit parallèle au sol sur toute sa longueur.
-
+[Buste haut vu de côté](highbust.jpg)
-
+[Buste haut de face](highbust2.jpg)
#### Pente d'épaule
-Many have had luck using an inclinometer app on a smartphone to measure [shoulder slope](https://freesewing.org/docs/measurements/shoulderslope).
+Beaucoup ont eu de la chance en utilisant une application d'inclinomètre sur un smartphone pour mesurer [la pente des épaules] (https://freesewing.org/docs/measurements/shoulderslope).
-#### Seat and hips
+#### Siège et hanches
-Sometimes people have [seat](https://freesewing.org/docs/measurements/seat) and [hips](https://freesewing.org/docs/measurements/hips) reversed.
+Parfois, les gens ont [siège](https://freesewing.org/docs/measurements/seat) et [hanches](https://freesewing.org/docs/measurements/hips) inversés.
-In FreeSewing terms, hips is measured at the upper point of the hip bones. Some other sources call this the "high hip".
+En termes de FreeSewing, les hanches sont mesurées au point supérieur des os de la hanche. D'autres sources appellent cela la "hanche haute".
-Seat is across the fullest part of your butt. Some other sources call this the "hip".
+L'assise se trouve sur la partie la plus large de tes fesses. D'autres sources appellent cela la "hanche".
-##### Waist
+##### Taille
-Where you take the [waist](https://freesewing.org/docs/measurements/waist) measurements is not necessarily connected to where, for instance, a waistband is.
+L'endroit où tu prends les mesures de la [taille] (https://freesewing.org/docs/measurements/waist) n'est pas nécessairement lié à l'endroit où se trouve, par exemple, une ceinture.
-Try bending sideways and noting the point where your body creases. (For bonus points, put your hand on your waist and sing "I'm a little teapot".)
+Essaie de te pencher sur le côté et de noter l'endroit où ton corps se plisse. (Pour les points bonus, mets ta main sur ta taille et chante "Je suis une petite théière")
diff --git a/markdown/org/docs/about/faq/seam-allowance/fr.md b/markdown/org/docs/about/faq/seam-allowance/fr.md
index 3388d6aa0fb..7d00e9d2a30 100644
--- a/markdown/org/docs/about/faq/seam-allowance/fr.md
+++ b/markdown/org/docs/about/faq/seam-allowance/fr.md
@@ -1,7 +1,7 @@
---
-title: Why are seam allowances not included by default?
+title: Pourquoi les marges de couture ne sont-elles pas incluses par défaut ?
---
-We don't include seam allowance by default because it's computationally expensive to add seam allowance since there is no closed form integral solution for offsetting a cubic Bezier curve.
+Nous n'incluons pas la marge de couture par défaut parce qu'il est coûteux de calculer la marge de couture étant donné qu'il n'y a pas de solution intégrale explicite pour compenser une courbe de Bézier cubique.
-We have a YouTube video with more information: [A look at the FreeSewing Timing Plugin](https://youtu.be/pn6w-O6nFbI)
+Nous avons une vidéo YouTube qui contient plus d'informations : [Un regard sur le plugin FreeSewing Timing](https://youtu.be/pn6w-O6nFbI)
diff --git a/markdown/org/docs/about/faq/standard-measurements/fr.md b/markdown/org/docs/about/faq/standard-measurements/fr.md
index 91870c9a259..e6108e515a3 100644
--- a/markdown/org/docs/about/faq/standard-measurements/fr.md
+++ b/markdown/org/docs/about/faq/standard-measurements/fr.md
@@ -1,9 +1,9 @@
---
-title: Where did the "standard" measurements go?
+title: Où sont passées les mesures "standard" ?
---
-In past versions of FreeSewing, we published a sizing table so that users could try out the platform without entering their measurements. Because there are no real standards for sizes, ours were -- like all sizing charts -- made up.
+Dans les versions antérieures de FreeSewing, nous avons publié un tableau des tailles pour que les utilisateurs puissent essayer la plateforme sans entrer leurs mesures. Comme il n'y a pas de normes réelles pour les tailles, les nôtres ont été - comme tous les tableaux de tailles - inventées.
-We found that publishing these created unreasonable expectations. Users were disappointed when their patterns generated with "standard" sizes didn't fit as they expected. We removed the made up measurements in favor of [curated measurements sets](https://freesewing.org/curated-sets).
+Nous avons constaté que leur publication créait des attentes déraisonnables. Les utilisateurs ont été déçus lorsque leurs patrons générés avec des tailles "standard" ne s'adaptaient pas comme ils l'espéraient. Nous avons supprimé les mesures inventées en faveur de [des mesures curatés] (https://freesewing.org/curated-sets).
-We also removed the ability to compare your measurements to "standard" ones to try to identify potential mismeasurements. In the future, we may implement different ways to check, but will only display these to users who are [comfortable with their measurement sets being compared](https://freesewing.org/account/compare).
+Nous avons également supprimé la possibilité de comparer tes mesures à des mesures "standard" pour essayer d'identifier d'éventuelles erreurs de mesure. À l'avenir, nous pourrons mettre en place différentes méthodes de vérification, mais nous ne les afficherons qu'aux utilisateurs qui sont [à l'aise avec la comparaison de leurs ensembles de mesures] (https://freesewing.org/account/compare).
diff --git a/markdown/org/docs/about/site/bookmarks/type/de.md b/markdown/org/docs/about/site/bookmarks/type/de.md
index 9c21a579abb..0fe8f2c499d 100644
--- a/markdown/org/docs/about/site/bookmarks/type/de.md
+++ b/markdown/org/docs/about/site/bookmarks/type/de.md
@@ -6,5 +6,5 @@ Jedes Lesezeichen hat ein **type** Attribut, das obligatorisch ist.
Wenn du ein Lesezeichen manuell erstellst, ist der Typ immer **benutzerdefiniert** und du kannst ihn nicht auswählen.
-Andere Typen sind **pattern**, **docs**, oder **set** , die automatisch gesetzt werden, wenn du ein Lesezeichen für ein Muster, eine Dokumentationsseite oder ein Messset setzt.
+Other types include **pattern**, **doc**, or **set** which will automatically be set when you bookmark a pattern, documentation page, or measurements set respectively.
diff --git a/markdown/org/docs/about/site/bookmarks/type/es.md b/markdown/org/docs/about/site/bookmarks/type/es.md
index 49d9cc900d1..f61a8897d70 100644
--- a/markdown/org/docs/about/site/bookmarks/type/es.md
+++ b/markdown/org/docs/about/site/bookmarks/type/es.md
@@ -6,5 +6,5 @@ Cada marcador tiene un atributo **type** que es obligatorio.
Cuando creas manualmente un marcador, el tipo siempre es **personalizado** , por lo que no puedes elegirlo.
-Otros tipos son **patrón**, **docs**, o **conjunto** que se establecerán automáticamente cuando marques como favorito un patrón, una página de documentación o un conjunto de medidas respectivamente.
+Other types include **pattern**, **doc**, or **set** which will automatically be set when you bookmark a pattern, documentation page, or measurements set respectively.
diff --git a/markdown/org/docs/about/site/bookmarks/type/fr.md b/markdown/org/docs/about/site/bookmarks/type/fr.md
index efd10c1c804..b1841593c51 100644
--- a/markdown/org/docs/about/site/bookmarks/type/fr.md
+++ b/markdown/org/docs/about/site/bookmarks/type/fr.md
@@ -6,5 +6,5 @@ Chaque marque page possède un attribut **type** qui est obligatoire.
Lorsque tu crées manuellement un marque page, le type est toujours **custom** et tu ne peux donc pas le choisir.
-D'autres types incluent **patron**, **docs**, ou **set** qui seront automatiquement mis en place lorsque tu marqueras la page d'un patron, d'une page de documentation ou d'un jeu de mesures respectivement.
+D'autres types incluent **patron**, **doc**, ou **set** qui seront automatiquement mis en place lorsque tu marqueras la page d'un patron, d'une page de documentation ou d'un jeu de mesures respectivement.
diff --git a/markdown/org/docs/about/site/bookmarks/type/nl.md b/markdown/org/docs/about/site/bookmarks/type/nl.md
index 704661c10d2..a46a0f2173e 100644
--- a/markdown/org/docs/about/site/bookmarks/type/nl.md
+++ b/markdown/org/docs/about/site/bookmarks/type/nl.md
@@ -6,5 +6,5 @@ Elke bladwijzer heeft een **type** attribuut dat verplicht is.
Als je handmatig een bladwijzer maakt, is het type altijd **custom** zodat je het niet kunt kiezen.
-Andere types zijn **patroon**, **docs**, of **set** die automatisch worden ingesteld wanneer je een bladwijzer maakt voor respectievelijk een patroon, documentatiepagina of meetset.
+Other types include **pattern**, **doc**, or **set** which will automatically be set when you bookmark a pattern, documentation page, or measurements set respectively.
diff --git a/markdown/org/docs/about/site/bookmarks/type/uk.md b/markdown/org/docs/about/site/bookmarks/type/uk.md
index 5e9fbf18c01..679250d9245 100644
--- a/markdown/org/docs/about/site/bookmarks/type/uk.md
+++ b/markdown/org/docs/about/site/bookmarks/type/uk.md
@@ -6,5 +6,5 @@ title: Тип
Коли ви створюєте закладку вручну, тип завжди **користувацький** , тому ви не можете його вибрати.
-Інші типи включають **деталі**, **документи**або **набір** , які будуть автоматично встановлені, коли ви зробите закладку на деталь, сторінку документації або набір вимірів відповідно.
+Other types include **pattern**, **doc**, or **set** which will automatically be set when you bookmark a pattern, documentation page, or measurements set respectively.
diff --git a/markdown/org/docs/about/site/en.md b/markdown/org/docs/about/site/en.md
index 453f435004a..e21782be297 100644
--- a/markdown/org/docs/about/site/en.md
+++ b/markdown/org/docs/about/site/en.md
@@ -25,7 +25,7 @@ So I'm not going to do that. I'm going to assume you are reading with an open mi
On every page of FreeSewing.org is the same header with links to the most important sections of the site:
- [Designs](/designs/) shows our collection of parametric designs you can generate bespoke sewing patterns from
-- [Documentation](/documentation/) holds all the documentation, for the website, for our designs, everything
+- [Documentation](/docs/) holds all the documentation, for the website, for our designs, everything
- [Blog](/blog/) holds blog posts with updates and news about FreeSewing
- [Showcase](/showcase/) show examples from the FreeSewing community, things they have made with FreeSewing patterns
- [Account](/account/) is where you can manage your FreeSewing account
diff --git a/markdown/org/docs/designs/bibi/cutting/en.md b/markdown/org/docs/designs/bibi/cutting/en.md
new file mode 100644
index 00000000000..c2a41555f3c
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/cutting/en.md
@@ -0,0 +1,14 @@
+---
+title: "Bibi Body Block: Cutting Instructions"
+---
+
+- Cut 1 back on the fold.
+- Cut 1 front on the fold.
+- Cut 2 sleeves _with good sides together_ (optional)
+ - If you cut sleeves separately, remember that one has to be a mirror image of the other.
+ - There is no sleeve part if sleeves are disabled or the sleeve length setting is below 5%
+
+## Caveats
+
+- There is extra hem allowance at the hem.
+- Depending on how you want to finish the neck and armholes, choose an appropriate seam allowance.
diff --git a/markdown/org/docs/designs/bibi/en.md b/markdown/org/docs/designs/bibi/en.md
new file mode 100644
index 00000000000..601b1bfd42b
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/en.md
@@ -0,0 +1,8 @@
+---
+title: "Bibi Body Block"
+---
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/fabric/en.md b/markdown/org/docs/designs/bibi/fabric/en.md
new file mode 100644
index 00000000000..f0886682887
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/fabric/en.md
@@ -0,0 +1,11 @@
+---
+title: "Bibi Body Block: Fabric Options"
+---
+
+Bibi is by default designed as a close-fitting top and is best suited to knit fabrics with some stretch, such as jersey.
+
+Woven fabrics with good drape could also work. Increase ease settings and ensure the neck hole is large enough to fit a head through.
+
+
+If you're new to sewing, interlock jersey is nice to work with, as it doesn't roll up. Prefer jersey with a few percent spandex for better recovery. Fabric weights can also help you make your choice. A weight of 130-200 grams per square meter (or 4-6 ounces per square yard) is likely to be about right.
+
diff --git a/markdown/org/docs/designs/bibi/instructions/dart.svg b/markdown/org/docs/designs/bibi/instructions/dart.svg
new file mode 100644
index 00000000000..8a2913be0da
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/instructions/dart.svg
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/instructions/en.md b/markdown/org/docs/designs/bibi/instructions/en.md
new file mode 100644
index 00000000000..22f99cc4936
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/instructions/en.md
@@ -0,0 +1,104 @@
+---
+title: "Bibi Body Block: Sewing Instructions"
+---
+
+
+
+###### Bibi is a pattern building block
+
+Bibi can be sewn as a simple top, but is mostly designed as a building block for other patterns or custom designs.
+
+Bibi is highly customizable, but it does not in itself represent a specific garment or style. Some option combinations might not make much sense.
+
+You may want to finish the hem, armholes, and/or neck using knit bands, knit binding or ribbing fabric.
+In this case, you may want to look at instructions from other designs, like Aaron or Teagan.
+
+There is also lots of other stuff you could customize.
+
+
+
+### Step 0: Prepare the fabric
+
+Cut out the parts including seam allowance and transfer markings and notches to the fabric.
+Note that there are two different kinds of notches. You probably want to use a different notch shape or a different pen/chalk color for notches with an ×.
+
+### Step 1: Prepare the front part
+
+If your pattern is for someone with a larger bust, your design will likely include
+either fabric gathering or a bust dart at the side seam of the front part.
+
+If your pattern contains neither an indicated gathering section nor a dart, skip to step 2.
+
+#### Bust darts
+
+If you drafted the pattern with _darts_, fold your front part _good sides together_ along the center line of the dart.
+
+Sew using an elastic stitch along the dart line from the side seam towards the bust.
+Near the dart tip, make sure to stitch as parallel to the fold line as possible while still stitching over the folded edge.
+
+If not using a serger, cut away any unnecessary fabric from the dart and finish raw edges.
+
+Repeat this for both sides.
+
+
+
+#### Gathering
+
+If you didn't select the dart option, gather the fabric by doing 2 or 3 parallel straight stitches through the seam allowance where indicated on the pattern.
+The stiches should have a longer stitch length setting, and you must *not* secure the ends by backstitching.
+Keep the thread ends loose and long.
+
+Hold the bobbin threads with one hand tight and bunch together the fabric with the other hand until
+you've gathered the side seam to the same length as the distance between the notches on the back part pattern.
+
+Secure the threads by tying a knot.
+
+Repeat this for both sides.
+
+
+
+
+
+There are lots of alternative techniques for this. If the difference between the lengths isn't that large,
+you could simply adjust/stretch the fabric while sewing the side seam later. Or you could pleat folds manually and pin them in place.
+
+Experiment with different methods on scrap fabric and look up books and tutorials for tips if you are unsure.
+
+
+
+### Step 2: Sew the shoulder seams
+
+Match up the front and back parts along the edges between the neck and the armholes _good sides together_ and matching raw edges.
+
+Sew using an elastic stitch. Repeat for both sides.
+
+
+
+### Step 3: Sew the sleeves
+
+If your design has a separate sleeve part, pin the sleeve part to the main body part, _good sides together_, matching notches and raw edges.
+
+The hem of the sleeve points towards the neck opening.
+
+Note that the sleeve part is not perfectly symmetrical. The ×-notch of the sleeve goes to the back part.
+The round notch attaches to the front part.
+
+Sew with an elastic stitch. Repeat for both sleeves.
+
+
+
+
+
+If your design doesn't have a sleeve part, skip to the next step.
+
+### Step 4: Sew the side seams
+
+_good sides together_, pin the side seams and the bottoms of the sleeves (if present) together.
+
+With the front part on top, sew using an elastic stitch. Repeat for both sides. Remove any threads used for gathering.
+
+
+
+### Step 5: Hem the openings
+
+If not using knit binding or knit bands fold over the fabric at the remaining openings _wrong sides together_ once and topstitch in place with an elastic stitch.
diff --git a/markdown/org/docs/designs/bibi/instructions/gather.svg b/markdown/org/docs/designs/bibi/instructions/gather.svg
new file mode 100644
index 00000000000..64d8f4d89c0
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/instructions/gather.svg
@@ -0,0 +1,306 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/instructions/shoulders.svg b/markdown/org/docs/designs/bibi/instructions/shoulders.svg
new file mode 100644
index 00000000000..beb53970c87
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/instructions/shoulders.svg
@@ -0,0 +1,265 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/instructions/sideseam.svg b/markdown/org/docs/designs/bibi/instructions/sideseam.svg
new file mode 100644
index 00000000000..f6144c74e27
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/instructions/sideseam.svg
@@ -0,0 +1,228 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/instructions/sleeve.svg b/markdown/org/docs/designs/bibi/instructions/sleeve.svg
new file mode 100644
index 00000000000..ea9e829c223
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/instructions/sleeve.svg
@@ -0,0 +1,381 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/instructions/sleeve2.svg b/markdown/org/docs/designs/bibi/instructions/sleeve2.svg
new file mode 100644
index 00000000000..c42a4098d07
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/instructions/sleeve2.svg
@@ -0,0 +1,198 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/measurements/en.md b/markdown/org/docs/designs/bibi/measurements/en.md
new file mode 100644
index 00000000000..45d5f4b1e44
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/measurements/en.md
@@ -0,0 +1,5 @@
+---
+title: "Bibi Body Block: Required Measurements"
+---
+
+
diff --git a/markdown/org/docs/designs/bibi/needs/en.md b/markdown/org/docs/designs/bibi/needs/en.md
new file mode 100644
index 00000000000..44fe989af73
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/needs/en.md
@@ -0,0 +1,28 @@
+---
+title: "Bibi Body Block: What You Need"
+---
+
+To make Bibi, you will need the following:
+
+- Basic sewing supplies
+- About 1 - 3 metres (1.1 - 3.3 yards) of a suitable fabric ([see Bibi Fabric options](/docs/designs/bibi/fabric/))
+ - A short crop top without sleeves needs probably less than a meter, a long dress with sleeves needs much more fabric.
+
+
+
+##### A serger/overlock is nice, but optional
+
+As with all knitwear and stretch fabrics, a serger/overlock will make your life easier.
+If you do not have one of those, don’t despair. You don’t really need it. All serged seams on Bibi can also be sewn with a short, narrow zigzag stitch (~2 mm wide) on a standard sewing machine.
+
+
+
+
+
+###### Bibi is a pattern building block
+
+Bibi can be sewn as a simple top, but is mostly designed as a building block for other patterns or custom designs.
+
+You may want to finish the hem, armholes, and neck using knit bands, knit binding or ribbing fabric. In this case, you may need additional material.
+
+
diff --git a/markdown/org/docs/designs/bibi/notes/en.md b/markdown/org/docs/designs/bibi/notes/en.md
new file mode 100644
index 00000000000..08bfbaac6c3
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/notes/en.md
@@ -0,0 +1,32 @@
+---
+title: "Bibi Body Block: Designer Notes"
+---
+
+When I was designing the Tina top, I originally was basing the pattern on
+Teagan and Brian. However, Tina is supposed to work for people with breasts
+and Brian is mostly designed for menswear and doesn't support much body
+and bust fitting. So I created Bibi as a base for Tina.
+
+For Bibi, I reused code from Brian mostly for the sleevecap and armhole construction
+and added a basic front bust adjustment. Because Bibi is supposed to be usable for very different lengths,
+I also changed the sideline calculation to fit to the waist and seat measurements
+and added a sleeveless option. After some fine-tuning, this is basically the result.
+
+While Bibi was specifically made to support people with breasts,
+it also works fine as a base for unisex clothes or t-shirts.
+
+However, it's also important to talk about what Bibi is not:
+
+Bibi can be sewn as a simple top or dress, but it's mostly designed as a building block for other patterns or your custom designs.
+
+Bibi is highly customizable, but it does not itself represent a specific garment or follow a specific style.
+Some option combinations might not make much sense and you'll have to experiment with different options
+yourself to find the design you're looking for.
+
+Bibi is also not a standard block/sloper for woven fabric. It only does a very basic front bust adjustment
+designed for stretchy knit fabric and will not work well as a base for fitted shirts and blouses from woven fabric.
+
+The name Bibi is a little joke and comes from *Bibi und Tina*, a German audio play for children,
+where 13-year-old witch *Bibi Blocksberg* is a companion of *Tina*. So it kinda makes sense.
+
+Jonathan
diff --git a/markdown/org/docs/designs/bibi/options/acrossbackfactor/en.md b/markdown/org/docs/designs/bibi/options/acrossbackfactor/en.md
new file mode 100644
index 00000000000..2a76eb8e2c7
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/acrossbackfactor/en.md
@@ -0,0 +1,9 @@
+---
+title: "Across back factor"
+---
+
+Controls your across back width as a factor of your shoulder to shoulder measurement
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/armholecurveback/en.md b/markdown/org/docs/designs/bibi/options/armholecurveback/en.md
new file mode 100644
index 00000000000..6048b1d8f7c
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/armholecurveback/en.md
@@ -0,0 +1,9 @@
+---
+title: "Armhole curve back"
+---
+
+Controls how much the armhole at the back curves towards the center. Higher values expose more of the shoulder.
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/armholecurvefront/en.md b/markdown/org/docs/designs/bibi/options/armholecurvefront/en.md
new file mode 100644
index 00000000000..2a588b6ea34
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/armholecurvefront/en.md
@@ -0,0 +1,9 @@
+---
+title: "Armhole curve front"
+---
+
+Controls how much the armhole at the front curves towards the center. Higher values expose more of the shoulder and upper bust.
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/armholedepth/en.md b/markdown/org/docs/designs/bibi/options/armholedepth/en.md
new file mode 100644
index 00000000000..e1e0860923a
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/armholedepth/en.md
@@ -0,0 +1,6 @@
+---
+title: "Armhole depth"
+---
+
+This option controls the depth of the armhole.
+
diff --git a/markdown/org/docs/designs/bibi/options/armholedropback/en.md b/markdown/org/docs/designs/bibi/options/armholedropback/en.md
new file mode 100644
index 00000000000..faf4434c0ad
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/armholedropback/en.md
@@ -0,0 +1,9 @@
+---
+title: "Armhole drop back"
+---
+
+Controls how much the armhole at the back curves towards the lower spine. Higher values expose more shoulder area and create something like a racer back top.
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/backneckbend/en.md b/markdown/org/docs/designs/bibi/options/backneckbend/en.md
new file mode 100644
index 00000000000..69315963453
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/backneckbend/en.md
@@ -0,0 +1,9 @@
+---
+title: "Back Neckline curvature"
+---
+
+Controls the curvature of the neck opening at the back.
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/backneckcutout/en.md b/markdown/org/docs/designs/bibi/options/backneckcutout/en.md
new file mode 100644
index 00000000000..692344d429e
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/backneckcutout/en.md
@@ -0,0 +1,9 @@
+---
+title: "Back Neckline depth"
+---
+
+Controls the depth of the neck opening at the back. A value of 100% puts the opening on the bust line.
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/bustease/en.md b/markdown/org/docs/designs/bibi/options/bustease/en.md
new file mode 100644
index 00000000000..3e306b3704e
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/bustease/en.md
@@ -0,0 +1,8 @@
+---
+title: "Bust ease"
+---
+
+Controls the amount of ease at the bust. This option fine-tunes the strength of the full bust adjustment (FBA).
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/chestease/en.md b/markdown/org/docs/designs/bibi/options/chestease/en.md
new file mode 100644
index 00000000000..e0b7ead4355
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/chestease/en.md
@@ -0,0 +1,9 @@
+---
+title: "Chest ease"
+---
+
+Controls the amount of ease at your chest
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/cuffease/en.md b/markdown/org/docs/designs/bibi/options/cuffease/en.md
new file mode 100644
index 00000000000..7a692dd5d5e
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/cuffease/en.md
@@ -0,0 +1,9 @@
+---
+title: "Sleeve fullness"
+---
+
+Controls the amount of ease at your sleeve opening.
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/dart/en.md b/markdown/org/docs/designs/bibi/options/dart/en.md
new file mode 100644
index 00000000000..5ca6ab58aff
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/dart/en.md
@@ -0,0 +1,13 @@
+---
+title: "Dart"
+---
+
+If the *HPS to waist front* measurement is larger than the *HPS to waist back* or when a *full bust adjustment* (FBA) affects the side seam, the front part often has a longer side seam than the back part.
+
+This option determines if a bust dart should be created to match lengths. Otherwise, fabric gathering might be used.
+
+This option has no effect if the side seam length difference isn't large enough to warrant a dart.
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/draftforhighbust/en.md b/markdown/org/docs/designs/bibi/options/draftforhighbust/en.md
new file mode 100644
index 00000000000..44dafc588e4
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/draftforhighbust/en.md
@@ -0,0 +1,23 @@
+---
+title: "Bust adjustment"
+---
+
+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.
+
+If you don't enable this option, Tina will essentially be drafted
+for a body without breasts that has the same chest circumference as
+your body with breasts. For people with breasts, this will cause a
+bunch of extra fabric at the chest and armholes that will make the
+top look like a poor fit.
+
+There is usually no need to disable this option. It will have little effect on people
+with smaller busts or no breasts.
+
+
+When the optional bust related measurements are not available, no FBA will be performed and this option has no effect.
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/en.md b/markdown/org/docs/designs/bibi/options/en.md
new file mode 100644
index 00000000000..f1ec1e11401
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/en.md
@@ -0,0 +1,5 @@
+---
+title: "Bibi Body Block: Design Options"
+---
+
+
diff --git a/markdown/org/docs/designs/bibi/options/fitwaist/en.md b/markdown/org/docs/designs/bibi/options/fitwaist/en.md
new file mode 100644
index 00000000000..9dbc148dc0a
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/fitwaist/en.md
@@ -0,0 +1,10 @@
+---
+title: "Fit the waist"
+---
+
+Enable this option to fit the waist of your Teagan, rather than draft a straight T-shirt shape.
+
+This will yield best results for those with a smaller waist who are looking for a more hourglass-shaped fitted T-shirt.
+
+If your waist is larger than your hips, you should not enable this option as you may end up with a T-shirt that you can't get in to.
+
diff --git a/markdown/org/docs/designs/bibi/options/flare/en.md b/markdown/org/docs/designs/bibi/options/flare/en.md
new file mode 100644
index 00000000000..2afbda7727b
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/flare/en.md
@@ -0,0 +1,11 @@
+---
+title: "Flare"
+---
+
+If the garment is longer than the seat, this option controls how much it flares out towards the hem.
+
+In other words, this option controls how wide the bottom hem is around the legs.
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/hipsease/en.md b/markdown/org/docs/designs/bibi/options/hipsease/en.md
new file mode 100644
index 00000000000..6459a46826f
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/hipsease/en.md
@@ -0,0 +1,9 @@
+---
+title: "Hips ease"
+---
+
+Controls the amount of ease at the hips.
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/length/en.md b/markdown/org/docs/designs/bibi/options/length/en.md
new file mode 100644
index 00000000000..8bb6516d476
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/length/en.md
@@ -0,0 +1,13 @@
+---
+title: "Length"
+---
+
+Which measurement to use for the hem. Of the length bonus is zero, the bottom of the garment will be at exactly the selected measurement.
+
+Note that the options *underbust*, *knee* and *floor* require the corresponding optional vertical measurements.
+If they are missing, a very rough estimate is used instead.
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/lengthbonus/en.md b/markdown/org/docs/designs/bibi/options/lengthbonus/en.md
new file mode 100644
index 00000000000..34d8e6d1d11
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/lengthbonus/en.md
@@ -0,0 +1,6 @@
+---
+title: "Length bonus"
+---
+
+Fine-tune the length of the garment. A negative value decreases the length, a positive value increases it.
+
diff --git a/markdown/org/docs/designs/bibi/options/necklinebend/en.md b/markdown/org/docs/designs/bibi/options/necklinebend/en.md
new file mode 100644
index 00000000000..d6b68b88000
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/necklinebend/en.md
@@ -0,0 +1,9 @@
+---
+title: "Front Neckline curvature"
+---
+
+Controls the curvature of the neck opening on the front.
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/necklinedepth/en.md b/markdown/org/docs/designs/bibi/options/necklinedepth/en.md
new file mode 100644
index 00000000000..76c80e96a4f
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/necklinedepth/en.md
@@ -0,0 +1,9 @@
+---
+title: "Front Neckline depth"
+---
+
+Controls the depth of the neck opening at the front. A value of 100% puts the opening on the bust line.
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/necklinewidth/en.md b/markdown/org/docs/designs/bibi/options/necklinewidth/en.md
new file mode 100644
index 00000000000..40accc8b415
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/necklinewidth/en.md
@@ -0,0 +1,9 @@
+---
+title: "Neckline width"
+---
+
+Controls the width of the neck opening.
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/seatease/en.md b/markdown/org/docs/designs/bibi/options/seatease/en.md
new file mode 100644
index 00000000000..c98e2580ee1
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/seatease/en.md
@@ -0,0 +1,9 @@
+---
+title: "Seat ease"
+---
+
+Controls the amount of ease at your seat.
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/shoulderease/en.md b/markdown/org/docs/designs/bibi/options/shoulderease/en.md
new file mode 100644
index 00000000000..b2814554e60
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/shoulderease/en.md
@@ -0,0 +1,15 @@
+---
+title: "Shoulder ease"
+---
+
+
+
+Controls the amount of ease on the shoulder to shoulder measurement.
+
+This option allows you to create some extra ease at the shoulders which shifts
+the shoulder seam more outwards and off the shoulder. Thereby creating extra room
+for extra layers of clothing underneath, or more shaped/padded shoulders.
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/shoulderease/shoulderease.svg b/markdown/org/docs/designs/bibi/options/shoulderease/shoulderease.svg
new file mode 100644
index 00000000000..76ec6a215da
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/shoulderease/shoulderease.svg
@@ -0,0 +1,151 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/shoulderslopereduction/en.md b/markdown/org/docs/designs/bibi/options/shoulderslopereduction/en.md
new file mode 100644
index 00000000000..52e9c1647af
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/shoulderslopereduction/en.md
@@ -0,0 +1,9 @@
+---
+title: Shoulder slope reduction
+---
+
+The amount by which the shoulder slope is reduced to allow for shoulder padding.
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecap.svg b/markdown/org/docs/designs/bibi/options/sleevecap.svg
new file mode 100644
index 00000000000..34eca409502
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecap.svg
@@ -0,0 +1,446 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapanchor.svg b/markdown/org/docs/designs/bibi/options/sleevecapanchor.svg
new file mode 100644
index 00000000000..802276f7e75
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapanchor.svg
@@ -0,0 +1,559 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapbackfactorx/en.md b/markdown/org/docs/designs/bibi/options/sleevecapbackfactorx/en.md
new file mode 100644
index 00000000000..c12dfb00030
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapbackfactorx/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap back X"
+---
+
+
+
+This option controls the horizontal placement of the sleevecap inflection point at the back of the sleeve.
+
+
+
+See [understanding the sleevecap](/docs/designs/brian/options#understanding-the-sleevecap) for an in-depth
+look into how the sleevecap is constructed and the influence of the different options on its shape.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapbackfactorx/sleevecapbackfactorx.svg b/markdown/org/docs/designs/bibi/options/sleevecapbackfactorx/sleevecapbackfactorx.svg
new file mode 100644
index 00000000000..5e8e35dd35c
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapbackfactorx/sleevecapbackfactorx.svg
@@ -0,0 +1,467 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapbackfactory/en.md b/markdown/org/docs/designs/bibi/options/sleevecapbackfactory/en.md
new file mode 100644
index 00000000000..83256c51581
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapbackfactory/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap back Y"
+---
+
+
+
+This option controls the vertical placement of the sleevecap inflection point at the back of the sleeve.
+
+
+
+See [understanding the sleevecap](/docs/designs/brian/options#understanding-the-sleevecap) for an in-depth
+look into how the sleevecap is constructed and the influence of the different options on its shape.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapbackfactory/sleevecapbackfactory.svg b/markdown/org/docs/designs/bibi/options/sleevecapbackfactory/sleevecapbackfactory.svg
new file mode 100644
index 00000000000..8348fbf7c7f
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapbackfactory/sleevecapbackfactory.svg
@@ -0,0 +1,467 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapease/en.md b/markdown/org/docs/designs/bibi/options/sleevecapease/en.md
new file mode 100644
index 00000000000..031e7c144da
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapease/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap ease"
+---
+
+Determines the amount of sleevecap ease.
+
+
+
+The amount of sleevecap ease determines how the sleeves rolls from the shoulder.
+More ease makes the sleeve curl into the seam as you see on suit jackets. Less ease makes the sleeve lie flat.
+
+For light fabric or knits, you want little to no sleevecap ease. For heavier woven fabrics, you need more sleevecap ease.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapfrontfactorx/en.md b/markdown/org/docs/designs/bibi/options/sleevecapfrontfactorx/en.md
new file mode 100644
index 00000000000..96c896135c7
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapfrontfactorx/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap front X"
+---
+
+
+
+This option controls the horizontal placement of the sleevecap inflection point at the front of the sleeve.
+
+
+
+See [understanding the sleevecap](/docs/designs/brian/options#understanding-the-sleevecap) for an in-depth
+look into how the sleevecap is constructed and the influence of the different options on its shape.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapfrontfactorx/sleevecapfrontfactorx.svg b/markdown/org/docs/designs/bibi/options/sleevecapfrontfactorx/sleevecapfrontfactorx.svg
new file mode 100644
index 00000000000..d58c9899afb
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapfrontfactorx/sleevecapfrontfactorx.svg
@@ -0,0 +1,467 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapfrontfactory/en.md b/markdown/org/docs/designs/bibi/options/sleevecapfrontfactory/en.md
new file mode 100644
index 00000000000..92fde59d505
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapfrontfactory/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap front Y"
+---
+
+
+
+This option controls the vertical placement of the sleevecap inflection point at the front of the sleeve.
+
+
+
+See [understanding the sleevecap](/docs/designs/brian/options#understanding-the-sleevecap) for an in-depth
+look into how the sleevecap is constructed and the influence of the different options on its shape.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapfrontfactory/sleevecapfrontfactory.svg b/markdown/org/docs/designs/bibi/options/sleevecapfrontfactory/sleevecapfrontfactory.svg
new file mode 100644
index 00000000000..e09d00f3d0f
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapfrontfactory/sleevecapfrontfactory.svg
@@ -0,0 +1,467 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapinflection.svg b/markdown/org/docs/designs/bibi/options/sleevecapinflection.svg
new file mode 100644
index 00000000000..f53517d2a1c
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapinflection.svg
@@ -0,0 +1,538 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq1offset/en.md b/markdown/org/docs/designs/bibi/options/sleevecapq1offset/en.md
new file mode 100644
index 00000000000..a23d5d81997
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq1offset/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap Q1 offset"
+---
+
+
+
+This option controls the offset in the first quadrant of the sleevecap.
+
+
+
+See [understanding the sleevecap](/docs/designs/brian/options#understanding-the-sleevecap) for an in-depth
+look into how the sleevecap is constructed and the influence of the different options on its shape.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq1offset/sleevecapq1offset.svg b/markdown/org/docs/designs/bibi/options/sleevecapq1offset/sleevecapq1offset.svg
new file mode 100644
index 00000000000..f0a2d726ec9
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq1offset/sleevecapq1offset.svg
@@ -0,0 +1,480 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq1spread1/en.md b/markdown/org/docs/designs/bibi/options/sleevecapq1spread1/en.md
new file mode 100644
index 00000000000..61971038860
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq1spread1/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap Q1 downward spread"
+---
+
+
+
+This option controls the downward spread in the first quadrant of the sleevecap.
+
+
+
+See [understanding the sleevecap](/docs/designs/brian/options#understanding-the-sleevecap) for an in-depth
+look into how the sleevecap is constructed and the influence of the different options on its shape.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq1spread1/sleevecapq1downwardspread.svg b/markdown/org/docs/designs/bibi/options/sleevecapq1spread1/sleevecapq1downwardspread.svg
new file mode 100644
index 00000000000..6914bc68fa8
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq1spread1/sleevecapq1downwardspread.svg
@@ -0,0 +1,480 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq1spread2/en.md b/markdown/org/docs/designs/bibi/options/sleevecapq1spread2/en.md
new file mode 100644
index 00000000000..a863495b88f
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq1spread2/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap Q1 upward spread"
+---
+
+
+
+This option controls the upward spread in the first quadrant of the sleevecap.
+
+
+
+See [understanding the sleevecap](/docs/designs/brian/options#understanding-the-sleevecap) for an in-depth
+look into how the sleevecap is constructed and the influence of the different options on its shape.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq1spread2/sleevecapq1spread2.svg b/markdown/org/docs/designs/bibi/options/sleevecapq1spread2/sleevecapq1spread2.svg
new file mode 100644
index 00000000000..f369a220f5e
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq1spread2/sleevecapq1spread2.svg
@@ -0,0 +1,480 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq2offset/en.md b/markdown/org/docs/designs/bibi/options/sleevecapq2offset/en.md
new file mode 100644
index 00000000000..f5aedcee381
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq2offset/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap Q2 offset"
+---
+
+
+
+This option controls the offset in the second quadrant of the sleevecap.
+
+
+
+See [understanding the sleevecap](/docs/designs/brian/options#understanding-the-sleevecap) for an in-depth
+look into how the sleevecap is constructed and the influence of the different options on its shape.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq2offset/sleevecapq2offset.svg b/markdown/org/docs/designs/bibi/options/sleevecapq2offset/sleevecapq2offset.svg
new file mode 100644
index 00000000000..dcc88d098f0
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq2offset/sleevecapq2offset.svg
@@ -0,0 +1,480 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq2spread1/en.md b/markdown/org/docs/designs/bibi/options/sleevecapq2spread1/en.md
new file mode 100644
index 00000000000..2e1961af6f1
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq2spread1/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap Q2 downward spread"
+---
+
+
+
+This option controls the downward spread in the second quadrant of the sleevecap.
+
+
+
+See [understanding the sleevecap](/docs/designs/brian/options#understanding-the-sleevecap) for an in-depth
+look into how the sleevecap is constructed and the influence of the different options on its shape.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq2spread1/sleevecapq2spread1.svg b/markdown/org/docs/designs/bibi/options/sleevecapq2spread1/sleevecapq2spread1.svg
new file mode 100644
index 00000000000..5197ed0114a
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq2spread1/sleevecapq2spread1.svg
@@ -0,0 +1,480 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq2spread2/en.md b/markdown/org/docs/designs/bibi/options/sleevecapq2spread2/en.md
new file mode 100644
index 00000000000..96171f54555
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq2spread2/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap Q2 upward spread"
+---
+
+
+
+This option controls the upward spread in the second quadrant of the sleevecap.
+
+
+
+See [understanding the sleevecap](/docs/designs/brian/options#understanding-the-sleevecap) for an in-depth
+look into how the sleevecap is constructed and the influence of the different options on its shape.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq2spread2/sleevecapq2spread2.svg b/markdown/org/docs/designs/bibi/options/sleevecapq2spread2/sleevecapq2spread2.svg
new file mode 100644
index 00000000000..222d43e460d
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq2spread2/sleevecapq2spread2.svg
@@ -0,0 +1,480 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq3offset/en.md b/markdown/org/docs/designs/bibi/options/sleevecapq3offset/en.md
new file mode 100644
index 00000000000..adb1d715812
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq3offset/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap Q3 offset"
+---
+
+
+
+This option controls the offset in the third quadrant of the sleevecap.
+
+
+
+See [understanding the sleevecap](/docs/designs/brian/options#understanding-the-sleevecap) for an in-depth
+look into how the sleevecap is constructed and the influence of the different options on its shape.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq3offset/sleevecapq3offset.svg b/markdown/org/docs/designs/bibi/options/sleevecapq3offset/sleevecapq3offset.svg
new file mode 100644
index 00000000000..ac048c72247
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq3offset/sleevecapq3offset.svg
@@ -0,0 +1,480 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq3spread1/en.md b/markdown/org/docs/designs/bibi/options/sleevecapq3spread1/en.md
new file mode 100644
index 00000000000..f29493ea1b8
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq3spread1/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap Q3 upward spread"
+---
+
+
+
+This option controls the upward spread in the third quadrant of the sleevecap.
+
+
+
+See [understanding the sleevecap](/docs/designs/brian/options#understanding-the-sleevecap) for an in-depth
+look into how the sleevecap is constructed and the influence of the different options on its shape.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq3spread1/sleevecapq3spread1.svg b/markdown/org/docs/designs/bibi/options/sleevecapq3spread1/sleevecapq3spread1.svg
new file mode 100644
index 00000000000..1649c2c5cc9
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq3spread1/sleevecapq3spread1.svg
@@ -0,0 +1,481 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq3spread2/en.md b/markdown/org/docs/designs/bibi/options/sleevecapq3spread2/en.md
new file mode 100644
index 00000000000..99406d19d55
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq3spread2/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap Q3 downward spread"
+---
+
+
+
+This option controls the downward spread in the third quadrant of the sleevecap.
+
+
+
+See [understanding the sleevecap](/docs/designs/brian/options#understanding-the-sleevecap) for an in-depth
+look into how the sleevecap is constructed and the influence of the different options on its shape.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq3spread2/sleevecapq3spread2.svg b/markdown/org/docs/designs/bibi/options/sleevecapq3spread2/sleevecapq3spread2.svg
new file mode 100644
index 00000000000..79135108ba0
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq3spread2/sleevecapq3spread2.svg
@@ -0,0 +1,481 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq4offset/en.md b/markdown/org/docs/designs/bibi/options/sleevecapq4offset/en.md
new file mode 100644
index 00000000000..d4a69cf4b20
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq4offset/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap Q4 offset"
+---
+
+
+
+This option controls the offset in the fourth quadrant of the sleevecap.
+
+
+
+See [understanding the sleevecap](/docs/designs/brian/options#understanding-the-sleevecap) for an in-depth
+look into how the sleevecap is constructed and the influence of the different options on its shape.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq4offset/sleevecapq4offset.svg b/markdown/org/docs/designs/bibi/options/sleevecapq4offset/sleevecapq4offset.svg
new file mode 100644
index 00000000000..b5877e2c0a1
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq4offset/sleevecapq4offset.svg
@@ -0,0 +1,480 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq4spread1/en.md b/markdown/org/docs/designs/bibi/options/sleevecapq4spread1/en.md
new file mode 100644
index 00000000000..f8f0af0009e
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq4spread1/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap Q4 upward spread"
+---
+
+
+
+This option controls the upward spread in the fourth quadrant of the sleevecap.
+
+
+
+See [understanding the sleevecap](/docs/designs/brian/options#understanding-the-sleevecap) for an in-depth
+look into how the sleevecap is constructed and the influence of the different options on its shape.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq4spread1/sleevecapq4spread1.svg b/markdown/org/docs/designs/bibi/options/sleevecapq4spread1/sleevecapq4spread1.svg
new file mode 100644
index 00000000000..42f42a721fe
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq4spread1/sleevecapq4spread1.svg
@@ -0,0 +1,481 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq4spread2/en.md b/markdown/org/docs/designs/bibi/options/sleevecapq4spread2/en.md
new file mode 100644
index 00000000000..3e589fdb6e3
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq4spread2/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap Q4 downward spread"
+---
+
+
+
+This option controls the downward spread in the fourth quadrant of the sleevecap.
+
+
+
+See [understanding the sleevecap](/docs/designs/brian/options#understanding-the-sleevecap) for an in-depth
+look into how the sleevecap is constructed and the influence of the different options on its shape.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapq4spread2/sleevecapq4spread2.svg b/markdown/org/docs/designs/bibi/options/sleevecapq4spread2/sleevecapq4spread2.svg
new file mode 100644
index 00000000000..b84e4d0c6c7
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapq4spread2/sleevecapq4spread2.svg
@@ -0,0 +1,481 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecapspread.svg b/markdown/org/docs/designs/bibi/options/sleevecapspread.svg
new file mode 100644
index 00000000000..9878d2f0943
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecapspread.svg
@@ -0,0 +1,584 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecaptop.svg b/markdown/org/docs/designs/bibi/options/sleevecaptop.svg
new file mode 100644
index 00000000000..39e7bb71c33
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecaptop.svg
@@ -0,0 +1,488 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecaptopfactorx/en.md b/markdown/org/docs/designs/bibi/options/sleevecaptopfactorx/en.md
new file mode 100644
index 00000000000..186708c88d1
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecaptopfactorx/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap top X"
+---
+
+
+
+This option controls the horizontal placement of the sleevecap top.
+
+
+
+See [understanding the sleevecap](/docs/designs/brian/options#understanding-the-sleevecap) for an in-depth
+look into how the sleevecap is constructed and the influence of the different options on its shape.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecaptopfactorx/sleevecaptopfactorx.svg b/markdown/org/docs/designs/bibi/options/sleevecaptopfactorx/sleevecaptopfactorx.svg
new file mode 100644
index 00000000000..be96935d057
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecaptopfactorx/sleevecaptopfactorx.svg
@@ -0,0 +1,467 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecaptopfactory/en.md b/markdown/org/docs/designs/bibi/options/sleevecaptopfactory/en.md
new file mode 100644
index 00000000000..e8a90d56241
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecaptopfactory/en.md
@@ -0,0 +1,18 @@
+---
+title: "Sleevecap top Y"
+---
+
+
+
+This option controls the vertical placement of the sleevecap top.
+
+
+
+See [understanding the sleevecap](/docs/designs/brian/options#understanding-the-sleevecap) for an in-depth
+look into how the sleevecap is constructed and the influence of the different options on its shape.
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevecaptopfactory/sleevecaptopfactory.svg b/markdown/org/docs/designs/bibi/options/sleevecaptopfactory/sleevecaptopfactory.svg
new file mode 100644
index 00000000000..cd55923d35e
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevecaptopfactory/sleevecaptopfactory.svg
@@ -0,0 +1,467 @@
+
+
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+ 2
+
+
+
+ 3
+
+
+
+ 4
+
+
+
+ 5
+
+
+
+ 6
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleeveease/en.md b/markdown/org/docs/designs/bibi/options/sleeveease/en.md
new file mode 100644
index 00000000000..7df18f6546c
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleeveease/en.md
@@ -0,0 +1,9 @@
+---
+title: "Sleeve ease"
+---
+
+Controls the amount of ease at the sleeve/your arm.
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleevelength/en.md b/markdown/org/docs/designs/bibi/options/sleevelength/en.md
new file mode 100644
index 00000000000..35c511bbb30
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleevelength/en.md
@@ -0,0 +1,9 @@
+---
+title: "Sleeve length"
+---
+
+Controls the length of the sleeves.
+
+
+
+
diff --git a/markdown/org/docs/designs/bibi/options/sleeves/en.md b/markdown/org/docs/designs/bibi/options/sleeves/en.md
new file mode 100644
index 00000000000..3341d51de89
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/sleeves/en.md
@@ -0,0 +1,5 @@
+---
+title: "Sleeves"
+---
+
+Weather to create a pattern with sleeves or not. If sleeves are enables, sleeve lengths above 5% will create normal set-in sleeves. Lengths below 5% will create cap/dolman sleeves.
diff --git a/markdown/org/docs/designs/bibi/options/strapwidth/en.md b/markdown/org/docs/designs/bibi/options/strapwidth/en.md
new file mode 100644
index 00000000000..291ab7d6e08
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/strapwidth/en.md
@@ -0,0 +1,5 @@
+---
+title: "Strap width"
+---
+
+If sleeves are disables, use this to control the width of the shoulder straps
diff --git a/markdown/org/docs/designs/bibi/options/waistease/en.md b/markdown/org/docs/designs/bibi/options/waistease/en.md
new file mode 100644
index 00000000000..31c561b915a
--- /dev/null
+++ b/markdown/org/docs/designs/bibi/options/waistease/en.md
@@ -0,0 +1,7 @@
+---
+title: "Waist ease"
+---
+
+If (and only if) you request to [fit the waist](/docs/designs/teagan/options/curvetowaist), this option allows you to control the amount of ease at the waist.
+
+If the waist is not fitted, this option is disabled.
diff --git a/markdown/org/docs/designs/charlie/cutting/en.md b/markdown/org/docs/designs/charlie/cutting/en.md
index 4753fde2c14..45cfd813e4a 100644
--- a/markdown/org/docs/designs/charlie/cutting/en.md
+++ b/markdown/org/docs/designs/charlie/cutting/en.md
@@ -9,7 +9,7 @@ title: "Charlie chinos: Cutting Instructions"
- Part **4**: **4 x**
- Part **6**: **2 x**
- Part **8**: **4 x** (2 pairs _with good sides together_)
-- Part **9**: **2 x** _with good sides together_
+- Part **9**: **1 x**
- Part **10**: **1 x** on the fold
- Part **11**: **1 x** if making a straight waistband
- Part **11**: **2 x** _with good sides together_ if making a curved waistband
diff --git a/markdown/org/docs/designs/cornelius/instructions/de.md b/markdown/org/docs/designs/cornelius/instructions/de.md
index 7160c2eff26..5ab65df07d8 100644
--- a/markdown/org/docs/designs/cornelius/instructions/de.md
+++ b/markdown/org/docs/designs/cornelius/instructions/de.md
@@ -7,7 +7,7 @@ title: "Cornelius Radlerhosen: Anleitung zum Nähen"
- Press under the seam allowances of the non-notched edges of the pocket facings.
- Stecke die linke Seite der Taschenbespannung an die rechte Seite der Taschenbeutel, _Kantenstich_ die gefalteten Kanten an die Taschenbeutel.
- _Hefte_ die Nahtzugaben der eingekerbten Kanten der Taschenbesetzungen an die Taschenbeutel.
-- Nähe die Taschenbeutel rechts auf rechts an die Vorderseite und bügle sie dann auf die linke Seite.
+- With right sides together, matching both notches, sew the pocket bags to the front and then press to the wrong side.
- Falte die Taschen entlang der Falzlinie in der Mitte und lege sie rechtsherum zusammen. Nähen Sie den Boden des Taschenbeutels zusammen.
- Alternativ kannst du _French Seam_ die Bodennähte der Taschenbeutel zusammennähen, wenn du das möchtest.
- _Baste_ the top and side of the pocket bags to the front seam allowances matching notches.
diff --git a/markdown/org/docs/designs/cornelius/instructions/en.md b/markdown/org/docs/designs/cornelius/instructions/en.md
index c9c3daf9040..4ed08688a0d 100644
--- a/markdown/org/docs/designs/cornelius/instructions/en.md
+++ b/markdown/org/docs/designs/cornelius/instructions/en.md
@@ -7,7 +7,7 @@ title: "Cornelius cycling breeches: Sewing Instructions"
- Press under the seam allowances of the non-notched edges of the pocket facings.
- Matching notches, pin the wrong sides of pocket facings to right side of pocket bags, _Edgestitch_ the folded edges to the pocket bags.
- _Baste_ the seam allowances of the notched edges of the pocket facings to the pocket bags.
-- With right sides together matching double notches sew the pocket bags to the front and then press to the wrong side.
+- With right sides together, matching both notches, sew the pocket bags to the front and then press to the wrong side.
- Fold the pockets in half along the fold line, right sides together. Stitch the bottom of the pocket bag together.
- Alternatively you can _French Seam_ the bottom seams of the pocket bags together if you prefer.
- _Baste_ the top and side of the pocket bags to the front seam allowances matching notches.
diff --git a/markdown/org/docs/designs/cornelius/instructions/es.md b/markdown/org/docs/designs/cornelius/instructions/es.md
index 14936f1d551..3d23f381585 100644
--- a/markdown/org/docs/designs/cornelius/instructions/es.md
+++ b/markdown/org/docs/designs/cornelius/instructions/es.md
@@ -7,7 +7,7 @@ title: "Pantalones de ciclista Cornelius: Instrucciones de costura"
- Press under the seam allowances of the non-notched edges of the pocket facings.
- Haciendo coincidir las muescas, sujeta con alfileres los lados equivocados de los revestimientos de los bolsillos al lado derecho de las bolsas de bolsillo, _Edgestitch_ los bordes doblados a las bolsas de bolsillo.
- _Hilvana_ los márgenes de costura de los bordes dentados de las carátulas de los bolsillos a las bolsas de los bolsillos.
-- Con los lados derechos juntos haciendo coincidir las muescas dobles, cose las bolsas de bolsillo a la parte delantera y luego presiona hacia el lado equivocado.
+- With right sides together, matching both notches, sew the pocket bags to the front and then press to the wrong side.
- Dobla los bolsillos por la mitad siguiendo la línea de pliegue, con los lados derechos juntos. Cose el fondo de la bolsa de bolsillo.
- Si lo prefieres, puedes unir las costuras inferiores de las bolsas con la _costura francesa_.
- _Baste_ the top and side of the pocket bags to the front seam allowances matching notches.
diff --git a/markdown/org/docs/designs/cornelius/instructions/fr.md b/markdown/org/docs/designs/cornelius/instructions/fr.md
index cce5e1d0291..c956836a7e6 100644
--- a/markdown/org/docs/designs/cornelius/instructions/fr.md
+++ b/markdown/org/docs/designs/cornelius/instructions/fr.md
@@ -7,7 +7,7 @@ title: "Culotte de cycliste Cornélius : Instructions de couture"
- Pliez et repassez les marges de coutures des bords non crantés des parements de poche.
- En faisant correspondre les encoches, épinglez l'envers des parements de poche sur l'endroit des sacs de poche, _surpiquez_ les bords pliés sur les sacs de poche.
- _Bâtir_ les marges de couture des bords crantés des parements de poche sur les sacs de poche.
-- Endroit contre endroit, en faisant correspondre les doubles encoches, coudre les poches sur le devant, puis repasser sur l'envers.
+- Endroit contre endroit, en faisant correspondre les deux encoches, coudre les poches sur le devant, puis repasser sur l'envers.
- Pliez les poches en deux le long de la ligne de pliage, endroit contre endroit. Coudre le fond du sac de poche ensemble.
- Si vous préférez, vous pouvez également faire une _couture anglaise_ pour coudre ensemble le bas des sacs de poches.
- _Bâtir_ le haut et le côté du sac de poche aux marges de couture de l'avant en faisant coïncider les crans.
diff --git a/markdown/org/docs/designs/cornelius/instructions/nl.md b/markdown/org/docs/designs/cornelius/instructions/nl.md
index 28ce7e05ddf..3a8ccee2bab 100644
--- a/markdown/org/docs/designs/cornelius/instructions/nl.md
+++ b/markdown/org/docs/designs/cornelius/instructions/nl.md
@@ -7,7 +7,7 @@ title: "Cornelius fietsbroek: Naai-instructies"
- Press under the seam allowances of the non-notched edges of the pocket facings.
- Speld de verkeerde kanten van de zakvullingen op de goede kant van de zakvullingen met dezelfde inkepingen, _Edgestitch_ de gevouwen randen op de zakvullingen.
- _Rijg_ de naadtoeslagen van de gekerfde randen van de zakvullingen aan de zakzakken.
-- Met de goede kanten op elkaar en de dubbele inkepingen naai je de zakjes aan de voorkant en pers je ze naar de verkeerde kant.
+- With right sides together, matching both notches, sew the pocket bags to the front and then press to the wrong side.
- Vouw de zakken dubbel langs de vouwlijn, goede kanten op elkaar. Naai de onderkant van de zak aan elkaar.
- Je kunt ook _Franse naad_ de onderste naden van de zakjes aan elkaar naaien als je dat liever doet.
- _Baste_ the top and side of the pocket bags to the front seam allowances matching notches.
diff --git a/markdown/org/docs/designs/cornelius/instructions/uk.md b/markdown/org/docs/designs/cornelius/instructions/uk.md
index b6cbdd3d73d..c6fd937ef4c 100644
--- a/markdown/org/docs/designs/cornelius/instructions/uk.md
+++ b/markdown/org/docs/designs/cornelius/instructions/uk.md
@@ -7,7 +7,7 @@ title: "Велосипедні бриджі Cornelius: Інструкція з
- Press under the seam allowances of the non-notched edges of the pocket facings.
- Сумістивши надсічки, приколіть виворітні сторони обшивок кишень до правого боку кишенькових мішків, _приметайте_ підігнуті краї до кишенькових мішків.
- _Приметайте_ припуски на шви надсічених країв обшивок кишень до мішковин кишень.
-- Лицьовими боками до лицьових боків, сумістивши подвійні надсічки, пришийте кишеньки до лицьового боку, а потім припрасуйте на виворітний бік.
+- With right sides together, matching both notches, sew the pocket bags to the front and then press to the wrong side.
- Складіть кишені навпіл по лінії згину лицьовими боками разом. Зшийте дно кишенькової сумки.
- Також ви можете _французький шов_ нижні шви кишенькових сумок разом, якщо бажаєте.
- _Baste_ the top and side of the pocket bags to the front seam allowances matching notches.
diff --git a/markdown/org/docs/designs/gozer/cutting/fr.md b/markdown/org/docs/designs/gozer/cutting/fr.md
index 5cf39f448ae..4ab05e332d2 100644
--- a/markdown/org/docs/designs/gozer/cutting/fr.md
+++ b/markdown/org/docs/designs/gozer/cutting/fr.md
@@ -1,6 +1,6 @@
---
-title: "Gozer le fantôme : Instructions de découpage"
+title: "Gozer le fantôme : Instructions de coupe"
---
- **Couleur 1 ; traditionnellement blanc**
- - Cut **1 Body (color 1)**
+ - Coupe **1 Corps**
diff --git a/markdown/org/docs/designs/gozer/fr.md b/markdown/org/docs/designs/gozer/fr.md
index 18bd55e2700..8ede6bdf990 100644
--- a/markdown/org/docs/designs/gozer/fr.md
+++ b/markdown/org/docs/designs/gozer/fr.md
@@ -2,9 +2,9 @@
title: Gozer le fantôme
---
-Not quite sure what to say about this. It was three weeks or so before Halloween, and I was working on a different pattern. Then the thought of a traditional ghost costume popped into my head.
+Je ne sais pas trop quoi dire à ce sujet. C'était environ trois semaines avant Halloween, et j'étais en train de travailler sur un autre modèle. Then the thought of a traditional ghost costume popped into my head.
-So as a joke I made this, just so I could post it on the discord server. And then Joost asked where the pattern was. So I posted it. And he published it.
+Alors pour plaisanter, j'ai fait ceci, juste pour pouvoir le poster sur le serveur discord. Puis Joost a demandé où se trouvait le patron. Je l'ai donc posté. Et il l'a publié.
Wouter
diff --git a/markdown/org/docs/designs/gozer/instructions/fr.md b/markdown/org/docs/designs/gozer/instructions/fr.md
index a204c9fd246..0dcdbec0e41 100644
--- a/markdown/org/docs/designs/gozer/instructions/fr.md
+++ b/markdown/org/docs/designs/gozer/instructions/fr.md
@@ -8,7 +8,7 @@ title: "Gozer le fantôme : Instructions de couture"
## Étape 2 : Le corps
-- Ourle le corps
+- Fais un ourlet sur le corps
## Étape 3: Profitez-en!
diff --git a/markdown/org/docs/designs/gozer/notes/fr.md b/markdown/org/docs/designs/gozer/notes/fr.md
index ec1b5caa91d..32072c27cbd 100644
--- a/markdown/org/docs/designs/gozer/notes/fr.md
+++ b/markdown/org/docs/designs/gozer/notes/fr.md
@@ -2,5 +2,5 @@
title: "Gozer le fantôme : Notes du concepteur"
---
-The designer, nor FreeSewing, are liable for anything that follows the use of this pattern. You've been warned.
+Ni la créatrice, ni FreeSewing, ne sont responsables de ce qui suit l'utilisation de ce modèle. Vous êtes prévenu.
diff --git a/markdown/org/docs/designs/onyx/instructions/fr.md b/markdown/org/docs/designs/onyx/instructions/fr.md
index 4f97954f383..1ea50b2c1d7 100644
--- a/markdown/org/docs/designs/onyx/instructions/fr.md
+++ b/markdown/org/docs/designs/onyx/instructions/fr.md
@@ -59,7 +59,7 @@ Décide de couper les pièces du devant et/ou du dos _sur le pli_:
- Pour les combinaisons, coupe le dos _sur le pli_ si tu fais une combinaison avec fermeture à glissière sur le devant, ou le devant _sur le pli_ si tu fais une combinaison avec fermeture à glissière sur le dos (3 pièces au total).
- Pour les pyjamas une pièce, les barboteuses et les combinaisons, coupe seulement le dos _sur le pli_ (3 pièces au total).
-Détermine le type d'ajustement que tu souhaites et règle tes facilités en conséquence. Assure-toi d'avoir un tissu approprié. En cas de doute, il est plus sûr de rendre le vêtement trop lâche que trop serré.
+Détermine le type d'ajustement que tu souhaites et règle l'aisance en conséquence. Assure-toi d'avoir un tissu approprié. En cas de doute, il est plus sûr de rendre le vêtement trop lâche que trop serré.
- Pour les combinaisons et les justaucorps, tu veux une aisance négative. Cela permettra au tissu extensible/de natation de se former autour du corps de la personne qui le porte.
- Pour les pyjamas d'une seule pièce, tu veux une aisance positive et adoucir la forme (c'est-à-dire ajouter de l'aisance aux endroits qui se découpent, comme la taille, pour donner à l'ensemble du vêtement une forme moins ajustée).
- Les grenouillères et les bodys utilisent une aisance positive, la quantité et la répartition de l'aisance variant beaucoup en fonction de la forme prévue du vêtement.
diff --git a/markdown/org/docs/designs/onyx/options/hoodfrontpiecesize/fr.md b/markdown/org/docs/designs/onyx/options/hoodfrontpiecesize/fr.md
index b957fbb46a2..392d2a53ddf 100644
--- a/markdown/org/docs/designs/onyx/options/hoodfrontpiecesize/fr.md
+++ b/markdown/org/docs/designs/onyx/options/hoodfrontpiecesize/fr.md
@@ -3,8 +3,8 @@ title: "Longueur des manches"
---
Contrôle la longueur des manches de ton vêtement.
- - 15 à 30 % d'entre eux feront des manches courtes.
- - 75 % d'entre eux feront des manches trois-quarts.
- - 100 % feront des manches longues, s'arrêtant au poignet.
- - 115% permettra de faire des manches couvrant les articulations, et est approprié si l'on utilise des trous pour les pouces.
+ - 15 à 30 % pour des manches courtes.
+ - 75 % pour des manches trois-quarts.
+ - 100 % pour des manches longues, s'arrêtant au poignet.
+ - 115% permettra de faire des manches couvrant les jointures, et est approprié si l'on utilise des trous pour les pouces.
diff --git a/markdown/org/docs/designs/onyx/options/neckbalance/fr.md b/markdown/org/docs/designs/onyx/options/neckbalance/fr.md
index 54364a4debb..99578e00a97 100644
--- a/markdown/org/docs/designs/onyx/options/neckbalance/fr.md
+++ b/markdown/org/docs/designs/onyx/options/neckbalance/fr.md
@@ -1,5 +1,5 @@
---
-title: "Position du manche"
+title: "Position du cou"
---
Contrôle l'endroit où le trou du cou est placé sur le vêtement. Pour une valeur de 0 %, le centre du trou du cou se trouve exactement à l'endroit où les quatre coutures raglan se croiseraient, les parties avant et arrière étant identiques et la manche étant symétrique. Une valeur positive déplace le cou vers l'avant du vêtement.
diff --git a/markdown/org/docs/designs/onyx/options/sleevelength/fr.md b/markdown/org/docs/designs/onyx/options/sleevelength/fr.md
index b957fbb46a2..392d2a53ddf 100644
--- a/markdown/org/docs/designs/onyx/options/sleevelength/fr.md
+++ b/markdown/org/docs/designs/onyx/options/sleevelength/fr.md
@@ -3,8 +3,8 @@ title: "Longueur des manches"
---
Contrôle la longueur des manches de ton vêtement.
- - 15 à 30 % d'entre eux feront des manches courtes.
- - 75 % d'entre eux feront des manches trois-quarts.
- - 100 % feront des manches longues, s'arrêtant au poignet.
- - 115% permettra de faire des manches couvrant les articulations, et est approprié si l'on utilise des trous pour les pouces.
+ - 15 à 30 % pour des manches courtes.
+ - 75 % pour des manches trois-quarts.
+ - 100 % pour des manches longues, s'arrêtant au poignet.
+ - 115% permettra de faire des manches couvrant les jointures, et est approprié si l'on utilise des trous pour les pouces.
diff --git a/markdown/org/docs/designs/onyx/options/wristease/fr.md b/markdown/org/docs/designs/onyx/options/wristease/fr.md
index bdf338cbd5f..fee1b0688c4 100644
--- a/markdown/org/docs/designs/onyx/options/wristease/fr.md
+++ b/markdown/org/docs/designs/onyx/options/wristease/fr.md
@@ -1,5 +1,5 @@
---
-title: "Facilité du poignet"
+title: "Aisance du poignet"
---
Affecte la largeur de l'extrémité de la manche sur certains vêtements. Il n'y a pas d'effet pour les manches se terminant au niveau du biceps ou au-dessus. Il n'y a pas d'effet pour les manches se terminant au niveau du biceps ou au-dessus.
diff --git a/markdown/org/docs/designs/shelly/instructions/fr.md b/markdown/org/docs/designs/shelly/instructions/fr.md
index bd401c899ff..da73c43fb35 100644
--- a/markdown/org/docs/designs/shelly/instructions/fr.md
+++ b/markdown/org/docs/designs/shelly/instructions/fr.md
@@ -28,24 +28,24 @@ Pour faire des t-shirts ou d'autres chemises avec du tissu extensible dans deux
- Jusqu'à 80 % environ produiront un crop top.
- 100 % descend au sommet de l'os de la hanche.
- 120% produira un t-shirt typique.
- - Avec 140 %, tu obtiendras une chemise un peu plus longue qui aura moins tendance sortir du pantalon ou à remonter.
+ - Avec 140 %, tu obtiendras une chemise un peu plus longue qui aura moins tendance à sortir du pantalon ou à remonter.
- 200%+ peuvent être utilisés pour faire une simple robe t-shirt. Il est suggéré de régler les côtés droits sur faux, et d'ajuster la forme des côtés (dans les options avancées) pour les robes t-shirt.
- En cas de doute, il est beaucoup plus facile de raccourcir une chemise ou une manche que de la rallonger.
- - Détermine le type d'ajustement que tu souhaites et règle tes facilités en conséquence. Assure-toi d'avoir un tissu approprié. En cas de doute, il est plus sûr de rendre la chemise trop lâche que trop serrée.
- - En général, lorsque tu travailles avec de l'élasthanne, tu veux que l'aisance soit négative à 0 %. Lorsque tu travailles avec un tissu de t-shirt ordinaire en coton/polyester, tu veux une aisance positive, à la fois parce que le tissu s'étire moins et parce que les styles typiques utilisant ce tissu sont plus lâches.
+ - Détermine le type d'ajustement que tu souhaites et règle l'aisance en conséquence. Assure-toi d'avoir un tissu approprié. En cas de doute, il est plus sûr de rendre la chemise trop lâche que trop serrée.
+ - En général, lorsque tu travailles avec de l'élasthanne, tu veux que l'aisance soit à 0 % ou négative. Lorsque tu travailles avec un tissu de t-shirt ordinaire en coton/polyester, tu veux une aisance positive, à la fois parce que le tissu s'étire moins et parce que les styles typiques utilisant ce tissu sont plus lâches.
- Les chemises de compression sensorielle seront les plus serrées / auront le plus d'aisance négative.
- Un tissu extensible dans les 4 sens est nécessaire. Le tissu de natation ou un autre tissu très extensible est fortement recommandé.
- - Allègement de la poitrine : -30% à -20%. C'est la partie la plus importante à comprimer à des fins sensorielles, et c'est un endroit relativement sûr pour mettre de la tension.
- - Facilité d'utilisation des manches : -20% à -10%. La compression peut être bénéfique, mais tu ne dois pas serrer au point de couper la circulation.
- - Facilité au poignet : -15% à 0%. La plupart du temps, c'est la préférence.
+ - Aisance de la poitrine : -30% à -20%. C'est la partie la plus importante à comprimer à des fins sensorielles, et c'est un endroit relativement sûr pour mettre de la tension.
+ - Aisance des manches : -20% à -10%. La compression peut être bénéfique, mais tu ne dois pas serrer au point de couper la circulation.
+ - Aisance du poignet : -15% à 0%. La plupart du temps, c'est la préférence.
- Aisance de l'encolure : 25 % à 100 % (25 % correspondra toujours à un tour de cou très serré qui nécessitera un peu d'étirement pour passer sur la tête, en raison de la façon dont le tour de cou est construit et parce que les trous de cou sont généralement un peu plus grands que le cou pour s'adapter à la tête.
- Chemise athlétique
- - L'auteur n'en a pas encore fait. Si quelqu'un sait quelles facilités utiliser, merci de me le faire savoir.
- - Il est recommandé d'utiliser un tissu très respirant avec un peu d'élasthanne/extensible.
+ - L'auteur n'en a pas encore fait. Si quelqu'un sait quelles aisances utiliser, merci de me le faire savoir.
+ - Il est recommandé d'utiliser un tissu très respirant avec un peu d'élasthanne/elasticité.
- Les aisances se situent entre celles d'un maillot de compression et d'un maillot de bain.
@@ -58,13 +58,13 @@ Pour faire des t-shirts ou d'autres chemises avec du tissu extensible dans deux
- T-shirt
- - L'auteur n'en a pas encore fait. Si quelqu'un sait quelles facilités utiliser, merci de me le faire savoir.
- - Les assouplissements seront beaucoup plus importants (plus positifs) que pour les autres types de chemises.
+ - L'auteur n'en a pas encore fait. Si quelqu'un sait quelles aisances utiliser, merci de me le faire savoir.
+ - Les aisances seront beaucoup plus importantes (plus positives) que pour les autres types de chemises.
- Sweatshirt
- - L'auteur n'en a pas encore fait. Si quelqu'un sait quelles facilités utiliser, merci de me le faire savoir.
+ - L'auteur n'en a pas encore fait. Si quelqu'un sait quelles aisances utiliser, merci de me le faire savoir.
- Les aisances seront similaires à celles d'un t-shirt, ou un peu plus grandes.
@@ -78,11 +78,11 @@ Pour faire des t-shirts ou d'autres chemises avec du tissu extensible dans deux
### Étape 2 : Fixer le tour de cou
- Avec _bons côtés ensemble_, plie la bande de cou en deux dans le sens de la longueur (pour qu'elle soit deux fois plus longue) et couds-la pour former une boucle.
-- Avec _endroit contre endroit_, plie la bande de cou en deux dans le sens de la longueur (pour qu'elle soit deux fois plus large).
-- Tourne la chemise _du bon côté_-out
-- Marque les quarts de point sur ton tour de cou avec des épingles à bille, des pinces ou de la craie.
+- _Envers contre envers_, plie la bande de cou en deux dans le sens de la longueur (pour qu'elle soit deux fois moins large).
+- Tourne la chemise _du bon côté_
+- Marque des points aux quarts sur ton tour de cou avec des épingles à bille, des pinces ou de la craie.
- Fais de même autour du trou du cou, en marquant le centre du devant, le centre du dos et les points médians de chaque manche.
-- Avec _bons côtés ensemble_, aligne les bords non finis de la bande de cou avec le bord du trou du cou, et aligne les quarts de points de la bande de cou avec les quarts de points du trou du cou. Étire le tour de cou si nécessaire pour que tous les points s'alignent. Épingle ou clipse le tour de cou autour du trou de l'encolure.
+- Avec _bons côtés ensemble_, aligne les bords non finis de la bande de cou avec le bord du trou du cou, et aligne les points de quarts de la bande de cou avec les points de quarts du trou du cou. Étire le tour de cou si nécessaire pour que tous les points s'alignent. Épingle ou clipse le tour de cou autour du trou de l'encolure.
- Couds soigneusement autour du trou du cou, en veillant à coudre à travers les 3 couches.
- Retourne le tour de cou. Il doit être bien à plat.
@@ -90,9 +90,9 @@ Pour faire des t-shirts ou d'autres chemises avec du tissu extensible dans deux
- Retourne la chemise à l'envers.
- Avec _bons côtés ensemble_, place les pièces avant et arrière ensemble et épingle/clip leurs côtés ensemble.
-- Avec _sur les bons côtés_, ferme la manche et épingle/clip le long de la couture de la manche.
+- Avec _les bons côtés ensemble_, ferme la manche et épingle/clip le long de la couture de la manche.
- Tu dois avoir préparé une couture unique, allant de l'extrémité de la manche à l'ourlet inférieur du corps.
-- Couds-le.
+- Couds-la.
- Répète pour l'autre côté.
### Étape 4 : (Facultatif) Ourlet
diff --git a/markdown/org/docs/designs/shelly/needs/fr.md b/markdown/org/docs/designs/shelly/needs/fr.md
index ba0cb256246..08bb1167705 100644
--- a/markdown/org/docs/designs/shelly/needs/fr.md
+++ b/markdown/org/docs/designs/shelly/needs/fr.md
@@ -6,7 +6,7 @@ Pour fabriquer Shelly, tu auras besoin des éléments suivants :
- Fourniture de base pour la couture
- Entre 0,5 et 2 mètres d'un tissu approprié, selon la taille et le style ([voir les options de tissu](/docs/patterns/shelly/fabric)).
- - Un rash guard à manches courtes pour enfants peut probablement être fabriqué avec 0,5 mètre de tissu restant.
+ - Un rash guard à manches courtes pour enfants peut probablement être fabriqué avec 0,5 mètre de chutes de tissus.
- Un maillot de bain à manches longues ou un t-shirt plus ample pour un adulte de grande taille prendra plus près de 2 mètres.
- Deux couleurs ou imprimés différents de tissu peuvent être utilisés (un pour les manches, un pour le corsage).
- (Facultatif) Tissu côtelé pour le cou, si tu utilises un tissu moins extensible.
diff --git a/markdown/org/docs/designs/shelly/notes/fr.md b/markdown/org/docs/designs/shelly/notes/fr.md
index 5a7d8cdce2b..4e006c47b01 100644
--- a/markdown/org/docs/designs/shelly/notes/fr.md
+++ b/markdown/org/docs/designs/shelly/notes/fr.md
@@ -2,11 +2,11 @@
title: "Maillot de bain Shelly : Notes du créateur"
---
-Shelly est mon premier dessin. Elle est née du besoin de chemises pouvant se comprimer très fortement (pour des besoins sensoriels issus de l'autisme), et de l'absence de chemises prêtes à l'emploi adaptées. Les maillots de bain trop petits sont assez serrés, mais exposent le ventre et pincent au niveau des aisselles, j'ai donc entrepris de concevoir un maillot qui serait à la fois confortable et thérapeutique.
+Shelly est mon premier design. Elle est née du besoin de chemises pouvant se comprimer très fortement (pour des besoins sensoriels issus de l'autisme), et de l'absence de chemises prêtes à l'emploi adaptées. Les maillots de bain trop petits sont assez serrés, mais exposent le ventre et pincent au niveau des aisselles, j'ai donc entrepris de concevoir un maillot qui serait à la fois confortable et thérapeutique.
Les manches raglan sont utilisées pour apporter plus de souplesse et de mobilité au niveau de l'aisselle, et sont très importantes pour les vêtements très serrés.
-Cela dit, Shelly est un modèle simple et polyvalent capable de fabriquer des hauts en tricot sur une large gamme d'eases, des chemises de compression serrées, aux tees raglan amples. Il s'agit d'un excellent premier projet de tricot, car il n'utilise que cinq pièces de tissu coupées à partir de quatre pièces de patron, et présente des coutures simples qui peuvent être entièrement réalisées à l'aide d'une surjeteuse. Elle est également assez tolérante aux petites erreurs de mesure/coupe/couture en raison de la nature élastique des tricots, en particulier du tissu de natation, et de l'absence de caractéristiques fines nécessitant une trop grande attention aux détails sur Shelly.
+Cela dit, Shelly est un modèle simple et polyvalent capable de fabriquer des hauts en tricot sur une large gamme d'aisances, des chemises de compression serrées, aux tee-shirts raglan amples. Il s'agit d'un excellent premier projet de tricot, car il n'utilise que cinq pièces de tissu coupées à partir de quatre pièces de patron, et présente des coutures simples qui peuvent être entièrement réalisées à l'aide d'une surjeteuse. Elle est également assez tolérante aux petites erreurs de mesure/coupe/couture en raison de la nature élastique des tricots, en particulier du tissu de natation, et de l'absence de caractéristiques fines nécessitant une trop grande attention aux détails sur Shelly.
Le nom est choisi parce que j'aime la plage et j'aime les coquillages.
diff --git a/markdown/org/docs/designs/shelly/options/bodylength/fr.md b/markdown/org/docs/designs/shelly/options/bodylength/fr.md
index 61a1c0163ed..494fa5fd94b 100644
--- a/markdown/org/docs/designs/shelly/options/bodylength/fr.md
+++ b/markdown/org/docs/designs/shelly/options/bodylength/fr.md
@@ -6,6 +6,6 @@ Contrôle la longueur de la chemise.
- Jusqu'à 80 % environ produiront un crop top.
- 100 % descend au sommet de l'os de la hanche.
- 120% produira un t-shirt typique.
- - Avec 140 %, tu obtiendras une chemise un peu plus longue qui aura moins tendance sortir du pantalon ou à remonter.
+ - Avec 140 %, tu obtiendras une chemise un peu plus longue qui aura moins tendance à sortir du pantalon ou à remonter.
- 200%+ peuvent être utilisés pour faire une simple robe t-shirt. Il est suggéré de régler les côtés droits sur faux, et d'ajuster la forme des côtés (dans les options avancées) pour les robes t-shirt.
diff --git a/markdown/org/docs/designs/shelly/options/fr.md b/markdown/org/docs/designs/shelly/options/fr.md
index 72af877a25a..f13da58a672 100644
--- a/markdown/org/docs/designs/shelly/options/fr.md
+++ b/markdown/org/docs/designs/shelly/options/fr.md
@@ -1,5 +1,5 @@
---
-title: "Chemise Shelly Options de conception"
+title: "Chemise Shelly : Options de conception"
---
diff --git a/markdown/org/docs/designs/shelly/options/neckbalance/fr.md b/markdown/org/docs/designs/shelly/options/neckbalance/fr.md
index 9fa2e5d8d7b..85b83e43657 100644
--- a/markdown/org/docs/designs/shelly/options/neckbalance/fr.md
+++ b/markdown/org/docs/designs/shelly/options/neckbalance/fr.md
@@ -1,5 +1,5 @@
---
-title: "Position du manche"
+title: "Position du cou"
---
Contrôle l'endroit où le trou du cou est placé sur la chemise. Pour une valeur de 0 %, le centre du trou du cou se trouve exactement à l'endroit où les quatre coutures raglan se croiseraient, les parties avant et arrière étant identiques. Une valeur positive déplace le cou vers l'avant de la chemise.
diff --git a/markdown/org/docs/designs/shelly/options/sideshape/fr.md b/markdown/org/docs/designs/shelly/options/sideshape/fr.md
index 4a45a404f5a..b7855c339db 100644
--- a/markdown/org/docs/designs/shelly/options/sideshape/fr.md
+++ b/markdown/org/docs/designs/shelly/options/sideshape/fr.md
@@ -1,5 +1,5 @@
---
-title: "Forme latérale"
+title: "Forme du côté"
---
Contrôle la façon dont la couture latérale est incurvée. Le zéro crée une ligne droite de l'aisselle au côté des hanches. Les valeurs positives ajoutent de la matière et donnent à la couture latérale une forme arrondie/convexe, tandis que les valeurs négatives enlèvent de la matière et donnent à la couture latérale une forme de sablier/concave. Cette option n'aura aucun effet si l'option "côtés droits" est activée.
diff --git a/markdown/org/docs/designs/shelly/options/sleeveease/fr.md b/markdown/org/docs/designs/shelly/options/sleeveease/fr.md
index 5fd5194a765..d9ef506a9d2 100644
--- a/markdown/org/docs/designs/shelly/options/sleeveease/fr.md
+++ b/markdown/org/docs/designs/shelly/options/sleeveease/fr.md
@@ -2,5 +2,5 @@
title: "Aisance des manches"
---
-Affecte la largeur de la manche à l'emmanchure sur toutes les chemises. Pour les chemises dont la longueur est inférieure à 100 %, cette option affecte également la largeur de la manche à l'ourlet, les manches courtes étant plus affectées par cette option, et les manches longues étant plus affectées par l'option d'aisance du poignet. Dans la plupart des cas, cette valeur doit être plus grande que l'aisance de la poitrine, car les épaules et les bras sont plus petits et le même pourcentage d'aisance se traduira par une aisance absolue plus petite. Pour les vêtements de compression, les épaules ont également besoin de plus de mobilité que la poitrine, et les élastiques très négatifs doivent généralement être évités pour cette option.
+Affecte la largeur de la manche à l'emmanchure sur toutes les chemises. Pour les chemises dont la longueur est inférieure à 100 %, cette option affecte également la largeur de la manche à l'ourlet, les manches courtes étant plus affectées par cette option, et les manches longues étant plus affectées par l'option d'aisance du poignet. Dans la plupart des cas, cette valeur doit être plus grande que l'aisance de la poitrine, car les épaules et les bras sont plus petits et le même pourcentage d'aisance se traduira par une aisance absolue plus petite. Pour les vêtements de compression, les épaules ont également besoin de plus de mobilité que la poitrine, et les aisances très négatives doivent généralement être évités pour cette option.
diff --git a/markdown/org/docs/designs/shelly/options/sleevelength/fr.md b/markdown/org/docs/designs/shelly/options/sleevelength/fr.md
index d3e2eedc103..e93b1fed1c7 100644
--- a/markdown/org/docs/designs/shelly/options/sleevelength/fr.md
+++ b/markdown/org/docs/designs/shelly/options/sleevelength/fr.md
@@ -3,8 +3,8 @@ title: "Longueur des manches"
---
Contrôle la longueur des manches de ta chemise.
- - 15 à 30 % d'entre eux feront des manches courtes.
- - 75 % d'entre eux feront des manches trois-quarts.
- - 100 % feront des manches longues, s'arrêtant au poignet.
- - 115% permettra de faire des manches couvrant les articulations, et est approprié si l'on utilise des trous pour les pouces.
+ - 15 à 30 % pour des manches courtes.
+ - 75 % pour des manches trois-quarts.
+ - 100 % pour des manches longues, s'arrêtant au poignet.
+ - 115% permettra de faire des manches couvrant les jointures, et est approprié si l'on utilise des trous pour les pouces.
diff --git a/markdown/org/docs/designs/shelly/options/wristease/fr.md b/markdown/org/docs/designs/shelly/options/wristease/fr.md
index 5ab13ad33ee..84c3df3ff7e 100644
--- a/markdown/org/docs/designs/shelly/options/wristease/fr.md
+++ b/markdown/org/docs/designs/shelly/options/wristease/fr.md
@@ -1,5 +1,5 @@
---
-title: "Facilité du poignet"
+title: "Aisance du poignet"
---
Affecte la largeur de l'extrémité de la manche sur certaines chemises. Il n'y a pas d'effet pour les manches se terminant au niveau du biceps ou au-dessus. Pour les manches plus longues, la mesure du poignet et cette option d'aisance du poignet ont un effet progressivement plus important, atteignant son plein effet pour les chemises à manches longues (longueur de manche de 100 % ou plus).
diff --git a/markdown/org/docs/designs/simon/instructions/9b.png b/markdown/org/docs/designs/simon/instructions/9b.png
index ecbfd0fa9ae..70819750f5e 100644
Binary files a/markdown/org/docs/designs/simon/instructions/9b.png and b/markdown/org/docs/designs/simon/instructions/9b.png differ
diff --git a/markdown/org/docs/designs/simon/instructions/9c.png b/markdown/org/docs/designs/simon/instructions/9c.png
index 15c8c5770b5..9702443b923 100644
Binary files a/markdown/org/docs/designs/simon/instructions/9c.png and b/markdown/org/docs/designs/simon/instructions/9c.png differ
diff --git a/markdown/org/docs/designs/simon/instructions/9e.png b/markdown/org/docs/designs/simon/instructions/9e.png
index f6a768f7bdc..9e6cda629d0 100644
Binary files a/markdown/org/docs/designs/simon/instructions/9e.png and b/markdown/org/docs/designs/simon/instructions/9e.png differ
diff --git a/markdown/org/docs/designs/simon/instructions/de.md b/markdown/org/docs/designs/simon/instructions/de.md
index d47e681a3db..2e2c9f5f63f 100644
--- a/markdown/org/docs/designs/simon/instructions/de.md
+++ b/markdown/org/docs/designs/simon/instructions/de.md
@@ -11,8 +11,7 @@ alle Schritte.
Wenn Sie dieses Muster herstellen wollen, können Kelly und Julian Ihnen den Weg zum Ende weisen.
Du findest das gesamte Material auf Kellys Website
-: [#simonsayssew mit kelly hogaboom & julian collins](https://kelly.hogaboom.org/2020/07/simon-says-sew-with-kelly-hogaboom-and-julian-collins/)
-
+: [#simonsayssew mit kelly hogaboom & julian collins](https://agni.hogaboom.org/2020/07/simon-says-sew-with-kelly-hogaboom-and-julian-collins/)
### Schritt 1: Sicherungsschnittstelle
@@ -252,6 +251,8 @@ Von der guten Seite Ihres Hemdes nähen Sie das gefaltete Plakat durch Nähen im
Um dies zu tun, nähen Sie genau auf Ihrer früheren Naht. Da du den Stoff deiner Leiste ein wenig über diese Naht hinaus gefaltet hast, wird sie hinten eingeklemmt, wodurch deine gefaltete Leiste fixiert und die Nahtzugabe innen festgehalten wird.
+
+
### Schritt 10: Bereiten Sie das Buttonhole Placket vor
> Wenn Sie einen ausgewachsenen Platz gewählt haben, können Sie die ersten beiden Unterschritte überspringen und einen klassischen Knopflochplatz verstehen.
diff --git a/markdown/org/docs/designs/simon/instructions/en.md b/markdown/org/docs/designs/simon/instructions/en.md
index 06c8f6096ef..df943067d46 100644
--- a/markdown/org/docs/designs/simon/instructions/en.md
+++ b/markdown/org/docs/designs/simon/instructions/en.md
@@ -11,8 +11,7 @@ all the steps.
If you're looking to make this pattern, Kelly and Julian can guide you start to finish.
You can find all the material's on Kelly's
-site: [#simonsayssew with kelly hogaboom & julian collins](https://kelly.hogaboom.org/2020/07/simon-says-sew-with-kelly-hogaboom-and-julian-collins/)
-
+site: [#simonsayssew with kelly hogaboom & julian collins](https://agni.hogaboom.org/2020/07/simon-says-sew-with-kelly-hogaboom-and-julian-collins/)
### Step 1: Fuse interfacing
@@ -256,6 +255,8 @@ From the good side of your shirt, sew down the folded placket by stitching in th
To do so, sew exactly on top of your earlier seam. Since you folded the fabric of your placket a bit past this seam, it will get caught at the back, fixing your folded placket in place, and locking the seam allowance inside.
+
+
### Step 10: Prepare the buttonhole placket
> If you have chosen a grown-on placket, you can skip the first two sub-steps and skip ahead to Understanding a classic buttonhole placket.
diff --git a/markdown/org/docs/designs/simon/instructions/es.md b/markdown/org/docs/designs/simon/instructions/es.md
index af6b40e2302..8730f77517b 100644
--- a/markdown/org/docs/designs/simon/instructions/es.md
+++ b/markdown/org/docs/designs/simon/instructions/es.md
@@ -10,9 +10,8 @@ Kelly Hogaboide y Julian Collins hicieron una costura Simon(e) , y tienen videos
todos los pasos.
Si estás buscando este patrón, Kelly y Julian pueden guiarte a empezar a terminar.
-Puedes encontrar todo el material en el sitio
-de Kelly: [#simonsayssew con Kelly Hogaboom y Julian Collins](https://kelly.Firstaboom.org/2020/07/simon-says-sew-with-kelly-Øaboom-and-ú-únian-collins/)
-
+You can find all the material's on Kelly's
+site: [#simonsayssew with kelly hogaboom & julian collins](https://agni.hogaboom.org/2020/07/simon-says-sew-with-kelly-hogaboom-and-julian-collins/)
### Paso 1: Fusionar interfaz
@@ -252,6 +251,8 @@ Desde el lado bueno de la camiseta, coser la placa plegada cruzando la zanja.
Para ello, coser exactamente encima de su costura anterior. Como has doblado la tela de la tapeta un poco más allá de esta costura, se enganchará en la parte posterior, fijando tu tapeta doblada en su sitio y bloqueando el margen de costura en el interior.
+
+
### Paso 10: Prepara el conjunto de posición del botón
> Si ha elegido un placket, puede omitir los dos primeros subpasos y saltar a Enderstanding un clásico placket.
diff --git a/markdown/org/docs/designs/simon/instructions/fr.md b/markdown/org/docs/designs/simon/instructions/fr.md
index 158b77c993f..6c8d5a2528e 100644
--- a/markdown/org/docs/designs/simon/instructions/fr.md
+++ b/markdown/org/docs/designs/simon/instructions/fr.md
@@ -11,8 +11,7 @@ toutes les étapes.
Si vous cherchez à créer ce modèle, Kelly et Julian peuvent vous guider vers la fin.
Tu peux trouver tout le matériel sur le site de Kelly
-: [#simonsayssew avec kelly hogaboom & julian collins](https://kelly.hogaboom.org/2020/07/simon-says-sew-with-kelly-hogaboom-and-julian-collins/)
-
+: [#simonsayssew avec kelly hogaboom & julian collins](https://agni.hogaboom.org/2020/07/simon-says-sew-with-kelly-hogaboom-and-julian-collins/)
### Étape 1 : Thermocoller l'entoilage
@@ -60,9 +59,9 @@ Placez les 2 pièces de vos poignets (l'une entoilée, l'autre non) endroit cont
Avant de retourner ta manchette, nous devons découper la marge de couture pour la rendre moins volumineuse.
-#### Repasser la marge de couture
+#### Repasser la marge de couture arrière
-
+
Replie les surplus de couture de chaque côté de la manchette, là où la manchette s'attache à la manche, et repasse-les.
@@ -252,6 +251,8 @@ Retourner la pièce sur l'endroit, et fixer la patte repliée en piquant dans la
Pour cela, coudre exactement sur votre couture précédente. Comme tu as plié le tissu de ta patte de boutonnage un peu au-delà de cette couture, il sera pris à l'arrière, fixant ta patte de boutonnage pliée en place, et bloquant le surplus de couture à l'intérieur.
+
+
### Etape 10: Préparer la patte de boutonnage (côté boutonnières)
> Si vous avez choisi une patte intégrée, vous pouvez passer les deux premières sous-étapes et passer à "Replier la patte de boutonnage".
@@ -441,9 +442,9 @@ Ensuite, couds horizontalement l'autre côté de la patte de boutonnage pour ter
>
> Par conséquent, ce sont les coutures et non les bords qui doivent être alignés, donc il faut positionner la manche de façon à ce qu'elle dépasse du bord de 1 cm.
-#### Manchon à goupille en place
+#### Épingler la manche en place
-
+
Étalez votre chemise sur l'envers, en mettant les deux devants et le dos bien à plat.
diff --git a/markdown/org/docs/designs/simon/instructions/nl.md b/markdown/org/docs/designs/simon/instructions/nl.md
index fff1da0ebef..92a00ed9ce9 100644
--- a/markdown/org/docs/designs/simon/instructions/nl.md
+++ b/markdown/org/docs/designs/simon/instructions/nl.md
@@ -11,8 +11,7 @@ alle stappen.
Als je dit patroon wilt maken, kan Kelly en Julian je begeleiden om te beginnen.
Je kunt al het materiaal vinden op Kelly's
-site: [#simonsayssew with kelly hogaboom & julian collins](https://kelly.hogaboom.org/2020/07/simon-says-sew-with-kelly-hogaboom-and-julian-collins/)
-
+site: [#simonsayssew with kelly hogaboom & julian collins](https://agni.hogaboom.org/2020/07/simon-says-sew-with-kelly-hogaboom-and-julian-collins/)
### Stap 1: Bevestig tussenvoering
@@ -240,9 +239,9 @@ Plooi het knopenpat opnieuw om, en let op dat de stof tot net voorbij de aanzetn
Als je daarmee blij bent, strijk dan het geplooide knopenpat.
-#### Stik het geplooide knopenpat
+#### Kleef de tussenvoering op de manchet
-
+
> Dit is de klassieke aanpak. Als je voor het naadloze knopenpat gekozen heb moet je dit niet doen.
>
@@ -252,6 +251,8 @@ Stik het geplooide knopenpat vast door langs de goede kant van je hemd in de naa
Om dit te doen stik je exact bovenop je eerdere naad. Omdat je de stof van je placket iets voorbij deze naad hebt gevouwen, zal hij aan de achterkant vast komen te zitten, waardoor je gevouwen placket op zijn plaats wordt gefixeerd en de naadtoeslag binnenin wordt opgesloten.
+
+
### Stap 10: Bereid het knoopsgatenpat voor
> Als je een aangeknipt knoopsgatenpat gekozen heb kan je de eerste twee substapjes overslaan en verdergaan met Hoe werkt een klassiek knopenpat.
@@ -378,9 +379,9 @@ Aangezien je deze schoudernaden gestreken hebt zou alles mooi plat moeten liggen
### Stap 13: Maak het mouwsplit
-#### Stik de mouwsplitreep
+#### Sierstiksel op de manchetten
-  
+  
- Leg je mouw met de goede kant naar beneden, en de mouwsplitreep bovenop, ook met de goede kant naar beneden.
- Leg de rand van de mouwsplitreep (de onderlap van het mouwsplit) gelijk met de knip in de mouw, aan de kant het dichtst bij de zijnaad.
@@ -579,9 +580,9 @@ Het is belangrijk om zowel de buitenste als de binnenste laag van je manchet aan
Strijk alles nog eens grondig als je dit gedaan hebt.
-#### Sierstiksel op de manchetten
+#### Strijk de schouderpas
-
+
> Let op dat je je manchetten strijkt voor je dit doet.
@@ -603,9 +604,9 @@ Zorg dat je de standaard naadwaarde in het oog houdt en - belangrijk - plooien v
>
> Dat is een beetje lastig, dus wees extra nauwkeurig aan de delen die het meest gebogen zijn: aan de schoudernaden.
-#### Stik de kraag smal door
+#### Stik de mouwsplitreep door
- 
+ 
Als je blij bent met hoe je kraag gedriegd is, wordt het tijd om het ding definitief vast te stikken.
diff --git a/markdown/org/docs/designs/simon/instructions/uk.md b/markdown/org/docs/designs/simon/instructions/uk.md
index ab606660ae2..eb4737b7edc 100644
--- a/markdown/org/docs/designs/simon/instructions/uk.md
+++ b/markdown/org/docs/designs/simon/instructions/uk.md
@@ -11,8 +11,7 @@ title: "Сорочка-символ: Інструкція з пошиття"
Якщо ви хочете зробити цей візерунок, Келлі та Джуліан допоможуть вам від початку до кінця.
Ви можете знайти всі матеріали на сайті Келлі
-: [#simonsayssew with kelly hogaboom & julian collins] (https://kelly.hogaboom.org/2020/07/simon-says-sew-with-kelly-hogaboom-and-julian-collins/)
-
+: [#simonsayssew with kelly hogaboom & julian collins] (https://agni.hogaboom.org/2020/07/simon-says-sew-with-kelly-hogaboom-and-julian-collins/)
### Крок 1: Взаємодія запобіжників
@@ -112,9 +111,9 @@ title: "Сорочка-символ: Інструкція з пошиття"
### Крок 4: З'єднайте нашийник і стійку нашийника
-#### Помістіть нашийник між стійками для нашийників і закріпіть його на місці
+#### Помістіть нашийник між стійками для нашийників і закріпіть на місці
-
+
Позначте шпилькою середню точку коміра і стійки коміра. Середня точка кожної стійки для коміра насправді трохи зміщена від центру, оскільки один кінець довший за інший. Замість цього знайдіть середню точку між двома надрізами.
@@ -252,6 +251,8 @@ title: "Сорочка-символ: Інструкція з пошиття"
Для цього прошийте точно поверх попереднього шва. Оскільки ви склали тканину планки трохи за цим швом, вона зачепиться ззаду, фіксуючи складену планку на місці і закриваючи припуски шва всередині.
+
+
### Крок 10: Підготуйте планку для петель
> Якщо ви вибрали петлю для дорослих, ви можете пропустити перші два підкроки і перейти до розділу "Розуміння класичної петлі для ґудзиків".
@@ -332,9 +333,9 @@ title: "Сорочка-символ: Інструкція з пошиття"
>
> Якщо ви знайомі з методом буріто, то вже знаєте, що робити. Якщо ні, то читайте далі, як акуратно закрити плечові шви сорочки, при цьому приховавши всі незавершені краї від сторонніх очей.
-#### Приколіть передню частину до зовнішньої кокетки
+#### Приколіть передні частини до зовнішньої кокетки
- 
+ 
Покладіть спину на підлогу доброю стороною догори, але будьте обережні, щоб скласти внутрішнє ярмо донизу (як показано пунктиром).
diff --git a/markdown/org/docs/designs/umbra/cutting/de.md b/markdown/org/docs/designs/umbra/cutting/de.md
new file mode 100644
index 00000000000..0b2fbb1b99a
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/cutting/de.md
@@ -0,0 +1,28 @@
+---
+title: "Umbra Unterhosen: Schnittanleitung"
+---
+
+Umbra besteht aus einem Rückenteil und einem gefütterten Vorderteil.
+Dies ist die Schnittliste:
+
+- **Hauptstoff**
+ - Schneide **1 Vorderteil**
+ - Schneide **1 Rückenteil**
+- **Futterstoff**
+ - Schneide **1 Vorderteil**
+
+Wenn du einen Overlock verwendet, kannst du überschüssigen Stoff mit dem Messer wegschneiden, verwende also eine normale Nahtzugabe.
+
+Wenn du keinen Overlock hast, empfehle ich dir, eine Nahtzugabe von 5 mm mit einem Overlook-Fuß und einem dehnbaren Kanten- bzw. Fake-Overlock-Stich zu verwenden.
+
+Je nachdem, wie du die Beinnähte abschließen möchtest, ist es in der Regel eine gute Idee, die Nahtzugabe an den Beinen des Futterteils wegzulassen, da der vordere Stoff nach innen umschlagen wird und dadurch die Kante versäubert wird.
+Wenn du für den Beinausschnitt ein umgeschlagenes Gummiband verwenden möchtest, lasse die Nahtzugabe für die Beinöffnung an allen Teilen weg.
+
+
+
+##### Notizen
+
+- Umbra ist ein großartiger Resteverwerter. Wenn du Stoffreste von einem [Teagan-T-Shirt](/designs/teagan/) oder irgendetwas aus einem dehnbaren Jersey-Stoff hast, ist dies eine gute Möglichkeit, diese zu verwenden. Wenn Sie nur kleinere Stücke haben, kannst du die beiden Hälften auch separat zuschneiden und zusammennähen, anstatt die Stücke im Stoffbruch zuzuschneiden. Dadurch entstehen jedoch zusätzliche Nähte.
+- Du kannst denselben Stoff für das gesamte Kleidungsstück verwenden, auch für das vordere Futter. Manche Menschen ziehen es vor, weichere Stoffe oder andere Materialien für das Futter zu verwenden.
+
+
diff --git a/markdown/org/docs/designs/umbra/cutting/en.md b/markdown/org/docs/designs/umbra/cutting/en.md
new file mode 100644
index 00000000000..9adf9c21c01
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/cutting/en.md
@@ -0,0 +1,27 @@
+---
+title: "Umbra undies: Cutting Instructions"
+---
+
+Umbra consists of a back piece and a lined front piece.
+This is the cut list:
+
+- **Main fabric**
+ - Cut **1 front**
+ - Cut **1 back**
+- **Lining fabric**
+ - Cut **1 front**
+
+If you use a serger, you can cut away excess fabric with the knife, so use standard seam allowance.
+
+If you don't have a serger, I recommend using an overlook foot and a flexible overedge / fake overlock stitch with a seam allowance equal to the width of that stitch (usually 5 mm).
+
+If you want to finish the leg openings with fold over elastics, you may want to skip the seam allowance for the leg opening on all parts.
+
+
+
+##### Notes
+
+- Umbra is a great scrap buster. If you have fabric scraps from making a [Teagan t-shirt](/designs/teagan/) or anything from a jersey fabric that has good stretch, this is a good way to use those up. If you only have smaller pieces, instead of cutting the pieces on the fold, you can cut both halves separately and sew them together. However, this introduces additional seams.
+- You can use the same fabric for the whole garment, including the front lining. Some people prefer using softer fabrics or different materials for the lining.
+
+
diff --git a/markdown/org/docs/designs/umbra/de.md b/markdown/org/docs/designs/umbra/de.md
new file mode 100644
index 00000000000..0810f8c3de0
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/de.md
@@ -0,0 +1,8 @@
+---
+title: "Umbra Unterhosen"
+---
+
+
+
+
+
diff --git a/markdown/org/docs/designs/umbra/en.md b/markdown/org/docs/designs/umbra/en.md
new file mode 100644
index 00000000000..21d4431b388
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/en.md
@@ -0,0 +1,8 @@
+---
+title: "Umbra undies"
+---
+
+
+
+
+
diff --git a/markdown/org/docs/designs/umbra/fabric/de.md b/markdown/org/docs/designs/umbra/fabric/de.md
new file mode 100644
index 00000000000..d3ede5a5bca
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/fabric/de.md
@@ -0,0 +1,7 @@
+---
+title: "Umbra Unterhosen: Stoff Optionen"
+---
+
+Für dieses Schnittmuster braucht man einen Stoff mit viel horizontaler und vertikaler Dehnung (manchmal auch „Vierwegestretch“). Am besten etwas das komfortabel, weich und atmungsaktiv ist.
+
+Zu den empfohlenen Stoffen gehören Stretchjerseys, Stretch-Mesh, Stretch-Strickgewebe oder die meisten Stoffe mit mindestens 5% Spandex. Beispielsweise Modal (Rayon) Jersey mit Spandex.
diff --git a/markdown/org/docs/designs/umbra/fabric/en.md b/markdown/org/docs/designs/umbra/fabric/en.md
new file mode 100644
index 00000000000..22625150bdd
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/fabric/en.md
@@ -0,0 +1,35 @@
+---
+title: "Umbra undies: Fabric Options"
+---
+
+You need a fabric with plenty of horizontal and vertical stretch (sometimes called “four-way stretch”) for this pattern. Preferably something that is comfortable, soft, and breathable.
+
+Recommended fabrics include stretch jerseys, stretch mesh, stretch knits, or most fabrics with at least 5% spandex. For example, modal (rayon) jersey with spandex.
+
+To test the stretch of your fabric, hold a known length of fabric against a rule.
+Then measure the length you can stretch that length of fabric to.
+For example if you can stretch a length of fabric from 10 cm to 18 cm, that fabric has a max stretch of 80%. If you can only stretch it to 13 cm, the stretch factor would be 30%.
+Measure the stretch in both directions (horizontal and vertical).
+
+Good underwear fabric should have a max stretch of at least 60-80%. Store-bought underwear often has fabric with a stretch factor of around 150% (which means it can be stretched to 2.5 times the original length). If your fabric has a stretch of only around 30%, it's probably pure cotton and less suitable for underwear.
+
+
+Be sure to adjust the "horizontal fabric stretch" and "vertical fabric stretch" options according to your fabric. Do **not** enter the max fabric stretch, enter the stretch you want the fabric to be when worn.
+
+
+If you have fabric with over 100% stretch, a good value for the horizontal stretch is 30%-50%.
+If you have fabric with around 80% stretch, a good default value for the horizontal stretch is 30%.
+If your fabric has 30% stretch, choose 15% horizontal stretch or less.
+If you want to use zipper pockets, go with a low stretch as the zippers can't stretch themselves.
+
+Fabric will wear out fast if you wear it near its maximum stretch, it will also be very uncomfortable.
+
+Note that the thickness of the fabric also affects the stretch you should enter. Go with lower stretch for thicker fabric.
+
+The vertical stretch can be much lower than the horizontal stretch. If you use a fabric that stretches more in one direction, use that for the horizontal direction.
+A good general value for the vertical stretch is around 5%. If it is too high, the fabric may press uncomfortably against your crotch area.
+
+
+* If you use a different fabric for the lining, make sure it has around the same stretch as the outer fabric.
+* If you use the same fabric for the lining, make sure to mark the lining piece, as otherwise both pieces may get confused easily during sewing.
+
diff --git a/markdown/org/docs/designs/umbra/instructions/en.md b/markdown/org/docs/designs/umbra/instructions/en.md
new file mode 100644
index 00000000000..b0b76ad8209
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/instructions/en.md
@@ -0,0 +1,110 @@
+---
+title: "Umbra undies: Sewing Instructions"
+---
+
+### Step 1: Sew the bulge
+
+If you have selected the bulge option, sew together the seam/dart between the bulge split and the crotch with _good sides together_. Do this for both front pieces separately. Trim seam allowance if necessary.
+
+Skip this step if your design doesn't have a bulge.
+
+
+
+### Step 2: Prepare pocket
+
+If you don't want pockets, skip to step 3.
+
+#### If you want to have inside pockets
+
+On the front piece from the lining fabric, fold down the seam allowance on the top edge, _bad sides together_, then fix using an elastic stitch.
+
+Create an additional fold, around 1.5 cm below the top or around the marked edge to the same side. Press that fold, but do not sew.
+
+
+
+#### If you want to have zipper pockets
+
+Of the front piece of the main fabric, insert twp zippers at the marked location.
+There are various techniques to do this. You may want to add some fusible interfacing on the bad side to make the fabric around the zipper more robust and less elastic.
+
+### Step 3: Stack fabrics
+
+Stack the parts in the following way, aligning and pinning the side seams and the crotch seams.
+
+* On the table, place the front part with lining fabric, _good side up_
+* On top of that, place the back part, _good side up_
+* On top of that, place the front part with main fabric, _bad side up_
+
+To double-check, the main fabric front part and the back part should have their _good sides together_ and the good side of the lining fabric should point towards the middle piece. The front parts on the outside of the stack should have their respective bad side pointing outwards, away from the back piece in the middle.
+
+Depending on your settings, the middle (back) part in your stack has likely a shorter crotch part and wider sides than the outer parts. Make sure to sandwich all three layers together on the future seams. You probably have to bunch up the fabric a bit.
+
+
+
+### Step 4: Sew the parts together
+
+Sew the crotch seam and both side seams together. Use a serger or a flexible stitch.
+
+
+
+### Step 5: Turn it the right side out
+
+Take only the main fabric front part (on top of the stack) and reverse the crotch part of it through the waistline opening, so that the bad sides of both front pieces are together. All seams should now be hidden between both front pieces.
+
+This should now roughly look like underwear.
+
+
+
+### Step 6: Create Pocket seams
+
+If you have selected a pocket option, sew front and lining together along the marked pocket seams using a coverstitch or an elastic stitch.
+
+
+
+### Step 7: Finish the leg seams
+
+You have several options for finishing the leg openings.
+
+#### Option A: Fold it over
+
+If you don't want to use an elastic band for the legs, you can as a simple option fold the seam allowance to the inside of the briefs and fix it using an elastic stitch. However some fabrics could warp with bad presser foot pressure and thread tension settings, so while this option is easy, it might not give the best results.
+
+#### Option B: Use an elastic band
+
+Another better option is to use a decorative elastic band. In this case follow [steps 8 to 10 from the Uma instructions](/docs/designs/uma/instructions#step-8-prepare-elastic) for the leg openings.
+
+#### Option C: Bias tape
+
+You can also use elastic fold-over bias tape, in which case you should trim all seam allowances on the leg openings to keep the intended shape.
+
+### Step 8: Prepare elastic for the waist
+
+Overlap the edges of each piece of your waistband elastic by your seam allowance and stitch together.
+
+To ensure that you stretch the elastic evenly, divide the waistband opening and your elastic into four quarters and mark the points with pins or chalk.
+
+
+
+### Step 9: Sew elastic for the waistband
+
+Choose if you want to have the elastic on the inside or on the outside on the finished undies. Smaller elastic bands should typically go on the inside, larger ones on the outside. The following pictures assume you want the elastic on the outside.
+
+If you want to have the elastic on the outside, pin the bad side of the elastics to the bad side of the fabric. If you want to have the elastic on the inside, join both good sides.
+
+If your elastic has a decorative edge, make sure that you line up the plain edge (not the decorative edge) of the elastic to the raw edge of the fabric. The decorative edge should be pointing towards the garment, not away from it.
+
+Pin the elastic to the waist opening of the fabric on the selected side, ensuring that you line up the quarter markings. It can be very helpful to stitch it on by hand so your elastic is kept in place properly for the next step.
+
+Sew the elastic to the garment using an elastic stitch. You will have to stretch the elastic slightly as you sew to make it lay flat against the fabric. Avoid stretching the fabric itself.
+
+
+
+Trim away any excess fabric that causes bulk or sticks out from the elastic.
+
+### Step 10: Fold the elastic inwards and sew it down again
+
+Fold the elastic and fabric to the other side, enclosing the raw edge of the fabric under the elastic. Sew again using an elastic stitch.
+
+
+
+You did it!
diff --git a/markdown/org/docs/designs/umbra/instructions/step01.svg b/markdown/org/docs/designs/umbra/instructions/step01.svg
new file mode 100644
index 00000000000..8cb2b72f23b
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/instructions/step01.svg
@@ -0,0 +1,721 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/umbra/instructions/step02.svg b/markdown/org/docs/designs/umbra/instructions/step02.svg
new file mode 100644
index 00000000000..58592304dd9
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/instructions/step02.svg
@@ -0,0 +1,710 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/umbra/instructions/step03.svg b/markdown/org/docs/designs/umbra/instructions/step03.svg
new file mode 100644
index 00000000000..1efdc89d346
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/instructions/step03.svg
@@ -0,0 +1,728 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/umbra/instructions/step04.svg b/markdown/org/docs/designs/umbra/instructions/step04.svg
new file mode 100644
index 00000000000..f7b069d9927
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/instructions/step04.svg
@@ -0,0 +1,727 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/umbra/instructions/step05.svg b/markdown/org/docs/designs/umbra/instructions/step05.svg
new file mode 100644
index 00000000000..bbe60ef0999
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/instructions/step05.svg
@@ -0,0 +1,748 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/umbra/instructions/step06.svg b/markdown/org/docs/designs/umbra/instructions/step06.svg
new file mode 100644
index 00000000000..ca8a202e1e7
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/instructions/step06.svg
@@ -0,0 +1,724 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/umbra/instructions/step08.svg b/markdown/org/docs/designs/umbra/instructions/step08.svg
new file mode 100644
index 00000000000..9568bcff3f8
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/instructions/step08.svg
@@ -0,0 +1,804 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/umbra/instructions/step09.svg b/markdown/org/docs/designs/umbra/instructions/step09.svg
new file mode 100644
index 00000000000..d9e6bb38705
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/instructions/step09.svg
@@ -0,0 +1,704 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/umbra/instructions/step10.svg b/markdown/org/docs/designs/umbra/instructions/step10.svg
new file mode 100644
index 00000000000..c3a7b4e2029
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/instructions/step10.svg
@@ -0,0 +1,970 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/markdown/org/docs/designs/umbra/measurements/de.md b/markdown/org/docs/designs/umbra/measurements/de.md
new file mode 100644
index 00000000000..aed22528a11
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/measurements/de.md
@@ -0,0 +1,15 @@
+---
+title: "Umbra Unterhosen: Erforderliche Maße"
+---
+
+
+
+
+Vergewissere dich, dass deine Maße auf einer definierten Taille beruhen. Wenn du Schwierigkeiten hast, deine Taille zu bestimmen, binde eine Schnur in ungefähr korrekter Höhe um deinen Körper (in der Regel etwas unterhalb der Rippen oder dort, wo sich die Haut faltet, wenn du dich zur Seite beugst).
+Verwende dies als Bezugslinie für die anderen Messungen.
+Die genaue Taillenhöhe ist nicht entscheidend, aber sie ist wichtig, um die Konsistenz der anderen Messungen zu gewährleisten.
+
+
+
+Beim Taille-Schritt-Taille-Maß solltest du deine Genitalien nicht mitmessen. Führe das Maßband an der Innenseite eines Beins entlang und nicht über die Körpermitte. Zusätzlicher Raum vorne kann mit der Option "Wölbung" geschaffen werden.
+
diff --git a/markdown/org/docs/designs/umbra/measurements/en.md b/markdown/org/docs/designs/umbra/measurements/en.md
new file mode 100644
index 00000000000..2dc5ebcc5b7
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/measurements/en.md
@@ -0,0 +1,15 @@
+---
+title: "Umbra undies: Required Measurements"
+---
+
+
+
+
+Ensure that yor measurements are based on a fixed waistline. If you have difficulty determining where your waist is, tie a string around your body at approximately the right height (usually a little below the ribs or where your skin folds if you bend sideways).
+Use this as a reference line for the other measurements.
+The exact waist height is not crucial, but it is essential to maintain consistency in the other measurements.
+
+
+
+To measure the cross seam precisely, exclude your genitals. Place the measuring tape alongside the inside of one of your legs, rather than over the center of your body. Extra room for your genitals can be added through the bulge option.
+
diff --git a/markdown/org/docs/designs/umbra/needs/de.md b/markdown/org/docs/designs/umbra/needs/de.md
new file mode 100644
index 00000000000..435708f7670
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/needs/de.md
@@ -0,0 +1,21 @@
+---
+title: "Umbra Unterhosen: Was du brauchst"
+---
+
+Um Umbra herzustellen, brauchst du Folgendes:
+
+- [Grundlegendes Nähzubehör](/docs/sewing/basic-sewing-supplies)
+- Etwa 0,7 Meter (0,8 Yards) eines geeigneten Stoffes (siehe [Stoffoptionen](/docs/designs/umbra/fabric))
+- Ungefähr 3 Meter (3,3 Yards) Unterwäsche-Gummiband, z. B. ein Picot-Gummiband oder ein umklappbares Gummiband
+
+
+
+##### Bindungsmethoden können die Nahterlaubnis
+
+beeinflussen, wenn Falten über elastisch (FOE) verwendet wird oder Strickverbindung, Sie können vor dem Schneiden die Naht an den Beinen und die Taille abschneiden wollen. Wenn du die Nahtzugabe beibehältst, wird das fertige Produkt eine etwas höhere Taille und etwas kleinere Beinöffnungen haben.
+
+##### Overlocks (Serger) sind schön, aber optional
+
+Wie bei allen Strickwaren und Stretchgeweben wird dir eine Overlock (Serger) das Leben erleichtern. Wenn du keine hast, musst du aber nicht verzweifeln. Du brauchst sie nicht unbedingt. Du kannst Umbra einfach mit einem Zickzackstich nähen.
+
+
diff --git a/markdown/org/docs/designs/umbra/needs/en.md b/markdown/org/docs/designs/umbra/needs/en.md
new file mode 100644
index 00000000000..6e5a3f135ea
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/needs/en.md
@@ -0,0 +1,21 @@
+---
+title: "Umbra undies: What You Need"
+---
+
+To make Umbra, you will need the following:
+
+- [Basic sewing supplies](/docs/sewing/basic-sewing-supplies)
+- About 0.7 meters (0.8 yards) of a suitable fabric (see [Fabric options](/docs/designs/umbra/fabric))
+- About 3 meters (3.3 yards) of underwear elastic, such as picot elastic or fold over elastic
+
+
+
+##### Binding methods may affect the seam allowance
+
+If using fold over elastic (FOE) or doing knit binding, you may wish to trim away the seam allowance at the legs and waist before cutting. If you keep the seam allowance, the finished product will have a slightly higher waist and slightly smaller leg openings.
+
+##### A serger/overlock is nice, but optional
+
+As with all knitwear and stretch fabrics, a serger/overlock will make your life easier. If you do not have one of those, don't despair. You don't really need it. You can just sew Umbra with a zigzag stitch or with various other stretch stitches.
+
+
diff --git a/markdown/org/docs/designs/umbra/notes/de.md b/markdown/org/docs/designs/umbra/notes/de.md
new file mode 100644
index 00000000000..e7cf5852dc2
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/notes/de.md
@@ -0,0 +1,31 @@
+---
+title: "Umbra Unterhosen: Designer Notes"
+---
+
+Umbra ist ein bequemer und flexibler Slip, der so vielen Menschen wie möglich gerecht werden soll.
+
+Umbra basiert auf einigen Experimenten, Prototypen und Messungen an meiner Lieblingsunterwäsche.
+
+Umbra ist speziell für vielfältige Nutzer konzipiert. Du kannst das Design für dich einfach auf verschiedene Weise anpassen um deinen Bedürfnissen gerecht zu werden. Jedoch werden nicht alle Anpassungen direkt in der Software unterstützt.
+
+Einige Funktionen von Umbra sind wie folgt:
+
+* Umbra kann so genäht werden, dass keine (potenziell juckende) Nahtzugabe die Haut berührt, was unter anderem Menschen mit empfindlicher Haut und mit sensorischen Problemen wie bei Autismus hilft. Die Schritt- und Seitennähte liegen innen zwischen den Lagen des Vorderteils und eventuelle Gummizüge an der Taille und den Beinöffnungen können auf Wunsch auf der Außenseite angebracht werden.
+* Umbra kann mit oder ohne Wölbung genäht werden. Du kannst das Design sogar zweimal entwerfen und das Vorderfutter ohne Wölbung und das Hauptstoff-Vorderteil mit Wölbung zuschneiden, und dadurch eine Vordertasche mit viel Platz schaffen.
+* Höhe, Rückenausschnitt, Vorderausschnitt und Zwickelbreite werden separat gesteuert, sodass z. B. sehr bequeme Tangas mit genügend Platz im Vorderteil oder viele andere Designs erstellt werden können.
+
+Umbra basiert auf dem Code von Uma von Natalia Sayang und Joost De Cock, wurde aber in seinem Aufbau und Standard-Design stark verändert.
+Einige Hauptunterschiede sind:
+* Umbra hat keinen separaten Zwickelteil, stattdessen wird das ganze Vorderteil mit Futter versehen.
+* Die Hüftmaße werden berücksichtigt, um die Weite des Bundes besser bestimmen zu können.
+* Die Höhe der Unterwäsche basiert auf dem normalerweise genaueren Taille-Schritt-Taille-Maß anstelle des Maßes von Taille bis Oberschenkel.
+* Die Positionen der Seiten- und Schrittnähte können frei eingestellt werden, auch wenn eine Wölbung gewählt wurde.
+* Das Rückenteil hat eine glattere, bequemere Kurve und bietet standardmäßig und maximal eine größere Abdeckung.
+
+
+Stelle sicher, dass du die Optionen horizontale und vertikale Stoffdehnung an deinen Stoff anpasst. Wenn das Schnittmuster im Vergleich zu gekauften Unterhosen riesig aussieht, liegt das vermutlich daran, dass diese viel mehr gedehnt werden.
+
+
+
+ Umbra kann leicht als Badehose genäht werden. Verwende einfach einen Bademodenstoff und nähe, falls gewünscht, ein einmal umgeschlagenes Stück Stoff mit zwei Löchern als Kordelzug anstelle des Gummibandes am Bund an.
+
diff --git a/markdown/org/docs/designs/umbra/notes/en.md b/markdown/org/docs/designs/umbra/notes/en.md
new file mode 100644
index 00000000000..18f78044bd5
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/notes/en.md
@@ -0,0 +1,31 @@
+---
+title: "Umbra undies: Designer Notes"
+---
+
+Umbra is a comfortable and flexible underwear briefs design that aims to be inclusive for as many people as possible.
+
+Umbra is based on some experiments, prototypes and measurements of my favourite underwear.
+
+Umbra is especially designed for diverse users. You can easily add several useful modifications, even if some of them are not directly supported by the software.
+
+Some features of Umbra are as follows:
+
+* It can be sewn so that no (potentially itchy) seam allowance touches the skin, which helps people with sensitive skin and those with autism. The crotch and side seams are placed on the inside between the front part layers and any elastics on the waist and leg openings can be put on the outside, if so desired.
+* It can be sewn with or without a bulge. You can even draft the design twice, and cut the front lining without bulge and the main fabric front part with one, and you'll be able to create a front pocket with plenty of space.
+* Rise, back exposure, front exposure and gusset width are controlled separately, so you can create e.g. very comfortable thongs with enough room in the front, or many other designs.
+
+Umbra is based on code from Uma by Natalia Sayang and Joost De Cock, but has been heavily modified in its construction and default style.
+Some key differences are:
+* Umbra doesn't have a separate gusset part and instead adds lining to the whole front piece.
+* The hip measurements are being taken into account to better determine the waistband size.
+* The height of the underwear is based on the usually more accurate Cross Seam measurement instead of the Waist to upper leg measurement.
+* The positions of the side and crotch seams can be adjusted freely, even with a bulge selected.
+* The back part has a smoother, more comfortable curve and provides greater coverage by default and at maximum.
+
+
+Be sure to adjust the "horizontal fabric stretch" and "vertical fabric stretch" options according to your fabric. The default stretch values are rather low. If your pattern appears huge compared to store-bought underwear, they probably use much more stretch.
+
+
+
+ If you wish to adapt Umbra to a swimwear bottom, it should be easy to do so. Simply use swimwear fabric and, if desired, sew on a folded over piece of fabric with two holes instead of a waistband elastic, to create a drawstring.
+
diff --git a/markdown/org/docs/designs/umbra/options/backdip/de.md b/markdown/org/docs/designs/umbra/options/backdip/de.md
new file mode 100644
index 00000000000..b502afb0292
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/backdip/de.md
@@ -0,0 +1,7 @@
+---
+title: "Absenkung hintere Taille"
+---
+
+Diese Option bestimmt, wie sehr die Rückentaillenkurven (mehr oder weniger Haut) sind.
+
+
diff --git a/markdown/org/docs/designs/umbra/options/backdip/en.md b/markdown/org/docs/designs/umbra/options/backdip/en.md
new file mode 100644
index 00000000000..7df71462dd3
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/backdip/en.md
@@ -0,0 +1,7 @@
+---
+title: "Back waist dip"
+---
+
+This option controls how much the back waist curves (revealing more or less skin).
+
+
diff --git a/markdown/org/docs/designs/umbra/options/backdip/es.md b/markdown/org/docs/designs/umbra/options/backdip/es.md
new file mode 100644
index 00000000000..75fe6a58224
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/backdip/es.md
@@ -0,0 +1,7 @@
+---
+title: "Buceo de cintura trasera"
+---
+
+Esta opción controla hasta qué punto las curvas de la cintura trasera (revelando más o menos la piel).
+
+
diff --git a/markdown/org/docs/designs/umbra/options/backdip/fr.md b/markdown/org/docs/designs/umbra/options/backdip/fr.md
new file mode 100644
index 00000000000..3da5121528f
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/backdip/fr.md
@@ -0,0 +1,7 @@
+---
+title: "Profondeur de la taille arrière"
+---
+
+Cette option permet de contrôler à quel point la taille arrière est courbée (révélant plus ou moins de peau).
+
+
diff --git a/markdown/org/docs/designs/umbra/options/backdip/nl.md b/markdown/org/docs/designs/umbra/options/backdip/nl.md
new file mode 100644
index 00000000000..3262e005d76
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/backdip/nl.md
@@ -0,0 +1,7 @@
+---
+title: "Achterste dip taille"
+---
+
+Deze optie bepaalt hoeveel de omgekeerde golfcurves (min of meer skin) onthullen.
+
+
diff --git a/markdown/org/docs/designs/umbra/options/backdip/uk.md b/markdown/org/docs/designs/umbra/options/backdip/uk.md
new file mode 100644
index 00000000000..b0be35ed7eb
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/backdip/uk.md
@@ -0,0 +1,7 @@
+---
+title: "Нахил спини до талії"
+---
+
+Ця опція контролює, наскільки сильно вигинається задня частина талії (відкриваючи більше або менше шкіри).
+
+
diff --git a/markdown/org/docs/designs/umbra/options/backdipshape/de.md b/markdown/org/docs/designs/umbra/options/backdipshape/de.md
new file mode 100644
index 00000000000..aa241efc67b
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/backdipshape/de.md
@@ -0,0 +1,12 @@
+---
+title: "Verlauf der Rückentaillenkurve"
+---
+
+Diese Option steuert die Kurve der hinteren Taillenabsenkung. Diese Option wirkt sich nur aus, wenn die hintere Taillenabsenkung auf einen Wert ungleich Null eingestellt ist.
+
+Höhere Werte erzeugen eine flachere Kurve in der Mitte und eine stärkere Kurve um die Seitennaht.
+
+Niedrigere Werte erzeugen eine schärfere Kurve in der Mitte und eine sanftere Kurve um die Seitennaht.
+
+
+
diff --git a/markdown/org/docs/designs/umbra/options/backdipshape/en.md b/markdown/org/docs/designs/umbra/options/backdipshape/en.md
new file mode 100644
index 00000000000..7f8294d134a
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/backdipshape/en.md
@@ -0,0 +1,11 @@
+---
+title: "Back waist dip shape"
+---
+
+This option controls the curve of the back waist dip. This option only has an effect if the back waist dip is set to a nonzero value.
+
+Higher values create a flatter curve at the center and increase the curve around the side seam.
+
+Lower values create a sharper curve at the center and a smoother curve around the side seam.
+
+
diff --git a/markdown/org/docs/designs/umbra/options/backexposure/de.md b/markdown/org/docs/designs/umbra/options/backexposure/de.md
new file mode 100644
index 00000000000..f5db103479e
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/backexposure/de.md
@@ -0,0 +1,6 @@
+---
+title: "Hintere Freilegung"
+---
+
+Diese Option steuert die Menge der exponierten Haut auf der Rückseite.
+
diff --git a/markdown/org/docs/designs/umbra/options/backexposure/en.md b/markdown/org/docs/designs/umbra/options/backexposure/en.md
new file mode 100644
index 00000000000..56c4d602a90
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/backexposure/en.md
@@ -0,0 +1,6 @@
+---
+title: "Back exposure"
+---
+
+This option controls the amount of exposed skin on the back.
+
diff --git a/markdown/org/docs/designs/umbra/options/backexposure/es.md b/markdown/org/docs/designs/umbra/options/backexposure/es.md
new file mode 100644
index 00000000000..da7e4275564
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/backexposure/es.md
@@ -0,0 +1,6 @@
+---
+title: "Exposición trasera"
+---
+
+Esta opción controla la cantidad de piel expuesta en la espalda.
+
diff --git a/markdown/org/docs/designs/umbra/options/backexposure/fr.md b/markdown/org/docs/designs/umbra/options/backexposure/fr.md
new file mode 100644
index 00000000000..d800b1a4d49
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/backexposure/fr.md
@@ -0,0 +1,6 @@
+---
+title: "Exposition des fesses"
+---
+
+Cette option permet de contrôler la quantité de peau exposée sur les fesses.
+
diff --git a/markdown/org/docs/designs/umbra/options/backexposure/nl.md b/markdown/org/docs/designs/umbra/options/backexposure/nl.md
new file mode 100644
index 00000000000..52e171df28d
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/backexposure/nl.md
@@ -0,0 +1,6 @@
+---
+title: "Blootstelling rug"
+---
+
+Deze optie bepaalt de hoeveelheid blootgestelde huid op de achterkant.
+
diff --git a/markdown/org/docs/designs/umbra/options/backexposure/uk.md b/markdown/org/docs/designs/umbra/options/backexposure/uk.md
new file mode 100644
index 00000000000..c785bc0e371
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/backexposure/uk.md
@@ -0,0 +1,6 @@
+---
+title: "Експозиція ззаду"
+---
+
+Ця опція контролює кількість відкритої шкіри на спині.
+
diff --git a/markdown/org/docs/designs/umbra/options/bulge/de.md b/markdown/org/docs/designs/umbra/options/bulge/de.md
new file mode 100644
index 00000000000..4f1a38efaea
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/bulge/de.md
@@ -0,0 +1,5 @@
+---
+title: Wölbung
+---
+
+Diese Option steuert, wie viel zusätzlicher Platz vorne in der Unterhose geschaffen wird. Hat unter 2 Grad keine Auswirkung.
diff --git a/markdown/org/docs/designs/umbra/options/bulge/en.md b/markdown/org/docs/designs/umbra/options/bulge/en.md
new file mode 100644
index 00000000000..6308a10a54d
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/bulge/en.md
@@ -0,0 +1,5 @@
+---
+title: Bulge
+---
+
+This option controls the extra room in the front of the underwear. Below 2 degrees, no extra bulge will be created.
diff --git a/markdown/org/docs/designs/umbra/options/bulgefullness/de.md b/markdown/org/docs/designs/umbra/options/bulgefullness/de.md
new file mode 100644
index 00000000000..32e6918589e
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/bulgefullness/de.md
@@ -0,0 +1,5 @@
+---
+title: Wölbungs-Fülle
+---
+
+Diese Option steuert die Form der Wölbung. Große Werte führen zu einer runderen, größeren Wölbung, wobei das Nähen aber etwas schwerer werden kann.
diff --git a/markdown/org/docs/designs/umbra/options/bulgefullness/en.md b/markdown/org/docs/designs/umbra/options/bulgefullness/en.md
new file mode 100644
index 00000000000..66a8258b83a
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/bulgefullness/en.md
@@ -0,0 +1,5 @@
+---
+title: Bulge fullness
+---
+
+This option controls the curve of the bulge, larger values lead to a more round, spacy bulge, but sewing might be more difficult.
diff --git a/markdown/org/docs/designs/umbra/options/de.md b/markdown/org/docs/designs/umbra/options/de.md
new file mode 100644
index 00000000000..c614f0dbe22
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/de.md
@@ -0,0 +1,5 @@
+---
+title: "Umbra Unterhosen: Design Optionen"
+---
+
+
diff --git a/markdown/org/docs/designs/umbra/options/elasticstretch/de.md b/markdown/org/docs/designs/umbra/options/elasticstretch/de.md
new file mode 100644
index 00000000000..c098526a9e6
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/elasticstretch/de.md
@@ -0,0 +1,11 @@
+---
+title: Elastikband-Dehnung
+---
+
+Diese Option steuert, wie stark das elastische Band im Verhältnis zum Stoff gedehnt wird.
+
+Dies bestimmt, wie viel kleiner die Länge des Gummibandes im Verhältnis zum realen Bundumfang angezeigt wird.
+Das Gleiche gilt für die Beinlöcher.
+
+Wenn dein Hauptstoff nicht sehr elastisch ist, solltest du diesen Wert wahrscheinlich erhöhen, damit die Unterhose gut hält.
+Wenn dein Hauptstoff bereits sehr elastisch ist, kannst du einen Wert nahe 0 % wählen.
diff --git a/markdown/org/docs/designs/umbra/options/elasticstretch/en.md b/markdown/org/docs/designs/umbra/options/elasticstretch/en.md
new file mode 100644
index 00000000000..8d6762688b4
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/elasticstretch/en.md
@@ -0,0 +1,11 @@
+---
+title: Elastic stretch
+---
+
+This option controls how much the elastic band is stretched relative to the fabric.
+
+This determines how much smaller the waistband elastic length will be shown relative to the actual waistband circumference.
+The same applies for the leg holes.
+
+If your main fabric is not very elastic, you should probably increase this so that the undies hold up well.
+If your main fabric is already very elastic, you can go close to 0%.
diff --git a/markdown/org/docs/designs/umbra/options/en.md b/markdown/org/docs/designs/umbra/options/en.md
new file mode 100644
index 00000000000..86b266beaa9
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/en.md
@@ -0,0 +1,5 @@
+---
+title: "Umbra undies: Design Options"
+---
+
+
diff --git a/markdown/org/docs/designs/umbra/options/flipback/en.md b/markdown/org/docs/designs/umbra/options/flipback/en.md
new file mode 100644
index 00000000000..ead60218275
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/flipback/en.md
@@ -0,0 +1,5 @@
+---
+title: Flip back part
+---
+
+This option controls if the back part will be flipped into an upright position.
diff --git a/markdown/org/docs/designs/umbra/options/frontdip/de.md b/markdown/org/docs/designs/umbra/options/frontdip/de.md
new file mode 100644
index 00000000000..4f3fda3db08
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/frontdip/de.md
@@ -0,0 +1,6 @@
+---
+title: "Absenkung der vorderen Taille"
+---
+
+Diese Option bestimmt, wie sehr die Vordertaillenkurven (mehr oder weniger Haut) sind.
+
diff --git a/markdown/org/docs/designs/umbra/options/frontdip/en.md b/markdown/org/docs/designs/umbra/options/frontdip/en.md
new file mode 100644
index 00000000000..7d8e7495f4c
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/frontdip/en.md
@@ -0,0 +1,6 @@
+---
+title: "Front waist dip"
+---
+
+This option controls how much the front waist curves (revealing more or less skin).
+
diff --git a/markdown/org/docs/designs/umbra/options/frontdip/es.md b/markdown/org/docs/designs/umbra/options/frontdip/es.md
new file mode 100644
index 00000000000..2dcd23e432c
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/frontdip/es.md
@@ -0,0 +1,6 @@
+---
+title: "Buceo de cintura frontal"
+---
+
+Esta opción controla hasta qué punto las curvas de cintura frontal (revelando más o menos la piel).
+
diff --git a/markdown/org/docs/designs/umbra/options/frontdip/fr.md b/markdown/org/docs/designs/umbra/options/frontdip/fr.md
new file mode 100644
index 00000000000..a5a221552a5
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/frontdip/fr.md
@@ -0,0 +1,6 @@
+---
+title: "Profondeur de la taille avant"
+---
+
+Cette option permet de contrôler à quel point la taille avant est courbée (révélant plus ou moins de peau).
+
diff --git a/markdown/org/docs/designs/umbra/options/frontdip/nl.md b/markdown/org/docs/designs/umbra/options/frontdip/nl.md
new file mode 100644
index 00000000000..ad747ab4cb7
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/frontdip/nl.md
@@ -0,0 +1,6 @@
+---
+title: "Voorste taille dip"
+---
+
+Deze optie bepaalt hoeveel de golfcurves vooraan tonen (min of meer skin).
+
diff --git a/markdown/org/docs/designs/umbra/options/frontdip/uk.md b/markdown/org/docs/designs/umbra/options/frontdip/uk.md
new file mode 100644
index 00000000000..be523a57d38
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/frontdip/uk.md
@@ -0,0 +1,6 @@
+---
+title: "Спереду нахил талії"
+---
+
+Ця опція контролює, наскільки сильно вигинається талія спереду (відкриваючи більше або менше шкіри).
+
diff --git a/markdown/org/docs/designs/umbra/options/frontdipshape/de.md b/markdown/org/docs/designs/umbra/options/frontdipshape/de.md
new file mode 100644
index 00000000000..2adc0fd7293
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/frontdipshape/de.md
@@ -0,0 +1,12 @@
+---
+title: "Verlauf der vorderen Taillenkurve"
+---
+
+Diese Option steuert die Kurve der vorderen Taillenabsenkung. Diese Option wirkt sich nur aus, wenn die vorderen Taillenabsenkung auf einen Wert ungleich Null eingestellt ist.
+
+Höhere Werte erzeugen eine flachere Kurve in der Mitte und eine stärkere Kurve um die Seitennaht.
+
+Niedrigere Werte erzeugen eine schärfere Kurve in der Mitte und eine sanftere Kurve um die Seitennaht.
+
+
+
diff --git a/markdown/org/docs/designs/umbra/options/frontdipshape/en.md b/markdown/org/docs/designs/umbra/options/frontdipshape/en.md
new file mode 100644
index 00000000000..282348ee212
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/frontdipshape/en.md
@@ -0,0 +1,11 @@
+---
+title: "Front waist dip shape"
+---
+
+This option controls the curve of the front waist dip. This option only has an effect if the front waist dip is set to a nonzero value.
+
+Higher values create a flatter curve at the center and increase the curve around the side seam.
+
+Lower values create a sharper curve at the center and a smoother curve around the side seam.
+
+
diff --git a/markdown/org/docs/designs/umbra/options/frontexposure/de.md b/markdown/org/docs/designs/umbra/options/frontexposure/de.md
new file mode 100644
index 00000000000..88a1f9d20b0
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/frontexposure/de.md
@@ -0,0 +1,6 @@
+---
+title: "Vordere Freilegung"
+---
+
+Steuert, wie viel Haut an der Vorderseite bedeckt wird.
+
diff --git a/markdown/org/docs/designs/umbra/options/frontexposure/en.md b/markdown/org/docs/designs/umbra/options/frontexposure/en.md
new file mode 100644
index 00000000000..1f72102e317
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/frontexposure/en.md
@@ -0,0 +1,6 @@
+---
+title: "Front exposure"
+---
+
+Controls how much skin on the front will be covered.
+
diff --git a/markdown/org/docs/designs/umbra/options/frontreduction/de.md b/markdown/org/docs/designs/umbra/options/frontreduction/de.md
new file mode 100644
index 00000000000..3307058bdd7
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/frontreduction/de.md
@@ -0,0 +1,5 @@
+---
+title: Verkleinerung der Vorderseite
+---
+
+Diese Option steuert, wie viel schmaler die Vorderseite im Vergleich zur Rückseite entworfen wird. Größere Werte machen den Slip optisch schmaler, erhöhen indirekt aber auch die Bedeckung des Pos und reduzieren die Bedeckung der Vorderseite.
diff --git a/markdown/org/docs/designs/umbra/options/frontreduction/en.md b/markdown/org/docs/designs/umbra/options/frontreduction/en.md
new file mode 100644
index 00000000000..0c22c298db0
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/frontreduction/en.md
@@ -0,0 +1,5 @@
+---
+title: Front reduction
+---
+
+This option controls how much less wide the front part will be compared to the back part. Increasing this option will make the underwear appear slimmer from the front and indirectly increase the back coverage and front exposure.
diff --git a/markdown/org/docs/designs/umbra/options/gussetposition/de.md b/markdown/org/docs/designs/umbra/options/gussetposition/de.md
new file mode 100644
index 00000000000..9e307bf99b5
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/gussetposition/de.md
@@ -0,0 +1,6 @@
+---
+title: "Zwickelposition"
+---
+
+Mit dieser Option kannst du den Zwickel nach vorne oder hinten verschieben.
+
diff --git a/markdown/org/docs/designs/umbra/options/gussetposition/en.md b/markdown/org/docs/designs/umbra/options/gussetposition/en.md
new file mode 100644
index 00000000000..583f946dcdc
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/gussetposition/en.md
@@ -0,0 +1,6 @@
+---
+title: "Gusset position"
+---
+
+This option allows you to shift the gusset forward or backward.
+
diff --git a/markdown/org/docs/designs/umbra/options/gussetposition/es.md b/markdown/org/docs/designs/umbra/options/gussetposition/es.md
new file mode 100644
index 00000000000..d05f2cf5ab2
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/gussetposition/es.md
@@ -0,0 +1,6 @@
+---
+title: "Posición del fuelle"
+---
+
+Esta opción te permite desplazar el fuelle hacia delante o hacia atrás.
+
diff --git a/markdown/org/docs/designs/umbra/options/gussetposition/fr.md b/markdown/org/docs/designs/umbra/options/gussetposition/fr.md
new file mode 100644
index 00000000000..32ca1dd32f6
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/gussetposition/fr.md
@@ -0,0 +1,6 @@
+---
+title: "Position du gousset"
+---
+
+Cette option te permet de décaler le gousset vers l'avant ou vers l'arrière.
+
diff --git a/markdown/org/docs/designs/umbra/options/gussetposition/nl.md b/markdown/org/docs/designs/umbra/options/gussetposition/nl.md
new file mode 100644
index 00000000000..6344b0aa5e5
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/gussetposition/nl.md
@@ -0,0 +1,6 @@
+---
+title: "Positie van de inzetrand"
+---
+
+Met deze optie kun je de inzetrand naar voren of naar achteren verschuiven.
+
diff --git a/markdown/org/docs/designs/umbra/options/gussetposition/uk.md b/markdown/org/docs/designs/umbra/options/gussetposition/uk.md
new file mode 100644
index 00000000000..37ee1d63835
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/gussetposition/uk.md
@@ -0,0 +1,6 @@
+---
+title: "Положення ластовиці"
+---
+
+Ця опція дозволяє змістити ластовицю вперед або назад.
+
diff --git a/markdown/org/docs/designs/umbra/options/gussetwidth/de.md b/markdown/org/docs/designs/umbra/options/gussetwidth/de.md
new file mode 100644
index 00000000000..ca185a9ac00
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/gussetwidth/de.md
@@ -0,0 +1,6 @@
+---
+title: "Zwickelbreite"
+---
+
+Diese Option steuert die minimale Breite im Schritt.
+
diff --git a/markdown/org/docs/designs/umbra/options/gussetwidth/en.md b/markdown/org/docs/designs/umbra/options/gussetwidth/en.md
new file mode 100644
index 00000000000..f2e6916062e
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/gussetwidth/en.md
@@ -0,0 +1,6 @@
+---
+title: "Gusset width"
+---
+
+This options controls the minimum width at the crotch.
+
diff --git a/markdown/org/docs/designs/umbra/options/legrise/de.md b/markdown/org/docs/designs/umbra/options/legrise/de.md
new file mode 100644
index 00000000000..f9015bba9f7
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/legrise/de.md
@@ -0,0 +1,6 @@
+---
+title: "Beinhöhe"
+---
+
+Diese Option legt fest, wie hoch das Bein ausgeschnitten ist.
+
diff --git a/markdown/org/docs/designs/umbra/options/legrise/en.md b/markdown/org/docs/designs/umbra/options/legrise/en.md
new file mode 100644
index 00000000000..24a9a8ec432
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/legrise/en.md
@@ -0,0 +1,6 @@
+---
+title: "Leg rise"
+---
+
+This option controls how high the leg is cut-out.
+
diff --git a/markdown/org/docs/designs/umbra/options/legrise/es.md b/markdown/org/docs/designs/umbra/options/legrise/es.md
new file mode 100644
index 00000000000..4403d31572e
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/legrise/es.md
@@ -0,0 +1,6 @@
+---
+title: "Elevación de la pierna"
+---
+
+Esta opción controla hasta qué punto se corta la pierna.
+
diff --git a/markdown/org/docs/designs/umbra/options/legrise/fr.md b/markdown/org/docs/designs/umbra/options/legrise/fr.md
new file mode 100644
index 00000000000..6cfde958be3
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/legrise/fr.md
@@ -0,0 +1,6 @@
+---
+title: "Montée des jambes"
+---
+
+Cette option permet de contrôler la hauteur à laquelle l'ouverture de la jambe est faite.
+
diff --git a/markdown/org/docs/designs/umbra/options/legrise/nl.md b/markdown/org/docs/designs/umbra/options/legrise/nl.md
new file mode 100644
index 00000000000..78c343e88d3
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/legrise/nl.md
@@ -0,0 +1,6 @@
+---
+title: "Beenverhoging"
+---
+
+Deze optie bepaalt hoe hoog de broekspijp is.
+
diff --git a/markdown/org/docs/designs/umbra/options/legrise/uk.md b/markdown/org/docs/designs/umbra/options/legrise/uk.md
new file mode 100644
index 00000000000..56f484be735
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/legrise/uk.md
@@ -0,0 +1,6 @@
+---
+title: "Підйом ноги"
+---
+
+Ця опція регулює висоту вирізу ніжки.
+
diff --git a/markdown/org/docs/designs/umbra/options/minfabricwidth/de.md b/markdown/org/docs/designs/umbra/options/minfabricwidth/de.md
new file mode 100644
index 00000000000..a3f534825e4
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/minfabricwidth/de.md
@@ -0,0 +1,8 @@
+---
+title: "Minimale Stoffbreite"
+---
+
+Steuert wie breit der Tanga-Riemen und das Seitenband minimal sein sollen.
+Hat keine Auswirkungen, wenn die Beinhöhe und die hintere Freilegung niedrig sind.
+
+Wenn die minimale Stoffbreite kleiner ist, als die doppelte Nahtzugabe, kann das Nähen knifflig werden.
diff --git a/markdown/org/docs/designs/umbra/options/minfabricwidth/en.md b/markdown/org/docs/designs/umbra/options/minfabricwidth/en.md
new file mode 100644
index 00000000000..7c2ff305764
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/minfabricwidth/en.md
@@ -0,0 +1,8 @@
+---
+title: "Minimum fabric width"
+---
+
+Controls the minimum width of the thong strip and side band.
+Does not have an effect if the back exposure and the leg rise is low.
+
+This might be tricky to sew if this is lower than twice the seam allowance.
diff --git a/markdown/org/docs/designs/umbra/options/pocketgap/de.md b/markdown/org/docs/designs/umbra/options/pocketgap/de.md
new file mode 100644
index 00000000000..f3fea03707b
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/pocketgap/de.md
@@ -0,0 +1,5 @@
+---
+title: Anstand zwischen den Taschen
+---
+
+Diese Option steuert den Abstand zwischen den Taschen. Falls die Taschen deaktiviert sind, hat sie keine Auswirkung. Indirekt steuert die Option, wie groß die Öffnung der mittleren Tasche ist.
diff --git a/markdown/org/docs/designs/umbra/options/pocketgap/en.md b/markdown/org/docs/designs/umbra/options/pocketgap/en.md
new file mode 100644
index 00000000000..c6a2bc727c4
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/pocketgap/en.md
@@ -0,0 +1,5 @@
+---
+title: Pocket gap
+---
+
+This option controls the distance between both side pockets. It only has an effect if pockets are used. This option indirectly controls how much space is available for inserting things into the center pocket.
diff --git a/markdown/org/docs/designs/umbra/options/pocketheight/de.md b/markdown/org/docs/designs/umbra/options/pocketheight/de.md
new file mode 100644
index 00000000000..78bec3f9c1a
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/pocketheight/de.md
@@ -0,0 +1,5 @@
+---
+title: Taschen-Höhe
+---
+
+Steuert, wie breit der Saum der Taschen sein soll oder an welcher Position die Reißverschlüsse platziert werden sollen. Hat keine Auswirkung, wenn Taschen deaktiviert sind.
diff --git a/markdown/org/docs/designs/umbra/options/pocketheight/en.md b/markdown/org/docs/designs/umbra/options/pocketheight/en.md
new file mode 100644
index 00000000000..525241fd839
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/pocketheight/en.md
@@ -0,0 +1,5 @@
+---
+title: Pocket height
+---
+
+This option controls the width of the pocket hem or the vertical position of the zippers. It only has an effect if pockets are used.
diff --git a/markdown/org/docs/designs/umbra/options/pockets/de.md b/markdown/org/docs/designs/umbra/options/pockets/de.md
new file mode 100644
index 00000000000..5698a130fc3
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/pockets/de.md
@@ -0,0 +1,5 @@
+---
+title: Taschen
+---
+
+Wähle zwischen folgenden Optionen aus: keine Taschen, Innentaschen (Zwei Innentaschen an den Seiten for Wertsachen sowie eine mittlere Tasche) oder Taschen mit Reißverschlüssen.
diff --git a/markdown/org/docs/designs/umbra/options/pockets/en.md b/markdown/org/docs/designs/umbra/options/pockets/en.md
new file mode 100644
index 00000000000..03206372d37
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/pockets/en.md
@@ -0,0 +1,5 @@
+---
+title: Pockets
+---
+
+Select, if you want no pockets, inside pockets (two pockets on the side for valuables and one pocket over the center of your body) or zipper pockets on the outside.
diff --git a/markdown/org/docs/designs/umbra/options/rise/de.md b/markdown/org/docs/designs/umbra/options/rise/de.md
new file mode 100644
index 00000000000..5cbd54510e7
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/rise/de.md
@@ -0,0 +1,6 @@
+---
+title: "Sitz"
+---
+
+Diese Option steuert die Höhe des Bundes. Ein Wert von 100% platziert den Bund auf Höhe der gemessenen Hüfte.
+
diff --git a/markdown/org/docs/designs/umbra/options/rise/en.md b/markdown/org/docs/designs/umbra/options/rise/en.md
new file mode 100644
index 00000000000..9c3f638bfa7
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/rise/en.md
@@ -0,0 +1,6 @@
+---
+title: "Rise"
+---
+
+This options controls the height of the waistband. A value of 100% will put the waistband on top of the hip measurement.
+
diff --git a/markdown/org/docs/designs/umbra/options/splitposition/de.md b/markdown/org/docs/designs/umbra/options/splitposition/de.md
new file mode 100644
index 00000000000..5aca1e5b46c
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/splitposition/de.md
@@ -0,0 +1,6 @@
+---
+title: "Schrittnaht"
+---
+
+Steuert die Position der Schrittnaht. Erhöhe den Wert, um die Schrittnaht für mehr Schutz nach hinten zu verschieben.
+
diff --git a/markdown/org/docs/designs/umbra/options/splitposition/en.md b/markdown/org/docs/designs/umbra/options/splitposition/en.md
new file mode 100644
index 00000000000..bf38870a500
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/splitposition/en.md
@@ -0,0 +1,6 @@
+---
+title: "Split position"
+---
+
+This options controls the length of the front piece in the crotch region. Increase this setting to add more protection towards the back.
+
diff --git a/markdown/org/docs/designs/umbra/options/xstretch/de.md b/markdown/org/docs/designs/umbra/options/xstretch/de.md
new file mode 100644
index 00000000000..5fd5eb12d11
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/xstretch/de.md
@@ -0,0 +1,6 @@
+---
+title: "Horizontale Stoffdehnung"
+---
+
+Stelle diese Option für mehr oder weniger dehnbare Stoffe ein, insbesondere für die horizontale Dehnung.
+
diff --git a/markdown/org/docs/designs/umbra/options/xstretch/en.md b/markdown/org/docs/designs/umbra/options/xstretch/en.md
new file mode 100644
index 00000000000..a7c95d930b0
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/xstretch/en.md
@@ -0,0 +1,8 @@
+---
+title: "Horizontal fabric stretch"
+---
+
+Adjust this option for more or less stretchy fabrics, specifically for horizontal stretch.
+
+Use the stretch you want the fabric to have when worn, not its maximum stretch.
+
diff --git a/markdown/org/docs/designs/umbra/options/xstretch/es.md b/markdown/org/docs/designs/umbra/options/xstretch/es.md
new file mode 100644
index 00000000000..6bae9595a97
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/xstretch/es.md
@@ -0,0 +1,6 @@
+---
+title: "Estiramiento horizontal del tejido"
+---
+
+Ajusta esta opción para tejidos más o menos elásticos, concretamente para el estiramiento horizontal.
+
diff --git a/markdown/org/docs/designs/umbra/options/xstretch/fr.md b/markdown/org/docs/designs/umbra/options/xstretch/fr.md
new file mode 100644
index 00000000000..99e5875982d
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/xstretch/fr.md
@@ -0,0 +1,6 @@
+---
+title: "Élasticité horizontale du tissu"
+---
+
+Ajuste cette option pour les tissus plus ou moins extensibles, plus précisément pour l'étirement horizontal.
+
diff --git a/markdown/org/docs/designs/umbra/options/xstretch/nl.md b/markdown/org/docs/designs/umbra/options/xstretch/nl.md
new file mode 100644
index 00000000000..b78a59cf1bd
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/xstretch/nl.md
@@ -0,0 +1,6 @@
+---
+title: "Horizontale stof stretch"
+---
+
+Pas deze optie aan voor meer of minder rekbare stoffen, specifiek voor horizontale stretch.
+
diff --git a/markdown/org/docs/designs/umbra/options/xstretch/uk.md b/markdown/org/docs/designs/umbra/options/xstretch/uk.md
new file mode 100644
index 00000000000..5d9807bc4fb
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/xstretch/uk.md
@@ -0,0 +1,6 @@
+---
+title: "Горизонтальна розтяжка тканини"
+---
+
+Налаштуйте цей параметр для більш-менш еластичних тканин, зокрема для горизонтального розтягування.
+
diff --git a/markdown/org/docs/designs/umbra/options/ystretch/de.md b/markdown/org/docs/designs/umbra/options/ystretch/de.md
new file mode 100644
index 00000000000..0f398b7fbce
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/ystretch/de.md
@@ -0,0 +1,6 @@
+---
+title: "Vertikale Stoffdehnung"
+---
+
+Stelle diese Option für mehr oder weniger dehnbare Stoffe ein, insbesondere für die vertikale Dehnung.
+
diff --git a/markdown/org/docs/designs/umbra/options/ystretch/en.md b/markdown/org/docs/designs/umbra/options/ystretch/en.md
new file mode 100644
index 00000000000..865e6123d7f
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/ystretch/en.md
@@ -0,0 +1,7 @@
+---
+title: "Vertical fabric stretch"
+---
+
+Adjust this option for more or less stretchy fabrics, specifically for vertical stretch.
+
+Use the stretch you want the fabric to have when worn, not its maximum stretch.
diff --git a/markdown/org/docs/designs/umbra/options/ystretch/es.md b/markdown/org/docs/designs/umbra/options/ystretch/es.md
new file mode 100644
index 00000000000..7d0820837e8
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/ystretch/es.md
@@ -0,0 +1,6 @@
+---
+title: "Estiramiento vertical del tejido"
+---
+
+Ajusta esta opción para tejidos más o menos elásticos, concretamente para el estiramiento vertical.
+
diff --git a/markdown/org/docs/designs/umbra/options/ystretch/fr.md b/markdown/org/docs/designs/umbra/options/ystretch/fr.md
new file mode 100644
index 00000000000..227aeb0ad54
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/ystretch/fr.md
@@ -0,0 +1,6 @@
+---
+title: "Élasticité verticale du tissu"
+---
+
+Ajuste cette option pour les tissus plus ou moins extensibles, plus particulièrement pour l'étirement vertical.
+
diff --git a/markdown/org/docs/designs/umbra/options/ystretch/nl.md b/markdown/org/docs/designs/umbra/options/ystretch/nl.md
new file mode 100644
index 00000000000..04f6dbccbd4
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/ystretch/nl.md
@@ -0,0 +1,6 @@
+---
+title: "Verticale stofstretch"
+---
+
+Pas deze optie aan voor meer of minder rekbare stoffen, specifiek voor verticale stretch.
+
diff --git a/markdown/org/docs/designs/umbra/options/ystretch/uk.md b/markdown/org/docs/designs/umbra/options/ystretch/uk.md
new file mode 100644
index 00000000000..fca7c583e84
--- /dev/null
+++ b/markdown/org/docs/designs/umbra/options/ystretch/uk.md
@@ -0,0 +1,6 @@
+---
+title: "Вертикальна розтяжка тканини"
+---
+
+Налаштуйте цей параметр для більш-менш еластичних тканин, зокрема для вертикального розтягування.
+
diff --git a/markdown/org/docs/designs/wahid/fabric/fr.md b/markdown/org/docs/designs/wahid/fabric/fr.md
index 35063c237f7..6bbfce2ee00 100644
--- a/markdown/org/docs/designs/wahid/fabric/fr.md
+++ b/markdown/org/docs/designs/wahid/fabric/fr.md
@@ -2,7 +2,7 @@
title: "Gilet Wahid : Options de tissu"
---
-Tous les tissus de costumes sont un très bon choix pour votre gilet. Toute boutique en tissu qui se respecte devrait avoir une catégorie avec du tissu pour costume. Vous pouvez simplement entrer, demander où vous pouvez trouver le tissu pour des costumes, et choisir quelque chose que vous aimez.
+Tous les tissus de costumes sont un très bon choix pour votre gilet. Toute boutique de tissu qui se respecte devrait avoir une catégorie avec du tissu pour costume. Vous pouvez simplement entrer, demander où vous pouvez trouver le tissu pour des costumes, et choisir quelque chose que vous aimez.
Ces tissus sont généralement en laine, mais vous pouvez aussi être un peu plus créatif et opter pour autre chose.
diff --git a/markdown/org/docs/designs/wahid/instructions/de.md b/markdown/org/docs/designs/wahid/instructions/de.md
index 055a1399698..08782e6784b 100644
--- a/markdown/org/docs/designs/wahid/instructions/de.md
+++ b/markdown/org/docs/designs/wahid/instructions/de.md
@@ -86,7 +86,7 @@ Wenn Sie fertig sind, drücken Sie diese Naht öffnen.
#### Markieren, wohin deine Tasche gehen muss
-
+
Ihr Frontmusterstück hat eine Helpline um zu zeigen, wohin die Welttasche gehen soll. Es sind zwei halbe Rechtecke, die zusammengeführt wurden, als du den Dart geschlossen hast, um die Form deiner Welttasche zu formen.
@@ -116,7 +116,7 @@ Nähen Sie nun entlang der Helpline, die den langen Rand Ihrer Tasche markiert.
#### Die Tasche öffnen
-
+
Zeit, die Tasche sorgfältig zu öffnen. Beginnen Sie in der Mitte der Tasche und schneiden Sie entlang der längsten Kanten zur Seite.
@@ -126,7 +126,7 @@ An den Kanten Ihrer Tasche müssen Sie aufhören, die Mitte zu öffnen und statt
#### Öffne die Naht
-
+
Drücken Sie die Naht entlang der langen Kanten der Tasche zu öffnen.
diff --git a/markdown/org/docs/designs/wahid/instructions/es.md b/markdown/org/docs/designs/wahid/instructions/es.md
index 39f128f3c2c..bf886833cb7 100644
--- a/markdown/org/docs/designs/wahid/instructions/es.md
+++ b/markdown/org/docs/designs/wahid/instructions/es.md
@@ -86,7 +86,7 @@ Cuando haya terminado, presione Abrir esta costura.
#### Marca a dónde tiene que ir tu bolsillo
-
+
Su pieza de patrón frontal tiene una línea de ayuda en ella para mostrar a dónde debe ir el bolsillo de soldadura. Son dos mitad rectángulos que se unieron cuando cerraste el dardo para formar la forma de tu bolsillo de soldadura.
@@ -116,7 +116,7 @@ Ahora coser a lo largo de la línea de ayuda que marca el largo borde de tu bols
#### Cortar el bolsillo
-
+
Es hora de cortar cuidadosamente el bolsillo. Empezar en el centro del bolsillo y cortar hacia los bordes más largos hacia el lado.
@@ -126,7 +126,7 @@ En los bordes de su bolsillo usted necesita dejar de cortar el centro y en su lu
#### Pulse abrir la costura
-
+
Pulse abrir la costura a lo largo de los bordes largos de su bolsillo.
diff --git a/markdown/org/docs/designs/wahid/instructions/fr.md b/markdown/org/docs/designs/wahid/instructions/fr.md
index 42bc2b7f9eb..c7fd906fe52 100644
--- a/markdown/org/docs/designs/wahid/instructions/fr.md
+++ b/markdown/org/docs/designs/wahid/instructions/fr.md
@@ -86,7 +86,7 @@ Lorsque vous avez terminé, repassez sur cette couture avec les marges ouvertes.
#### Marquer l'emplacement de votre poche
-
+
Votre pièce de patron avant possède une ligne d'aide pour montrer où doit être placée la poche passepoilée. Il s'agit de deux demi-rectangles réunis lors de la couture de la pince pour créer la forme de votre poche passepoilée.
@@ -116,7 +116,7 @@ Cousez maintenant le long de la ligne d’aide qui marque le bord long de votre
#### Couper et ouvrir la poche
-
+
Il est temps de couper soigneusement la poche. Commencez au milieu de la poche et coupez le long des bords les plus longs vers le côté.
@@ -126,7 +126,7 @@ Aux bords de votre poche, vous devez arrêter d'ouvrir le centre un peu avant et
#### Repasser pour ouvrir la marge de couture
-
+
Repassez pour ouvrir la marge de couture le long des bords longs de votre poche.
@@ -140,7 +140,7 @@ Retournez le parement de poche vers l'arrière et repassez.

-Move your pocket facing out of the way to reveal those little triangles at the side of your pocket.
+Déplacez votre parement de poche sur le côté pour révéler ces petits triangles sur le côté de votre poche.
Repliez-les vers l'arrière en vous assurant de garder un rectangle parfait pour l'ouverture de poche, puis repassez-les.
diff --git a/markdown/org/docs/designs/wahid/instructions/nl.md b/markdown/org/docs/designs/wahid/instructions/nl.md
index def22d5d8f6..13f2aa053d9 100644
--- a/markdown/org/docs/designs/wahid/instructions/nl.md
+++ b/markdown/org/docs/designs/wahid/instructions/nl.md
@@ -86,7 +86,7 @@ Strijk deze naad open wanneer je klaar bent.
#### Markeer waar je zak moet komen
-
+
Je voorpand heeft een hulplijn om aan te geven waar de paspelzak moet komen. Het zijn twee halve rechthoeken die samenkwamen wanneer je de neep sloot, en samen de vorm van je paspelzak hebben.
@@ -116,7 +116,7 @@ Stik nu langs de hulplijnen die de lange rand van je zakopening aangeeft.
#### Knip de zak open
-
+
Tijd om de zak voorzichtig open te knippen. Begin in het midden van de zakopening, en knip langs de lange randen naar de zijkant.
@@ -126,7 +126,7 @@ Aan de zijranden van de zakopening moet je stoppen met in het midden te knippen
#### Strijk de naadwaarde open
-
+
Strijk de naadwaarde aan de lange kanten van je zakopening open.
diff --git a/markdown/org/docs/designs/wahid/instructions/uk.md b/markdown/org/docs/designs/wahid/instructions/uk.md
index bb6b54e0c26..8fe2326f2ad 100644
--- a/markdown/org/docs/designs/wahid/instructions/uk.md
+++ b/markdown/org/docs/designs/wahid/instructions/uk.md
@@ -86,7 +86,7 @@ title: "Жилет вахід: Інструкція з пошиття"
#### Позначте, куди має йти ваша кишеня
-
+
На передній частині викрійки є допоміжна лінія, яка показує, де повинна знаходитися кишеня з прорізним швом. Це два напівпрямокутники, які з'єдналися разом, коли ви закрили виточку, щоб сформувати форму кишені.
@@ -116,7 +116,7 @@ title: "Жилет вахід: Інструкція з пошиття"
#### Розріжте кишеню
-
+
Час акуратно розрізати кишеню. Почніть з середини кишені і розріжте вздовж найдовших країв у бік.
@@ -126,7 +126,7 @@ title: "Жилет вахід: Інструкція з пошиття"
#### Розкрийте припуск на шов
-
+
Розпрасуйте припуски на шви вздовж довгих країв кишені.
diff --git a/markdown/org/docs/designs/wahid/notes/fr.md b/markdown/org/docs/designs/wahid/notes/fr.md
index c603f009100..6c831367f2e 100644
--- a/markdown/org/docs/designs/wahid/notes/fr.md
+++ b/markdown/org/docs/designs/wahid/notes/fr.md
@@ -2,7 +2,7 @@
title: "Gilet Wahid Notes du créateur"
---
-J'aime les gilets. I think they are not only pretty to look at, they are also warm, cut down on the amount of shirt ironing you have to do, and have these cute little pockets you can put tiny things in.
+J'aime les gilets. Je pense qu'elles ne sont pas seulement jolies à regarder, elles sont aussi chaudes, réduisent la quantité de repassage de chemise que tu dois faire, et ont ces petites poches mignonnes dans lesquelles tu peux mettre des choses minuscules.
J'ai donc conçu Wahid pour pouvoir me fabriquer des gilets.
diff --git a/markdown/org/docs/designs/wahid/options/armholedepth/fr.md b/markdown/org/docs/designs/wahid/options/armholedepth/fr.md
index 2d1e031d61e..3be31826815 100644
--- a/markdown/org/docs/designs/wahid/options/armholedepth/fr.md
+++ b/markdown/org/docs/designs/wahid/options/armholedepth/fr.md
@@ -4,5 +4,5 @@ title: "Profondeur d'emmanchure"
Cette option contrôle la profondeur de l'emmanchure.
-Cette option s'applique à la nouvelle façon v3 de calculer la profondeur de l'emmanchure. Si tu actives l'option [legacy armhole depth](/docs/designs/wahid/options/legacyarmholedepth) , cette option ne s'appliquera pas, mais c'est sa version legacy [armhole depth factor](/docs/designs/wahid/options/armholedepthfactor) qui s'appliquera.
+Cette option s'applique à la nouvelle façon v3 de calculer la profondeur de l'emmanchure. Si tu actives l'option [profondeur d'emmanchure legacy](/docs/designs/wahid/options/legacyarmholedepth) , cette option ne s'appliquera pas, mais c'est sa version legacy [facteur de profondeur d'emmanchure](/docs/designs/wahid/options/armholedepthfactor) qui s'appliquera.
diff --git a/markdown/org/docs/designs/wahid/options/legacyarmholedepth/fr.md b/markdown/org/docs/designs/wahid/options/legacyarmholedepth/fr.md
index 84cecd2bffc..63017bdf014 100644
--- a/markdown/org/docs/designs/wahid/options/legacyarmholedepth/fr.md
+++ b/markdown/org/docs/designs/wahid/options/legacyarmholedepth/fr.md
@@ -8,4 +8,4 @@ L'ancienne méthode (v2) utilisait la circonférence du biceps pour estimer la p
La méthode v3 utilise plutôt la mesure de la taille à l'aisselle pour situer le bas de l'emmanchure.
-Si tu actives cette option, le bloc Brian reviendra à la façon v2 de calculer la profondeur de l'emmanchure, et Wahid suivra.
+Si tu actives cette option, le bloc Brian reviendra à la façon v2 pour calculer la profondeur de l'emmanchure, et Wahid suivra.
diff --git a/markdown/org/docs/designs/wahid/options/weltheight/fr.md b/markdown/org/docs/designs/wahid/options/weltheight/fr.md
index 2c20e3a92f6..73a2e131146 100644
--- a/markdown/org/docs/designs/wahid/options/weltheight/fr.md
+++ b/markdown/org/docs/designs/wahid/options/weltheight/fr.md
@@ -2,7 +2,7 @@
title: "Hauteur du revers de poche"
---
-Contrôle la hauteur des douilles de poche.
+Contrôle la hauteur des passepoils de poche.
diff --git a/markdown/org/newsletter/2022q4/uk.md b/markdown/org/newsletter/2022q4/uk.md
index 8b0d70449ca..ebef1781797 100644
--- a/markdown/org/newsletter/2022q4/uk.md
+++ b/markdown/org/newsletter/2022q4/uk.md
@@ -37,7 +37,7 @@ FreeSewing 2.22 вийшов наприкінці серпня, в ньому з
### Конфігурація на рівні частин, також відома як підтримка пакетів
-На [нашій дорожній карті](https://github.com/freesewing/freesewing/discussions/1278) - яка, якщо ви звернули увагу, містить все більше речей під заголовком *вже реалізованих* - у нас була так звана підтримка *пакетів*. Ідея полягала в тому, що ми хотіли б дати можливість створювати дизайн, вільно комбінуючи різні компоненти. Наприклад, ви можете взяти рукава з набору рукавів, комір з набору комірів, додати кишені з набору комірів, і так далі.
+На [нашій дорожній карті](https://github.com/freesewing/freesewing/discussions/1278) - яка, якщо ви звернули увагу, містить все більше речей під заголовком *вже реалізованих* - у нас була так звана підтримка *пакетів*. Ідея полягала в тому, що ми хотіли б дати можливість створювати дизайн, вільно комбінуючи різні компоненти. Наприклад, ви можете взяти рукава з набору рукавів *, комір з набору комірів *, додати кишені з набору комірів *,* і так далі.
Це одна з тих речей, яка має багато сенсу, але викликає питання: Як все це буде працювати під капотом? У версії 2 FreeSewing реалізація цих ідей була б нетривіальною, тому що, хоча ми підтримуємо розширення викрійок на інші дизайни, цей процес є надто громіздким для такого рівня спеціального поєднання різних дизайнів.
diff --git a/markdown/org/newsletter/2023q1/fr.md b/markdown/org/newsletter/2023q1/fr.md
index f5b6c68565c..e2fcd826ce0 100644
--- a/markdown/org/newsletter/2023q1/fr.md
+++ b/markdown/org/newsletter/2023q1/fr.md
@@ -69,7 +69,7 @@ Le chiffre d'affaires de FreeSewing au cours de l'année 2022 était de `9,325,5
Nous avons constaté un énorme afflux d'utilisateurs, de mécènes et de revenus en 2020 sans doute parce que [notre modèle de masque facial](https://freesewing.org/designs/florence/) a été follement populaire pendant la pénurie d'EPI cette année-là. Ce pic s'est atténué depuis, et a entraîné une tendance à la baisse des revenus d'une année sur l'autre. De plus, l'inflation et la crise du coût de la vie ont été particulièrement tangibles cette année, et j'ai reçu plus d'un message d'excuse de la part de mécènes qui voulaient continuer à nous soutenir mais qui se sont sentis obligés de nous supprimer de leur budget mensuel pour être sûrs de pouvoir subvenir à leurs besoins et/ou à ceux de leur famille.
-Je ne me sens donc pas mal à l'idée que les revenus soient moins élevés cette année. Je pense que l'année a été difficile pour beaucoup de gens, et nous avons toujours cherché à obtenir le soutien de ceux qui pouvaient l'épargner sans difficultés. Oui, c'est agréable de franchir la barrière des 10 000 `. Oui, j'aimerais bien arriver à `12.000` et atteindre `1.000` MRR (monthly recurring revenue) mais je ne vais pas laisser cela m'empêcher d'être fière du travail que nous faisons.
+Je ne me sens donc pas mal à l'idée que les revenus soient moins élevés cette année. Je pense que l'année a été difficile pour beaucoup de gens, et nous avons toujours cherché à obtenir le soutien de ceux qui pouvaient l'épargner sans difficultés. Oui, c'est agréable de franchir la barrière des 10.000. Oui, j'aimerais bien arriver à `12.000` et atteindre `1.000` MRR (monthly recurring revenue) mais je ne vais pas laisser cela m'empêcher d'être fière du travail que nous faisons.
Je suis fière non seulement du travail que nous faisons, mais aussi parce que FreeSewing est une force pour le bien dans ce monde. En ajoutant les `9.325,54`de cette année, les contributions de FreeSewing à [Médecins sans frontières/Doctors Without Borders](https://www.msf.org/) s'élèvent à `38.814,94` euros ou environ 41,6k dollars américains. De l'argent qui aide les gens qui sont dans une situation pire que la nôtre.
diff --git a/markdown/org/newsletter/2024q1/de.md b/markdown/org/newsletter/2024q1/de.md
index 7cb36f62a7e..45b06d8e8ee 100644
--- a/markdown/org/newsletter/2024q1/de.md
+++ b/markdown/org/newsletter/2024q1/de.md
@@ -40,7 +40,7 @@ und mach weiter so.
-***
+---
@@ -94,7 +94,7 @@ zu wenden! Bis dahin werden wir sehen, was die Zukunft bringt.
-***
+---
@@ -124,7 +124,7 @@ Ich schätze Wouters Ansatz sehr: Er hat seine eigenen Bedürfnisse, die ihn zu
-***
+---
@@ -164,7 +164,7 @@ Wir werden sehen, wie es läuft. You can find out for yourself, we're [@freesewi
-***
+---
@@ -178,7 +178,7 @@ Ok, dann hoffen wir mal, dass am Ende alles gut gegangen ist. Aber zur Erinnerun
-***
+---
@@ -187,7 +187,7 @@ Ok, dann hoffen wir mal, dass am Ende alles gut gegangen ist. Aber zur Erinnerun
2023 war kein einfaches Jahr für mich persönlich und auch nicht für FreeSewing. The amount of time and effort that went into v3 is something that takes a lot out of you, and I am not ashamed to admit that more than any other year before I've struggled with feelings of _why am I even doing this_.
Aber heute bin ich glücklich und stolz, weil FreeSewing im Jahr 2023 einen Umsatz von **10.222,07€** ($11.301) erzielt hat.
-Wie du vielleicht weißt, gehen [alle Einnahmen von FreeSewing an Ärzte ohne Grenzen] (https\://freesewing.org/docs/about/pledge). Das bedeutet, dass 10.222,07 € für einige der bedürftigsten Menschen auf diesem Planeten gespendet wurden.
+Wie du vielleicht weißt, gehen [alle Einnahmen von FreeSewing an Ärzte ohne Grenzen] (https://freesewing.org/docs/about/pledge). Das bedeutet, dass 10.222,07 € für einige der bedürftigsten Menschen auf diesem Planeten gespendet wurden.
Ich freue mich besonders, dass wir wieder über die 10-Kilometer-Marke geklettert sind, nachdem wir ein paar Jahre in Folge unter diese Marke gerutscht sind.
diff --git a/markdown/org/newsletter/2024q1/es.md b/markdown/org/newsletter/2024q1/es.md
index 0c9eac06153..df8465fcfcc 100644
--- a/markdown/org/newsletter/2024q1/es.md
+++ b/markdown/org/newsletter/2024q1/es.md
@@ -40,7 +40,7 @@ y sigue así.
-***
+---
@@ -95,7 +95,7 @@ para aportar ideas. Hasta entonces, veremos qué nos depara el futuro.
-***
+---
@@ -125,7 +125,7 @@ Realmente aprecio el enfoque de Wouter, que tiene sus propias necesidades como i
-***
+---
@@ -164,7 +164,7 @@ Supongo que ya veremos cómo va. Puedes averiguarlo por ti mismo, estamos [@free
-***
+---
@@ -178,7 +178,7 @@ Vale, espero que al final todo haya ido bien. Pero como recordatorio: Puedes rec
-***
+---
diff --git a/markdown/org/newsletter/2024q1/fr.md b/markdown/org/newsletter/2024q1/fr.md
index f26e5ce35a3..5f543848f4e 100644
--- a/markdown/org/newsletter/2024q1/fr.md
+++ b/markdown/org/newsletter/2024q1/fr.md
@@ -40,7 +40,7 @@ et continuez comme ça.
-***
+---
@@ -95,7 +95,7 @@ pour nous faire part de tes idées ! D'ici là, nous verrons ce que l'avenir nou
-***
+---
@@ -125,7 +125,7 @@ J'apprécie vraiment l'approche de Wouter, qui a ses propres besoins qui sont à
-***
+---
@@ -165,7 +165,7 @@ Je suppose que nous verrons comment ça se passe. You can find out for yourself,
-***
+---
@@ -179,7 +179,7 @@ Ok, alors voilà, j'espère que tout s'est bien passé à la fin. Mais pour rapp
-***
+---
@@ -188,7 +188,7 @@ Ok, alors voilà, j'espère que tout s'est bien passé à la fin. Mais pour rapp
2023 n'a pas été une année facile pour moi personnellement, ni pour FreeSewing d'ailleurs. The amount of time and effort that went into v3 is something that takes a lot out of you, and I am not ashamed to admit that more than any other year before I've struggled with feelings of _why am I even doing this_.
Cependant, aujourd'hui, je me sens heureuse et fière parce que les recettes de FreeSewing pour 2023 ont atteint **10 222,07** (11 301 $).
-Comme tu le sais peut-être ou non, [tous les revenus de FreeSewing sont reversés à Médecins sans frontières] (https\://freesewing.org/docs/about/pledge), ce qui signifie que 10 222,07 € ont été versés pour aider certaines des personnes les plus vulnérables de cette planète.
+Comme tu le sais peut-être ou non, [tous les revenus de FreeSewing sont reversés à Médecins sans frontières] (https://freesewing.org/docs/about/pledge), ce qui signifie que 10 222,07 € ont été versés pour aider certaines des personnes les plus vulnérables de cette planète.
Je suis particulièrement heureux que nous ayons repassé au-dessus de la barre des 10 000, après être descendus en dessous plusieurs années de suite.
diff --git a/markdown/org/newsletter/2024q1/nl.md b/markdown/org/newsletter/2024q1/nl.md
index 9f08b603336..cdb3f727252 100644
--- a/markdown/org/newsletter/2024q1/nl.md
+++ b/markdown/org/newsletter/2024q1/nl.md
@@ -40,7 +40,7 @@ en ga zo door.
-***
+---
@@ -95,7 +95,7 @@ te bellen met ideeën! Tot die tijd zien we wel wat de toekomst brengt.
-***
+---
@@ -125,7 +125,7 @@ Ik waardeer Wouter's aanpak echt, waarbij hij zijn eigen behoeften heeft die de
-***
+---
@@ -165,7 +165,7 @@ Ik denk dat we wel zullen zien hoe het gaat. Je kunt het zelf ontdekken, we zijn
-***
+---
@@ -179,7 +179,7 @@ Ok, hopelijk is het uiteindelijk allemaal goed gegaan. Maar ter herinnering: Je
-***
+---
diff --git a/markdown/org/newsletter/2024q1/uk.md b/markdown/org/newsletter/2024q1/uk.md
index 5c96880f2d7..e5e1ef8f3be 100644
--- a/markdown/org/newsletter/2024q1/uk.md
+++ b/markdown/org/newsletter/2024q1/uk.md
@@ -40,7 +40,7 @@ title: 2024 Зимове видання
-***
+---
@@ -70,7 +70,7 @@ title: 2024 Зимове видання
відбудуться 4 та 18 січня. Ви також можете знайти дати на вкладці "Події" на сервері
FreeSewing Discord (знаходиться вгорі ліворуч). Ви можете написати мені
на @lexander2002 на Discord або Діані (головному організатору) на
-dianawildschut\@posteo.net, щоб повідомити нам, що ви прийдете :-) Ви можете знайти De War
+dianawildschut@posteo.net, щоб повідомити нам, що ви прийдете :-) Ви можете знайти De War
за адресою Heiligenbergerweg 34, 3816 AK, в Амерсфорті. Ми запрошуємо людей не тільки користуватися
, але й зробити свій внесок у забезпечення життєдіяльності "Де Війни". Сайт
працює на безоплатній основі, "ціноутворення на основі сприйнятої цінності".
@@ -95,7 +95,7 @@ FreeSewing також буде частиною їхнього дводенно
-***
+---
@@ -103,7 +103,7 @@ FreeSewing також буде частиною їхнього дводенно
На FreeSewing.org з'явилися два нових дизайни, про які ви, можливо, ще не знаєте. Звернімося до Воутера, який підписався за них обох, тож давайте послухаємо, що він скаже:
-[Отіс] (https\://freesewing.org/designs/otis) - дитячий комбінезон:
+[Отіс] (https://freesewing.org/designs/otis) - дитячий комбінезон:
> _Коли у моєї племінниці народилася дитина, я знала, що робити: пошити їй одяг для малюка. І я ніколи не шила одягу для немовлят. What they should look like was easy. У мене були власні діти багато років тому, і суцільнолиті речі повинні бути простими у виготовленні_.
>
@@ -125,14 +125,14 @@ FreeSewing також буде частиною їхнього дводенно
-***
+---
## Ми (ледве) вчимося.
> _Щодо назви: Я думаю, що молодші за мене люди називають Instagram "грамом", тому я взяв це і зробив дієслово, бо що може бути кращим способом продемонструвати, що я не маю жодного уявлення про те, про що говорю._
-> _Це також заплутана відсилка до [допису в блозі 6 з половиною років тому] (https\://freesewing.org/blog/freesewing-goes-jamstack), тож якщо ви це зрозуміли, то вітаю, але я відволікаюся._
+> _Це також заплутана відсилка до [допису в блозі 6 з половиною років тому] (https://freesewing.org/blog/freesewing-goes-jamstack), тож якщо ви це зрозуміли, то вітаю, але я відволікаюся._
>
> _Інстаграм. Я говорю про Instagram. Або в більш широкому сенсі - все те, що ми робимо (і не робимо), щоб "просувати" вільне шиття, підвищувати обізнаність і так далі. Назвемо його **marketing**._.
@@ -161,11 +161,11 @@ FreeSewing також буде частиною їхнього дводенно
Тож я трохи трепетно ставлюся до того, щоб знову долучитися до боротьби, але я також усвідомлюю той факт, що жодна робота не має значення, якщо люди принаймні не можуть якось про неї дізнатися.
Тож я не впевнений, як мені це вдасться, і боюся, що тут немає великого висновку. Я просто хотів поділитися своїми думками з цього приводу.
-Побачимо, як воно буде. Ви можете переконатися в цьому самі, ми [@freesewing_org] (https\://www\.instagram.com/freesewing_org/) на _грамах_.
+Побачимо, як воно буде. Ви можете переконатися в цьому самі, ми [@freesewing_org] (https://www.instagram.com/freesewing_org/) на _грамах_.
-***
+---
@@ -179,7 +179,7 @@ FreeSewing також буде частиною їхнього дводенно
-***
+---
@@ -188,7 +188,7 @@ FreeSewing також буде частиною їхнього дводенно
2023 рік був непростим як для мене особисто, так і для FreeSewing. Кількість часу та зусиль, витрачених на створення v3, забирає багато сил, і мені не соромно зізнатися, що більше, ніж у будь-який інший рік до цього, я боровся з почуттям "навіщо я взагалі це роблю".
Однак сьогодні я відчуваю себе щасливою і гордою, тому що дохід FreeSewing за 2023 рік склав **€10,222,07** ($11,301).
-Як ви, можливо, знаєте, [весь дохід FreeSewing йде до організації "Лікарі без кордонів"] (https\://freesewing.org/docs/about/pledge), а це означає, що 10 222,07 євро пішли на допомогу найуразливішим людям на нашій планеті.
+Як ви, можливо, знаєте, [весь дохід FreeSewing йде до організації "Лікарі без кордонів"] (https://freesewing.org/docs/about/pledge), а це означає, що 10 222,07 євро пішли на допомогу найуразливішим людям на нашій планеті.
Я особливо радий, що ми знову піднялися вище позначки в 10 тисяч, після того, як кілька років поспіль опускалися нижче.
diff --git a/markdown/org/newsletter/2024q2/de.md b/markdown/org/newsletter/2024q2/de.md
new file mode 100644
index 00000000000..d35aee4843a
--- /dev/null
+++ b/markdown/org/newsletter/2024q2/de.md
@@ -0,0 +1,274 @@
+---
+date: 2024-04-01
+edition: 2024q2
+intro: Willkommen zur Frühlingsausgabe 2024 des FreeSewing-Newsletters.
+title: 2024 Frühjahrsausgabe
+---
+
+Willkommen zur Frühlingsausgabe 2024 des FreeSewing-Newsletters.
+
+Hier ist das, was wir heute für dich haben, kein Scherz:
+
+- 👕 FreeSewing 3.2 bringt Tristan, Lumina, Lumira und mehr (3-Minuten-Lesung von joost)
+- 📨 E-Mail ist wieder schwieriger geworden (1-minute read by joost)
+- 🕸️ Aufbau des Vertrauensnetzes von FreeSewing nach dem XZ-Backdoor-Versuch (5-Minuten von joost)
+- 🤔 Wie sich die Herausforderungen von FreeSewing im Laufe der Zeit verändert haben (2-Minuten-Lesung von joost)
+
+Sollen wir loslegen?
+
+
+
+
+
+## 👕 FreeSewing 3.2 bringt Tristan, Lumina, Lumira und mehr
+
+Wir haben FreeSewing v3.2 im ersten Quartal 2024 veröffentlicht und es enthält 3 neue
+Designs sowie eine Reihe von Fehlerbehebungen und Verbesserungen.
+
+Werfen wir einen Blick auf die Highlights:
+
+### The Tristan Top
+
+Als erstes gibt es [das Tristan Top] (https\://freesewing.org/designs/tristan). Tristan ist ein Oberteil mit Prinzessnähten und (optionaler) Schnürung vorne oder/und hinten. Seine Entstehungsgeschichte ist die Notwendigkeit eines Kostüms für ein Renaissance-Festival, also ist das wahrscheinlich ein guter Indikator dafür, was dich erwartet.
+
+Tristan wurde von Natalia entworfen, die auch [einen Blogbeitrag über das neue Tristan-Design geschrieben hat] (https\://freesewing.org/blog/our-newest-design-is-the-tristan-top), also ist das ein guter Ort, um alle Details über dieses neue Design zu erfahren.
+
+### The Lumina and Lumira Leggings
+
+Ich gebe dir eine Sekunde, um den Titel noch einmal zu überfliegen, aber ja, es gibt zwei verschiedene Leggings-Muster mit ähnlichen Namen: [die Lumira Leggings] (https\://freesewing.org/designs/lumira) und die [Lumina Leggings] (https\://freesewing.org/designs/lumina).
+
+Ich empfehle dir, die Designernotizen für [Lumina] (https\://freesewing.org/designs/lumina#notes) und [Lumira] (https\://freesewing.org/designs/lumira#notes) zu lesen, um den Unterschied zwischen diesen Designs zu verstehen, zu verstehen, warum sie sich unterscheiden und zu wissen, was für dich am besten geeignet ist.
+
+### Bug fixes and improvements
+
+Regelmäßige Leserinnen und Leser des Newsletters wissen, dass wir auf
+laufend Verbesserungen vornehmen, die nicht an eine neue Version gebunden sind,
+aber es ist eine gute Gelegenheit, sie aufzulisten.
+
+- Sandy hat eine neue Paneele
+ Option, die
+ von [Paula](https://github.com/freesewing/freesewing/pull/5861) hinzugefügt wurde. Du
+ könntest deinen kreisförmigen Rock auch aus mehreren ähnlichen Mustern zusammenstellen, indem du
+ selbst anpasst, aber das übernimmt jetzt das Muster für dich.
+- Was als [Fehlerbericht für die Bizeps-Erleichterung auf
+ Jaeger] (https\://github.com/freesewing/freesewing/issues/5999) begann, endete mit einer
+ Änderung der Art und Weise, wie der Armumfang auf Brian berechnet wird, insbesondere die Tiefe
+ des Armlochs. Da Brian unser grundlegendster Block ist, wird dies
+ Auswirkungen auf viele andere Entwürfe haben.
+- In [Carlton](https://freesewing.org/designs/carlton) - und damit auch in
+ [Carlita](https://freesewing.org/designs/carlita) - haben wir
+ korrigiert, wo die Nahtzugabe am Unterkragen falsch eingezeichnet war.
+- In [Charlie](https://freesewing.org/designs/charlie) wurde bei der Gesäßtaschenleiste
+ (4) und der Vordertaschenleiste (8) fälschlicherweise angegeben, dass 2 statt 4
+ in der Schnittliste geschnitten werden. This too is resolved.
+- In [Hugo](https://freesewing.org/designs/hugo) haben wir einen Fehler behoben, der dazu führte, dass
+ das Design fehlerhaft war, wenn die vollständige Einstellung ausgeschaltet war, und wir haben ein Problem
+ behoben, bei dem die Öffnung der Vordertasche mit zunehmendem Hüftumfang
+ immer enger wurde.
+- Wir haben eine neue
+ [Path.combine()](https://freesewing.dev/reference/api/path/combine) Methode zu
+ [unserer Kern-API](https://freesewing.dev/reference/api) hinzugefügt. Dabei ging es darum, wie Path.join() Lücken in den
+ verbundenen Pfaden - die entweder durch "Verschiebe"-Operationen oder durch einen Unterschied zwischen
+ dem End- und dem Startpunkt der verbundenen Pfade verursacht werden - mit einem Liniensegment
+ ausgefüllt werden. Dieses Verhalten wird erwartet/beabsichtigt, aber wir haben
+ `Path.combine()` hinzugefügt, um das andere Verhalten zu erleichtern: Das Kombinieren verschiedener Pfade
+ zu einem einzigen Pfadobjekt, ohne dass sich die Zeichenoperationen ändern.
+- Das [Titelmakro] (https\://freesewing.dev/reference/macros/title) kann jetzt
+ mit einer `Noten`- und `Klassen.Noten`-Einstellung in seiner Konfiguration konfiguriert werden, was es
+ Designern ermöglicht, Noten zu (dem Titel) eines Musterteils hinzuzufügen.
+- Unser [i18n plugin](https://freesewing.dev/reference/plugins/i18n) unterstützt jetzt
+ die Übersetzung von verschachtelten Arrays von Strings, was Designern
+ mehr Flexibilität bei der Verkettung von übersetzten Teilen von Strings gibt.
+
+Im [FreeSewing 3.2 Ankündigungs-Blogpost] (https\://freesewing.org/blog/v3-2-0) findest du alle Details.
+
+
+
+---
+
+
+
+## 📨 E-Mail ist gerade wieder schwieriger geworden
+
+Wenn du dies in deinem Posteingang liest und nicht in einer archivierten Kopie auf
+FreeSewing.org, dann konnten wir dir diese E-Mail zustellen, was eine gute
+Nachricht ist.
+
+Was du vielleicht nicht weißt, ist, dass dies nicht gerade trivial ist und schon seit Jahren nicht mehr
+ist. Aber in letzter Zeit sind die Dinge noch komplexer geworden. Gmail
+(Google) und Yahoo zum Beispiel haben im ersten
+Quartal von
+2024 neue Beschränkungen eingeführt, die
+zusätzliche Arbeit auf unserer Seite erfordern, um die Chancen zu maximieren, dass diese E-Mail
+tatsächlich in deinem Posteingang landet.
+
+Außerdem werden sogenannte _Massen-E-Mail-Versender_ den strengsten
+Kontrollen unterzogen. Wenn du 5000 Nachrichten pro Tag versendest, giltst du als Massenversender und
+wird besonders genau überprüft. Da dieser Newsletter rund 14.000
+Abonnenten hat, müssen wir uns an die höchstmöglichen Standards halten.
+
+Natürlich mag niemand Spam und ich spreche mich nicht gegen diese Regeln aus.
+Es ist nur so, dass der Zeit- und Arbeitsaufwand, der erforderlich ist, um etwas so
+scheinbar Triviales wie das Versenden einer E-Mail in großem Umfang zu realisieren, immer größer wird, da
+das Internet sich zu einem de facto Pay-to-Play-Modell entwickelt.
+
+Im Moment bemühe ich mich noch darum, und ich hoffe, sie haben ausgereicht
+, um dies in deinen Posteingang zu bekommen. Aber es ist etwas, das wir vielleicht zu einem späteren Zeitpunkt
+wieder aufgreifen müssen, wenn es unsere begrenzte Zeit und unsere Ressourcen zunehmend belastet.
+
+
+
+---
+
+
+
+## 🕸️ Aufbau des Vertrauensnetzes von FreeSewing nach dem XZ-Backdoor-Versuch (5-Minuten von joost)
+
+Je nachdem, woher du deine Nachrichten beziehst, hast du vielleicht schon von
+[dem Backdoor-Versuch des Komprimierungsprogramms xz
+] (https\://arstechnica.com/security/2024/03/backdoor-found-in-widely-used-linux-utility-breaks-encrypted-ssh-connections/) gehört oder gelesen.
+
+Kurz gesagt, ein böswilliger Akteur versuchte, eine Hintertür in dieses
+Dienstprogramm einzuschleusen, was letztendlich ein Versuch war, einen Gated RCE-Exploit in
+SSHd zu schmuggeln.
+
+Oder, in [ELI5](https://en.wiktionary.org/wiki/ELI5) Worten: Jemand hat
+Code zu einer kleinen Bibliothek beigetragen, die schändliche Absichten hatte. Dies geschah auf hinterhältige Art und Weise
+und das eigentliche Ziel war nicht die Bibliothek selbst, sondern ein anderes Software
+Projekt, das diese Bibliothek verwendet: Der Secure Shell Deamon. Ein _Daemon_ ist nur ein
+cooleres Wort für einen _Dienst_ auf einem Computer, denn warum sollte man Dinge nicht cooler machen.
+Dieser spezielle Daemon oder Dienst, der _secure shell_ Daemon, ist für die
+Handhabung von Secure Shell (SSH) Verbindungen verantwortlich. Es ist der Goldstandard für die Fernverwaltung von Linux- (und Unix-) Systemen
+.
+
+Der Code schmuggelte eine RCE-Backdoor mit Gates ein. RCE steht für _remote code
+execution_, was bedeutet, dass du aus der Ferne _etwas_ tun kannst, ohne dich zu authentifizieren
+oder so. Oder anders ausgedrückt: Er ermöglicht es,
+ein entferntes Computersystem zu kontrollieren, auf das man normalerweise keinen Zugriff haben sollte.
+Die Tatsache, dass er _gated_ ist, bedeutet, dass der Autor von
+Maßnahmen ergriffen hat, um sicherzustellen, dass nur er den bösartigen
+Code verwenden kann. Wie eine Hintertür mit einem Schlüssel.
+
+Es ist kaum zu überschätzen, wie schwerwiegend dieser Versuch ist, praktisch jedes Linux-System auf dem Planeten
+zurückzudrängen. Es ist nicht nur das weltweit am weitesten verbreitete
+Betriebssystem, auch bei den Server-Betriebssystemen ist seine Dominanz überwältigend.
+Oder wie ich oft sage: _Alles, was wichtig ist, läuft auf Linux_.
+
+Dies ist eine fortlaufende Geschichte, und ich hoffe, dass daraus eine Netflix
+Miniserie mit David Cross in der Rolle des [Andres
+Freund] (https\://github.com/anarazel) wird, aber ich schweife ab. Dies ist der FreeSewing
+Newsletter, also wollte ich etwas aus dieser Geschichte herausgreifen, von dem ich denke, dass
+für FreeSewing, oder wirklich für jedes Open-Source-Projekt da draußen, relevant ist.
+
+### Maintainer Burnout und der lange Weg, Vertrauen zu gewinnen
+
+Eines der faszinierenden Elemente dieser Geschichte ist, _wer_ die Änderungen beigesteuert hat,
+und warum sie akzeptiert wurden, ohne dass die böswilligen
+Absichten des Beitrags aufgedeckt wurden.
+
+Weil der Benutzer, der sie gemacht hat, seit **years** zum Projekt
+beigetragen hat und aufgrund dieser Arbeit einen Status erreicht hat, bei dem es eine Menge
+implizites Vertrauen aufgrund seiner Arbeit gab, obwohl er so gut wie nichts über
+weiß, wer oder was sich hinter dem Benutzernamen `JiaT75` (in diesem Fall) verbirgt. Solch ein _langer Betrug_ ist
+eine erhebliche Investition von Zeit und Mühe, daher ist die derzeitige Annahme
+, dass es sich um einen nationalstaatlichen Akteur handelte (man denke an die NSA oder das Äquivalent in einem anderen Land
+). Es ist auch wichtig zu erwähnen, dass der xy-Maintainer
+mit den vielen Aufgaben, die mit der Wartung der Software
+verbunden sind, nicht zurechtkam und aktiv nach Hilfe suchte, um ein Burnout zu vermeiden. Dieses
+Szenario ist bei Open-Source-Projekten erschreckend häufig anzutreffen und schafft eine
+Situation, in der böswillige Akteure nur allzu leicht einen Vorteil aus erschöpften
+Maintainern ziehen können, die verzweifelt versuchen, einen Teil der Arbeit loszuwerden.
+
+### Ein Netz des Vertrauens aufbauen
+
+Das Problem, wem man vertrauen kann, ist natürlich nicht neu. Eine Möglichkeit, dem entgegenzuwirken
+, ist der Aufbau eines _Vertrauensnetzes_. So wird es in größeren
+Open-Source-Softwareprojekten gemacht, an denen viele Freiwillige beteiligt sind, wie z.B.
+
+In der Praxis beruht ein solches Vertrauensnetz auf Beziehungen zwischen
+Menschen, die die wahre Identität des anderen kennen und überprüft haben. Zum Beispiel
+gibt es eine Reihe von Leuten in der FreeSewing-Community, die ich im echten
+Leben getroffen habe. Wir sind uns nicht nur von Angesicht zu Angesicht begegnet, sondern haben Zeit miteinander verbracht, wir wissen
+wo wir wohnen, wir kennen die Partner oder die Familie des anderen oder haben eine andere
+greifbare Möglichkeit, die ein hohes Maß an Sicherheit bietet, dass diese Person wirklich
+ist, wer sie zu sein behauptet.
+
+Diese Menschen wiederum können ähnliche Verbindungen zu anderen Menschen haben, die sie kennen,
+kennengelernt haben und denen sie vertrauen, und zwar auf einer Ebene, die weit über die Online-Welt hinausgeht. Diese
+schafft ein Netz des Vertrauens, in dem du deinen Freunden vertrauen kannst, und die Freunde von
+deinen Freunden und so weiter.
+
+In Anbetracht der aktuellen Ereignisse und in Anerkennung der rasanten Beschleunigung von
+was mit generativer künstlicher Intelligenz möglich ist, wird FreeSewing
+von nun an alle Schreibzugriffe oder erhöhten Privilegien auf Mitglieder der Community
+beschränken, die Teil des Vertrauensnetzes von FreeSewing sind.
+
+Natürlich werden wir auch weiterhin Beiträge von
+annehmen - oder besser gesagt, überprüfen -. Aber Berechtigungen, die das Potenzial haben, Schaden anzurichten, werden auf
+auf Personen beschränkt, zu denen Vertrauen aufgebaut wurde AFK (away from
+keyboard).
+
+Um den Aufbau eines solchen Vertrauensnetzes zu erleichtern, werden wir damit beginnen,
+diese Verbindungen zwischen Menschen zu dokumentieren. So können Menschen, die
+mehr Verantwortung innerhalb von FreeSewing übernehmen möchten, das Vertrauensnetz einsehen und
+sehen, wer in ihrer Nähe wohnt, damit sie sich über
+in unser Vertrauensnetz einklinken können.
+
+Mir ist klar, dass es extrem unwahrscheinlich ist, dass FreeSewing das Ziel eines Hintertürchenversuchs
+eines nationalen Akteurs sein wird, aber es ist trotzdem eine gute Idee, die besten Praktiken zu übernehmen und
+transparent zu machen, wie wir vorgehen.
+
+Ich werde also in den nächsten Wochen damit beginnen, dieses Netz des Vertrauens aufzubauen und zu dokumentieren
+und alle Zugriffskontrollen und Berechtigungen zu überprüfen, um sicherzustellen, dass wir
+alles tun, was wir können, um zu verhindern, dass selbst die engagiertesten Akteure
+den Brunnen vergiften.
+
+
+
+---
+
+
+
+## 🤔 Wie sich die Herausforderungen von FreeSewing im Laufe der Zeit verändert haben
+
+Wusstest du, dass FreeSewing v1 vor 7 Jahren und 7 Tagen
+ veröffentlicht wurde? Seitdem haben wir
+viele große und kleine Änderungen vorgenommen, und unsere Kernbibliothek und unser Plugin-System
+sind zu einer zuverlässigen - und sicherlich meinungsstarken - Möglichkeit gereift, parametrische
+Nähmuster zu entwerfen.
+
+Die Herausforderungen, die aus technischer Sicht am interessantesten sind, wurden
+mehr oder weniger gelöst. Was übrig bleibt, ist die Benutzeroberfläche, oder
+das Benutzererlebnis (UX), wie wir es gerne nennen.
+
+FreeSewing kann eine Menge, aber wie kann man all diese Funktionen für die Nutzer von
+verfügbar machen, ohne sie zu überfordern? Ist das überhaupt auf dem Handy möglich, das heute die
+dominierende Art ist, online zu gehen? Wie schaffst du es, dass es ein intuitives Erlebnis wird,
+oder dass jemand, der nach einer Google-Suche nach _freien Nähmustern_
+auf FreeSewing.org landet, in den wenigen
+Sekunden versteht, was FreeSewing ist und tut, bevor er zum nächsten
+Link in seinen Suchergebnissen weitergeht?
+
+Um es klar zu sagen: Ich kenne die Antwort auf diese Fragen nicht. Aber es ist
+zunehmend, womit wir unsere Zeit verbringen. Der Prozentsatz der Menschen da draußen, die unsere Software
+direkt nutzen, ist unbedeutend im Vergleich zu der Anzahl der Menschen, die
+(nur) über unsere Website konsumieren. Für die meisten Besucher ist FreeSewing
+**is** eine Website und wenn es etwas anderes ist, ist das für sie wahrscheinlich nicht klar,
+oder sogar relevant.
+
+Natürlich gibt es Raum für Verbesserungen, aber oft gibt es keinen eindeutigen Weg
+nach vorne. Vielleicht - oder sollte ich sagen fast sicher - ist dies ein Bereich, in dem ich
+nicht das Talent oder die Fähigkeit habe, eine große, übergreifende
+Strategie zu entwickeln. Aber ich ertappe mich dabei, wie ich viele meiner eigenen Ideen oder Impulse
+in diesem Bereich in Frage stelle.
+
+Deshalb habe ich mich gefragt, ob wir ein kleines Experiment machen können. Ein Experiment, bei dem ich
+dir - meinem lieben Leser - eine einfache Frage stelle. Bist du bereit dafür? Hier
+ist die Frage:
+
+> **Was ist FreeSewing?**
+
+Ich würde gerne deine Antwort hören. Du kannst einfach auf "Antworten" klicken, um mir Bescheid zu geben.
+
+_PS: Ich habe diese Frage am Ende vergraben, weil ich denke, dass ich deine Gedanken hören möchte, wenn du dir alles durchliest, was auf
+steht.
diff --git a/markdown/org/newsletter/2024q2/en.md b/markdown/org/newsletter/2024q2/en.md
new file mode 100644
index 00000000000..892a9933301
--- /dev/null
+++ b/markdown/org/newsletter/2024q2/en.md
@@ -0,0 +1,287 @@
+---
+date: "2024-04-01"
+edition: "2024q2"
+intro: "Welcome to the 2024 Spring edition of the FreeSewing newsletter."
+title: "2024 Spring edition"
+---
+
+Welcome to the 2024 Spring edition of the FreeSewing newsletter.
+
+Here's what we've got for you today, no joke:
+
+- 👕 FreeSewing 3.2 brings Tristan, Lumina, Lumira, and more (3-minute read by joost)
+- 📨 Email just got harder, again (1-minute read by joost)
+- 🕸️ Building FreeSewing's web of trust in the wake of the XZ backdoor attempt (5-minute by joost)
+- 🤔 How FreeSewing's challenges have shifted over time (2-minute read by joost)
+
+
+Shall we get started?
+
+
+
+
+
+## 👕 FreeSewing 3.2 brings Tristan, Lumina, Lumira, and more
+
+We released FreeSewing v3.2 earlier during Q1 2024 and it includes 3 new
+designs, as well as a range of bug fixes and improvements.
+
+Let's have a look at the highlights:
+
+### The Tristan Top
+
+First up, there is [the Tristan Top](https://freesewing.org/designs/tristan). Tristan is a top with princess seams and (optional) lacing at front or/and back. It’s origin story is the need for a costume for a Renaissance festival, so that is probably a good indicator of what to expect.
+
+Tristan was design by Natalia who also [wrote a blog post about the new Tristan design](https://freesewing.org/blog/our-newest-design-is-the-tristan-top), so that's a great place to get all the details about this new design.
+
+### The Lumina and Lumira Leggings
+
+I’ll give you a second to scan that title again, but yes there are two different leggings patterns with similar names: [the Lumira Leggings](https://freesewing.org/designs/lumira) and the [Lumina Leggings](https://freesewing.org/designs/lumina).
+
+Both were born out of Wouter’s desire for good cycling gear, and I suggest you check out the designer notes for both [Lumina](https://freesewing.org/designs/lumina#notes) and [Lumira](https://freesewing.org/designs/lumira#notes) to fully appreciate the difference between these designs, why they differ, and what would work best for you.
+
+### Bug fixes and improvements
+
+Regular readers of the newsletter will know that we continiously roll out
+improvements on FreeSewing.org and that those are not tied to a new release,
+but it's a good opportunity to list them so here are some highlights of the bug
+fixes and improvements that went into the 3.2 release:
+
+- Sandy has [a new panels
+ option](https://freesewing.org/docs/designs/sandy/options/panels) that was
+ added by [Paula](https://github.com/freesewing/freesewing/pull/5861). You
+ could aways create your circle skirt out of a number of a similar patterns by
+ doing the match yourself, but now the pattern will take care of that for you.
+- What started out as [a bug report for the biceps ease on
+ Jaeger](https://github.com/freesewing/freesewing/issues/5999) ended with a
+ change to the way the armscye is calculated on Brian, in particular the depth
+ of the armhole. Given that Brian is our most foundational block, this will
+ have ripple effects on many other designs, you can expect that out-of-the-box
+ the armscye will reach a bit lower.
+- In [Carlton](https://freesewing.org/designs/carlton) — and thus in
+ [Carlita](https://freesewing.org/designs/carlita) — we have fixed and issue
+ where the seam allowance on the undercollar was incorrectly drawn.
+- In [Charlie](https://freesewing.org/designs/charlie), the back pocket welt
+ (4) and front pocket facing (8) incorrectly indicated to cut 2 instead of 4
+ in the cutlist. This too is resolved.
+- In [Hugo](https://freesewing.org/designs/hugo), we fixed a bug that caused
+ the design to error when the complete setting was off, and we fixed an issue
+ where the front pocket opening would get increasingly narrow as the hip
+ circumference increased.
+- We’ve added a new
+ [Path.combine()](https://freesewing.dev/reference/api/path/combine) method to
+ [our core API](https://freesewing.dev/reference/api). Its origins lie in a
+ discussion in [issue
+ #5976](https://github.com/freesewing/freesewing/issues/5976) which was
+ originally filed as a bug report about how Path.join() connects gaps in the
+ joined paths — caused by either `move` operations, or a difference between
+ the end and start point of joined paths — to be filled in with a line
+ segment. That behaviour is expected/intended, but we’ve added
+ `Path.combine()` to faciliate the other behavior: Combining different paths
+ into a single Path object without alterning any of its drawing operations.
+- The [title macro](https://freesewing.dev/reference/macros/title) now can be
+ configured with a `notes` and `classes.notes` setting in its config, allowing
+ designers to add notes to (the title of) a pattern part.
+- Our [i18n plugin](https://freesewing.dev/reference/plugins/i18n) now supports
+ now supports translation of nested arrays of strings, which gives designers
+ more flexibility to concatenate translated parts of strings.
+
+The [FreeSewing 3.2 announcement blog post](https://freesewing.org/blog/v3-2-0) has all the details.
+
+
+
+
+---
+
+
+
+
+## 📨 Email just got harder, again
+
+If you are reading this in your inbox, and not an archived copy on
+FreeSewing.org, then we were able to deliver this email to you, which is good
+news.
+
+What you may not realize is that doing so is not exactly trivial, and hasn't
+been for years. But recently, things have gotten even more complex. Gmail
+(Google) and Yahoo for example have [implemented new restrictions in the first
+quarter of
+2024](https://www.xomedia.io/blog/a-deep-dive-into-email-deliverability/) which
+requires additional work on our end to maximize the chances of this email
+actually landing in your inbox.
+
+Furthermore, so-called _bulk email senders_ are subject to the most stringent
+checks. If you send 5000 messages a day, you are considered a bulk sender and
+will be subject to extra scrutiny. As this newsletter has about 14k
+subscribers, we are being held to the highest possible standards.
+
+Obviously, nobody likes spam, and I am not advocating against these rules.
+It's just that the amount of time and effort required to make something as
+seeminly trivial as sending out an email work at scale is ever-increasing as
+the internet trends towards a de-facto pay-to-play model.
+
+For now, I am still making those efforts, and hopefully they proved sufficient
+to get this to your inbox. But it's something we may need to revisit at a later
+time if it becomes an increasing strain on our limited time and resources.
+
+
+
+
+---
+
+
+
+## 🕸️ Building FreeSewing's web of trust in the wake of the XZ backdoor attempt (5-minute by joost)
+
+Depending on where you get your news from, you might have heard or read about
+[the backdoor attempt of the xz compression
+utility](https://arstechnica.com/security/2024/03/backdoor-found-in-widely-used-linux-utility-breaks-encrypted-ssh-connections/).
+
+In a nutshell, a malicious actor attempted to introduce a backdoor in this
+utility, which ultimately was an attempt to smuggle a gated RCE exploit into
+SSHd.
+
+Or, in [ELI5](https://en.wiktionary.org/wiki/ELI5) terms: Somebody contributed
+code to a small library that had nefarious intent. It was done in a sneaky way
+and the ultimate target was not the library itself, but rather another software
+project that uses this library: The Secure Shell Deamon. A _daemon_ is just a
+cooler word for a _service_ on a computer, because why not make things cooler.
+This particular daemon or service, the _secure shell_ daemon is responsible for
+handling secure shell (SSH) connections. It's the gold standard for remote
+management of Linux (and unix) systems.
+
+The code smuggled in a gated RCE backdoor. RCE stands for _remote code
+execution_, meaning it allows you to _do stuff_ remotely without needing to
+authenticate or anything. Or to put it differently, it allows one to control
+a remote computer system they normally should not have access to.
+The fact that it is _gated_ means that the author of
+the malicious code took steps to ensure that only they could use the malicious
+code. Like a backdoor with a key.
+
+It's hard to overstate the gravity of this attempt at backdooring essentially
+every Linux system on the planet. It's not only the world's most widely used
+operating system, its dominance of server operating systems is overwhelming.
+Or as I often say: _Anything that matters runs on Linux_.
+
+This is an ongoing story and I for one am hoping it will be made into a Netflix
+mini-series starring David Cross in the role of [Andres
+Freund](https://github.com/anarazel), but I digress. This is the FreeSewing
+newsletter, so I wanted to lift something out of this story that I think
+is relevant to FreeSewing, or really to any open source project out there.
+
+### Maintainer burnout and the long con of gaining trust
+
+One of the fascinating elements of this story is _who_ contributed the changes,
+and why they were accepted without sufficient scrutiny to reveal the malicious
+intent of the contribution.
+
+Because the user who made them had been contributing for __years__ to the project
+and in light of this work had risen in status to a level where there was a lot
+of implicit trust based on their work, despite knowing next to nothing about
+who or what goes behind username `JiaT75` (in this case). Such a _long con_ is
+a significant investment of time and effort, so the currently held assumption
+is that this was a nation-state actor (think NSA or some other country's
+equivalent). It's also important to note that the xy maintainer was having a
+hard time dealing with the long tail of responsibilities of maintaining
+software and was actively looking for help to stave off burnout. It's a
+scenario that is shockingly common across open source projects and creates a
+situation where malicious actors can all too easily take advantage of exhausted
+maintainers desperate to offload some of the work.
+
+### Establishing a web of trust
+
+This problem of *who can you trust* is of course not new. One way to counter it
+is by establishing a _web of trust_. This is how things are done in larger
+open source software projects involving many volunteers, such as [the Debian
+project](https://www.debian.org/).
+
+In practical terms, such a web of trust is built upon relationships between
+people who know and have verified each other's true identity. For example,
+there's a number of people in the FreeSewing community that I have met in real
+life. We've not merely met face to face, but have spent time together, we know
+where we live, we know each other's partners or family, or have some other
+tangible way that provides a high level of assurance that this person really is
+who they claim to be.
+
+Those people, in turn, can have similar connections with others who they know,
+have met, and trust to a level that goes well beyond the online world. This
+creates a web of trust where you can trust your friends, and the friends of
+your friends and so on.
+
+In light of current events, and in acknowledgment of the rapid accelaration of
+what is possible with generatative artificial intelligence, FreeSewing will
+henceforth restrict all write access or elevated privileges to community
+members who are part of FreeSewing's web of trust.
+
+We will of course continue to accept -- or rather review -- contributions from
+everyone. But permissions that unlock the potential to do harm will be
+restricted to people for whom trust has been established AFK (away from
+keyboard).
+
+In order to facilitate building such a web of trust, we will start documenting
+these connections between people. This will allow people who are looking to
+take on more responsibilities within FreeSewing to look at its web of trust and
+see who lives close to them so they can hook in to our web of trust through
+that person.
+
+I realize that FreeSewing is extremely unlikely to be the target of a backdoor
+attempt by a nation state actor, but adopting best practices and being
+transparent about how we do things is a good idea regardless.
+
+So, I will start building and documenting this web of trust over the next couple
+of weeks, and review all access control and permissions to make sure we are
+doing everything we can to prevent even the most dedicated actors from poisoning
+the well.
+
+
+
+---
+
+
+
+## 🤔 How FreeSewing's challenges have shifted over time
+
+Did you know that [FreeSewing v1 was released 7 years and 7 days
+ago](https://freesewing.org/blog/announcing-freesewing)? Since that time we've
+made many changes big and small, and our core library and plugin system have
+matured into a reliable -- and certainly opinionated -- way to design parametric
+sewing patterns.
+
+The challenges that are most interesting from a technical point of view have
+been more or less solved. What's left is the user-facing side of things, or
+the user experience (UX) as we like to call it.
+
+FreeSewing can do a lot, so how make all of that functionality available to the
+users without overwhelming them? Is that even possible on mobile, which is the
+dominant way in which people go online now. How do you create it an intuitive experience,
+or guide someone who arrives on FreeSewing.org after a _free sewing patterns_
+Google search towards an understanding of what FreeSewing is and does in the handful of
+seconds that people are likely to give it a chance before moving on to the next
+link in their search results.
+
+To be clear: I do not know the answer to these questions. But it is
+increasingly what we spend our time on. The percentage of people out there who
+use our software directly is insignificant compared to the amount of people who
+(only) consume our software through our website. For most visitors, FreeSewing
+__is__ a website and if it is anything else, that is probably not clear to them,
+or even relevant.
+
+Obviously there is room for improvement, but often there is no one obvious path
+forward. Perhaps -- or should I say almost certainly -- this is an area where I
+lack the talent or skill to come up with some sort of grand overarching
+strategy. But I find myself second-guessing a lot of my own ideas or impulses
+in this area.
+
+So, I was wondering if we could do a little experiment. An experiment where I
+ask you -- my dear reader -- a simple question. Are you ready for it? Here
+is the question:
+
+
+> **What is FreeSewing?**
+
+I'd love to hear your answer. You can simply hit reply to let me know.
+
+_PS: I burried this question at the end because I feel if you read through all of
+what came before, I probably want to hear your thoughts._
+
+
diff --git a/markdown/org/newsletter/2024q2/es.md b/markdown/org/newsletter/2024q2/es.md
new file mode 100644
index 00000000000..ab0f9539191
--- /dev/null
+++ b/markdown/org/newsletter/2024q2/es.md
@@ -0,0 +1,279 @@
+---
+date: 2024-04-01
+edition: 2024q2
+intro: Bienvenido a la edición de primavera 2024 del boletín FreeSewing.
+title: 2024 Edición de primavera
+---
+
+Bienvenido a la edición de primavera 2024 del boletín FreeSewing.
+
+Esto es lo que tenemos hoy para ti, no es broma:
+
+- 👕 FreeSewing 3.2 trae Tristan, Lumina, Lumira y más (lectura de 3 minutos por joost)
+- 📨 El correo electrónico se ha vuelto más difícil, otra vez (lectura de 1 minuto por joost)
+- 🕸️ Construir la red de confianza de FreeSewing tras el intento de backdoor del XZ (5 minutos por joost)
+- 🤔 Cómo han cambiado los retos de FreeSewing con el tiempo (lectura de 2 minutos por joost)
+
+¿Empezamos?
+
+
+
+
+
+## 👕 FreeSewing 3.2 trae Tristan, Lumina, Lumira y más
+
+Lanzamos FreeSewing v3.2 a principios del primer trimestre de 2024 e incluye 3 nuevos diseños de
+, así como una serie de correcciones de errores y mejoras.
+
+Echemos un vistazo a lo más destacado:
+
+### The Tristan Top
+
+En primer lugar, está [el Tristan Top](https://freesewing.org/designs/tristan). Tristán es un top con costuras princesa y lazada (opcional) delante y/o detrás. Su historia de origen es la necesidad de un disfraz para una fiesta renacentista, así que probablemente sea un buen indicador de lo que cabe esperar.
+
+Tristán fue diseñado por Natalia, que también [escribió una entrada en su blog sobre el nuevo diseño de Tristán](https://freesewing.org/blog/our-newest-design-is-the-tristan-top), así que ese es un buen lugar para obtener todos los detalles sobre este nuevo diseño.
+
+### The Lumina and Lumira Leggings
+
+Te daré un segundo para que vuelvas a escanear ese título, pero sí, hay dos patrones de leggings diferentes con nombres similares: [los Leggings Lumira](https://freesewing.org/designs/lumira) y los [Leggings Lumina](https://freesewing.org/designs/lumina).
+
+Ambos nacieron del deseo de Wouter de tener una buena equipación ciclista, y te sugiero que consultes las notas del diseñador tanto de [Lumina](https://freesewing.org/designs/lumina#notes) como de [Lumira](https://freesewing.org/designs/lumira#notes) para apreciar plenamente la diferencia entre estos diseños, por qué difieren y qué te iría mejor a ti.
+
+### Bug fixes and improvements
+
+Los lectores habituales del boletín sabrán que en FreeSewing.org introducimos continuamente mejoras en
+y que éstas no están vinculadas a una nueva versión,
+pero es una buena oportunidad para enumerarlas, así que aquí tienes algunos puntos destacados de las correcciones de errores
+y mejoras que se han incluido en la versión 3.2:
+
+- Sandy tiene una nueva opción de paneles
+ que fue
+ añadida por [Paula](https://github.com/freesewing/freesewing/pull/5861). Tú
+ podrías crear tu falda circular a partir de una serie de patrones similares haciendo tú misma la combinación, pero ahora el patrón se encargará de ello por ti.
+- Lo que empezó como un informe de error sobre la facilidad de los bíceps en
+ Jaeger acabó con un cambio en
+ sobre la forma de calcular el contorno de los brazos en Brian, en concreto sobre la profundidad
+ de la sisa. Dado que Brian es nuestro bloque más fundacional, esto
+ tendrá efectos dominó en muchos otros diseños, puedes esperar que, fuera de la caja
+ , el codo de los brazos llegue un poco más abajo.
+- En [Carlton](https://freesewing.org/designs/carlton) - y, por tanto, en
+ [Carlita](https://freesewing.org/designs/carlita) - hemos arreglado y emitido
+ en el que el margen de costura del cuello interior estaba mal trazado.
+- En [Charlie](https://freesewing.org/designs/charlie), el ribete del bolsillo trasero
+ (4) y el ribete del bolsillo delantero (8) indicaban incorrectamente cortar 2 en lugar de 4
+ en la lista de cortes. This too is resolved.
+- En [Hugo](https://freesewing.org/designs/hugo), hemos corregido un error que hacía que
+ el diseño diera error cuando el ajuste completo estaba desactivado, y hemos solucionado un problema
+ por el que la abertura del bolsillo delantero se hacía cada vez más estrecha a medida que aumentaba la circunferencia de la cadera
+ .
+- Hemos añadido un nuevo método
+ [Path.combine()](https://freesewing.dev/reference/api/path/combine) a
+ [nuestra API central](https://freesewing.dev/reference/api). Sus orígenes se encuentran en un debate de
+ en issue
+ \#5976 que fue
+ archivado originalmente como un informe de error sobre cómo Path.join() conecta los huecos en las rutas unidas
+ -causados por operaciones de `movimiento`, o por una diferencia entre
+ el punto final y el punto inicial de las rutas unidas- para rellenarlos con un segmento de línea
+ . Ese comportamiento es el esperado/intencionado, pero hemos añadido
+ `Path.combine()` para facilitar el otro comportamiento: Combinar distintas rutas
+ en un único objeto Ruta sin alterar ninguna de sus operaciones de dibujo.
+- La macro [title](https://freesewing.dev/reference/macros/title) ahora puede configurarse
+ con un ajuste `notes` y `classes.notes` en su configuración, lo que permite a los diseñadores
+ añadir notas a (el título de) una parte de patrón.
+- Nuestro [plugin i18n](https://freesewing.dev/reference/plugins/i18n) ahora admite
+ ahora admite la traducción de matrices anidadas de cadenas, lo que da a los diseñadores
+ más flexibilidad para concatenar partes traducidas de cadenas.
+
+La [entrada del blog del anuncio de FreeSewing 3.2](https://freesewing.org/blog/v3-2-0) tiene todos los detalles.
+
+
+
+---
+
+
+
+## 📨 El correo electrónico vuelve a ser más difícil
+
+Si estás leyendo esto en tu bandeja de entrada, y no una copia archivada en
+FreeSewing.org, entonces hemos podido enviarte este correo electrónico, lo cual es una buena noticia
+.
+
+Lo que quizá no sepas es que hacerlo no es precisamente trivial, y no lo ha sido
+durante años. Pero recientemente, las cosas se han vuelto aún más complejas. Gmail
+(Google) y Yahoo, por ejemplo, han implementado nuevas restricciones en el primer
+trimestre de
+2024 lo que
+requiere un trabajo adicional por nuestra parte para maximizar las posibilidades de que este correo
+llegue realmente a tu bandeja de entrada.
+
+Además, los denominados _remitentes de correo electrónico masivo_ están sujetos a los controles más estrictos de
+. Si envías 5000 mensajes al día, se te considera un remitente masivo y
+estará sujeto a un escrutinio adicional. Como este boletín tiene unos 14.000 suscriptores en
+, se nos exige el máximo nivel de calidad.
+
+Obviamente, a nadie le gusta el spam, y no estoy abogando en contra de estas normas.
+Lo que ocurre es que la cantidad de tiempo y esfuerzo necesarios para hacer que algo tan
+aparentemente trivial como enviar un correo electrónico funcione a escala es cada vez mayor, ya que
+internet tiende hacia un modelo de pago por jugar de facto.
+
+Por ahora, sigo haciendo esos esfuerzos, y espero que hayan sido suficientes
+para que esto llegue a tu bandeja de entrada. Pero es algo que tal vez tengamos que volver a examinar más adelante
+si se convierte en una carga cada vez mayor para nuestro tiempo y recursos limitados.
+
+
+
+---
+
+
+
+## 🕸️ Construir la red de confianza de FreeSewing tras el intento de backdoor del XZ (5 minutos por joost)
+
+Dependiendo de dónde obtengas tus noticias, puede que hayas oído o leído sobre
+el intento de backdoor de la utilidad de compresión xz
+.
+
+En pocas palabras, un actor malicioso intentó introducir una puerta trasera en esta utilidad
+, que en última instancia era un intento de introducir un exploit RCE en
+SSHd.
+
+O, en términos de [ELI5](https://en.wiktionary.org/wiki/ELI5): Alguien aportó código
+a una pequeña biblioteca que tenía intenciones nefastas. Se hizo de forma furtiva
+y el objetivo final no era la propia biblioteca, sino otro proyecto de software
+que utiliza esta biblioteca: El Deamon Secure Shell. Un _daemon_ no es más que una palabra más guay de
+para designar un _servicio_ en un ordenador, porque ¿por qué no hacer las cosas más guays?
+Este demonio o servicio concreto, el demonio _secure shell_, se encarga de
+gestionar las conexiones secure shell (SSH). Es el estándar de oro para la gestión remota
+de sistemas Linux (y unix).
+
+El código introdujo de contrabando una puerta trasera RCE cerrada. RCE significa _ejecución remota de código
+_, lo que significa que te permite _hacer cosas_ remotamente sin necesidad de autenticarte en
+ni nada. O dicho de otro modo, permite controlar
+un sistema informático remoto al que normalmente no debería tener acceso.
+El hecho de que esté _gated_ significa que el autor de
+el código malicioso tomó medidas para asegurarse de que sólo él podía utilizar el código malicioso de
+. Como una puerta trasera con llave.
+
+Es difícil exagerar la gravedad de este intento de backdooring esencialmente
+todos los sistemas Linux del planeta. No sólo es el sistema operativo
+más utilizado del mundo, sino que su dominio de los sistemas operativos de servidor es abrumador.
+O como suelo decir: _Todo lo que importa funciona en Linux_.
+
+Se trata de una historia en curso y, por mi parte, espero que se convierta en una miniserie de Netflix
+protagonizada por David Cross en el papel de Andres
+Freund, pero estoy divagando. Este es el boletín de FreeSewing
+, así que quería sacar algo de esta historia que creo que
+es relevante para FreeSewing, o realmente para cualquier proyecto de código abierto que exista.
+
+### El agotamiento del mantenedor y la larga estafa de ganarse la confianza
+
+Uno de los elementos fascinantes de esta historia es _quién_ aportó los cambios,
+y por qué se aceptaron sin un escrutinio suficiente para revelar la intención maliciosa
+de la aportación.
+
+Porque el usuario que las hizo había estado contribuyendo durante **years** al proyecto
+y a la luz de este trabajo había ascendido de estatus hasta un nivel en el que había mucha
+confianza implícita basada en su trabajo, a pesar de no saber casi nada sobre
+quién o qué hay detrás del nombre de usuario `JiaT75` (en este caso). Una estafa tan _larga_ es
+una inversión significativa de tiempo y esfuerzo, por lo que la suposición que se mantiene actualmente
+es que se trataba de un actor de un Estado-nación (piensa en la NSA o en el equivalente a
+de algún otro país). También es importante señalar que el mantenedor de xy tenía
+dificultades para hacer frente a la larga cola de responsabilidades que supone mantener el software
+y buscaba activamente ayuda para evitar el agotamiento. Se trata de un escenario
+que es sorprendentemente común en los proyectos de código abierto y crea una situación
+en la que los actores maliciosos pueden aprovecharse con demasiada facilidad de los agotados mantenedores de
+, desesperados por descargar parte del trabajo.
+
+### Establecer una red de confianza
+
+Este problema de _en quién puedes confiar_ no es, por supuesto, nuevo. Una forma de contrarrestarlo
+es estableciendo una _red de confianza_. Así es como se hacen las cosas en los grandes proyectos de software de código abierto
+en los que participan muchos voluntarios, como el proyecto Debian
+.
+
+En términos prácticos, esa red de confianza se construye sobre relaciones entre
+personas que conocen y han verificado la verdadera identidad de las demás. Por ejemplo,
+hay varias personas en la comunidad FreeSewing que he conocido en la vida real
+. No sólo nos hemos visto cara a cara, sino que hemos pasado tiempo juntos, sabemos
+dónde vivimos, conocemos a la pareja o a la familia del otro, o tenemos algún otro
+modo tangible que proporciona un alto nivel de seguridad de que esta persona es realmente
+quien dice ser.
+
+Esas personas, a su vez, pueden tener conexiones similares con otras a las que conocen,
+han conocido y en las que confían a un nivel que va mucho más allá del mundo online. Este
+crea una red de confianza en la que puedes confiar en tus amigos, y los amigos de
+en tus amigos, y así sucesivamente.
+
+A la luz de los acontecimientos actuales, y en reconocimiento de la rápida aceleración de
+lo que es posible con la inteligencia artificial generativa, FreeSewing
+restringirá a partir de ahora todo acceso de escritura o privilegios elevados a los miembros de la comunidad
+que formen parte de la red de confianza de FreeSewing.
+
+Por supuesto, seguiremos aceptando -o mejor dicho, revisando- las contribuciones de
+de todo el mundo. Pero los permisos que desbloquean la posibilidad de hacer daño estarán
+restringidos a las personas para las que se haya establecido la confianza AFK (lejos del teclado
+).
+
+Para facilitar la construcción de esa red de confianza, empezaremos a documentar
+esas conexiones entre personas. Esto permitirá a las personas que deseen
+asumir más responsabilidades dentro de FreeSewing mirar su red de confianza y
+ver quién vive cerca de ellos para que puedan engancharse a nuestra red de confianza a través de
+esa persona.
+
+Soy consciente de que es extremadamente improbable que FreeSewing sea el objetivo de un intento de
+por la puerta trasera por parte de un actor de un estado nación, pero adoptar las mejores prácticas y ser
+transparente sobre cómo hacemos las cosas es una buena idea a pesar de todo.
+
+Así pues, empezaré a construir y documentar esta red de confianza en las próximas dos
+semanas, y revisaré todos los controles de acceso y permisos para asegurarme de que estamos
+haciendo todo lo posible para evitar que incluso los actores más dedicados envenenen
+el pozo.
+
+
+
+---
+
+
+
+## 🤔 Cómo han cambiado los retos de FreeSewing con el tiempo
+
+¿Sabías que FreeSewing v1 se lanzó hace 7 años y 7 días
+? Desde entonces hemos
+hecho muchos cambios grandes y pequeños, y nuestra biblioteca central y el sistema de plugins han
+madurado hasta convertirse en una forma fiable -y ciertamente opinable- de diseñar patrones de costura paramétricos
+.
+
+Los retos más interesantes desde el punto de vista técnico se han resuelto más o menos en
+. Lo que queda es la parte de cara al usuario, o
+la experiencia del usuario (UX), como nos gusta llamarla.
+
+FreeSewing puede hacer muchas cosas, así que ¿cómo poner toda esa funcionalidad a disposición de los usuarios de
+sin abrumarlos? ¿Es eso posible incluso en el móvil, que es la
+forma dominante en que la gente se conecta ahora a Internet. ¿Cómo creas una experiencia intuitiva,
+o guías a alguien que llega a FreeSewing.org después de una búsqueda en Google de _patrones de costura gratuitos_
+hacia la comprensión de lo que es y hace FreeSewing en el puñado de
+segundos en que es probable que la gente le dé una oportunidad antes de pasar al siguiente enlace
+de sus resultados de búsqueda?
+
+Para que quede claro: no conozco la respuesta a estas preguntas. Pero es
+cada vez más a lo que dedicamos nuestro tiempo. El porcentaje de personas que
+utilizan nuestro software directamente es insignificante comparado con la cantidad de personas que
+(sólo) consumen nuestro software a través de nuestro sitio web. Para la mayoría de los visitantes, FreeSewing
+**is** un sitio web y si es otra cosa, probablemente no les quede claro,
+o ni siquiera sea relevante.
+
+Obviamente, hay margen de mejora, pero a menudo no hay un camino obvio
+hacia adelante. Tal vez -o debería decir casi seguro- éste sea un ámbito en el que
+carezca de talento o habilidad para idear algún tipo de gran estrategia global
+. Pero me encuentro cuestionando muchas de mis propias ideas o impulsos
+en este ámbito.
+
+Así que me preguntaba si podríamos hacer un pequeño experimento. Un experimento en el que
+te plantea -a mi querido lector- una pregunta sencilla. ¿Estás preparado? Aquí
+está la cuestión:
+
+> \*\*¿Qué es FreeSewing?
+
+Me encantaría escuchar tu respuesta. Puedes simplemente pulsar responder para hacérmelo saber.
+
+_PS: He enterrado esta pregunta al final porque creo que si has leído todo
+lo que había antes, probablemente quiera oír lo que piensas.
diff --git a/markdown/org/newsletter/2024q2/fr.md b/markdown/org/newsletter/2024q2/fr.md
new file mode 100644
index 00000000000..b16fbb0eca2
--- /dev/null
+++ b/markdown/org/newsletter/2024q2/fr.md
@@ -0,0 +1,264 @@
+---
+date: 04-01-2024
+edition: 2024q2
+intro: Bienvenue dans l'édition du printemps 2024 de la newsletter de FreeSewing.
+title: 2024 Édition de printemps
+---
+
+Bienvenue dans l'édition du printemps 2024 de la newsletter de FreeSewing.
+
+Sans blague, voici ce que nous te proposons pour aujourd'hui :
+
+- 👕 FreeSewing 3.2 apporte Tristan, Lumina, Lumira, et plus encore (lecture de 3 minutes par joost).
+- 📨 Le courrier électronique gagne en difficultés, encore une fois (lecture en 1 minute par joost)
+- 🕸️ Construire le réseau de confiance de FreeSewing suite à la tentative de backdoor du XZ (5 minutes par joost).
+- 🤔 Comment les défis de FreeSewing se sont déplacés au fil du temps (lecture de 2 minutes par joost).
+
+On peut commencer ?
+
+
+
+
+
+## 👕 FreeSewing 3.2 apporte Tristan, Lumina, Lumira, etc.
+
+Nous avons publié FreeSewing v3.2 plus tôt au cours du premier trimestre 2024 et il comprend 3 nouveaux modèles
+, ainsi qu'une série de corrections de bugs et d'améliorations.
+
+Jetons un coup d'œil aux faits marquants :
+
+### The Tristan Top
+
+Tout d'abord, il y a [le haut Tristan] (https://freesewing.org/designs/tristan). Tristan est un haut avec des coutures princesse et un laçage (facultatif) sur le devant et/ou dans le dos. Originalement il remplit de besoin pour un costume pour un festival de la Renaissance, c'est probablement un bon indicateur de ce que tu vas trouver.
+
+Tristan a été conçu par Natalia qui a également [écrit un article de blog sur le nouveau design de Tristan] (https://freesewing.org/blog/our-newest-design-is-the-tristan-top), c'est un bon endroit pour obtenir tous les détails sur ce nouveau design.
+
+### The Lumina and Lumira Leggings
+
+Je te laisse une seconde pour lire à nouveau ce titre, mais oui, il y a deux modèles de leggings différents avec des noms similaires : [le Lumira Leggings](https://freesewing.org/designs/lumira) et le [Lumina Leggings](https://freesewing.org/designs/lumina).
+
+Les deux sont nés du désir de Wouter d'avoir un bon équipement cycliste, et je te suggère de consulter les notes du concepteur pour [Lumina](https://freesewing.org/designs/lumina#notes) et [Lumira](https://freesewing.org/designs/lumira#notes) pour bien comprendre la différence entre ces designs, pourquoi ils diffèrent, et ce qui te conviendrait le mieux.
+
+### Bug fixes and improvements
+
+Les lecteurs réguliers de la newsletter savent que nous apportons continuellement des améliorations
+sur FreeSewing.org et que celles-ci ne sont pas liées à une nouvelle version,
+mais c'est une bonne occasion de les énumérer.
+
+- Sandy a un [nouveau panneau d'option](https://freesewing.org/docs/designs/sandy/options/panels) qui a été ajouté par [Paula](https://github.com/freesewing/freesewing/pull/5861). Tu pourrais toujours créer ta jupe circulaire à partir d'un certain nombre de motifs similaires en faisant les correspondances toi-même, mais maintenant le patron s'en chargera pour toi.
+- Ce qui a commencé comme un rapport de bogue pour l'aisance du biceps sur
+ Jaeger s'est terminé par un changement
+ de la façon dont l'encolure des bras est calculée sur Brian, en particulier la profondeur
+ de l'emmanchure. Étant donné que Brian est notre bloc le plus fondamental, cela aura
+ des effets conjugués sur de nombreuses autres design, tu peux t'attendre à ce que l'emmanchure soit un peu plus basse dans les versions de base des designs.
+- Dans [Carlton](https://freesewing.org/designs/carlton) - et donc dans
+ [Carlita](https://freesewing.org/designs/carlita) - nous avons corrigé le problème
+ où la marge de couture du sous col était mal dessinée.
+- Dans [Charlie](https://freesewing.org/designs/charlie), le passepoil de la poche arrière
+ (4) et le parement de la poche avant (8) indiquaient à tort de couper 2 au lieu de 4
+ dans la liste de coupe. This too is resolved.
+- Dans [Hugo](https://freesewing.org/designs/hugo), nous avons corrigé un bug qui provoquait
+ une erreur de conception lorsque le réglage complet était désactivé, et nous avons corrigé un problème
+ où l'ouverture de la poche avant devenait de plus en plus étroite à mesure que la circonférence de la hanche
+ augmentait.
+- Nous avons ajouté une nouvelle méthode
+ [Path.combine()](https://freesewing.dev/reference/api/path/combine) à
+ [notre API de base](https://freesewing.dev/reference/api). Ses origines se trouvent dans une discussion
+ dans issue
+ \#5976 qui a été
+ à l'origine déposée comme un rapport de bogue sur la façon dont Path.join() connecte les trous dans les
+ chemins joints - causées soit par les opérations `move`, soit par une différence entre
+ les points de fin et de début des chemins joints - pour être remplies avec un segment de ligne
+ . Ce comportement est attendu, mais nous avons ajouté
+ `Path.combine()` pour faciliter l'autre comportement : Combiner différents chemins
+ en un seul objet Path sans altérer les opérations de dessin.
+- La [macro titre](https://freesewing.dev/reference/macros/title) peut maintenant être configurée avec un paramètre `notes` et `classes.notes` dans sa configuration, ce qui permet aux concepteurs de
+ d'ajouter des notes (au titre) d'une partie de patron.
+- Notre [plugin i18n](https://freesewing.dev/reference/plugins/i18n)
+ prend désormais en charge la traduction des tableaux imbriqués de chaînes de caractères, ce qui donne aux concepteurs
+ plus de flexibilité pour concaténer les parties traduites des chaînes de caractères.
+
+Le [billet de blog sur l'annonce de FreeSewing 3.2] (https://freesewing.org/blog/v3-2-0) contient tous les détails.
+
+
+
+---
+
+
+
+## 📨 Le courrier électronique gagne en difficultés, encore une fois
+
+Si tu lis ceci dans ta boîte de réception, et non une copie archivée sur
+FreeSewing.org, c'est que nous avons pu t'envoyer cet e-mail, ce qui est une bonne nouvelle
+.
+
+Ce dont tu ne te rends peut-être pas compte, c'est que le faire n'est pas vraiment anodin, et ce, depuis des années. Mais récemment, les choses sont devenues encore plus complexes. Gmail
+(Google) et Yahoo par exemple ont mis en place de nouvelles restrictions au premier
+trimestre de
+2024 ce qui
+nécessite un travail supplémentaire de notre part pour maximiser les chances que cet email
+atterrisse effectivement dans ta boîte de réception.
+
+De plus, les expéditeurs d'e-mails dits "volumineux" sont soumis aux contrôles les plus stricts.
+. Si tu envoies 5000 messages par jour, tu es considéré comme un expéditeur en masse et
+fera l'objet d'un examen plus approfondi. Comme cette lettre d'information compte environ 14 000 abonnés, nous sommes tenus de respecter les normes les plus strictes possibles.
+
+Évidemment, personne n'aime le spam, et je ne plaide pas contre ces règles.
+C'est juste que le temps et les efforts nécessaires pour faire fonctionner à grande échelle quelque chose d'aussi
+apparemment trivial que l'envoi d'un e-mail ne cessent d'augmenter à mesure que
+l'Internet tend vers un modèle de facto de paiement à l'acte.
+
+Pour l'instant, je continue à faire ces efforts, et j'espère qu'ils se sont avérés suffisants
+pour que ceci arrive dans ta boîte de réception. Mais c'est quelque chose que nous devrons peut-être réexaminer plus tard
+si cela devient une contrainte de plus en plus forte sur notre temps et nos ressources limités.
+
+
+
+---
+
+
+
+## 🕸️ Construire le réseau de confiance de FreeSewing suite à la tentative de backdoor du XZ (5 minutes par joost).
+
+Selon l'endroit où tu lis les infos, tu as peut-être entendu ou lu quelque chose sur
+[la tentative de porte dérobée de l'utilitaire de compression xz
+] (https://arstechnica.com/security/2024/03/backdoor-found-in-widely-used-linux-utility-breaks-encrypted-ssh-connections/).
+
+En bref, un acteur malveillant a tenté d'introduire une porte dérobée dans cet utilitaire, ce qui, en fin de compte, était une tentative d'introduire clandestinement un exploit RCE dans SSHd.
+
+Ou, en termes [ELI5](https://en.wiktionary.org/wiki/ELI5) : Quelqu'un a contribué au code
+d'une petite bibliothèque avec des intentions néfastes. Cela a été fait de manière sournoise
+et la cible finale n'était pas la bibliothèque elle-même, mais plutôt un autre projet logiciel
+qui utilise cette bibliothèque : Le Secure Shell Deamon. Un _daemon_ est juste un mot
+plus cool pour désigner un _service_ sur un ordinateur, parce que pourquoi ne pas rendre les choses plus cool.
+Ce démon ou service particulier, le démon _secure shell_, est responsable de
+la gestion des connexions Secure Shell (SSH). C'est la référence en matière de gestion à distance
+des systèmes Linux (et unix).
+
+Le code introduit clandestinement une porte dérobée RCE. RCE signifie _remote code
+execution_, c'est-à-dire qu'il te permet de _faire des choses_ à distance sans avoir besoin de
+s'authentifier ou quoi que ce soit d'autre. Ou, pour le dire autrement, il permet de contrôler
+un système informatique distant auquel on ne devrait normalement pas avoir accès.
+Le fait qu'il soit _gated_ signifie que l'auteur de
+le code malveillant a pris des mesures pour s'assurer qu'il était le seul à pouvoir utiliser le code malveillant
+. Comme une porte dérobée avec une clé.
+
+Il est difficile d'exagérer la gravité de cette tentative de backdooring, essentiellement
+tous les systèmes Linux de la planète. Ce n'est pas seulement le système d'exploitation
+le plus utilisé au monde, sa domination sur les systèmes d'exploitation des serveurs est écrasante.
+Ou comme je le dis souvent : _Tout ce qui compte fonctionne sous Linux_.
+
+Cette histoire est en cours et j'espère pour ma part qu'elle fera l'objet d'une mini-série sur Netflix
+avec David Cross dans le rôle de [Andres
+Freund] (https://github.com/anarazel), mais je m'écarte du sujet. C'est la lettre d'information de FreeSewing
+, alors j'ai voulu extraire de cette histoire quelque chose que je pense
+être pertinent pour FreeSewing, ou vraiment pour n'importe quel projet open source.
+
+### L'épuisement du mainteneur et le long con de gagner la confiance
+
+L'un des éléments fascinants de cette histoire est de savoir _qui_ a apporté les modifications,
+et pourquoi elles ont été acceptées sans un examen suffisant pour révéler l'intention malveillante
+de la contribution.
+
+Parce que l'utilisateur qui les a créés a contribué pendant **des années** au projet
+et qu'à la lumière de ce travail, son statut s'est élevé à un niveau où il y avait beaucoup
+de confiance implicite basée sur son travail, malgré le fait qu'on ne sait pratiquement rien de
+qui ou ce qui se cache derrière le nom d'utilisateur `JiaT75` (dans ce cas). Une telle _long con_ est
+un investissement important en temps et en efforts, donc l'hypothèse actuellement retenue
+est qu'il s'agit d'un acteur national (pense à la NSA ou à l'équivalent
+d'un autre pays). Il est également important de noter que le responsable de xy avait
+du mal à faire face à la longue série de responsabilités liées à la maintenance du logiciel
+et qu'il cherchait activement de l'aide pour éviter le burnout. C'est un scénario
+qui est scandaleusement courant dans les projets open source et qui crée une situation
+où les acteurs malveillants peuvent trop facilement profiter des mainteneurs épuisés
+qui cherchent désespérément à se décharger d'une partie du travail.
+
+### Établir un réseau de confiance
+
+Ce problème de _qui peux-tu croire_ n'est bien sûr pas nouveau. Une façon de la contrer
+est d'établir un _réseau de confiance_. C'est ainsi que les choses se passent dans les grands projets
+de logiciels libres impliquant de nombreux bénévoles, tels que [le projet Debian
+] (https://www.debian.org/).
+
+Concrètement, un tel réseau de confiance repose sur des relations entre
+personnes qui connaissent et ont vérifié la véritable identité de chacune d'entre elles. Par exemple,
+, il y a un certain nombre de personnes dans la communauté FreeSewing que j'ai rencontrées dans la vraie vie
+. Nous ne nous sommes pas simplement rencontrés face à face, mais nous avons passé du temps ensemble, nous savons
+où nous vivons, nous connaissons le partenaire ou la famille de l'autre, ou nous avons d'autres
+moyens tangibles qui fournissent un niveau élevé d'assurance que cette personne est vraiment
+ce qu'elle prétend être.
+
+Ces personnes, à leur tour, peuvent avoir des liens similaires avec d'autres personnes qu'elles connaissent,
+qu'elles ont rencontrées, et en qui elles ont confiance à un niveau qui va bien au-delà du monde en ligne. Cela
+crée un réseau de confiance où tu peux faire confiance à tes amis, et les amis de tes amis et ainsi de suite.
+
+À la lumière des événements actuels, et en reconnaissance de l'accélération rapide de
+ce qui est possible avec l'intelligence artificielle générative, FreeSewing
+limitera dorénavant tout accès en écriture ou privilèges élevés aux membres de la communauté
+qui font partie du réseau de confiance de FreeSewing.
+
+Nous continuerons bien sûr à accepter - ou plutôt à examiner - les contributions de tout le monde. Mais les autorisations qui permettent de faire du mal seront
+limitées aux personnes pour lesquelles la confiance a été établie AFK (away from
+keyboard).
+
+Afin de faciliter la construction d'un tel réseau de confiance, nous allons commencer à documenter
+ces liens entre les personnes. Cela permettra aux personnes qui souhaitent
+prendre plus de responsabilités au sein de FreeSewing de consulter le réseau de confiance et
+de voir qui vit près d'eux afin qu'ils puissent se connecter à notre réseau de confiance par l'intermédiaire de
+cette personne.
+
+Je sais qu'il est très peu probable que FreeSewing soit la cible d'une tentative de porte dérobée
+par un acteur national, mais adopter les meilleures pratiques et être
+transparent sur la façon dont nous faisons les choses est une bonne idée.
+
+Je vais donc commencer à construire et à documenter ce réseau de confiance au cours des deux
+prochaines semaines, et passer en revue tous les contrôles d'accès et toutes les autorisations pour m'assurer que nous
+faisons tout ce que nous pouvons pour empêcher même les acteurs les plus dévoués d'empoisonner
+le puits.
+
+
+
+---
+
+
+
+## 🤔 Comment les défis de FreeSewing se sont déplacés au fil du temps.
+
+Sais-tu que [FreeSewing v1 a été publié il y a 7 ans et 7 jours
+] (https://freesewing.org/blog/announcing-freesewing) ? Depuis, nous avons
+apporté de nombreux changements, petits et grands, et notre bibliothèque de base et notre système de plugins ont
+mûri pour devenir un moyen fiable - et certainement influencé - de concevoir des patrons de couture paramétriques
+.
+
+Les défis les plus intéressants d'un point de vue technique ont plus ou moins été résolus. Ce qui reste, c'est le côté face à l'utilisateur, ou
+l'expérience utilisateur (UX) comme nous aimons l'appeler.
+
+FreeSewing peut faire beaucoup de choses, alors comment mettre toutes ces fonctionnalités à la disposition des utilisateurs de
+sans les submerger ? Est-ce que c'est même possible sur téléphone qui est le moyen principal
+par lequel les gens vont en ligne maintenant. Comment créer une expérience intuitive,
+ou guider quelqu'un qui arrive sur FreeSewing.org après une recherche _free sewing patterns_
+Google vers une compréhension de ce qu'est et fait FreeSewing dans les quelques
+secondes où les gens sont susceptibles de lui donner une chance avant de passer au lien
+suivant dans leurs résultats de recherche.
+
+Pour être clair : je ne connais pas la réponse à ces questions. Mais c'est
+de plus en plus ce à quoi nous consacrons notre temps. Le pourcentage de personnes qui
+utilisent directement notre logiciel est insignifiant par rapport au nombre de personnes qui
+consomment (uniquement) notre logiciel par l'intermédiaire de notre site Web. Pour la plupart des visiteurs, FreeSewing
+**is** est un site Web et s'il s'agit d'autre chose, ce n'est probablement pas clair pour eux,
+ou même pertinent.
+
+Il est évident qu'il y a matière à amélioration, mais souvent il n'y a pas de chemin évident
+. Peut-être -- ou devrais-je dire presque certainement -- c'est un domaine dans lequel
+je n'ai pas le talent ou les compétences nécessaires pour élaborer une sorte de grande stratégie globale. Mais je me retrouve à remettre en question beaucoup de mes propres idées ou impulsions
+dans ce domaine.
+
+Alors, je me demandais si nous pouvions faire une petite expérience. Une expérience au cours de laquelle je
+te pose - mon cher lecteur - une question simple. Es-tu prêt pour cela ? Voici la question :
+
+> **Qu'est-ce que FreeSewing ?**
+
+J'aimerais entendre ta réponse. Tu peux simplement cliquer sur répondre pour me le faire savoir.
+
+_PS : J'ai enterré cette question à la fin parce que j'ai l'impression que si tu as lu tout
+ce qui précède, j'ai probablement envie d'entendre tes pensées.
diff --git a/markdown/org/newsletter/2024q2/nl.md b/markdown/org/newsletter/2024q2/nl.md
new file mode 100644
index 00000000000..c2e0b9fdfcf
--- /dev/null
+++ b/markdown/org/newsletter/2024q2/nl.md
@@ -0,0 +1,279 @@
+---
+date: 2024-04-01
+edition: 2024q2
+intro: Welkom bij de 2024 lente editie van de FreeSewing nieuwsbrief.
+title: 2024 Voorjaarseditie
+---
+
+Welkom bij de 2024 lente editie van de FreeSewing nieuwsbrief.
+
+Dit is wat we vandaag voor je hebben, geen grapje:
+
+- FreeSewing 3.2 brengt Tristan, Lumina, Lumira en meer (3 minuten lezen door joost)
+- 📨 E-mail is weer moeilijker geworden (1 minuut gelezen door joost)
+- 🕸️ Bouwen aan het web van vertrouwen van FreeSewing in de nasleep van de XZ achterdeurpoging (5 minuten door joost)
+- 🤔 Hoe de uitdagingen van FreeSewing in de loop der tijd zijn veranderd (2 minuten lezen door joost)
+
+Zullen we beginnen?
+
+
+
+
+
+## FreeSewing 3.2 brengt Tristan, Lumina, Lumira en meer
+
+We hebben FreeSewing v3.2 eerder uitgebracht in Q1 2024 en het bevat 3 nieuwe
+ontwerpen, evenals een reeks bugfixes en verbeteringen.
+
+Laten we eens kijken naar de hoogtepunten:
+
+### The Tristan Top
+
+Als eerste is er [de Tristan Top](https://freesewing.org/designs/tristan). Tristan is een top met prinsessennaden en (optioneel) een vetersluiting voor en/of achter. Het verhaal over de oorsprong is de behoefte aan een kostuum voor een Renaissance festival, dus dat is waarschijnlijk een goede indicatie van wat je kunt verwachten.
+
+Tristan is ontworpen door Natalia die ook [een blogpost schreef over het nieuwe Tristan ontwerp](https://freesewing.org/blog/our-newest-design-is-the-tristan-top), dus dat is een geweldige plek om alle details over dit nieuwe ontwerp te krijgen.
+
+### The Lumina and Lumira Leggings
+
+Ik geef je even de tijd om die titel nog een keer te scannen, maar ja, er zijn twee verschillende leggingspatronen met vergelijkbare namen: [de Lumira Leggings](https://freesewing.org/designs/lumira) en de [Lumina Leggings](https://freesewing.org/designs/lumina).
+
+Beide zijn voortgekomen uit Wouter's verlangen naar goede fietskleding, en ik raad je aan om de ontwerpnotities voor zowel [Lumina](https://freesewing.org/designs/lumina#notes) als [Lumira](https://freesewing.org/designs/lumira#notes) te bekijken om het verschil tussen deze ontwerpen te begrijpen, waarom ze verschillen en wat het beste voor jou zou werken.
+
+### Bug fixes and improvements
+
+Regelmatige lezers van de nieuwsbrief zullen weten dat we voortdurend
+verbeteringen uitrollen op FreeSewing.org en dat die niet gebonden zijn aan een nieuwe release,
+maar het is een goede gelegenheid om ze op te sommen, dus hier zijn enkele hoogtepunten van de bug
+fixes en verbeteringen die in de 3.2 release zijn opgenomen:
+
+- Sandy heeft een nieuwe panelen
+ optie die
+ is toegevoegd door [Paula](https://github.com/freesewing/freesewing/pull/5861). Je zou
+ altijd je cirkelrok kunnen maken van een aantal vergelijkbare patronen door
+ zelf te matchen, maar nu zorgt het patroon daarvoor.
+- Wat begon als een bugrapport voor het bicepsgemak op
+ Jaeger eindigde met een
+ wijziging in de manier waarop de armscye wordt berekend op Brian, in het bijzonder de diepte
+ van het armsgat. Aangezien Brian ons meest fundamentele blok is, zal dit
+ gevolgen hebben voor veel andere ontwerpen.
+- In [Carlton](https://freesewing.org/designs/carlton) - en dus ook in
+ [Carlita](https://freesewing.org/designs/carlita) - hebben we
+ hersteld en uitgegeven waar de naadtoeslag op de onderkraag verkeerd was getekend.
+- In [Charlie](https://freesewing.org/designs/charlie) is voor de achterzak welt
+ (4) en voorzak facing (8) ten onrechte aangegeven dat er 2 in plaats van 4
+ in de kniplijst moeten worden geknipt. This too is resolved.
+- In [Hugo](https://freesewing.org/designs/hugo) hebben we een bug verholpen die ervoor zorgde dat
+ het ontwerp een foutmelding gaf als de volledige instelling uit stond, en we hebben een probleem verholpen
+ waarbij de opening van de voorzak steeds smaller werd naarmate de heup
+ groter werd.
+- We hebben een nieuwe methode
+ [Path.combine()](https://freesewing.dev/reference/api/path/combine) toegevoegd aan
+ [onze kern-API](https://freesewing.dev/reference/api). De oorsprong ligt in een
+ discussie in issue
+ \#5976 die
+ oorspronkelijk was ingediend als een bugrapport over hoe Path.join() gaten in de
+ samengevoegde paden verbindt - veroorzaakt door `verplaats` operaties, of een verschil tussen
+ het eind- en beginpunt van samengevoegde paden - om op te vullen met een lijn
+ segment. Dat gedrag wordt verwacht/bedoeld, maar we hebben
+ `Path.combine()` toegevoegd om het andere gedrag te vergemakkelijken: Het combineren van verschillende paden
+ in een enkel Path object zonder de tekenbewerkingen af te wisselen.
+- De [title macro](https://freesewing.dev/reference/macros/title) kan nu
+ geconfigureerd worden met een `notes` en `classes.notes` instelling in de configuratie, zodat
+ ontwerpers noten kunnen toevoegen aan (de titel van) een patroondeel.
+- Onze [i18n plugin](https://freesewing.dev/reference/plugins/i18n) ondersteunt nu
+ ondersteunt nu vertaling van geneste matrices van strings, wat ontwerpers
+ meer flexibiliteit geeft om vertaalde delen van strings aan elkaar te rijgen.
+
+De [FreeSewing 3.2 aankondiging blog post](https://freesewing.org/blog/v3-2-0) heeft alle details.
+
+
+
+---
+
+
+
+## E-mail is weer moeilijker geworden
+
+Als je dit in je inbox leest en niet in een gearchiveerde kopie op
+FreeSewing.org, dan hebben we deze e-mail bij je kunnen afleveren en dat is goed
+nieuws.
+
+Wat je je misschien niet realiseert is dat dit niet bepaald triviaal is, en dat is
+al jaren niet meer. Maar onlangs zijn de dingen nog ingewikkelder geworden. Gmail
+(Google) en Yahoo bijvoorbeeld hebben nieuwe beperkingen geïmplementeerd in het eerste
+kwartaal van
+2024 waardoor
+extra werk van onze kant vereist is om de kans te maximaliseren dat deze e-mail
+daadwerkelijk in je inbox terechtkomt.
+
+Bovendien worden zogenaamde _bulk e-mail afzenders_ onderworpen aan de strengste
+controles. Als je 5000 berichten per dag verstuurt, word je beschouwd als een bulkverzender en wordt
+extra kritisch bekeken. Aangezien deze nieuwsbrief ongeveer 14k
+abonnees heeft, worden we aan de hoogst mogelijke normen gehouden.
+
+Uiteraard houdt niemand van spam en ik pleit niet tegen deze regels.
+Het is gewoon zo dat de hoeveelheid tijd en moeite die nodig is om iets dat
+zo triviaal lijkt als het versturen van een e-mail op schaal te laten werken, steeds groter wordt naarmate
+het internet evolueert naar een de-facto pay-to-play model.
+
+Voorlopig doe ik die inspanningen nog steeds, en hopelijk zijn ze voldoende gebleken
+om dit in jullie inbox te krijgen. Maar het is iets dat we op een later tijdstip
+misschien opnieuw moeten bekijken als het een steeds groter beslag legt op onze beperkte tijd en middelen.
+
+
+
+---
+
+
+
+## 🕸️ Bouwen aan het web van vertrouwen van FreeSewing in de nasleep van de XZ achterdeurpoging (5 minuten door joost)
+
+Afhankelijk van waar je je nieuws vandaan haalt, heb je misschien gehoord of gelezen over
+de backdoor poging van het xz compressie
+hulpprogramma.
+
+In een notendop probeerde een kwaadwillende actor een backdoor te introduceren in dit
+hulpprogramma, wat uiteindelijk een poging was om een gated RCE-exploit binnen te smokkelen in
+SSHd.
+
+Of, in [ELI5](https://en.wiktionary.org/wiki/ELI5) termen: Iemand heeft
+code bijgedragen aan een kleine bibliotheek die snode bedoelingen had. Het werd op een geniepige manier gedaan
+en het uiteindelijke doelwit was niet de bibliotheek zelf, maar een ander software
+project dat deze bibliotheek gebruikt: De Secure Shell Deamon. Een _daemon_ is gewoon een
+cooler woord voor een _service_ op een computer, want waarom dingen niet cooler maken.
+Deze specifieke daemon of dienst, de _secure shell_ daemon is verantwoordelijk voor
+het afhandelen van beveiligde shell (SSH) verbindingen. Het is de gouden standaard voor extern
+beheer van Linux (en unix) systemen.
+
+De code smokkelde een gesloten RCE backdoor binnen. RCE staat voor _remote code
+execution_, wat betekent dat je _dingen_ op afstand kunt doen zonder
+authenticatie of iets dergelijks. Of anders gezegd, het stelt iemand in staat om
+te bedienen van een computersysteem op afstand waar hij normaal gesproken geen toegang toe zou mogen hebben.
+Het feit dat het _gated_ is betekent dat de auteur van
+de kwaadaardige code stappen heeft genomen om ervoor te zorgen dat alleen zij de kwaadaardige
+code konden gebruiken. Als een achterdeur met een sleutel.
+
+Het is moeilijk om de ernst te overschatten van deze poging tot backdooring van in wezen
+elk Linux systeem op de planeet. Het is niet alleen 's werelds meest gebruikte besturingssysteem
+, de dominantie van server besturingssystemen is overweldigend.
+Of zoals ik vaak zeg: Alles wat er toe doet draait op Linux_.
+
+Dit is een doorlopend verhaal en ik hoop dat er een Netflix
+miniserie van wordt gemaakt met David Cross in de rol van Andres
+Freund, maar ik dwaal af. Dit is de FreeSewing
+nieuwsbrief, dus ik wilde iets uit dit verhaal halen waarvan ik denk dat
+relevant is voor FreeSewing, of eigenlijk voor elk open source project dat er is.
+
+### Burn-out bij de beheerder en de lange weg om vertrouwen te winnen
+
+Een van de fascinerende elementen van dit verhaal is _wie_ de wijzigingen heeft bijgedragen,
+en waarom ze werden geaccepteerd zonder voldoende nauwkeurig onderzoek om de kwaadaardige
+bedoeling van de bijdrage te onthullen.
+
+Omdat de gebruiker die ze maakte al **years** had bijgedragen aan het project
+en door dit werk in status was gestegen tot een niveau waarop er veel
+impliciet vertrouwen was gebaseerd op hun werk, ondanks dat ze vrijwel niets wisten over
+wie of wat er achter gebruikersnaam `JiaT75` (in dit geval) schuilgaat. Zo'n _lange oplichting_ is
+een aanzienlijke investering in tijd en moeite, dus de huidige aanname
+is dat dit een actor uit een natiestaat was (denk aan NSA of het
+equivalent van een ander land). Het is ook belangrijk om op te merken dat de xy-beheerder het
+erg moeilijk had met de lange staart van verantwoordelijkheden van het onderhouden van
+software en actief op zoek was naar hulp om een burnout te voorkomen. Het is een
+scenario dat schokkend vaak voorkomt bij open source projecten en een
+situatie creëert waarin kwaadwillende actoren maar al te gemakkelijk misbruik kunnen maken van uitgeputte
+beheerders die wanhopig zijn om wat van het werk over te nemen.
+
+### Een web van vertrouwen creëren
+
+Dit probleem van _wie kun je vertrouwen_ is natuurlijk niet nieuw. Een manier om het tegen te gaan
+is door een _web van vertrouwen_ te creëren. Dit is hoe dingen worden gedaan in grotere
+open source software projecten waarbij veel vrijwilligers betrokken zijn, zoals het Debian
+project.
+
+Praktisch gezien is zo'n web van vertrouwen gebouwd op relaties tussen
+mensen die elkaars ware identiteit kennen en hebben geverifieerd. Bijvoorbeeld,
+er zijn een aantal mensen in de FreeSewing gemeenschap die ik in het echte
+leven heb ontmoet. We hebben elkaar niet alleen persoonlijk ontmoet, maar ook tijd met elkaar doorgebracht, we kennen
+waar we wonen, we kennen elkaars partners of familie, of hebben een andere
+tastbare manier die een hoge mate van zekerheid geeft dat deze persoon echt
+is wie hij beweert te zijn.
+
+Die mensen kunnen op hun beurt soortgelijke connecties hebben met anderen die ze kennen,
+hebben ontmoet en vertrouwen op een niveau dat veel verder gaat dan de online wereld. Dit
+creëert een web van vertrouwen waarin je je vrienden kunt vertrouwen, en de vrienden van
+je vrienden enzovoort.
+
+In het licht van de huidige gebeurtenissen en als erkenning van de snelle versnelling van
+wat er mogelijk is met generatieve kunstmatige intelligentie, zal FreeSewing
+voortaan alle schrijftoegang of verhoogde privileges beperken tot leden van de gemeenschap
+die deel uitmaken van FreeSewing's web van vertrouwen.
+
+We blijven natuurlijk bijdragen accepteren - of liever gezegd beoordelen - van
+iedereen. Maar rechten die het potentieel ontsluiten om kwaad te doen, worden
+beperkt tot mensen voor wie vertrouwen is opgebouwd AFK (weg van
+toetsenbord).
+
+Om het bouwen van zo'n web van vertrouwen te vergemakkelijken, beginnen we met het documenteren van
+deze verbindingen tussen mensen. Hierdoor kunnen mensen die
+meer verantwoordelijkheden binnen FreeSewing op zich willen nemen, het vertrouwensweb bekijken en
+zien wie er bij hen in de buurt woont, zodat ze zich kunnen aansluiten bij ons vertrouwensweb via
+die persoon.
+
+Ik realiseer me dat het zeer onwaarschijnlijk is dat FreeSewing het doelwit wordt van een achterdeur
+poging door een nationale actor, maar het is hoe dan ook een goed idee om best practices toe te passen en
+transparant te zijn over hoe we dingen doen.
+
+Ik zal dus in de komende paar weken beginnen met het bouwen en documenteren van dit web van vertrouwen,
+, en alle toegangscontroles en toestemmingen herzien om er zeker van te zijn dat we
+alles doen wat we kunnen om te voorkomen dat zelfs de meest toegewijde actoren
+de bron vergiftigen.
+
+
+
+---
+
+
+
+## 🤔 Hoe de uitdagingen van FreeSewing in de loop der tijd zijn veranderd
+
+Wist je dat FreeSewing v1 7 jaar en 7 dagen
+geleden is uitgebracht? Sinds die tijd hebben we
+veel grote en kleine veranderingen doorgevoerd, en onze kernbibliotheek en plugin-systeem zijn
+uitgegroeid tot een betrouwbare -- en zeker eigenwijze -- manier om parametrische
+naaipatronen te ontwerpen.
+
+De uitdagingen die vanuit technisch oogpunt het meest interessant zijn, zijn
+min of meer opgelost. Wat overblijft is de gebruikerskant, of
+de gebruikerservaring (UX) zoals wij het graag noemen.
+
+FreeSewing kan veel, dus hoe maak je al die functionaliteit beschikbaar voor de
+gebruikers zonder ze te overweldigen? Is dat zelfs mogelijk op mobiel, wat nu de
+dominante manier is waarop mensen online gaan. Hoe maak je er een intuïtieve ervaring van,
+of hoe begeleid je iemand die op FreeSewing.org terechtkomt na een Google-zoekopdracht naar _gratis naaipatronen_
+naar een begrip van wat FreeSewing is en doet in de handvol
+seconden dat mensen het waarschijnlijk een kans geven voordat ze verder gaan naar de volgende
+link in hun zoekresultaten.
+
+Voor de duidelijkheid: ik weet het antwoord op deze vragen niet. Maar het is
+steeds meer waar we onze tijd aan besteden. Het percentage mensen dat
+onze software rechtstreeks gebruikt, is verwaarloosbaar vergeleken met het aantal mensen dat
+(alleen) onze software gebruikt via onze website. Voor de meeste bezoekers is FreeSewing
+**is** een website en als het iets anders is, is dat waarschijnlijk niet duidelijk voor hen,
+of zelfs maar relevant.
+
+Er is duidelijk ruimte voor verbetering, maar vaak is er niet één duidelijk pad
+voorwaarts. Misschien -- of moet ik zeggen bijna zeker -- is dit een gebied waar ik
+het talent of de vaardigheid mis om een soort grote overkoepelende
+strategie te bedenken. Maar ik betrap mezelf erop dat ik veel van mijn eigen ideeën of impulsen
+op dit gebied in twijfel trek.
+
+Dus ik vroeg me af of we een klein experiment konden doen. Een experiment waarbij ik
+aan jou -- mijn beste lezer -- een eenvoudige vraag stel. Ben je er klaar voor? Hier
+is de vraag:
+
+> **Wat is FreeSewing?**
+
+Ik hoor graag je antwoord. Je kunt gewoon op reply drukken om het me te laten weten.
+
+_PS: Ik heb deze vraag aan het eind begraven, omdat ik het gevoel heb dat als je door alles van
+hebt gelezen wat ervoor kwam, ik waarschijnlijk je gedachten wil horen._
diff --git a/markdown/org/newsletter/2024q2/uk.md b/markdown/org/newsletter/2024q2/uk.md
new file mode 100644
index 00000000000..2db3f48e9c1
--- /dev/null
+++ b/markdown/org/newsletter/2024q2/uk.md
@@ -0,0 +1,280 @@
+---
+date: 2024-04-01
+edition: 2024q2
+intro: Ласкаво просимо до весняного випуску 2024 року інформаційного бюлетеня FreeSewing.
+title: 2024 Весняний випуск
+---
+
+Ласкаво просимо до весняного випуску 2024 року інформаційного бюлетеня FreeSewing.
+
+Ось що ми маємо для вас сьогодні, і це не жарт:
+
+- FreeSewing 3.2 приносить Tristan, Lumina, Lumira та багато іншого (3-хвилинне читання від joost)
+- Електронна пошта знову стала складнішою (1 хвилина читання від joost)
+- 🕸️ Побудова мережі довіри до FreeSewing після спроби бекдору XZ (5 хвилин на joost)
+- Як змінилися виклики FreeSewing з плином часу (2-хвилинне читання від joost)
+
+Почнемо?
+
+
+
+
+
+## FreeSewing 3.2 приносить Tristan, Lumina, Lumira та багато іншого
+
+Ми випустили FreeSewing v3.2 раніше в першому кварталі 2024 року, і він включає в себе 3 нових дизайни
+, а також ряд виправлень і поліпшень.
+
+Давайте подивимося на основні моменти:
+
+### The Tristan Top
+
+По-перше, це [Tristan Top] (https://freesewing.org/designs/tristan). Трістан - топ зі швами "принцеса" та (за бажанням) шнурівкою спереду та/або ззаду. Історія його виникнення - це потреба в костюмі для фестивалю Ренесансу, тож це, мабуть, хороший показник того, чого очікувати.
+
+Трістан був розроблений Наталією, яка також [написала пост про новий дизайн Трістана] (https://freesewing.org/blog/our-newest-design-is-the-tristan-top), тож це чудове місце, де можна дізнатися всі подробиці про цей новий дизайн.
+
+### The Lumina and Lumira Leggings
+
+Я дам вам секунду, щоб відсканувати цю назву ще раз, але так, є дві різні моделі легінсів зі схожими назвами: [the Lumira Leggings] (https://freesewing.org/designs/lumira) та [Lumina Leggings] (https://freesewing.org/designs/lumina).
+
+Обидві моделі народилися з бажання Воутера створити хороше велосипедне спорядження, і я пропоную вам ознайомитися з дизайнерськими нотатками для [Lumina] (https://freesewing.org/designs/lumina#notes) та [Lumira] (https://freesewing.org/designs/lumira#notes), щоб повністю оцінити різницю між цими моделями, чому вони відрізняються, і яка з них підійде вам найкраще.
+
+### Bug fixes and improvements
+
+Постійні читачі бюлетеня знають, що ми постійно впроваджуємо
+покращення на FreeSewing.org, і що вони не пов'язані з новим випуском,
+але це гарна можливість перерахувати їх, тому ось деякі основні моменти виправлення помилок
+і покращень, які увійшли до випуску 3.2:
+
+- Сенді має нові панелі
+ опції, які були
+ додані [Паулою](https://github.com/freesewing/freesewing/pull/5861). Ви завжди
+ можете створити свою спідницю-коло з кількох схожих викрійок,
+ виконавши підбір самостійно, але тепер викрійка подбає про це за вас.
+- Те, що почалося як [звіт про баг для біцепса на
+ Jaeger] (https://github.com/freesewing/freesewing/issues/5999), закінчилося
+ зміною способу розрахунку обхвату плеча на Брайані, зокрема глибини
+ пройми. Враховуючи, що Брайан є нашим найбільш фундаментальним блоком, це матиме
+ вплив на багато інших конструкцій, ви можете очікувати, що поза коробкою
+ обхвату буде трохи нижчим.
+- В [Carlton](https://freesewing.org/designs/carlton) - і, відповідно, в
+ [Carlita](https://freesewing.org/designs/carlita) - ми виправили і випустили
+ , де припуск на шов на комірі був неправильно накреслений.
+- У моделі [Charlie](https://freesewing.org/designs/charlie) для шва задньої кишені
+ (4) і лицьової частини передньої кишені (8) у списку розкрою помилково вказано 2 замість 4
+ . This too is resolved.
+- У [Hugo](https://freesewing.org/designs/hugo) ми виправили баг, який призводив до
+ помилок у дизайні при вимкненому повному налаштуванні, а також вирішили проблему
+ , коли отвір передньої кишені ставав дедалі вужчим зі збільшенням обхвату стегон
+ .
+- Ми додали новий метод
+ [Path.combine()](https://freesewing.dev/reference/api/path/combine) до
+ [нашого основного API](https://freesewing.dev/reference/api). Вона виникла з
+ обговорення у випуску
+ \#5976, яке було
+ спочатку подано як звіт про ваду про те, як Path.join() з'єднує пропуски у
+ об'єднаних шляхах - спричинені або операціями `move`, або різницею між
+ кінцевою та початковою точками об'єднаних шляхів - і заповнює їх відрізком лінії
+ . Така поведінка є очікуваною/передбачуваною, але ми додали
+ `Path.combine()`, щоб полегшити іншу поведінку: Об'єднання різних контурів
+ в один об'єкт Path без зміни операцій малювання.
+- Макрос [title макрос](https://freesewing.dev/reference/macros/title) тепер можна
+ налаштувати за допомогою параметрів `notes` та `classes.notes` у його конфігурації, що дозволить дизайнерам
+ додавати примітки до частини шаблону (заголовка).
+- Наш [плагін i18n](https://freesewing.dev/reference/plugins/i18n) тепер підтримує
+ тепер підтримує переклад вкладених масивів рядків, що надає дизайнерам
+ більше гнучкості для конкатенації перекладених частин рядків.
+
+Всі деталі можна знайти у блозі [Анонс FreeSewing 3.2] (https://freesewing.org/blog/v3-2-0).
+
+
+
+---
+
+
+
+## Електронна пошта знову стала складнішою
+
+Якщо ви читаєте цей лист у своїй поштовій скриньці, а не архівну копію на
+FreeSewing.org, значить ми змогли доставити його вам, що є гарною
+новиною.
+
+Можливо, ви не усвідомлюєте, що це не зовсім тривіально, і не було
+роками. Але останнім часом все стало ще складніше. Gmail
+(Google) та Yahoo, наприклад, [запровадили нові обмеження в першому
+кварталі
+2024 року] (https://www.xomedia.io/blog/a-deep-dive-into-email-deliverability/), що
+вимагає додаткової роботи з нашого боку, щоб максимізувати шанси на те, що цей лист
+дійсно потрапить до вашої поштової скриньки.
+
+Крім того, так звані _масові відправники_ підлягають найсуворішим перевіркам
+. Якщо ви надсилаєте 5000 повідомлень на день, ви вважаєтесь масовим відправником, і
+підлягає додатковій перевірці. Оскільки цей бюлетень має близько 14 тис. підписників
+, ми дотримуємося найвищих стандартів.
+
+Очевидно, що ніхто не любить спам, і я не виступаю проти цих правил.
+Просто кількість часу та зусиль, необхідних для того, щоб зробити щось
+, здавалося б, тривіальне, як розсилка електронних листів, працює в масштабах, постійно зростає, оскільки
+Інтернет має тенденцію до де-факто моделі "плати за послугу" (pay-to-play).
+
+Наразі я все ще докладаю цих зусиль, і сподіваюся, що вони виявилися достатніми
+, щоб отримати цей лист до вашої поштової скриньки. Але, можливо, нам доведеться повернутися до цього питання пізніше
+, якщо це стане все більшим навантаженням на наш обмежений час і ресурси.
+
+
+
+---
+
+
+
+## 🕸️ Побудова мережі довіри до FreeSewing після спроби бекдору XZ (5 хвилин на joost)
+
+Залежно від того, звідки ви отримуєте новини, ви могли чути або читати про
+спроба бекдору в утиліті для стиснення xz
+.
+
+У двох словах, зловмисник намагався впровадити бекдор в утиліту
+, що в кінцевому підсумку було спробою контрабанди закритого RCE-експлоіта в
+SSHd.
+
+Або, кажучи мовою [ELI5](https://en.wiktionary.org/wiki/ELI5): Хтось додав код
+до невеликої бібліотеки з недобрими намірами. Це було зроблено підступно
+і кінцевою метою була не сама бібліотека, а інший програмний
+проект, який використовує цю бібліотеку: Secure Shell Deamon. Демон - це просто
+крутіше слово для позначення _сервісу_ на комп'ютері, бо чому б не зробити речі крутішими.
+Цей конкретний демон або служба, демон _secure shell_, відповідає за обробку
+з'єднань по захищеній оболонці (SSH). Це золотий стандарт для віддаленого
+керування системами Linux (і Unix).
+
+Код проникає через закритий бекдор RCE. RCE розшифровується як _віддалене
+виконання коду_, що означає, що він дозволяє вам _робити щось_ віддалено без необхідності
+автентифікації або чогось подібного. Або, інакше кажучи, він дозволяє контролювати
+віддалену комп'ютерну систему, до якої зазвичай не мають доступу.
+Той факт, що він _закритий_, означає, що автор
+шкідливого коду вжив заходів для того, щоб тільки він міг використовувати шкідливий
+код. Як чорний хід з ключем.
+
+Важко переоцінити серйозність цієї спроби бекдору фактично
+кожну систему Linux на планеті. Це не лише найпоширеніша у світі операційна система
+, але й переважна більшість серверних операційних систем.
+Або, як я часто кажу: Все, що має значення, працює на Linux.
+
+Ця історія триває, і я, зі свого боку, сподіваюся, що з неї зроблять міні-серіал на Netflix
+з Девідом Кроссом у ролі [Андреса
+Фройнда] (https://github.com/anarazel), але я відволікаюся. Це інформаційний бюлетень FreeSewing
+, тому я хотів би витягнути з цієї історії дещо, що, на мою думку,
+має відношення до FreeSewing, або взагалі до будь-якого проекту з відкритим вихідним кодом.
+
+### Вигоряння мапінтейнера та довгий шлях до довіри
+
+Одним із цікавих елементів цієї історії є те, хто вніс зміни,
+і чому вони були прийняті без достатньої перевірки, щоб виявити зловмисні
+наміри цього внеску.
+
+Тому що користувач, який їх створив, робив внесок для **years** проекту
+і в світлі цієї роботи піднявся в статусі до рівня, коли було багато
+неявної довіри, заснованої на його роботі, незважаючи на те, що він майже нічого не знав про
+, хто або що ховається за ім'ям користувача `JiaT75` (в даному випадку). Така _довга афера_ вимагає
+значних витрат часу та зусиль, тому наразі припущення
+, що це був актор національної держави (згадайте АНБ або еквівалент
+іншої країни). Важливо також зазначити, що супровідник xy мав
+труднощі з довгим хвостом обов'язків з підтримки програмного забезпечення
+і активно шукав допомоги, щоб запобігти вигоранню. Це
+сценарій, який шокуюче поширений у проектах з відкритим вихідним кодом і створює
+ситуацію, коли зловмисники можуть дуже легко скористатися виснаженими
+супровідниками, які відчайдушно намагаються розвантажити частину роботи.
+
+### Створення мережі довіри
+
+Проблема "кому можна довіряти", звичайно, не нова. Одним із способів протистояти цьому
+є створення "павутини довіри". Саме так це робиться у великих
+проектах програмного забезпечення з відкритим кодом, до яких залучено багато волонтерів, таких як проект Debian
+.
+
+На практиці така мережа довіри будується на відносинах між
+людьми, які знають і перевірили справжню особистість один одного. Наприклад,
+у спільноті FreeSewing є багато людей, з якими я зустрічалася в реальному
+житті. Ми не просто зустрічалися віч-на-віч, а проводили час разом, ми знаємо
+, де живемо, ми знаємо партнерів або сім'ю один одного, або маємо інший
+відчутний спосіб, який забезпечує високий рівень впевненості в тому, що ця людина дійсно є
+, за кого вона себе видає.
+
+Ці люди, в свою чергу, можуть мати подібні зв'язки з іншими людьми, яких вони знають,
+зустрічали, і довіряти їм на рівні, що виходить далеко за межі онлайн-світу. Цей
+створює мережу довіри, де ви можете довіряти своїм друзям, а друзі
+своїм друзям і так далі.
+
+У світлі поточних подій та на знак визнання швидкого прискорення
+того, що можливо за допомогою генеративного штучного інтелекту, FreeSewing
+відтепер обмежуватиме всі права на запис або підвищені привілеї для членів спільноти
+, які є частиною мережі довіри FreeSewing.
+
+Звичайно, ми продовжимо приймати - чи радше переглядати - внески від
+від усіх охочих. Але дозволи, які відкривають потенціал заподіяння шкоди, будуть
+обмежені людьми, яким встановлено довіру AFK (подалі від
+клавіатури).
+
+Щоб полегшити побудову такої павутини довіри, ми почнемо документувати
+ці зв'язки між людьми. Це дозволить людям, які хочуть
+взяти на себе більше відповідальності у Вільному Шитті, подивитися на мережу довіри і
+побачити, хто живе поруч з ними, щоб вони могли приєднатися до нашої мережі довіри через
+цієї людини.
+
+Я розумію, що FreeSewing вкрай малоймовірно, що FreeSewing стане мішенню для спроби чорного ходу
+з боку національної держави, але переймати найкращі практики та бути
+прозорими щодо того, як ми працюємо, - це хороша ідея, незважаючи ні на що.
+
+Отже, я почну будувати і документувати цю павутину довіри протягом наступних кількох
+тижнів, а також перегляну весь контроль доступу і дозволи, щоб переконатися, що ми
+робимо все можливе, щоб навіть найвідданіші актори не змогли отруїти
+колодязь.
+
+
+
+---
+
+
+
+## 🤔 Як змінилися виклики FreeSewing з плином часу
+
+Чи знали ви, що [FreeSewing v1 було випущено 7 років і 7 днів
+тому] (https://freesewing.org/blog/announcing-freesewing)? З того часу ми
+багато великих і малих змін, а наша основна бібліотека і система плагінів
+перетворилися на надійний - і, безумовно, самодостатній - спосіб проектування параметричних
+викрійок одягу.
+
+Найцікавіші з технічної точки зору виклики були
+більш-менш вирішені. Залишається тільки сторона, звернена до користувача, або
+користувацький досвід (UX), як ми любимо його називати.
+
+FreeSewing може багато чого, тож як зробити всю цю функціональність доступною для користувачів
+, не перевантажуючи їх? Чи можливо це взагалі на мобільному телефоні, який є
+домінуючим способом, за допомогою якого люди зараз виходять в Інтернет. Як зробити його інтуїтивно зрозумілим,
+або направити того, хто потрапляє на FreeSewing.org після
+пошуку в Google до розуміння того, що таке FreeSewing і чим він займається, за кілька
+секунд, які люди, швидше за все, дадуть йому шанс, перш ніж перейти до наступного
+посилання в результатах пошуку.
+
+Скажу відверто: я не знаю відповіді на ці питання. Але це
+все частіше те, на що ми витрачаємо свій час. Відсоток людей, які
+використовують наше програмне забезпечення безпосередньо, є незначним порівняно з кількістю людей, які
+(лише) споживають наше програмне забезпечення через наш веб-сайт. Для більшості відвідувачів FreeSewing
+**is** - це веб-сайт, а якщо це щось інше, то, ймовірно, незрозуміле для них,
+або навіть неактуальне.
+
+Очевидно, що є місце для вдосконалення, але часто не існує єдиного очевидного шляху
+вперед. Можливо - або я б сказав майже напевно - це та сфера, де мені
+бракує таланту або навичок, щоб розробити якусь грандіозну всеохоплюючу
+стратегію. Але я переосмислюю багато своїх власних ідей чи імпульсів
+у цій сфері.
+
+Тож я подумав, що ми могли б провести невеличкий експеримент. Експеримент, в якому я
+задам тобі, мій дорогий читачу, просте запитання. Чи готові ви до цього? Ось тут
+є питання:
+
+> **Що таке FreeSewing?**
+
+Я хотів би почути вашу відповідь. Ви можете просто натиснути кнопку "Відповісти", щоб повідомити мені про це.
+
+_PS: Я поховав це питання в кінці, тому що відчуваю, що якщо ви прочитаєте все
+, що було до цього, я, мабуть, захочу почути ваші думки._.
diff --git a/markdown/org/showcase/a-full-body-onyx-swimsuit-with-swim-skirt/uk.md b/markdown/org/showcase/a-full-body-onyx-swimsuit-with-swim-skirt/uk.md
index 1438d1218cb..15c20d76fda 100644
--- a/markdown/org/showcase/a-full-body-onyx-swimsuit-with-swim-skirt/uk.md
+++ b/markdown/org/showcase/a-full-body-onyx-swimsuit-with-swim-skirt/uk.md
@@ -15,6 +15,6 @@ Featuring a hood, thumb holes, and long sleeves and legs, it provides nearly ful
The swim skirt provides additional modesty and adds some flair.
-It is fully lined, including the hood and sleeves, with all but one of the seams hidden inside the lining, and very comfortable. Center seam and outseam ease are 0%, while most eases controlling tightness are set to \~-10%, though wrist is at +11% to give room for the hand, and leg hem is at +10% to help it get over the foot. The skirt length is 100% and width is 126% and is gathered and topstitched into place with no hems or folding.
+It is fully lined, including the hood and sleeves, with all but one of the seams hidden inside the lining, and very comfortable. Center seam and outseam ease are 0%, while most eases controlling tightness are set to ~-10%, though wrist is at +11% to give room for the hand, and leg hem is at +10% to help it get over the foot. The skirt length is 100% and width is 126% and is gathered and topstitched into place with no hems or folding.
Fabric used is 80% nylon/20% spandex mid-weight swim fabric for the fashion fabric, and 80% polyester/20% spandex heavyweight swim fabric for the lining. Construction is done using a serger/overlock machine for the seams, and a twin needle using a triple stretch stitch for the hems.
diff --git a/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/de.md b/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/de.md
index e989d5b4b96..c1888a9da56 100644
--- a/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/de.md
+++ b/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/de.md
@@ -6,6 +6,7 @@ intro: This Tristan top is lined and had bias binding applied to the neck hole,
designs:
- tristan
maker: Natalia
+author: 60164
---
This Tristan top is lined and had bias binding applied to the neck hole, armholes, and hem. It laces in the front to make it easier to wear. This top is technically reversible, although the eyelets are a bit rough on the back side. The boning used is lightweight plastic boning. It gives a nice amount of structure, and support for the lacing.
diff --git a/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/en.md b/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/en.md
index 508815f88bf..18aa79dc5b8 100644
--- a/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/en.md
+++ b/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/en.md
@@ -4,7 +4,7 @@ caption: "A top made out of fabric scraps. The main fabric was likely upholstery
date: 20240116
intro: "This Tristan top is lined and had bias binding applied to the neck hole, armholes, and hem."
designs: ["tristan"]
-maker: Natalia
+author: 19867
---
This Tristan top is lined and had bias binding applied to the neck hole, armholes, and hem. It laces in the front to make it easier to wear. This top is technically reversible, although the eyelets are a bit rough on the back side. The boning used is lightweight plastic boning. It gives a nice amount of structure, and support for the lacing.
diff --git a/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/es.md b/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/es.md
index e989d5b4b96..c1888a9da56 100644
--- a/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/es.md
+++ b/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/es.md
@@ -6,6 +6,7 @@ intro: This Tristan top is lined and had bias binding applied to the neck hole,
designs:
- tristan
maker: Natalia
+author: 60164
---
This Tristan top is lined and had bias binding applied to the neck hole, armholes, and hem. It laces in the front to make it easier to wear. This top is technically reversible, although the eyelets are a bit rough on the back side. The boning used is lightweight plastic boning. It gives a nice amount of structure, and support for the lacing.
diff --git a/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/fr.md b/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/fr.md
index e989d5b4b96..c1888a9da56 100644
--- a/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/fr.md
+++ b/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/fr.md
@@ -6,6 +6,7 @@ intro: This Tristan top is lined and had bias binding applied to the neck hole,
designs:
- tristan
maker: Natalia
+author: 60164
---
This Tristan top is lined and had bias binding applied to the neck hole, armholes, and hem. It laces in the front to make it easier to wear. This top is technically reversible, although the eyelets are a bit rough on the back side. The boning used is lightweight plastic boning. It gives a nice amount of structure, and support for the lacing.
diff --git a/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/nl.md b/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/nl.md
index e989d5b4b96..c1888a9da56 100644
--- a/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/nl.md
+++ b/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/nl.md
@@ -6,6 +6,7 @@ intro: This Tristan top is lined and had bias binding applied to the neck hole,
designs:
- tristan
maker: Natalia
+author: 60164
---
This Tristan top is lined and had bias binding applied to the neck hole, armholes, and hem. It laces in the front to make it easier to wear. This top is technically reversible, although the eyelets are a bit rough on the back side. The boning used is lightweight plastic boning. It gives a nice amount of structure, and support for the lacing.
diff --git a/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/uk.md b/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/uk.md
index e289c399aaf..c9b78b51add 100644
--- a/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/uk.md
+++ b/markdown/org/showcase/a-lined-tristan-top-with-front-lacing/uk.md
@@ -6,6 +6,7 @@ intro: This Tristan top is lined and had bias binding applied to the neck hole,
designs:
- tristan
maker: Наталя
+author: 60164
---
This Tristan top is lined and had bias binding applied to the neck hole, armholes, and hem. It laces in the front to make it easier to wear. This top is technically reversible, although the eyelets are a bit rough on the back side. The boning used is lightweight plastic boning. It gives a nice amount of structure, and support for the lacing.
diff --git a/markdown/org/showcase/a-noble-top-for-the-renaissance-festival/en.md b/markdown/org/showcase/a-noble-top-for-the-renaissance-festival/en.md
index 3c86206f75f..401f00d6676 100644
--- a/markdown/org/showcase/a-noble-top-for-the-renaissance-festival/en.md
+++ b/markdown/org/showcase/a-noble-top-for-the-renaissance-festival/en.md
@@ -4,7 +4,7 @@ caption: "This top is made from scrap cotton fabrics"
date: 20231016
intro: "This top is based on the Noble block."
designs: ["tristan"]
-maker: Natalia
+author: 19867
---
This top was made based on the Noble block, and later spun off into its own design, Tristan. The wearer reports that their body is asymmetric, which you can see in the back view. They were very happy with this simple variation of Noble.
diff --git a/markdown/org/showcase/a-short-sleeved-simon-with-bonus-charlie-and-florent/en.md b/markdown/org/showcase/a-short-sleeved-simon-with-bonus-charlie-and-florent/en.md
new file mode 100644
index 00000000000..a57259dffb9
--- /dev/null
+++ b/markdown/org/showcase/a-short-sleeved-simon-with-bonus-charlie-and-florent/en.md
@@ -0,0 +1,17 @@
+---
+title: "A short-sleeved Simon with bonus Charlie and Florent"
+caption: "Did you spot Charlie on Naël's legs and a Florent on the front?"
+date: 20240501
+intro: "This Simon shirt by super-maker Naël looks fantastic."
+author: 32412
+designs: ["simon"]
+---
+
+This short-sleeved Simon shirt by super-maker Naël looks fantastic and they look great wearing it! They cut the minimum sleeve length and then cut additional length because it was too long.
+
+And you can spot a pair of Charlie pants and a Florent flat cap in the front!
+
+
+
+
+
diff --git a/markdown/org/showcase/a-sturdy-albert-apron-by-ojensen/de.md b/markdown/org/showcase/a-sturdy-albert-apron-by-ojensen/de.md
new file mode 100644
index 00000000000..73d933bd291
--- /dev/null
+++ b/markdown/org/showcase/a-sturdy-albert-apron-by-ojensen/de.md
@@ -0,0 +1,11 @@
+---
+title: A sturdy Albert apron by ojensen
+caption: It was made out of a fairly sturdy duck canvas.
+date: 20240418
+intro: This Albert apron was Oliver's very first sewing project!
+author: null
+designs:
+ - albert
+---
+
+This Albert apron was Oliver's very first sewing project! They made it out of a fairly sturdy duck canvas. We think this is a great intro to sewing and excellent work!
diff --git a/markdown/org/showcase/a-sturdy-albert-apron-by-ojensen/en.md b/markdown/org/showcase/a-sturdy-albert-apron-by-ojensen/en.md
new file mode 100644
index 00000000000..09cd9114146
--- /dev/null
+++ b/markdown/org/showcase/a-sturdy-albert-apron-by-ojensen/en.md
@@ -0,0 +1,11 @@
+---
+title: "A sturdy Albert apron by ojensen"
+caption: "It was made out of a fairly sturdy duck canvas."
+date: 20240418
+intro: "This Albert apron was Oliver's very first sewing project!"
+author: null
+designs: ["albert"]
+---
+
+This Albert apron was Oliver's very first sewing project! They made it out of a fairly sturdy duck canvas. We think this is a great intro to sewing and excellent work!
+
diff --git a/markdown/org/showcase/a-sturdy-albert-apron-by-ojensen/es.md b/markdown/org/showcase/a-sturdy-albert-apron-by-ojensen/es.md
new file mode 100644
index 00000000000..73d933bd291
--- /dev/null
+++ b/markdown/org/showcase/a-sturdy-albert-apron-by-ojensen/es.md
@@ -0,0 +1,11 @@
+---
+title: A sturdy Albert apron by ojensen
+caption: It was made out of a fairly sturdy duck canvas.
+date: 20240418
+intro: This Albert apron was Oliver's very first sewing project!
+author: null
+designs:
+ - albert
+---
+
+This Albert apron was Oliver's very first sewing project! They made it out of a fairly sturdy duck canvas. We think this is a great intro to sewing and excellent work!
diff --git a/markdown/org/showcase/a-sturdy-albert-apron-by-ojensen/fr.md b/markdown/org/showcase/a-sturdy-albert-apron-by-ojensen/fr.md
new file mode 100644
index 00000000000..c1e328ac63c
--- /dev/null
+++ b/markdown/org/showcase/a-sturdy-albert-apron-by-ojensen/fr.md
@@ -0,0 +1,11 @@
+---
+title: Un tablier Albert robuste par ojensen
+caption: Il était fait d'une toile canard assez solide.
+date: 20240418
+intro: Ce tablier Albert a été le tout premier projet de couture d'Oliver !
+author: null
+designs:
+ - albert
+---
+
+Ce tablier Albert a été le tout premier projet de couture d'Oliver ! Iel l'a fait d'une toile canard assez solide. Nous pensons que c'est une excellente introduction à la couture et un excellent travail !
diff --git a/markdown/org/showcase/a-sturdy-albert-apron-by-ojensen/nl.md b/markdown/org/showcase/a-sturdy-albert-apron-by-ojensen/nl.md
new file mode 100644
index 00000000000..73d933bd291
--- /dev/null
+++ b/markdown/org/showcase/a-sturdy-albert-apron-by-ojensen/nl.md
@@ -0,0 +1,11 @@
+---
+title: A sturdy Albert apron by ojensen
+caption: It was made out of a fairly sturdy duck canvas.
+date: 20240418
+intro: This Albert apron was Oliver's very first sewing project!
+author: null
+designs:
+ - albert
+---
+
+This Albert apron was Oliver's very first sewing project! They made it out of a fairly sturdy duck canvas. We think this is a great intro to sewing and excellent work!
diff --git a/markdown/org/showcase/a-sturdy-albert-apron-by-ojensen/uk.md b/markdown/org/showcase/a-sturdy-albert-apron-by-ojensen/uk.md
new file mode 100644
index 00000000000..e06d187fc16
--- /dev/null
+++ b/markdown/org/showcase/a-sturdy-albert-apron-by-ojensen/uk.md
@@ -0,0 +1,11 @@
+---
+title: A sturdy Albert apron by ojensen
+caption: It was made out of a fairly sturdy duck canvas.
+date: 20240418
+intro: This Albert apron was Oliver's very first sewing project!
+author: null
+designs:
+ - альберт
+---
+
+This Albert apron was Oliver's very first sewing project! They made it out of a fairly sturdy duck canvas. We think this is a great intro to sewing and excellent work!
diff --git a/markdown/org/showcase/a-top-based-on-sven-with-the-hood-of-hugo/en.md b/markdown/org/showcase/a-top-based-on-sven-with-the-hood-of-hugo/en.md
new file mode 100644
index 00000000000..7efe0763ace
--- /dev/null
+++ b/markdown/org/showcase/a-top-based-on-sven-with-the-hood-of-hugo/en.md
@@ -0,0 +1,13 @@
+---
+title: "A top based on Sven with the hood of Hugo"
+caption: "We love the color combo and trim detail"
+date: 20240429
+intro: "This excellent mashup design features the body of Sven and the hood of Hugo."
+author: 32412
+designs: ["sven", "hugo"]
+---
+
+This excellent mashup design features the body of Sven and the hood of Hugo for a nice overall look! Great work as always by FreeSewing maker Naël.
+
+
+
diff --git a/markdown/org/showcase/aaron-on-a-not-me-sized-dress-form-by-braveness23/en.md b/markdown/org/showcase/aaron-on-a-not-me-sized-dress-form-by-braveness23/en.md
new file mode 100644
index 00000000000..54c50f28abf
--- /dev/null
+++ b/markdown/org/showcase/aaron-on-a-not-me-sized-dress-form-by-braveness23/en.md
@@ -0,0 +1,23 @@
+---
+title: "Aaron on a not-me sized dress form by braveness23"
+caption: "This Aaron is sewn in a nice drapey gray fabric"
+date: 20240503
+intro: "This Aaron was maker braveness23's first project!"
+author: 23123
+designs: ["aaron"]
+---
+
+This Aaron was maker braveness23's first project! He shared some helpful construction details:
+
+"I serged the sides and tops of the arms. I sewed the bottom hem with a double needle on my Brother sewing machine. And I follow [this [Single Fold Knit Binding Youtube video]](https://youtu.be/DIxlWrmNayY) for the neck and arms. For the later I used a double needle, surger thread and a super low bobbin tension on my Bernina sewing machine"
+
+He mentioned that it was a really good fit but doesn't conceal his parastomal hernia, but it wasn't designed for that purpose. Also, he wishes he had made the armholes a lot smaller. We appreciate when folks share these kinds of details for the benefit of future makers!
+
+Great work, braveness23!
+
+
+
+
+
+
+
diff --git a/markdown/org/showcase/albert-apron-by-saber007s-son/en.md b/markdown/org/showcase/albert-apron-by-saber007s-son/en.md
new file mode 100644
index 00000000000..dfddeb82f31
--- /dev/null
+++ b/markdown/org/showcase/albert-apron-by-saber007s-son/en.md
@@ -0,0 +1,11 @@
+---
+title: "Albert Apron by Saber.007's son"
+caption: "Great fabric choice!"
+date: 20240429
+intro: "Saber.007's son did an excellent job sewing this Albert apron."
+author: 20165
+designs: ["albert"]
+---
+
+Saber.007's son did an excellent job sewing this Albert apron!
+
diff --git a/markdown/org/showcase/an-aaron-undershirt-by-lasermonkey12/en.md b/markdown/org/showcase/an-aaron-undershirt-by-lasermonkey12/en.md
new file mode 100644
index 00000000000..e5dcd56dc74
--- /dev/null
+++ b/markdown/org/showcase/an-aaron-undershirt-by-lasermonkey12/en.md
@@ -0,0 +1,15 @@
+---
+title: "An Aaron undershirt by lasermonkey12"
+caption: "Love the fun fabric"
+date: 20240501
+intro: "The maker raised the arm holes on this Aaron A-shirt."
+author: 31287
+designs: ["aaron"]
+---
+
+The maker raised the arm holes on this Aaron A-shirt. She shared:
+
+"I've been making Aarons! I want to use them as undershirts so I've pulled the armholes up very high (-12% if I remember right, for sweat catching reasons) and I need to bring the neckline down so that it'll still be below any buttons I like to leave undone. This one is great for today's gym trip though!"
+
+Great result!
+
diff --git a/markdown/org/showcase/bella-block/en.md b/markdown/org/showcase/bella-block/en.md
index 9cd14743e0f..920e4bd8ca9 100644
--- a/markdown/org/showcase/bella-block/en.md
+++ b/markdown/org/showcase/bella-block/en.md
@@ -5,6 +5,7 @@ date: "2021-01-21"
intro: "Bella bodice block"
title: "Bella bodice block"
designs: ["bella"]
+author: 19867
---
diff --git a/markdown/org/showcase/bruces-by-paul/de.md b/markdown/org/showcase/bruces-by-paul/de.md
index 1d6919bcae9..9643c1d8505 100644
--- a/markdown/org/showcase/bruces-by-paul/de.md
+++ b/markdown/org/showcase/bruces-by-paul/de.md
@@ -6,6 +6,7 @@ intro: "Bruces von Paul"
title: "Bruces von Paul"
designs:
- "bruce"
+author: 433
---

diff --git a/markdown/org/showcase/bruces-by-paul/en.md b/markdown/org/showcase/bruces-by-paul/en.md
index aaf1c2e490a..4665fa9c178 100644
--- a/markdown/org/showcase/bruces-by-paul/en.md
+++ b/markdown/org/showcase/bruces-by-paul/en.md
@@ -5,6 +5,7 @@ date: "2018-12-19"
intro: "Bruces by Paul"
title: "Bruces by Paul"
designs: ["bruce"]
+author: 433
---

diff --git a/markdown/org/showcase/bruces-by-paul/es.md b/markdown/org/showcase/bruces-by-paul/es.md
index 9da46f8502f..4122697e1eb 100644
--- a/markdown/org/showcase/bruces-by-paul/es.md
+++ b/markdown/org/showcase/bruces-by-paul/es.md
@@ -6,6 +6,7 @@ intro: "Bruces por Paul"
title: "Bruces por Paul"
designs:
- "bruce"
+author: 433
---

diff --git a/markdown/org/showcase/bruces-by-paul/fr.md b/markdown/org/showcase/bruces-by-paul/fr.md
index f9b21ae9707..18bb6699bf0 100644
--- a/markdown/org/showcase/bruces-by-paul/fr.md
+++ b/markdown/org/showcase/bruces-by-paul/fr.md
@@ -6,6 +6,7 @@ intro: "Des Bruces faits par Paul"
title: "Des Bruces faits par Paul"
designs:
- "bruce"
+author: 433
---

diff --git a/markdown/org/showcase/bruces-by-paul/nl.md b/markdown/org/showcase/bruces-by-paul/nl.md
index 3c7dcb36605..66a501f8eab 100644
--- a/markdown/org/showcase/bruces-by-paul/nl.md
+++ b/markdown/org/showcase/bruces-by-paul/nl.md
@@ -6,6 +6,7 @@ intro: "Bruce door Paul"
title: "Bruce door Paul"
designs:
- "bruce"
+author: 433
---

diff --git a/markdown/org/showcase/bruces-by-paul/uk.md b/markdown/org/showcase/bruces-by-paul/uk.md
index 957892c381c..5938aafff2e 100644
--- a/markdown/org/showcase/bruces-by-paul/uk.md
+++ b/markdown/org/showcase/bruces-by-paul/uk.md
@@ -6,6 +6,7 @@ intro: "Брюки від Paul"
title: "Брюки від Paul"
designs:
- "Брюс."
+author: 433
---

diff --git a/markdown/org/showcase/carlton-coat/uk.md b/markdown/org/showcase/carlton-coat/uk.md
index 5baf930db5c..6663770398d 100644
--- a/markdown/org/showcase/carlton-coat/uk.md
+++ b/markdown/org/showcase/carlton-coat/uk.md
@@ -15,4 +15,4 @@ To specify it a little more - we simply made the sleeves more tight and also inc
More images you can find on google disc:
-https\://drive.google.com/drive/folders/1ERGkaSApfh9PgL4T4CBzmYI9Kd-Z0Pgf?usp=drive_link
+https://drive.google.com/drive/folders/1ERGkaSApfh9PgL4T4CBzmYI9Kd-Z0Pgf?usp=drive_link
diff --git a/markdown/org/showcase/flowery-hawaiian-simon/en.md b/markdown/org/showcase/flowery-hawaiian-simon/en.md
new file mode 100644
index 00000000000..2828cf7378c
--- /dev/null
+++ b/markdown/org/showcase/flowery-hawaiian-simon/en.md
@@ -0,0 +1,13 @@
+---
+title: "Flowery Hawaiian Simon"
+caption: "flowery hawaiian Simon"
+date: 20240430
+intro: "Simon made with a camp collar (almost a lapel) and short sleeves. Fabric is 100% cotton."
+author: 23364
+designs: ["simon"]
+---
+
+
+
+
+
diff --git a/markdown/org/showcase/green-cathrin/en.md b/markdown/org/showcase/green-cathrin/en.md
index 2406501d3b4..78ec216767e 100644
--- a/markdown/org/showcase/green-cathrin/en.md
+++ b/markdown/org/showcase/green-cathrin/en.md
@@ -5,6 +5,7 @@ date: "2021-10-19"
intro: "A green 11-panel Cathrin corset"
title: "A green 11-panel Cathrin corset"
designs: ["cathrin"]
+author: 19867
---

diff --git a/markdown/org/showcase/guin-gingham-simon/en.md b/markdown/org/showcase/guin-gingham-simon/en.md
index 9e6013b7eb5..98100355258 100644
--- a/markdown/org/showcase/guin-gingham-simon/en.md
+++ b/markdown/org/showcase/guin-gingham-simon/en.md
@@ -5,6 +5,7 @@ date: "2023-01-27"
intro: "Guin made this great modified Simon by giving it fun lantern sleeves in a contrasting color that definitely has nothing to do with running out of navy gingham. All's well that ends well, though - his shirt turned out awesome. Also loving the way the stripe matching turned out across the front."
title: "Guin's Gingham Lantern Simon"
designs: ["simon"]
+author: 27042
---
Guin made this great modified Simon by giving it fun lantern sleeves in a contrasting color that definitely has nothing to do with running out of navy gingham. All's well that ends well, though - his shirt turned out awesome. Also loving the way the stripe matching turned out across the front.
diff --git a/markdown/org/showcase/huey-by-paul/de.md b/markdown/org/showcase/huey-by-paul/de.md
index adb109dd7d4..be8cf256ac2 100644
--- a/markdown/org/showcase/huey-by-paul/de.md
+++ b/markdown/org/showcase/huey-by-paul/de.md
@@ -6,5 +6,6 @@ intro: "FIXME_no_intro"
title: "Huey von Paul"
designs:
- "huey"
+author: 433
---
diff --git a/markdown/org/showcase/huey-by-paul/en.md b/markdown/org/showcase/huey-by-paul/en.md
index cac26d43018..0e3862cdca3 100644
--- a/markdown/org/showcase/huey-by-paul/en.md
+++ b/markdown/org/showcase/huey-by-paul/en.md
@@ -5,6 +5,7 @@ date: "2018-09-29"
intro: "FIXME_no_intro"
title: "Huey by Paul"
designs: ["huey"]
+author: 433
---
diff --git a/markdown/org/showcase/huey-by-paul/es.md b/markdown/org/showcase/huey-by-paul/es.md
index abae5b4ee6b..18ff4fae63d 100644
--- a/markdown/org/showcase/huey-by-paul/es.md
+++ b/markdown/org/showcase/huey-by-paul/es.md
@@ -6,5 +6,6 @@ intro: "FIXME_no_intro"
title: "Huey por Paul"
designs:
- "huey"
+author: 433
---
diff --git a/markdown/org/showcase/huey-by-paul/fr.md b/markdown/org/showcase/huey-by-paul/fr.md
index c0983545a58..753b08a89b4 100644
--- a/markdown/org/showcase/huey-by-paul/fr.md
+++ b/markdown/org/showcase/huey-by-paul/fr.md
@@ -6,5 +6,6 @@ intro: "FIXME_no_intro"
title: "Huey par Paul"
designs:
- "huey"
+author: 433
---
diff --git a/markdown/org/showcase/huey-by-paul/nl.md b/markdown/org/showcase/huey-by-paul/nl.md
index dce6ff9c4d9..5589f6b49e1 100644
--- a/markdown/org/showcase/huey-by-paul/nl.md
+++ b/markdown/org/showcase/huey-by-paul/nl.md
@@ -6,5 +6,6 @@ intro: "FIXME_geen_intro"
title: "Huey door Paul"
designs:
- "huey"
+author: 433
---
diff --git a/markdown/org/showcase/huey-by-paul/uk.md b/markdown/org/showcase/huey-by-paul/uk.md
index 9f150b768b1..4566a04b56c 100644
--- a/markdown/org/showcase/huey-by-paul/uk.md
+++ b/markdown/org/showcase/huey-by-paul/uk.md
@@ -6,5 +6,6 @@ intro: "FIXME_no_intro"
title: "Huey by Paul"
designs:
- "Х'юї."
+author: 433
---
diff --git a/markdown/org/showcase/lasermonkeys-modded-bruces/en.md b/markdown/org/showcase/lasermonkeys-modded-bruces/en.md
new file mode 100644
index 00000000000..ea72e9d47fc
--- /dev/null
+++ b/markdown/org/showcase/lasermonkeys-modded-bruces/en.md
@@ -0,0 +1,29 @@
+---
+title: "Lasermonkey's modded Bruces"
+caption: "This is the pair that kicked off "the underwear thing""
+date: 20240429
+intro: "The FreeSewing community on Discord has enjoyed following along the journey of these Bruce modifications."
+author: 31287
+designs: ["bruce"]
+---
+
+The FreeSewing community on Discord has enjoyed following along the journey of these Bruce modifications. Lasermonkey12 graciously shared her highly modified pattern pieces which are shown below.
+
+
+
+
+
+But wait, there's more!
+
+This shows how she added additional crutch gusset part that allows me to easily put in pads even though the legs are super long. Clever!
+
+
+
+Bonus showcase! Here's an even further modified version with front+inset and side+back merged. Only 3 pieces and 4 seams.
+
+
+
+
+
+Equipped with this knowledge, we hope you'll go out and make a bunch of versions for yourself. Awesome undies for all.
+
diff --git a/markdown/org/showcase/linnen-jaeger-by-paul/de.md b/markdown/org/showcase/linnen-jaeger-by-paul/de.md
index efc62990318..861dfee9352 100644
--- a/markdown/org/showcase/linnen-jaeger-by-paul/de.md
+++ b/markdown/org/showcase/linnen-jaeger-by-paul/de.md
@@ -6,5 +6,6 @@ intro: "FIXME_no_intro"
title: "Jaeger by Paul"
designs:
- "jaeger"
+author: 433
---
diff --git a/markdown/org/showcase/linnen-jaeger-by-paul/en.md b/markdown/org/showcase/linnen-jaeger-by-paul/en.md
index aa424c56370..01a23f91956 100644
--- a/markdown/org/showcase/linnen-jaeger-by-paul/en.md
+++ b/markdown/org/showcase/linnen-jaeger-by-paul/en.md
@@ -5,6 +5,7 @@ date: "2018-09-29"
intro: "FIXME_no_intro"
title: "Jaeger by Paul"
designs: ["jaeger"]
+author: 433
---
diff --git a/markdown/org/showcase/linnen-jaeger-by-paul/es.md b/markdown/org/showcase/linnen-jaeger-by-paul/es.md
index ce13f1a0c6d..67172174f0f 100644
--- a/markdown/org/showcase/linnen-jaeger-by-paul/es.md
+++ b/markdown/org/showcase/linnen-jaeger-by-paul/es.md
@@ -6,5 +6,6 @@ intro: "FIXME_no_intro"
title: "Jaeger de Paul"
designs:
- "jaeger"
+author: 433
---
diff --git a/markdown/org/showcase/linnen-jaeger-by-paul/fr.md b/markdown/org/showcase/linnen-jaeger-by-paul/fr.md
index 2a95a6e916e..1d9dcd26882 100644
--- a/markdown/org/showcase/linnen-jaeger-by-paul/fr.md
+++ b/markdown/org/showcase/linnen-jaeger-by-paul/fr.md
@@ -6,5 +6,6 @@ intro: "FIXME_no_intro"
title: "Jaeger par Paul"
designs:
- "jaeger"
+author: 433
---
diff --git a/markdown/org/showcase/linnen-jaeger-by-paul/nl.md b/markdown/org/showcase/linnen-jaeger-by-paul/nl.md
index 296422606c6..1d8d7c0daf9 100644
--- a/markdown/org/showcase/linnen-jaeger-by-paul/nl.md
+++ b/markdown/org/showcase/linnen-jaeger-by-paul/nl.md
@@ -6,5 +6,6 @@ intro: "FIXME_geen_intro"
title: "Jaeger door Paul"
designs:
- "jaeger"
+author: 433
---
diff --git a/markdown/org/showcase/linnen-jaeger-by-paul/uk.md b/markdown/org/showcase/linnen-jaeger-by-paul/uk.md
index cc3945afb16..52f83045287 100644
--- a/markdown/org/showcase/linnen-jaeger-by-paul/uk.md
+++ b/markdown/org/showcase/linnen-jaeger-by-paul/uk.md
@@ -6,5 +6,6 @@ intro: "FIXME_no_intro"
title: "Jaeger by Paul"
designs:
- "Єгер."
+author: 433
---
diff --git a/markdown/org/showcase/lower-rise-ursula/en.md b/markdown/org/showcase/lower-rise-ursula/en.md
index 68c9b6c3530..7b9ad3d4c74 100644
--- a/markdown/org/showcase/lower-rise-ursula/en.md
+++ b/markdown/org/showcase/lower-rise-ursula/en.md
@@ -5,6 +5,7 @@ date: "2021-09-16"
intro: "This Ursula was made made in a cotton spandex knit (94% Cotton, 6% Spandex) with burgundy picot elastic."
title: "Lower rise Ursula"
designs: ["ursula"]
+author: 19867
---
This Ursula was made made in a cotton spandex knit (94% Cotton, 6% Spandex) with burgundy picot elastic.
diff --git a/markdown/org/showcase/mini-shin-swim-trunks/en.md b/markdown/org/showcase/mini-shin-swim-trunks/en.md
index d4b2990124d..4deeb1d6a46 100644
--- a/markdown/org/showcase/mini-shin-swim-trunks/en.md
+++ b/markdown/org/showcase/mini-shin-swim-trunks/en.md
@@ -5,6 +5,7 @@ date: "2022-06-27"
intro: "The making of these mini Shins was photographed to help draw illustrations for the instructions. While those are under construction -- or if you prefer photographs to drawings -- the entire series of photos can be viewed on Discord ."
title: "Mini Shin swim trunks"
designs: ["shin"]
+author: 19867
---
The making of these mini Shins was photographed to help draw illustrations for the instructions. While those are under construction -- or if you prefer photographs to drawings -- the entire series of photos can be [viewed on Discord](https://discord.com/channels/698854858052075530/787402509543145532/973065355763253289).
diff --git a/markdown/org/showcase/modified-tamiko-nursing-cover/en.md b/markdown/org/showcase/modified-tamiko-nursing-cover/en.md
index 591b465a381..254852231e3 100644
--- a/markdown/org/showcase/modified-tamiko-nursing-cover/en.md
+++ b/markdown/org/showcase/modified-tamiko-nursing-cover/en.md
@@ -5,6 +5,7 @@ date: "2022-06-12"
intro: "The maker shared:"
title: "Modified Tamiko as a nursing cover"
designs: ["tamiko"]
+author: 19867
---
The maker shared:
diff --git a/markdown/org/showcase/my-fisrt-sewing-project/de.md b/markdown/org/showcase/my-fisrt-sewing-project/de.md
new file mode 100644
index 00000000000..556d7137f5d
--- /dev/null
+++ b/markdown/org/showcase/my-fisrt-sewing-project/de.md
@@ -0,0 +1,11 @@
+---
+title: My fisrt sewing project!
+caption: 25/03/2024
+date: 20240325
+intro: idk what to put here.
+author: 73391
+designs:
+ - shelly
+---
+
+????
diff --git a/markdown/org/showcase/my-fisrt-sewing-project/en.md b/markdown/org/showcase/my-fisrt-sewing-project/en.md
new file mode 100644
index 00000000000..a4d460dee2b
--- /dev/null
+++ b/markdown/org/showcase/my-fisrt-sewing-project/en.md
@@ -0,0 +1,11 @@
+---
+title: "My fisrt sewing project!"
+caption: "25/03/2024"
+date: 20240325
+intro: "idk what to put here."
+author: 73391
+designs: ["shelly"]
+---
+
+????
+
diff --git a/markdown/org/showcase/my-fisrt-sewing-project/es.md b/markdown/org/showcase/my-fisrt-sewing-project/es.md
new file mode 100644
index 00000000000..556d7137f5d
--- /dev/null
+++ b/markdown/org/showcase/my-fisrt-sewing-project/es.md
@@ -0,0 +1,11 @@
+---
+title: My fisrt sewing project!
+caption: 25/03/2024
+date: 20240325
+intro: idk what to put here.
+author: 73391
+designs:
+ - shelly
+---
+
+????
diff --git a/markdown/org/showcase/my-fisrt-sewing-project/fr.md b/markdown/org/showcase/my-fisrt-sewing-project/fr.md
new file mode 100644
index 00000000000..474addc1c95
--- /dev/null
+++ b/markdown/org/showcase/my-fisrt-sewing-project/fr.md
@@ -0,0 +1,11 @@
+---
+title: Mon premier projet de couture !
+caption: 25/03/2024
+date: 20240325
+intro: je ne sais pas quoi mettre ici.
+author: 73391
+designs:
+ - shelly
+---
+
+????
diff --git a/markdown/org/showcase/my-fisrt-sewing-project/nl.md b/markdown/org/showcase/my-fisrt-sewing-project/nl.md
new file mode 100644
index 00000000000..556d7137f5d
--- /dev/null
+++ b/markdown/org/showcase/my-fisrt-sewing-project/nl.md
@@ -0,0 +1,11 @@
+---
+title: My fisrt sewing project!
+caption: 25/03/2024
+date: 20240325
+intro: idk what to put here.
+author: 73391
+designs:
+ - shelly
+---
+
+????
diff --git a/markdown/org/showcase/my-fisrt-sewing-project/uk.md b/markdown/org/showcase/my-fisrt-sewing-project/uk.md
new file mode 100644
index 00000000000..1400ccc040b
--- /dev/null
+++ b/markdown/org/showcase/my-fisrt-sewing-project/uk.md
@@ -0,0 +1,11 @@
+---
+title: My fisrt sewing project!
+caption: 25/03/2024
+date: 20240325
+intro: idk what to put here.
+author: 73391
+designs:
+ - шеллі
+---
+
+????
diff --git a/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/de.md b/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/de.md
index 01dd599f1d9..281703c54b8 100644
--- a/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/de.md
+++ b/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/de.md
@@ -8,6 +8,7 @@ designs:
- "florent"
- "theo"
- "wahid"
+author: 433
---

diff --git a/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/en.md b/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/en.md
index ba8fad9f2ef..47d0a50726d 100644
--- a/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/en.md
+++ b/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/en.md
@@ -5,6 +5,7 @@ date: "2018-01-02"
intro: "Outfit - Florent, Theodore & Wahid by Paul"
title: "Outfit - Florent, Theodore & Wahid by Paul"
designs: ["florent","theo","wahid"]
+author: 433
---

diff --git a/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/es.md b/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/es.md
index ad99ec268ba..fff9376b837 100644
--- a/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/es.md
+++ b/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/es.md
@@ -8,6 +8,7 @@ designs:
- "florent"
- "theo"
- "wahid"
+author: 433
---

diff --git a/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/fr.md b/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/fr.md
index 571c1a309b3..65cdee702e1 100644
--- a/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/fr.md
+++ b/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/fr.md
@@ -8,6 +8,7 @@ designs:
- "florent"
- "theo"
- "wahid"
+author: 433
---

diff --git a/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/nl.md b/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/nl.md
index 3678130adf3..da1791ccab5 100644
--- a/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/nl.md
+++ b/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/nl.md
@@ -8,6 +8,7 @@ designs:
- "florent"
- "theo"
- "wahid"
+author: 433
---

diff --git a/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/uk.md b/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/uk.md
index 6f335cc6399..bd72a4d451d 100644
--- a/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/uk.md
+++ b/markdown/org/showcase/outfit-wahid-theo-florent-by-paul/uk.md
@@ -8,6 +8,7 @@ designs:
- "флорентійський"
- "Тео."
- "вахід"
+author: 433
---

diff --git a/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/de.md b/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/de.md
index 422868efbc2..ca364871080 100644
--- a/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/de.md
+++ b/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/de.md
@@ -8,6 +8,7 @@ designs:
- "simon"
- "wahid"
- "theo"
+author: 433
---

diff --git a/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/en.md b/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/en.md
index 5153ec7f54a..3a5151b3e7c 100644
--- a/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/en.md
+++ b/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/en.md
@@ -5,6 +5,7 @@ date: "2018-01-02"
intro: "Outfit - Simon, Theo & Wahid by Paul"
title: "Outfit - Simon, Theo & Wahid by Paul"
designs: ["simon","wahid","theo"]
+author: 433
---

diff --git a/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/es.md b/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/es.md
index abf18c13c44..f18c9c8de46 100644
--- a/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/es.md
+++ b/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/es.md
@@ -8,6 +8,7 @@ designs:
- "simon"
- "wahid"
- "theo"
+author: 433
---

diff --git a/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/fr.md b/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/fr.md
index 6b4c4511a95..13817337bf2 100644
--- a/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/fr.md
+++ b/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/fr.md
@@ -8,6 +8,7 @@ designs:
- "simon"
- "wahid"
- "theo"
+author: 433
---

diff --git a/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/nl.md b/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/nl.md
index 918aeb4c396..928a09191a5 100644
--- a/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/nl.md
+++ b/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/nl.md
@@ -8,6 +8,7 @@ designs:
- "simon"
- "wahid"
- "theo"
+author: 433
---

diff --git a/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/uk.md b/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/uk.md
index 78854daba98..08f5e4bfb27 100644
--- a/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/uk.md
+++ b/markdown/org/showcase/outfit-wahid-theo-simon-by-paul/uk.md
@@ -8,6 +8,7 @@ designs:
- "Саймон"
- "вахід"
- "Тео."
+author: 433
---

diff --git a/markdown/org/showcase/ramoth-cathrin-corset/de.md b/markdown/org/showcase/ramoth-cathrin-corset/de.md
index 379bb3fa0c9..18f884695b3 100644
--- a/markdown/org/showcase/ramoth-cathrin-corset/de.md
+++ b/markdown/org/showcase/ramoth-cathrin-corset/de.md
@@ -1,5 +1,5 @@
---
-maker: "Ramoth"
+author: 23386
caption: "Ramoth Cathrin Korsett ...mit Schmetterlingen!"
date: "2023-01-31"
intro: "Hier ist ein fantastisches Schmetterlings-Cathrin-Korsett von Ramoth - ihr allererstes! Sie teilten dies über zukünftige Änderungen mit:"
diff --git a/markdown/org/showcase/ramoth-cathrin-corset/es.md b/markdown/org/showcase/ramoth-cathrin-corset/es.md
index b049640fd74..9e8bbb98b6e 100644
--- a/markdown/org/showcase/ramoth-cathrin-corset/es.md
+++ b/markdown/org/showcase/ramoth-cathrin-corset/es.md
@@ -1,5 +1,5 @@
---
-maker: "Ramoth"
+author: 23386
caption: "Corsé Ramoth Cathrin ...¡con mariposas!"
date: "2023-01-31"
intro: "Aquí tienes un fantástico corsé Cathrin mariposa fabricado por Ramoth, ¡el primero! Compartieron esto sobre futuras alteraciones:"
diff --git a/markdown/org/showcase/ramoth-cathrin-corset/fr.md b/markdown/org/showcase/ramoth-cathrin-corset/fr.md
index 52f8916b858..145c679e136 100644
--- a/markdown/org/showcase/ramoth-cathrin-corset/fr.md
+++ b/markdown/org/showcase/ramoth-cathrin-corset/fr.md
@@ -1,5 +1,5 @@
---
-maker: "Ramoth"
+author: 23386
caption: "Corset Ramoth Cathrin ...avec des papillons !"
date: "2023-01-31"
intro: "Voici un fantastique corset Cathrin en forme de papillon fabriqué par Ramoth - leur tout premier ! Ils ont partagé ceci à propos des futures modifications :"
diff --git a/markdown/org/showcase/ramoth-cathrin-corset/nl.md b/markdown/org/showcase/ramoth-cathrin-corset/nl.md
index 19e8f08dac6..acc5a0dfb30 100644
--- a/markdown/org/showcase/ramoth-cathrin-corset/nl.md
+++ b/markdown/org/showcase/ramoth-cathrin-corset/nl.md
@@ -1,5 +1,5 @@
---
-maker: "Ramoth"
+author: 23386
caption: "Ramoth Cathrin Corset ...met vlinders!"
date: "2023-01-31"
intro: "Hier is een fantastisch vlinderkorset van Cathrin gemaakt door Ramoth - hun allereerste! Dit deelden ze over toekomstige aanpassingen:"
diff --git a/markdown/org/showcase/ramoth-cathrin-corset/uk.md b/markdown/org/showcase/ramoth-cathrin-corset/uk.md
index d4e709fd2eb..c94990b9ae2 100644
--- a/markdown/org/showcase/ramoth-cathrin-corset/uk.md
+++ b/markdown/org/showcase/ramoth-cathrin-corset/uk.md
@@ -1,5 +1,5 @@
---
-maker: "Рамот"
+author: 23386
caption: "Корсет Ramoth Cathrin ... з метеликами!"
date: "2023-01-31"
intro: "Ось фантастичний корсет-метелик Cathrin від Ramoth - їхній найперший! Вони розповіли про майбутні зміни:"
diff --git a/markdown/org/showcase/ramoth-short-sleeve-simon/de.md b/markdown/org/showcase/ramoth-short-sleeve-simon/de.md
index 92b69f72fb1..52b7e6bc302 100644
--- a/markdown/org/showcase/ramoth-short-sleeve-simon/de.md
+++ b/markdown/org/showcase/ramoth-short-sleeve-simon/de.md
@@ -1,5 +1,5 @@
---
-maker: "Ramoth"
+author: 23386
caption: "Der kurzärmelige Simon von Ramoth, bei dem der Großteil der Formgebung in die hinteren Abnäher verlagert wurde"
date: "30.09.2021"
intro: "Das kurzärmelige Simon-Shirt von Ramoth"
diff --git a/markdown/org/showcase/ramoth-short-sleeve-simon/es.md b/markdown/org/showcase/ramoth-short-sleeve-simon/es.md
index 085c824dc81..3ef74f13b1f 100644
--- a/markdown/org/showcase/ramoth-short-sleeve-simon/es.md
+++ b/markdown/org/showcase/ramoth-short-sleeve-simon/es.md
@@ -1,5 +1,5 @@
---
-maker: "Ramoth"
+author: 23386
caption: "Simón de manga corta de Ramoth con la mayor parte de la forma desplazada a las pinzas de la espalda"
date: "2021-09-30"
intro: "Camiseta de manga corta Simon de Ramoth"
diff --git a/markdown/org/showcase/ramoth-short-sleeve-simon/fr.md b/markdown/org/showcase/ramoth-short-sleeve-simon/fr.md
index e175532fd06..661d3f79b7b 100644
--- a/markdown/org/showcase/ramoth-short-sleeve-simon/fr.md
+++ b/markdown/org/showcase/ramoth-short-sleeve-simon/fr.md
@@ -1,5 +1,5 @@
---
-maker: "Ramoth"
+author: 23386
caption: "Simon à manches courtes de Ramoth, dont la plupart des formes ont été déplacées vers les pinces du dos."
date: "30-09-2021"
intro: "La chemise Simon à manches courtes de Ramoth"
diff --git a/markdown/org/showcase/ramoth-short-sleeve-simon/nl.md b/markdown/org/showcase/ramoth-short-sleeve-simon/nl.md
index d8d1fa04268..c82be2619ae 100644
--- a/markdown/org/showcase/ramoth-short-sleeve-simon/nl.md
+++ b/markdown/org/showcase/ramoth-short-sleeve-simon/nl.md
@@ -1,5 +1,5 @@
---
-maker: "Ramoth"
+author: 23386
caption: "Ramoths Simon met korte mouwen, waarbij de meeste vorm is verplaatst naar de figuurnaden op de rug"
date: "2021-09-30"
intro: "Simon overhemd met korte mouwen van Ramoth"
diff --git a/markdown/org/showcase/ramoth-short-sleeve-simon/uk.md b/markdown/org/showcase/ramoth-short-sleeve-simon/uk.md
index 04385bddd9a..a9dd3783b48 100644
--- a/markdown/org/showcase/ramoth-short-sleeve-simon/uk.md
+++ b/markdown/org/showcase/ramoth-short-sleeve-simon/uk.md
@@ -1,5 +1,5 @@
---
-maker: "Рамот"
+author: 23386
caption: "Симон з коротким рукавом від Ramoth з більшою частиною форми, зміщеною на задні виточки"
date: "2021-09-30"
intro: "Сорочка Рамота з коротким рукавом Simon"
diff --git a/markdown/org/showcase/ramoth-simon-flannel/de.md b/markdown/org/showcase/ramoth-simon-flannel/de.md
index dd24b87cbb3..f7ab67b0763 100644
--- a/markdown/org/showcase/ramoth-simon-flannel/de.md
+++ b/markdown/org/showcase/ramoth-simon-flannel/de.md
@@ -1,5 +1,5 @@
---
-maker: "Ramoth"
+author: 23386
caption: "Ich liebe die Motten auf diesem schönen Simon-Flanell"
date: "2023-02-03"
intro: "Ramoths Simon Flanell"
diff --git a/markdown/org/showcase/ramoth-simon-flannel/es.md b/markdown/org/showcase/ramoth-simon-flannel/es.md
index 6b99d8b0e30..138034d5486 100644
--- a/markdown/org/showcase/ramoth-simon-flannel/es.md
+++ b/markdown/org/showcase/ramoth-simon-flannel/es.md
@@ -1,5 +1,5 @@
---
-maker: "Ramoth"
+author: 23386
caption: "Me encantan las polillas de esta preciosa franela Simon"
date: "2023-02-03"
intro: "Franela Simon de Ramoth"
diff --git a/markdown/org/showcase/ramoth-simon-flannel/fr.md b/markdown/org/showcase/ramoth-simon-flannel/fr.md
index c4583f64fa8..0bfca7ce881 100644
--- a/markdown/org/showcase/ramoth-simon-flannel/fr.md
+++ b/markdown/org/showcase/ramoth-simon-flannel/fr.md
@@ -1,5 +1,5 @@
---
-maker: "Ramoth"
+author: 23386
caption: "J'adore les papillons de nuit sur cette magnifique flanelle Simon."
date: "2023-02-03"
intro: "La flanelle Simon de Ramoth"
diff --git a/markdown/org/showcase/ramoth-simon-flannel/nl.md b/markdown/org/showcase/ramoth-simon-flannel/nl.md
index 264ebeb47e1..350376fc333 100644
--- a/markdown/org/showcase/ramoth-simon-flannel/nl.md
+++ b/markdown/org/showcase/ramoth-simon-flannel/nl.md
@@ -1,5 +1,5 @@
---
-maker: "Ramoth"
+author: 23386
caption: "Prachtige motten op deze mooie Simon flanel"
date: "2023-02-03"
intro: "Ramoth's Simon Flanel"
diff --git a/markdown/org/showcase/ramoth-simon-flannel/uk.md b/markdown/org/showcase/ramoth-simon-flannel/uk.md
index 5df37442da3..eff36ee5892 100644
--- a/markdown/org/showcase/ramoth-simon-flannel/uk.md
+++ b/markdown/org/showcase/ramoth-simon-flannel/uk.md
@@ -1,5 +1,5 @@
---
-maker: "Рамот"
+author: 23386
caption: "Любіть метеликів на цій прекрасній фланелі Simon"
date: "2023-02-03"
intro: "Simon Flannel від Ramoth"
diff --git a/markdown/org/showcase/short-sleeve-short-leg-onyx-swimsuit/uk.md b/markdown/org/showcase/short-sleeve-short-leg-onyx-swimsuit/uk.md
index 0d586dd9247..139875885de 100644
--- a/markdown/org/showcase/short-sleeve-short-leg-onyx-swimsuit/uk.md
+++ b/markdown/org/showcase/short-sleeve-short-leg-onyx-swimsuit/uk.md
@@ -13,4 +13,4 @@ An Onyx one-piece swimsuit/unisuit made with short sleeves and short legs. It's
It uses 80% nylon / 20% spandex mid-weight swim fabric for the fashion layer, and 80% polyester / 20% spandex heavyweight swim fabric for the lining layer.
-Made with a front zipper, a neckband, \~30% leg and sleeve length, \~-20% ease for chest, waist, hips, upper legs, \~-10% sleeve ease, \~-10% center seam ease. The seams are made with a serger/overlocker. The hems are single-fold and made with a double-needle using a triple stretch stitch. The zipper is a 12" long, #5 gauge molded plastic zipper.
+Made with a front zipper, a neckband, ~30% leg and sleeve length, ~-20% ease for chest, waist, hips, upper legs, ~-10% sleeve ease, ~-10% center seam ease. The seams are made with a serger/overlocker. The hems are single-fold and made with a double-needle using a triple stretch stitch. The zipper is a 12" long, #5 gauge molded plastic zipper.
diff --git a/markdown/org/showcase/shorts/de.md b/markdown/org/showcase/shorts/de.md
index 222a3d9ecca..f0790343e47 100644
--- a/markdown/org/showcase/shorts/de.md
+++ b/markdown/org/showcase/shorts/de.md
@@ -6,6 +6,7 @@ intro: "-"
designs:
- titan
maker: Galit
+author: 49445
---
-Shorts for my dauther
+Shorts for my daughter
diff --git a/markdown/org/showcase/shorts/en.md b/markdown/org/showcase/shorts/en.md
index 10e107187bd..a63f861adef 100644
--- a/markdown/org/showcase/shorts/en.md
+++ b/markdown/org/showcase/shorts/en.md
@@ -5,7 +5,8 @@ date: 20231118
intro: "-"
designs: ["titan"]
maker: Galit
+author: 49445
---
-Shorts for my dauther
+Shorts for my daughter
diff --git a/markdown/org/showcase/shorts/es.md b/markdown/org/showcase/shorts/es.md
index 8fe296c35a8..c3d454dc95f 100644
--- a/markdown/org/showcase/shorts/es.md
+++ b/markdown/org/showcase/shorts/es.md
@@ -6,6 +6,7 @@ intro: "-"
designs:
- titán
maker: Galit
+author: 49445
---
-Shorts for my dauther
+Shorts for my daughter
diff --git a/markdown/org/showcase/shorts/fr.md b/markdown/org/showcase/shorts/fr.md
index 222a3d9ecca..ed5e7928b0e 100644
--- a/markdown/org/showcase/shorts/fr.md
+++ b/markdown/org/showcase/shorts/fr.md
@@ -6,6 +6,7 @@ intro: "-"
designs:
- titan
maker: Galit
+author: 49445
---
-Shorts for my dauther
+Short pour ma fille
diff --git a/markdown/org/showcase/shorts/nl.md b/markdown/org/showcase/shorts/nl.md
index 9e98b319c73..55eb66f130d 100644
--- a/markdown/org/showcase/shorts/nl.md
+++ b/markdown/org/showcase/shorts/nl.md
@@ -6,6 +6,7 @@ intro: "-"
designs:
- titan
maker: Galit
+author: 49445
---
-Korte broek voor mijn dochter
+Shorts for my daughter
diff --git a/markdown/org/showcase/shorts/uk.md b/markdown/org/showcase/shorts/uk.md
index 064087d3107..983092bc87f 100644
--- a/markdown/org/showcase/shorts/uk.md
+++ b/markdown/org/showcase/shorts/uk.md
@@ -6,6 +6,7 @@ intro: "-"
designs:
- титан
maker: Galit
+author: 49445
---
-Shorts for my dauther
+Shorts for my daughter
diff --git a/markdown/org/showcase/simon-by-ramoth/de.md b/markdown/org/showcase/simon-by-ramoth/de.md
index b02aeb9bdd4..5a0e5b24336 100644
--- a/markdown/org/showcase/simon-by-ramoth/de.md
+++ b/markdown/org/showcase/simon-by-ramoth/de.md
@@ -1,5 +1,5 @@
---
-maker: "Ramoth"
+author: 23386
caption: "Ramoths beeindruckender erster Simon"
date: "24.08.2021"
intro: "Ramoth hat diesen fantastischen ersten Entwurf des Simon-Shirts gemacht und großzügig einige hilfreiche Passformhinweise geteilt. Sie sagten:"
diff --git a/markdown/org/showcase/simon-by-ramoth/es.md b/markdown/org/showcase/simon-by-ramoth/es.md
index 4d33abcf615..acfaa7b9c3a 100644
--- a/markdown/org/showcase/simon-by-ramoth/es.md
+++ b/markdown/org/showcase/simon-by-ramoth/es.md
@@ -1,5 +1,5 @@
---
-maker: "Ramoth"
+author: 23386
caption: "El impresionante primer Simon de Ramoth"
date: "2021-08-24"
intro: "Ramoth hizo este fantástico primer borrador de la camiseta Simon y compartió generosamente algunas notas útiles sobre el ajuste. Dijeron:"
diff --git a/markdown/org/showcase/simon-by-ramoth/fr.md b/markdown/org/showcase/simon-by-ramoth/fr.md
index 1f2ac0ac7d7..69d565b5464 100644
--- a/markdown/org/showcase/simon-by-ramoth/fr.md
+++ b/markdown/org/showcase/simon-by-ramoth/fr.md
@@ -1,5 +1,5 @@
---
-maker: "Ramoth"
+author: 23386
caption: "L'impressionnant premier Simon de Ramoth"
date: "2021-08-24"
intro: "Ramoth a réalisé cette fantastique première ébauche de la chemise Simon et a généreusement partagé quelques notes utiles sur la coupe. Ils ont dit :"
diff --git a/markdown/org/showcase/simon-by-ramoth/nl.md b/markdown/org/showcase/simon-by-ramoth/nl.md
index 60419565587..91aa1fb7b1f 100644
--- a/markdown/org/showcase/simon-by-ramoth/nl.md
+++ b/markdown/org/showcase/simon-by-ramoth/nl.md
@@ -1,5 +1,5 @@
---
-maker: "Ramoth"
+author: 23386
caption: "Ramoths indrukwekkende eerste Simon"
date: "2021-08-24"
intro: "Ramoth maakte dit fantastische eerste ontwerp van het Simon shirt en deelde genereus een aantal nuttige opmerkingen over de pasvorm. Ze zeiden:"
diff --git a/markdown/org/showcase/simon-by-ramoth/uk.md b/markdown/org/showcase/simon-by-ramoth/uk.md
index 499cc7c3c11..035f47a5fe6 100644
--- a/markdown/org/showcase/simon-by-ramoth/uk.md
+++ b/markdown/org/showcase/simon-by-ramoth/uk.md
@@ -1,5 +1,5 @@
---
-maker: "Рамот"
+author: 23386
caption: "Вражаючий перший \"Саймон\" Рамота"
date: "2021-08-24"
intro: "Рамот створила цей фантастичний перший ескіз сорочки для Саймона і щедро поділилася корисними порадами щодо підгонки. Вони сказали:"
diff --git a/markdown/org/showcase/trampoline-punk-a-punk-suit-made-from-a-trampoline-using-the-jaeger-jacket-and-charlie-chinos-patterns/en.md b/markdown/org/showcase/trampoline-punk-a-punk-suit-made-from-a-trampoline-using-the-jaeger-jacket-and-charlie-chinos-patterns/en.md
new file mode 100644
index 00000000000..e7018a7037d
--- /dev/null
+++ b/markdown/org/showcase/trampoline-punk-a-punk-suit-made-from-a-trampoline-using-the-jaeger-jacket-and-charlie-chinos-patterns/en.md
@@ -0,0 +1,12 @@
+---
+title: "Trampoline Punk: A Punk Suit Made from a Trampoline Using the Jaeger Jacket and Charlie Chinos Patterns"
+caption: "Jaeger Jacket and Charlie Chinos from the back, with a skull applique on the jacket"
+date: 20240412
+intro: |
+ Trampoline Punk attempts to answer the question "Can you sew a formal suit from a trampoline?" The answer: sort of, but you have to be willing to bleed for it.
+author: 65187
+designs: ["jaeger", "charlie"]
+---
+
+Trampoline Punk attempts to answer the question "Can you sew a formal suit from a trampoline?" The answer: sort of, but you have to be willing to bleed for it. The formal jacket and pants are sewn from the family's trampoline that was destroyed in a 2023 windstorm. The dress shirt and patchwork skull are sewn from the designer's 22-year-old wedding dress. The garment features punk detailing such as DIY patches, safety pin embellishments, and chains from the trampoline rigging. Don't try this at home unless you are willing to sacrifice several sewing machine needles, your favorite scissors, and most of the skin on your hands.
+
diff --git a/markdown/org/showcase/two-non-binary-hi/en.md b/markdown/org/showcase/two-non-binary-hi/en.md
new file mode 100644
index 00000000000..15e8fe6b64d
--- /dev/null
+++ b/markdown/org/showcase/two-non-binary-hi/en.md
@@ -0,0 +1,16 @@
+---
+title: "Two Non-binary Hi"
+caption: "Two Hi sharks, at 100% size done in non-binary flag stripes "
+date: 20240502
+intro: "This was my first Freesewing make, and I'm really pleased with how they came out!"
+author: 31916
+designs: ["hi"]
+---
+
+This was my first Freesewing make, and I'm really pleased with how they came out!
+They were presents for two friends and my first time sewing with this kind of fabric. It was 'cuddle fleece' with a one way stretch and fur a little bit longer than the original Blåhaj.
+
+As happy as I am with them, I did not enjoy sewing these. I printed my copy without seam allowance cause I come from a hand sewing background and that's what I'm used to, but it was definitely a mistake when using black fur since marking out the stitch lines was a nightmare when preparing the striped pieces. Fluffy fabric brings its own challenges and I could have made it a lot easier for myself.
+
+They came out as good as I had hoped and the pattern was really simple to follow (especially if you don't impose setbacks on yourself) and the recipients were overjoyed with their enbyhajs!
+
diff --git a/markdown/org/showcase/ursula-test-pairs/en.md b/markdown/org/showcase/ursula-test-pairs/en.md
index bb5a3fb9349..358d5204626 100644
--- a/markdown/org/showcase/ursula-test-pairs/en.md
+++ b/markdown/org/showcase/ursula-test-pairs/en.md
@@ -5,6 +5,7 @@ date: "2021-06-26"
intro: "Ursula is a basic, highly-customizable undies pattern. Here are some of the early versions testing different combinations of options, which may be useful to you as you design your own pairs."
title: "Early tests of Ursula"
designs: ["ursula"]
+author: 19867
---
diff --git a/markdown/org/showcase/waralee-with-pocket-by-nael/en.md b/markdown/org/showcase/waralee-with-pocket-by-nael/en.md
new file mode 100644
index 00000000000..5586bea76a2
--- /dev/null
+++ b/markdown/org/showcase/waralee-with-pocket-by-nael/en.md
@@ -0,0 +1,17 @@
+---
+title: "Waralee with pocket, by Naël"
+caption: "These Waralees look so good on the recipient."
+date: 20240429
+intro: "We adore these Waralee wrap pants by Naël featuring a pocket on the belt and a cute FreeSewing label."
+author: 32412
+designs: ["waralee"]
+---
+
+We adore these Waralee wrap pants by Naël featuring a pocket on the belt and a cute FreeSewing label.
+
+
+
+
+
+
+
diff --git a/markdown/org/showcase/waralees-by-moderndragon-featuring-a-fancy-seam-finish/en.md b/markdown/org/showcase/waralees-by-moderndragon-featuring-a-fancy-seam-finish/en.md
new file mode 100644
index 00000000000..01949e70c15
--- /dev/null
+++ b/markdown/org/showcase/waralees-by-moderndragon-featuring-a-fancy-seam-finish/en.md
@@ -0,0 +1,19 @@
+---
+title: "Waralees by moderndragon, featuring a fancy seam finish"
+caption: "These Waralees were made of a old duvet cover that they dyed."
+date: 20240423
+intro: "This was moderndragon's very first Waralee wrap pants!"
+author: 22007
+designs: ["waralee"]
+---
+
+This was moderndragon's very first Waralee wrap pants!
+
+They also tried their hand at a fancy seam finish for the crotch seam. Which was a bit of a challenge, given that it's a really curved seam. But they think it was worth it.
+
+Can you believe they created this vibrant fabric by dyeing an old duvet cover?
+
+Lovely work!
+
+
+
diff --git a/markdown/org/showcase/wonderful-waralees-by-tuesday/de.md b/markdown/org/showcase/wonderful-waralees-by-tuesday/de.md
new file mode 100644
index 00000000000..72bb542de01
--- /dev/null
+++ b/markdown/org/showcase/wonderful-waralees-by-tuesday/de.md
@@ -0,0 +1,11 @@
+---
+title: Wonderful Waralees by Tuesday
+caption: What a great look!
+date: 20240418
+intro: FreeSewing maker Tuesday said these Waralee wrap pants are extremely comfortable.
+author: 22693
+designs:
+ - waralee
+---
+
+FreeSewing maker Tuesday said these Waralee wrap pants are extremely comfortable. We enjoyed following along with the adventure of creating them! Turned out just fab.
diff --git a/markdown/org/showcase/wonderful-waralees-by-tuesday/en.md b/markdown/org/showcase/wonderful-waralees-by-tuesday/en.md
new file mode 100644
index 00000000000..edb75486812
--- /dev/null
+++ b/markdown/org/showcase/wonderful-waralees-by-tuesday/en.md
@@ -0,0 +1,11 @@
+---
+title: "Wonderful Waralees by Tuesday"
+caption: "What a great look!"
+date: 20240418
+intro: "FreeSewing maker Tuesday said these Waralee wrap pants are extremely comfortable."
+author: 22693
+designs: ["waralee"]
+---
+
+FreeSewing maker Tuesday said these Waralee wrap pants are extremely comfortable. We enjoyed following along with the adventure of creating them! Turned out just fab.
+
diff --git a/markdown/org/showcase/wonderful-waralees-by-tuesday/es.md b/markdown/org/showcase/wonderful-waralees-by-tuesday/es.md
new file mode 100644
index 00000000000..72bb542de01
--- /dev/null
+++ b/markdown/org/showcase/wonderful-waralees-by-tuesday/es.md
@@ -0,0 +1,11 @@
+---
+title: Wonderful Waralees by Tuesday
+caption: What a great look!
+date: 20240418
+intro: FreeSewing maker Tuesday said these Waralee wrap pants are extremely comfortable.
+author: 22693
+designs:
+ - waralee
+---
+
+FreeSewing maker Tuesday said these Waralee wrap pants are extremely comfortable. We enjoyed following along with the adventure of creating them! Turned out just fab.
diff --git a/markdown/org/showcase/wonderful-waralees-by-tuesday/fr.md b/markdown/org/showcase/wonderful-waralees-by-tuesday/fr.md
new file mode 100644
index 00000000000..53a52c71756
--- /dev/null
+++ b/markdown/org/showcase/wonderful-waralees-by-tuesday/fr.md
@@ -0,0 +1,11 @@
+---
+title: Merveilleux Waralees par Tuesday
+caption: Quel beau look !
+date: 20240418
+intro: Le fabricant de FreeSewins Tuesday a déclaré que ce pantalon enveloppant Waralee est extrêmement confortable.
+author: 22693
+designs:
+ - waralee
+---
+
+Le fabricant de FreeSewins Tuesday a déclaré que ce pantalon enveloppant Waralee est extrêmement confortable. Nous avons aimé suivre l'aventure de leur création ! Le résultat est tout simplement fabuleux.
diff --git a/markdown/org/showcase/wonderful-waralees-by-tuesday/nl.md b/markdown/org/showcase/wonderful-waralees-by-tuesday/nl.md
new file mode 100644
index 00000000000..72bb542de01
--- /dev/null
+++ b/markdown/org/showcase/wonderful-waralees-by-tuesday/nl.md
@@ -0,0 +1,11 @@
+---
+title: Wonderful Waralees by Tuesday
+caption: What a great look!
+date: 20240418
+intro: FreeSewing maker Tuesday said these Waralee wrap pants are extremely comfortable.
+author: 22693
+designs:
+ - waralee
+---
+
+FreeSewing maker Tuesday said these Waralee wrap pants are extremely comfortable. We enjoyed following along with the adventure of creating them! Turned out just fab.
diff --git a/markdown/org/showcase/wonderful-waralees-by-tuesday/uk.md b/markdown/org/showcase/wonderful-waralees-by-tuesday/uk.md
new file mode 100644
index 00000000000..8df732115ad
--- /dev/null
+++ b/markdown/org/showcase/wonderful-waralees-by-tuesday/uk.md
@@ -0,0 +1,11 @@
+---
+title: Wonderful Waralees by Tuesday
+caption: What a great look!
+date: 20240418
+intro: FreeSewing maker Tuesday said these Waralee wrap pants are extremely comfortable.
+author: 22693
+designs:
+ - Waralee
+---
+
+FreeSewing maker Tuesday said these Waralee wrap pants are extremely comfortable. We enjoyed following along with the adventure of creating them! Turned out just fab.
diff --git a/markdown/org/showcase/yoga-set-by-paul/de.md b/markdown/org/showcase/yoga-set-by-paul/de.md
index d30fbe018d1..b930dfe8fb0 100644
--- a/markdown/org/showcase/yoga-set-by-paul/de.md
+++ b/markdown/org/showcase/yoga-set-by-paul/de.md
@@ -7,5 +7,6 @@ title: "Yoga Outfit von Paul"
designs:
- "aaron"
- "bruce"
+author: 433
---
diff --git a/markdown/org/showcase/yoga-set-by-paul/en.md b/markdown/org/showcase/yoga-set-by-paul/en.md
index 328ec37fe05..8ade6afb7b1 100644
--- a/markdown/org/showcase/yoga-set-by-paul/en.md
+++ b/markdown/org/showcase/yoga-set-by-paul/en.md
@@ -5,6 +5,7 @@ date: "2018-09-29"
intro: "FIXME_no_intro"
title: "Yoga Outfit by Paul"
designs: ["aaron","bruce"]
+author: 433
---
diff --git a/markdown/org/showcase/yoga-set-by-paul/es.md b/markdown/org/showcase/yoga-set-by-paul/es.md
index 0ec9315ae41..b1f6693439a 100644
--- a/markdown/org/showcase/yoga-set-by-paul/es.md
+++ b/markdown/org/showcase/yoga-set-by-paul/es.md
@@ -7,5 +7,6 @@ title: "Conjunto de yoga de Paul"
designs:
- "aaron"
- "bruce"
+author: 433
---
diff --git a/markdown/org/showcase/yoga-set-by-paul/fr.md b/markdown/org/showcase/yoga-set-by-paul/fr.md
index 67734e67951..227237d8057 100644
--- a/markdown/org/showcase/yoga-set-by-paul/fr.md
+++ b/markdown/org/showcase/yoga-set-by-paul/fr.md
@@ -7,5 +7,6 @@ title: "Tenue de yoga par Paul"
designs:
- "aaron"
- "bruce"
+author: 433
---
diff --git a/markdown/org/showcase/yoga-set-by-paul/nl.md b/markdown/org/showcase/yoga-set-by-paul/nl.md
index 647b78bc031..36ed073a346 100644
--- a/markdown/org/showcase/yoga-set-by-paul/nl.md
+++ b/markdown/org/showcase/yoga-set-by-paul/nl.md
@@ -7,5 +7,6 @@ title: "Yoga Outfit door Paul"
designs:
- "aaron"
- "bruce"
+author: 433
---
diff --git a/markdown/org/showcase/yoga-set-by-paul/uk.md b/markdown/org/showcase/yoga-set-by-paul/uk.md
index 47c86e3632e..c19c6df037a 100644
--- a/markdown/org/showcase/yoga-set-by-paul/uk.md
+++ b/markdown/org/showcase/yoga-set-by-paul/uk.md
@@ -7,5 +7,6 @@ title: "Екіпірування для йоги від Павла"
designs:
- "Аароне."
- "Брюс."
+author: 433
---
diff --git a/package.json b/package.json
index 9bdd7774ed8..8059cd55e90 100644
--- a/package.json
+++ b/package.json
@@ -72,7 +72,7 @@
"esbuild-plugin-yaml": "^0.0.1",
"eslint": "^8.23.1",
"eslint-plugin-jsonc": "^2.4.0",
- "eslint-plugin-markdown": "^4.0.1",
+ "eslint-plugin-markdown": "^5.0.0",
"eslint-plugin-mongo": "^1.0.5",
"eslint-plugin-yaml": "^0.5.0",
"husky": "^9.0.10",
diff --git a/packages/core/README.md b/packages/core/README.md
index 71b5ae9c6d1..1078c24b572 100644
--- a/packages/core/README.md
+++ b/packages/core/README.md
@@ -21,7 +21,7 @@
{
expect(round(bbox.bottomRight.x)).to.equal(119.86)
expect(round(bbox.bottomRight.y)).to.equal(43.49)
})
+
+ it('Should offset small curves', () => {
+ const curve = new Path()
+ .move(new Point(0, 0))
+ .curve(new Point(0.1, 0.1), new Point(0.2, 0.2), new Point(0.1, 1.1))
+ const offset = curve.offset(1)
+ const bbox = offset.bbox()
+ expect(round(bbox.bottomRight.x)).to.equal(-0.9)
+ expect(round(bbox.bottomRight.y)).to.equal(1.19)
+ })
+
+ it('Should offset zero length path', () => {
+ let logged = false
+ const log = { warn: () => (logged = true) }
+ const curve = new Path().__withLog(log).move(new Point(0, 0)).line(new Point(0, 0)).close()
+ expect(logged).to.equal(false)
+ const offset = curve.offset(1)
+ expect(logged).to.equal(true)
+ const bbox = offset.bbox()
+ expect(round(bbox.bottomRight.x)).to.equal(0)
+ expect(round(bbox.bottomRight.y)).to.equal(0)
+ })
})
describe('length', () => {
@@ -354,6 +376,15 @@ describe('Path', () => {
expect(box.bottomRight.y).to.equal(456)
})
+ it('Should find the bounding box of an empty path', () => {
+ const path = new Path().move(new Point(123, 456)).close()
+ const box = path.bbox()
+ expect(box.topLeft.x).to.equal(123)
+ expect(box.topLeft.y).to.equal(456)
+ expect(box.bottomRight.x).to.equal(123)
+ expect(box.bottomRight.y).to.equal(456)
+ })
+
it('Should reverse a path', () => {
const test = new Path()
.move(new Point(123, 456))
@@ -371,6 +402,20 @@ describe('Path', () => {
expect(rev.ops[2].type).to.equal('line')
})
+ it('Should rotate a path', () => {
+ const test = new Path()
+ .move(new Point(123, 456))
+ .line(new Point(12, 23))
+ .curve(new Point(0, 40), new Point(123, 34), new Point(230, 4))
+ .close()
+ let deg = 60
+ let rotationOrigin = new Point(42, 100)
+ let rotated = test.rotate(deg, rotationOrigin, true)
+ expect(test.length()).to.equal(rotated.length())
+ expect(test.ops[0].to.rotate(deg, rotationOrigin).x).to.equal(rotated.ops[0].to.x)
+ expect(test.ops[0].to.rotate(deg, rotationOrigin).y).to.equal(rotated.ops[0].to.y)
+ })
+
it('Should find the edges of a path', () => {
const test = new Path()
.move(new Point(45, 60))
@@ -635,6 +680,33 @@ describe('Path', () => {
expect(halves[1].ops[0].to.y).to.equal(30)
})
+ it('Should determine the angle on a path', () => {
+ const a = new Point(0, 0)
+ const b = new Point(0, 40)
+ const c = new Point(40, 40)
+ const d = new Point(100, 40)
+ const e = new Point(100, 0)
+
+ const linePoint = new Point(80, 40)
+ const curvePoint = new Point(5, 35)
+
+ const path = new Path().move(a).curve(b, b, c).line(d).line(e)
+
+ let angleAtStart = path.angleAt(a)
+ let angleOnCurve = path.angleAt(curvePoint)
+ let angleOnJoint = path.angleAt(c)
+ let angleOnLine = path.angleAt(linePoint)
+ let angleOnCorner = path.angleAt(d)
+ let angleOnEnd = path.angleAt(e)
+
+ expect(angleAtStart).to.equal(-90)
+ expect(angleOnCurve).to.equal(-45)
+ expect(angleOnJoint).to.equal(0)
+ expect(angleOnLine).to.equal(0)
+ expect(angleOnCorner).to.equal(0)
+ expect(angleOnEnd).to.equal(90)
+ })
+
it('Should trim a path when lines overlap', () => {
const A = new Point(0, 0)
const B = new Point(100, 100)
@@ -916,6 +988,21 @@ describe('Path', () => {
expect(invalid).to.equal(true)
})
+ it('Should log a warning when calling rotate with an origin that is not a point', () => {
+ let invalid = false
+ const log = { warn: () => (invalid = true) }
+ const test = new Path().__withLog(log).move(new Point(123, 456)).line(new Point(12, 23))
+
+ expect(invalid).to.equal(false)
+ let deg = 60
+ try {
+ test.rotate(deg, 'someOrigin')
+ } catch (err) {
+ expect('' + err).to.contain('Cannot read properties of')
+ }
+ expect(invalid).to.equal(true)
+ })
+
it('Should add a noop operation', () => {
const p1 = new Path().noop()
expect(p1.ops.length).to.equal(1)
diff --git a/packages/models/README.md b/packages/models/README.md
index aea0bc987e7..d35da3779ce 100644
--- a/packages/models/README.md
+++ b/packages/models/README.md
@@ -21,7 +21,7 @@
{
for (let sub of subscribers[lang]) {
if (l > 0) {
+ const unsubGet = `https://freesewing.org${
+ lang === 'en' ? '/' : '/' + lang + '/'
+ }newsletter/unsubscribe?x=${sub.ehash}`
+ const unsubPost = `https://backend3.freesewing.org/ocunsub/${sub.ehash}`
const body = mustache.render(template, {
...i18n[lang],
- unsubscribe: `https://freesewing.org${
- lang === 'en' ? '/' : '/' + lang + '/'
- }newsletter/unsubscribe?x=${sub.ehash}`,
+ unsubscribe: unsubGet,
content,
})
console.log(`[${lang}] ${l}/${subs} (${i}) Sending to ${sub.email}`)
@@ -141,6 +143,16 @@ const send = async (test = true) => {
Charset: 'utf-8',
Data: i18n[lang].title,
},
+ Headers: [
+ {
+ Name: 'List-Unsubscribe',
+ Value: unsubPost,
+ },
+ {
+ Name: 'List-Unsubscribe-Post',
+ Value: 'List-Unsubscribe=One-Click',
+ },
+ ],
},
},
Destination: {
diff --git a/sites/backend/package.json b/sites/backend/package.json
index d5402230213..5a662082ab2 100644
--- a/sites/backend/package.json
+++ b/sites/backend/package.json
@@ -29,11 +29,11 @@
"peerDependencies": {},
"dependencies": {
"@aws-sdk/client-sesv2": "3.535.0",
- "@prisma/client": "5.11.0",
+ "@prisma/client": "5.13.0",
"bcryptjs": "2.4.3",
"cors": "2.8.5",
"dotenv": "16.4.5",
- "express": "4.19.1",
+ "express": "4.19.2",
"js-yaml": "4.1.0",
"lodash.get": "4.4.2",
"mustache": "4.2.0",
@@ -41,16 +41,16 @@
"passport": "0.7.0",
"passport-http": "0.3.0",
"passport-jwt": "4.0.1",
- "pino": "8.19.0",
+ "pino": "9.0.0",
"qrcode": "1.5.3",
- "swagger-ui-dist": "5.12.0",
+ "swagger-ui-dist": "5.17.2",
"swagger-ui-express": "5.0.0"
},
"devDependencies": {
"chai": "5.1.0",
"chai-http": "4.4.0",
"esbuild": "0.20.2",
- "mocha": "10.3.0",
+ "mocha": "10.4.0",
"mocha-steps": "1.3.0",
"nodemon": "3.1.0",
"prisma": "5.11.0"
diff --git a/sites/backend/src/controllers/subscribers.mjs b/sites/backend/src/controllers/subscribers.mjs
index 827783180f1..88f2adf065b 100644
--- a/sites/backend/src/controllers/subscribers.mjs
+++ b/sites/backend/src/controllers/subscribers.mjs
@@ -1,4 +1,7 @@
import { SubscriberModel } from '../models/subscriber.mjs'
+// Catch-all page
+import { html as ocunsubOk } from '../html/ocunsub-ok.mjs'
+import { html as ocunsubKo } from '../html/ocunsub-ko.mjs'
export function SubscribersController() {}
@@ -47,12 +50,16 @@ SubscribersController.prototype.confirm = async (req, res, tools) => {
}
/*
- * Unsubscribe from the newsletter
+ * One-Click unsubscribe from the newsletter
* See: https://freesewing.dev/reference/backend/api
*/
-SubscribersController.unsubscribe = async (req, res, tools) => {
- const Subscriber = new SubscriberModel(tools)
- await Subscriber.unsubscribe(req)
+SubscribersController.prototype.ocunsub = async (req, res, tools) => {
+ if (!res.params?.ehash) return res.set('Content-Type', 'text/html').status(200).send(ocunsubKo)
- return Subscriber.sendResponse(res)
+ const Subscriber = new SubscriberModel(tools)
+ const result = await Subscriber.ocunsub(req)
+
+ if (result) return res.set('Content-Type', 'text/html').status(200).send(ocunsubOk)
+
+ return res.set('Content-Type', 'text/html').status(200).send(okunsubKo)
}
diff --git a/sites/backend/src/html/ocunsub-ko.mjs b/sites/backend/src/html/ocunsub-ko.mjs
new file mode 100644
index 00000000000..ac9b6932335
--- /dev/null
+++ b/sites/backend/src/html/ocunsub-ko.mjs
@@ -0,0 +1,9 @@
+import { wrapper } from './shared.mjs'
+
+export const html = wrapper({
+ content: `
+🫤 FNpe
+Whatever you intended to do, it did not work.
+Contact support
+`,
+})
diff --git a/sites/backend/src/html/ocunsub-ok.mjs b/sites/backend/src/html/ocunsub-ok.mjs
new file mode 100644
index 00000000000..160f0110fb7
--- /dev/null
+++ b/sites/backend/src/html/ocunsub-ok.mjs
@@ -0,0 +1,8 @@
+import { wrapper } from './shared.mjs'
+
+export const html = wrapper({
+ content: `
+👋 Farewell
+You have been unsubscribed.
+`,
+})
diff --git a/sites/backend/src/models/set.mjs b/sites/backend/src/models/set.mjs
index 4a75662ed2d..923f377493f 100644
--- a/sites/backend/src/models/set.mjs
+++ b/sites/backend/src/models/set.mjs
@@ -90,15 +90,25 @@ SetModel.prototype.guardedCreate = async function ({ body, user }) {
*/
SetModel.prototype.guardedRead = async function ({ params, user }) {
/*
- * Enforce RBAC
- */
- if (!this.rbac.readSome(user)) return this.setResponse(403, 'insufficientAccessLevel')
-
- /*
- * Attempt to read the record from the database
+ * If the set is public, we do not need to enforce RBAC
+ * So let's load it first
*/
await this.read({ id: parseInt(params.id) })
+ /*
+ * If it's public, return early
+ */
+ if (this.record?.public)
+ return this.setResponse(200, false, {
+ result: 'success',
+ set: this.asSet(),
+ })
+
+ /*
+ * If it's not public, enforce RBAC
+ */
+ if (!this.rbac.readSome(user)) return this.setResponse(403, 'insufficientAccessLevel')
+
/*
* If it does not exist, send a 404
*/
diff --git a/sites/backend/src/models/subscriber.mjs b/sites/backend/src/models/subscriber.mjs
index 458335508d6..4be6968f0eb 100644
--- a/sites/backend/src/models/subscriber.mjs
+++ b/sites/backend/src/models/subscriber.mjs
@@ -156,9 +156,9 @@ SubscriberModel.prototype.unsubscribe = async function ({ params }) {
return this.setResponse(204)
} else {
- /*
- * If not, perhaps it's an account ehash rather than subscriber ehash
- */
+ /*
+ * If not, perhaps it's an account ehash rather than subscriber ehash
+ */
await this.User.read({ ehash })
if (this.User.record) {
await this.User.update({ newsletter: false })
@@ -173,6 +173,43 @@ SubscriberModel.prototype.unsubscribe = async function ({ params }) {
return this.setResponse(404)
}
+/*
+ * One-click unsubscribe a user
+ * This is an unauthenticated route (has to for newsletter subscribers might not be users)
+ *
+ * @param {body} object - The request body
+ * @returns {SubscriberModal} object - The SubscriberModel
+ */
+SubscriberModel.prototype.ocunsub = async function ({ params }) {
+ const { ehash } = params
+
+ /*
+ * Find the subscription record
+ */
+ await this.read({ ehash })
+
+ /*
+ * If found, remove the record
+ */
+ if (this.record) {
+ await this.delete({ id: this.record.id })
+
+ return true
+ } else {
+ /*
+ * If not, perhaps it's an account ehash rather than subscriber ehash
+ */
+ await this.User.read({ ehash })
+ if (this.User.record) {
+ await this.User.update({ newsletter: false })
+
+ return true
+ }
+ }
+
+ return false
+}
+
/*
* A helper method to validate input and load the subscription record
*
diff --git a/sites/backend/src/routes/subscribers.mjs b/sites/backend/src/routes/subscribers.mjs
index 4381eb474f8..2950d36217b 100644
--- a/sites/backend/src/routes/subscribers.mjs
+++ b/sites/backend/src/routes/subscribers.mjs
@@ -17,4 +17,13 @@ export function subscribersRoutes(tools) {
// Unsubscribe from newsletter
app.delete('/subscriber/:ehash', (req, res) => Subscriber.unsubscribe(req, res, tools))
+
+ // One-Click unsubscribe (ocunsub) from newsletter needs to be a POST request.
+ // See https://datatracker.ietf.org/doc/html/rfc8058
+ app.post('/ocunsub/:ehash', (req, res) => Subscriber.ocunsub(req, res, tools))
+
+ // Just in case somebody lands here with a GET request
+ app.get('/ocunsub/:ehash', (req, res) =>
+ res.redirect(`https://freesewing.org/newsletter/unsubscribe?i=${req.params.ehash}`)
+ )
}
diff --git a/sites/dev/components/web-of-trust.mjs b/sites/dev/components/web-of-trust.mjs
new file mode 100644
index 00000000000..4139e74fab3
--- /dev/null
+++ b/sites/dev/components/web-of-trust.mjs
@@ -0,0 +1,9514 @@
+// Dependencies
+import { trustees, connections, lastUpdate } from 'config/trustees.mjs'
+import { shortDate } from 'shared/utils.mjs'
+// Hooks
+import { useState, useContext } from 'react'
+// Context
+import { ModalContext } from 'shared/context/modal-context.mjs'
+import { PanZoomContext } from 'shared/components/workbench/pattern/pan-zoom-context.mjs'
+// Components
+import { Point } from '@freesewing/core'
+import { ModalWrapper } from 'shared/components/wrappers/modal.mjs'
+import { WebLink, linkClasses } from 'shared/components/link.mjs'
+import { TransformWrapper, TransformComponent } from 'react-zoom-pan-pinch'
+import { UserIcon, MapMarkerIcon, LinkIcon } from 'shared/components/icons.mjs'
+
+/**
+ * This displays the trustees as a table
+ */
+export const WebOfTrustTable = () => {
+ const { setModal } = useContext(ModalContext)
+
+ return (
+
+
+
+ User
+ Location
+
+
+
+ {Object.keys(trustees).map((id) => (
+
+
+
+ setModal(
+
+
+
+ )
+ }
+ >
+ {trustees[id].title}
+
+
+ {trustees[id].in}
+
+ ))}
+
+
+ )
+}
+
+/**
+ * Helper method to draw a connection between two trustees on the map
+ *
+ * @param {object} from - An objectt with x and y coordinates
+ * @param {object} to - An objectt with x and y coordinates
+ * @return {string} pathString - The path string to draw the path
+ */
+const fromToPath = (from, to) => {
+ const p = {}
+ const angle = 35
+ const shift = 0.5
+ p.from = new Point(from.x, from.y)
+ p.to = new Point(to.x, to.y)
+ p.fromCp = p.from.shiftFractionTowards(p.to, shift).rotate(-1 * angle, p.from)
+ p.toCp = p.to.shiftFractionTowards(p.from, shift).rotate(angle, p.to)
+
+ return `M ${p.from.x},${p.from.y} C ${p.fromCp.x}, ${p.fromCp.y} ${p.toCp.x}, ${p.toCp.y} ${p.to.x}, ${p.to.y}`
+}
+
+/**
+ * This component shows the trustee details, typically loaded in a modal window
+ *
+ * @param {number} props.id - The id (FreeSewing user id) of the trustee
+ */
+const Details = ({ id }) => (
+ <>
+ Trustee Details
+
+
+ {trustees[id].title}
+
+
+ {trustees[id].in}
+
+
+
+
+ {`FreeSewing.org/users/user?id=${id}`}
+
+
+
+ >
+)
+
+/**
+ * This displays the trustees as a map
+ */
+export const WebOfTrustMap = () => {
+ const [fullMap, setFullMap] = useState(false)
+ const { setModal } = useContext(ModalContext)
+
+ const { onTransformed, setZoomFunctions } = useContext(PanZoomContext)
+
+ return (
+ <>
+
+
+
+ Last update:{' '}
+
+ {shortDate(
+ 'en',
+ new Date(
+ new Date(
+ lastUpdate.substr(0, 4),
+ lastUpdate.substr(4, 2) - 1,
+ lastUpdate.substr(6, 2)
+ )
+ ),
+ false
+ )}
+
+
+ setFullMap(!fullMap)}>
+ {fullMap ? 'Crop map' : 'Show full map'}
+
+
+ >
+ )
+}
+
+/* eslint-disable */
+/*
+ * React version of https://upload.wikimedia.org/wikipedia/commons/b/bc/BlankMap-World-Compact.svg
+ */
+const world = (
+ <>
+
+
+
+
+
+
+
+ Sudan
+
+
+ South Sudan
+
+
+ Georgia
+
+
+ Abkhazia
+
+
+
+ South Ossetia
+
+
+
+
+ Peru
+
+
+ Burkina Faso
+
+
+ France
+
+
+
+
+
+
+
+
+
+ Guadeloupe
+
+
+
+
+
+
+
+ Martinique
+
+
+
+ Reunion
+
+
+
+ Mayotte
+
+
+
+ French Guiana
+
+
+
+ Libya
+
+
+ Belarus
+
+
+ Pakistan
+
+
+ Azad Kashmir
+
+
+
+ Indonesia
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Yemen
+
+
+
+
+
+
+ Madagascar
+
+
+
+
+
+ Bolivia, Plurinational State of
+
+
+
+
+ Serbia
+
+
+ Kosovo
+
+
+
+
+ Cote d'Ivoire
+
+
+ Algeria
+
+
+ Switzerland
+
+
+ Cameroon
+
+
+ North Macedonia
+
+
+ Botswana
+
+
+ Kenya
+
+
+ Jordan
+
+
+ Mexico
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ United Arab Emirates
+
+
+
+
+ Belize
+
+
+
+
+ Brazil
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sierra Leone
+
+
+
+
+ Mali
+
+
+ Congo, Democratic Republic of the
+
+
+ Italy
+
+
+
+
+
+
+
+ Somalia
+
+
+ Somaliland
+
+
+
+ Afghanistan
+
+
+ Bangladesh
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dominican Republic
+
+
+
+
+ Guinea-Bissau
+
+
+
+
+
+
+
+
+
+
+ Ghana
+
+
+ Austria
+
+
+ Sweden
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Turkey
+
+
+
+
+
+ Uganda
+
+
+ Mozambique
+
+
+
+
+
+
+ Japan
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ New Zealand
+
+
+
+
+
+
+
+
+
+
+
+ Cuba
+
+
+
+
+
+
+
+
+
+
+ Venezuela, Bolivarian Republic of
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Portugal
+
+
+
+
+
+
+
+
+
+
+ Colombia
+
+
+ Mauritania
+
+
+
+
+ Angola
+
+
+
+
+ Germany
+
+
+
+
+
+
+
+ Thailand
+
+
+
+
+
+
+
+
+
+
+
+ Australia
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Papua New Guinea
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Iraq
+
+
+ Croatia
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Greenland
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Niger
+
+
+ Denmark
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Latvia
+
+
+ Romania
+
+
+ Zambia
+
+
+ Myanmar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ethiopia
+
+
+ Guatemala
+
+
+ Suriname
+
+
+ Czech Republic
+
+
+ Chad
+
+
+ Albania
+
+
+ Finland
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Syrian Arab Republic
+
+
+ Kyrgyzstan
+
+
+ Solomon Islands
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Oman
+
+
+
+
+
+ Panama
+
+
+
+
+
+
+
+ Argentina
+
+
+
+
+
+
+
+ United Kingdom of Great Britain and Northern Ireland
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Costa Rica
+
+
+ Paraguay
+
+
+ Guinea
+
+
+
+
+ Ireland
+
+
+
+
+
+ Nigeria
+
+
+
+
+
+ Tunisia
+
+
+
+
+ Poland
+
+
+ Namibia
+
+
+ South Africa
+
+
+ Egypt
+
+
+ Tanzania, United Republic of
+
+
+
+
+
+
+ Saudi Arabia
+
+
+
+
+
+
+
+ Viet Nam
+
+
+
+
+
+
+
+
+
+
+
+
+ Russian Federation
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Crimea
+
+
+
+ Haiti
+
+
+
+
+
+
+ Bosnia and Herzegovina
+
+
+ India
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ China
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Hong Kong
+
+
+
+
+
+
+
+ Macao
+
+
+
+ Taiwan
+
+
+
+
+
+ Canada
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ El Salvador
+
+
+ Guyana
+
+
+ Belgium
+
+
+ Equatorial Guinea
+
+
+
+
+ Lesotho
+
+
+ Bulgaria
+
+
+ Burundi
+
+
+ Djibouti
+
+
+ Azerbaijan
+
+
+
+
+
+ Nagorno-Karabakh
+
+
+
+
+ Iran, Islamic Republic of
+
+
+
+
+
+
+ Malaysia
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Philippines
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Uruguay
+
+
+ Congo
+
+
+ Montenegro
+
+
+
+ Estonia
+
+
+
+
+
+
+
+ Rwanda
+
+
+ Armenia
+
+
+ Senegal
+
+
+ Togo
+
+
+ Spain
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Gabon
+
+
+
+
+ Hungary
+
+
+ Malawi
+
+
+ Tajikistan
+
+
+ Cambodia
+
+
+
+
+
+
+ Korea, Republic of
+
+
+
+
+
+
+
+
+
+
+
+ Honduras
+
+
+
+
+ Iceland
+
+
+ Nicaragua
+
+
+ Chile
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Morocco
+
+
+
+ Western Sahara
+
+
+ Sahrawi Arab Democratic Republic (Free Zone)
+
+
+
+
+ Liberia
+
+
+ Netherlands
+
+
+
+
+
+
+
+
+
+
+
+ Bonaire, Sint Eustatius and Saba
+
+
+
+
+ Central African Republic
+
+
+ Slovakia
+
+
+ Lithuania
+
+
+ Zimbabwe
+
+
+ Sri Lanka
+
+
+
+
+
+ Israel
+
+
+
+
+ Gaza Strip (State of Palestine)
+
+
+ West Bank (State of Palestine)
+
+
+
+
+
+
+ Lao People's Democratic Republic
+
+
+ Korea, Democratic People's Republic of
+
+
+ Greece
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Turkmenistan
+
+
+ Ecuador
+
+
+
+
+
+
+
+
+
+
+
+
+ Benin
+
+
+ Slovenia
+
+
+ Norway
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Moldova, Republic of
+
+
+ Transnistria
+
+
+
+
+ Ukraine
+
+
+ Donetsk People's Republic
+
+
+
+ Luhansk People's Republic
+
+
+
+
+ Lebanon
+
+
+
+ Nepal
+
+
+ Eritrea
+
+
+
+
+ United States of America
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Kazakhstan
+
+
+
+
+ French Southern Territories
+
+
+
+ Eswatini
+
+
+
+ Uzbekistan
+
+
+ Mongolia
+
+
+ Bhutan
+
+
+ New Caledonia
+
+
+
+
+
+
+
+
+
+
+ Fiji
+
+
+
+
+
+
+
+
+
+
+
+
+ Kuwait
+
+
+
+
+
+
+ Timor-Leste
+
+
+
+
+
+
+ Bahamas
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Vanuatu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Falkland Islands (Malvinas)
+
+
+
+
+
+
+
+
+
+
+
+
+ South Georgia and the South Sandwich Islands
+
+
+
+
+
+ Gambia, Republic of The
+
+
+
+ Qatar
+
+
+
+ Jamaica
+
+
+
+ Cyprus
+
+
+
+
+ Northern Cyprus
+
+
+
+
+ Puerto Rico
+
+
+
+ Brunei Darussalam
+
+
+
+
+
+
+ Trinidad and Tobago
+
+
+
+
+
+
+ Cabo Verde
+
+
+
+
+
+
+
+
+
+
+
+
+ French Polynesia
+
+
+
+
+
+
+
+
+
+
+
+
+ Samoa
+
+
+
+
+
+
+ Luxembourg
+
+
+
+ Comoros
+
+
+
+
+
+
+
+ Mauritius
+
+
+
+ Faroe Islands
+
+
+
+
+
+
+
+
+
+
+ Sao Tome and Principe
+
+
+
+
+
+
+ Virgin Islands, U.S.
+
+
+
+
+
+
+ Curacao
+
+
+
+ Sint Maarten (Dutch Part)
+
+
+
+ Dominica
+
+
+
+ Tonga
+
+
+
+
+
+
+ Kiribati
+
+
+
+
+
+
+ Micronesia, Federated States of
+
+
+
+ Bahrain
+
+
+
+ Andorra
+
+
+
+ Northern Mariana Islands
+
+
+
+ Palau
+
+
+
+ Seychelles
+
+
+
+ Antigua and Barbuda
+
+
+
+
+
+
+ Barbados
+
+
+
+ Turks and Caicos Islands
+
+
+
+
+
+
+
+ Saint Vincent and the Grenadines
+
+
+
+ Saint Lucia
+
+
+
+ Grenada
+
+
+
+ Malta
+
+
+
+ Maldives
+
+
+
+ Cayman Islands
+
+
+
+ Saint Kitts and Nevis
+
+
+
+
+
+
+ Montserrat
+
+
+
+ Saint Barthelemy
+
+
+
+ Niue
+
+
+
+ Saint Pierre and Miquelon
+
+
+
+ Cook Islands
+
+
+
+
+
+
+ Wallis and Futuna
+
+
+
+ American Samoa
+
+
+
+ Marshall Islands
+
+
+
+ Aruba
+
+
+
+ Liechtenstein
+
+
+
+ Virgin Islands, British
+
+
+
+
+
+
+ Saint Helena, Ascension and Tristan Da Cunha
+
+
+
+ Jersey
+
+
+
+ Anguilla
+
+
+
+ Saint Martin (French Part)
+
+
+
+ Guernsey
+
+
+
+ San Marino
+
+
+
+ Bermuda
+
+
+
+ Tuvalu
+
+
+
+ Nauru
+
+
+
+ Gibraltar
+
+
+
+ Pitcairn
+
+
+
+ Monaco
+
+
+
+ Holy See (Vatican City State)
+
+
+
+ Isle of Man
+
+
+
+ Guam
+
+
+
+ Singapore
+
+
+
+ Norfolk Island
+
+
+
+ Tokelau
+
+
+ >
+)
+/* eslint-enable */
diff --git a/sites/dev/package.json b/sites/dev/package.json
index 06c5d74a6f6..bd733bc49c9 100644
--- a/sites/dev/package.json
+++ b/sites/dev/package.json
@@ -32,17 +32,17 @@
"@mdx-js/mdx": "^3.0.0",
"@mdx-js/react": "^3.0.0",
"@mdx-js/runtime": "2.0.0-next.9",
- "@next/bundle-analyzer": "14.1.4",
- "@tailwindcss/typography": "0.5.10",
+ "@next/bundle-analyzer": "14.2.3",
+ "@tailwindcss/typography": "0.5.13",
"algoliasearch": "4.22.1",
- "daisyui": "4.7.3",
+ "daisyui": "4.10.4",
"lodash.get": "4.4.2",
"lodash.orderby": "4.6.0",
"lodash.set": "4.3.2",
- "next": "14.1.4",
- "react": "18.2.0",
+ "next": "14.2.3",
+ "react": "18.3.1",
"react-copy-to-clipboard": "5.1.0",
- "react-dom": "18.2.0",
+ "react-dom": "18.3.1",
"react-hotkeys-hook": "4.5.0",
"react-instantsearch-dom": "6.40.4",
"react-instantsearch-hooks-web": "6.47.3",
@@ -64,7 +64,7 @@
"postcss": "8.4.38",
"remark-extract-frontmatter": "3.2.0",
"remark-mdx-frontmatter": "4.0.0",
- "tailwindcss": "3.4.1",
+ "tailwindcss": "3.4.3",
"yaml-loader": "0.8.1"
},
"engines": {
diff --git a/sites/lab/hooks/use-design.mjs b/sites/lab/hooks/use-design.mjs
index f22a81f61f8..aa42ec9738d 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'
@@ -54,11 +55,13 @@ import { Titan as titan } from '@freesewing/titan'
import { Trayvon as trayvon } from '@freesewing/trayvon'
import { Tristan as tristan } from '@freesewing/tristan'
import { Uma as uma } from '@freesewing/uma'
+import { Umbra as umbra } from '@freesewing/umbra'
import { Wahid as wahid } from '@freesewing/wahid'
import { Walburga as walburga } from '@freesewing/walburga'
import { Waralee as waralee } from '@freesewing/waralee'
import { Yuri as yuri } from '@freesewing/yuri'
import { Jane as jane } from '@freesewing/jane'
+import { Lily as lily } from '@freesewing/lily'
const designs = {
aaron,
@@ -67,6 +70,7 @@ const designs = {
bella,
benjamin,
bent,
+ bibi,
bob,
breanna,
brian,
@@ -113,11 +117,13 @@ const designs = {
trayvon,
tristan,
uma,
+ umbra,
wahid,
walburga,
waralee,
yuri,
jane,
+ lily,
}
export const useDesign = (design) => (designs[design] ? designs[design] : false)
diff --git a/sites/lab/package.json b/sites/lab/package.json
index cce2c19d072..3c1262e20db 100644
--- a/sites/lab/package.json
+++ b/sites/lab/package.json
@@ -30,23 +30,23 @@
"@mdx-js/mdx": "^3.0.0",
"@mdx-js/react": "^3.0.0",
"@mdx-js/runtime": "2.0.0-next.9",
- "@tailwindcss/typography": "0.5.10",
+ "@tailwindcss/typography": "0.5.13",
"algoliasearch": "4.22.1",
"d3-dispatch": "3.0.1",
"d3-drag": "3.0.0",
"d3-selection": "3.0.0",
- "daisyui": "4.7.3",
- "i18next": "23.10.1",
+ "daisyui": "4.10.4",
+ "i18next": "23.11.2",
"lodash.get": "4.4.2",
"lodash.orderby": "4.6.0",
"lodash.set": "4.3.2",
- "next": "14.1.4",
- "next-i18next": "15.2.0",
+ "next": "14.2.3",
+ "next-i18next": "15.3.0",
"ora": "8.0.1",
- "react": "18.2.0",
+ "react": "18.3.1",
"react-copy-to-clipboard": "5.1.0",
"react-hotkeys-hook": "4.5.0",
- "react-i18next": "14.1.0",
+ "react-i18next": "14.1.1",
"react-instantsearch-dom": "6.40.4",
"react-swipeable": "7.0.1",
"react-timeago": "7.2.0",
@@ -65,7 +65,7 @@
"postcss": "8.4.38",
"remark-extract-frontmatter": "3.2.0",
"remark-mdx-frontmatter": "4.0.0",
- "tailwindcss": "3.4.1",
+ "tailwindcss": "3.4.3",
"yaml-loader": "0.8.1"
},
"engines": {
diff --git a/sites/org/hooks/use-design.mjs b/sites/org/hooks/use-design.mjs
index de6c7f2e460..a7915656e34 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'
@@ -51,10 +52,12 @@ import { Titan as titan } from '@freesewing/titan'
import { Trayvon as trayvon } from '@freesewing/trayvon'
import { Tristan as tristan } from '@freesewing/tristan'
import { Uma as uma } from '@freesewing/uma'
+import { Umbra as umbra } from '@freesewing/umbra'
import { Wahid as wahid } from '@freesewing/wahid'
import { Walburga as walburga } from '@freesewing/walburga'
import { Waralee as waralee } from '@freesewing/waralee'
import { Yuri as yuri } from '@freesewing/yuri'
+import { Lily as lily } from '@freesewing/lily'
const designs = {
aaron,
@@ -63,6 +66,7 @@ const designs = {
bella,
benjamin,
bent,
+ bibi,
bob,
breanna,
brian,
@@ -106,10 +110,12 @@ const designs = {
trayvon,
tristan,
uma,
+ umbra,
wahid,
walburga,
waralee,
yuri,
+ lily,
}
export const useDesign = (design) => (designs[design] ? designs[design] : false)
diff --git a/sites/org/package.json b/sites/org/package.json
index 9276ee11271..f2774f443e2 100644
--- a/sites/org/package.json
+++ b/sites/org/package.json
@@ -29,30 +29,36 @@
"peerDependencies": {},
"dependencies": {
"@bugsnag/js": "7.22.4",
- "@bugsnag/plugin-react": "7.19.0",
+ "@bugsnag/plugin-react": "7.22.7",
"@mdx-js/mdx": "^3.0.0",
"@mdx-js/react": "^3.0.0",
"@mdx-js/runtime": "2.0.0-next.9",
"@tailwindcss/nesting": "^0.0.0-insiders.565cd3e",
- "@tailwindcss/typography": "0.5.10",
+ "@tailwindcss/typography": "0.5.13",
"algoliasearch": "4.22.1",
"react-copy-to-clipboard": "5.1.0",
- "daisyui": "4.7.3",
+ "daisyui": "4.10.4",
"echarts": "5.5.0",
"echarts-for-react": "3.0.2",
- "jotai": "2.7.1",
- "jotai-location": "0.5.4",
+ "jotai": "2.8.0",
+ "jotai-location": "0.5.5",
"lodash.get": "4.4.2",
"lodash.orderby": "4.6.0",
"lodash.set": "4.3.2",
"luxon": "3.4.4",
- "next": "14.1.4",
+ "next": "14.2.3",
+ "next-i18next": "15.3.0",
"ora": "8.0.1",
+ "react": "18.3.1",
+ "react-dom": "18.3.1",
"react-dropzone": "14.2.3",
"react-hotkeys-hook": "4.5.0",
+ "react-i18next": "14.1.1",
"react-instantsearch-dom": "6.40.4",
+ "react-instantsearch-hooks-web": "6.47.3",
"react-swipeable": "7.0.1",
"react-timeago": "7.2.0",
+ "react-zoom-pan-pinch": "3.4.4",
"rehype-autolink-headings": "7.1.0",
"rehype-highlight": "7.0.0",
"rehype-sanitize": "6.0.0",
@@ -63,7 +69,7 @@
"remark-gfm": "4.0.0",
"remark-mdx-frontmatter": "4.0.0",
"strip-markdown": "6.0.0",
- "use-local-storage-state": "19.1.0",
+ "use-local-storage-state": "19.2.0",
"yaml-loader": "0.8.1"
},
"devDependencies": {
@@ -72,7 +78,7 @@
"postcss": "8.4.38",
"remark-extract-frontmatter": "3.2.0",
"remark-mdx-frontmatter": "4.0.0",
- "tailwindcss": "3.4.1",
+ "tailwindcss": "3.4.3",
"yaml-loader": "0.8.1"
},
"engines": {
diff --git a/sites/org/pages/account/patterns/lily/edit.mjs b/sites/org/pages/account/patterns/lily/edit.mjs
new file mode 100644
index 00000000000..4f6a6136207
--- /dev/null
+++ b/sites/org/pages/account/patterns/lily/edit.mjs
@@ -0,0 +1,86 @@
+/*
+ * This page is auto-generated. Do not edit it by hand.
+ */
+import { Lily } from 'designs/lily/src/index.mjs'
+// Dependencies
+import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
+import { nsMerge, getSearchParam } from 'shared/utils.mjs'
+// Hooks
+import { useState, useEffect, useContext } from 'react'
+import { useTranslation } from 'next-i18next'
+import { useBackend } from 'shared/hooks/use-backend.mjs'
+// Context
+import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
+// Components
+import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
+import { Workbench, ns as wbNs } from 'shared/components/workbench/new.mjs'
+import { WorkbenchLayout } from 'site/components/layouts/workbench.mjs'
+import { Loading } from 'shared/components/spinner.mjs'
+
+// Translation namespaces used on this page
+const ns = nsMerge('lily', wbNs, pageNs)
+
+const EditDesignComponent = ({ id, design, Design, settings }) => (
+
+)
+
+const EditLilyPage = ({ page }) => {
+ const { setLoadingStatus } = useContext(LoadingStatusContext)
+ const backend = useBackend()
+ const { t } = useTranslation(ns)
+
+ const [pattern, setPattern] = useState(false)
+
+ useEffect(() => {
+ const getPattern = async () => {
+ setLoadingStatus([true, t('backendLoadingStarted')])
+ let result
+ try {
+ result = await backend.getPattern(id)
+ if (result.success) {
+ setPattern(result.data.pattern)
+ setLoadingStatus([true, 'backendLoadingCompleted', true, true])
+ } else setLoadingStatus([true, 'backendError', true, false])
+ } catch (err) {
+ console.log(err)
+ setLoadingStatus([true, 'backendError', true, false])
+ }
+ }
+ const id = getSearchParam('id')
+ if (id) getPattern()
+ }, [backend, setLoadingStatus, t])
+
+ return (
+ // prettier-ignore
+
+ {pattern ? (
+
+ ) : (
+
+
{t('account:oneMomentPLease')}
+
+
+ )}
+
+ )
+}
+
+export default EditLilyPage
+
+export async function getStaticProps({ locale }) {
+ return {
+ props: {
+ ...(await serverSideTranslations(locale, ns)),
+ page: {
+ locale,
+ path: ['account', 'patterns', 'lily'],
+ title: 'Lily',
+ },
+ },
+ }
+}
diff --git a/sites/org/pages/admin/subscribers.mjs b/sites/org/pages/admin/subscribers.mjs
index 503e86d3231..53fbcdbf14e 100644
--- a/sites/org/pages/admin/subscribers.mjs
+++ b/sites/org/pages/admin/subscribers.mjs
@@ -1,9 +1,8 @@
// Dependencies
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
-import { nsMerge, getSearchParam } from 'shared/utils.mjs'
+import { nsMerge } from 'shared/utils.mjs'
// Hooks
-import { useTranslation } from 'next-i18next'
-import { useState, useEffect } from 'react'
+import { useState } from 'react'
import { useBackend } from 'shared/hooks/use-backend.mjs'
// Components
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
@@ -14,7 +13,6 @@ import { SearchIcon } from 'shared/components/icons.mjs'
const ns = nsMerge(pageNs, authNs)
const SubscribersPage = ({ page }) => {
- const { t } = useTranslation(ns)
const [subscribers, setSubscribers] = useState()
const [q, setQ] = useState()
const [hits, setHits] = useState([])
diff --git a/sites/org/pages/docs/index.mjs b/sites/org/pages/docs/index.mjs
index a7a8af0a9e4..6f0cca2071b 100644
--- a/sites/org/pages/docs/index.mjs
+++ b/sites/org/pages/docs/index.mjs
@@ -2,6 +2,8 @@
import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import { loadMdxAsStaticProps } from 'shared/mdx/load.mjs'
import { nsMerge } from 'shared/utils.mjs'
+// Hooks
+import { useState } from 'react'
// Components
import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
import { MdxWrapper } from 'shared/components/wrappers/mdx.mjs'
@@ -9,17 +11,23 @@ import { DocsLayout, ns as layoutNs } from 'site/components/layouts/docs.mjs'
export const ns = nsMerge('docs', pageNs, layoutNs)
-const DocsHomePage = ({ page, locale, frontmatter, mdx, mdxSlug }) => (
- }
- >
-
-
-)
+const DocsHomePage = ({ page, locale, frontmatter, mdx, mdxSlug }) => {
+ const [wide, setWide] = useState(false)
+
+ return (
+ (
+
+ )}
+ >
+
+
+ )
+}
export default DocsHomePage
diff --git a/sites/org/pages/new/lily.mjs b/sites/org/pages/new/lily.mjs
new file mode 100644
index 00000000000..e9abc59ccd7
--- /dev/null
+++ b/sites/org/pages/new/lily.mjs
@@ -0,0 +1,41 @@
+/*
+ * This page is auto-generated. Do not edit it by hand.
+ */
+import { Lily } from 'designs/lily/src/index.mjs'
+// Dependencies
+import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
+import { nsMerge } from 'shared/utils.mjs'
+// Components
+import { PageWrapper, ns as pageNs } from 'shared/components/wrappers/page.mjs'
+import { Workbench, ns as wbNs } from 'shared/components/workbench/new.mjs'
+import { WorkbenchLayout } from 'site/components/layouts/workbench.mjs'
+
+// Translation namespaces used on this page
+const ns = nsMerge('lily', wbNs, pageNs)
+
+const NewLilyPage = ({ page, docs }) => (
+
+
+
+)
+
+export default NewLilyPage
+
+export async function getStaticProps({ locale }) {
+ return {
+ props: {
+ ...(await serverSideTranslations(locale, ns)),
+ page: {
+ locale,
+ path: ['new', 'lily'],
+ title: 'Lily',
+ },
+ },
+ }
+}
diff --git a/sites/sde/package.json b/sites/sde/package.json
index 93fa2362bb1..509006cecc4 100644
--- a/sites/sde/package.json
+++ b/sites/sde/package.json
@@ -44,47 +44,47 @@
"@mdx-js/react": "^3.0.0",
"@mdx-js/runtime": "2.0.0-next.9",
"@tailwindcss/nesting": "^0.0.0-insiders.565cd3e",
- "@tailwindcss/typography": "0.5.10",
+ "@tailwindcss/typography": "0.5.13",
"autoprefixer": "10.4.19",
"axios": "1.6.8",
"d3-dispatch": "3.0.1",
"d3-drag": "3.0.0",
"d3-selection": "3.0.0",
- "daisyui": "4.7.3",
+ "daisyui": "4.10.4",
"echarts": "5.5.0",
"echarts-for-react": "3.0.2",
"file-saver": "2.0.5",
- "i18next": "23.10.1",
- "jotai": "2.7.1",
- "jotai-location": "0.5.4",
+ "i18next": "23.11.2",
+ "jotai": "2.8.0",
+ "jotai-location": "0.5.5",
"js-yaml": "4.1.0",
"lodash.debounce": "^4.0.8",
"lodash.get": "4.4.2",
"lodash.orderby": "4.6.0",
"lodash.set": "4.3.2",
"mustache": "4.2.0",
- "next": "14.1.4",
- "next-i18next": "15.2.0",
+ "next": "14.2.3",
+ "next-i18next": "15.3.0",
"pdfkit": "0.14.0",
"postcss-for": "2.1.1",
- "react": "18.2.0",
- "react-dom": "18.2.0",
+ "react": "18.3.1",
+ "react-dom": "18.3.1",
"react-copy-to-clipboard": "5.1.0",
"react-hotkeys-hook": "4.5.0",
- "react-i18next": "14.1.0",
+ "react-i18next": "14.1.1",
"react-dropzone": "14.2.3",
"react-swipeable": "7.0.1",
"react-timeago": "7.2.0",
- "react-zoom-pan-pinch": "3.4.3",
+ "react-zoom-pan-pinch": "3.4.4",
"remark-gfm": "4.0.0",
"remark-frontmatter": "5.0.0",
"remark-mdx-frontmatter": "4.0.0",
"remark-smartypants": "2.1.0",
"slugify": "^1.6.6",
"svg-to-pdfkit": "https://git@github.com/eriese/SVG-to-PDFKit",
- "tailwindcss": "3.4.1",
- "tlds": "1.251.0",
- "use-local-storage-state": "19.1.0",
+ "tailwindcss": "3.4.3",
+ "tlds": "1.252.0",
+ "use-local-storage-state": "19.2.0",
"web-worker": "1.3.0"
},
"devDependencies": {},
diff --git a/sites/shared/components/account/de.yaml b/sites/shared/components/account/de.yaml
index 11c2795871d..c47ce038aa5 100644
--- a/sites/shared/components/account/de.yaml
+++ b/sites/shared/components/account/de.yaml
@@ -188,6 +188,8 @@ customBookmark: Benutzerdefinierte Lesezeichen
yourBookmarks: Deine Lesezeichen
bookmarkThisThing: Setze ein Lesezeichen für diese Seite { thing }
page: Seite
+doc: Dokumentation
+pattern: Schnittmuster
#sets
set: Maßnahmeset
name: Name
@@ -250,7 +252,6 @@ andMore: and more
unitsMustSave: "Note: You must save after changing Units to have the change take effect on this page."
makePublic: Make public
makePrivate: Make private
-pattern: Schnittmuster
patternNew: Ein neues Muster generieren
patternNewInfo: Wähle ein Design, füge deine Maße hinzu und wir erstellen ein maßgeschneidertes Nähmuster für dich.
designNew: Ein neues Design erstellen
diff --git a/sites/shared/components/account/es.yaml b/sites/shared/components/account/es.yaml
index ceaa799b514..82404dd0870 100644
--- a/sites/shared/components/account/es.yaml
+++ b/sites/shared/components/account/es.yaml
@@ -188,6 +188,8 @@ customBookmark: Marcadores personalizados
yourBookmarks: Tus favoritos
bookmarkThisThing: Marca este { thing }
page: Página
+doc: Documentación
+pattern: Patrón
#sets
set: Conjunto de medidas
name: Nombre
@@ -250,7 +252,6 @@ andMore: and more
unitsMustSave: "Note: You must save after changing Units to have the change take effect on this page."
makePublic: Make public
makePrivate: Make private
-pattern: Patrón
patternNew: Generar un nuevo patrón
patternNewInfo: Elige un diseño, añade tu juego de medidas y generaremos un patrón de costura a medida para ti.
designNew: Crear un nuevo diseño
diff --git a/sites/shared/components/account/fr.yaml b/sites/shared/components/account/fr.yaml
index 4421c5f5d7e..7d2fec1c170 100644
--- a/sites/shared/components/account/fr.yaml
+++ b/sites/shared/components/account/fr.yaml
@@ -188,6 +188,8 @@ customBookmark: Marques pages personnalisés
yourBookmarks: Tes marques pages
bookmarkThisThing: Ajoute un marque page à { thing }
page: Page
+doc: Documentation
+pattern: Patron
#sets
set: Jeux de mesures
name: Nom
@@ -250,7 +252,6 @@ andMore: et plus
unitsMustSave: "Remarque : tu dois enregistrer après avoir modifié les unités pour que le changement prenne effet sur cette page."
makePublic: Rendre public
makePrivate: Rendre privé
-pattern: Patron
patternNew: Génère un nouveau modèle
patternNewInfo: Choisis un modèle, ajoute ton jeu de mesures, et nous générerons pour toi un patron de couture sur mesure.
designNew: Créer un nouveau dessin
diff --git a/sites/shared/components/account/nl.yaml b/sites/shared/components/account/nl.yaml
index a075db49fa2..195b134c102 100644
--- a/sites/shared/components/account/nl.yaml
+++ b/sites/shared/components/account/nl.yaml
@@ -188,6 +188,8 @@ customBookmark: Aangepaste bladwijzers
yourBookmarks: Je bladwijzers
bookmarkThisThing: Bookmark deze { thing }
page: Pagina
+doc: Documentatie
+pattern: Patroon
#sets
set: Meetset
name: Naam
@@ -250,7 +252,6 @@ andMore: and more
unitsMustSave: "Note: You must save after changing Units to have the change take effect on this page."
makePublic: Make public
makePrivate: Make private
-pattern: Patroon
patternNew: Een nieuw patroon genereren
patternNewInfo: Kies een ontwerp, voeg je maatset toe en wij maken een naaipatroon op maat voor je.
designNew: Een nieuw ontwerp creëren
diff --git a/sites/shared/components/account/patterns.mjs b/sites/shared/components/account/patterns.mjs
index c5415d7bee1..d55b7cb0009 100644
--- a/sites/shared/components/account/patterns.mjs
+++ b/sites/shared/components/account/patterns.mjs
@@ -8,6 +8,7 @@ import {
horFlexClasses,
newPatternUrl,
} from 'shared/utils.mjs'
+import orderBy from 'lodash.orderby'
import { freeSewingConfig as conf, controlLevels } from 'shared/config/freesewing.config.mjs'
// Context
import { LoadingStatusContext } from 'shared/context/loading-status-context.mjs'
@@ -35,6 +36,7 @@ import {
CameraIcon,
EditIcon,
ResetIcon,
+ RightIcon,
UploadIcon,
FreeSewingIcon,
CloneIcon,
@@ -540,6 +542,19 @@ export const PatternCard = ({
return {inner}
}
+// Component to show the sort header in the pattern table
+const SortButton = ({ field, label, order, orderAsc, updateOrder }) => (
+ updateOrder(field)}
+ className="btn-link text-secondary flex flex-row gap-2 items-center decoration-0 no-underline"
+ >
+ {label}
+ {order === field ? (
+
+ ) : null}
+
+)
+
// Component for the account/patterns page
export const Patterns = () => {
const router = useRouter()
@@ -554,6 +569,8 @@ export const Patterns = () => {
const [patterns, setPatterns] = useState([])
const [selected, setSelected] = useState({})
const [refresh, setRefresh] = useState(0)
+ const [order, setOrder] = useState('id')
+ const [orderAsc, setOrderAsc] = useState(true)
// Helper var to see how many are selected
const selCount = Object.keys(selected).length
@@ -601,6 +618,14 @@ export const Patterns = () => {
setLoadingStatus([true, 'nailedIt', true, true])
}
+ // Helper method to update the order state
+ const updateOrder = (field) => {
+ if (order !== field) {
+ setOrder(field)
+ setOrderAsc(true)
+ } else setOrderAsc(!orderAsc)
+ }
+
return (
@@ -624,16 +649,42 @@ export const Patterns = () => {
checked={patterns.length === selCount}
/>
-
#
+
+
+
{t('account:img')}
-
{t('account:name')}
-
{t('account:design')}
-
{t('account:createdAt')}
-
{t('account:public')}
+
+
+
+
+
+
+
+
+
+
+
+
- {patterns.map((pattern, i) => (
+ {orderBy(patterns, order, orderAsc ? 'asc' : 'desc').map((pattern, i) => (
{
+ // Normalize stroke across designs
+ stroke = stroke * strokeScale
+
+ return (
+
+
+
+
+ )
+}
+
+/*
+ * React component for the front
+ */
+export const UmbraFront = ({
+ className = 'w-64', // CSS classes to apply
+ stroke = 1, // Stroke width to use
+}) => {
+ // Normalize stroke across designs
+ stroke = stroke * strokeScale
+
+ return (
+
+
+
+ )
+}
+
+/*
+ * React component for the back
+ */
+export const UmbraBack = ({
+ className = 'w-64', // CSS classes to apply
+ stroke = 1, // Stroke width to use
+}) => {
+ // Normalize stroke across designs
+ stroke = stroke * strokeScale
+
+ return (
+
+
+
+ )
+}
+
+/*
+ * SVG elements for the front
+ */
+export const Front = ({ stroke }) => (
+ <>
+
+
+ >
+)
+
+/*
+ * SVG elements for the back
+ */
+const Back = ({ stroke }) => (
+ <>
+
+
+ >
+)
diff --git a/sites/shared/components/icons.mjs b/sites/shared/components/icons.mjs
index a1069541af7..bbff1da1995 100644
--- a/sites/shared/components/icons.mjs
+++ b/sites/shared/components/icons.mjs
@@ -455,6 +455,13 @@ export const LockIcon = (props) => (
)
+export const MapMarkerIcon = (props) => (
+
+
+
+
+)
+
export const MastodonIcon = (props) => (
diff --git a/sites/shared/components/mdx/index.mjs b/sites/shared/components/mdx/index.mjs
index 70aa30baacf..f9ba3f7206b 100644
--- a/sites/shared/components/mdx/index.mjs
+++ b/sites/shared/components/mdx/index.mjs
@@ -19,6 +19,8 @@ import { MeasieImage } from 'shared/components/measurements/image.mjs'
// Dev/Org jargon
import { Term as SharedTerm, termList } from 'shared/components/jargon.mjs'
import { jargon, site } from 'site/prebuild/jargon.mjs'
+// Dev web of trust
+import { WebOfTrustMap, WebOfTrustTable } from '../../../dev/components/web-of-trust.mjs'
export const Term = ({ children }) =>
export const TermList = termList(jargon, site)
@@ -69,6 +71,8 @@ export const components = (site = 'org', slug = []) => {
...extra,
Method: HttpMethod,
StatusCode: HttpStatusCode,
+ WebOfTrustTable,
+ WebOfTrustMap,
}
const specific = {}
diff --git a/sites/shared/components/mdx/read-more.mjs b/sites/shared/components/mdx/read-more.mjs
index 9af3fc62ce4..e96798ee086 100644
--- a/sites/shared/components/mdx/read-more.mjs
+++ b/sites/shared/components/mdx/read-more.mjs
@@ -26,9 +26,10 @@ const onActivePath = (slug, active) => (active ? active.slice(0, slug.length) ==
* This is a recursive function, so it needs to be lean
*/
const RenderTree = ({ tree, recurse, depth = 1, level = 0, active = false }) => {
- const orderedTree = orderBy(tree, ['o', 't'], ['asc', 'asc']).filter(
- (item) => typeof item === 'object'
- )
+ const orderedTree = orderBy(tree, ['o', 't'], ['asc', 'asc'])
+ .filter((item) => typeof item === 'object')
+ .filter((item) => !item.h)
+ .filter((item) => !item._)
return (