1
0
Fork 0

feat: Add various content types to docusaurus (#7231)

This brings blog posts, showcase posts, and newsletter editions into the Docusaurus site.

It also adds support for using TailwindCSS inside a container. So this will probably end up being the new freesewing.org site in v4.
This commit is contained in:
Joost De Cock 2024-11-18 11:05:16 +01:00 committed by GitHub
parent ef8f68bcaf
commit 469eb43c95
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
595 changed files with 20432 additions and 2469 deletions

View file

@ -1,10 +1,10 @@
---
title: Adding measurements
order: 30
sidebar_position: 30
---
FreeSewing is all about _bespoke_ sewing patterns -- or *parametric
design* to use a more generic term.
FreeSewing is all about _bespoke_ sewing patterns -- or _parametric
design_ to use a more generic term.
That means that when drafting our pattern, I will take the measurements provided
by the user into account.
@ -21,7 +21,7 @@ So let's add it as a required measurement.
In our `src/bib.mjs` file, we will add a `measurements` property to the `bib` object.
This property will be an Array (a list) holding all required measurements for this part.
I am using [*the official name* of the measurement](/reference/measurements) here. For head
I am using [_the official name_ of the measurement](/reference/measurements) here. For head
circumference, that name is `head`.
:::note [FIXME]

View file

@ -1,6 +1,6 @@
---
title: Adding options
order: 40
sidebar_position: 40
---
I have shown what our bib should look like, and added the _head_ measurement
@ -12,7 +12,7 @@ to work with. But there's still a number of choices I have to make:
I could make all of these choices for the user and set them in stone, so to speak.
But since the pattern I am designing is code, it is trivial (and _IMHO_ very satisfying)
But since the pattern I am designing is code, it is trivial (and _IMHO_ very satisfying)
to make a pattern flexible and let the user choose.
All I need to do to give control to the user is add _options_ to the part.
@ -34,10 +34,10 @@ export const bib = {
measurements: [ 'head' ],
// highlight-start
options: {
neckRatio: {
pct: 80,
min: 70,
max: 90,
neckRatio: {
pct: 80,
min: 70,
max: 90,
menu: 'fit'
},
},
@ -61,7 +61,7 @@ They are all documented [in the part reference docs](/reference/api/part/config/
##### What is `menu` and why should you care?
The `menu` property on our option is *extra*.
The `menu` property on our option is _extra_.
It will be ignored by FreeSewing's core library and if we leave it out, our design will produce the same result.
Instead, this `menu` property is there for the benefit of FreeSewing's development environment which will use this to build a menu structure for the various
@ -85,25 +85,25 @@ export const bib = {
draft: draftBib,
measurements: [ 'head' ],
options: {
neckRatio: {
pct: 80,
min: 70,
max: 90,
neckRatio: {
pct: 80,
min: 70,
max: 90,
menu: 'fit'
},
// highlight-start
widthRatio: {
pct: 45,
min: 35,
max: 55,
menu: 'style'
widthRatio: {
pct: 45,
min: 35,
max: 55,
menu: 'style'
},
lengthRatio: {
pct: 75,
min: 55,
max: 85,
menu: 'style'
lengthRatio: {
pct: 75,
min: 55,
max: 85,
menu: 'style'
},
// highlight-end
},
@ -116,4 +116,3 @@ Later, I will test-drive our pattern to see how it behaves when we adapt the opt
between their minimum and maximum values. At that time, I may need to tweak these values.
With that out of the way, I will start drawing the bib.

View file

@ -1,6 +1,6 @@
---
title: Avoiding overlap
order: 92
sidebar_position: 92
---
While we've only drawn the end of one strap, it's pretty obvious they overlap,
@ -11,9 +11,10 @@ Specifically, we're going to rotate our strap out of the way until it no longer
The rest of our bib should stay as it is, so let's start by making a list of points we need
to rotate.
However, there is a catch.
However, there is a catch.
## Macros and auto-generated IDs
We have used the `round` macro to help us round the corners
of our strap, and it added a bunch of auto-generated points to our pattern. We need to
rotate these points too, but what are their names?
@ -49,7 +50,7 @@ that return value, but if we did, it would look like this:
```
Those names aren't very handy to remember. So I will rewrite this code a bit to
we'll capture these return values from the `round` macros and create
we'll capture these return values from the `round` macros and create
easy-to-remember points from them:
<Example tutorial caption="It looks the same as before, but now those macro points are accessible to us">
@ -68,36 +69,38 @@ function draftBib({
part,
}) {
/*
* Construct the quarter neck opening
*/
/\*
- Construct the quarter neck opening
_/
let tweak = 1
let target = (measurements.head * options.neckRatio) /4
let target = (measurements.head _ options.neckRatio) /4
let delta
do {
points.right = new Point(
tweak * measurements.head / 10,
0
)
points.bottom = new Point(
0,
tweak * measurements.head / 12
)
points.right = new Point(
tweak _ measurements.head / 10,
0
)
points.bottom = new Point(
0,
tweak _ measurements.head / 12
)
points.rightCp1 = points.right.shift(
90,
90,
points.bottom.dy(points.right) / 2
)
points.bottomCp2 = points.bottom.shift(
0,
0,
points.bottom.dx(points.right) / 2
)
paths.quarterNeck = new Path()
.move(points.right)
.curve(
points.rightCp1,
points.bottomCp2,
points.rightCp1,
points.bottomCp2,
points.bottom
)
.hide()
@ -105,11 +108,13 @@ function draftBib({
delta = paths.quarterNeck.length() - target
if (delta > 0) tweak = tweak * 0.99
else tweak = tweak * 1.02
} while (Math.abs(delta) > 1)
/*
* Construct the complete neck opening
*/
} while (Math.abs(delta) > 1)
/\*
- Construct the complete neck opening
\*/
points.rightCp2 = points.rightCp1.flipY()
points.bottomCp1 = points.bottomCp2.flipX()
points.left = points.right.flipX()
@ -119,97 +124,103 @@ function draftBib({
points.topCp1 = points.bottomCp2.flipY()
points.topCp2 = points.bottomCp1.flipY()
paths.neck = new Path()
.move(points.top)
.curve(points.topCp2, points.leftCp1, points.left)
.curve(points.leftCp2, points.bottomCp1, points.bottom)
.curve(points.bottomCp2, points.rightCp1, points.right)
.curve(points.rightCp2, points.topCp1, points.top)
.close()
.addClass('fabric')
paths.neck = new Path()
.move(points.top)
.curve(points.topCp2, points.leftCp1, points.left)
.curve(points.leftCp2, points.bottomCp1, points.bottom)
.curve(points.bottomCp2, points.rightCp1, points.right)
.curve(points.rightCp2, points.topCp1, points.top)
.close()
.addClass('fabric')
/*
* Drawing the bib outline
*/
const width = measurements.head * options.widthRatio
const length = measurements.head * options.lengthRatio
/\*
points.topLeft = new Point(
width / -2,
points.top.y - (width / 2 - points.right.x)
)
points.topRight = points.topLeft.shift(0, width)
points.bottomLeft = points.topLeft.shift(-90, length)
points.bottomRight = points.topRight.shift(-90, length)
- Drawing the bib outline
_/
const width = measurements.head _ options.widthRatio
const length = measurements.head \* options.lengthRatio
/*
* Shape the straps
*/
points.topLeft = new Point(
width / -2,
points.top.y - (width / 2 - points.right.x)
)
points.topRight = points.topLeft.shift(0, width)
points.bottomLeft = points.topLeft.shift(-90, length)
points.bottomRight = points.topRight.shift(-90, length)
/\*
- Shape the straps
\*/
points.edgeLeft = new Point(points.topLeft.x, points.left.y)
points.edgeRight = new Point(points.topRight.x, points.right.y)
points.edgeTop = new Point(0, points.topLeft.y)
points.edgeLeftCp = points.edgeLeft.shiftFractionTowards(points.topLeft, 0.5)
points.edgeRightCp = points.edgeLeftCp.flipX()
points.edgeTopLeftCp = points.edgeTop.shiftFractionTowards(
points.topLeft,
0.5
)
points.edgeTopRightCp = points.edgeTopLeftCp.flipX()
points.edgeLeftCp = points.edgeLeft.shiftFractionTowards(points.topLeft, 0.5)
points.edgeRightCp = points.edgeLeftCp.flipX()
points.edgeTopLeftCp = points.edgeTop.shiftFractionTowards(
points.topLeft,
0.5
)
points.edgeTopRightCp = points.edgeTopLeftCp.flipX()
// Round the straps
const strap = points.edgeTop.dy(points.top)
// Round the straps
const strap = points.edgeTop.dy(points.top)
points.tipRight = points.edgeTop.translate(strap / 2, strap / 2)
points.tipRightTop = new Point(points.tipRight.x, points.edgeTop.y)
points.tipRightBottom = new Point(points.tipRight.x, points.top.y)
points.tipRight = points.edgeTop.translate(strap / 2, strap / 2)
points.tipRightTop = new Point(points.tipRight.x, points.edgeTop.y)
points.tipRightBottom = new Point(points.tipRight.x, points.top.y)
// highlight-start
/*
* Macros will return the auto-generated IDs
*/
// highlight-start
/\*
- Macros will return the auto-generated IDs
\*/
const ids1 = {
tipRightTop: macro("round", {
id: "tipRightTop",
from: points.edgeTop,
to: points.tipRight,
via: points.tipRightTop,
hide: false
}),
tipRightBottom: macro("round", {
id: "tipRightBottom",
from: points.tipRight,
to: points.top,
via: points.tipRightBottom,
hide: false
})
tipRightTop: macro("round", {
id: "tipRightTop",
from: points.edgeTop,
to: points.tipRight,
via: points.tipRightTop,
hide: false
}),
tipRightBottom: macro("round", {
id: "tipRightBottom",
from: points.tipRight,
to: points.top,
via: points.tipRightBottom,
hide: false
})
}
/*
* Create points from them with easy names
*/
/\*
- Create points from them with easy names
\*/
for (const side in ids1) {
for (const id of ['start', 'cp1', 'cp2', 'end']) {
points[`${side}${utils.capitalize(id)}`] = points[ids1[side].points[id]].copy()
}
for (const id of ['start', 'cp1', 'cp2', 'end']) {
points[`${side}${utils.capitalize(id)}`] = points[ids1[side].points[id]].copy()
}
}
// highlight-end
/*
* Now, adapt our `rect` path so it's no longer a rectangle:
*/
paths.rect = new Path()
.move(points.edgeTop)
.curve(points.edgeTopLeftCp, points.edgeLeftCp, points.edgeLeft)
.line(points.bottomLeft)
.line(points.bottomRight)
.line(points.edgeRight)
.curve(points.edgeRightCp, points.edgeTopRightCp, points.edgeTop)
.close()
return part
/\*
- Now, adapt our `rect` path so it's no longer a rectangle:
\*/
paths.rect = new Path()
.move(points.edgeTop)
.curve(points.edgeTopLeftCp, points.edgeLeftCp, points.edgeLeft)
.line(points.bottomLeft)
.line(points.bottomRight)
.line(points.edgeRight)
.curve(points.edgeRightCp, points.edgeTopRightCp, points.edgeTop)
.close()
return part
}
```
````
</Example>
Once we have our list of points to rotate, we can rotate them. How far? Until the strap no longer overlaps.
@ -236,28 +247,28 @@ function draftBib({
let delta
do {
points.right = new Point(
tweak * measurements.head / 10,
tweak * measurements.head / 10,
0
)
points.bottom = new Point(
0,
0,
tweak * measurements.head / 12
)
points.rightCp1 = points.right.shift(
90,
90,
points.bottom.dy(points.right) / 2
)
points.bottomCp2 = points.bottom.shift(
0,
0,
points.bottom.dx(points.right) / 2
)
paths.quarterNeck = new Path()
.move(points.right)
.curve(
points.rightCp1,
points.bottomCp2,
points.rightCp1,
points.bottomCp2,
points.bottom
)
.hide()
@ -266,7 +277,7 @@ function draftBib({
if (delta > 0) tweak = tweak * 0.99
else tweak = tweak * 1.02
} while (Math.abs(delta) > 1)
/*
* Construct the complete neck opening
*/
@ -422,5 +433,6 @@ function draftBib({
return part
}
```
````
</Example>

View file

@ -1,6 +1,6 @@
---
title: Completing the neck opening
order: 80
sidebar_position: 80
---
We've constructed the perfectly sized quarter neck, and we're going to use this
@ -25,36 +25,38 @@ function draftBib({
part,
}) {
/*
* Construct the quarter neck opening
*/
/\*
- Construct the quarter neck opening
_/
let tweak = 1
let target = (measurements.head * options.neckRatio) /4
let target = (measurements.head _ options.neckRatio) /4
let delta
do {
points.right = new Point(
tweak * measurements.head / 10,
0
)
points.bottom = new Point(
0,
tweak * measurements.head / 12
)
points.right = new Point(
tweak _ measurements.head / 10,
0
)
points.bottom = new Point(
0,
tweak _ measurements.head / 12
)
points.rightCp1 = points.right.shift(
90,
90,
points.bottom.dy(points.right) / 2
)
points.bottomCp2 = points.bottom.shift(
0,
0,
points.bottom.dx(points.right) / 2
)
paths.quarterNeck = new Path()
.move(points.right)
.curve(
points.rightCp1,
points.bottomCp2,
points.rightCp1,
points.bottomCp2,
points.bottom
)
// highlight-start
@ -64,11 +66,13 @@ function draftBib({
delta = paths.quarterNeck.length() - target
if (delta > 0) tweak = tweak * 0.99
else tweak = tweak * 1.02
} while (Math.abs(delta) > 1)
return part
} while (Math.abs(delta) > 1)
return part
}
```
````
</Example>
We're saying: _hide this path_. In other words, don't show it.
@ -105,28 +109,28 @@ function draftBib({
let delta
do {
points.right = new Point(
tweak * measurements.head / 10,
tweak * measurements.head / 10,
0
)
points.bottom = new Point(
0,
0,
tweak * measurements.head / 12
)
points.rightCp1 = points.right.shift(
90,
90,
points.bottom.dy(points.right) / 2
)
points.bottomCp2 = points.bottom.shift(
0,
0,
points.bottom.dx(points.right) / 2
)
paths.quarterNeck = new Path()
.move(points.right)
.curve(
points.rightCp1,
points.bottomCp2,
points.rightCp1,
points.bottomCp2,
points.bottom
)
.hide()
@ -160,11 +164,12 @@ function draftBib({
// highlight-end
return part
}
```
````
</Example>
To add the points, we're using the `Point.flipX()` and `Point.flipY()` methods
here. There's a few new Path methods too, like `close()` and `addClass()`.
here. There's a few new Path methods too, like `close()` and `addClass()`.
Perhaps you can figure out what they do? If not, both [the Point
documentation](/reference/api/point/) and [the Path

View file

@ -1,6 +1,6 @@
---
title: Conclusion (of part 2)
order: 99
sidebar_position: 99
---
You made it to the end of part 2, in which we got to do some real parametric design.
@ -14,7 +14,7 @@ way.
You've also learned how to draw paths, which are the lines and curves that make up our pattern.
And we've used macros which can help us with repetitive tasks.
What we've gotten so far is a perfectly suitable sewing pattern. You can print this,
What we've gotten so far is a perfectly suitable sewing pattern. You can print this,
and make a nice bib out of it.
But when we stick to these basics, FreeSewing doesn't really get a chance to shine.

View file

@ -1,6 +1,6 @@
---
title: Constructing the neck opening
order: 60
sidebar_position: 60
---
Our goal is to construct an oval neck opening that has a circumference
@ -51,39 +51,41 @@ function draftBib({
}) {
// highlight-start
/*
* Construct the quarter neck opening
*/
/\*
- Construct the quarter neck opening
\*/
points.right = new Point(
measurements.head / 10,
0
measurements.head / 10,
0
)
points.bottom = new Point(
0,
measurements.head / 12
0,
measurements.head / 12
)
points.rightCp1 = points.right.shift(
90,
points.bottom.dy(points.right) / 2
)
points.bottomCp2 = points.bottom.shift(
0,
points.bottom.dx(points.right) / 2
)
points.rightCp1 = points.right.shift(
90,
points.bottom.dy(points.right) / 2
)
points.bottomCp2 = points.bottom.shift(
0,
points.bottom.dx(points.right) / 2
)
paths.quarterNeck = new Path()
.move(points.right)
.curve(
points.rightCp1,
points.bottomCp2,
points.bottom
)
paths.quarterNeck = new Path()
.move(points.right)
.curve(
points.rightCp1,
points.bottomCp2,
points.bottom
)
// highlight-end
return part
return part
}
```
````
</Example>
We've added some points to our part, and drawn our first path.
@ -93,10 +95,10 @@ Let's look at each line in detail.
```js
points.right = new Point(
measurements.head / 10,
measurements.head / 10,
0
)
```
````
- We're adding a point named `right` to the `points` object which holds our
part's points
@ -108,10 +110,7 @@ points.right = new Point(
The creation of `points.bottom` is very similar, so let's skip to the next line:
```js
points.rightCp1 = points.right.shift(
90,
points.bottom.dy(points.right) / 2
)
points.rightCp1 = points.right.shift(90, points.bottom.dy(points.right) / 2)
```
- We're adding a point named `rightCp1`, which will become the _control point_
@ -130,7 +129,9 @@ the right (0 degrees) for half of the X-delta between points `bottom` and
`right`.
:::tip
##### Further reading
The `Point.shift()` and `Point.dy()` are just the tip of the iceberg.
Points come with a bunch of these methods.
You can find them all in [the Point API docs](/reference/api/point/).
@ -144,11 +145,7 @@ introduced on the next line: Paths.
```js
paths.quarterNeck = new Path()
.move(points.right)
.curve(
points.rightCp1,
points.bottomCp2,
points.bottom
)
.curve(points.rightCp1, points.bottomCp2, points.bottom)
```
- We're adding a path named `quarterNeck` to the `paths` object which holds our
@ -166,7 +163,7 @@ From there, we drew a cubic Bézier curve to our `bottom` point by using
:::tip
Many of the methods in the FreeSewing API are *chainable* allowing you
Many of the methods in the FreeSewing API are _chainable_ allowing you
to string them together like in this example.
:::

View file

@ -1,6 +1,6 @@
---
title: Creating the closure
order: 91
sidebar_position: 91
---
Things are starting to look good, but we can't fit the bib over the baby's head like this.
@ -60,28 +60,27 @@ function draftBib({
tweak _ measurements.head / 12
)
points.rightCp1 = points.right.shift(
90,
points.bottom.dy(points.right) / 2
)
points.bottomCp2 = points.bottom.shift(
0,
points.bottom.dx(points.right) / 2
)
points.rightCp1 = points.right.shift(
90,
points.bottom.dy(points.right) / 2
)
points.bottomCp2 = points.bottom.shift(
0,
points.bottom.dx(points.right) / 2
)
paths.quarterNeck = new Path()
.move(points.right)
.curve(
points.rightCp1,
points.bottomCp2,
points.bottom
)
.hide()
paths.quarterNeck = new Path()
.move(points.right)
.curve(
points.rightCp1,
points.bottomCp2,
points.bottom
)
.hide()
delta = paths.quarterNeck.length() - target
if (delta > 0) tweak = tweak * 0.99
else tweak = tweak * 1.02
delta = paths.quarterNeck.length() - target
if (delta > 0) tweak = tweak _ 0.99
else tweak = tweak _ 1.02
} while (Math.abs(delta) > 1)

View file

@ -1,6 +1,6 @@
---
title: A part's draft method
order: 50
sidebar_position: 50
---
Time to turn our attention to the draft method of our part.

View file

@ -1,6 +1,6 @@
---
title: Drawing the bib outline
order: 88
sidebar_position: 88
---
With our neck opening in place, let us draw the basic outline of our bib.
@ -17,46 +17,47 @@ function draftBib({
part,
}) {
// Construct the quarter neck opening
let tweak = 1
let target = (measurements.head * options.neckRatio) /4
let delta
do {
points.right = new Point(
tweak * measurements.head / 10,
0
)
points.bottom = new Point(
0,
tweak * measurements.head / 12
)
// Construct the quarter neck opening
let tweak = 1
let target = (measurements.head _ options.neckRatio) /4
let delta
do {
points.right = new Point(
tweak _ measurements.head / 10,
0
)
points.bottom = new Point(
0,
tweak \* measurements.head / 12
)
points.rightCp1 = points.right.shift(
90,
90,
points.bottom.dy(points.right) / 2
)
points.bottomCp2 = points.bottom.shift(
0,
0,
points.bottom.dx(points.right) / 2
)
paths.quarterNeck = new Path()
.move(points.right)
.curve(
points.rightCp1,
points.bottomCp2,
points.bottom
)
.hide()
paths.quarterNeck = new Path()
.move(points.right)
.curve(
points.rightCp1,
points.bottomCp2,
points.bottom
)
.hide()
delta = paths.quarterNeck.length() - target
if (delta > 0) tweak = tweak * 0.99
else tweak = tweak * 1.02
} while (Math.abs(delta) > 1)
delta = paths.quarterNeck.length() - target
if (delta > 0) tweak = tweak _ 0.99
else tweak = tweak _ 1.02
} while (Math.abs(delta) > 1)
/*
* Construct the complete neck opening
*/
/\*
- Construct the complete neck opening
\*/
points.rightCp2 = points.rightCp1.flipY()
points.bottomCp1 = points.bottomCp2.flipX()
points.left = points.right.flipX()
@ -66,43 +67,45 @@ function draftBib({
points.topCp1 = points.bottomCp2.flipY()
points.topCp2 = points.bottomCp1.flipY()
paths.neck = new Path()
.move(points.top)
.curve(points.topCp2, points.leftCp1, points.left)
.curve(points.leftCp2, points.bottomCp1, points.bottom)
.curve(points.bottomCp2, points.rightCp1, points.right)
.curve(points.rightCp2, points.topCp1, points.top)
.close()
.addClass('fabric')
paths.neck = new Path()
.move(points.top)
.curve(points.topCp2, points.leftCp1, points.left)
.curve(points.leftCp2, points.bottomCp1, points.bottom)
.curve(points.bottomCp2, points.rightCp1, points.right)
.curve(points.rightCp2, points.topCp1, points.top)
.close()
.addClass('fabric')
// highlight-start
/*
* Drawing the bib outline
*/
const width = measurements.head * options.widthRatio
const length = measurements.head * options.lengthRatio
/\*
points.topLeft = new Point(
width / -2,
points.top.y - (width / 2 - points.right.x)
)
points.topRight = points.topLeft.shift(0, width)
points.bottomLeft = points.topLeft.shift(-90, length)
points.bottomRight = points.topRight.shift(-90, length)
- Drawing the bib outline
_/
const width = measurements.head _ options.widthRatio
const length = measurements.head \* options.lengthRatio
paths.rect = new Path()
.move(points.topLeft)
.line(points.bottomLeft)
.line(points.bottomRight)
.line(points.topRight)
.line(points.topLeft)
.close()
.addClass('fabric')
points.topLeft = new Point(
width / -2,
points.top.y - (width / 2 - points.right.x)
)
points.topRight = points.topLeft.shift(0, width)
points.bottomLeft = points.topLeft.shift(-90, length)
points.bottomRight = points.topRight.shift(-90, length)
paths.rect = new Path()
.move(points.topLeft)
.line(points.bottomLeft)
.line(points.bottomRight)
.line(points.topRight)
.line(points.topLeft)
.close()
.addClass('fabric')
// highlight-end
return part
return part
}
```
````
</Example>
First thing we did was create the `width` and `length` variables to
@ -111,7 +114,7 @@ save ourselves some typing:
```js
const width = measurements.head * options.widthRatio
const length = measurements.head * options.lengthRatio
```
````
Both the length and width of our bib are a factor of the head circumference.
This way, our bib size will adapt to the size of the baby, and the user can tweak
@ -120,10 +123,7 @@ the length and width by playing with the options we added to the pattern.
Once we have our variables, we're adding some new points, and a second path called `rect`.
```js
points.topLeft = new Point(
width / -2,
points.top.y - (width / 2 - points.right.x)
)
points.topLeft = new Point(width / -2, points.top.y - (width / 2 - points.right.x))
points.topRight = points.topLeft.shift(0, width)
points.bottomLeft = points.topLeft.shift(-90, length)
points.bottomRight = points.topRight.shift(-90, length)
@ -142,4 +142,3 @@ We're calculating the `topLeft` point so that the top edge of our bib
and the sides are equidistant from the neck opening.
We didn't have to do that. But it looks nicely balanced this way.

View file

@ -1,6 +1,6 @@
---
title: Drawing the straps
order: 93
sidebar_position: 93
---
All we have to do now is flip a bunch of points on the other side,
@ -28,36 +28,38 @@ function draftBib({
part,
}) {
/*
* Construct the neck opening
*/
/\*
- Construct the neck opening
_/
let tweak = 1
let target = (measurements.head * options.neckRatio) /4
let target = (measurements.head _ options.neckRatio) /4
let delta
do {
points.right = new Point(
tweak * measurements.head / 10,
0
)
points.bottom = new Point(
0,
tweak * measurements.head / 12
)
points.right = new Point(
tweak _ measurements.head / 10,
0
)
points.bottom = new Point(
0,
tweak _ measurements.head / 12
)
points.rightCp1 = points.right.shift(
90,
90,
points.bottom.dy(points.right) / 2
)
points.bottomCp2 = points.bottom.shift(
0,
0,
points.bottom.dx(points.right) / 2
)
paths.quarterNeck = new Path()
.move(points.right)
.curve(
points.rightCp1,
points.bottomCp2,
points.rightCp1,
points.bottomCp2,
points.bottom
)
.hide()
@ -65,11 +67,13 @@ function draftBib({
delta = paths.quarterNeck.length() - target
if (delta > 0) tweak = tweak * 0.99
else tweak = tweak * 1.02
} while (Math.abs(delta) > 1)
/*
* Construct the complete neck opening
*/
} while (Math.abs(delta) > 1)
/\*
- Construct the complete neck opening
\*/
points.rightCp2 = points.rightCp1.flipY()
points.bottomCp1 = points.bottomCp2.flipX()
points.left = points.right.flipX()
@ -79,233 +83,239 @@ function draftBib({
points.topCp1 = points.bottomCp2.flipY()
points.topCp2 = points.bottomCp1.flipY()
// strikeout-start
/* Remove this path
paths.neck = new Path()
.move(points.top)
.curve(points.topCp2, points.leftCp1, points.left)
.curve(points.leftCp2, points.bottomCp1, points.bottom)
.curve(points.bottomCp2, points.rightCp1, points.right)
.curve(points.rightCp2, points.topCp1, points.top)
.close()
.addClass('fabric')
*/
// strikeout-end
// strikeout-start
/_ Remove this path
paths.neck = new Path()
.move(points.top)
.curve(points.topCp2, points.leftCp1, points.left)
.curve(points.leftCp2, points.bottomCp1, points.bottom)
.curve(points.bottomCp2, points.rightCp1, points.right)
.curve(points.rightCp2, points.topCp1, points.top)
.close()
.addClass('fabric')
_/
// strikeout-end
// Drawing the bib outline
const width = measurements.head * options.widthRatio
const length = measurements.head * options.lengthRatio
// Drawing the bib outline
const width = measurements.head _ options.widthRatio
const length = measurements.head _ options.lengthRatio
points.topLeft = new Point(
width / -2,
points.top.y - (width / 2 - points.right.x)
)
points.topRight = points.topLeft.shift(0, width)
points.bottomLeft = points.topLeft.shift(-90, length)
points.bottomRight = points.topRight.shift(-90, length)
points.topLeft = new Point(
width / -2,
points.top.y - (width / 2 - points.right.x)
)
points.topRight = points.topLeft.shift(0, width)
points.bottomLeft = points.topLeft.shift(-90, length)
points.bottomRight = points.topRight.shift(-90, length)
/*
* Shape the straps
*/
/\*
- Shape the straps
\*/
points.edgeLeft = new Point(points.topLeft.x, points.left.y)
points.edgeRight = new Point(points.topRight.x, points.right.y)
points.edgeTop = new Point(0, points.topLeft.y)
points.edgeLeftCp = points.edgeLeft.shiftFractionTowards(points.topLeft, 0.5)
points.edgeRightCp = points.edgeLeftCp.flipX()
points.edgeTopLeftCp = points.edgeTop.shiftFractionTowards(
points.topLeft,
0.5
)
points.edgeTopRightCp = points.edgeTopLeftCp.flipX()
points.edgeLeftCp = points.edgeLeft.shiftFractionTowards(points.topLeft, 0.5)
points.edgeRightCp = points.edgeLeftCp.flipX()
points.edgeTopLeftCp = points.edgeTop.shiftFractionTowards(
points.topLeft,
0.5
)
points.edgeTopRightCp = points.edgeTopLeftCp.flipX()
// Round the straps
const strap = points.edgeTop.dy(points.top)
// Round the straps
const strap = points.edgeTop.dy(points.top)
points.tipRight = points.edgeTop.translate(strap / 2, strap / 2)
points.tipRightTop = new Point(points.tipRight.x, points.edgeTop.y)
points.tipRightBottom = new Point(points.tipRight.x, points.top.y)
points.tipRight = points.edgeTop.translate(strap / 2, strap / 2)
points.tipRightTop = new Point(points.tipRight.x, points.edgeTop.y)
points.tipRightBottom = new Point(points.tipRight.x, points.top.y)
/*
* Macros will return the auto-generated IDs
*/
/\*
- Macros will return the auto-generated IDs
_/
const ids1 = {
tipRightTop: macro("round", {
id: "tipRightTop",
from: points.edgeTop,
to: points.tipRight,
via: points.tipRightTop,
// strikeout-start
/* Remove this to have the macro
* only create the points we need
* and not draw a path
hide: false
*/
// strikeout-end
}),
tipRightBottom: macro("round", {
id: "tipRightBottom",
from: points.tipRight,
to: points.top,
via: points.tipRightBottom,
// strikeout-start
/* Remove this to have the macro
* only create the points we need
* and not draw a path
hide: false
*/
// strikeout-end
})
}
/*
* Create points from them with easy names
*/
for (const side in ids1) {
for (const id of ['start', 'cp1', 'cp2', 'end']) {
points[`${side}${utils.capitalize(id)}`] = points[ids1[side].points[id]].copy()
}
}
/*
* This is the list of points we need to rotate
* to move our strap out of the way
*/
const rotateThese = [
"edgeTopLeftCp",
"edgeTop",
"tipRight",
"tipRightTop",
"tipRightTopStart",
"tipRightTopCp1",
"tipRightTopCp2",
"tipRightTopEnd",
"tipRightBottomStart",
"tipRightBottomCp1",
"tipRightBottomCp2",
"tipRightBottomEnd",
"tipRightBottom",
"top",
"topCp2"
]
/*
* We're rotating all the points in
* the `rotateThese` array around
* the `edgeLeft` point.
*
* We're using increments of 1 degree
* until the `tipRightBottomStart` point
* is 1 mm beyond the center of our bib.
*/
while (points.tipRightBottomStart.x > -1) {
for (const p of rotateThese) points[p] = points[p].rotate(1, points.edgeLeft)
}
tipRightTop: macro("round", {
id: "tipRightTop",
from: points.edgeTop,
to: points.tipRight,
via: points.tipRightTop,
// strikeout-start
/* Remove this repetition
macro("round", {
from: points.edgeTop,
to: points.tipRight,
via: points.tipRightTop,
prefix: "tipRightTop",
hide: false,
class: 'contrast dotted',
})
macro("round", {
from: points.tipRight,
to: points.top,
via: points.tipRightBottom,
prefix: "tipRightBottom",
hide: false,
class: 'contrast dotted',
})
paths.rect = new Path()
.move(points.edgeTop)
.curve(points.edgeTopLeftCp, points.edgeLeftCp, points.edgeLeft)
.line(points.bottomLeft)
.line(points.bottomRight)
.line(points.edgeRight)
.curve(points.edgeRightCp, points.edgeTopRightCp, points.edgeTop)
.close()
*/
/_ Remove this to have the macro
_ only create the points we need
_ and not draw a path
hide: false
_/
// strikeout-end
}),
tipRightBottom: macro("round", {
id: "tipRightBottom",
from: points.tipRight,
to: points.top,
via: points.tipRightBottom,
// strikeout-start
/_ Remove this to have the macro
_ only create the points we need
_ and not draw a path
hide: false
\*/
// strikeout-end
})
}
// highlight-start
// Add points for second strap
points.edgeTopRightCp = points.edgeTopLeftCp.flipX()
points.topCp1 = points.topCp2.flipX()
points.tipLeftTopStart = points.tipRightTopStart.flipX()
points.tipLeftTopCp1 = points.tipRightTopCp1.flipX()
points.tipLeftTopCp2 = points.tipRightTopCp2.flipX()
points.tipLeftTopEnd = points.tipRightTopEnd.flipX()
points.tipLeftBottomStart = points.tipRightBottomStart.flipX()
points.tipLeftBottomCp1 = points.tipRightBottomCp1.flipX()
points.tipLeftBottomCp2 = points.tipRightBottomCp2.flipX()
points.tipLeftBottomEnd = points.tipRightBottomEnd.flipX()
/\*
// Create one path for the bib outline
paths.seam = new Path()
.move(points.edgeLeft)
.line(points.bottomLeft)
.line(points.bottomRight)
.line(points.edgeRight)
.curve(
points.edgeRightCp,
points.edgeTopRightCp,
points.tipLeftTopStart
)
.curve(
points.tipLeftTopCp1,
points.tipLeftTopCp2,
points.tipLeftTopEnd
)
.curve(
points.tipLeftBottomCp1,
points.tipLeftBottomCp2,
points.tipLeftBottomEnd
)
.curve(
points.topCp1,
points.rightCp2,
points.right
)
.curve(
points.rightCp1,
points.bottomCp2,
points.bottom
)
.curve(
points.bottomCp1,
points.leftCp2,
points.left
)
.curve(
points.leftCp1,
points.topCp2,
points.tipRightBottomEnd
)
.curve(
points.tipRightBottomCp2,
points.tipRightBottomCp1,
points.tipRightBottomStart
)
.curve(
points.tipRightTopCp2,
points.tipRightTopCp1,
points.tipRightTopStart
)
.curve(
points.edgeTopLeftCp,
points.edgeLeftCp,
points.edgeLeft
)
.close()
.addClass("fabric")
// highlight-end
- Create points from them with easy names
\*/
for (const side in ids1) {
for (const id of ['start', 'cp1', 'cp2', 'end']) {
points[`${side}${utils.capitalize(id)}`] = points[ids1[side].points[id]].copy()
}
}
return part
/\*
- This is the list of points we need to rotate
- to move our strap out of the way
\*/
const rotateThese = [
"edgeTopLeftCp",
"edgeTop",
"tipRight",
"tipRightTop",
"tipRightTopStart",
"tipRightTopCp1",
"tipRightTopCp2",
"tipRightTopEnd",
"tipRightBottomStart",
"tipRightBottomCp1",
"tipRightBottomCp2",
"tipRightBottomEnd",
"tipRightBottom",
"top",
"topCp2"
]
/\*
_ We're rotating all the points in
_ the `rotateThese` array around
_ the `edgeLeft` point.
_
_ We're using increments of 1 degree
_ until the `tipRightBottomStart` point
_ is 1 mm beyond the center of our bib.
_/
while (points.tipRightBottomStart.x > -1) {
for (const p of rotateThese) points[p] = points[p].rotate(1, points.edgeLeft)
}
// strikeout-start
/\* Remove this repetition
macro("round", {
from: points.edgeTop,
to: points.tipRight,
via: points.tipRightTop,
prefix: "tipRightTop",
hide: false,
class: 'contrast dotted',
})
macro("round", {
from: points.tipRight,
to: points.top,
via: points.tipRightBottom,
prefix: "tipRightBottom",
hide: false,
class: 'contrast dotted',
})
paths.rect = new Path()
.move(points.edgeTop)
.curve(points.edgeTopLeftCp, points.edgeLeftCp, points.edgeLeft)
.line(points.bottomLeft)
.line(points.bottomRight)
.line(points.edgeRight)
.curve(points.edgeRightCp, points.edgeTopRightCp, points.edgeTop)
.close()
\*/
// strikeout-end
// highlight-start
// Add points for second strap
points.edgeTopRightCp = points.edgeTopLeftCp.flipX()
points.topCp1 = points.topCp2.flipX()
points.tipLeftTopStart = points.tipRightTopStart.flipX()
points.tipLeftTopCp1 = points.tipRightTopCp1.flipX()
points.tipLeftTopCp2 = points.tipRightTopCp2.flipX()
points.tipLeftTopEnd = points.tipRightTopEnd.flipX()
points.tipLeftBottomStart = points.tipRightBottomStart.flipX()
points.tipLeftBottomCp1 = points.tipRightBottomCp1.flipX()
points.tipLeftBottomCp2 = points.tipRightBottomCp2.flipX()
points.tipLeftBottomEnd = points.tipRightBottomEnd.flipX()
// Create one path for the bib outline
paths.seam = new Path()
.move(points.edgeLeft)
.line(points.bottomLeft)
.line(points.bottomRight)
.line(points.edgeRight)
.curve(
points.edgeRightCp,
points.edgeTopRightCp,
points.tipLeftTopStart
)
.curve(
points.tipLeftTopCp1,
points.tipLeftTopCp2,
points.tipLeftTopEnd
)
.curve(
points.tipLeftBottomCp1,
points.tipLeftBottomCp2,
points.tipLeftBottomEnd
)
.curve(
points.topCp1,
points.rightCp2,
points.right
)
.curve(
points.rightCp1,
points.bottomCp2,
points.bottom
)
.curve(
points.bottomCp1,
points.leftCp2,
points.left
)
.curve(
points.leftCp1,
points.topCp2,
points.tipRightBottomEnd
)
.curve(
points.tipRightBottomCp2,
points.tipRightBottomCp1,
points.tipRightBottomStart
)
.curve(
points.tipRightTopCp2,
points.tipRightTopCp1,
points.tipRightTopStart
)
.curve(
points.edgeTopLeftCp,
points.edgeLeftCp,
points.edgeLeft
)
.close()
.addClass("fabric")
// highlight-end
return part
}
```
</Example>
```

View file

@ -1,10 +1,10 @@
---
title: Fitting the neck opening
order: 70
sidebar_position: 70
---
We are not going to create some opening that we _hope_ is the right size, we're
going to make sure it is. Here's how we'll make sure the neck opening is _just
going to make sure it is. Here's how we'll make sure the neck opening is _just
right_:
<Example tutorial caption="It might look the same as before, but now it's just right">
@ -19,54 +19,56 @@ function draftBib({
part,
}) {
/*
* Construct the quarter neck opening
*/
// highlight-start
/\*
- Construct the quarter neck opening
_/
// highlight-start
let tweak = 1
let target = (measurements.head * options.neckRatio) /4
let target = (measurements.head _ options.neckRatio) /4
let delta
do {
// highlight-end
points.right = new Point(
// highlight-start
tweak * measurements.head / 10,
// highlight-end
0
)
points.bottom = new Point(
0,
// highlight-start
tweak * measurements.head / 12
// highlight-end
)
// highlight-end
points.right = new Point(
// highlight-start
tweak _ measurements.head / 10,
// highlight-end
0
)
points.bottom = new Point(
0,
// highlight-start
tweak _ measurements.head / 12
// highlight-end
)
points.rightCp1 = points.right.shift(
90,
90,
points.bottom.dy(points.right) / 2
)
points.bottomCp2 = points.bottom.shift(
0,
0,
points.bottom.dx(points.right) / 2
)
paths.quarterNeck = new Path()
.move(points.right)
.curve(
points.rightCp1,
points.bottomCp2,
points.rightCp1,
points.bottomCp2,
points.bottom
)
// highlight-start
delta = paths.quarterNeck.length() - target
if (delta > 0) tweak = tweak * 0.99
else tweak = tweak * 1.02
} while (Math.abs(delta) > 1)
delta = paths.quarterNeck.length() - target
if (delta > 0) tweak = tweak _ 0.99
else tweak = tweak _ 1.02
} while (Math.abs(delta) > 1)
// highlight-end
return part
return part
}
```
</Example>
@ -94,3 +96,4 @@ are within 1 mm of our target value.
Now that we're happy with the length of our quarter neck opening, let's
complete the entire neck opening.
```

View file

@ -1,14 +1,14 @@
---
title: Creating a new design
order: 10
sidebar_position: 10
---
The development environment has already setup various designs for us.
Since I am using the **From scratch** template, the files I want to edit live
Since I am using the **From scratch** template, the files I want to edit live
in `design/from-scratch`.
The design's main file is `design/from-scratch/src/index.mjs`, and our bib part
will live in `design/from-scratch/src/bib.mjs`.
will live in `design/from-scratch/src/bib.mjs`.
This `bib.mjs` file is where will be doing most of the work here in part 2 of this
tutorial. But let's start with the `index.mjs` file as an appetizer, because this
@ -37,7 +37,7 @@ Not too intimidating, is it?
## Imports
At the top of the file, we have a bunch of *imports*:
At the top of the file, we have a bunch of _imports_:
```src/index.mjs
import { Design } from '@freesewing/core'
@ -48,13 +48,13 @@ import { bib } from './bib.mjs'
An `import` is how JavaScript loads code from a different file. \
It essentially says: _import **something** from **somewhere**_:
| Something | Somewhere | Description |
| ---------:|:--------- |:----------- |
| `Design` | `@freesewing/core` | Loads the `Design` constructor from FreeSewing's core library |
| `i18n` | `../i18n/index.mjs` | Loads `i18n` from the `index.mjs` file in the `i18n` one level higher (these are the translations) |
| `bib` | `./bib.mjs` | Loads `bib` from the `bib.mjs` file in the same folder (this is our part) |
| Something | Somewhere | Description |
| --------: | :------------------ | :------------------------------------------------------------------------------------------------- |
| `Design` | `@freesewing/core` | Loads the `Design` constructor from FreeSewing's core library |
| `i18n` | `../i18n/index.mjs` | Loads `i18n` from the `index.mjs` file in the `i18n` one level higher (these are the translations) |
| `bib` | `./bib.mjs` | Loads `bib` from the `bib.mjs` file in the same folder (this is our part) |
As you can see, the *somewhere* can be different things. A local file like in
As you can see, the _somewhere_ can be different things. A local file like in
lines 2 and 3, or a package published on
[NPM](https://www.npmjs.com/package/@freesewing/core), in line 1.
@ -82,7 +82,7 @@ If you are not familiar with this syntax, you'll get the hang of it soon enough.
## Design constructor
Finally, the most interesting part of this file is the middle part where we are
Finally, the most interesting part of this file is the middle part where we are
creating a new design:
```src/index.mjs
@ -95,7 +95,7 @@ const FromScratch = new Design({
})
```
The `Design` that we imported on line 1 is a so-called **constructor**.
The `Design` that we imported on line 1 is a so-called **constructor**.
A constructor is a function that can create things out of nothing. Or,
to be more accurate, that you can use with the `new` keyword.
@ -105,8 +105,8 @@ It's a convention that constructor names start with an **C**apital letter.
:::
We are passing some info to this `Design` function, but the `data` we are
passing is optional. If we strip that away for a moment, and don't bother
assigning the result to a variable, we reveal the essence of what it takes to
passing is optional. If we strip that away for a moment, and don't bother
assigning the result to a variable, we reveal the essence of what it takes to
create a new FreeSewing design:
```src/index.mjs
@ -115,8 +115,8 @@ new Design({
})
```
In several places in this documentation, I will mention that *a design is not
much more than a thin wrapper around parts*. But I feel nothing drives
In several places in this documentation, I will mention that _a design is not
much more than a thin wrapper around parts_. But I feel nothing drives
that point home like seeing it in code like this.
To create a new design, we call the `Design` constructor and give it a list
@ -124,9 +124,8 @@ To create a new design, we call the `Design` constructor and give it a list
:::note RELATED
Refer to [the design reference documentation](/reference/api/design) for
Refer to [the design reference documentation](/reference/api/design) for
all details about what you can pass to the Design constructor.
:::
That's it. So let's look at where the real action is next: Our first part.

View file

@ -1,6 +1,6 @@
---
title: Creating a part
order: 20
sidebar_position: 20
---
Much like garments themselves, patterns are made up of _parts_.
@ -9,14 +9,14 @@ so on. The pattern you create today is very simple, and only has one part: the b
:::tip
It's a good idea to keep each part in its own file. You don't *have to* do
this, but it's a good habit to get into.
It's a good idea to keep each part in its own file. You don't _have to_ do
this, but it's a good habit to get into.
:::
## bib.mjs
I am going to use the **From scratch** template. So the files I want to edit live
I am going to use the **From scratch** template. So the files I want to edit live
in `design/from-scratch`.
Our part lives in `design/from-scratch/src/bib.mjs`, and it currently looks like this:
@ -41,8 +41,8 @@ The only mandatory keys on a part object are `name` and `draft`.
:::note RELATED
Refer to [the part reference documentation](/reference/api/part) for
all details about configuring the part object
Refer to [the part reference documentation](/reference/api/part) for
all details about configuring the part object
:::
:::note
@ -52,7 +52,6 @@ Each parts stands on its own, and parts from various designs can be combined
to create other designs.
:::
### The part name
```src/bib.mjs

View file

@ -1,6 +1,6 @@
---
title: Rounding the corners
order: 94
sidebar_position: 94
---
We already know how to round corners, we'll have the `round` macro take care of that for us.
@ -22,36 +22,38 @@ function draftBib({
part,
}) {
/*
* Construct the quarter neck opening
*/
/\*
- Construct the quarter neck opening
_/
let tweak = 1
let target = (measurements.head * options.neckRatio) /4
let target = (measurements.head _ options.neckRatio) /4
let delta
do {
points.right = new Point(
tweak * measurements.head / 10,
0
)
points.bottom = new Point(
0,
tweak * measurements.head / 12
)
points.right = new Point(
tweak _ measurements.head / 10,
0
)
points.bottom = new Point(
0,
tweak _ measurements.head / 12
)
points.rightCp1 = points.right.shift(
90,
90,
points.bottom.dy(points.right) / 2
)
points.bottomCp2 = points.bottom.shift(
0,
0,
points.bottom.dx(points.right) / 2
)
paths.quarterNeck = new Path()
.move(points.right)
.curve(
points.rightCp1,
points.bottomCp2,
points.rightCp1,
points.bottomCp2,
points.bottom
)
.hide()
@ -59,11 +61,13 @@ function draftBib({
delta = paths.quarterNeck.length() - target
if (delta > 0) tweak = tweak * 0.99
else tweak = tweak * 1.02
} while (Math.abs(delta) > 1)
/*
* Construct the complete neck opening
*/
} while (Math.abs(delta) > 1)
/\*
- Construct the complete neck opening
\*/
points.rightCp2 = points.rightCp1.flipY()
points.bottomCp1 = points.bottomCp2.flipX()
points.left = points.right.flipX()
@ -73,216 +77,225 @@ function draftBib({
points.topCp1 = points.bottomCp2.flipY()
points.topCp2 = points.bottomCp1.flipY()
// Drawing the bib outline
const width = measurements.head * options.widthRatio
const length = measurements.head * options.lengthRatio
// Drawing the bib outline
const width = measurements.head _ options.widthRatio
const length = measurements.head _ options.lengthRatio
points.topLeft = new Point(
width / -2,
points.top.y - (width / 2 - points.right.x)
)
points.topRight = points.topLeft.shift(0, width)
points.bottomLeft = points.topLeft.shift(-90, length)
points.bottomRight = points.topRight.shift(-90, length)
points.topLeft = new Point(
width / -2,
points.top.y - (width / 2 - points.right.x)
)
points.topRight = points.topLeft.shift(0, width)
points.bottomLeft = points.topLeft.shift(-90, length)
points.bottomRight = points.topRight.shift(-90, length)
/*
* Shape the straps
*/
/\*
- Shape the straps
\*/
points.edgeLeft = new Point(points.topLeft.x, points.left.y)
points.edgeRight = new Point(points.topRight.x, points.right.y)
points.edgeTop = new Point(0, points.topLeft.y)
points.edgeLeftCp = points.edgeLeft.shiftFractionTowards(points.topLeft, 0.5)
points.edgeRightCp = points.edgeLeftCp.flipX()
points.edgeTopLeftCp = points.edgeTop.shiftFractionTowards(
points.topLeft,
0.5
)
points.edgeTopRightCp = points.edgeTopLeftCp.flipX()
points.edgeLeftCp = points.edgeLeft.shiftFractionTowards(points.topLeft, 0.5)
points.edgeRightCp = points.edgeLeftCp.flipX()
points.edgeTopLeftCp = points.edgeTop.shiftFractionTowards(
points.topLeft,
0.5
)
points.edgeTopRightCp = points.edgeTopLeftCp.flipX()
// Round the straps
const strap = points.edgeTop.dy(points.top)
// Round the straps
const strap = points.edgeTop.dy(points.top)
points.tipRight = points.edgeTop.translate(strap / 2, strap / 2)
points.tipRightTop = new Point(points.tipRight.x, points.edgeTop.y)
points.tipRightBottom = new Point(points.tipRight.x, points.top.y)
points.tipRight = points.edgeTop.translate(strap / 2, strap / 2)
points.tipRightTop = new Point(points.tipRight.x, points.edgeTop.y)
points.tipRightBottom = new Point(points.tipRight.x, points.top.y)
/*
* Macros will return the auto-generated IDs
*/
/\*
- Macros will return the auto-generated IDs
\*/
const ids1 = {
tipRightTop: macro("round", {
id: "tipRightTop",
from: points.edgeTop,
to: points.tipRight,
via: points.tipRightTop,
}),
tipRightBottom: macro("round", {
id: "tipRightBottom",
from: points.tipRight,
to: points.top,
via: points.tipRightBottom,
})
tipRightTop: macro("round", {
id: "tipRightTop",
from: points.edgeTop,
to: points.tipRight,
via: points.tipRightTop,
}),
tipRightBottom: macro("round", {
id: "tipRightBottom",
from: points.tipRight,
to: points.top,
via: points.tipRightBottom,
})
}
/*
* Create points from them with easy names
*/
/\*
- Create points from them with easy names
\*/
for (const side in ids1) {
for (const id of ['start', 'cp1', 'cp2', 'end']) {
points[`${side}${utils.capitalize(id)}`] = points[ids1[side].points[id]].copy()
}
for (const id of ['start', 'cp1', 'cp2', 'end']) {
points[`${side}${utils.capitalize(id)}`] = points[ids1[side].points[id]].copy()
}
}
/*
* This is the list of points we need to rotate
* to move our strap out of the way
*/
- This is the list of points we need to rotate
- to move our strap out of the way
_/
const rotateThese = [
"edgeTopLeftCp",
"edgeTop",
"tipRight",
"tipRightTop",
"tipRightTopStart",
"tipRightTopCp1",
"tipRightTopCp2",
"tipRightTopEnd",
"tipRightBottomStart",
"tipRightBottomCp1",
"tipRightBottomCp2",
"tipRightBottomEnd",
"tipRightBottom",
"top",
"topCp2"
"edgeTopLeftCp",
"edgeTop",
"tipRight",
"tipRightTop",
"tipRightTopStart",
"tipRightTopCp1",
"tipRightTopCp2",
"tipRightTopEnd",
"tipRightBottomStart",
"tipRightBottomCp1",
"tipRightBottomCp2",
"tipRightBottomEnd",
"tipRightBottom",
"top",
"topCp2"
]
/*
* We're rotating all the points in
* the `rotateThese` array around
* the `edgeLeft` point.
*
* We're using increments of 1 degree
* until the `tipRightBottomStart` point
* is 1 mm beyond the center of our bib.
*/
while (points.tipRightBottomStart.x > -1) {
/_
- We're rotating all the points in
- the `rotateThese` array around
- the `edgeLeft` point.
-
- We're using increments of 1 degree
- until the `tipRightBottomStart` point
- is 1 mm beyond the center of our bib.
\*/
while (points.tipRightBottomStart.x > -1) {
for (const p of rotateThese) points[p] = points[p].rotate(1, points.edgeLeft)
}
// Add points for second strap
points.edgeTopRightCp = points.edgeTopLeftCp.flipX()
points.topCp1 = points.topCp2.flipX()
points.tipLeftTopStart = points.tipRightTopStart.flipX()
points.tipLeftTopCp1 = points.tipRightTopCp1.flipX()
points.tipLeftTopCp2 = points.tipRightTopCp2.flipX()
points.tipLeftTopEnd = points.tipRightTopEnd.flipX()
points.tipLeftBottomStart = points.tipRightBottomStart.flipX()
points.tipLeftBottomCp1 = points.tipRightBottomCp1.flipX()
points.tipLeftBottomCp2 = points.tipRightBottomCp2.flipX()
points.tipLeftBottomEnd = points.tipRightBottomEnd.flipX()
// highlight-start
/*
* Round the bottom corners
* Macros will return the auto-generated IDs
*/
const ids2 = {
bottomLeft: macro("round", {
id: "bottomLeft",
from: points.topLeft,
to: points.bottomRight,
via: points.bottomLeft,
radius: points.bottomRight.x / 4,
}),
bottomRight: macro("round", {
id: "bottomRight",
from: points.bottomLeft,
to: points.topRight,
via: points.bottomRight,
radius: points.bottomRight.x / 4,
})
}
/*
* Create points from them with easy names
*/
for (const side in ids2) {
for (const id of ['start', 'cp1', 'cp2', 'end']) {
points[`${side}${utils.capitalize(id)}`] = points[ids2[side].points[id]].copy()
}
// Add points for second strap
points.edgeTopRightCp = points.edgeTopLeftCp.flipX()
points.topCp1 = points.topCp2.flipX()
points.tipLeftTopStart = points.tipRightTopStart.flipX()
points.tipLeftTopCp1 = points.tipRightTopCp1.flipX()
points.tipLeftTopCp2 = points.tipRightTopCp2.flipX()
points.tipLeftTopEnd = points.tipRightTopEnd.flipX()
points.tipLeftBottomStart = points.tipRightBottomStart.flipX()
points.tipLeftBottomCp1 = points.tipRightBottomCp1.flipX()
points.tipLeftBottomCp2 = points.tipRightBottomCp2.flipX()
points.tipLeftBottomEnd = points.tipRightBottomEnd.flipX()
// highlight-start
/\*
- Round the bottom corners
- Macros will return the auto-generated IDs
\*/
const ids2 = {
bottomLeft: macro("round", {
id: "bottomLeft",
from: points.topLeft,
to: points.bottomRight,
via: points.bottomLeft,
radius: points.bottomRight.x / 4,
}),
bottomRight: macro("round", {
id: "bottomRight",
from: points.bottomLeft,
to: points.topRight,
via: points.bottomRight,
radius: points.bottomRight.x / 4,
})
}
/\*
- Create points from them with easy names
\*/
for (const side in ids2) {
for (const id of ['start', 'cp1', 'cp2', 'end']) {
points[`${side}${utils.capitalize(id)}`] = points[ids2[side].points[id]].copy()
}
}
// highlight-end
// Create one path for the bib outline
paths.seam = new Path()
.move(points.edgeLeft)
// strikeout-start
/* We only need to replace the start
* with the new lines below
.line(points.bottomLeft)
.line(points.bottomRight)
*/
// strikeout-end
// highlight-start
.line(points.bottomLeftStart)
.curve(points.bottomLeftCp1, points.bottomLeftCp2, points.bottomLeftEnd)
.line(points.bottomRightStart)
.curve(points.bottomRightCp1, points.bottomRightCp2, points.bottomRightEnd)
// highlight-end
.line(points.edgeRight)
.curve(
points.edgeRightCp,
points.edgeTopRightCp,
points.tipLeftTopStart
)
.curve(
points.tipLeftTopCp1,
points.tipLeftTopCp2,
points.tipLeftTopEnd
)
.curve(
points.tipLeftBottomCp1,
points.tipLeftBottomCp2,
points.tipLeftBottomEnd
)
.curve(
points.topCp1,
points.rightCp2,
points.right
)
.curve(
points.rightCp1,
points.bottomCp2,
points.bottom
)
.curve(
points.bottomCp1,
points.leftCp2,
points.left
)
.curve(
points.leftCp1,
points.topCp2,
points.tipRightBottomEnd
)
.curve(
points.tipRightBottomCp2,
points.tipRightBottomCp1,
points.tipRightBottomStart
)
.curve(
points.tipRightTopCp2,
points.tipRightTopCp1,
points.tipRightTopStart
)
.curve(
points.edgeTopLeftCp,
points.edgeLeftCp,
points.edgeLeft
)
.close()
.addClass("fabric")
// Create one path for the bib outline
paths.seam = new Path()
.move(points.edgeLeft)
// strikeout-start
/_ We only need to replace the start
_ with the new lines below
.line(points.bottomLeft)
.line(points.bottomRight)
\*/
// strikeout-end
// highlight-start
.line(points.bottomLeftStart)
.curve(points.bottomLeftCp1, points.bottomLeftCp2, points.bottomLeftEnd)
.line(points.bottomRightStart)
.curve(points.bottomRightCp1, points.bottomRightCp2, points.bottomRightEnd)
// highlight-end
.line(points.edgeRight)
.curve(
points.edgeRightCp,
points.edgeTopRightCp,
points.tipLeftTopStart
)
.curve(
points.tipLeftTopCp1,
points.tipLeftTopCp2,
points.tipLeftTopEnd
)
.curve(
points.tipLeftBottomCp1,
points.tipLeftBottomCp2,
points.tipLeftBottomEnd
)
.curve(
points.topCp1,
points.rightCp2,
points.right
)
.curve(
points.rightCp1,
points.bottomCp2,
points.bottom
)
.curve(
points.bottomCp1,
points.leftCp2,
points.left
)
.curve(
points.leftCp1,
points.topCp2,
points.tipRightBottomEnd
)
.curve(
points.tipRightBottomCp2,
points.tipRightBottomCp1,
points.tipRightBottomStart
)
.curve(
points.tipRightTopCp2,
points.tipRightTopCp1,
points.tipRightTopStart
)
.curve(
points.edgeTopLeftCp,
points.edgeLeftCp,
points.edgeLeft
)
.close()
.addClass("fabric")
return part
return part
}
```
</Example>
```

View file

@ -1,6 +1,6 @@
---
title: Shaping the straps
order: 90
sidebar_position: 90
---
Our straps should follow the neck opening, which isn't that hard to do.
@ -15,7 +15,6 @@ As always, [the API docs](/reference/api/point/) have all the details.
:::
<Example tutorial caption="All of a sudden, things are starting to look like a bib">
```design/src/bib.mjs
function draftBib({
@ -28,36 +27,38 @@ function draftBib({
part,
}) {
/*
* Construct the quarter neck opening
*/
/\*
- Construct the quarter neck opening
_/
let tweak = 1
let target = (measurements.head * options.neckRatio) /4
let target = (measurements.head _ options.neckRatio) /4
let delta
do {
points.right = new Point(
tweak * measurements.head / 10,
0
)
points.bottom = new Point(
0,
tweak * measurements.head / 12
)
points.right = new Point(
tweak _ measurements.head / 10,
0
)
points.bottom = new Point(
0,
tweak _ measurements.head / 12
)
points.rightCp1 = points.right.shift(
90,
90,
points.bottom.dy(points.right) / 2
)
points.bottomCp2 = points.bottom.shift(
0,
0,
points.bottom.dx(points.right) / 2
)
paths.quarterNeck = new Path()
.move(points.right)
.curve(
points.rightCp1,
points.bottomCp2,
points.rightCp1,
points.bottomCp2,
points.bottom
)
.hide()
@ -65,11 +66,13 @@ function draftBib({
delta = paths.quarterNeck.length() - target
if (delta > 0) tweak = tweak * 0.99
else tweak = tweak * 1.02
} while (Math.abs(delta) > 1)
/*
* Construct the complete neck opening
*/
} while (Math.abs(delta) > 1)
/\*
- Construct the complete neck opening
\*/
points.rightCp2 = points.rightCp1.flipY()
points.bottomCp1 = points.bottomCp2.flipX()
points.left = points.right.flipX()
@ -79,75 +82,81 @@ function draftBib({
points.topCp1 = points.bottomCp2.flipY()
points.topCp2 = points.bottomCp1.flipY()
paths.neck = new Path()
.move(points.top)
.curve(points.topCp2, points.leftCp1, points.left)
.curve(points.leftCp2, points.bottomCp1, points.bottom)
.curve(points.bottomCp2, points.rightCp1, points.right)
.curve(points.rightCp2, points.topCp1, points.top)
.close()
.addClass('fabric')
paths.neck = new Path()
.move(points.top)
.curve(points.topCp2, points.leftCp1, points.left)
.curve(points.leftCp2, points.bottomCp1, points.bottom)
.curve(points.bottomCp2, points.rightCp1, points.right)
.curve(points.rightCp2, points.topCp1, points.top)
.close()
.addClass('fabric')
/*
* Drawing the bib outline
*/
const width = measurements.head * options.widthRatio
const length = measurements.head * options.lengthRatio
/\*
points.topLeft = new Point(
width / -2,
points.top.y - (width / 2 - points.right.x)
)
points.topRight = points.topLeft.shift(0, width)
points.bottomLeft = points.topLeft.shift(-90, length)
points.bottomRight = points.topRight.shift(-90, length)
- Drawing the bib outline
_/
const width = measurements.head _ options.widthRatio
const length = measurements.head \* options.lengthRatio
points.topLeft = new Point(
width / -2,
points.top.y - (width / 2 - points.right.x)
)
points.topRight = points.topLeft.shift(0, width)
points.bottomLeft = points.topLeft.shift(-90, length)
points.bottomRight = points.topRight.shift(-90, length)
// strikeout-start
/*
* Remove this path
/\*
- Remove this path
paths.rect = new Path()
.move(points.topLeft)
.line(points.bottomLeft)
.line(points.bottomRight)
.line(points.topRight)
.line(points.topLeft)
.close()
.addClass('fabric')
*/
// strikeout-end
.move(points.topLeft)
.line(points.bottomLeft)
.line(points.bottomRight)
.line(points.topRight)
.line(points.topLeft)
.close()
.addClass('fabric')
\*/
// strikeout-end
// highlight-start
/*
* Shape the straps
*/
/\*
- Shape the straps
\*/
points.edgeLeft = new Point(points.topLeft.x, points.left.y)
points.edgeRight = new Point(points.topRight.x, points.right.y)
points.edgeTop = new Point(0, points.topLeft.y)
points.edgeLeftCp = points.edgeLeft.shiftFractionTowards(points.topLeft, 0.5)
points.edgeRightCp = points.edgeLeftCp.flipX()
points.edgeTopLeftCp = points.edgeTop.shiftFractionTowards(
points.topLeft,
0.5
)
points.edgeTopRightCp = points.edgeTopLeftCp.flipX()
points.edgeLeftCp = points.edgeLeft.shiftFractionTowards(points.topLeft, 0.5)
points.edgeRightCp = points.edgeLeftCp.flipX()
points.edgeTopLeftCp = points.edgeTop.shiftFractionTowards(
points.topLeft,
0.5
)
points.edgeTopRightCp = points.edgeTopLeftCp.flipX()
/*
* Now, adapt our `rect` path so it's no longer a rectangle:
*/
/\*
- Now, adapt our `rect` path so it's no longer a rectangle:
\*/
paths.rect = new Path()
.move(points.edgeTop)
.curve(points.edgeTopLeftCp, points.edgeLeftCp, points.edgeLeft)
.line(points.bottomLeft)
.line(points.bottomRight)
.line(points.edgeRight)
.curve(points.edgeRightCp, points.edgeTopRightCp, points.edgeTop)
.close()
.move(points.edgeTop)
.curve(points.edgeTopLeftCp, points.edgeLeftCp, points.edgeLeft)
.line(points.bottomLeft)
.line(points.bottomRight)
.line(points.edgeRight)
.curve(points.edgeRightCp, points.edgeTopRightCp, points.edgeTop)
.close()
// highlight-end
return part
return part
}
```
</Example>
```