wip: Rewrite tutorial for v3
This commit is contained in:
parent
7487f1f449
commit
32d6e938df
15 changed files with 349 additions and 303 deletions
|
@ -4,6 +4,8 @@
|
|||
"p": {
|
||||
"bib": "Bib"
|
||||
},
|
||||
"s": {},
|
||||
"s": {
|
||||
"finishWithBiasTape": "Finish with bias tape"
|
||||
},
|
||||
"o": {}
|
||||
}
|
||||
|
|
|
@ -173,7 +173,7 @@ export const bib = {
|
|||
paths.bias = paths.seam
|
||||
.offset(-5)
|
||||
.attr('class', 'various dashed')
|
||||
.attr('data-text', 'finishWithBiasTape')
|
||||
.attr('data-text', 'tutorial:finishWithBiasTape')
|
||||
.attr('data-text-class', 'center fill-various')
|
||||
|
||||
// Add the title
|
||||
|
|
|
@ -13,11 +13,12 @@ export const step1 = {
|
|||
snippets,
|
||||
complete,
|
||||
sa,
|
||||
store,
|
||||
paperless,
|
||||
macro,
|
||||
part,
|
||||
}) => {
|
||||
let w = 500 * options.size
|
||||
const w = 500 * options.size
|
||||
points.topLeft = new Point(0, 0)
|
||||
points.topRight = new Point(w, 0)
|
||||
points.bottomLeft = new Point(0, w / 2)
|
||||
|
@ -32,33 +33,33 @@ export const step1 = {
|
|||
.close()
|
||||
.attr('class', 'fabric')
|
||||
|
||||
// Complete?
|
||||
if (complete) {
|
||||
if (sa) paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
|
||||
/*
|
||||
* Annotations
|
||||
*/
|
||||
|
||||
// Cutlist
|
||||
store.cutlist.setCut({ cut: 1, from: 'fabric' })
|
||||
|
||||
// Logo & Hello
|
||||
points.logo = points.topLeft.shiftFractionTowards(points.bottomRight, 0.5)
|
||||
snippets.logo = new Snippet('logo', points.logo)
|
||||
points.text = points.logo
|
||||
.shift(-90, w / 8)
|
||||
.attr('data-text', 'hello')
|
||||
.attr('data-text-class', 'center')
|
||||
|
||||
if (sa) {
|
||||
paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
|
||||
}
|
||||
}
|
||||
if (complete) points.text = points.logo.shift(-90, w / 8).addText('hello', 'center')
|
||||
|
||||
// Paperless?
|
||||
if (paperless) {
|
||||
//Dimensions
|
||||
macro('hd', {
|
||||
id: 'width',
|
||||
from: points.bottomLeft,
|
||||
to: points.bottomRight,
|
||||
y: points.bottomLeft.y + sa + 15,
|
||||
})
|
||||
macro('vd', {
|
||||
id: 'height',
|
||||
from: points.bottomRight,
|
||||
to: points.topRight,
|
||||
x: points.topRight.x + sa + 15,
|
||||
})
|
||||
}
|
||||
|
||||
return part
|
||||
},
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
title: Design guide
|
||||
---
|
||||
|
||||
This short guide will illustrate and explain how designs work in FreeSewing.
|
||||
Not to be confused with how sewing patterns work — although there are [great books
|
||||
about that](https://www.assembil.com/how-patterns-work-book/) if you're
|
||||
interested — it's about what goes on under the hood each time a sewing
|
||||
Hi there and welcome to this guide that explains how FreeSewing designs work.
|
||||
|
||||
|
||||
it's about what goes on under the hood each time a sewing
|
||||
pattern is generated by FreeSewing.
|
||||
|
||||
This illustration is a good starting point to gain a better
|
||||
|
@ -185,10 +185,11 @@ understanding of the structure of a FreeSewing design:
|
|||
```
|
||||
</Example>
|
||||
|
||||
If it looks like _a lot_ don't despair. There's a lot of repetition, and we'll
|
||||
work through the building blocks step by step.
|
||||
If it looks like _a lot_ don't despair. I included all the info on the
|
||||
graphical overview, but most of it you can safely ignore and consider _under
|
||||
the hood_ unless you want to do some really advanced things with FreeSewing.
|
||||
|
||||
If we look at our image, it can be divided into three areas:
|
||||
If we look at our image through squinted eyes, we can identify three areas:
|
||||
|
||||
- The[ **Settings**](#the-settings) on the left
|
||||
- The[ **Render stage**](#rendering-your-pattern) on the right
|
||||
|
|
|
@ -3,68 +3,53 @@ title: Adding measurements
|
|||
order: 130
|
||||
---
|
||||
|
||||
FreeSewing is all about _made-to-measure_ sewing patterns;
|
||||
we are going to draft our pattern according to the measurements provided to us.
|
||||
FreeSewing is all about _made-to-measure_ 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.
|
||||
|
||||
Which begs the question, which measurements?
|
||||
|
||||
It is we, as the pattern designers, who decide which measurements are used
|
||||
to draft our pattern. For our bib, the only measurement we need is the
|
||||
As the pattern designers, you get to decide which measurements are used
|
||||
to draft the pattern. For this bib, I am going to use the
|
||||
_head circumference_.
|
||||
|
||||
So let's add it as a required measurement.
|
||||
|
||||
## Adding required measurements
|
||||
|
||||
In our `design/src/bib.mjs` file, on the `bib` object, there is a key called
|
||||
`measurements` (line 121) that will hold a list (an array) of all required measurements
|
||||
for this part.
|
||||
In our `design/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.
|
||||
|
||||
We are going to use [*the official name* of the measurement](/reference/measurements). For head
|
||||
I am usign [*the official name* of the measurement](/reference/measurements) here. For head
|
||||
circumference, that name is `head`.
|
||||
|
||||
```design/src/bib.mjs
|
||||
function draftBib({ part }) {
|
||||
function draftBib({ part }) => {
|
||||
return part
|
||||
}
|
||||
|
||||
export const bib = {
|
||||
name: 'tutorial.bib',
|
||||
draft: draftBib,
|
||||
from: false,
|
||||
hide: {
|
||||
self: false,
|
||||
from: false,
|
||||
after: false
|
||||
},
|
||||
options: {},
|
||||
// start-highlight
|
||||
// highlight-start
|
||||
measurements: [ 'head' ],
|
||||
// end-highlight
|
||||
optionalMeasurements: [],
|
||||
plugins: []
|
||||
// highlight-end
|
||||
}
|
||||
```
|
||||
|
||||
Now everybody knows this part requires the `head` measurement.
|
||||
From now on, this part requires the `head` measurement.
|
||||
|
||||
This change will also get picked up by the development environment, and we'll now see this screen:
|
||||
|
||||

|
||||
|
||||
Since it's just one measurement, let's simply enter a value by hand.
|
||||
This change will also get picked up by the development environment, which will now complain that it is missing some measurements.
|
||||
Since it's just one measurement, I will simply enter a value by hand.
|
||||
For example `38` as 38 cm is a realistic head circumference measurement for a baby.
|
||||
|
||||
Enter `38` in the box, and click on **Draft Design** in the sidebar under the **View** heading.
|
||||
This brings us back to our work in progress:
|
||||
<Tip>
|
||||
|
||||
##### Why using standard measurements names matters
|
||||
|
||||
## Notes
|
||||
|
||||
### Why using standard measurements names matters
|
||||
|
||||
In principle, we can use any name we want for our measurements.
|
||||
Our core library really doesn't care.
|
||||
In principle, I can use any name I want for our measurements.
|
||||
The FreeSewing core library does not care.
|
||||
|
||||
However, if everybody uses their own (names for) measurements, then people
|
||||
aren't able to re-use their measurements across designs.
|
||||
|
@ -73,5 +58,7 @@ So if you have any intention at all to play nice with the FreeSewing ecosystem,
|
|||
please make sure to re-use the names of existing measurements, rather than
|
||||
invent your own.
|
||||
|
||||
See our [best practices](/guides/best-practices/reuse-measurements) on this
|
||||
See the [best practices](/guides/best-practices/reuse-measurements) on this
|
||||
topic for details.
|
||||
|
||||
</Tip>
|
||||
|
|
|
@ -3,65 +3,78 @@ title: Adding options
|
|||
order: 140
|
||||
---
|
||||
|
||||
We know what our bib should look like, and we have the _head_ measurement
|
||||
to work with. But there's still a number of choices we have to make:
|
||||
I have shown what our bib should look like, and added the _head_ measurement
|
||||
to work with. But there's still a number of choices I have to make:
|
||||
|
||||
- How large should the neck opening be?
|
||||
- How wide should the bib be?
|
||||
- How long should the bib be?
|
||||
|
||||
We can make all of these choices for the user and set them in stone, so to speak.
|
||||
I could make all of these choices for the user and set them in stone, so to speak.
|
||||
|
||||
But since we're designing a pattern in code, it's trivial to make our pattern
|
||||
flexible and let the user decide. All we have to do is add options to our part.
|
||||
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.
|
||||
|
||||
## Add the neckRatio option
|
||||
|
||||
The first option we're going to add controls the ratio between the neck opening
|
||||
The first option I will add controls the ratio between the neck opening
|
||||
and the head circumference. Let's call it `neckRatio`.
|
||||
|
||||
We'll add a new `options` key to our part object for this:
|
||||
For this, I will add the `options` property to our `bib` object:
|
||||
|
||||
```design/src/bib.mjs
|
||||
function draftBib({ part }) {
|
||||
|
||||
function draftBib({ part }) => {
|
||||
return part
|
||||
}
|
||||
|
||||
export const bib = {
|
||||
|
||||
name: 'tutorial.bib',
|
||||
draft: draftBib,
|
||||
from: false,
|
||||
hide: {
|
||||
self: false,
|
||||
from: false,
|
||||
after: false
|
||||
},
|
||||
measurements: [ 'head' ],
|
||||
// highlight-start
|
||||
options: {
|
||||
neckRatio: { pct: 80, min: 70, max: 90, menu: 'fit' },
|
||||
neckRatio: {
|
||||
pct: 80,
|
||||
min: 70,
|
||||
max: 90,
|
||||
menu: 'fit'
|
||||
},
|
||||
},
|
||||
// highlight-end
|
||||
measurements: [],
|
||||
optionalMeasurements: [],
|
||||
plugins: []
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Can you guess what it means?
|
||||
|
||||
- We've added a option of type percentage
|
||||
- We've added the `options` property to our `bib` object
|
||||
- On the `options` property, we have added `neckRatio` which holds the configuration for our option
|
||||
- It is a `pct` option -- whcih means it's a percentage
|
||||
- Its default value is 90%
|
||||
- Its minimum value is 70%
|
||||
- Its maximum value is 90%
|
||||
- Its default value is 80%
|
||||
- We've added this option to the *fit* menu
|
||||
|
||||
There are different types of options, but percentages are by far the most common ones.
|
||||
They are all documented [in the part reference docs](/reference/api/part/config/options).
|
||||
|
||||
<Note>
|
||||
|
||||
There are different types of options, but percentages are the most common ones.
|
||||
They are all documented [in the part reference docs](/reference/api/part/config/options).
|
||||
##### What is `menu` and why should you care?
|
||||
|
||||
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 FreeSewing's development
|
||||
environment which will use this to build a menu structure for the various
|
||||
options.
|
||||
|
||||
Each option type has a number of required properties. But in addition to that,
|
||||
you can add more to facilitate integrating with a front-end or other user
|
||||
interface.
|
||||
|
||||
You will see that after adding this option, the development environment will
|
||||
have a `fit` section under **Design Options**. This `menu` property is where
|
||||
that is based on.
|
||||
|
||||
</Note>
|
||||
|
||||
|
@ -70,25 +83,43 @@ They are all documented [in the part reference docs](/reference/api/part/config/
|
|||
Let's do something similar for the width and length of our bib:
|
||||
|
||||
```design/src/bib.mjs
|
||||
function draftBib({ part }) => {
|
||||
return part
|
||||
}
|
||||
|
||||
export const bib = {
|
||||
name: 'tutorial.bib',
|
||||
draft: draftBib,
|
||||
measurements: [ 'head' ],
|
||||
options: {
|
||||
neckRatio: { pct: 80, min: 70, max: 90, menu: 'fit' },
|
||||
widthRatio: { pct: 45, min: 35, max: 55, menu: 'style' },
|
||||
lengthRatio: { pct: 75, min: 55, max: 85, menu: 'style' },
|
||||
neckRatio: {
|
||||
pct: 80,
|
||||
min: 70,
|
||||
max: 90,
|
||||
menu: 'fit'
|
||||
},
|
||||
// highlight-start
|
||||
widthRatio: {
|
||||
pct: 45,
|
||||
min: 35,
|
||||
max: 55,
|
||||
menu: 'style'
|
||||
},
|
||||
lengthRatio: {
|
||||
pct: 75,
|
||||
min: 55,
|
||||
max: 85,
|
||||
menu: 'style'
|
||||
},
|
||||
// highlight-end
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
- We've added `widthRatio` and `lengthRatio` options
|
||||
- We've given all options sensible defaults
|
||||
- We've given all options sensible maximum and minimum boundaries
|
||||
- We've added these two new options to the *style* menu
|
||||
This pretty much the exact same thing, except that are placing this in the `style` menu.
|
||||
|
||||
Later, we'll test-drive our pattern to see how it behaves when we adapt the options
|
||||
between their minimum and maximum values. At that time, we can still tweak these values.
|
||||
Later, I will test-drive our pattern to see how it behaves when we adapt the options
|
||||
between their minimum and maximum values. At that time, I may need to tweak these values.
|
||||
|
||||
With that out of the way, let's start drawing our bib.
|
||||
With that out of the way, I will start drawing the bib.
|
||||
|
||||
## Notes
|
||||
|
||||
The `menu` key on an option does not do anything for our pattern as such.
|
||||
Instead it signals to the frontend that this is how options should be grouped
|
||||
together and presented to the user.
|
||||
|
|
|
@ -7,49 +7,7 @@ Time to turn our attention to the draft method of our part.
|
|||
Inside our `design/src/bib.mjs` file, this is what it currently looks like:
|
||||
|
||||
```design/src/bib.mjs
|
||||
function draftBib ({
|
||||
// Uncomment below to destructure what you need
|
||||
/*
|
||||
* Content constructors
|
||||
*/
|
||||
//Path, // A Path constructor to create new paths
|
||||
//Point, // A Point constructor to create new points
|
||||
//Snippet, // A Snippet constructor to create new snippets
|
||||
/*
|
||||
* Content constainers
|
||||
*/
|
||||
//paths, // Add a Path to your part by adding it to this object
|
||||
//points, // Add a Points to your part by adding it to this object
|
||||
//snippets, // Add a Snippet to your part by adding it to this object
|
||||
/*
|
||||
* Access to settings
|
||||
*/
|
||||
//absoluteOptions, // Access to settings.absoluteOptions
|
||||
//complete, // Access to settings.complete
|
||||
//measurements, // Access to settings.measurements
|
||||
//options, // Access to settings.options
|
||||
//paperless, // Access to settings.paperless
|
||||
//sa, // Access to settings.sa
|
||||
//scale, // Access to settings.scale
|
||||
/*
|
||||
* Access to utilities
|
||||
*/
|
||||
//getId, //See the getId documentation
|
||||
//hide, //See the hide documentation
|
||||
//log, //See the logging documentation
|
||||
//macro, //See the macros documentation
|
||||
//setHidden, //See the setHidden documentation
|
||||
//store, //See the store documentation
|
||||
//unhide, //See the unhide documentation
|
||||
//units, //See the units documentation
|
||||
///utils, //See the utils documentation
|
||||
/*
|
||||
* Return value
|
||||
*/
|
||||
part, // Your draft method must return this
|
||||
}) {
|
||||
|
||||
// Work your magic here
|
||||
function draftBib({ part }) => {
|
||||
return part
|
||||
}
|
||||
```
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
title: Pattern design tutorial
|
||||
---
|
||||
|
||||
Welcome to the FreeSewing pattern design tutorial, where we'll learn how to
|
||||
design a made-to-measure sewing pattern, start to finish.
|
||||
Hello there, and welcome to this FreeSewing pattern design tutorial.
|
||||
My name is Joost, and in this tutorial I will show you
|
||||
how to design a made-to-measure sewing pattern, start to finish.
|
||||
|
||||
<Tip>
|
||||
##### Before you start
|
||||
|
@ -13,11 +14,11 @@ guide](/guides/prerequisites). It's very short, but covers some basic
|
|||
terminology and concepts that we'll use throughout this guide.
|
||||
</Tip>
|
||||
|
||||
We will be designing a pattern for a baby bib. It's a very simple pattern, but
|
||||
that's the point. Our focus today is on learning FreeSewing and how to
|
||||
translate our designs into code.
|
||||
I will be designing a pattern for a baby bib. It's a very simple pattern, but
|
||||
that's ok. It is a tutorial after all. This will give us plenty to work with.
|
||||
|
||||
At the end of this tutorial, we will have created this pattern:
|
||||
At the end of this tutorial, I will have created this pattern, and if you
|
||||
follow along, so will you:
|
||||
|
||||
|
||||
<Example tutorial="1" previewFirst="1" caption="Our end result">
|
||||
|
@ -30,13 +31,16 @@ function draftBib({
|
|||
measurements,
|
||||
options,
|
||||
macro,
|
||||
store,
|
||||
complete,
|
||||
snippets,
|
||||
Snippet,
|
||||
part,
|
||||
}) {
|
||||
|
||||
// Construct the quarter neck opening
|
||||
/*
|
||||
* Construct the quarter neck opening
|
||||
*/
|
||||
let tweak = 1
|
||||
let target = (measurements.head * options.neckRatio) /4
|
||||
let delta
|
||||
|
@ -57,7 +61,9 @@ function draftBib({
|
|||
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()
|
||||
|
@ -67,7 +73,9 @@ function draftBib({
|
|||
points.topCp1 = points.bottomCp2.flipY()
|
||||
points.topCp2 = points.bottomCp1.flipY()
|
||||
|
||||
// Drawing the bib outline
|
||||
/*
|
||||
* Drawing the bib outline
|
||||
*/
|
||||
const width = measurements.head * options.widthRatio
|
||||
const length = measurements.head * options.lengthRatio
|
||||
|
||||
|
@ -92,7 +100,9 @@ function draftBib({
|
|||
)
|
||||
points.edgeTopRightCp = points.edgeTopLeftCp.flipX()
|
||||
|
||||
// Round the straps
|
||||
/*
|
||||
* Round the straps
|
||||
*/
|
||||
const strap = points.edgeTop.dy(points.top)
|
||||
|
||||
points.tipRight = points.edgeTop.translate(strap / 2, strap / 2)
|
||||
|
@ -132,10 +142,14 @@ function draftBib({
|
|||
for (const p of rotateThese) points[p] = points[p].rotate(1, points.edgeLeft)
|
||||
}
|
||||
|
||||
// Snap anchor
|
||||
/*
|
||||
* Snap anchor
|
||||
*/
|
||||
points.snapLeft = points.top.shiftFractionTowards(points.edgeTop, 0.5)
|
||||
|
||||
// Add points for second strap
|
||||
/*
|
||||
* Add points for second strap
|
||||
*/
|
||||
points.edgeTopRightCp = points.edgeTopLeftCp.flipX()
|
||||
points.topCp1 = points.topCp2.flipX()
|
||||
points.tipLeftTopStart = points.tipRightTopStart.flipX()
|
||||
|
@ -148,7 +162,9 @@ function draftBib({
|
|||
points.tipLeftBottomEnd = points.tipRightBottomEnd.flipX()
|
||||
points.snapRight = points.snapLeft.flipX()
|
||||
|
||||
// Round the bottom corners
|
||||
/*
|
||||
* Round the bottom corners
|
||||
*/
|
||||
macro("round", {
|
||||
from: points.topLeft,
|
||||
to: points.bottomRight,
|
||||
|
@ -164,7 +180,9 @@ function draftBib({
|
|||
prefix: "bottomRight"
|
||||
})
|
||||
|
||||
// Create one path for the bib outline
|
||||
/*
|
||||
* Create one path for the bib outline
|
||||
*/
|
||||
paths.seam = new Path()
|
||||
.move(points.edgeLeft)
|
||||
.line(points.bottomLeftStart)
|
||||
|
@ -185,20 +203,31 @@ function draftBib({
|
|||
.close()
|
||||
.addClass("fabric")
|
||||
|
||||
if (complete) {
|
||||
// Add snaps
|
||||
points.snapLeft = points.top
|
||||
.shiftFractionTowards(points.edgeTop, 0.5)
|
||||
/*
|
||||
* Mark the bias tape, but only if complete is set
|
||||
*/
|
||||
if (complete) paths.bias = paths.seam
|
||||
.offset(-5)
|
||||
.addClass("various dashed")
|
||||
.addText("finishWithBiasTape", "center fill-various")
|
||||
/*
|
||||
* Annotations
|
||||
*/
|
||||
|
||||
// Cutlist
|
||||
store.cutlist.setCut({ cut: 1, from: 'fabric' })
|
||||
|
||||
// Snaps
|
||||
points.snapLeft = points.top.shiftFractionTowards(points.edgeTop, 0.5)
|
||||
points.snapRight = points.snapLeft.flipX()
|
||||
snippets.snapStud = new Snippet('snap-stud', points.snapLeft)
|
||||
snippets.snapSocket = new Snippet('snap-socket', points.snapRight)
|
||||
.attr('opacity', 0.5)
|
||||
snippets.snapSocket = new Snippet('snap-socket', points.snapRight).attr('opacity', 0.5)
|
||||
|
||||
// Add a logo
|
||||
// Logo
|
||||
points.logo = new Point(0, 0)
|
||||
snippets.logo = new Snippet("logo", points.logo)
|
||||
|
||||
// Add a title
|
||||
// Title
|
||||
points.title = points.bottom.shift(-90, 45)
|
||||
macro("title", {
|
||||
at: points.title,
|
||||
|
@ -207,40 +236,33 @@ function draftBib({
|
|||
scale: 0.7
|
||||
})
|
||||
|
||||
// Add a scalbox
|
||||
// Scalbox
|
||||
points.scalebox = points.title.shift(-90, 55)
|
||||
macro("scalebox", { at: points.scalebox })
|
||||
|
||||
paths.bias = paths.seam
|
||||
.offset(-5)
|
||||
.addClass("various dashed")
|
||||
.addText("finishWithBiasTape", "center fill-various")
|
||||
|
||||
}
|
||||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
|
||||
Before we can get started, let's make sure we have the required software
|
||||
installed on our computer:
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before I can get started, I want to make sure I have the required software
|
||||
installed on my computer.
|
||||
|
||||
FreeSewing is a JavaScript library that can run in the browser, on
|
||||
[Node.js](https://nodejs.org/), or a variety of other runtimes such as Deno,
|
||||
AWS Lambda, and so on.
|
||||
[Node.js](https://nodejs.org/), or a variety of other runtimes such as Bun,
|
||||
Deno, AWS Lambda, and so on.
|
||||
|
||||
For development, we'll use Node.js. If we don't have Node.js on our system,
|
||||
follow the link above and install it on our system.
|
||||
For development, I will use Node.js. If you don't have Node.js on our system,
|
||||
follow the link above and install it.
|
||||
|
||||
<Tip compact>We need Node.js 16 or higher to use FreeSewing</Tip>
|
||||
<Tip compact>You need Node.js 18 (lts/hydrogen) or higher to use FreeSewing</Tip>
|
||||
|
||||
When we're done, we can test whether it works by running:
|
||||
To test whether NodeJS is installed, and see it's version, you can run this command:
|
||||
|
||||
```sh
|
||||
node -v
|
||||
```
|
||||
|
||||
If we get the Node.js version number, we're all set.
|
||||
If you get the Node.js version number, that means NodeJs is installed. Yay!
|
||||
|
|
|
@ -3,42 +3,45 @@ title: Setting up the development environment
|
|||
order: 100
|
||||
---
|
||||
|
||||
Open a terminal and enter the following command:
|
||||
FreeSewing provides a development environment that visualizes your design for you.
|
||||
|
||||
To set it up, I will open a terminal and enter the following command:
|
||||
|
||||
```sh
|
||||
npx @freesewing/new-design@next
|
||||
```
|
||||
<Fixme compact>Remove `@next` suffix once v3 is in production</Fixme>
|
||||
|
||||
We'll be asked some questions.
|
||||
It will ask some questions.
|
||||
All the defaults will do, but here are the details:
|
||||
|
||||
- *What template would you like to use?* — Pick the default: **Tutorial**
|
||||
- *What package manager should we use?* — Pick the default: **npm**, unless you are certain you have **yarn** installed
|
||||
|
||||
After we've answered these questions, files will be copied, dependencies installed, and components downloaded.
|
||||
After answering these questions, files will be copied, dependencies installed, and requirements downloaded.
|
||||
|
||||
<Note>
|
||||
|
||||
This will take a few minutes because we're loading some software for our development environment.
|
||||
This will take a few minutes because the development environment has a number
|
||||
of dependencies that need to be downloaded.
|
||||
|
||||
</Note>
|
||||
|
||||
When it's ready, enter the `tutorial` directory that was just created and run `npm run dev`:
|
||||
When it's ready, you can enter the `tutorial` directory that was just created and run `npm run dev`:
|
||||
|
||||
```sh
|
||||
cd tutorial
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Or if we chose to use yarn as package manager:
|
||||
Or if you want to use yarn as package manager:
|
||||
|
||||
```sh
|
||||
cd tutorial
|
||||
yarn dev
|
||||
```
|
||||
|
||||
Now open our browser at http://localhost:8000
|
||||
Now open a browser and go to http://localhost:8000
|
||||
|
||||
If all goes well, we'll should see this landing page:
|
||||
|
||||
|
@ -48,5 +51,6 @@ If all goes well, we'll should see this landing page:
|
|||
|
||||
### Need help?
|
||||
|
||||
If you run into any issues, [join our **#development-help** chat room on on
|
||||
Discord](https://discord.freesewing.org/) and we'll figure it out together.
|
||||
If you run into any issues, head over to [FreeSewing.org/support](https://next.freesewing.org/support)
|
||||
which lists the various ways in which you can get help.
|
||||
|
||||
|
|
|
@ -1,77 +1,84 @@
|
|||
---
|
||||
title: Our first part
|
||||
title: Creating a part
|
||||
order: 120
|
||||
---
|
||||
|
||||
Much like garments themselves, patterns are made up of _parts_.
|
||||
Most patterns will have multiple parts. A sleeve, a back part, the collar, and
|
||||
so on. Our pattern is very simple, and only has one part: the bib.
|
||||
so on. The pattern you create today is very simple, and only has one part: the bib.
|
||||
|
||||
It's a good idea to keep each part in its own file. We don't *have to* do
|
||||
this, but it's a good habit to get into. When we create more elaborate designs
|
||||
with multiple parts, keeping each in its own file makes for a more tidy
|
||||
and approachable code base.
|
||||
<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.
|
||||
|
||||
</Tip>
|
||||
|
||||
## bib.mjs
|
||||
|
||||
The previous step has already set everything up for us. Our design's main file
|
||||
lives in `design/src/index.mjs`, and our part lives in `design/src/bib.mjs`.
|
||||
Since I chose the `tutorial` preset, the development environment is preconfigured for this tutorial.
|
||||
|
||||
This `bib.mjs` is where we'll do all our work. The file includes a comments to guide you on how to use it. We removed those for clarity in our example. It currently looks like this:
|
||||
The design's main file lives in `design/src/index.mjs`, and the bib part lives in `design/src/bib.mjs`.
|
||||
|
||||
This `bib.mjs` is where I will be doing most of the work.
|
||||
The file that was created includes a lot of comments to provide guidance to those not using this tutorial.
|
||||
I have removed those comments from the inline examples in this tutorial for clarity in our example.
|
||||
|
||||
The `bib.mjs` file currently looks like this:
|
||||
|
||||
```design/src/bib.mjs
|
||||
import { pluginBundle } from "@freesewing/plugin-bundle"
|
||||
|
||||
function draftBib ({
|
||||
part, // Your draft method must return this
|
||||
})
|
||||
{
|
||||
// Work your magic here
|
||||
/*
|
||||
* This function drafts the part
|
||||
*/
|
||||
function draftBib ({ part }) => {
|
||||
return part
|
||||
}
|
||||
export const bib = {
|
||||
|
||||
/*
|
||||
* This is the part object
|
||||
*/
|
||||
export const bib = {
|
||||
name: 'tutorial.bib',
|
||||
draft: draftBib,[],
|
||||
from: false,
|
||||
hide: {
|
||||
self: false,
|
||||
from: false,
|
||||
after: false
|
||||
},
|
||||
options: {},
|
||||
measurements: [],
|
||||
optionalMeasurements: [],
|
||||
plugins: [ pluginBundle ]
|
||||
draft: draftBib,
|
||||
}
|
||||
```
|
||||
|
||||
### The part object
|
||||
|
||||
Each part in FreeSewing is an object that describes everything there is to know about the part.
|
||||
Each part in FreeSewing is an object that describes the part, and has a `draft`
|
||||
method to do the actual work of drafting the part.
|
||||
|
||||
The only mandatory keys on a part object are `name` and `draft`.
|
||||
|
||||
<Related>
|
||||
|
||||
Refer to [the part reference documentation](/reference/api/part) for
|
||||
all details about configuring the part object
|
||||
</Related>
|
||||
|
||||
<Note>
|
||||
|
||||
A design in FreeSewing is a thin wrapper around a collection of parts.
|
||||
Each parts stands on its own, and parts from various designs can be combined
|
||||
to create other designs.
|
||||
</Note>
|
||||
|
||||
|
||||
#### The part name
|
||||
|
||||
```design/src/bib.mjs
|
||||
name: 'tutorial.bib',
|
||||
```
|
||||
|
||||
A part's `name` should be unique in a pattern. Apart from that, anything goes.
|
||||
Although we probably want to give it a sensible name.
|
||||
A part's `name` should be unique in a design. I used `tutorial.bib` as the
|
||||
name, because that makes sense.
|
||||
|
||||
As we can see in the example above, we're using `tutorial.bib` as the name.
|
||||
<Warning>
|
||||
|
||||
<Tip>
|
||||
We **strongly** recommend that you follow this `design.part` naming scheme to avoid
|
||||
naming conflicts when mixing parts from various designs to create new designs.
|
||||
</Tip>
|
||||
I **strongly** recommend that you apply the same `designName.partName` naming scheme in all your parts.
|
||||
This avoids naming conflicts when mixing parts from various designs to create a new design.
|
||||
|
||||
</Warning>
|
||||
|
||||
#### The part's draft method
|
||||
|
||||
|
@ -81,7 +88,8 @@ naming conflicts when mixing parts from various designs to create new designs.
|
|||
|
||||
The second mandatory key on the part object is `draft` which should hold the method that drafts the part.
|
||||
|
||||
In our example above, it refers to the `draftBib` function we defined at the top of the file.
|
||||
In the example above, it refers to the `draftBib` function that was defined at the top of the same `bib.mjs` file.
|
||||
|
||||
For now this function doesn't do much, but that will change soon enough.
|
||||
|
||||
<Note>
|
||||
|
@ -99,56 +107,76 @@ to get started. Or, read on for an explanation of what's going on in the
|
|||
</Tip>
|
||||
|
||||
The `index.mjs` file is already complete and we won't be making any changes to
|
||||
it. But for those who are curious about what's going on inside `index.mjs`,
|
||||
we're including a version with comments below:
|
||||
it. But if you are curious about what's going on inside `index.mjs`,
|
||||
this is all we need:
|
||||
|
||||
```design/src/index.mjs
|
||||
/*
|
||||
* Import the `Design` constructor
|
||||
* from the FreeSewing core library
|
||||
*
|
||||
* This Design constructor is a method
|
||||
* (also known as a function)
|
||||
* that creates a new Design
|
||||
*/
|
||||
import { Design } from '@freesewing/core'
|
||||
/*
|
||||
* Import the `bib` part from the bib.mjs file
|
||||
* in the same folder as this index.mjs file
|
||||
*
|
||||
* This is the part we'll be working on
|
||||
* in this tutorial
|
||||
*/
|
||||
import { bib } from './bib.mjs'
|
||||
import { i18n } from '../i18n/index.mjs'
|
||||
|
||||
/*
|
||||
* Create a new Pattern by passing
|
||||
* a configuration object
|
||||
* to the Design constructor
|
||||
*/
|
||||
const Pattern = new Design({
|
||||
/*
|
||||
* This `data` key is optional, but we
|
||||
* typically add a name and version here
|
||||
*/
|
||||
data: {
|
||||
name: "Tutorial",
|
||||
},
|
||||
/*
|
||||
* This `parts` key is the most important thing
|
||||
* It holds a list of `parts` for our Design.
|
||||
* A Pattern/Design is in the end not much more
|
||||
* than a collection of parts.
|
||||
*/
|
||||
const Tutorial = new Design({
|
||||
parts: [ bib ],
|
||||
})
|
||||
|
||||
/*
|
||||
* We are exporting our Pattern
|
||||
* (so others can use it)
|
||||
* but we also (re-)export our bib part
|
||||
* this allows others to re-use it
|
||||
* in their own designs
|
||||
*/
|
||||
export { bib, Pattern }
|
||||
export { bib, Tutorial, i18n }
|
||||
```
|
||||
|
||||
If you are familiar with Javascript, I hope you are happy to see that FreeSewing uses ESM modules, and named exports.
|
||||
|
||||
If you are not familiar with Javascript, these `import` statements are how we load code from other files.
|
||||
There's three of them:
|
||||
|
||||
```design/src/index.mjs
|
||||
import { Design } from '@freesewing/core'
|
||||
```
|
||||
|
||||
This loads the `Design` constructure from FreeSewing's core library.
|
||||
A constructor is a function that creates something. So the `Design` constructor creates a Design.
|
||||
|
||||
```design/src/index.mjs
|
||||
import { bib } from './bib.mjs'
|
||||
```
|
||||
|
||||
This loads the `bib` part from the `bib.mjs` file in the same folder.
|
||||
This is what we will be working on.
|
||||
|
||||
```design/src/index.mjs
|
||||
import { i18n } from '../i18n/index.mjs'
|
||||
```
|
||||
|
||||
And this loads something named `i18n` from the `index.mjs` file in the `i18n`
|
||||
folder that's one level higher. These are the translations.
|
||||
|
||||
I will show you how you can provide translations for your designs towards the
|
||||
end of this tutorial.
|
||||
|
||||
```design/src/index.mjs
|
||||
const Tutorial = new Design({
|
||||
parts: [ bib ],
|
||||
})
|
||||
```
|
||||
|
||||
This is where the magic happens. We create a new Design by passing the Design
|
||||
constructure a configuration object. All it holds is the `parts` key that is
|
||||
an array of our parts.
|
||||
|
||||
Which goes to show that a design isn't much more than a bunch of parts.
|
||||
|
||||
```design/src/index.mjs
|
||||
export { bib, Tutorial, i18n }
|
||||
```
|
||||
|
||||
And then all that's left to do is export things so that people can use them.
|
||||
These are named exports. We are exporting three things:
|
||||
|
||||
- `Tutorial` is our complete design. Exporting it means people can use it.
|
||||
- `bib` is our part. We are exporting it so people can re-use just this part.
|
||||
- `i18n` are the translations. We are exporting it so people can load them when using our Tutorial.
|
||||
|
||||
<Related>
|
||||
|
||||
Refer to [the design reference documentation](/reference/api/design) for
|
||||
all details about what you can pass to the Design constructor.
|
||||
</Related>
|
||||
|
||||
|
|
|
@ -6,6 +6,9 @@ order: 110
|
|||
Inside our `tutorial` folder, the `design/src` folder holds the source code for
|
||||
the new pattern we will create.
|
||||
|
||||
If you want to support internationalization in your design, your translations
|
||||
go in the `design/i18n` folder.
|
||||
|
||||
We can safely ignore all other files and folders, as they are part of the
|
||||
FreeSewing development environment.
|
||||
So feel free to skip ahead to [Our first part](/tutorials/pattern-design/our-first-part).
|
||||
|
|
|
@ -99,7 +99,7 @@ export default DocsPage
|
|||
export async function getStaticProps({ params }) {
|
||||
return {
|
||||
props: {
|
||||
...(await serverSideTranslations('en', ['docs', ...ns])),
|
||||
...(await serverSideTranslations('en', ['docs', 'tutorial', ...ns])),
|
||||
slug: params.slug.join('/'),
|
||||
page: {
|
||||
locale: 'en',
|
||||
|
|
|
@ -7,7 +7,7 @@ export const MdxWrapper = ({ title = false, path, language, children, noFooter =
|
|||
return (
|
||||
<>
|
||||
{title ? <h1>{title}</h1> : null}
|
||||
<div className="text-primary mdx text-base-content text-base">{children}</div>
|
||||
<div className="mdx text-base-content">{children}</div>
|
||||
{noFooter ? null : (
|
||||
<div
|
||||
className={`flex flex-row gap-1 text-sm opacity-70 justify-end items-center
|
||||
|
|
|
@ -15,7 +15,7 @@ export const MdxWrapper = ({ title = false, path, language, children }) => {
|
|||
return (
|
||||
<>
|
||||
{title ? <h1>{title}</h1> : null}
|
||||
<div className="text-primary mdx text-base-content text-base">
|
||||
<div className="mdx text-base-content text-base">
|
||||
<MDXProvider components={components}>{children}</MDXProvider>
|
||||
</div>
|
||||
<div
|
||||
|
|
|
@ -2,9 +2,13 @@ import { Tab, Tabs } from '../tabs.mjs'
|
|||
import Md from 'react-markdown'
|
||||
import { pluginFlip } from '@freesewing/plugin-flip'
|
||||
import { pluginGore } from '@freesewing/plugin-gore'
|
||||
import { pluginI18n } from '@freesewing/plugin-i18n'
|
||||
import { Design } from '@freesewing/core'
|
||||
import yaml from 'js-yaml'
|
||||
import { Pattern, PatternXray } from '@freesewing/react-components'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
|
||||
export const ns = ['tutorial', 'plugin-annotations']
|
||||
|
||||
// Get code from children
|
||||
export const asText = (reactEl) => {
|
||||
|
@ -59,6 +63,7 @@ const buildPattern = (children, settings = { margin: 5 }, tutorial = false, pape
|
|||
|
||||
// Handles display of pattern in mormal or xray mode
|
||||
const ShowPattern = ({ renderProps, logs, mode = 'normal' }) => {
|
||||
const { t } = useTranslation(ns)
|
||||
if (!renderProps) return null
|
||||
|
||||
if (logs.pattern.error.length > 0 || logs.sets[0].error.length > 0)
|
||||
|
@ -68,7 +73,11 @@ const ShowPattern = ({ renderProps, logs, mode = 'normal' }) => {
|
|||
</div>
|
||||
)
|
||||
|
||||
return mode === 'xray' ? <PatternXray {...{ renderProps }} /> : <Pattern {...{ renderProps }} />
|
||||
return mode === 'xray' ? (
|
||||
<PatternXray {...{ renderProps, t }} className="freesewing pattern text-base-content" />
|
||||
) : (
|
||||
<Pattern {...{ renderProps, t }} className="freesewing pattern text-base-content" />
|
||||
)
|
||||
}
|
||||
|
||||
// Wrapper component dealing with the tabs and code view
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue