1
0
Fork 0

wip: Rewrite tutorial for v3

This commit is contained in:
joostdecock 2023-09-28 09:11:06 +02:00
parent 7487f1f449
commit 32d6e938df
15 changed files with 349 additions and 303 deletions

View file

@ -4,6 +4,8 @@
"p": { "p": {
"bib": "Bib" "bib": "Bib"
}, },
"s": {}, "s": {
"finishWithBiasTape": "Finish with bias tape"
},
"o": {} "o": {}
} }

View file

@ -173,7 +173,7 @@ export const bib = {
paths.bias = paths.seam paths.bias = paths.seam
.offset(-5) .offset(-5)
.attr('class', 'various dashed') .attr('class', 'various dashed')
.attr('data-text', 'finishWithBiasTape') .attr('data-text', 'tutorial:finishWithBiasTape')
.attr('data-text-class', 'center fill-various') .attr('data-text-class', 'center fill-various')
// Add the title // Add the title

View file

@ -13,11 +13,12 @@ export const step1 = {
snippets, snippets,
complete, complete,
sa, sa,
store,
paperless, paperless,
macro, macro,
part, part,
}) => { }) => {
let w = 500 * options.size const w = 500 * options.size
points.topLeft = new Point(0, 0) points.topLeft = new Point(0, 0)
points.topRight = new Point(w, 0) points.topRight = new Point(w, 0)
points.bottomLeft = new Point(0, w / 2) points.bottomLeft = new Point(0, w / 2)
@ -32,33 +33,33 @@ export const step1 = {
.close() .close()
.attr('class', 'fabric') .attr('class', 'fabric')
// Complete? if (sa) paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
if (complete) { /*
* Annotations
*/
// Cutlist
store.cutlist.setCut({ cut: 1, from: 'fabric' })
// Logo & Hello
points.logo = points.topLeft.shiftFractionTowards(points.bottomRight, 0.5) points.logo = points.topLeft.shiftFractionTowards(points.bottomRight, 0.5)
snippets.logo = new Snippet('logo', points.logo) 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) { if (complete) points.text = points.logo.shift(-90, w / 8).addText('hello', 'center')
paths.sa = paths.seam.offset(sa).attr('class', 'fabric sa')
}
}
// Paperless? //Dimensions
if (paperless) {
macro('hd', { macro('hd', {
id: 'width',
from: points.bottomLeft, from: points.bottomLeft,
to: points.bottomRight, to: points.bottomRight,
y: points.bottomLeft.y + sa + 15, y: points.bottomLeft.y + sa + 15,
}) })
macro('vd', { macro('vd', {
id: 'height',
from: points.bottomRight, from: points.bottomRight,
to: points.topRight, to: points.topRight,
x: points.topRight.x + sa + 15, x: points.topRight.x + sa + 15,
}) })
}
return part return part
}, },

View file

@ -2,10 +2,10 @@
title: Design guide title: Design guide
--- ---
This short guide will illustrate and explain how designs work in FreeSewing. Hi there and welcome to this guide that explains how FreeSewing designs work.
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 it's about what goes on under the hood each time a sewing
pattern is generated by FreeSewing. pattern is generated by FreeSewing.
This illustration is a good starting point to gain a better This illustration is a good starting point to gain a better
@ -185,10 +185,11 @@ understanding of the structure of a FreeSewing design:
``` ```
</Example> </Example>
If it looks like _a lot_ don't despair. There's a lot of repetition, and we'll If it looks like _a lot_ don't despair. I included all the info on the
work through the building blocks step by step. 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[ **Settings**](#the-settings) on the left
- The[ **Render stage**](#rendering-your-pattern) on the right - The[ **Render stage**](#rendering-your-pattern) on the right

View file

@ -3,68 +3,53 @@ title: Adding measurements
order: 130 order: 130
--- ---
FreeSewing is all about _made-to-measure_ sewing patterns; FreeSewing is all about _made-to-measure_ sewing patterns -- or *parametric
we are going to draft our pattern according to the measurements provided to us. 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? Which begs the question, which measurements?
It is we, as the pattern designers, who decide which measurements are used As the pattern designers, you get to decide which measurements are used
to draft our pattern. For our bib, the only measurement we need is the to draft the pattern. For this bib, I am going to use the
_head circumference_. _head circumference_.
So let's add it as a required measurement. So let's add it as a required measurement.
## Adding required measurements ## Adding required measurements
In our `design/src/bib.mjs` file, on the `bib` object, there is a key called In our `design/src/bib.mjs` file, we will add a `measurements` property to the `bib` object.
`measurements` (line 121) that will hold a list (an array) of all required measurements This property will be an Array (a list) holding all required measurements for this part.
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`. circumference, that name is `head`.
```design/src/bib.mjs ```design/src/bib.mjs
function draftBib({ part }) { function draftBib({ part }) => {
return part return part
} }
export const bib = { export const bib = {
name: 'tutorial.bib', name: 'tutorial.bib',
draft: draftBib, draft: draftBib,
from: false, // highlight-start
hide: {
self: false,
from: false,
after: false
},
options: {},
// start-highlight
measurements: [ 'head' ], measurements: [ 'head' ],
// end-highlight // highlight-end
optionalMeasurements: [],
plugins: []
} }
``` ```
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: 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.
![This screen tells us that we are missing some required measurements](./required-measurements.png)
Since it's just one measurement, let's simply enter a value by hand.
For example `38` as 38 cm is a realistic head circumference measurement for a baby. 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. <Tip>
This brings us back to our work in progress:
##### Why using standard measurements names matters
## Notes In principle, I can use any name I want for our measurements.
The FreeSewing core library does not care.
### 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.
However, if everybody uses their own (names for) measurements, then people However, if everybody uses their own (names for) measurements, then people
aren't able to re-use their measurements across designs. 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 please make sure to re-use the names of existing measurements, rather than
invent your own. 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. topic for details.
</Tip>

View file

@ -3,65 +3,78 @@ title: Adding options
order: 140 order: 140
--- ---
We know what our bib should look like, and we have the _head_ measurement 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 we have to make: to work with. But there's still a number of choices I have to make:
- How large should the neck opening be? - How large should the neck opening be?
- How wide should the bib be? - How wide should the bib be?
- How long 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 But since the pattern I am designing is code, it is trivial (and _IMHO_ very satisfying)
flexible and let the user decide. All we have to do is add options to our part. 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 ## 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`. 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 ```design/src/bib.mjs
function draftBib({ part }) { function draftBib({ part }) => {
return part return part
} }
export const bib = { export const bib = {
name: 'tutorial.bib', name: 'tutorial.bib',
draft: draftBib, draft: draftBib,
from: false, measurements: [ 'head' ],
hide: {
self: false,
from: false,
after: false
},
// highlight-start // highlight-start
options: { options: {
neckRatio: { pct: 80, min: 70, max: 90, menu: 'fit' }, neckRatio: {
pct: 80,
min: 70,
max: 90,
menu: 'fit'
},
}, },
// highlight-end // highlight-end
measurements: [],
optionalMeasurements: [],
plugins: []
} }
``` ```
Can you guess what it means? 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 minimum value is 70%
- Its maximum value is 90% - 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> <Note>
There are different types of options, but percentages are the most common ones. ##### What is `menu` and why should you care?
They are all documented [in the part reference docs](/reference/api/part/config/options).
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> </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: Let's do something similar for the width and length of our bib:
```design/src/bib.mjs ```design/src/bib.mjs
function draftBib({ part }) => {
return part
}
export const bib = {
name: 'tutorial.bib',
draft: draftBib,
measurements: [ 'head' ],
options: { options: {
neckRatio: { pct: 80, min: 70, max: 90, menu: 'fit' }, neckRatio: {
widthRatio: { pct: 45, min: 35, max: 55, menu: 'style' }, pct: 80,
lengthRatio: { pct: 75, min: 55, max: 85, menu: 'style' }, 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 This pretty much the exact same thing, except that are placing this in the `style` menu.
- 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
Later, we'll test-drive our pattern to see how it behaves when we adapt the options 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, we can still tweak these values. 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.

View file

@ -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: Inside our `design/src/bib.mjs` file, this is what it currently looks like:
```design/src/bib.mjs ```design/src/bib.mjs
function draftBib ({ function draftBib({ part }) => {
// 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
return part return part
} }
``` ```

View file

@ -2,8 +2,9 @@
title: Pattern design tutorial title: Pattern design tutorial
--- ---
Welcome to the FreeSewing pattern design tutorial, where we'll learn how to Hello there, and welcome to this FreeSewing pattern design tutorial.
design a made-to-measure sewing pattern, start to finish. 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> <Tip>
##### Before you start ##### 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. terminology and concepts that we'll use throughout this guide.
</Tip> </Tip>
We will be designing a pattern for a baby bib. It's a very simple pattern, but I 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 that's ok. It is a tutorial after all. This will give us plenty to work with.
translate our designs into code.
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"> <Example tutorial="1" previewFirst="1" caption="Our end result">
@ -30,13 +31,16 @@ function draftBib({
measurements, measurements,
options, options,
macro, macro,
store,
complete, complete,
snippets, snippets,
Snippet, Snippet,
part, part,
}) { }) {
// Construct the quarter neck opening /*
* Construct the quarter neck opening
*/
let tweak = 1 let tweak = 1
let target = (measurements.head * options.neckRatio) /4 let target = (measurements.head * options.neckRatio) /4
let delta let delta
@ -57,7 +61,9 @@ function draftBib({
else tweak = tweak * 1.02 else tweak = tweak * 1.02
} while (Math.abs(delta) > 1) } while (Math.abs(delta) > 1)
// Construct the complete neck opening /*
* Construct the complete neck opening
*/
points.rightCp2 = points.rightCp1.flipY() points.rightCp2 = points.rightCp1.flipY()
points.bottomCp1 = points.bottomCp2.flipX() points.bottomCp1 = points.bottomCp2.flipX()
points.left = points.right.flipX() points.left = points.right.flipX()
@ -67,7 +73,9 @@ function draftBib({
points.topCp1 = points.bottomCp2.flipY() points.topCp1 = points.bottomCp2.flipY()
points.topCp2 = points.bottomCp1.flipY() points.topCp2 = points.bottomCp1.flipY()
// Drawing the bib outline /*
* Drawing the bib outline
*/
const width = measurements.head * options.widthRatio const width = measurements.head * options.widthRatio
const length = measurements.head * options.lengthRatio const length = measurements.head * options.lengthRatio
@ -92,7 +100,9 @@ function draftBib({
) )
points.edgeTopRightCp = points.edgeTopLeftCp.flipX() points.edgeTopRightCp = points.edgeTopLeftCp.flipX()
// Round the straps /*
* Round the straps
*/
const strap = points.edgeTop.dy(points.top) const strap = points.edgeTop.dy(points.top)
points.tipRight = points.edgeTop.translate(strap / 2, strap / 2) 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) 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) 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.edgeTopRightCp = points.edgeTopLeftCp.flipX()
points.topCp1 = points.topCp2.flipX() points.topCp1 = points.topCp2.flipX()
points.tipLeftTopStart = points.tipRightTopStart.flipX() points.tipLeftTopStart = points.tipRightTopStart.flipX()
@ -148,7 +162,9 @@ function draftBib({
points.tipLeftBottomEnd = points.tipRightBottomEnd.flipX() points.tipLeftBottomEnd = points.tipRightBottomEnd.flipX()
points.snapRight = points.snapLeft.flipX() points.snapRight = points.snapLeft.flipX()
// Round the bottom corners /*
* Round the bottom corners
*/
macro("round", { macro("round", {
from: points.topLeft, from: points.topLeft,
to: points.bottomRight, to: points.bottomRight,
@ -164,7 +180,9 @@ function draftBib({
prefix: "bottomRight" prefix: "bottomRight"
}) })
// Create one path for the bib outline /*
* Create one path for the bib outline
*/
paths.seam = new Path() paths.seam = new Path()
.move(points.edgeLeft) .move(points.edgeLeft)
.line(points.bottomLeftStart) .line(points.bottomLeftStart)
@ -185,20 +203,31 @@ function draftBib({
.close() .close()
.addClass("fabric") .addClass("fabric")
if (complete) { /*
// Add snaps * Mark the bias tape, but only if complete is set
points.snapLeft = points.top */
.shiftFractionTowards(points.edgeTop, 0.5) 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() points.snapRight = points.snapLeft.flipX()
snippets.snapStud = new Snippet('snap-stud', points.snapLeft) snippets.snapStud = new Snippet('snap-stud', points.snapLeft)
snippets.snapSocket = new Snippet('snap-socket', points.snapRight) snippets.snapSocket = new Snippet('snap-socket', points.snapRight).attr('opacity', 0.5)
.attr('opacity', 0.5)
// Add a logo // Logo
points.logo = new Point(0, 0) points.logo = new Point(0, 0)
snippets.logo = new Snippet("logo", points.logo) snippets.logo = new Snippet("logo", points.logo)
// Add a title // Title
points.title = points.bottom.shift(-90, 45) points.title = points.bottom.shift(-90, 45)
macro("title", { macro("title", {
at: points.title, at: points.title,
@ -207,40 +236,33 @@ function draftBib({
scale: 0.7 scale: 0.7
}) })
// Add a scalbox // Scalbox
points.scalebox = points.title.shift(-90, 55) points.scalebox = points.title.shift(-90, 55)
macro("scalebox", { at: points.scalebox }) macro("scalebox", { at: points.scalebox })
paths.bias = paths.seam
.offset(-5)
.addClass("various dashed")
.addText("finishWithBiasTape", "center fill-various")
}
return part return part
} }
``` ```
</Example> </Example>
Before we can get started, let's make sure we have the required software
installed on our computer:
## Prerequisites ## 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 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, [Node.js](https://nodejs.org/), or a variety of other runtimes such as Bun,
AWS Lambda, and so on. Deno, AWS Lambda, and so on.
For development, we'll use Node.js. If we don't have Node.js 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 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 ```sh
node -v 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!

View file

@ -3,42 +3,45 @@ title: Setting up the development environment
order: 100 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 ```sh
npx @freesewing/new-design@next npx @freesewing/new-design@next
``` ```
<Fixme compact>Remove `@next` suffix once v3 is in production</Fixme> <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: All the defaults will do, but here are the details:
- *What template would you like to use?* — Pick the default: **Tutorial** - *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 - *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> <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> </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 ```sh
cd tutorial cd tutorial
npm run dev npm run dev
``` ```
Or if we chose to use yarn as package manager: Or if you want to use yarn as package manager:
```sh ```sh
cd tutorial cd tutorial
yarn dev 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: 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? ### Need help?
If you run into any issues, [join our **#development-help** chat room on on If you run into any issues, head over to [FreeSewing.org/support](https://next.freesewing.org/support)
Discord](https://discord.freesewing.org/) and we'll figure it out together. which lists the various ways in which you can get help.

View file

@ -1,77 +1,84 @@
--- ---
title: Our first part title: Creating a part
order: 120 order: 120
--- ---
Much like garments themselves, patterns are made up of _parts_. Much like garments themselves, patterns are made up of _parts_.
Most patterns will have multiple parts. A sleeve, a back part, the collar, and 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 <Tip>
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 It's a good idea to keep each part in its own file. You don't *have to* do
and approachable code base. this, but it's a good habit to get into.
</Tip>
## bib.mjs ## bib.mjs
The previous step has already set everything up for us. Our design's main file Since I chose the `tutorial` preset, the development environment is preconfigured for this tutorial.
lives in `design/src/index.mjs`, and our part lives in `design/src/bib.mjs`.
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 ```design/src/bib.mjs
import { pluginBundle } from "@freesewing/plugin-bundle" /*
* This function drafts the part
function draftBib ({ */
part, // Your draft method must return this function draftBib ({ part }) => {
})
{
// Work your magic here
return part return part
} }
export const bib = {
/*
* This is the part object
*/
export const bib = {
name: 'tutorial.bib', name: 'tutorial.bib',
draft: draftBib,[], draft: draftBib,
from: false,
hide: {
self: false,
from: false,
after: false
},
options: {},
measurements: [],
optionalMeasurements: [],
plugins: [ pluginBundle ]
} }
``` ```
### The part object ### 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`. The only mandatory keys on a part object are `name` and `draft`.
<Related> <Related>
Refer to [the part reference documentation](/reference/api/part) for Refer to [the part reference documentation](/reference/api/part) for
all details about configuring the part object all details about configuring the part object
</Related> </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 #### The part name
```design/src/bib.mjs ```design/src/bib.mjs
name: 'tutorial.bib', name: 'tutorial.bib',
``` ```
A part's `name` should be unique in a pattern. Apart from that, anything goes. A part's `name` should be unique in a design. I used `tutorial.bib` as the
Although we probably want to give it a sensible name. name, because that makes sense.
As we can see in the example above, we're using `tutorial.bib` as the name. <Warning>
<Tip> I **strongly** recommend that you apply the same `designName.partName` naming scheme in all your parts.
We **strongly** recommend that you follow this `design.part` naming scheme to avoid This avoids naming conflicts when mixing parts from various designs to create a new design.
naming conflicts when mixing parts from various designs to create new designs.
</Tip> </Warning>
#### The part's draft method #### 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. 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. For now this function doesn't do much, but that will change soon enough.
<Note> <Note>
@ -99,56 +107,76 @@ to get started. Or, read on for an explanation of what's going on in the
</Tip> </Tip>
The `index.mjs` file is already complete and we won't be making any changes to 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`, it. But if you are curious about what's going on inside `index.mjs`,
we're including a version with comments below: this is all we need:
```design/src/index.mjs ```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 { 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 { bib } from './bib.mjs'
import { i18n } from '../i18n/index.mjs'
/* const Tutorial = new Design({
* 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.
*/
parts: [ bib ], parts: [ bib ],
}) })
/* export { bib, Tutorial, i18n }
* 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 }
``` ```
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>

View file

@ -6,6 +6,9 @@ order: 110
Inside our `tutorial` folder, the `design/src` folder holds the source code for Inside our `tutorial` folder, the `design/src` folder holds the source code for
the new pattern we will create. 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 We can safely ignore all other files and folders, as they are part of the
FreeSewing development environment. FreeSewing development environment.
So feel free to skip ahead to [Our first part](/tutorials/pattern-design/our-first-part). So feel free to skip ahead to [Our first part](/tutorials/pattern-design/our-first-part).

View file

@ -99,7 +99,7 @@ export default DocsPage
export async function getStaticProps({ params }) { export async function getStaticProps({ params }) {
return { return {
props: { props: {
...(await serverSideTranslations('en', ['docs', ...ns])), ...(await serverSideTranslations('en', ['docs', 'tutorial', ...ns])),
slug: params.slug.join('/'), slug: params.slug.join('/'),
page: { page: {
locale: 'en', locale: 'en',

View file

@ -7,7 +7,7 @@ export const MdxWrapper = ({ title = false, path, language, children, noFooter =
return ( return (
<> <>
{title ? <h1>{title}</h1> : null} {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 : ( {noFooter ? null : (
<div <div
className={`flex flex-row gap-1 text-sm opacity-70 justify-end items-center className={`flex flex-row gap-1 text-sm opacity-70 justify-end items-center

View file

@ -15,7 +15,7 @@ export const MdxWrapper = ({ title = false, path, language, children }) => {
return ( return (
<> <>
{title ? <h1>{title}</h1> : null} {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> <MDXProvider components={components}>{children}</MDXProvider>
</div> </div>
<div <div

View file

@ -2,9 +2,13 @@ import { Tab, Tabs } from '../tabs.mjs'
import Md from 'react-markdown' import Md from 'react-markdown'
import { pluginFlip } from '@freesewing/plugin-flip' import { pluginFlip } from '@freesewing/plugin-flip'
import { pluginGore } from '@freesewing/plugin-gore' import { pluginGore } from '@freesewing/plugin-gore'
import { pluginI18n } from '@freesewing/plugin-i18n'
import { Design } from '@freesewing/core' import { Design } from '@freesewing/core'
import yaml from 'js-yaml' import yaml from 'js-yaml'
import { Pattern, PatternXray } from '@freesewing/react-components' import { Pattern, PatternXray } from '@freesewing/react-components'
import { useTranslation } from 'next-i18next'
export const ns = ['tutorial', 'plugin-annotations']
// Get code from children // Get code from children
export const asText = (reactEl) => { 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 // Handles display of pattern in mormal or xray mode
const ShowPattern = ({ renderProps, logs, mode = 'normal' }) => { const ShowPattern = ({ renderProps, logs, mode = 'normal' }) => {
const { t } = useTranslation(ns)
if (!renderProps) return null if (!renderProps) return null
if (logs.pattern.error.length > 0 || logs.sets[0].error.length > 0) if (logs.pattern.error.length > 0 || logs.sets[0].error.length > 0)
@ -68,7 +73,11 @@ const ShowPattern = ({ renderProps, logs, mode = 'normal' }) => {
</div> </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 // Wrapper component dealing with the tabs and code view