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:
parent
ef8f68bcaf
commit
469eb43c95
595 changed files with 20432 additions and 2469 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -47,6 +47,8 @@ sites/orgdocs/src/lib/designs.mjs
|
|||
sites/orgdocs/src/lib/designinfo.mjs
|
||||
sites/orgdocs/src/lib/i18n.mjs
|
||||
sites/orgdocs/docs/designs/*/options/readme.mdx
|
||||
sites/orgdocs/authors.json
|
||||
sites/orgdocs/showcase-tags.mjs
|
||||
|
||||
# Lab auto-generated content
|
||||
sites/lab/lib
|
||||
|
|
|
@ -32,7 +32,7 @@ packageJson:
|
|||
author: AlfaLyr (https://github.com/alfalyr)
|
||||
i18n:
|
||||
private: true
|
||||
jane:
|
||||
jane:
|
||||
author: SeaZeeZee (https://github.com/SeaZeeZee)
|
||||
lab:
|
||||
private: true
|
||||
|
@ -73,6 +73,14 @@ packageJson:
|
|||
files:
|
||||
- index.json
|
||||
- package.json
|
||||
react-components:
|
||||
exports:
|
||||
".":
|
||||
"internal": "./src/index.mjs"
|
||||
"default": "./dist/index.mjs"
|
||||
"./linedrawings": "./src/linedrawings/index.mjs"
|
||||
"./pattern": "./src/pattern/index.mjs"
|
||||
"./xray": "./src/pattern-xray/index.mjs"
|
||||
rehype-hightlight-lines:
|
||||
private: true
|
||||
sandy:
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import designs from './designs.json' assert { type: 'json' }
|
||||
import packages from './packages.json' assert { type: 'json' }
|
||||
import plugins from './plugins.json' assert { type: 'json' }
|
||||
import sites from './sites.json' assert { type: 'json' }
|
||||
|
||||
// Helper method to construct summary objects
|
||||
const unpack = (obj, folder) =>
|
||||
|
@ -22,14 +21,13 @@ const unpackDesigns = (obj, folder) =>
|
|||
)
|
||||
|
||||
// Re-Export imported JSON
|
||||
export { designs, packages, plugins, sites }
|
||||
export { designs, packages, plugins }
|
||||
|
||||
// All software
|
||||
export const software = {
|
||||
...unpackDesigns(designs, 'designs'),
|
||||
...unpack(plugins, 'plugins'),
|
||||
...unpack(packages, 'packages'),
|
||||
...unpack(sites, 'sites'),
|
||||
}
|
||||
|
||||
// All software published on NPM
|
||||
|
@ -40,4 +38,4 @@ export const publishedSoftware = {
|
|||
}
|
||||
|
||||
export const publishedTypes = ['designs', 'packages', 'plugins']
|
||||
export const types = [...publishedTypes, 'sites']
|
||||
export const types = publishedTypes
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"backend": "FreeSewing backend",
|
||||
"dev": "FreeSewing website with documentation for contributors & developers",
|
||||
"org": "FreeSewing website",
|
||||
"sde": "Stand-alone develpment environment. Basis for the @freesewing/new-design package",
|
||||
"shared": "Shared code and React components for different websites"
|
||||
}
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
title: Guides
|
||||
order: zbb
|
||||
---
|
||||
|
||||
Below is an overview of the various FreeSewing guides:
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
---
|
||||
title: About Frontmatter
|
||||
order: 10
|
||||
sidebar_position: 10
|
||||
---
|
||||
|
||||
Frontmatter is a way to add metadata to Markdown documents.
|
||||
|
||||
Frontmatter sits at the top of the file (it's matter that's at the front) and is
|
||||
surrounded by lines with three dashes on them. It contains several keys with a value.
|
||||
surrounded by lines with three dashes on them. It contains several keys with a value.
|
||||
|
||||
The `title` key is required on every page, it holds the title of the page.
|
||||
The `title` key is required on every page, it holds the title of the page.
|
||||
|
||||
The `order` key is not required and can be used to sort pages in a certain order, if there is no order key then the pages will be sorted alphabetically.
|
||||
|
||||
```md
|
||||
---
|
||||
title: About Frontmatter
|
||||
order: 20
|
||||
sidebar_position: 20
|
||||
---
|
||||
```
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Lists or arrays
|
||||
order: 30
|
||||
sidebar_position: 30
|
||||
---
|
||||
|
||||
Values are typically text or numbers, but you can also make it a list or array.
|
||||
|
@ -9,7 +9,8 @@ There's two types of syntax for this:
|
|||
```md
|
||||
tags: [tag1, another, three]
|
||||
categories:
|
||||
- cat1
|
||||
- anothercat
|
||||
- somethingelse
|
||||
|
||||
- cat1
|
||||
- anothercat
|
||||
- somethingelse
|
||||
```
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Multi-line text
|
||||
order: 40
|
||||
sidebar_position: 40
|
||||
---
|
||||
|
||||
To add multi-line text in Frontmatter, use a `|` character,
|
||||
|
@ -8,6 +8,6 @@ and prefix the lines by spaces:
|
|||
|
||||
```md
|
||||
about: |
|
||||
This is a multi-line text
|
||||
that will be assigned to the about key
|
||||
This is a multi-line text
|
||||
that will be assigned to the about key
|
||||
```
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Structure
|
||||
order: 20
|
||||
sidebar_position: 20
|
||||
---
|
||||
|
||||
Frontmatter is made up of `key: value` pairs.
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
title: Howtos
|
||||
order: zcc
|
||||
---
|
||||
|
||||
You can find a list of all FreeSewing hotwtos below:
|
||||
|
@ -17,4 +16,3 @@ Guides and howtos are on a spectrum with howtos being terse _do-this-then-that_
|
|||
guides take more time to explain in-depth what is being done and why.
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
title: Reference
|
||||
order: zdd
|
||||
---
|
||||
|
||||
You can find a list of all FreeSewing reference documentation below:
|
||||
|
@ -12,4 +11,3 @@ You can find a list of all FreeSewing reference documentation below:
|
|||
## Full list
|
||||
|
||||
<ReadMore recurse />
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
title: Training
|
||||
order: zzz
|
||||
---
|
||||
|
||||
FreeSewing has created the following training materials:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Getting started with Codespaces
|
||||
order: 13
|
||||
sidebar_position: 13
|
||||
---
|
||||
|
||||
:::note
|
||||
|
@ -29,19 +29,22 @@ to have or use your own computer to perform this development work.
|
|||
## Accessing Codespaces
|
||||
|
||||
Access Codespaces from the GitHub website while logged in:
|
||||
|
||||
- The "Your Codespaces" page is accessed via the "Codespaces" link at the top
|
||||
of any GitHub page.
|
||||
of any GitHub page.
|
||||
- A shortcut URL is: https://github.com/codespaces
|
||||
|
||||
## Creating a codespace
|
||||
|
||||
To create a new codespace:
|
||||
|
||||
- Select the "New codespace" button at the top of the Your Codespaces page.
|
||||
- A shortcut URL is: https://github.com/codespaces/new
|
||||
|
||||
This will open a "Create a New Codespace" page.
|
||||
|
||||
On the Create a New Codespace page, select the options for your codespace:
|
||||
|
||||
- Repository -> ("`username/freesewing`" assuming that is the name of your GitHub repository)
|
||||
- Branch -> (select the branch you want to use)
|
||||
- Region -> (select the region most appropriate for you)
|
||||
|
@ -52,14 +55,13 @@ The Codespaces app will open in the browser window.
|
|||
The Codespaces app is basically the [Visual Studio Code][vs] app with
|
||||
Codespaces and GitHub integration built in.
|
||||
|
||||
[vs]: https://code.visualstudio.com
|
||||
|
||||
(Wait 45 seconds or so for the Codespace app to clone the repository from
|
||||
GitHub to the codespace repository and start.)
|
||||
[vs]: https://code.visualstudio.com 'Wait 45 seconds or so for the Codespace app to clone the repository from
|
||||
GitHub to the codespace repository and start.'
|
||||
|
||||
## Editing files
|
||||
|
||||
You can browse and edit files in your codespace repository from within the app:
|
||||
|
||||
- On the Activity Bar on the far left side of the page, select the
|
||||
Explorer icon.
|
||||
(The icon looks like two pages of paper.)
|
||||
|
@ -72,6 +74,7 @@ Auto-save is enabled by default, so any changes you make are
|
|||
automatically saved in your codespace repository.
|
||||
|
||||
To commit changes to your codespace repository:
|
||||
|
||||
- In the Activity Bar on the far left side of the page,
|
||||
select the Source Control icon.
|
||||
- In the Source Control sidebar you can see a list of changed files.
|
||||
|
@ -82,6 +85,7 @@ To commit changes to your codespace repository:
|
|||
|
||||
To push committed changes from your codespace repository back to your
|
||||
GitHub repository:
|
||||
|
||||
- After committing changes to your codespace repository, press the
|
||||
"Sync Changes" button to push the committed changes to your GitHub
|
||||
repository.
|
||||
|
@ -94,13 +98,16 @@ GitHub repository:
|
|||
In the "Terminal" panel at the bottom of the page, you can run commands.
|
||||
|
||||
To start the lab website (to view and test new designs and design changes):
|
||||
|
||||
- In the Terminal panel, run `yarn kickstart` and then `yarn lab`.
|
||||
|
||||
To start the dev or org websites (to view and test documentation changes):
|
||||
|
||||
- dev: In the Terminal panel, run `cd sites/dev` and `yarn start`.
|
||||
- org: In the Terminal panel, run `cd sites/org` and `yarn start`.
|
||||
|
||||
After the lab, dev, or org website starts:
|
||||
|
||||
- The usual `localhost:8000` port will automatically be forwarded to a custom
|
||||
URL.
|
||||
- A pop-up will appear saying that the port has been forwarded. The "Open in
|
||||
|
@ -122,6 +129,7 @@ However, you can make the port public so others can access it
|
|||
(or so you can access it on a different browser while not logged into GitHub).
|
||||
|
||||
To make the port public:
|
||||
|
||||
- In the Ports panel, right-click on the port and select
|
||||
Port Visibility -> Public.
|
||||
- The custom URL will be now be a publicly-accessible forwarded port.
|
||||
|
@ -130,6 +138,7 @@ To make the port public:
|
|||
## Starting and stopping a codespace
|
||||
|
||||
You can start and stop your codespace via the Your Codespaces page.
|
||||
|
||||
- To start: Click on the codespace name to browse to the Codespaces
|
||||
app URL for that codespace.
|
||||
(You can also right-click to copy the URL and open it in a
|
||||
|
@ -150,7 +159,8 @@ You can rename a codespace to make it easier to identify.
|
|||
(This will help if you have more than one codespace.)
|
||||
|
||||
To rename a codespace:
|
||||
- Go to the Your Codespaces page.
|
||||
|
||||
- Go to the Your Codespaces page.
|
||||
- Open the "..." ellipses menu next to the codespace
|
||||
and select "Rename".
|
||||
|
||||
|
@ -158,17 +168,18 @@ To rename a codespace:
|
|||
|
||||
You can access GitHub Settings via the user icon menu in the upper right
|
||||
corner of any GitHub page (but not on the Codespaces app page).
|
||||
|
||||
- Selecting the "Settings" menu item will open the GitHub Settings page.
|
||||
- The Codespaces settings are under "Codespaces" in the left sidebar
|
||||
on the Settings page.
|
||||
on the Settings page.
|
||||
- A shortcut URL is: https://github.com/settings/codespaces
|
||||
|
||||
|
||||
Among the Codespaces settings available are:
|
||||
|
||||
- "Default idle timeout" (how long codespaces continue to run when idle,
|
||||
before being stopped)
|
||||
before being stopped)
|
||||
- "Default retention period" (how long codespace repositories are kept
|
||||
when unused, before being deleted)
|
||||
when unused, before being deleted)
|
||||
|
||||
:::note
|
||||
Do not be confused by the other Settings icon/menu at the bottom left of the
|
||||
|
@ -180,11 +191,13 @@ are located.
|
|||
## Usage and Quotas
|
||||
|
||||
To check usage:
|
||||
|
||||
- Usage information is under "Billing and plans" in the left sidebar on
|
||||
the Settings page.
|
||||
- A shortcut URL is: https://github.com/settings/billing
|
||||
|
||||
About quotas:
|
||||
|
||||
- As a free account user, you have a quota of 120 core-hours of usage
|
||||
and 15 GB of storage per billing month.
|
||||
That is the total for all your codespaces combined.
|
||||
|
@ -209,18 +222,20 @@ Don't worry -- you won't get a bill if you exceed your quota!
|
|||
Instead, you will just be unable to start any of your codespaces
|
||||
until the start of the next billing month.
|
||||
And, if you have any work-in-progress changes that you need access to
|
||||
before then, you can export those changes to a new GitHub branch.
|
||||
before then, you can export those changes to a new GitHub branch.
|
||||
:::
|
||||
|
||||
## Deleting a codespace
|
||||
|
||||
To delete a codespace:
|
||||
|
||||
- Go to the Your Codespaces page.
|
||||
- Open the "..." ellipses menu next to the codespace
|
||||
and select "Delete".
|
||||
|
||||
:::note RELATED
|
||||
For more information, please see:
|
||||
|
||||
- [GitHub Codebases documentation](https://docs.github.com/en/codespaces).
|
||||
- [About billing for GitHub Codespaces](https://docs.github.com/en/billing/managing-billing-for-github-codespaces/about-billing-for-github-codespaces)
|
||||
:::
|
||||
:::
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Getting started with Gitpod
|
||||
order: 10
|
||||
sidebar_position: 10
|
||||
---
|
||||
|
||||
If you don't want to set up a dev environment or if you just want to kick the
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Setting up the FreeSewing development environment
|
||||
order: 40
|
||||
sidebar_position: 40
|
||||
---
|
||||
|
||||
FreeSewing provides a development environment to help you design and develop
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Start the development environment
|
||||
order: 50
|
||||
sidebar_position: 50
|
||||
---
|
||||
|
||||
FreeSewing provides a development environment to help you design and develop patterns.
|
||||
|
@ -21,7 +21,9 @@ yarn lab
|
|||
Then point your browser to http://localhost:8000
|
||||
|
||||
:::tip
|
||||
|
||||
### Adding a new design
|
||||
|
||||
This is all you need to work on existing designs. If you'd like to add a new design, run:
|
||||
|
||||
```bash
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Installing Node.js
|
||||
order: 20
|
||||
sidebar_position: 20
|
||||
---
|
||||
|
||||
Now we will use `nvm` to install Node.js. Run the following command:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Installing nvm
|
||||
order: 10
|
||||
sidebar_position: 10
|
||||
---
|
||||
|
||||
FreeSewing is built with [Node.js](https://nodejs.org/), a JavaScript runtime.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Using a different Node.js version
|
||||
order: 30
|
||||
sidebar_position: 30
|
||||
---
|
||||
|
||||
Now that you've got Node.js setup, we can start setting up the FreeSewing
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Getting started on Linux
|
||||
order: 15
|
||||
sidebar_position: 15
|
||||
---
|
||||
|
||||
In this tutorial, we will setup Node.js and initialize the FreeSewing
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Setting up the FreeSewing development environment
|
||||
order: 40
|
||||
sidebar_position: 40
|
||||
---
|
||||
|
||||
FreeSewing provides a development environment to help you design and develop
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Start the development environment
|
||||
order: 50
|
||||
sidebar_position: 50
|
||||
---
|
||||
|
||||
FreeSewing provides a development environment to help you design and develop patterns.
|
||||
|
@ -21,7 +21,9 @@ yarn lab
|
|||
Then point your browser to http://localhost:8000
|
||||
|
||||
:::tip
|
||||
|
||||
### Adding a new design
|
||||
|
||||
This is all you need to work on existing designs. If you'd like to add a new design, run:
|
||||
|
||||
```bash
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Installing Node.js
|
||||
order: 20
|
||||
sidebar_position: 20
|
||||
---
|
||||
|
||||
Now we will use `nvm` to install Node.js. Run the following command:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Installing nvm
|
||||
order: 15
|
||||
sidebar_position: 15
|
||||
---
|
||||
|
||||
FreeSewing is built with [Node.js](https://nodejs.org/), a JavaScript runtime.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Installing the Xcode command line tools
|
||||
order: 10
|
||||
sidebar_position: 10
|
||||
---
|
||||
|
||||
Before we can get started, we need some basic tools for development.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Using a different Node.js version
|
||||
order: 30
|
||||
sidebar_position: 30
|
||||
---
|
||||
|
||||
Now that you've got Node.js setup, we can start setting up the FreeSewing
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Getting started on Mac
|
||||
order: 25
|
||||
sidebar_position: 25
|
||||
---
|
||||
|
||||
In this tutorial, we will setup Node.js and initialize the FreeSewing
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Getting started with Vercel
|
||||
order: 14
|
||||
sidebar_position: 14
|
||||
---
|
||||
|
||||
## What is Vercel?
|
||||
|
@ -23,6 +23,7 @@ containing a fork of the FreeSewing repository.
|
|||
## Why you might want to use Vercel
|
||||
|
||||
There are reasons why you might want your own Vercel account:
|
||||
|
||||
- You can preview your changes:
|
||||
- if you develop on a mobile device or if you do not have access to a
|
||||
computer.
|
||||
|
@ -61,7 +62,7 @@ Free Hobby accounts are limited to 3 Projects per Git repository.
|
|||
|
||||
Under each project there will be many, many deployments.
|
||||
|
||||
_Deployments are simply builds, an instance of a website/app
|
||||
\_Deployments are simply builds, an instance of a website/app
|
||||
built from a specific commit version of a specific branch of the repository.
|
||||
These deployments can be accessed using a web browser to preview
|
||||
the web app or website.
|
||||
|
@ -103,11 +104,11 @@ account/credentials without having to create a separate username
|
|||
or password.
|
||||
|
||||
1. On the [Vercel website][v] select the "Sign Up" button.
|
||||
(A shortcut URL is: [https://vercel.com/signup][vsu].)
|
||||
(A shortcut URL is: [https://vercel.com/signup][vsu].)
|
||||
2. Select the "Continue with GitHub" button.
|
||||
3. A pop-up window will appear asking you for permission to access
|
||||
your GitHub information.
|
||||
Press the green "Authorize Vercel" button to continue.
|
||||
your GitHub information.
|
||||
Press the green "Authorize Vercel" button to continue.
|
||||
|
||||
[v]: https://vercel.com
|
||||
[vsu]: https://vercel.com/signup
|
||||
|
@ -125,12 +126,12 @@ FreeSewing repository.
|
|||
2. Select your personal GitHub account from the list.
|
||||
3. Select the "Only select repositories" radio button.
|
||||
4. In "Select repositories" drop-down menu, select your `freesewing`
|
||||
repository.
|
||||
repository.
|
||||
5. Click the green "Install" button.
|
||||
6. Confirm that you are giving permission to access the repository
|
||||
by entering your GitHub password.
|
||||
by entering your GitHub password.
|
||||
7. Finally, back at the Import Git Repository screen complete the
|
||||
import by selecting the white "Import" button.
|
||||
import by selecting the white "Import" button.
|
||||
|
||||
## Creating a project
|
||||
|
||||
|
@ -139,15 +140,16 @@ create a project.
|
|||
|
||||
By default, the default Root Directory will be `sites/dev`.
|
||||
The Root Directory setting will determine the build type for the project.
|
||||
|
||||
- `sites/dev` will build a freesewing.dev website
|
||||
- `sites/org` will build a freesewing.org website
|
||||
|
||||
1. Change the name of the project, if you wish.
|
||||
Names can consist of alphanumeric lowercase and hyphen characters.
|
||||
Names can consist of alphanumeric lowercase and hyphen characters.
|
||||
2. Change the Root Directory to the desired setting, as described above.
|
||||
3. In the Build & Development Settings,
|
||||
add `yarn build` as the Build Command override.
|
||||
(All the other settings will work fine with the default values.)
|
||||
add `yarn build` as the Build Command override.
|
||||
(All the other settings will work fine with the default values.)
|
||||
4. Press the white "Deploy" button.
|
||||
|
||||
Vercel will then create the project and start building the project's first
|
||||
|
@ -167,17 +169,18 @@ ones based on the `develop` branch
|
|||
`develop` instead of `main).
|
||||
|
||||
Created deployments include:
|
||||
|
||||
1. The initial production deployment. (Because you don't have a branch named
|
||||
`main` in your repository, Vercel will instead create the initial
|
||||
production deployment from the default `develop` branch.)
|
||||
`main` in your repository, Vercel will instead create the initial
|
||||
production deployment from the default `develop` branch.)
|
||||
2. A new preview deployment every time you update your `develop` branch in GitHub
|
||||
(for example, whenever you sync it with the latest `freesewing/freesewing`
|
||||
updates)
|
||||
(for example, whenever you sync it with the latest `freesewing/freesewing`
|
||||
updates)
|
||||
3. A new preview deployment for every new branch you push to GitHub
|
||||
4. A new preview deployment for every update you make to these new branches
|
||||
when you push to GitHub
|
||||
when you push to GitHub
|
||||
5. A new preview deployment for every update you make to your existing branches
|
||||
when you push to GitHub
|
||||
when you push to GitHub
|
||||
|
||||
If you have multiple projects for the same repository
|
||||
(for example, if you have both `sites/org` and `sites/dev` projects),
|
||||
|
@ -196,7 +199,7 @@ Once they start, deployments take about
|
|||
You will manage your account and projects from the Vercel Dashboard
|
||||
page, [https://vercel.com/dashboard][vd].
|
||||
|
||||
The default __Overview__ tab at the top of the Dashboard page will show your repositories
|
||||
The default **Overview** tab at the top of the Dashboard page will show your repositories
|
||||
and projects.
|
||||
Click on a project name to go to its project page.
|
||||
|
||||
|
@ -204,31 +207,32 @@ Click on a project name to go to its project page.
|
|||
|
||||
## Project pages
|
||||
|
||||
The default __Project__ tab at the top of the project page will show the
|
||||
The default **Project** tab at the top of the project page will show the
|
||||
the production deployment and some of the most recent preview
|
||||
deployments for that project.
|
||||
|
||||
Click on the __Deployments__ tab to see all of the project's deployments.
|
||||
Click on the **Deployments** tab to see all of the project's deployments.
|
||||
Click on a deployment name to go to its deployment page.
|
||||
|
||||
Click on the __Settings__ tab to see the project's settings.
|
||||
Click on the **Settings** tab to see the project's settings.
|
||||
|
||||
## Deployment pages
|
||||
|
||||
On the default __Deployment__ tab at the top of the deployment page
|
||||
On the default **Deployment** tab at the top of the deployment page
|
||||
you will see information about the deployment.
|
||||
|
||||
Under __Domains__ you will see one or more URLs that can be used to
|
||||
Under **Domains** you will see one or more URLs that can be used to
|
||||
access the deployment.
|
||||
These are also the URLs that you can share with others so they
|
||||
can view your deployments.
|
||||
|
||||
- URLs containing hash characters link to the deployment for a single
|
||||
commit.
|
||||
commit.
|
||||
- URLs without a hash point to the deployment for the latest version
|
||||
of that branch.
|
||||
of that branch.
|
||||
|
||||
If you ever want to delete a deployment you can do so on its
|
||||
deployment page, under the "__...__" three dots menu.
|
||||
deployment page, under the "**...**" three dots menu.
|
||||
|
||||
## Usage and Billing
|
||||
|
||||
|
@ -237,11 +241,12 @@ Vercel's free Hobby accounts come with
|
|||
This should be at least 10-15x the amount you will actually use in
|
||||
a month, so do not worry about this.
|
||||
|
||||
If you want to check your usage, please seee the __Usage__ tab at the
|
||||
If you want to check your usage, please seee the **Usage** tab at the
|
||||
top of the Dashboard page.
|
||||
|
||||
- A shortcut URL is [https://vercel.com/dashboard/usage][vu]
|
||||
- Or, [https://vercel.com/account/billing][vb] will show a summary
|
||||
of your usage.
|
||||
of your usage.
|
||||
|
||||
## Disabling automatic deployments
|
||||
|
||||
|
@ -249,8 +254,8 @@ You can disable and enable automatic deployments for a project,
|
|||
for example if you wish to temporarily stop them while working on
|
||||
a bug that prevents successful builds.
|
||||
|
||||
On the Project Settings page, select __Git__ from the menu on the
|
||||
left. Change the __Ignored Build Step__ behavior from "Automatic" to
|
||||
On the Project Settings page, select **Git** from the menu on the
|
||||
left. Change the **Ignored Build Step** behavior from "Automatic" to
|
||||
"Don't build anything".
|
||||
|
||||
[vu]: https://vercel.com/dashboard/usage
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Getting started on Windows
|
||||
order: 30
|
||||
sidebar_position: 30
|
||||
---
|
||||
|
||||
:::warning
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Setting up the development environment
|
||||
order: 20
|
||||
sidebar_position: 20
|
||||
---
|
||||
|
||||
FreeSewing provides a development environment that visualizes your design for
|
||||
|
@ -18,7 +18,7 @@ It will ask if it is ok to install the development environment in a new folder
|
|||
named `freesewing`. You can accept the default, or pick a different folder name
|
||||
if you prefer.
|
||||
|
||||
It will also ask what package manager you would like to use.
|
||||
It will also ask what package manager you would like to use.
|
||||
Here too the default (`npm`) is fine., unless you are certain you have **yarn** installed.
|
||||
|
||||
After answering these questions, files will be downloaded, dependencies installed,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Installing NodeJS
|
||||
order: 10
|
||||
sidebar_position: 10
|
||||
---
|
||||
|
||||
FreeSewing is a JavaScript project, so you need JavaScript to work with it.
|
||||
|
@ -9,14 +9,15 @@ precise. You can switch this website theme from light to dark mode, and
|
|||
that would not work without JavaScript.
|
||||
|
||||
As a **user** of FreeSewing, this is all you need. To develop with FreeSewing
|
||||
you are going to need to be able to run JavaScript *outside* the browser using
|
||||
a JavaScript *runtime*. Which just means a thing that can *run* JavaScript.
|
||||
you are going to need to be able to run JavaScript _outside_ the browser using
|
||||
a JavaScript _runtime_. Which just means a thing that can _run_ JavaScript.
|
||||
|
||||
We are going to be using [NodeJS](https://nodejs.org/) in this tutorial. It is
|
||||
the most established of the different JavaScript runtimes. But there's also
|
||||
other runtimes like [Deno](https://deno.com/) or [Bun](https://bun.sh/).
|
||||
the most established of the different JavaScript runtimes. But there's also
|
||||
other runtimes like [Deno](https://deno.com/) or [Bun](https://bun.sh/).
|
||||
|
||||
## Install
|
||||
|
||||
If you don't have NodeJS on your system, you can go to
|
||||
[NodeJS.org](https://nodejs.org/) and follow the install instructions.
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: The FreeSewing development environment
|
||||
order: 30
|
||||
sidebar_position: 30
|
||||
---
|
||||
|
||||
If you have been to FreeSewing.org the FreeSewing development environment will look familiar.
|
||||
|
@ -44,4 +44,3 @@ For the following along this tutorial, you have two options:
|
|||
- Pick **From scratch** if you prefer to actively participate by recreating the design in this tutorial.
|
||||
|
||||
I recommend the latter. You will learn (and remember) a lot more if you are actively engaging.
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Folder structure
|
||||
order: 40
|
||||
sidebar_position: 40
|
||||
---
|
||||
|
||||
Inside the `freesewing` folder -- which might have a different name if that is
|
||||
|
@ -23,10 +23,10 @@ this menu:
|
|||

|
||||
|
||||
As you might have guessed by now, each of these options is contained in its
|
||||
own subfolder under `designs`.
|
||||
own subfolder under `designs`.
|
||||
|
||||
You can edit the files under `designs/[template]/src/` and the changes you make
|
||||
will be reflected in the development environment.
|
||||
|
||||
Don't take my word for it though. Let's start doing exactly that
|
||||
Don't take my word for it though. Let's start doing exactly that
|
||||
in [Part 2](/tutorials/pattern-design/part2).
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
:::
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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>
|
||||
```
|
||||
|
|
|
@ -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.
|
||||
```
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
```
|
||||
|
|
|
@ -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>
|
||||
```
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
title: Adding annotations
|
||||
order: 20
|
||||
sidebar_position: 20
|
||||
---
|
||||
|
||||
Our pattern is still a little bit *bare*. It would be nice to add some *annotations* to it.
|
||||
Our pattern is still a little bit _bare_. It would be nice to add some _annotations_ to it.
|
||||
|
||||
When I say *annotations* it's an umbrella term for things like text or other
|
||||
When I say _annotations_ it's an umbrella term for things like text or other
|
||||
bits of information that help the user understand the pattern.
|
||||
|
||||
## Adding snippets
|
||||
|
@ -42,15 +42,17 @@ function draftBib({
|
|||
part,
|
||||
}) {
|
||||
|
||||
/*
|
||||
* Construct the neck opening
|
||||
*/
|
||||
const target = (measurements.head * options.neckRatio) / 4
|
||||
/\*
|
||||
|
||||
- Construct the neck opening
|
||||
_/
|
||||
const target = (measurements.head _ options.neckRatio) / 4
|
||||
let tweak = 1
|
||||
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, points.bottom.dy(points.right) / 2)
|
||||
points.bottomCp2 = points.bottom.shift(0, points.bottom.dx(points.right) / 2)
|
||||
|
@ -62,108 +64,116 @@ function draftBib({
|
|||
delta = paths.neck.length() - target
|
||||
if (delta > 0) tweak = tweak * 0.99
|
||||
else tweak = tweak * 1.02
|
||||
} while (Math.abs(delta) > 1)
|
||||
|
||||
points.rightCp2 = points.rightCp1.flipY()
|
||||
points.bottomCp1 = points.bottomCp2.flipX()
|
||||
} while (Math.abs(delta) > 1)
|
||||
|
||||
points.left = points.right.flipX()
|
||||
points.leftCp1 = points.rightCp2.flipX()
|
||||
points.leftCp2 = points.rightCp1.flipX()
|
||||
points.rightCp2 = points.rightCp1.flipY()
|
||||
points.bottomCp1 = points.bottomCp2.flipX()
|
||||
|
||||
points.top = points.bottom.flipY()
|
||||
points.topCp1 = points.bottomCp2.flipY()
|
||||
points.topCp2 = points.bottomCp1.flipY()
|
||||
points.left = points.right.flipX()
|
||||
points.leftCp1 = points.rightCp2.flipX()
|
||||
points.leftCp2 = points.rightCp1.flipX()
|
||||
|
||||
/*
|
||||
* Construct the outline
|
||||
*/
|
||||
let width = measurements.head * options.widthRatio
|
||||
let length = measurements.head * options.lengthRatio
|
||||
points.top = points.bottom.flipY()
|
||||
points.topCp1 = points.bottomCp2.flipY()
|
||||
points.topCp2 = points.bottomCp1.flipY()
|
||||
|
||||
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.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)
|
||||
- Construct the outline
|
||||
_/
|
||||
let width = measurements.head _ options.widthRatio
|
||||
let length = measurements.head \* options.lengthRatio
|
||||
|
||||
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.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)
|
||||
|
||||
/*
|
||||
* Round the end of 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()
|
||||
|
||||
/\*
|
||||
|
||||
- Round the end of the straps
|
||||
\*/
|
||||
let 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()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Rotate straps so they don't overlap
|
||||
*/
|
||||
/\*
|
||||
|
||||
- Rotate straps so they don't overlap
|
||||
\*/
|
||||
let 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',
|
||||
]
|
||||
|
||||
while (points.tipRightBottomStart.x > -1) {
|
||||
for (let p of rotateThese) points[p] = points[p].rotate(1, points.edgeLeft)
|
||||
}
|
||||
while (points.tipRightBottomStart.x > -1) {
|
||||
for (let p of rotateThese) points[p] = points[p].rotate(1, points.edgeLeft)
|
||||
}
|
||||
|
||||
/*
|
||||
* Add points to anchor snaps on
|
||||
*/
|
||||
/\*
|
||||
|
||||
- Add points to anchor snaps on
|
||||
\*/
|
||||
points.snapLeft = points.top.shiftFractionTowards(points.edgeTop, 0.5)
|
||||
|
||||
/*
|
||||
* Mirror points to the other side
|
||||
*/
|
||||
/\*
|
||||
|
||||
- Mirror points to the other side
|
||||
\*/
|
||||
points.edgeTopRightCp = points.edgeTopLeftCp.flipX()
|
||||
points.topCp1 = points.topCp2.flipX()
|
||||
points.tipLeftTopStart = points.tipRightTopStart.flipX()
|
||||
|
@ -176,83 +186,88 @@ function draftBib({
|
|||
points.tipLeftBottomEnd = points.tipRightBottomEnd.flipX()
|
||||
points.snapRight = points.snapLeft.flipX()
|
||||
|
||||
/*
|
||||
* Round the bottom of the bib
|
||||
* Radius is fixed, but you could use an option for it)
|
||||
*
|
||||
* Macros will return the auto-generated IDs
|
||||
*/
|
||||
/\*
|
||||
|
||||
- Round the bottom of the bib
|
||||
- Radius is fixed, but you could use an option for it)
|
||||
-
|
||||
- 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,
|
||||
}),
|
||||
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
|
||||
*/
|
||||
/_
|
||||
- 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()
|
||||
}
|
||||
for (const id of ['start', 'cp1', 'cp2', 'end']) {
|
||||
points[`${side}${utils.capitalize(id)}`] = points[ids2[side].points[id]].copy()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct the path
|
||||
*/
|
||||
/\*
|
||||
|
||||
- Construct the path
|
||||
\*/
|
||||
paths.seam = new Path()
|
||||
.move(points.edgeLeft)
|
||||
.line(points.bottomLeftStart)
|
||||
.curve(points.bottomLeftCp1, points.bottomLeftCp2, points.bottomLeftEnd)
|
||||
.line(points.bottomRightStart)
|
||||
.curve(points.bottomRightCp1, points.bottomRightCp2, points.bottomRightEnd)
|
||||
.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()
|
||||
.attr('class', 'fabric')
|
||||
.move(points.edgeLeft)
|
||||
.line(points.bottomLeftStart)
|
||||
.curve(points.bottomLeftCp1, points.bottomLeftCp2, points.bottomLeftEnd)
|
||||
.line(points.bottomRightStart)
|
||||
.curve(points.bottomRightCp1, points.bottomRightCp2, points.bottomRightEnd)
|
||||
.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()
|
||||
.attr('class', 'fabric')
|
||||
|
||||
// highlight-start
|
||||
/*
|
||||
*
|
||||
* Annotations
|
||||
*
|
||||
*/
|
||||
// highlight-start
|
||||
/\*
|
||||
|
||||
/*
|
||||
* Add the snaps
|
||||
*/
|
||||
-
|
||||
- Annotations
|
||||
- \*/
|
||||
|
||||
/\*
|
||||
|
||||
- Add the snaps
|
||||
\*/
|
||||
snippets.snapStud = new Snippet('snap-stud', points.snapLeft)
|
||||
snippets.snapSocket = new Snippet('snap-socket', points.snapRight).attr('opacity', 0.5)
|
||||
|
||||
/*
|
||||
* Add the logo
|
||||
*/
|
||||
/\*
|
||||
|
||||
- Add the logo
|
||||
\*/
|
||||
points.logo = new Point(0, 0)
|
||||
snippets.logo = new Snippet('logo', points.logo)
|
||||
// highlight-end
|
||||
|
||||
return part
|
||||
return part
|
||||
}
|
||||
```
|
||||
|
||||
````
|
||||
</Example>
|
||||
|
||||
## Setting the cutlist, adding a title and scalebox
|
||||
|
@ -522,6 +537,6 @@ function draftBib({
|
|||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
````
|
||||
|
||||
</Example>
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
---
|
||||
title: Dealing with laser cutters
|
||||
order: 25
|
||||
sidebar_position: 25
|
||||
---
|
||||
|
||||
Laser cutters is merely an example of a situation where your user wants not the
|
||||
complete detailed pattern with all annotations, but just the outlines.
|
||||
Essentially what we had at the end of part 2 of this tutorial.
|
||||
|
||||
Since then, we've added a bunch of embellishments, and perhaps the user does
|
||||
Since then, we've added a bunch of embellishments, and perhaps the user does
|
||||
not want those.
|
||||
|
||||
Well, good news: there is a setting for that too. That setting is `complete`,
|
||||
Well, good news: there is a setting for that too. That setting is `complete`,
|
||||
and more annotations will automatically take it into account.
|
||||
|
||||
For example, if you put a logo or title on the pattern, it will check the
|
||||
For example, if you put a logo or title on the pattern, it will check the
|
||||
`complete` setting and if it is `false` it will do nothing.
|
||||
When we say we're going to *complete* our pattern, we mean we're going to add
|
||||
When we say we're going to _complete_ our pattern, we mean we're going to add
|
||||
things like a title and a scalebox and so on.
|
||||
|
||||
So while in most scenarios you don't have to worry about `complete`, you
|
||||
So while in most scenarios you don't have to worry about `complete`, you
|
||||
should keep it in mind when you are adding text or paths to the design
|
||||
that should not be shown on a non-complete pattern.
|
||||
|
||||
|
@ -46,15 +46,15 @@ function draftBib({
|
|||
part,
|
||||
}) {
|
||||
|
||||
/*
|
||||
* Construct the neck opening
|
||||
*/
|
||||
const target = (measurements.head * options.neckRatio) / 4
|
||||
let tweak = 1
|
||||
let delta
|
||||
do {
|
||||
points.right = new Point((tweak * measurements.head) / 10, 0)
|
||||
points.bottom = new Point(0, (tweak * measurements.head) / 12)
|
||||
/\*
|
||||
_ Construct the neck opening
|
||||
_/
|
||||
const target = (measurements.head _ options.neckRatio) / 4
|
||||
let tweak = 1
|
||||
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, points.bottom.dy(points.right) / 2)
|
||||
points.bottomCp2 = points.bottom.shift(0, points.bottom.dx(points.right) / 2)
|
||||
|
@ -66,229 +66,229 @@ function draftBib({
|
|||
delta = paths.neck.length() - target
|
||||
if (delta > 0) tweak = tweak * 0.99
|
||||
else tweak = tweak * 1.02
|
||||
} while (Math.abs(delta) > 1)
|
||||
|
||||
points.rightCp2 = points.rightCp1.flipY()
|
||||
points.bottomCp1 = points.bottomCp2.flipX()
|
||||
} while (Math.abs(delta) > 1)
|
||||
|
||||
points.left = points.right.flipX()
|
||||
points.leftCp1 = points.rightCp2.flipX()
|
||||
points.leftCp2 = points.rightCp1.flipX()
|
||||
points.rightCp2 = points.rightCp1.flipY()
|
||||
points.bottomCp1 = points.bottomCp2.flipX()
|
||||
|
||||
points.top = points.bottom.flipY()
|
||||
points.topCp1 = points.bottomCp2.flipY()
|
||||
points.topCp2 = points.bottomCp1.flipY()
|
||||
points.left = points.right.flipX()
|
||||
points.leftCp1 = points.rightCp2.flipX()
|
||||
points.leftCp2 = points.rightCp1.flipX()
|
||||
|
||||
/*
|
||||
* Construct the outline
|
||||
*/
|
||||
let width = measurements.head * options.widthRatio
|
||||
let length = measurements.head * options.lengthRatio
|
||||
points.top = points.bottom.flipY()
|
||||
points.topCp1 = points.bottomCp2.flipY()
|
||||
points.topCp2 = points.bottomCp1.flipY()
|
||||
|
||||
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)
|
||||
/\*
|
||||
_ Construct the outline
|
||||
_/
|
||||
let width = measurements.head _ options.widthRatio
|
||||
let length = measurements.head _ options.lengthRatio
|
||||
|
||||
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.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.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.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)
|
||||
|
||||
/*
|
||||
* Round the end of the straps
|
||||
*/
|
||||
let strap = points.edgeTop.dy(points.top)
|
||||
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.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)
|
||||
/\*
|
||||
_ Round the end of the straps
|
||||
_/
|
||||
let strap = points.edgeTop.dy(points.top)
|
||||
|
||||
/*
|
||||
* 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,
|
||||
}),
|
||||
}
|
||||
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)
|
||||
|
||||
/*
|
||||
* 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()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Rotate straps so they don't overlap
|
||||
*/
|
||||
let rotateThese = [
|
||||
'edgeTopLeftCp',
|
||||
'edgeTop',
|
||||
'tipRight',
|
||||
'tipRightTop',
|
||||
'tipRightTopStart',
|
||||
'tipRightTopCp1',
|
||||
'tipRightTopCp2',
|
||||
'tipRightTopEnd',
|
||||
'tipRightBottomStart',
|
||||
'tipRightBottomCp1',
|
||||
'tipRightBottomCp2',
|
||||
'tipRightBottomEnd',
|
||||
'tipRightBottom',
|
||||
'top',
|
||||
'topCp2',
|
||||
]
|
||||
|
||||
while (points.tipRightBottomStart.x > -1) {
|
||||
for (let p of rotateThese) points[p] = points[p].rotate(1, points.edgeLeft)
|
||||
}
|
||||
|
||||
/*
|
||||
* Add points to anchor snaps on
|
||||
*/
|
||||
points.snapLeft = points.top.shiftFractionTowards(points.edgeTop, 0.5)
|
||||
|
||||
/*
|
||||
* Mirror points to the other side
|
||||
*/
|
||||
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()
|
||||
points.snapRight = points.snapLeft.flipX()
|
||||
|
||||
/*
|
||||
* Round the bottom of the bib
|
||||
* Radius is fixed, but you could use an option for it)
|
||||
*
|
||||
* 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()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct the path
|
||||
*/
|
||||
paths.seam = new Path()
|
||||
.move(points.edgeLeft)
|
||||
.line(points.bottomLeftStart)
|
||||
.curve(points.bottomLeftCp1, points.bottomLeftCp2, points.bottomLeftEnd)
|
||||
.line(points.bottomRightStart)
|
||||
.curve(points.bottomRightCp1, points.bottomRightCp2, points.bottomRightEnd)
|
||||
.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()
|
||||
.attr('class', 'fabric')
|
||||
|
||||
/*
|
||||
*
|
||||
* Annotations
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Cut list
|
||||
*/
|
||||
store.cutlist.addCut({ cut: 1, from: 'fabric' })
|
||||
|
||||
/*
|
||||
* Add the snaps
|
||||
*/
|
||||
snippets.snapStud = new Snippet('snap-stud', points.snapLeft)
|
||||
snippets.snapSocket = new Snippet('snap-socket', points.snapRight).attr('opacity', 0.5)
|
||||
|
||||
// highlight-start
|
||||
/*
|
||||
* Add the bias tape
|
||||
*/
|
||||
if (complete)
|
||||
paths.bias = paths.seam
|
||||
.offset(-5)
|
||||
.addClass('note dashed')
|
||||
.addText('tutorial:finishWithBiasTape', 'center fill-note')
|
||||
// highlight-end
|
||||
|
||||
/*
|
||||
* Add the title
|
||||
*/
|
||||
points.title = points.bottom.shift(-90, 45)
|
||||
macro('title', {
|
||||
at: points.title,
|
||||
nr: 1,
|
||||
title: 'bib',
|
||||
align: 'center',
|
||||
scale: 0.8,
|
||||
})
|
||||
|
||||
/*
|
||||
* Add the scalebox
|
||||
*/
|
||||
points.scalebox = points.title.shift(-90, 65)
|
||||
macro('scalebox', { at: points.scalebox })
|
||||
|
||||
/*
|
||||
* Add the logo
|
||||
*/
|
||||
points.logo = new Point(0, 0)
|
||||
snippets.logo = new Snippet('logo', points.logo)
|
||||
|
||||
return part
|
||||
/\*
|
||||
_ 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,
|
||||
}),
|
||||
}
|
||||
```
|
||||
|
||||
/\*
|
||||
_ 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()
|
||||
}
|
||||
}
|
||||
|
||||
/\*
|
||||
_ Rotate straps so they don't overlap
|
||||
_/
|
||||
let rotateThese = [
|
||||
'edgeTopLeftCp',
|
||||
'edgeTop',
|
||||
'tipRight',
|
||||
'tipRightTop',
|
||||
'tipRightTopStart',
|
||||
'tipRightTopCp1',
|
||||
'tipRightTopCp2',
|
||||
'tipRightTopEnd',
|
||||
'tipRightBottomStart',
|
||||
'tipRightBottomCp1',
|
||||
'tipRightBottomCp2',
|
||||
'tipRightBottomEnd',
|
||||
'tipRightBottom',
|
||||
'top',
|
||||
'topCp2',
|
||||
]
|
||||
|
||||
while (points.tipRightBottomStart.x > -1) {
|
||||
for (let p of rotateThese) points[p] = points[p].rotate(1, points.edgeLeft)
|
||||
}
|
||||
|
||||
/\*
|
||||
_ Add points to anchor snaps on
|
||||
_/
|
||||
points.snapLeft = points.top.shiftFractionTowards(points.edgeTop, 0.5)
|
||||
|
||||
/\*
|
||||
_ Mirror points to the other side
|
||||
_/
|
||||
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()
|
||||
points.snapRight = points.snapLeft.flipX()
|
||||
|
||||
/\*
|
||||
_ Round the bottom of the bib
|
||||
_ Radius is fixed, but you could use an option for it) \*
|
||||
_ 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()
|
||||
}
|
||||
}
|
||||
|
||||
/\*
|
||||
_ Construct the path
|
||||
_/
|
||||
paths.seam = new Path()
|
||||
.move(points.edgeLeft)
|
||||
.line(points.bottomLeftStart)
|
||||
.curve(points.bottomLeftCp1, points.bottomLeftCp2, points.bottomLeftEnd)
|
||||
.line(points.bottomRightStart)
|
||||
.curve(points.bottomRightCp1, points.bottomRightCp2, points.bottomRightEnd)
|
||||
.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()
|
||||
.attr('class', 'fabric')
|
||||
|
||||
/\* \*
|
||||
_ Annotations
|
||||
_
|
||||
\*/
|
||||
|
||||
/\*
|
||||
_ Cut list
|
||||
_/
|
||||
store.cutlist.addCut({ cut: 1, from: 'fabric' })
|
||||
|
||||
/\*
|
||||
_ Add the snaps
|
||||
_/
|
||||
snippets.snapStud = new Snippet('snap-stud', points.snapLeft)
|
||||
snippets.snapSocket = new Snippet('snap-socket', points.snapRight).attr('opacity', 0.5)
|
||||
|
||||
// highlight-start
|
||||
/\*
|
||||
_ Add the bias tape
|
||||
_/
|
||||
if (complete)
|
||||
paths.bias = paths.seam
|
||||
.offset(-5)
|
||||
.addClass('note dashed')
|
||||
.addText('tutorial:finishWithBiasTape', 'center fill-note')
|
||||
// highlight-end
|
||||
|
||||
/\*
|
||||
_ Add the title
|
||||
_/
|
||||
points.title = points.bottom.shift(-90, 45)
|
||||
macro('title', {
|
||||
at: points.title,
|
||||
nr: 1,
|
||||
title: 'bib',
|
||||
align: 'center',
|
||||
scale: 0.8,
|
||||
})
|
||||
|
||||
/\*
|
||||
_ Add the scalebox
|
||||
_/
|
||||
points.scalebox = points.title.shift(-90, 65)
|
||||
macro('scalebox', { at: points.scalebox })
|
||||
|
||||
/\*
|
||||
_ Add the logo
|
||||
_/
|
||||
points.logo = new Point(0, 0)
|
||||
snippets.logo = new Snippet('logo', points.logo)
|
||||
|
||||
return part
|
||||
}
|
||||
|
||||
````
|
||||
</Example>
|
||||
|
||||
|
||||
|
@ -556,6 +556,6 @@ function draftBib({
|
|||
|
||||
return part
|
||||
}
|
||||
```
|
||||
</Example>
|
||||
````
|
||||
|
||||
</Example>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Conclusion
|
||||
order: 90
|
||||
sidebar_position: 90
|
||||
---
|
||||
|
||||
Congratulations, we have created our first pattern. And while it's arguably
|
||||
|
@ -25,13 +25,14 @@ stuck at any moment, or need some help or advice, you can [join our chat
|
|||
room](https://discord.freesewing.org/) and we'll help you out.
|
||||
|
||||
:::note COMMENT (by joost)
|
||||
|
||||
##### How did I do?
|
||||
|
||||
You could do me a real favor by letting me know what you loved or hated about
|
||||
this tutorial.
|
||||
|
||||
Were there areas that were not clear? Did I dwell too long on one topic, or
|
||||
rushed through another one too quickly? Your feedback helps improve things,
|
||||
rushed through another one too quickly? Your feedback helps improve things,
|
||||
so don't be shy and tell me what you think.
|
||||
|
||||
You can reach me at joost@freesewing.org
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Saving space (and trees) with exand
|
||||
order: 40
|
||||
sidebar_position: 40
|
||||
---
|
||||
|
||||
There is one more way we like to save space (and trees): The `expand` setting.
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
---
|
||||
title: How to communicate to the user
|
||||
order: 50
|
||||
sidebar_position: 50
|
||||
---
|
||||
|
||||
As a designer, there are times you want to bring something to the attention of
|
||||
the user. I am not talking about generic information that can go in the
|
||||
the user. I am not talking about generic information that can go in the
|
||||
documentation, but rather a message that is tailored specifically to this
|
||||
pattern, much like this pattern is specifically tailored to the user.
|
||||
|
||||
|
@ -47,15 +47,15 @@ function draftBib({
|
|||
part,
|
||||
}) {
|
||||
|
||||
/*
|
||||
* Construct the neck opening
|
||||
*/
|
||||
const target = (measurements.head * options.neckRatio) / 4
|
||||
let tweak = 1
|
||||
let delta
|
||||
do {
|
||||
points.right = new Point((tweak * measurements.head) / 10, 0)
|
||||
points.bottom = new Point(0, (tweak * measurements.head) / 12)
|
||||
/\*
|
||||
_ Construct the neck opening
|
||||
_/
|
||||
const target = (measurements.head _ options.neckRatio) / 4
|
||||
let tweak = 1
|
||||
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, points.bottom.dy(points.right) / 2)
|
||||
points.bottomCp2 = points.bottom.shift(0, points.bottom.dx(points.right) / 2)
|
||||
|
@ -67,277 +67,278 @@ function draftBib({
|
|||
delta = paths.neck.length() - target
|
||||
if (delta > 0) tweak = tweak * 0.99
|
||||
else tweak = tweak * 1.02
|
||||
} while (Math.abs(delta) > 1)
|
||||
|
||||
points.rightCp2 = points.rightCp1.flipY()
|
||||
points.bottomCp1 = points.bottomCp2.flipX()
|
||||
} while (Math.abs(delta) > 1)
|
||||
|
||||
points.left = points.right.flipX()
|
||||
points.leftCp1 = points.rightCp2.flipX()
|
||||
points.leftCp2 = points.rightCp1.flipX()
|
||||
points.rightCp2 = points.rightCp1.flipY()
|
||||
points.bottomCp1 = points.bottomCp2.flipX()
|
||||
|
||||
points.top = points.bottom.flipY()
|
||||
points.topCp1 = points.bottomCp2.flipY()
|
||||
points.topCp2 = points.bottomCp1.flipY()
|
||||
points.left = points.right.flipX()
|
||||
points.leftCp1 = points.rightCp2.flipX()
|
||||
points.leftCp2 = points.rightCp1.flipX()
|
||||
|
||||
/*
|
||||
* Construct the outline
|
||||
*/
|
||||
let width = measurements.head * options.widthRatio
|
||||
let length = measurements.head * options.lengthRatio
|
||||
points.top = points.bottom.flipY()
|
||||
points.topCp1 = points.bottomCp2.flipY()
|
||||
points.topCp2 = points.bottomCp1.flipY()
|
||||
|
||||
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)
|
||||
/\*
|
||||
_ Construct the outline
|
||||
_/
|
||||
let width = measurements.head _ options.widthRatio
|
||||
let length = measurements.head _ options.lengthRatio
|
||||
|
||||
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.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.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.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)
|
||||
|
||||
/*
|
||||
* Round the end of the straps
|
||||
*/
|
||||
let strap = points.edgeTop.dy(points.top)
|
||||
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.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)
|
||||
/\*
|
||||
_ Round the end of the straps
|
||||
_/
|
||||
let strap = points.edgeTop.dy(points.top)
|
||||
|
||||
/*
|
||||
* 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,
|
||||
}),
|
||||
}
|
||||
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)
|
||||
|
||||
/*
|
||||
* 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()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Rotate straps so they don't overlap
|
||||
*/
|
||||
let rotateThese = [
|
||||
'edgeTopLeftCp',
|
||||
'edgeTop',
|
||||
'tipRight',
|
||||
'tipRightTop',
|
||||
'tipRightTopStart',
|
||||
'tipRightTopCp1',
|
||||
'tipRightTopCp2',
|
||||
'tipRightTopEnd',
|
||||
'tipRightBottomStart',
|
||||
'tipRightBottomCp1',
|
||||
'tipRightBottomCp2',
|
||||
'tipRightBottomEnd',
|
||||
'tipRightBottom',
|
||||
'top',
|
||||
'topCp2',
|
||||
]
|
||||
|
||||
while (points.tipRightBottomStart.x > -1) {
|
||||
for (let p of rotateThese) points[p] = points[p].rotate(1, points.edgeLeft)
|
||||
}
|
||||
|
||||
/*
|
||||
* Add points to anchor snaps on
|
||||
*/
|
||||
points.snapLeft = points.top.shiftFractionTowards(points.edgeTop, 0.5)
|
||||
|
||||
/*
|
||||
* Mirror points to the other side
|
||||
*/
|
||||
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()
|
||||
points.snapRight = points.snapLeft.flipX()
|
||||
|
||||
/*
|
||||
* Round the bottom of the bib
|
||||
* Radius is fixed, but you could use an option for it)
|
||||
*
|
||||
* 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()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct the path
|
||||
*/
|
||||
paths.seam = new Path()
|
||||
.move(points.edgeLeft)
|
||||
.line(points.bottomLeftStart)
|
||||
.curve(points.bottomLeftCp1, points.bottomLeftCp2, points.bottomLeftEnd)
|
||||
.line(points.bottomRightStart)
|
||||
.curve(points.bottomRightCp1, points.bottomRightCp2, points.bottomRightEnd)
|
||||
.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()
|
||||
.attr('class', 'fabric')
|
||||
|
||||
/*
|
||||
*
|
||||
* Annotations
|
||||
*
|
||||
*/
|
||||
|
||||
// highlight-start
|
||||
/*
|
||||
* Let the user know about the bias tape and fabric requirements
|
||||
*/
|
||||
store.flag.note({
|
||||
msg: 'tutorial:biasTapeLength',
|
||||
replace: {
|
||||
l: units(paths.seam.length()),
|
||||
},
|
||||
})
|
||||
// highlight-end
|
||||
|
||||
/*
|
||||
* Cut list
|
||||
*/
|
||||
store.cutlist.addCut({ cut: 1, from: 'fabric' })
|
||||
|
||||
/*
|
||||
* Add the snaps
|
||||
*/
|
||||
snippets.snapStud = new Snippet('snap-stud', points.snapLeft)
|
||||
snippets.snapSocket = new Snippet('snap-socket', points.snapRight).attr('opacity', 0.5)
|
||||
|
||||
/*
|
||||
* Add the bias tape
|
||||
*/
|
||||
if (complete)
|
||||
paths.bias = paths.seam
|
||||
.offset(-5)
|
||||
.addClass('note dashed')
|
||||
.addText('finishWithBiasTape', 'center fill-note')
|
||||
|
||||
/*
|
||||
* Add the title
|
||||
*/
|
||||
points.title = points.bottom.shift(-90, 45)
|
||||
macro('title', {
|
||||
at: points.title,
|
||||
nr: 1,
|
||||
title: 'bib',
|
||||
align: 'center',
|
||||
scale: 0.8,
|
||||
})
|
||||
|
||||
/*
|
||||
* Add the scalebox
|
||||
*/
|
||||
points.scalebox = points.title.shift(-90, 65)
|
||||
macro('scalebox', { at: points.scalebox })
|
||||
|
||||
/*
|
||||
* Add the logo
|
||||
*/
|
||||
points.logo = new Point(0, 0)
|
||||
snippets.logo = new Snippet('logo', points.logo)
|
||||
|
||||
/*
|
||||
* Add dimensions
|
||||
*/
|
||||
macro('hd', {
|
||||
id: 'wFull',
|
||||
from: points.bottomLeftStart,
|
||||
to: points.bottomRightEnd,
|
||||
y: points.bottomLeft.y + 15,
|
||||
})
|
||||
macro('vd', {
|
||||
id: 'hBottomToOpeningBottom',
|
||||
from: points.bottomRightStart,
|
||||
to: points.bottom,
|
||||
x: points.bottomRight.x + 15,
|
||||
})
|
||||
macro('vd', {
|
||||
id: 'hBottomToOpeningCenter',
|
||||
from: points.bottomRightStart,
|
||||
to: points.right,
|
||||
x: points.bottomRight.x + 30,
|
||||
})
|
||||
macro('vd', {
|
||||
id: 'hTotal',
|
||||
from: points.bottomRightStart,
|
||||
to: points.tipLeftTopStart,
|
||||
x: points.bottomRight.x + 45,
|
||||
})
|
||||
macro('hd', {
|
||||
id: 'wOpening',
|
||||
from: points.left,
|
||||
to: points.right,
|
||||
y: points.left.y + 25,
|
||||
})
|
||||
macro('ld', {
|
||||
id: 'wStrap',
|
||||
from: points.tipLeftBottomEnd,
|
||||
to: points.tipLeftTopStart,
|
||||
d: -15,
|
||||
})
|
||||
|
||||
return part
|
||||
/\*
|
||||
_ 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,
|
||||
}),
|
||||
}
|
||||
|
||||
/\*
|
||||
_ 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()
|
||||
}
|
||||
}
|
||||
|
||||
/\*
|
||||
_ Rotate straps so they don't overlap
|
||||
_/
|
||||
let rotateThese = [
|
||||
'edgeTopLeftCp',
|
||||
'edgeTop',
|
||||
'tipRight',
|
||||
'tipRightTop',
|
||||
'tipRightTopStart',
|
||||
'tipRightTopCp1',
|
||||
'tipRightTopCp2',
|
||||
'tipRightTopEnd',
|
||||
'tipRightBottomStart',
|
||||
'tipRightBottomCp1',
|
||||
'tipRightBottomCp2',
|
||||
'tipRightBottomEnd',
|
||||
'tipRightBottom',
|
||||
'top',
|
||||
'topCp2',
|
||||
]
|
||||
|
||||
while (points.tipRightBottomStart.x > -1) {
|
||||
for (let p of rotateThese) points[p] = points[p].rotate(1, points.edgeLeft)
|
||||
}
|
||||
|
||||
/\*
|
||||
_ Add points to anchor snaps on
|
||||
_/
|
||||
points.snapLeft = points.top.shiftFractionTowards(points.edgeTop, 0.5)
|
||||
|
||||
/\*
|
||||
_ Mirror points to the other side
|
||||
_/
|
||||
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()
|
||||
points.snapRight = points.snapLeft.flipX()
|
||||
|
||||
/\*
|
||||
_ Round the bottom of the bib
|
||||
_ Radius is fixed, but you could use an option for it) \*
|
||||
_ 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()
|
||||
}
|
||||
}
|
||||
|
||||
/\*
|
||||
_ Construct the path
|
||||
_/
|
||||
paths.seam = new Path()
|
||||
.move(points.edgeLeft)
|
||||
.line(points.bottomLeftStart)
|
||||
.curve(points.bottomLeftCp1, points.bottomLeftCp2, points.bottomLeftEnd)
|
||||
.line(points.bottomRightStart)
|
||||
.curve(points.bottomRightCp1, points.bottomRightCp2, points.bottomRightEnd)
|
||||
.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()
|
||||
.attr('class', 'fabric')
|
||||
|
||||
/\* \*
|
||||
_ Annotations
|
||||
_
|
||||
\*/
|
||||
|
||||
// highlight-start
|
||||
/\*
|
||||
_ Let the user know about the bias tape and fabric requirements
|
||||
_/
|
||||
store.flag.note({
|
||||
msg: 'tutorial:biasTapeLength',
|
||||
replace: {
|
||||
l: units(paths.seam.length()),
|
||||
},
|
||||
})
|
||||
// highlight-end
|
||||
|
||||
/\*
|
||||
_ Cut list
|
||||
_/
|
||||
store.cutlist.addCut({ cut: 1, from: 'fabric' })
|
||||
|
||||
/\*
|
||||
_ Add the snaps
|
||||
_/
|
||||
snippets.snapStud = new Snippet('snap-stud', points.snapLeft)
|
||||
snippets.snapSocket = new Snippet('snap-socket', points.snapRight).attr('opacity', 0.5)
|
||||
|
||||
/\*
|
||||
_ Add the bias tape
|
||||
_/
|
||||
if (complete)
|
||||
paths.bias = paths.seam
|
||||
.offset(-5)
|
||||
.addClass('note dashed')
|
||||
.addText('finishWithBiasTape', 'center fill-note')
|
||||
|
||||
/\*
|
||||
_ Add the title
|
||||
_/
|
||||
points.title = points.bottom.shift(-90, 45)
|
||||
macro('title', {
|
||||
at: points.title,
|
||||
nr: 1,
|
||||
title: 'bib',
|
||||
align: 'center',
|
||||
scale: 0.8,
|
||||
})
|
||||
|
||||
/\*
|
||||
_ Add the scalebox
|
||||
_/
|
||||
points.scalebox = points.title.shift(-90, 65)
|
||||
macro('scalebox', { at: points.scalebox })
|
||||
|
||||
/\*
|
||||
_ Add the logo
|
||||
_/
|
||||
points.logo = new Point(0, 0)
|
||||
snippets.logo = new Snippet('logo', points.logo)
|
||||
|
||||
/\*
|
||||
_ Add dimensions
|
||||
_/
|
||||
macro('hd', {
|
||||
id: 'wFull',
|
||||
from: points.bottomLeftStart,
|
||||
to: points.bottomRightEnd,
|
||||
y: points.bottomLeft.y + 15,
|
||||
})
|
||||
macro('vd', {
|
||||
id: 'hBottomToOpeningBottom',
|
||||
from: points.bottomRightStart,
|
||||
to: points.bottom,
|
||||
x: points.bottomRight.x + 15,
|
||||
})
|
||||
macro('vd', {
|
||||
id: 'hBottomToOpeningCenter',
|
||||
from: points.bottomRightStart,
|
||||
to: points.right,
|
||||
x: points.bottomRight.x + 30,
|
||||
})
|
||||
macro('vd', {
|
||||
id: 'hTotal',
|
||||
from: points.bottomRightStart,
|
||||
to: points.tipLeftTopStart,
|
||||
x: points.bottomRight.x + 45,
|
||||
})
|
||||
macro('hd', {
|
||||
id: 'wOpening',
|
||||
from: points.left,
|
||||
to: points.right,
|
||||
y: points.left.y + 25,
|
||||
})
|
||||
macro('ld', {
|
||||
id: 'wStrap',
|
||||
from: points.tipLeftBottomEnd,
|
||||
to: points.tipLeftTopStart,
|
||||
d: -15,
|
||||
})
|
||||
|
||||
return part
|
||||
}
|
||||
|
||||
```
|
||||
</Example>
|
||||
```
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Supporting translation
|
||||
order: 80
|
||||
sidebar_position: 80
|
||||
---
|
||||
|
||||
:::note [FIXME]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Facilitating frontend integration
|
||||
order: 60
|
||||
sidebar_position: 60
|
||||
---
|
||||
|
||||
Strictly speaking, this tutorial is about learning to use FreeSewing's core
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Supporting paperless patterns
|
||||
order: 30
|
||||
sidebar_position: 30
|
||||
---
|
||||
|
||||
The goal of paperless patterns is to create a pattern that we don't need to
|
||||
|
@ -14,14 +14,14 @@ So let's make the extra effort to make our bib design support paperless.
|
|||
## The paperless setting
|
||||
|
||||
Users can request paperless patterns by setting [the `paperless`
|
||||
setting](/reference/settings/paperless) to a *truthy* value.
|
||||
setting](/reference/settings/paperless) to a _truthy_ value.
|
||||
|
||||
With paperless enabled, FreeSewing will automatically render a grid for each
|
||||
pattern part with metric or imperial markings, depending on the units requested
|
||||
by the user.
|
||||
|
||||
Such a grid is already a good starting point. In addition, we'll be using
|
||||
different macros to add *dimensions* to the pattern.
|
||||
different macros to add _dimensions_ to the pattern.
|
||||
|
||||
While the grid gets added automatically, the dimensions we have to add ourselves.
|
||||
Thankfully, there's macros that can help us with that, specifically:
|
||||
|
@ -58,15 +58,15 @@ function draftBib({
|
|||
part,
|
||||
}) {
|
||||
|
||||
/*
|
||||
* Construct the neck opening
|
||||
*/
|
||||
const target = (measurements.head * options.neckRatio) / 4
|
||||
let tweak = 1
|
||||
let delta
|
||||
do {
|
||||
points.right = new Point((tweak * measurements.head) / 10, 0)
|
||||
points.bottom = new Point(0, (tweak * measurements.head) / 12)
|
||||
/\*
|
||||
_ Construct the neck opening
|
||||
_/
|
||||
const target = (measurements.head _ options.neckRatio) / 4
|
||||
let tweak = 1
|
||||
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, points.bottom.dy(points.right) / 2)
|
||||
points.bottomCp2 = points.bottom.shift(0, points.bottom.dx(points.right) / 2)
|
||||
|
@ -78,267 +78,268 @@ function draftBib({
|
|||
delta = paths.neck.length() - target
|
||||
if (delta > 0) tweak = tweak * 0.99
|
||||
else tweak = tweak * 1.02
|
||||
} while (Math.abs(delta) > 1)
|
||||
|
||||
points.rightCp2 = points.rightCp1.flipY()
|
||||
points.bottomCp1 = points.bottomCp2.flipX()
|
||||
} while (Math.abs(delta) > 1)
|
||||
|
||||
points.left = points.right.flipX()
|
||||
points.leftCp1 = points.rightCp2.flipX()
|
||||
points.leftCp2 = points.rightCp1.flipX()
|
||||
points.rightCp2 = points.rightCp1.flipY()
|
||||
points.bottomCp1 = points.bottomCp2.flipX()
|
||||
|
||||
points.top = points.bottom.flipY()
|
||||
points.topCp1 = points.bottomCp2.flipY()
|
||||
points.topCp2 = points.bottomCp1.flipY()
|
||||
points.left = points.right.flipX()
|
||||
points.leftCp1 = points.rightCp2.flipX()
|
||||
points.leftCp2 = points.rightCp1.flipX()
|
||||
|
||||
/*
|
||||
* Construct the outline
|
||||
*/
|
||||
let width = measurements.head * options.widthRatio
|
||||
let length = measurements.head * options.lengthRatio
|
||||
points.top = points.bottom.flipY()
|
||||
points.topCp1 = points.bottomCp2.flipY()
|
||||
points.topCp2 = points.bottomCp1.flipY()
|
||||
|
||||
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)
|
||||
/\*
|
||||
_ Construct the outline
|
||||
_/
|
||||
let width = measurements.head _ options.widthRatio
|
||||
let length = measurements.head _ options.lengthRatio
|
||||
|
||||
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.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.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.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)
|
||||
|
||||
/*
|
||||
* Round the end of the straps
|
||||
*/
|
||||
let strap = points.edgeTop.dy(points.top)
|
||||
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.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)
|
||||
/\*
|
||||
_ Round the end of the straps
|
||||
_/
|
||||
let strap = points.edgeTop.dy(points.top)
|
||||
|
||||
/*
|
||||
* 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,
|
||||
}),
|
||||
}
|
||||
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)
|
||||
|
||||
/*
|
||||
* 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()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Rotate straps so they don't overlap
|
||||
*/
|
||||
let rotateThese = [
|
||||
'edgeTopLeftCp',
|
||||
'edgeTop',
|
||||
'tipRight',
|
||||
'tipRightTop',
|
||||
'tipRightTopStart',
|
||||
'tipRightTopCp1',
|
||||
'tipRightTopCp2',
|
||||
'tipRightTopEnd',
|
||||
'tipRightBottomStart',
|
||||
'tipRightBottomCp1',
|
||||
'tipRightBottomCp2',
|
||||
'tipRightBottomEnd',
|
||||
'tipRightBottom',
|
||||
'top',
|
||||
'topCp2',
|
||||
]
|
||||
|
||||
while (points.tipRightBottomStart.x > -1) {
|
||||
for (let p of rotateThese) points[p] = points[p].rotate(1, points.edgeLeft)
|
||||
}
|
||||
|
||||
/*
|
||||
* Add points to anchor snaps on
|
||||
*/
|
||||
points.snapLeft = points.top.shiftFractionTowards(points.edgeTop, 0.5)
|
||||
|
||||
/*
|
||||
* Mirror points to the other side
|
||||
*/
|
||||
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()
|
||||
points.snapRight = points.snapLeft.flipX()
|
||||
|
||||
/*
|
||||
* Round the bottom of the bib
|
||||
* Radius is fixed, but you could use an option for it)
|
||||
*
|
||||
* 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()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct the path
|
||||
*/
|
||||
paths.seam = new Path()
|
||||
.move(points.edgeLeft)
|
||||
.line(points.bottomLeftStart)
|
||||
.curve(points.bottomLeftCp1, points.bottomLeftCp2, points.bottomLeftEnd)
|
||||
.line(points.bottomRightStart)
|
||||
.curve(points.bottomRightCp1, points.bottomRightCp2, points.bottomRightEnd)
|
||||
.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()
|
||||
.attr('class', 'fabric')
|
||||
|
||||
/*
|
||||
*
|
||||
* Annotations
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Cut list
|
||||
*/
|
||||
store.cutlist.addCut({ cut: 1, from: 'fabric' })
|
||||
|
||||
/*
|
||||
* Add the snaps
|
||||
*/
|
||||
snippets.snapStud = new Snippet('snap-stud', points.snapLeft)
|
||||
snippets.snapSocket = new Snippet('snap-socket', points.snapRight).attr('opacity', 0.5)
|
||||
|
||||
/*
|
||||
* Add the bias tape
|
||||
*/
|
||||
if (complete)
|
||||
paths.bias = paths.seam
|
||||
.offset(-5)
|
||||
.addClass('note dashed')
|
||||
.addText('fronscratch:finishWithBiasTape', 'center fill-note')
|
||||
|
||||
/*
|
||||
* Add the title
|
||||
*/
|
||||
points.title = points.bottom.shift(-90, 45)
|
||||
macro('title', {
|
||||
at: points.title,
|
||||
nr: 1,
|
||||
title: 'bib',
|
||||
align: 'center',
|
||||
scale: 0.8,
|
||||
})
|
||||
|
||||
/*
|
||||
* Add the scalebox
|
||||
*/
|
||||
points.scalebox = points.title.shift(-90, 65)
|
||||
macro('scalebox', { at: points.scalebox })
|
||||
|
||||
/*
|
||||
* Add the logo
|
||||
*/
|
||||
points.logo = new Point(0, 0)
|
||||
snippets.logo = new Snippet('logo', points.logo)
|
||||
|
||||
// highlight-start
|
||||
/*
|
||||
* Add dimensions
|
||||
*/
|
||||
macro('hd', {
|
||||
id: 'wFull',
|
||||
from: points.bottomLeftStart,
|
||||
to: points.bottomRightEnd,
|
||||
y: points.bottomLeft.y + 15,
|
||||
})
|
||||
macro('vd', {
|
||||
id: 'hBottomToOpeningBottom',
|
||||
from: points.bottomRightStart,
|
||||
to: points.bottom,
|
||||
x: points.bottomRight.x + 15,
|
||||
})
|
||||
macro('vd', {
|
||||
id: 'hBottomToOpeningCenter',
|
||||
from: points.bottomRightStart,
|
||||
to: points.right,
|
||||
x: points.bottomRight.x + 30,
|
||||
})
|
||||
macro('vd', {
|
||||
id: 'hTotal',
|
||||
from: points.bottomRightStart,
|
||||
to: points.tipLeftTopStart,
|
||||
x: points.bottomRight.x + 45,
|
||||
})
|
||||
macro('hd', {
|
||||
id: 'wOpening',
|
||||
from: points.left,
|
||||
to: points.right,
|
||||
y: points.left.y + 25,
|
||||
})
|
||||
macro('ld', {
|
||||
id: 'wStrap',
|
||||
from: points.tipLeftBottomEnd,
|
||||
to: points.tipLeftTopStart,
|
||||
d: -15,
|
||||
})
|
||||
// highlight-end
|
||||
|
||||
return part
|
||||
/\*
|
||||
_ 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,
|
||||
}),
|
||||
}
|
||||
|
||||
/\*
|
||||
_ 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()
|
||||
}
|
||||
}
|
||||
|
||||
/\*
|
||||
_ Rotate straps so they don't overlap
|
||||
_/
|
||||
let rotateThese = [
|
||||
'edgeTopLeftCp',
|
||||
'edgeTop',
|
||||
'tipRight',
|
||||
'tipRightTop',
|
||||
'tipRightTopStart',
|
||||
'tipRightTopCp1',
|
||||
'tipRightTopCp2',
|
||||
'tipRightTopEnd',
|
||||
'tipRightBottomStart',
|
||||
'tipRightBottomCp1',
|
||||
'tipRightBottomCp2',
|
||||
'tipRightBottomEnd',
|
||||
'tipRightBottom',
|
||||
'top',
|
||||
'topCp2',
|
||||
]
|
||||
|
||||
while (points.tipRightBottomStart.x > -1) {
|
||||
for (let p of rotateThese) points[p] = points[p].rotate(1, points.edgeLeft)
|
||||
}
|
||||
|
||||
/\*
|
||||
_ Add points to anchor snaps on
|
||||
_/
|
||||
points.snapLeft = points.top.shiftFractionTowards(points.edgeTop, 0.5)
|
||||
|
||||
/\*
|
||||
_ Mirror points to the other side
|
||||
_/
|
||||
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()
|
||||
points.snapRight = points.snapLeft.flipX()
|
||||
|
||||
/\*
|
||||
_ Round the bottom of the bib
|
||||
_ Radius is fixed, but you could use an option for it) \*
|
||||
_ 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()
|
||||
}
|
||||
}
|
||||
|
||||
/\*
|
||||
_ Construct the path
|
||||
_/
|
||||
paths.seam = new Path()
|
||||
.move(points.edgeLeft)
|
||||
.line(points.bottomLeftStart)
|
||||
.curve(points.bottomLeftCp1, points.bottomLeftCp2, points.bottomLeftEnd)
|
||||
.line(points.bottomRightStart)
|
||||
.curve(points.bottomRightCp1, points.bottomRightCp2, points.bottomRightEnd)
|
||||
.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()
|
||||
.attr('class', 'fabric')
|
||||
|
||||
/\* \*
|
||||
_ Annotations
|
||||
_
|
||||
\*/
|
||||
|
||||
/\*
|
||||
_ Cut list
|
||||
_/
|
||||
store.cutlist.addCut({ cut: 1, from: 'fabric' })
|
||||
|
||||
/\*
|
||||
_ Add the snaps
|
||||
_/
|
||||
snippets.snapStud = new Snippet('snap-stud', points.snapLeft)
|
||||
snippets.snapSocket = new Snippet('snap-socket', points.snapRight).attr('opacity', 0.5)
|
||||
|
||||
/\*
|
||||
_ Add the bias tape
|
||||
_/
|
||||
if (complete)
|
||||
paths.bias = paths.seam
|
||||
.offset(-5)
|
||||
.addClass('note dashed')
|
||||
.addText('fronscratch:finishWithBiasTape', 'center fill-note')
|
||||
|
||||
/\*
|
||||
_ Add the title
|
||||
_/
|
||||
points.title = points.bottom.shift(-90, 45)
|
||||
macro('title', {
|
||||
at: points.title,
|
||||
nr: 1,
|
||||
title: 'bib',
|
||||
align: 'center',
|
||||
scale: 0.8,
|
||||
})
|
||||
|
||||
/\*
|
||||
_ Add the scalebox
|
||||
_/
|
||||
points.scalebox = points.title.shift(-90, 65)
|
||||
macro('scalebox', { at: points.scalebox })
|
||||
|
||||
/\*
|
||||
_ Add the logo
|
||||
_/
|
||||
points.logo = new Point(0, 0)
|
||||
snippets.logo = new Snippet('logo', points.logo)
|
||||
|
||||
// highlight-start
|
||||
/\*
|
||||
_ Add dimensions
|
||||
_/
|
||||
macro('hd', {
|
||||
id: 'wFull',
|
||||
from: points.bottomLeftStart,
|
||||
to: points.bottomRightEnd,
|
||||
y: points.bottomLeft.y + 15,
|
||||
})
|
||||
macro('vd', {
|
||||
id: 'hBottomToOpeningBottom',
|
||||
from: points.bottomRightStart,
|
||||
to: points.bottom,
|
||||
x: points.bottomRight.x + 15,
|
||||
})
|
||||
macro('vd', {
|
||||
id: 'hBottomToOpeningCenter',
|
||||
from: points.bottomRightStart,
|
||||
to: points.right,
|
||||
x: points.bottomRight.x + 30,
|
||||
})
|
||||
macro('vd', {
|
||||
id: 'hTotal',
|
||||
from: points.bottomRightStart,
|
||||
to: points.tipLeftTopStart,
|
||||
x: points.bottomRight.x + 45,
|
||||
})
|
||||
macro('hd', {
|
||||
id: 'wOpening',
|
||||
from: points.left,
|
||||
to: points.right,
|
||||
y: points.left.y + 25,
|
||||
})
|
||||
macro('ld', {
|
||||
id: 'wStrap',
|
||||
from: points.tipLeftBottomEnd,
|
||||
to: points.tipLeftTopStart,
|
||||
d: -15,
|
||||
})
|
||||
// highlight-end
|
||||
|
||||
return part
|
||||
}
|
||||
|
||||
```
|
||||
</Example>
|
||||
```
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Adding seam allowance
|
||||
order: 10
|
||||
sidebar_position: 10
|
||||
---
|
||||
|
||||
When adding seam allowance to a pattern, there are 3 things that come into play:
|
||||
|
@ -24,29 +24,30 @@ function draftBib({
|
|||
part,
|
||||
}) {
|
||||
|
||||
points.topLeft = new Point(0,0)
|
||||
points.bottomRight = new Point(100,40)
|
||||
points.topRight = new Point(points.bottomRight.x, points.topLeft.y)
|
||||
points.bottomLeft = new Point(points.topLeft.x, points.bottomRight.y)
|
||||
points.cp1 = new Point(50, 20)
|
||||
points.cp2 = new Point(70, 60)
|
||||
points.topLeft = new Point(0,0)
|
||||
points.bottomRight = new Point(100,40)
|
||||
points.topRight = new Point(points.bottomRight.x, points.topLeft.y)
|
||||
points.bottomLeft = new Point(points.topLeft.x, points.bottomRight.y)
|
||||
points.cp1 = new Point(50, 20)
|
||||
points.cp2 = new Point(70, 60)
|
||||
|
||||
paths.shape = new Path()
|
||||
.move(points.topLeft)
|
||||
.line(points.bottomLeft)
|
||||
.curve(points.cp1, points.cp2, points.bottomRight)
|
||||
.line(points.topRight)
|
||||
.line(points.topLeft)
|
||||
.close()
|
||||
.addClass('fabric')
|
||||
paths.shape = new Path()
|
||||
.move(points.topLeft)
|
||||
.line(points.bottomLeft)
|
||||
.curve(points.cp1, points.cp2, points.bottomRight)
|
||||
.line(points.topRight)
|
||||
.line(points.topLeft)
|
||||
.close()
|
||||
.addClass('fabric')
|
||||
|
||||
// highlight-start
|
||||
if (sa) paths.sa = paths.shape.offset(sa).addClass('fabric sa')
|
||||
// highlight-end
|
||||
// highlight-start
|
||||
if (sa) paths.sa = paths.shape.offset(sa).addClass('fabric sa')
|
||||
// highlight-end
|
||||
|
||||
return part
|
||||
return part
|
||||
}
|
||||
```
|
||||
|
||||
````
|
||||
</Example>
|
||||
|
||||
As you can see from the source, we can destructure an `sa` variable (short for
|
||||
|
@ -63,7 +64,7 @@ seam allowance:
|
|||
if (sa) paths.sa = paths.shape
|
||||
.offset(sa)
|
||||
.addClass('fabric sa')
|
||||
```
|
||||
````
|
||||
|
||||
To refer back to our three question: Whether the user wants seam allowance, and
|
||||
if so how much seam allowance is answered by the `sa` value passed to our draft
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: Testing your designs
|
||||
order: 70
|
||||
sidebar_position: 70
|
||||
---
|
||||
|
||||
With the basic outline of our pattern ready, now would be a good time
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
---
|
||||
title: Tutorials
|
||||
order: zaa
|
||||
---
|
||||
|
||||
You can find a list of all FreeSewing tutorials below:
|
||||
|
@ -14,4 +13,3 @@ You can find a list of all FreeSewing tutorials below:
|
|||
Tutorials are lessons that take you by the hand through a series of steps to complete a project.
|
||||
|
||||
:::
|
||||
|
||||
|
|
|
@ -1,74 +1,46 @@
|
|||
{
|
||||
"name": "@freesewing/dev",
|
||||
"version": "3.3.0-rc.1",
|
||||
"description": "FreeSewing website with documentation for contributors & developers",
|
||||
"author": "Joost De Cock <joost@joost.at> (https://github.com/joostdecock)",
|
||||
"homepage": "https://freesewing.org/",
|
||||
"repository": "github:freesewing/freesewing",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/freesewing/freesewing/issues"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://freesewing.org/patrons/join"
|
||||
},
|
||||
"name": "dev",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "next build",
|
||||
"cibuild": "yarn build && node scripts/algolia.mjs",
|
||||
"clean": "rimraf prebuild/* && rimraf public/locales/*/* && rimraf public/feeds/* && rimraf ../shared/prebuild/data/*",
|
||||
"dev": "next dev -p 8000",
|
||||
"develop": "next dev -p 8000",
|
||||
"i18n": "SITE=dev node --conditions=internal ../shared/prebuild/i18n-only.mjs",
|
||||
"lint": "next lint",
|
||||
"prebuild": "node --conditions=internal --experimental-json-modules ./prebuild.mjs",
|
||||
"serve": "pm2 start npm --name 'dev' -- run start",
|
||||
"start": "yarn prebuild && yarn dev",
|
||||
"wbuild": "next build",
|
||||
"prewbuild": "node --conditions=internal --experimental-json-modules ./prebuild.mjs"
|
||||
"docusaurus": "docusaurus",
|
||||
"start": "docusaurus start",
|
||||
"build": "docusaurus build",
|
||||
"swizzle": "docusaurus swizzle",
|
||||
"deploy": "docusaurus deploy",
|
||||
"clear": "docusaurus clear",
|
||||
"serve": "docusaurus serve",
|
||||
"write-translations": "docusaurus write-translations",
|
||||
"write-heading-ids": "docusaurus write-heading-ids"
|
||||
},
|
||||
"peerDependencies": {},
|
||||
"dependencies": {
|
||||
"@mdx-js/mdx": "^3.0.0",
|
||||
"@docusaurus/core": "3.5.2",
|
||||
"@docusaurus/preset-classic": "3.5.2",
|
||||
"@mdx-js/react": "^3.0.0",
|
||||
"@mdx-js/runtime": "2.0.0-next.9",
|
||||
"@next/bundle-analyzer": "14.2.3",
|
||||
"@tailwindcss/typography": "0.5.13",
|
||||
"algoliasearch": "4.23.3",
|
||||
"daisyui": "4.11.1",
|
||||
"lodash.get": "4.4.2",
|
||||
"lodash.orderby": "4.6.0",
|
||||
"lodash.set": "4.3.2",
|
||||
"next": "14.2.3",
|
||||
"react": "18.3.1",
|
||||
"react-copy-to-clipboard": "5.1.0",
|
||||
"react-dom": "18.3.1",
|
||||
"react-hotkeys-hook": "4.5.0",
|
||||
"react-instantsearch-dom": "6.40.4",
|
||||
"react-instantsearch-hooks-web": "6.47.3",
|
||||
"react-swipeable": "7.0.1",
|
||||
"react-timeago": "7.2.0",
|
||||
"rehype-autolink-headings": "7.1.0",
|
||||
"rehype-highlight": "7.0.0",
|
||||
"rehype-sanitize": "6.0.0",
|
||||
"rehype-slug": "6.0.0",
|
||||
"rehype-stringify": "10.0.1",
|
||||
"remark": "15.0.1",
|
||||
"remark-copy-linked-files": "git+https://git@github.com/joostdecock/remark-copy-linked-files",
|
||||
"remark-gfm": "4.0.0",
|
||||
"strip-markdown": "6.0.0"
|
||||
"clsx": "^2.0.0",
|
||||
"prism-react-renderer": "^2.3.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-markdown": "^9.0.1",
|
||||
"tailwindcss": "^3.4.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "10.4.19",
|
||||
"js-yaml": "4.1.0",
|
||||
"postcss": "8.4.38",
|
||||
"remark-extract-frontmatter": "3.2.0",
|
||||
"remark-mdx-frontmatter": "5.0.0",
|
||||
"tailwindcss": "3.4.3",
|
||||
"yaml-loader": "0.8.1"
|
||||
"@docusaurus/module-type-aliases": "3.5.2",
|
||||
"@docusaurus/types": "3.5.2"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.5%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 3 chrome version",
|
||||
"last 3 firefox version",
|
||||
"last 5 safari version"
|
||||
]
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18.17.0 <22"
|
||||
},
|
||||
"private": true
|
||||
"node": ">=18.0"
|
||||
}
|
||||
}
|
||||
|
|
41
sites/orgdocs/blog/2-20-for-dolls/index.mdx
Normal file
41
sites/orgdocs/blog/2-20-for-dolls/index.mdx
Normal file
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'Photo by Anna Doschechko [via Pexels]'
|
||||
date: '2022-01-24'
|
||||
intro: 'FreeSewing 2.20: Would you like it smaller?'
|
||||
title: 'FreeSewing 2.20: Would you like it smaller?'
|
||||
---
|
||||
|
||||
I'm happy to announce that we've released FreeSewing 2.20, which comes with a
|
||||
feature request that was on our roadmap: Better support for doll clothes. We
|
||||
have some passionate doll enthusiasts in our community which make sense when
|
||||
you consider that our patterns adapt seamlessly to all sorts of measurements,
|
||||
including those of dolls.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
But there's another issue that comes up when generating these tiny patterns,
|
||||
that is that while the pattern itself adapts to the doll measurements, things
|
||||
like font sizes and arrows and logos do not. That causes doll patterns to look
|
||||
like a chaotic mess as the things that are typically taking up just a bit of
|
||||
space tend to overwhelm the actual pattern:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
To make this happen, we've added [a new scale
|
||||
setting](/docs/about/site/draft#scale) that you can find under _Advanced_ after
|
||||
enabling _Expert mode_. We hope those of you making doll clothes will find
|
||||
this useful, and as always [we look forward to hearing your
|
||||
feedback](https://discord.freesewing.org/).
|
||||
|
||||
## More in this release
|
||||
|
||||
2.20 also packs a bunch of changes and improvements, check the
|
||||
[changelog](https://github.com/freesewing/freesewing/blob/develop/CHANGELOG.md#2200-2022-01-24)
|
||||
for the full list.
|
89
sites/orgdocs/blog/2019-yearly-report/index.mdx
Normal file
89
sites/orgdocs/blog/2019-yearly-report/index.mdx
Normal file
|
@ -0,0 +1,89 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'Close-up of a dandelion against a pink background'
|
||||
date: '2019-12-10'
|
||||
intro: '4109 reasons to be happy about 2019'
|
||||
title: '4109 reasons to be happy about 2019'
|
||||
---
|
||||
|
||||
Wow! What a year it's been for FreeSewing.
|
||||
In August we released version 2.0 which was nothing less than a complete rewrite
|
||||
of our entire technology stack.
|
||||
|
||||
For our users, the most obvious change is that you get to see your pattern adapt
|
||||
live in your browser as you tweak options and preferences.
|
||||
It's one of those things that I knew should be possible with the state of web
|
||||
technology today, yet seeing it actually happen still boggles my mind somehow.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
## Scaling is hard, but we made remarkable progress
|
||||
|
||||
Cool as our new technoglogy stack is, it is not the most important work we've done over the last
|
||||
year. Yes, it's pretty neat, and yes it's only possible because of the work done
|
||||
on 2.0. But that work itself is what matters most. The main reason for the 2.0
|
||||
rewrite was to allow the project to scale horizontally. Or to put it bluntly,
|
||||
to allow FreeSewing to go where I could not carry it on my own.
|
||||
|
||||
In a way, FreeSewing has grown up as a (software) project. We have several people
|
||||
making regular contributions, [an active chat room](https://discord.freesewing.org/),
|
||||
[a dedicated website for developer and translator documentation](https://freesewing.dev),
|
||||
a plethora of [packages we publish on NPM](https://www.npmjs.com/search?q=keywords:freesewing),
|
||||
we've contributed fixes and improvements to upstream software we depend on, and we now
|
||||
also have other people and teams who depend on the packages we put out.
|
||||
|
||||
We (currently) have [23 patterns available](/designs/), we publish 62 packages on NPM
|
||||
(the Node.js package registry). Since putting out version 2.0, on average 450 people
|
||||
sign up every month, and our total tally currently stands above 15.000.
|
||||
|
||||
## Translation has never been easier
|
||||
|
||||
Since v2, we've also switched to [Crowdin](https://crowdin.com) for
|
||||
[our translations](https://freesewing.dev/guides/translator/). Translation is arguably
|
||||
the best way to democratize access to our platform, and I'd like to give a shout-out to
|
||||
all people who have helped and continue to help with these efforts.
|
||||
|
||||
It's perhaps also a good time to point out that you too can help with this.
|
||||
Our [documentation for translators](https://freesewing.dev/guides/translator/) is a good
|
||||
place to get started, or stop by [our chat room](https://discord.freesewing.org/).
|
||||
|
||||
## What we're planning for next year
|
||||
|
||||
Our next year plans roughly fall apart into two categories:
|
||||
improving our platform, and adding more patterns.
|
||||
|
||||
As the project grows, so does the amount of work required to keep everything
|
||||
running smoothly. We still have more performance improvements to do, as well as
|
||||
auxiliary tasks such as writing more tests so we can go ahead and change things with
|
||||
confidence, rather than risk that rolling out a new feature causes bugs down the line.
|
||||
|
||||
We also know there is a lot of room for improvement of the user experience (UX), as
|
||||
well as design and user interface (UI). We've been doing the best we can, but it's
|
||||
not really our field of expertise, and we're hoping to find more contributors who can
|
||||
help us in this regard.
|
||||
|
||||
## v2.2 will include a ladies bodice block
|
||||
|
||||
But hey, you want more patterns, right? So rest assured that that's high on our
|
||||
todo list. We are going to apply some affirmative action towards the ladies who have
|
||||
so far been under-served. Not only by making existing patterns available to them
|
||||
(as we did recently with Simone, a ladies version of our Simon pattern) but also
|
||||
by developing a dedicated ladies block to develop patterns on.
|
||||
|
||||
We have earmarked this as a must-have for FreeSewing v2.2, which we hope to be able
|
||||
to release sometime in January.
|
||||
|
||||
We're also looking at ways to get more designers on board with FreeSewing.
|
||||
One plan on the drawing board is to offer pair-programming sessions to designers
|
||||
where they walk us through their vision, and we implement their design in FreeSewing.
|
||||
We're even thinking of live-streaming these sessions so anybody who is interested
|
||||
can drop by and follow along.
|
||||
|
||||
## 'Tis the season for giving
|
||||
|
||||
Thanks to our awesome patrons, revenue was up this year too. As you may or may not know,
|
||||
FreeSewing donates 100% of its revenue to Médecins Sans Frontières/Doctors Without Borders.
|
||||
So this morning, I had the great honour to write a 4109.38€ cheque to [MSF](https://www.msf.org/).
|
||||
|
||||
That felt **real good** so thanks to [all our patrons](/patrons) for their continued support.
|
||||
If you'd like to join this awesome group of people, [you can do so here](/patrons/join).
|
68
sites/orgdocs/blog/2021-wrapup/index.mdx
Normal file
68
sites/orgdocs/blog/2021-wrapup/index.mdx
Normal file
|
@ -0,0 +1,68 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'Picture by Snapwire - Via pexels.com'
|
||||
date: '2022-01-01'
|
||||
intro: "I'm not going to do a whole blog post about 2021 stuff because I feel like most of us just sorta want to move on and forget about it, but if you were looking for a longer read, then here's the table of content of our latest newsletter edition that also went out today:"
|
||||
title: '2021 wrap-up: A new FreeSewing.dev and announcing our bug bounty program'
|
||||
---
|
||||
|
||||
I'm not going to do a whole blog post about 2021 stuff because I feel like most
|
||||
of us just sorta want to move on and forget about it, but if you were looking
|
||||
for a longer read, then here's the table of content of [our latest newsletter
|
||||
edition](/newsletter/2022q1/) that also went out today:
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
- 🎉 2021 is salted and burned
|
||||
- 🧐 What our contributors have been up to in 2021
|
||||
- 🎖️ FreeSewing is now an 'all contributors' project
|
||||
- 🚧 Why version 3 has been put on hold
|
||||
- 🤓 What I've been up to in 2021
|
||||
- 🐛 FreeSewing's bug bounty program
|
||||
- ⛑️ Yearly revenue and where it went (spoiler: same as always)
|
||||
- 🤞 What I hope will happen this year
|
||||
|
||||
Here, I'd like to cherry-pick just those things that I think are exciting right
|
||||
now.
|
||||
|
||||
## freesewing.dev has been rebuilt
|
||||
|
||||
[The effort I started in the summer](https://freesewing.dev/blog/project-2022)
|
||||
came to fruition on the last day of the year as I deployed the new
|
||||
[freesewing.dev](https://freesewing.dev/blog/project-2022) site in production.
|
||||
|
||||
It's a complete redesign, and the code is now [hosted in our
|
||||
monorepo](https://github.com/freesewing/freesewing), which means that [our
|
||||
dedicated repository for
|
||||
freesewing.dev](https://github.com/freesewing/freesewing.dev) has now been
|
||||
archived.
|
||||
|
||||
This effort implemented a bunch of items from [our v3
|
||||
roadmap](https://github.com/freesewing/freesewing/discussions/1278) which has
|
||||
sort of grown into this long list of ideas/plans. From the top of my head:
|
||||
|
||||
- Migrate to NextJS
|
||||
- Better open graph support
|
||||
- Migrate style to TailwindCSS
|
||||
- Migrate blog posts and showcase posts to Strapi
|
||||
- Migrate newsletter to Strapi
|
||||
- Move markdown content into monorepo & merge Crowdin translation projects
|
||||
- Add endpoint to backend for auto-generated open graph images
|
||||
|
||||
Have all been implemented as a direct result or side effect of this effort.
|
||||
|
||||
This site will also become the blueprint for an overhaul of freesewing.org,
|
||||
something that's on the planning for this year.
|
||||
|
||||
## FreeSewing's bug bounty program
|
||||
|
||||
Once again, [read our newsletter](/newsletter/2022q1/) for the entire
|
||||
backstory, but here's the gist of it: We are now launching the FreeSewing bug
|
||||
bounty program:
|
||||
|
||||
> If you find a bug in one of our patterns, or in our core library, we will
|
||||
> (with your permission) add you to our list of contributors, and send you a
|
||||
> little something to say thanks.
|
||||
|
||||
So keep your eyes peeled, and if something seems off, [let us know about
|
||||
it](https://discord.freesewing.org/) and we'll send you some goodies
|
247
sites/orgdocs/blog/a-call-for-help/index.mdx
Normal file
247
sites/orgdocs/blog/a-call-for-help/index.mdx
Normal file
|
@ -0,0 +1,247 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'Note: This post is a long read. Although nowhere near as long as this book'
|
||||
date: '2020-08-30'
|
||||
intro: 'Please help grow FreeSewing beyond what I can do on my own'
|
||||
title: 'Please help grow FreeSewing beyond what I can do on my own'
|
||||
---
|
||||
|
||||
Hi everyone, Joost here. I'm writing this post to address some problems that
|
||||
have been worrying me lately. Specifically, these problems:
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
1. [There is too much work for one
|
||||
person](#problem-1-there-is-too-much-work-for-one-person) 2. [I feel I'm
|
||||
losing track of the sewing
|
||||
community](#problem-2-i-feel-im-losing-track-of-the-community) 3. [I feel
|
||||
insecure about how to deal with the issue of systemic
|
||||
racism](#problem-3-i-feel-insecure-about-how-to-deal-with-the-issue-of-systemic-racism)
|
||||
|
||||
The good news is that it's a relatively short list. The even better news is
|
||||
that all of these problems be addressed by the same solution: [Community
|
||||
building](#community-building).
|
||||
|
||||
Before we get into that, let's briefly look at each problem:
|
||||
|
||||
## Problem 1: There is too much work for one person
|
||||
|
||||
Over the course of the last week I read [Working in public: The making and
|
||||
maintenance of open source software](https://www.amazon.com/dp/0578675862/) by
|
||||
[Nadia Eghbal](https://nadiaeghbal.com/).
|
||||
|
||||
I bought it because I was hoping to find answers to some of the questions that
|
||||
I ask myself. Questions like “_How do other maintainers do it?_”, or “_Am I
|
||||
doing it wrong?_”
|
||||
|
||||
In other words, I was hoping to find a fix for what I increasingly perceive as
|
||||
a problem: The inability to scale my own labour in line with how I'd like to
|
||||
scale FreeSewing, the project.
|
||||
|
||||
I don't want to spoil the book, but it didn't provide any straightforward
|
||||
answers on how to address that problem. It turns out that the vast majority of
|
||||
open source maintainers are in the same boat. Most projects are run by either a
|
||||
single person, or a handful of people.
|
||||
|
||||
There's nothing wrong with that. But it does put a firm upper limit on how much
|
||||
projects like FreeSewing can accomplish.
|
||||
|
||||
## Problem 2: I feel I'm losing track of the sewing community
|
||||
|
||||
I worry that I have been neglecting the communal aspects of FreeSewing, there
|
||||
are no comments or _social_ aspects on the site. I've always felt it was a
|
||||
fool's errand to try to corral people onto your own website. Better to let
|
||||
them have discussions on the platforms of their choice.
|
||||
|
||||
For the sewing community, the platform of choice is often Instagram. Since I
|
||||
have left Instagram a year ago, I feel like I'm getting further away from the
|
||||
sewing community.
|
||||
|
||||
My [reasons for
|
||||
leaving](https://joost.decock.org/post/187710847164/24-hours-from-now-i-want-to-remove-my-instagram)
|
||||
are as valid today as they were back then, but I wish I could connect with the
|
||||
sewing community in a way that works for me.
|
||||
|
||||
## Problem 3: I feel insecure about how to deal with the issue of systemic
|
||||
|
||||
racism.
|
||||
|
||||
First things first: **Black lives matter** ✊🏾
|
||||
|
||||
My insecurity stems from my environment. I am a white, middle-aged, cis-gender
|
||||
man who was born and raised in a country with a history drenched in the blood
|
||||
of people of color ([that country is
|
||||
Belgium](https://en.wikipedia.org/wiki/Atrocities_in_the_Congo_Free_State)).
|
||||
To this day, casual racism permeates all aspects of the society I live in.
|
||||
|
||||
A welcoming and diverse community is a _sine qua non_ for me. But I feel
|
||||
ill-equipped to figure out how to create one on FreeSewing.
|
||||
|
||||
## Community building
|
||||
|
||||
As I mentioned earlier, these things have been on my mind for a while, albeit
|
||||
they were a lot more fuzzy. Then earlier this month I listened to [Black
|
||||
makers matter with Julian Collins on the podcast Love To
|
||||
Sew](https://lovetosewpodcast.com/episodes/episode-156-black-makers-matter-with-julian-collins/).
|
||||
|
||||
[Julian](https://www.instagram.com/juliancreates/) is a patron of FreeSewing
|
||||
(thanks Julian) and actively involved with the [Black Makers
|
||||
Matter](https://www.instagram.com/blkmakersmatter/) movement on Instagram. I
|
||||
reached out to Julian looking for help, and we had a lengthy Zoom call where we
|
||||
talked about his work and how he goes about organizing the community.
|
||||
|
||||
Julian had a lot of good advice. I couldn't possibly cram it all into this
|
||||
post, but it sort of boils down to:
|
||||
|
||||
- Just ask people for help
|
||||
- Be clear about what kind of community you want to build
|
||||
|
||||
So I am taking Julian's advice to heart, and asking for help. Before we get to
|
||||
that though, let's make sure we're all on the same page about the kind of
|
||||
community we're trying to build here.
|
||||
|
||||
## Quick check: Are you on board with FreeSewing's values?
|
||||
|
||||
To ensure that your values are aligned with those of FreeSewing, please take a
|
||||
moment to familiarize yourself with:
|
||||
|
||||
- [Our community standards](/docs/about/community-standards/)
|
||||
- [Our code of conduct](https://freesewing.dev/contributors/code-of-conduct/)
|
||||
- [Our revenue pledge](/docs/about/pledge/)
|
||||
|
||||
If reading that made you happy rather than angry, we could use your help :)
|
||||
|
||||
## Please help grow FreeSewing beyond what I can do on my own
|
||||
|
||||
We're starting simple: We plan to hold a Zoom/Skype/Whatever call every 2 weeks
|
||||
to figure it out as we go. We start the first weekend of September (next
|
||||
weekend). We haven't picked a time yet, for it will depend on the time zones
|
||||
the participants live in.
|
||||
|
||||
If you'd like to attend, please [let us know in our chat
|
||||
room](https://discord.freesewing.org/).
|
||||
|
||||
### What kind of help is needed?
|
||||
|
||||
Beggars can't be choosers. All help is welcome, and I certainly don't want to
|
||||
turn down any volunteers.
|
||||
|
||||
That being said, an overly vague call defuses the message. So I've
|
||||
listed/included a number of _roles_ below to give you an idea of the kind of
|
||||
work that goes into FreeSewing. It's not meant to be an exhaustive list, but
|
||||
merely a starting point for a discussion.
|
||||
|
||||
The order is alphabetic.
|
||||
|
||||
**Backend Developer** You keep our backend in step with the latest frontend
|
||||
developments. Express is no stranger to you. Node JS is a good friend. Or
|
||||
maybe you'd like them to be.
|
||||
|
||||
**Body Ambassador** Maybe you're unusually short or tall. Maybe you have a bit
|
||||
of a pot belly or very large breasts. Maybe you have a disability that requires
|
||||
fit adjustments. Whatever it is, you represent a minority fitting issue, and
|
||||
are willing to act as an ambassador to make sure your needs are heard and
|
||||
understood.
|
||||
|
||||
**Community Builder** You're an extrovert extraordinaire, or you're good at
|
||||
faking it. You enjoy chatting with all sorts of people, and networking is just
|
||||
you doing you. You're like the jelly that molds a group of individuals into a
|
||||
cohesive community.
|
||||
|
||||
**Database Administrator** You look after our database. Other people might
|
||||
feel that's not important, but you know better. You're familiar with MongoDB.
|
||||
|
||||
**Devops Engineer** Your aim is to make almost all these other roles
|
||||
irrelevant by automating the heck out of everything. CI and Github actions are
|
||||
fun for you. You like to sit back and have the robots do the work for you.
|
||||
|
||||
**Frontend Developer** You improve our websites, specifically freesewing.org
|
||||
and freesewing.dev. Both of them are built with
|
||||
[Gatsby](https://www.gatsbyjs.com/), an open source framework for building
|
||||
frontends that is powered by [React](https://reactjs.org/). If you know these
|
||||
things, or would like to learn them, this is your jam.
|
||||
|
||||
**Illustrator** You create illustrations to go alongside the written
|
||||
documentation. If you draw a bicycle from memory, it actually looks like a
|
||||
bicycle.
|
||||
|
||||
**Inclusion & Diversity Manager** You have skin in the game when it comes to
|
||||
inclusion and diversity. You'll help make our community welcoming and diverse.
|
||||
You won't be afraid to tell this pasty white dude when he's wrong.
|
||||
|
||||
**Language Ambassador** You represent FreeSewing in a non-English community.
|
||||
You can help answer questions or triage problem reports. Or you can point out
|
||||
where translations are missing.
|
||||
|
||||
**Pattern Ambassador** You'll be responsible for a specific FreeSewing
|
||||
design/pattern. You'll be _the person_ to ask questions about how to make that
|
||||
pattern. You'll make sure the documentation is not forgotten. And you can
|
||||
help with questions or triage problem reports to developers or designers.
|
||||
|
||||
**Pattern Designer** You come up with new pattern designs for FreeSewing. You
|
||||
might not know how to turn on a computer, but damn if you can't draft a bodice.
|
||||
|
||||
**Pattern Developer** You program new designs for FreeSewing. You might not
|
||||
know how to design sewing patterns, but you're not afraid of Javascript and are
|
||||
happy to team up with a designer to work on a new pattern together.
|
||||
|
||||
**Proofreader** You check original English text of translations for typos
|
||||
and/or grammar mistakes. You propose improvements and watch over a consistent
|
||||
style and tone across FreeSewing's documentation and written text. You're
|
||||
fluent in the language you're proofreading.
|
||||
|
||||
**Social Media Platform Manager** You represent FreeSewing on a _platform_,
|
||||
where platform could be Facebook, Twitter, Instagram, Tiktok, Snapchat, Reddit
|
||||
…. You manage the FreeSewing account on the platform, and use it to
|
||||
interact with the community.
|
||||
|
||||
**System Administrator** You look after our servers. You install updates, make
|
||||
sure certificates are up-to-date, the works. Linux is where your heart lies.
|
||||
You secretly automated most of your work with Ansible but hey, you put the
|
||||
playbooks in Git so no worries.
|
||||
|
||||
**Technical Writer (code)** You write documentation for freesewing.dev, our
|
||||
developers website. You have good writing skills and familiarity with code
|
||||
(Javascript).
|
||||
|
||||
**Technical Writer (sewing)** You write documentation for freesewing.org, our
|
||||
makers website. You have good writing skills and familiarity with sewing.
|
||||
|
||||
**Translator** You translate FreeSewing into one of its additional languages
|
||||
(French, German, Dutch, Spanish) or if you're ambitious, add a new one. You're
|
||||
fluent in the language you're translating to, and have a good grasp of English.
|
||||
|
||||
**UX Designer** You know what UX is and are happy to point out where it sucks
|
||||
and how it can be made better.
|
||||
|
||||
**Release Manager** You pull the plug on new releases, you bundle our code,
|
||||
and publish new versions of our packages on NPM.
|
||||
|
||||
**Web Designer** You know how to make things pretty, even if you're not sure
|
||||
how to actually make them work. You appreciate that we don't use #000 for
|
||||
black.
|
||||
|
||||
### What's in it for me?
|
||||
|
||||
We can't offer you money. Please [read our revenue pledge](/docs/about/pledge/)
|
||||
to understand why that is.
|
||||
|
||||
What we can offer is responsibility, recognition, and a stake in something that
|
||||
strives to be a force for good in this world.
|
||||
|
||||
It can also be an excellent learning opportunity for those of you who would
|
||||
like to pivot to a role in web development. And for as far as my time
|
||||
stretches — I will gladly teach and mentor people from underprivileged
|
||||
communities aiming for social mobility.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Maybe you can help. Maybe you know somebody who can help, or for whom this
|
||||
would be a valuable learning experience.
|
||||
|
||||
Either way, I'd appreciate it if you could help spread the message that I'm
|
||||
asking for help.
|
||||
|
||||
Thank you,
|
||||
|
||||
Joost
|
22
sites/orgdocs/blog/albert-apron/index.mdx
Normal file
22
sites/orgdocs/blog/albert-apron/index.mdx
Normal file
|
@ -0,0 +1,22 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'Keep those home-made clothes clean while cooking with the Albert apron'
|
||||
date: '2020-10-17'
|
||||
intro: 'What do you do if your daughter needed an apron for school?'
|
||||
title: 'We haz apron now: FreeSewing 2.10 brings you Albert, a humble apron pattern'
|
||||
---
|
||||
|
||||
What do you do if your daughter needed an apron for school?
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
- Would you run out to the store and buy one?
|
||||
- Would you fire up your sewing machine and make one?
|
||||
- Would you say to yourself _hmm, better make a pattern first_ and then
|
||||
share your FreeSewing pattern so that now everybody can have an apron?
|
||||
|
||||
Because [that's what Wouter did](/showcase/albert-by-wouter/), so we wrapped it
|
||||
into FreeSewing v2.10, and [voila](/designs/albert/).
|
||||
|
||||

|
67
sites/orgdocs/blog/all-contributors/index.mdx
Normal file
67
sites/orgdocs/blog/all-contributors/index.mdx
Normal file
|
@ -0,0 +1,67 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: "We're saying thanks to our contributors and want to make sure their contributions get the credit they deserve"
|
||||
date: '2021-11-28'
|
||||
intro: 'During our last contributor call , we decided that we would implement the All Contributors specification as a way to honour all our contributors.'
|
||||
title: 'Calling all contributors'
|
||||
---
|
||||
|
||||
During [our last contributor
|
||||
call](https://github.com/freesewing/freesewing/issues/1514), we decided that we
|
||||
would implement the [All Contributors
|
||||
specification](https://allcontributors.org/) as a way to honour all our
|
||||
contributors.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
If on the surface, a contributor call decision to honour contributors sounds
|
||||
like some sort of self-serving nonsense, let me reassure you that there's no
|
||||
risk of dislocated shoulders from patting ourselves on the back. Instead it's
|
||||
about (also) honouring those contributions that tend to go overlooked in Open
|
||||
Source.
|
||||
|
||||
The All Contributors website summerazes it as:
|
||||
|
||||
> This is a specification for recognizing contributors to an open source
|
||||
> project in a way that rewards each and every contribution, not just code.
|
||||
>
|
||||
> People are giving themselves and their free time to contribute to open source
|
||||
> projects in so many ways, so we believe everyone should be praised for their
|
||||
> contributions (code or not).
|
||||
|
||||
When we talk about _contributors_ in open source projects, there is often the
|
||||
assumption that this is all the people who contribute code to the project. The
|
||||
fact the [GitHub lists the contributors of a project based on the actual
|
||||
commits](https://github.com/freesewing/freesewing/graphs/contributors) goes a
|
||||
long way to cement that view.
|
||||
|
||||
But there's plenty of contributions that fly under the radar of an automated
|
||||
system based on the commit history. Things like documentation and blog posts,
|
||||
community building, answering questions or submitting bug reports, are all
|
||||
valuable contributions that deserve to be recognized.
|
||||
|
||||
By implementing the All Contributors specification, we pledge to give those
|
||||
people credit for their contributions, and make that credit visible. In
|
||||
practice the list of contributors will be included in the `README.md` file of
|
||||
all our packages, as well as in the main `README.md` file of [our
|
||||
`freesewing/freesewing` monorepo](https://github.com/freesewing/freesewing).
|
||||
|
||||
In the future, we also plan to make this list available on our website.
|
||||
|
||||
## How does it work?
|
||||
|
||||
Going forward, we will make an effort to add all contributors regardless of how
|
||||
they contribute to the project. But we'd also like to capture contributions
|
||||
that were made up until now.
|
||||
|
||||
For this, we need your help. If you've contributed to FreeSewing, let us know.
|
||||
You can [let us know on Discord](https://discord.freesewing.org/), or you can
|
||||
[create an
|
||||
issue](https://github.com/freesewing/freesewing/issues/new?assignees=joostdecock&labels=%F0%9F%92%9C+all+contributors&template=all-contributors.md&title=All+Contributors%3A+Please+add+%28username+here%29),
|
||||
or you can comment on [any
|
||||
issue](https://github.com/freesewing/freesewing/issues) or [pull
|
||||
request](https://github.com/freesewing/freesewing/pulls) using [the
|
||||
instructions for the all-contributors
|
||||
bot](https://allcontributors.org/docs/en/bot/usage).
|
||||
|
||||
Don't be shy, add yourself :)
|
18
sites/orgdocs/blog/annnouncing-yuri/index.mdx
Normal file
18
sites/orgdocs/blog/annnouncing-yuri/index.mdx
Normal file
|
@ -0,0 +1,18 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'Designer Hellgy struts their stuff, while their Yuri flows in a summer breeze'
|
||||
date: '2021-09-05'
|
||||
intro: "Announcing FreeSewing v2.18: Congratulations, it's a Yuri"
|
||||
title: "Announcing FreeSewing v2.18: Congratulations, it's a Yuri"
|
||||
---
|
||||
|
||||
I'm happy to announce the immediate availability of FreeSewing v2.18 and our
|
||||
latest addition to our catalog of designs: [The Yuri hoodie](/designs/yuri/) .
|
||||
Designed by [Hellgy](https://twitter.com/hellgy) and coded by their bae
|
||||
[Biou](https://github.com/biou/), Yuri is everything they love about [our Huey
|
||||
hoodie](/designs/huey/) sans their arch enemy: zippers.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
Checkout [Hellgy's showcase for more pictures](/showcase/yuri-by-its-designer),
|
||||
or check out [the pattern page itself](/designs/yuri/) for all details.
|
105
sites/orgdocs/blog/announcing-carlita/index.mdx
Normal file
105
sites/orgdocs/blog/announcing-carlita/index.mdx
Normal file
|
@ -0,0 +1,105 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'Picture you and him, in matching coats.'
|
||||
date: '2018-01-26'
|
||||
intro: "This one's for the ladies --- and I'm not (just) talking about that picture of heart-throb Benedict Cumberbatch at the top of this post."
|
||||
title: 'Announcing Carlita, the womenswear version of our Carlton coat.'
|
||||
---
|
||||
|
||||
This one's for the ladies --- and I'm not (just) talking about that picture of
|
||||
heart-throb Benedict Cumberbatch at the top of this post.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
Instead, I'm talking about the release of our latest pattern: the [Carlita
|
||||
Coat](/designs/carlita) which is out in beta as of today.
|
||||
|
||||
Carlita is --- you guessed it --- the womenswear version of our Carlton coat,
|
||||
which recreates the iconic Sherlock Holmes coat worn by BC on the BBC series.
|
||||
|
||||
## How did we do it?
|
||||
|
||||
For details on how this project came to be, I refer you to [the Carlton
|
||||
announcement post](/blog/announcing-carlton-and-bent/). Here, I'd like to
|
||||
focus on the specifics of how we turned this menswear pattern into a coat for
|
||||
ladies.
|
||||
|
||||
We wanted to stay as close to the original as possible, so all we did was make
|
||||
changes to address one challenge: fitting the breasts.
|
||||
|
||||
### Princess, meet your seam
|
||||
|
||||
We drew an extra princess seam in the front panel of the coat, through which we
|
||||
added shaping for the bust.
|
||||
|
||||
To be able to do that accurately, Carlita requires three extra measurements in
|
||||
addition to the measurements required by Carlton. They are:
|
||||
|
||||
- The [high bust](/docs/measurements/#highBust)
|
||||
- The [bust span](/docs/measurements/#bustSpan)
|
||||
- The [high point shoulder to
|
||||
bust](/docs/measurements/#highPointShoulderToBust)
|
||||
|
||||
We use your high bust measurements to draft the coat, and then do a full bust
|
||||
adjustment on the princess seam based on your (full) chest circumference, bust
|
||||
span and HPS to bust.
|
||||
|
||||
### All of the pockets, but we had to move some of them
|
||||
|
||||
The addition of the princess seam made the map pocket placement a bit
|
||||
difficult, so we've slightly moved it, and aligned it vertically, rather than
|
||||
slightly tilted as it is in Carlton.
|
||||
|
||||
This way, the pocket can be integrated in the princess seam, somewhere in the
|
||||
underboob region.
|
||||
|
||||
### One extra option: The princess seam smooth factor
|
||||
|
||||
Carlita also has one extra option that Carlton doesn't have, the somewhat
|
||||
elaborately named [Princess seam smooth
|
||||
factor](/docs/designs/carlita/options#princessSeamSmoothFactor).
|
||||
|
||||
This controls how sharply the princess seam will revert back after having added
|
||||
the extra volume for your chest.
|
||||
|
||||
A picture says more than a thousand words, so here's the option sampled on the
|
||||
relevant part of the pattern:
|
||||
|
||||

|
||||
|
||||
As you can see, the option controls the urgency with which the princess seam
|
||||
reverts back to your waistline after passing the fullest point of your bust.
|
||||
|
||||
A low factor will make for a more fitted coat, but also a more curvy seam that
|
||||
is harder to sew.
|
||||
|
||||
A higher smooth factor will smooth this out so it's a more sloped retreat to
|
||||
the downward seam. This will make the coat less fitted under your chest, and
|
||||
the seam easier to sew.
|
||||
|
||||
## A reminder about made-to-measure patterns
|
||||
|
||||
This goes without saying for regular visitors to this site, but if you're new
|
||||
here, it's worth repeating:
|
||||
|
||||
> This coat is not drafted with a certain cup size in mind. Instead, it will
|
||||
> adapt to your chest based on your measurements.
|
||||
|
||||
## Ladies, we need your feedback
|
||||
|
||||
This is our first womenswear pattern with a fitted chest. As such, we're
|
||||
breaking new ground here, and I'd be interested to see how this pattern adapts
|
||||
to a variety of body shapes/cup sizes.
|
||||
|
||||
If you're planning to make this coat, or a muslin of it, please share your
|
||||
experience, and don't hesitate to get in touch should you run into any issues.
|
||||
|
||||
I plan to design more womenswear patterns, so if there are any fit issues, I'd
|
||||
like to know about it sooner rather than later.
|
||||
|
||||
## Shout-out
|
||||
|
||||
Last but not least, I'd like to thank [Anneke](http://www.annekecaramin.com/)
|
||||
for her help throughout this project, and tolerating my countless rants about
|
||||
my love/hate relationship with boobs.
|
106
sites/orgdocs/blog/announcing-carlton-and-bent/index.mdx
Normal file
106
sites/orgdocs/blog/announcing-carlton-and-bent/index.mdx
Normal file
|
@ -0,0 +1,106 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: "You too can wear this coat. Although you're on your own for the hat. At least for now."
|
||||
date: '2017-12-20'
|
||||
intro: 'Announcing Carlton, aka the Sherlock Holmes coat, and the Bent Body Block'
|
||||
title: 'Announcing Carlton, aka the Sherlock Holmes coat, and the Bent Body Block'
|
||||
---
|
||||
|
||||
Good news everybody, we've got your cosplaying needs covered. That is, if you
|
||||
are cosplaying as Sherlock Holmes. Our newest pattern release, [the Carlton
|
||||
Coat](/designs/carlton) is exactly what the doctor prescribed if for some
|
||||
weird reason your doctor wants you to look like everyone's favorite detective.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
My memory is foggy on the exact origin of this endeavor. It probably involved
|
||||
me complaining about the cold and my lack of a warm winter coat, but apart from
|
||||
that, I'm not too sure.
|
||||
|
||||
What I do remember is that at one point,
|
||||
[Anneke](http://www.annekecaramin.com/) and myself decided that we would
|
||||
reverse-engineer the Sherlock Holmes coat. More specifically, the coat worn by
|
||||
Benedict Cumberbatch in the BBC series Sherlock Holmes.
|
||||
|
||||

|
||||
|
||||
The coat is popular with cosplayers for obvious reasons, but it's also just a
|
||||
really nice coat, and other brave souls [such as
|
||||
Melissa](http://blog.fehrtrade.com/gallery/868/the-sherlock-coat/) have tried
|
||||
their hand at it.
|
||||
|
||||
I must admit that I didn't know Melissa made a similar coat until mine was
|
||||
finished. Furthermore, her blog post mentions that she used the instructions in
|
||||
a livejournal post that is no longer available.
|
||||
|
||||
Anneke and myself did no such thing and just put the pattern together based on
|
||||
screengrabs from the TV show. We're hardcore like that.
|
||||
|
||||
### About the coat
|
||||
|
||||
Carlton is a double-breasted long overcoat in the tradition of horseback
|
||||
uniform coats where the back of the coat isn't split, but rather has wide
|
||||
pleats that can drape over the back of the horse. Or, more realistically, fan
|
||||
open behind you as you walk about.
|
||||
|
||||
 
|
||||
|
||||
It comes with two patch pockets on the front, two map pockets at the chest, and
|
||||
two inner pockets. Six pockets in total, so you'll have plenty of room for all
|
||||
your belongings.
|
||||
|
||||
 
|
||||
|
||||
I finished mine just in time for a trip to Köln to visit my beloved friend
|
||||
and tailor [Sebastian Hoofs](http://sebastian-hoofs.de/massschneider/). It was
|
||||
cold as eff over there, but the coat kept me nice and warm. Not surprising
|
||||
since it's made in a hefty wool I picked up in [Bacci in
|
||||
Florence](http://www.baccitessuti.it/en/index.html) over the summer, and I took
|
||||
the extra step of interlining it with French terry (I really don't like to be
|
||||
cold).
|
||||
|
||||
 
|
||||
|
||||
### Burn the patriarchy to the ground through the power of pockets
|
||||
|
||||
Ladies take note: Carlita --- a female version of Carlton --- is currently on
|
||||
the drawing board.
|
||||
|
||||
Initially, the plan was to release male and female versions side by side, but
|
||||
adapting the coat has proven to be more involved than anticipated because,
|
||||
well, because boobs.
|
||||
|
||||
I also feel like I have to keep too many plates spinning right now, so I'm
|
||||
hopeful that getting Carlton out the door will create some time/space to make
|
||||
Carlita follow soon(ish). Either way, I've promised Anneke that we'd do a
|
||||
female version, and [she's a freesewing Captain now](/patrons), so I intend to
|
||||
keep that promise.
|
||||
|
||||
Oh, and about that title: When Carlita's ready, she will have just as many
|
||||
pockets as Carlton.
|
||||
|
||||
## Also, this: Introducing the Bent Body Block We're actually releasing two
|
||||
|
||||
patterns today. Apart from the Carlton Coat, there's also the [Bent Body
|
||||
Block](/designs/bent).
|
||||
|
||||
Bent is a two-part sleeve variation of our [Brian Body Block](/designs/bent).
|
||||
It's essentially a base for coat and jacket patterns for menswear.
|
||||
|
||||
I originally designed Bent as a base for my [refashioners 2017 zebra
|
||||
jacket](/blog/the-refashioners-2017/), so you can expect that jacket pattern to
|
||||
also hit the site in the coming months.
|
||||
|
||||
Carlton is also based on Bent, so we're giving you both today.
|
||||
|
||||
Have wonderful and happy holidays if you're into that kind of thing. And happy
|
||||
making!
|
103
sites/orgdocs/blog/announcing-charlie/index.mdx
Normal file
103
sites/orgdocs/blog/announcing-charlie/index.mdx
Normal file
|
@ -0,0 +1,103 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'Photo by Flo Dahm from Pexels'
|
||||
date: '2021-04-18'
|
||||
intro: "We've just published FreeSewing v2.15 and it comes with a new pattern: The Charlie Chinos trouser pattern ."
|
||||
title: 'Charlie Chinos: who wants some new trousers?'
|
||||
---
|
||||
|
||||
We've just published FreeSewing v2.15 and it comes with a new pattern: [The
|
||||
Charlie Chinos trouser pattern](/designs/charlie/).
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
I have lost track of how long a chino trouser pattern has been on my to-do
|
||||
list, but it's measured in years. I'm very happy I finally landed where I
|
||||
wanted to be.
|
||||
|
||||
I have a picture of it here, but due to the dark fabric, you can't really make
|
||||
out much:
|
||||
|
||||

|
||||
|
||||
So instead, let me tell you about why I am so excited about this.
|
||||
|
||||
##### Based on Titan
|
||||
|
||||
First up, Charlie is based on Titan, our unisex trouser block that is also the
|
||||
foundation for [our Paco pattern](/designs/paco/). So if you're familiar with
|
||||
any of those, you already know how Charlie will fit you.
|
||||
|
||||
##### More measurements, more options, better fit
|
||||
|
||||
As a token of how much I feel this is an improvement, I've deprecated
|
||||
Theo. Based on an Aldrich draft, Theo uses very few
|
||||
measurements, and while that worked fine for a certain set of people, it's a
|
||||
less versatile pattern.
|
||||
|
||||
Charlie will adapt better to differently shaped bodies, and has a hell of a lot
|
||||
more options that allow you to configure your trousers so you get them just as
|
||||
you like. In case you're wondering, Theo has 5 options, whereas Charlie has 31.
|
||||
|
||||
That being said, we will keep Theo available. Deprecated merely means that
|
||||
we've added a little warning message saying that we recommend Charlie instead.
|
||||
|
||||
##### Easier to make
|
||||
|
||||
Another reason to opt for Charlie rather than Theo: Charlie is easier to make.
|
||||
It has a more straight-forward fly and waistband construction, and the front
|
||||
pockets have been cleverly designed to give you the ease of construction that
|
||||
comes with side-seam pockets, yet the classic look of slanted pockets.
|
||||
|
||||
Theo ranks 4 stars on our difficulty scale, and I've given Charlie 3 stars. If
|
||||
you were afraid of making trousers, this might be the pattern you've been
|
||||
waiting for.
|
||||
|
||||
##### Real pockets
|
||||
|
||||
Charlie is a unisex pattern and the pockets are real. You have welt (aka
|
||||
jetted) pockets at the back, and slanted pockets at the front. In both cases,
|
||||
you have control over the size and depth of the pockets.
|
||||
|
||||
The front pockets deserve a special mention. They look like traditional slanted
|
||||
pockets, but are set in on the side seam. To make that possible, the back panel
|
||||
of the trousers wraps around the front, following the pocket slant.
|
||||
|
||||
## Other 2.15 news
|
||||
|
||||
Charlie is the main act, but there's a lot of work that went in this 2.15
|
||||
release.
|
||||
|
||||
As always, [the
|
||||
changelog](https://github.com/freesewing/freesewing/blob/develop/CHANGELOG.md)
|
||||
has all the details, but allow me to highlight some of the more noteworthy
|
||||
changes:
|
||||
|
||||
- We have [a new bartack
|
||||
plugin](https://freesewing.dev/reference/plugins/bartack/)
|
||||
- The [buttons plugin](https://freesewing.dev/reference/plugins/buttons/)
|
||||
provides new
|
||||
[buttonhole-start](https://freesewing.dev/reference/snippets/buttonhole-start)
|
||||
and
|
||||
[buttonhole-end](https://freesewing.dev/reference/snippets/buttonhole-end)
|
||||
snippets
|
||||
- The [dimension plugin](https://freesewing.dev/reference/plugins/dimension/)
|
||||
provides a new [rmad macro](https://freesewing.dev/reference/macros/rmad/)
|
||||
- The [logo plugin](https://freesewing.dev/reference/plugins/logo/) now
|
||||
supports dark mode
|
||||
- Titan and Paco have a new `waistbandHeight` option
|
||||
- Core no longer rounds point coordinates to avoid misses when using
|
||||
[path.split](https://freesewing.dev/reference/api/path/split/)
|
||||
- [Bella](/designs/bella/) has a fix to the shoulder to better accommodate
|
||||
doll-sized clothing
|
||||
- [Charlie](/designs/charlie/) is the first pattern to list some of the
|
||||
absolute dimensions when configuring a pattern, but we plan to extend this
|
||||
to other designs We have documented [the new raise
|
||||
methods](https://freesewing.dev/reference/api/part/raise) for designers who
|
||||
want to utilize this feature.
|
||||
- Speaking of documentation, the examples in our [documentation for
|
||||
developers](https://freesewing.dev/) now allows you to toggle a switch to
|
||||
reveal the points and paths in the examples
|
||||
- The [part.getId()](https://freesewing.dev/reference/api/part/getid/) method
|
||||
now takes a prefix argument
|
122
sites/orgdocs/blog/announcing-freesewing-library/index.mdx
Normal file
122
sites/orgdocs/blog/announcing-freesewing-library/index.mdx
Normal file
|
@ -0,0 +1,122 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: "I don't drink, but this seemed appropriate for a celebration post ¯\\_(ツ)_/¯"
|
||||
date: '2018-08-25'
|
||||
intro: 'Celebrating one year of freesewing.org: Announcing the freesewing library'
|
||||
title: 'Celebrating one year of freesewing.org: Announcing the freesewing library'
|
||||
---
|
||||
|
||||
Exactly one year ago, the doors of freesewing.org swung open for our users,
|
||||
while those of makemypattern.com get one of those _we've moved_ signs.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
Looking back at [that blog post from 12 months ago](/blog/open-for-business),
|
||||
it almost beggars belief that the things announced then are only one year old.
|
||||
The concept of a draft, the comparison functionality, or even paperless
|
||||
patterns. They all celebrate their first birthday today.
|
||||
|
||||
Not this site though, because [driven by the looming GDPR
|
||||
deadline](/blog/gdpr-plan), we dumped our Jekyll based site for a new front end
|
||||
sometime in May.
|
||||
|
||||
## More languages with less languages
|
||||
|
||||
GDPR was only part of that story. Other reasons for the rewrite were our
|
||||
desire to support multiple languages, and to simplify our technology stack.
|
||||
|
||||
In other words, we wanted to reach people who speak different languages, and
|
||||
wanted to limit the number of programming languages required to do so.
|
||||
|
||||
### More natural languages
|
||||
|
||||
We've done remarkably well on this front. While you won't find every last bit
|
||||
of content translated, this website's main features are now available in five
|
||||
languages:
|
||||
|
||||
- English
|
||||
- German
|
||||
- Spanish
|
||||
- French
|
||||
- Dutch
|
||||
|
||||
Which really is 100% thanks to the great work of our wonderful
|
||||
translators.
|
||||
|
||||
### Less programming languages
|
||||
|
||||
The switch from Jekyll to a [Nuxt](https://nuxtjs.org/)-based front-end has
|
||||
removed [Ruby](https://www.ruby-lang.org/) from our technology stack.
|
||||
Freesewing.org now runs on JavaScript, PHP and a little bit of C (which we'll
|
||||
ignore for now).
|
||||
|
||||
But removing programming languages is not a goal _an sich_. Rather, the
|
||||
underlying ambition is to simplify things, make it easier for people to get
|
||||
involved, and ultimately attract more contributors so that the project can grow
|
||||
and flourish.
|
||||
|
||||
Today, designing/developing patterns is not an insurmountable obstacle. We've
|
||||
got [benjamin](/designs/benjamin), [florent](/designs/florent), and
|
||||
[sandy](/designs/sandy) to show for it. All of these were contributed by
|
||||
people for whom freesewing was initially new, they went through the design
|
||||
tutorial, and in the end created a pattern of their own.
|
||||
|
||||
We'd like more people to follow in their footsteps. So making the process as
|
||||
simple as possible is a worthy investment of our time.
|
||||
|
||||
## Announcing freesewing, the library
|
||||
|
||||
For the past 2 months, I have taken time off from pattern making and sewing to
|
||||
tackle our [technical debt](https://en.wikipedia.org/wiki/Technical_debt).
|
||||
|
||||
Specifically, I've set out to rewrite our core back-end from the ground up in
|
||||
JavaScript. But there's a twist. It's no longer a back-end. It's a library you
|
||||
can use both in your browser, or on the server with
|
||||
[node.js](https://nodejs.org/).
|
||||
|
||||
It is currently in version 0.10, and feature complete with freesewing core.
|
||||
It's [available on GitHub](https://github.com/freesewing/freesewing) and
|
||||
[NPM](https://www.npmjs.com/package/freesewing), and is fully documented at
|
||||
[developer.freesewing.org](https://developer.freesewing.org/).
|
||||
|
||||
And while its API is richer than core's, it's footprint is actually a lot
|
||||
smaller:
|
||||
|
||||

|
||||
|
||||
Which is good news, in case you were wondering.
|
||||
|
||||
## What happens next?
|
||||
|
||||
A lot of work needs to be done before we can actually use this on
|
||||
freesewing.org:
|
||||
|
||||
- All our existing patterns need to be parted to the JS version.
|
||||
[Brian](https://github.com/freesewing/brian) is the first pattern to have
|
||||
been ported.
|
||||
- Rewrite our data back-end in JS. Since this will remove the PHP programming
|
||||
language from our stack.
|
||||
- Build a new website using the freesewing library and our new data back-end.
|
||||
|
||||
This really is a lot of work, and while I hope that by the end of the year
|
||||
we'll have made good progress, I can't promise it will be done.
|
||||
|
||||
## But I just want patterns
|
||||
|
||||
Chances are, all you care about is patterns. What you want is more patterns,
|
||||
better patterns, different patterns. And all of this rewriting is not exactly
|
||||
pushing your buttons.
|
||||
|
||||
I get that. I really do. I for one have a list of patterns I'd like to see
|
||||
added to the site. And my work on other aspects of the project keeps me from
|
||||
adding them.
|
||||
|
||||
But I believe that investing now in a streamlined developer experience will
|
||||
have a knock-on effect in the long term.
|
||||
|
||||
If we want a few extra patterns, this is not the right approach. But if we want
|
||||
a lot more patterns, I believe it is.
|
||||
|
||||
And I want a lot more patterns.
|
52
sites/orgdocs/blog/announcing-freesewing-social/index.mdx
Normal file
52
sites/orgdocs/blog/announcing-freesewing-social/index.mdx
Normal file
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
title: 'Announcing FreeSewing.social'
|
||||
caption: 'Silhouette Photo of Elephant during Golden Hour by Renato Conti'
|
||||
date: '2023-11-03'
|
||||
intro: 'FreeSewing now has a home on the fediverse, and you can join too'
|
||||
authors: 1
|
||||
---
|
||||
|
||||
FreeSewing has carved out a spaced for itself on the Fediverse and that space
|
||||
is [FreeSewing.social](https://freesewing.social). It's a Mastodon instance
|
||||
that is open to all FreeSewing users, and the larger community. ## The
|
||||
FreeSewing Mastodon instance The official FreeSewing account
|
||||
([@freesewing@freesewing.social](https://freesewing.social/@freesewing)) will
|
||||
be used for formal announcements, so if you want the headlines, follow that
|
||||
one.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
I will be using my own account
|
||||
([@joost@freesewing.social](https://freesewing.social/@joost)) for more
|
||||
frequent updates, news, discussion and whatnot. So if you'd like to be more in
|
||||
the loop, that's a good one to follow.
|
||||
|
||||
And -- it bears repeating -- you are welcome to join this instance. If you were
|
||||
wondering about Mastodon/Fediverse but were not too sure about what to do or
|
||||
what server to join, this is your chance.
|
||||
|
||||
## Leaving Twitter I need more work like I need another hole in my head, so
|
||||
|
||||
setting up this instance was something I've been mulling over for a while, but
|
||||
in the end I decided to do it because Twitter -- where both FreeSewing and
|
||||
myself have an account -- has been transformed into something that I honestly
|
||||
don't want to have anything to do with.
|
||||
|
||||
This has been going on for a while, and leaving Twitter at this point is not
|
||||
exactly a strong statement. It's just that I've been busy, and certainly was
|
||||
too busy to deal with this. So I decided that the website migration was a good
|
||||
time to make the formal announcement.
|
||||
|
||||
So, I will remove both `@j__st` and `@freesewing_org` from Twitter at the end
|
||||
of this month.
|
||||
|
||||
## Joining Bluesky The Fediverse is not for everyone, and for those who like
|
||||
|
||||
the Twitter experience, Bluesky seems to be the alternative that is somewhat
|
||||
closest.
|
||||
|
||||
This is by no means an endorsement, but I have created
|
||||
[joost.at](https://bsky.app/profile/joost.at) and
|
||||
[FreeSewing.org](https://bsky.app/profile/freesewing.org) on Bluesky. I will do
|
||||
my best to also post there so that those people who prefer it can get their
|
||||
updates that way.
|
126
sites/orgdocs/blog/announcing-freesewing-v30/index.mdx
Normal file
126
sites/orgdocs/blog/announcing-freesewing-v30/index.mdx
Normal file
|
@ -0,0 +1,126 @@
|
|||
---
|
||||
title: 'Announcing FreeSewing v3.0'
|
||||
caption: 'This picture by Engin Akyurt seems like the sort of understated celebration that is suitable or this announcement'
|
||||
date: '2023-09-30'
|
||||
intro: 'FreeSewing 3.0 is finally here. The 3.0 release culminates more than a year of work, and comes just over four years after the v2.0 release. What I’m saying is: I don’t make announcements like this often, and it’s a big deal. You should get excited.'
|
||||
authors: 1
|
||||
---
|
||||
|
||||
FreeSewing 3.0 is finally here.
|
||||
|
||||
FreeSewing is the leading open source platform for made-to-measure sewing
|
||||
patterns, loved by home sewers and fashion entrepreneurs alike.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
The 3.0 release culminates more than a year of work, and comes just over four
|
||||
years after the v2.0 release. What I'm saying is: I don't make announcements
|
||||
like this often, and it's a _big deal_. You should get excited.
|
||||
|
||||
## Breaking changes
|
||||
|
||||
Let's start with the obvious: This is a major release so there are breaking changes.
|
||||
Listing all of them would be rather challenging, and probably not that useful.
|
||||
The first pre-release versions of FreeSewing 3 is almost a year old, and all of
|
||||
the people who contributed designs have either ported their designs, or I
|
||||
did it for them.
|
||||
|
||||
Still, I want to list three breaking changes that are super obviously going to
|
||||
break your stuff if you rely on FreeSewing code;
|
||||
|
||||
- **FreeSewing 3 is ESM only**: Migrating a large Javascript project to ESM
|
||||
modules is enough to make even the most seasoned developers break down and
|
||||
cry, but it's done.
|
||||
- **FreeSewing 3 uses named exports**: There are obviously some places where a
|
||||
default export is required (looking at you NextJS) but whereever we can, we
|
||||
now use named exports exclusively because we all know those are better.
|
||||
- **FreeSewing 3 requires Node 18 or newer**: I recommend lts/hydrogen
|
||||
|
||||
With that out of the way, let's talk about what's new.
|
||||
A lot of work went into this release, and I couldn't possibly cover all of it.
|
||||
But allow me to name-check some of the more fundamental changes.
|
||||
|
||||
## Designs are now JBOP
|
||||
|
||||
A big driver for the decision to freeze the v2 branch and start working on v3
|
||||
was to make it easier to mix-and-match parts from various designs.
|
||||
|
||||
Design inheritance was already possible in v2, but because the configuration
|
||||
was handled on the design level, it required careful re-configuration of
|
||||
(required) measurements, options, part dependencies, and so on. It was possible
|
||||
but came with a lot of friction.
|
||||
|
||||
In v3, all configuration is moved to the part level, and a design is now not
|
||||
much more than _just a bunch of parts_ (JBOP). It is the parts themselves that
|
||||
configure what they need. This includes anything from the measurements they
|
||||
require, the options they provide, the plugins they use, their dependencies,
|
||||
and so on.
|
||||
|
||||
This way, re-use parts from various designs, and all of their configuration,
|
||||
dependencies, plugins, and so on will follow.
|
||||
|
||||
## Less boilerplate
|
||||
|
||||
Creating a design has also become a lot simpler, you essentially pass your list
|
||||
of parts to our `Design` constructor and you're done:
|
||||
|
||||
```mjs
|
||||
import { Design } from '@freesewing/core'
|
||||
|
||||
export const MyDesign = new Design({
|
||||
parts: [
|
||||
/* ... your parts here ... */
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
Speaking of less boilerplate, in v2, the most common plugins were already
|
||||
bundled in the `@freesewing/plugin-bundle` package, but you still had to
|
||||
include them in your design. In v3, those plugins have moved to the
|
||||
`@freesewing/core-plugins` package, and will be loaded by FreeSewing's core
|
||||
library by default (although you can opt out of that).
|
||||
|
||||
## Plugins with more powers
|
||||
|
||||
In addition to providing macros, snippets, or tapping into FreeSewing's
|
||||
lifecycle hooks, plugins can now also add methods to the store.
|
||||
|
||||
This is allows further extending FreeSewing with whatever exciting thing you
|
||||
can thing of. As an example, the way logging is handled in the core library
|
||||
was re-implemented based on this. Which means that if you would like a
|
||||
different logging solution, you can simple provide your own log handler in a
|
||||
plugin.
|
||||
|
||||
## New development environment
|
||||
|
||||
With the version 3 release comes a new development environment that closely
|
||||
mimics what we will be providing at FreeSewing.org (more on that later).
|
||||
|
||||
The development environment ships with various templates that you can use to
|
||||
either start a design from scratch, or extend one of our blocks. You don't have
|
||||
to choose one over the other either, you can use all of these at the same time,
|
||||
and if you want even add more.
|
||||
|
||||
Our new development environment now allows (optionally) integrates with the
|
||||
FreeSewing backend. You can authenticate with your FreeSewing account so you
|
||||
can (re)use your measurements while working on your designs.
|
||||
|
||||
## Not everything is versioned
|
||||
|
||||
There's a lot more I could talk about, but I need to address the elephant in
|
||||
the room: So we have 3.0 now, when do non-developers get to use this?
|
||||
|
||||
Well... I'm going to need a bit more time. Everything is sort of ready, but
|
||||
some things always a bit more time because you can't really to them in advance.
|
||||
Things like translation, some more testing, not to mention migrating 50k users
|
||||
to a completely different infrastructure.
|
||||
|
||||
So as a regular user of FreeSewing.org who is not itching to spin up a
|
||||
development environment, you will need to hold on a little longer. But
|
||||
clearly, it's going to be soon now. I'd say a matter of weeks, rather than
|
||||
months.
|
||||
|
||||
In the meanwhile, if you find a problem or bug, create an issue because
|
||||
FreeSewing 3 is now production-ready and fully supported.
|
||||
|
||||
joost
|
86
sites/orgdocs/blog/announcing-freesewing/index.mdx
Normal file
86
sites/orgdocs/blog/announcing-freesewing/index.mdx
Normal file
|
@ -0,0 +1,86 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'The freesewing logo'
|
||||
date: '2017-03-24'
|
||||
intro: 'I am are proud to announce freesewing core v1.0.0 and the accompanying documentation that describes the freesewing project in detail.'
|
||||
title: 'Announcing freesewing, an open source platform for made-to-measure sewing patterns'
|
||||
---
|
||||
|
||||
I am are proud to announce [freesewing core
|
||||
v1.0.0](https://github.com/freesewing/core) and the accompanying
|
||||
[documentation](/docs) that describes the freesewing project in detail.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
But I'm also realistic, and understand that you don't have time to plow through
|
||||
pages upon pages of documentation.
|
||||
|
||||
So instead, here's a story to give you the essence of freesewing in a nutshell:
|
||||
|
||||
## The freesewing origin story Sewing is easy. It really is. What's hard is
|
||||
|
||||
getting things to fit properly. That's why you use a sewing pattern. It's a
|
||||
blueprint for whatever it is you are making. A good pattern gives you good
|
||||
fit. Most patterns don't.
|
||||
|
||||
That's because — much like clothes in the shop — patterns come in
|
||||
sizes. And sizes are a crude way to put people in boxes. They are made for an
|
||||
imaginary average person, rather than for you.
|
||||
|
||||
There's another way, and that is to draft a pattern based on your measurements.
|
||||
These made-to-measure patterns are vastly superior, but they require a lot of
|
||||
work.
|
||||
|
||||
I wanted to change that, and that effort evolved into
|
||||
[MakeMyPattern.com](https://makemypattern.com/). I ran that site for a
|
||||
number of years, and it was a remarkable success. Probably helped by the fact
|
||||
that I gave away all patterns for free.
|
||||
|
||||
In the world of home sewing, it tends to require a bit of explaining why one
|
||||
would choose to give away their work for free. Things are different in the
|
||||
open source world where the idea of sharing your work with others for the
|
||||
benefit of all is the very thread from which communities are woven.
|
||||
|
||||
While I can't magically bring the culture of open source to sewing patterns, I
|
||||
certainly can bring sewing patterns into the open source world.
|
||||
|
||||
[Freesewing.org](https://freesewing.org/) will continue to offer what
|
||||
[Makemypattern.com](https://makemypattern.com/) does today: free sewing
|
||||
patterns drafted to your measurements. But additionally, it will be open to
|
||||
your contributions.
|
||||
|
||||
Here's hoping that in the Venn diagram of the somewhat geeky and sewing, it's
|
||||
not just me in the middle.
|
||||
|
||||
joost
|
||||
|
||||
## Shout-outs Freesewing is a project by [Joost De
|
||||
|
||||
Cock](https://github.com/joostdecock) and contributors.
|
||||
|
||||
Hat-tip to [@jakesgordon](https://github.com/jakesgordon) and [Kevin
|
||||
Lindsey](http://www.kevlindev.com) for allowing me to port some of their code.
|
||||
|
||||
The early-stage enthusiasm and input of
|
||||
[@diggydev](https://github.com/diggydev), [@cabi](https://github.com/cabi),
|
||||
[@woutervdub](https://github.com/woutervdub),
|
||||
[@cloutiy](https://github.com/cloutiy),
|
||||
[@straytaoist](https://github.com/straytaoist),
|
||||
[@netpraxis](https://github.com/netpraxis),
|
||||
[@Stefan1960](https://github.com/Stefan1960),
|
||||
[@brendare1](https://github.com/brendare1),
|
||||
[@JorisJoppe](https://github.com/JorisJoppe),
|
||||
[@JamJenkins](https://github.com/JamJenkins), and
|
||||
[@fightingrabbit](https://github.com/fightingrabbit) has been a great boon to
|
||||
this project.
|
||||
|
||||
Thanks to [@annekecaramin](https://twitter.com/annekecaramin) for designing a
|
||||
logo cool enough to put on a Tshirt.
|
||||
|
||||
Special thanks to [@scorchtorch](https://twitter.com/scorchtorch) for being the
|
||||
best at that heart/salad/antlers thing.
|
||||
|
||||
Last but not least, this project would not exist without the users, supporters,
|
||||
and donors of [makemypattern.com](https://makemypattern.com/).
|
||||
|
||||
Thanks guys!
|
36
sites/orgdocs/blog/announcing-hortensia/index.mdx
Normal file
36
sites/orgdocs/blog/announcing-hortensia/index.mdx
Normal file
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'An example Hortensia made by the designer'
|
||||
date: '2021-02-13'
|
||||
intro: "I'm happy to announce the immeadiate availability of our latest FreeSewing pattern: the Hortensia handbag ."
|
||||
title: 'Say hi to our latest pattern: The Hortensia handbag'
|
||||
---
|
||||
|
||||
I'm happy to announce the immeadiate availability of our latest FreeSewing
|
||||
pattern: [the Hortensia handbag](/designs/hortensia/).
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
Hortensia's origin story traces back to
|
||||
[@stoffsuchti](https://twitter.com/stoffsuchti) who wanted to create a pattern
|
||||
for a handbag, and was looking for somebody who could implement that design in
|
||||
code.
|
||||
|
||||
It was [Wouter](https://github.com/woutervdub) who answered the call and
|
||||
implemented the pattern, making this another success story from the FreeSewing
|
||||
community.
|
||||
|
||||
## No measurements needed
|
||||
|
||||
This is the first pattern on FreeSewing that does not require any measurements
|
||||
to make. There's some options you can choose — to control the size of the
|
||||
handbag for one thing — but since this is a handbag, no measurements are
|
||||
needed.
|
||||
|
||||
This makes Hortensia a great project to make as a gift, since there's no need
|
||||
to worry about fit.
|
||||
|
||||
:::tip
|
||||
Now show us yours If you do make a Hortensia, do [send us
|
||||
pictures](https://discord.freesewing.org/).
|
||||
:::
|
47
sites/orgdocs/blog/announcing-penelope/index.mdx
Normal file
47
sites/orgdocs/blog/announcing-penelope/index.mdx
Normal file
|
@ -0,0 +1,47 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'The pattern illustration for Penelope'
|
||||
date: '2018-06-29'
|
||||
intro: "I'm very happy to announce the immeadiate availability of the Penelope Pencil Skirt , out in beta today."
|
||||
title: 'Announcing the Penelope Pencil Skirt; And our womenswear roadmap'
|
||||
---
|
||||
|
||||
I'm very happy to announce the immeadiate availability of
|
||||
[the Penelope Pencil Skirt](/designs/penelope), out in beta today.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
Penelope was designed by [@woutervdub](/users/user?id=132) who also signed for
|
||||
[benjamin](/designs/benjamin).
|
||||
|
||||
## Freesewing is not (just) for menswear
|
||||
|
||||
This new foray into womenswear foreshadows our plans for the second half of
|
||||
this year. That's right, we're going to be making more patterns for ladies.
|
||||
|
||||
Freesewing has a bit of a menswear reputation, since historically we've had a
|
||||
lot more patterns for men than for ladies. But that doesn't mean women are
|
||||
second-class citizens here. It's just a side-effect of how this project was
|
||||
historically run by a man. Can you blame a brother for designing patterns he'd
|
||||
like to wear himself?
|
||||
|
||||
Today, freesewing is a communal effort, and there's plenty of ladies involved.
|
||||
So it only make sense to make a conscious effort to do something for our
|
||||
sisters. And that's exactly what we'll be doing.
|
||||
|
||||
We've got another pattern in the pipeline that is not only for women, but also
|
||||
by a woman. By [@AlfaLyr](/users/user?id=1230) in particular, who has designed a
|
||||
circle skirt pattern that is going to land here real soon.
|
||||
|
||||
In parallel, I'll be working with [@AnnekeCaramin](/users/user?id=168) on a
|
||||
female equivalent for [Brian](/designs/brian), our basic body block on which
|
||||
many of our patterns are based. The idea is to make a quality bodice block for
|
||||
ladies that is made-to-measure and can handle the common fitting issues
|
||||
automatically. I'm talking about full bust adjustment, sway back, these kind of
|
||||
things.
|
||||
|
||||
Once we have that block, expect us to spin it into a bunch of dresses and tops.
|
||||
|
||||
And as always, if you have pattern design skills but are a bit intimidated by
|
||||
the platform, reach out to us to see if we can join forces to make your ideas a
|
||||
reality.
|
30
sites/orgdocs/blog/announcing-sandy/index.mdx
Normal file
30
sites/orgdocs/blog/announcing-sandy/index.mdx
Normal file
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: "Did you know that Sandy was named after Olivia Newton-John's character in the move Grease?"
|
||||
date: '2018-08-01'
|
||||
intro: "Ladies and gentlemen --- because who says men can't wear skirts --- I am happy to announce the immeadiate availability of our latest freesewing pattern: the Sandy circle skirt ."
|
||||
title: 'Announcing Sandy, a circle skirt designed by @AlfyLyr'
|
||||
---
|
||||
|
||||
Ladies and gentlemen --- because who says men can't wear skirts --- I am happy
|
||||
to announce the immeadiate availability of our latest freesewing pattern: [the
|
||||
Sandy circle skirt](/designs/sandy).
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
Sandy was designed by [@AlfaLyr](/users/user?id=1230) who really did a stellar job.
|
||||
This makes it also another pattern from the freesewing community, something
|
||||
that I'm very excited about.
|
||||
|
||||
## All the options
|
||||
|
||||
As many patterns here at freesewing, Sandy comes with a bunch of options to
|
||||
allow you to customize your skirt to your wishes.
|
||||
|
||||
There's options for how much of circle you want (half? full? Something else?),
|
||||
how long you want it, the shape and overlap of the waistband, whether you want
|
||||
pleats, how much hem, and so on.
|
||||
|
||||
I can see this becoming rather the success story. So go and treat yourself to
|
||||
a new skirt, and let [@AlfyLyr](/users/user?id=1230) know how it
|
||||
works out for you.
|
39
sites/orgdocs/blog/announcing-shin/index.mdx
Normal file
39
sites/orgdocs/blog/announcing-shin/index.mdx
Normal file
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'I guess this is what augmented reality looks like?'
|
||||
date: '2018-09-29'
|
||||
intro: 'A while ago I found myself in need of some new swim trunks. So I drafted a pattern and made some:'
|
||||
title: 'Announcing Shin, a swim trunks pattern'
|
||||
---
|
||||
|
||||
A while ago I found myself in need of some new swim trunks. So I drafted a
|
||||
pattern and made some:
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||

|
||||
|
||||
I asked if people would be interested in a pattern like this, and turns out
|
||||
that yes, they were.
|
||||
|
||||
So, after some more tweaking, I think this is ready for you guys, and meanwhile
|
||||
Roy has already provided an illustration for it too.
|
||||
|
||||

|
||||
|
||||
## Options and documentation available
|
||||
|
||||
Shin comes with options, and they are very close to the options available for
|
||||
[Bruce](/designs/bruce).
|
||||
|
||||
All [options are documented](/docs/designs/shin/options), as are the [required
|
||||
measurements](/docs/designs/shin#measurements), and I've also written
|
||||
[instructions for how to make this](/docs/designs/shin/instructions).
|
||||
|
||||
I still have to do the illustrations, but it's really not hard so you'll
|
||||
probably figure it out without them. Essentially, you can go and make this
|
||||
right now.
|
||||
|
||||
Enjoy!
|
25
sites/orgdocs/blog/announcing-sven/index.mdx
Normal file
25
sites/orgdocs/blog/announcing-sven/index.mdx
Normal file
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'A Sven made for the office. As in, kinda boring'
|
||||
date: '2017-07-09'
|
||||
intro: 'Winter caused me to design this pattern. I was cold, and needed some sweaters, so what does one do?'
|
||||
title: 'Announcing the Sven Sweater; A basic sweater based on the Brian body block'
|
||||
---
|
||||
|
||||
Winter caused me to design this pattern. I was cold, and needed some sweaters,
|
||||
so what does one do?
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
Sven stayed under the radar until now because I designed it on the (then
|
||||
unreleased) freesewing platform, and until now I didn't have a place to show it
|
||||
to people.
|
||||
|
||||
That's how we got here. Now about that sweater: It's a simple design based on
|
||||
the Brian body block. I've made three different version myself, changing the
|
||||
neckline and fabrics, and it really does what it needs to do very well (as in,
|
||||
keep me warm).
|
||||
|
||||
## Pictures or it didn't happen
|
||||
|
||||
Check out the [Sven showcases](/showcase/tags/sven) for some samples.
|
62
sites/orgdocs/blog/announcing-teagan/index.mdx
Normal file
62
sites/orgdocs/blog/announcing-teagan/index.mdx
Normal file
|
@ -0,0 +1,62 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'Photo by Alex Andrews from Pexels'
|
||||
date: '2020-09-09'
|
||||
intro: "A while ago somebody asked whether we had a T-shirt pattern on freesewing.org and it turns out, we didn't."
|
||||
title: 'FreeSewing 2.9 brings our Teagan T-shirt pattern'
|
||||
---
|
||||
|
||||
A while ago somebody asked whether we had a T-shirt pattern on freesewing.org
|
||||
and it turns out, we didn't.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
There's no good reason for that, we just never got around to that. So today
|
||||
we're rolling out version 2.9 of FreeSewing with our latest pattern: [the
|
||||
Teagan T-shirt](/designs/teagan/).
|
||||
|
||||

|
||||
|
||||
## Who is this for?
|
||||
|
||||
Teagan is fitted T-shirt pattern with options for altering the neckline,
|
||||
length, and sleeves.
|
||||
|
||||
Teagan is based on [our Brian block](/designs/brian/), which does not take
|
||||
breasts into account. That being said, this will work for people with breasts
|
||||
too. Since it uses the chest circumference it will simply draft a T-shirt to
|
||||
fit your full chest.
|
||||
|
||||
We've also added an option to draft this to your high bust, which would give
|
||||
you a more fitted T-shirt with ease & stretch having to accomodate for your
|
||||
breasts.
|
||||
|
||||

|
||||
|
||||
## Community Updates
|
||||
|
||||
If you're thinking about sewing Teagan, but you're new to sewing or working
|
||||
with knits, never fear! FreeSewing has more support than ever. Chat with us on
|
||||
[Discord](https://discord.freesewing.org/), in a [Facebook
|
||||
Group](https://www.facebook.com/groups/627769821272714), or on
|
||||
[Reddit](https://www.reddit.com/r/freesewing/). Find us on social as
|
||||
@freesewing_org on [Instagram](https://www.instagram.com/freesewing_org/) and
|
||||
[Twitter](https://twitter.com/freesewing_org). If you're looking for tutorials,
|
||||
there's a new [YouTube
|
||||
channel](https://www.youtube.com/channel/UCLAyxEL72gHvuKBpa-GmCvQ) for that. It
|
||||
has a whole series on [sewing up
|
||||
Teagan](https://www.youtube.com/playlist?list=PLY9EmRuXR20Y7FonIHD6mX9yIpFh_emX1),
|
||||
as well as this amazing preview.
|
||||
|
||||
<YouTube id="3UGJSNxNe8I" />
|
||||
|
||||
If all of this sounds awesome, and you want to get more involved with
|
||||
FreeSewing, you can check out our repositories and source code on
|
||||
[Github](https://github.com/freesewing/) or connect with other contributors via
|
||||
[Discord](https://discord.freesewing.org/). You can find announcements about
|
||||
upcoming contributor calls on Discord, in the announcements channel.
|
||||
|
||||
And if you sew up a Teagan T-shirt, let us know what you think!
|
23
sites/orgdocs/blog/announcing-ursula/index.mdx
Normal file
23
sites/orgdocs/blog/announcing-ursula/index.mdx
Normal file
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'Photo by Karolina Grabowska from Pexels'
|
||||
date: '2021-06-27'
|
||||
intro: 'Announcing Ursula, a basic, highly-customizable underwear pattern'
|
||||
title: 'Announcing Ursula, a basic, highly-customizable underwear pattern'
|
||||
---
|
||||
|
||||
FreeSewing 2.17 is out, and it while it comes with many fixes and improvements,
|
||||
the biggest news is certainly a brand new pattern: [The Ursula
|
||||
Undies](/designs/uma/) by US-based designer Natalia Sayang.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||

|
||||
|
||||
The picture above is from [this showcase post](/showcase/ursula-test-pairs/)
|
||||
which includes several more examples of the different styles you can accomplish
|
||||
with this versatile pattern.
|
||||
|
||||
Ursula is a quick make, not to mention the ultimate stash-buster. We are
|
||||
really excited about it.
|
86
sites/orgdocs/blog/announcing-v2/index.mdx
Normal file
86
sites/orgdocs/blog/announcing-v2/index.mdx
Normal file
|
@ -0,0 +1,86 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'This release really is a sea-change'
|
||||
date: '2019-08-25'
|
||||
intro: 'Welcome to version 2 of FreeSewing, the open source platform for made-to-measure sewing patterns.'
|
||||
title: 'Announcing FreeSewing v2.0'
|
||||
---
|
||||
|
||||
Welcome to version 2 of FreeSewing, the open source platform for
|
||||
made-to-measure sewing patterns.
|
||||
|
||||
This release culminates more than a year of work, and comes two years to the
|
||||
day since FreeSewing first went live. Today, we once again raise the bar for
|
||||
what you can expect from modern-day sewing patterns.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
## 🦄 Harder, better, faster, stronger
|
||||
|
||||
[\*](https://www.youtube.com/watch?v=GDpmVUEjagg)
|
||||
|
||||
We are _extremely_ excited about this release, which is not just merely a new
|
||||
major version with some breaking changes, but a complete rewrite in
|
||||
JavaScript/Node.js. We won't go into the nitty gritty here, but if you'd like
|
||||
to know how we've done it, check out [the developer
|
||||
docs](https://freesewing.dev) or [FreeSewing on
|
||||
GitHub](https://github.com/freesewing).
|
||||
|
||||
## ✨ Live preview
|
||||
|
||||
FreeSewing has always had a reputation for publishing sewing patterns with tons
|
||||
of options for you to tweak. Which is great, but can be a bit overwhelming
|
||||
because you only got to see the result of all those tweaks at the very end.
|
||||
But those days are gone. Now, no matter what changes you make, you get a live
|
||||
preview of what your pattern will look like, taking the guesswork out of
|
||||
configuring your pattern exactly as you like it.
|
||||
|
||||
## 🧂 Recipes
|
||||
|
||||
Where we used to store your patterns for you, now we'll store your _recipes_
|
||||
instead. You can go through as many pattern iterations as you want. And when
|
||||
you're happy, we'll save all the settings it takes to create that exact pattern
|
||||
in a so-called recipe.
|
||||
|
||||
You can then at any time re-use that recipe to recreate your pattern, or use it
|
||||
as a starting point to make a slightly different pattern. You can also share
|
||||
these recipes, allowing others to generate the same look for their own
|
||||
measurements.
|
||||
|
||||
## 🤝 Getting involved was never easier
|
||||
|
||||
What hasn't changed is that we still support 5 languages (shout-out to all
|
||||
translators) and that FreeSewing is still a 100% communal effort (shout-out to
|
||||
all contributors). There's only volunteers here, and if you'd like to help out,
|
||||
it's never been easier.
|
||||
|
||||
For those who are interested in our code, head over to our new developer
|
||||
documentation at [freesewing.dev](https://freesewing.dev) to learn about the
|
||||
new platform, our core API, our plugins, and more.
|
||||
|
||||
For those of you who are interested in designing patterns, we have updated our
|
||||
[pattern design tutorial](https://freesewing.dev/tutorial) so you can hit the
|
||||
ground running.
|
||||
|
||||
There's good news for translators too, as we now use
|
||||
[Crowdin](https://crowdin.com/) which makes translation a breeze. If you'd like
|
||||
to help out with translation, or maybe even add a new language to FreeSewing,
|
||||
make sure to [get in touch](https://discord.freesewing.org/).
|
||||
|
||||
## 💩 Usual caveats apply
|
||||
|
||||
It's conventional wisdom in software development that refactoring code is good,
|
||||
but rewriting it from scratch is bad. Still, we did it anyway because we wanted
|
||||
to make it easier for people to get involved in the project, and generate
|
||||
patterns in real-time in the browser.
|
||||
|
||||
That being said, this is a .zero release so you may stumble upon an issue left
|
||||
or right. When you do, please [let us know](https://discord.freesewing.org/) or
|
||||
submit an issue.
|
||||
|
||||
## 🤞 Tell us what you think
|
||||
|
||||
We'd love to hear your feedback. We're **@freesewing_org** on
|
||||
[Twitter](https://twitter.com/freesewing_org) and
|
||||
[Instagram](https://instagram.com/freesewing_org), use the **#freesewing**
|
||||
hashtag, or [check our share page](/share).
|
41
sites/orgdocs/blog/bella-bodice-block/index.mdx
Normal file
41
sites/orgdocs/blog/bella-bodice-block/index.mdx
Normal file
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'Remember when we were allowed to go outside?'
|
||||
date: '2021-01-17'
|
||||
intro: 'The Bella bodice block for womenswear'
|
||||
title: 'The Bella bodice block for womenswear'
|
||||
---
|
||||
|
||||
We've just published a new pattern on this website: [Bella, a bodice block for
|
||||
womenswear](/designs/bella/). It's a block with bust and waist dart, and a
|
||||
waist dart at the back.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
My goal when venturing into womenswear was to make one foundational block from
|
||||
which we could then spin out a range of different garments.
|
||||
|
||||
Which is why we have [Breanna](/designs/breanna/), which I designed from
|
||||
scratch. Unfortunately, it hasn't been the end-all be-all that I — perhaps
|
||||
naively — hoped it would be.
|
||||
|
||||
For Bella, I worked with someone from the industry to implement a design that
|
||||
is commonly used for commercial garment making. As such, I am curious to see
|
||||
how this one will pan out.
|
||||
|
||||
My initial plan was to also make a variation with a shoulder dart at the front,
|
||||
to replace the bust dart, but in the end I settled for getting it released,
|
||||
rather than work on it longer.
|
||||
|
||||
Which brings me to:
|
||||
|
||||
##### I'm taking a break from womenswear
|
||||
|
||||
I feel like I'm expending a lot of effort here for little result. It's getting
|
||||
me down, and I need a win.
|
||||
|
||||
I want to work on something that I can not only design, but also make and wear.
|
||||
Something that gives me joy, and makes me feel like I know what I'm doing.
|
||||
|
||||
So while I'll still help out people who want to design for women themselves, I
|
||||
am taking a break from womenswear.
|
55
sites/orgdocs/blog/benjamin-bow-tie-beta/index.mdx
Normal file
55
sites/orgdocs/blog/benjamin-bow-tie-beta/index.mdx
Normal file
|
@ -0,0 +1,55 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'If you like it, put a bow on it'
|
||||
date: '2017-11-14'
|
||||
intro: 'Our family of freesewing patterns has grown once again, and the benjamin of the family is... Benjamin .'
|
||||
title: "The Benjamin Bow Tie pattern is now available in beta. And I didn't even have to do anything."
|
||||
---
|
||||
|
||||
Our family of freesewing patterns has grown once again, and the benjamin of the
|
||||
family is... [Benjamin](/designs/benjamin).
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
Benjamin is a bow tie that comes with a variety of options to control pretty
|
||||
much every aspect of your bow tie.
|
||||
|
||||
You can opt for a made-to-measure bow tie, or draft Benjamin with an adjustment
|
||||
ribbon to allow some flexibility in the fit. Something that makes this a great
|
||||
handmade gift for the upcoming holiday season.
|
||||
|
||||
## Benjamin is more special than you realize
|
||||
|
||||
Here's the thing about Benjamin that I'm most excited about: I didn't do
|
||||
anything.
|
||||
|
||||

|
||||
|
||||
That's right, Benjamin was designed and coded by [Wouter Van
|
||||
Wageningen](/users/user?id=132) who has over the last couple of months been teaching
|
||||
himself the ins and outs of the freesewing platform:
|
||||
|
||||
> I had a blast making the Bow Tie pattern. I basically used it to move from
|
||||
> the BabyBib tutorial into something that was original and not too complex
|
||||
> (and actually useful). I wanted to get the whole process under control
|
||||
> before venturing out into the real stuff.
|
||||
>
|
||||
> That I was able to pick things up so easily is due mostly to the great
|
||||
> [BabyBib tutorial](https://freesewing.org/tutorials/pattern-design/) and the
|
||||
> help you've provided [here](https://discord.freesewing.org).
|
||||
|
||||
## Who will be next to contribute a pattern?
|
||||
|
||||
When I released freesewing as an open source platform, I obviously hoped that
|
||||
others would join the effort.
|
||||
|
||||
But I never thought that less than 3 months after the public release of
|
||||
freesewing, we'd have our first pattern from the freesewing community.
|
||||
|
||||

|
||||
|
||||
So yeah, Benjamin is a BFD, Wouter is a badass, and I am hopeful that this will
|
||||
be the first of many patterns that we as a community will be able to make
|
||||
available to all.
|
156
sites/orgdocs/blog/breanna-measurements-sizes-in-2-2/index.mdx
Normal file
156
sites/orgdocs/blog/breanna-measurements-sizes-in-2-2/index.mdx
Normal file
|
@ -0,0 +1,156 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: "This post describes what's new in version 2.2 of FreeSewing"
|
||||
date: '2020-02-22'
|
||||
intro: "A look at what's new in FreeSewing 2.2, including Breanna, our bodice block for womenswear"
|
||||
title: "A look at what's new in FreeSewing 2.2, including Breanna, our bodice block for womenswear"
|
||||
---
|
||||
|
||||
Version 2.2 of FreeSewing is here, and it has a bunch of changes and
|
||||
improvements big and small. The
|
||||
[changelog](https://github.com/freesewing/freesewing/blob/develop/CHANGELOG.md)
|
||||
lists all the changes, but here's what you need to know:
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
- [New pattern: Breanna is a bodice block for
|
||||
womenswear](#new-pattern-breanna-is-a-bodice-block-for-womenswear)
|
||||
- [New/Different measurements to better suit
|
||||
womenswear](#newdifferent-measurements-to-better-suit-womenswear)
|
||||
- [Generate patterns in _standard_ sizes (no account
|
||||
required)](#generate-patterns-in-standard-sizes-no-account-required)
|
||||
|
||||
Let's have a look at what it all means:
|
||||
|
||||
## New pattern: Breanna is a bodice block for womenswear
|
||||
|
||||
Meet [Breanna](/designs/breanna/), our bodice block for womenswear.
|
||||
|
||||
A block (or sloper) may not the most exciting pattern to look at, but it plays
|
||||
an important role as it is the basic form which other patterns are built on.
|
||||
|
||||
For example, we have a similar block for menswear called
|
||||
[Brian](/designs/brian/) and our [Aaron](/designs/aaron/),
|
||||
[Bent](/designs/bent/), [Carlita](/designs/carlita/),
|
||||
[Carlton](/designs/carlton/), [Huey](/designs/huey/), [Hugo](/designs/hugo/),
|
||||
[Jaeger](/designs/jaeger/), [Simon](/designs/simon/),
|
||||
[Simone](/designs/simone/), [Sven](/designs/sven/), and
|
||||
[Wahid](/designs/wahid/) patterns can all can trace their lineage back to Brain
|
||||
somehow.
|
||||
|
||||
In other words, Breanna is an important building block for us to extend our
|
||||
womenswear collection. But that does not mean it is not good news for you too.
|
||||
If you have been sewing for a while, chances are drafting your own block/sloper
|
||||
has perpetually been on your to-do list. Well, good news, because here is your
|
||||
block ready to go.
|
||||
|
||||
Oh, and of course it has all the bells and whistles you can expect from us.
|
||||
Have a look at [the pattern options](/docs/designs/breanna/options/) and I
|
||||
think you'll be positively impressed. If nothing else, this block can
|
||||
accommodate 1 or 2 bust darts in 15 different places, giving you 120 unique
|
||||
ways to place your bust dart(s).
|
||||
|
||||
Breanna has has been a while in the making, and we'd love to get your feedback
|
||||
on it. Making a muslin from a block like this really isn't much work. So if
|
||||
you've got some time to spare to whip this one up and let us know how it went,
|
||||
that would be great.
|
||||
|
||||
## New/Different measurements to better suit womenswear
|
||||
|
||||
Now that we're making our jouney into womenswear, we realized that the
|
||||
measurements we use on the site are somewhat skewed towards menswear. In
|
||||
addition, we had a lot of people stuggling with the shoulder slope measurement.
|
||||
So we decided to re-visit our measuremets, and we've made the following
|
||||
changes:
|
||||
|
||||
### We have a bunch of new _HPS_ measurements
|
||||
|
||||
We've settled on the High-Point Shoulder, the so-called HPS point, as the basis
|
||||
for many of the vertical torso measurements. If you're not certain what/where
|
||||
the HPS point is, [check the HPS documentation](/docs/sewing/hps/).
|
||||
|
||||
### We discontinued the Center Back To Neck measurement
|
||||
|
||||
As we mentioned earlier, we use measurements from the HPS point now for
|
||||
vertical torso measurements. As a result, we've discontinued the old _Center
|
||||
back neck to waist_ measurement.
|
||||
|
||||
Given that this measurement is now gone, you may need to add another
|
||||
measurement for certain patterns.
|
||||
|
||||
### We changed the way the shoulder slope is measured
|
||||
|
||||
We noticed that people struggles with the way we asked them to measure [the
|
||||
shoulder slope measurement](/docs/measurements/shoulderslope) so we have
|
||||
changed how to do that.
|
||||
|
||||
Because the new method yields a very different number (that ultimately captures
|
||||
the same thing, how much your shoulder slopes downward) here too we had to go
|
||||
in and reset all the existing data. In other words, you'll have to re-measure
|
||||
your shoulder slope.
|
||||
|
||||
## Generate patterns in _standard_ sizes (no account required
|
||||
|
||||
To get great patterns, you need good measurements, and a bunch of them. It's
|
||||
what we do here at FreeSewing, and most of the problems with patterns are
|
||||
because something goes wrong with taking measurements.
|
||||
|
||||
Unfortunately, there is no magic shortcut for this. If you want something
|
||||
made-to-measure, it's always going to start with acurate measurements.
|
||||
|
||||
This does raise the bar for people who are new to the site, and want to kick
|
||||
the tires.
|
||||
|
||||
> _Oooh, free patterns, nice_ 😍 _Wait, I have to create an account first?_ 🤔
|
||||
> _And take all these measurements?_ 😬 _That seems like a lot of work._
|
||||
|
||||
Fair enough.
|
||||
|
||||
In addition, our regular visitors also asked us whether they could get to see a
|
||||
pattern and play around with it without first having to put in a bunch of
|
||||
measurements.
|
||||
|
||||
So **_drumroll_** that is no longer required. We now offer all our patterns in
|
||||
_standard sizes_. Not only do you not have to take measurements to try out the
|
||||
patterns, you don't even have to sign up or log in. No account needed, just
|
||||
pick a pattern, a size, and you're good to go.
|
||||
|
||||
Obvously, made-to-measure patterns is _our thing_, and we're not changing that.
|
||||
But we're hoping that by lowering the bar to try out our platform, more people
|
||||
will give FreeSewing a try.
|
||||
|
||||
### What are standard sizes anyway?
|
||||
|
||||
The hardest thing about adding support for standard sizes? Figuring out what
|
||||
the heck standard sizes are supposed to be. We took a stab at it, and if you're
|
||||
curious you can check out our sizing table here (link no longer exists).
|
||||
|
||||
For menswear, our size range is 32 to 50, and they are based on a size 38
|
||||
baseline that we then graded up and down. For womenswear, our size range is 28
|
||||
to 48, and they are based on a size 34 baseline that we then graded up and
|
||||
down.
|
||||
|
||||
:::tip
|
||||
If you're not sure what these numbers are, they are the neck circumference in
|
||||
cm.
|
||||
:::
|
||||
|
||||
While we tried to make our size ranges inclusive, and these tables are an
|
||||
honest attempt to come up with something that makes sense, please understand
|
||||
that this is not our core business. We've love to hear your feedback on the
|
||||
sizing tables, and are open to tweaks and suggestions, but at the end of the
|
||||
day, what we want is to give you a pattern drafted to your measurements. These
|
||||
sizes are just a way to lure you in 🤫
|
||||
|
||||
## Also: All the other stuff
|
||||
|
||||
Now go and click around, for we've changed a bunch of other stuff too.
|
||||
|
||||
If you bump into any problems or have questions, as always [our chat room is
|
||||
the place to get in touch](https://discord.freesewing.org/).
|
||||
|
||||
And if you happen to like what we do here, perhaps now is a good time to tell
|
||||
your friends about FreeSewing. After all, they can now check it out without
|
||||
needing to sign up.
|
||||
|
||||
PS: We have [a handy share page](/share/) you can use for this.
|
100
sites/orgdocs/blog/bye-2020/index.mdx
Normal file
100
sites/orgdocs/blog/bye-2020/index.mdx
Normal file
|
@ -0,0 +1,100 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: "A photo by <a href='https://unsplash.com/@onevagabond'>Paulo Silva</a> shows an empty Times Square in New York during the COVID pandemic"
|
||||
date: '2021-01-10'
|
||||
intro: "Aren't we all glad 2020 is over?"
|
||||
title: 'The year 2020 was something alright'
|
||||
---
|
||||
|
||||
Aren't we all glad 2020 is over?
|
||||
|
||||
Realistically, at least some of you, or your loved ones, got caught in the
|
||||
absolute gut-punch that is the COVID-19 pandemic. Either indirectly through
|
||||
lost income or other practical concerns, or directly by battling the virus
|
||||
itself.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
I can only offer my sympathy, and the belief that things will get better. So
|
||||
hang in there, and let me briefly take your mind of things by sharing some good
|
||||
news against the bleak backdrop of the annus horribilis that 2020 turned out to
|
||||
be.
|
||||
|
||||
##### The face mask tsunami
|
||||
|
||||
FreeSewing found itself — absolutely unexpected I might add — under the glaring
|
||||
spotlight of international media this year. A tidal wave of attention rolled
|
||||
over us, and while the peak lasted only a good month, the repercussions and
|
||||
long tail of these events have shaped our entire year.
|
||||
|
||||
It all started in February when COVID-19 was starting to rear its ugly head in
|
||||
Europe and the supplies of personal protective equipment (PPE) started
|
||||
dwindling. It seemed that face masks were going to be a big factor in trying to
|
||||
slow down the spread of this disease, but they were getting harder to come by
|
||||
every day.
|
||||
|
||||
So on February 28th, after some design and experimentation, we [published our
|
||||
face mask pattern on freesewing.org](/blog/florence-face-mask/). Three weeks
|
||||
later, we followed up with [a one-page PDF that people could share and
|
||||
adapt](/blog/facemask-frenzy/).
|
||||
|
||||
We did not really want to be in the center of this, we just wanted to help
|
||||
people make masks. But when [Forbes ran an editorial calling on people to help
|
||||
out with the healthcare workers PPE
|
||||
shortage](https://www.forbes.com/sites/tjmccue/2020/03/20/calling-all-people-who-sew-and-make-you-can-help-solve-2020-n95-type-mask-shortage/),
|
||||
we suddenly found ourselves in the middle of a gigantic spotlight. The article
|
||||
prominently featured FreeSewing, and linked to [our blog
|
||||
post](/blog/facemask-frenzy).
|
||||
|
||||
At that time, there were few patterns available for face masks, and soon enough
|
||||
a long list of other publications started running links to our pattern and
|
||||
website. When I found [the instruction video that I made for the pattern
|
||||
staring back at me on the website of the New York
|
||||
Times](https://www.nytimes.com/2020/03/31/opinion/coronavirus-n95-mask.html),
|
||||
it was a veritable oh-crap moment. Sure enough, in the month following the
|
||||
Forbes publication, a million people descended on freesewing.org.
|
||||
|
||||
The sudden jump in visitors and users (not to mention patrons) made it clear
|
||||
that I am a bottleneck of the project, and so in the latter half of the year
|
||||
we've set out to [try and remedy that with some community
|
||||
building](/blog/a-call-for-help/). On one hand it's slow going, but on the
|
||||
other hand if I look at how vibrant the FreeSewing community is today, it
|
||||
almost beggars belief that we did all of this throughout 2020. We now have
|
||||
regular [contributor
|
||||
calls](https://github.com/freesewing/freesewing/discussions), and [our chat
|
||||
rooms are never empty](https://discord.freesewing.org/).
|
||||
|
||||
I hope to continue to fade into the background and let other people carry some
|
||||
of the torches. Not because I don't want to work on this anymore, but because I
|
||||
want to grow FreeSewing beyond what I can do on my own.
|
||||
|
||||
##### Black Lives Matter Since this is a look at 2020, I also want to pause and
|
||||
|
||||
acknowledge the **Black Lives Matter** movement and the ongoing problem of
|
||||
systemic racism. It is an area where my background and genetic material makes
|
||||
me ill-equipped to take a leading role, so here too I rely on our community for
|
||||
guidance.
|
||||
|
||||
We are also expanding our efforts to provide patterns that work for all body
|
||||
types, and I am particularly proud of how many of our users come to us because
|
||||
our patterns help them project the gender of their choice.
|
||||
|
||||
##### We helped more people than ever this year On the practical side of
|
||||
|
||||
things, I have extended our book year with a couple of weeks so that going
|
||||
forward, we will just follow the calendar years. With a couple of hours left in
|
||||
this year, FreeSewing's revenue for 2020 clocks in at **10.736,82 euro**. That
|
||||
makes 2020 and absolute bumper year, and it's more than all previous years
|
||||
combined (2015: € 256.65, 2016: € 473.50, 2017: € 673.14, 2018: € 3162.14,
|
||||
2019: € 4109.38).
|
||||
|
||||
As always, all of FreeSewing's revenue -- the entire 10.736,82 euro -- [goes to
|
||||
Doctors Without Borders](/docs/about/pledge/).
|
||||
|
||||
I am truly grateful for your continued support and contributions. I feel like
|
||||
in a very small way, we are able to apply some balm to the hurt that seems at
|
||||
times omnipresent in the world.
|
||||
|
||||
Thank you so much, and stay safe
|
||||
|
||||
love joost
|
191
sites/orgdocs/blog/calling-all-patrons/index.mdx
Normal file
191
sites/orgdocs/blog/calling-all-patrons/index.mdx
Normal file
|
@ -0,0 +1,191 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'We are building a bedrock of loyal supporters to ensure a sustainable future for freesewing.org, our code, our patterns, and our community.'
|
||||
date: '2017-12-10'
|
||||
intro: 'Calling all Patrons; Join our bedrock of loyal supporters.'
|
||||
title: 'Calling all Patrons; Join our bedrock of loyal supporters.'
|
||||
---
|
||||
|
||||
Every year, on this day, I write about what happened in the previous 12 months,
|
||||
and look ahead at what you can expect in the year ahead.
|
||||
|
||||
This year is no different, but boy do I have a lot to talk about.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
## 2017: the year freesewing was born
|
||||
|
||||
While freesewing was conceived in 2016 -- that's when I started working on it
|
||||
-- 2017 was the year it saw the light of day.
|
||||
|
||||
Freesewing core v1.0.0 [was released in March this
|
||||
year](/blog/announcing-freesewing/). For most people, that event passed under
|
||||
the radar. An open source platform for made-to-measure sewing patterns? What
|
||||
does this thing actually do?
|
||||
|
||||
A lot, as it turns out. Something that's become more obvious since [the release
|
||||
of freesewing.org](/blog/open-for-business/) at the end of August.
|
||||
|
||||

|
||||
|
||||
On Christmas day, it will (only) have been four months since this release. Yet
|
||||
in that time, we've signed up **2735 users** for whom we host **1522 drafts**,
|
||||
and **2359 models**.
|
||||
|
||||
We launched with 11 patterns, and have since added 4, bringing the current
|
||||
total to 15. Half of those new patterns are a community effort, which is
|
||||
particularly promising.
|
||||
|
||||
Yes, it's still early days. But I think it's safe to say that the decision to
|
||||
reinvent makemypattern.com as an open source project was the right call.
|
||||
|
||||
Speaking of which.
|
||||
|
||||
## MakeMyPattern.com is no more Shortly before publishing this blog post, I've
|
||||
|
||||
pulled the plug on [makemypattern.com](https://makemypattern.com/).
|
||||
|
||||
You can try to visit that link, but you'll only end up back here.
|
||||
|
||||
MakeMyPattern.com saw the light of day in 2012. It went through a number of
|
||||
iterations since, and today is finally superseded by freesewing.org.
|
||||
|
||||

|
||||
|
||||
We had a good run, and I feel that for any project, it's a good way to go when
|
||||
you get cannibalized by something better that you inspired.
|
||||
|
||||
## Let's talk money Like every year on this day, I've transferred all donations
|
||||
|
||||
into the account of [Médecins Sans Frontières/Doctors Without
|
||||
Borders](http://www.msf.org/).
|
||||
|
||||
This year we came in at **673.14€**, so that's what I've transferred.
|
||||
|
||||
> Why should we give you money in the first place if you're just going to give
|
||||
> it away?
|
||||
|
||||
I've also come to understand that people have a bunch of questions about this.
|
||||
Like _Why are you doing this?_ and _Why should we give you money in the first
|
||||
place if you're just going to give it away?_
|
||||
|
||||
These questions have led to some soul-searching recently. What I've learned is
|
||||
that it's not easy to talk about money. Nor is it easy to put in words things
|
||||
that you know to be right, almost instinctively.
|
||||
|
||||
But I wanted to be completely transparent about what's going on, so I made the
|
||||
effort to write about these things on [our pledge page](/docs/about/pledge).
|
||||
And I'm copying them here verbatim:
|
||||
|
||||
> ##### Noblesse oblige
|
||||
>
|
||||
> You probably assume that we ask for money to keep the servers running. But
|
||||
> that’s not exactly true.
|
||||
>
|
||||
> I don’t know if you’re familiar with the phrase _noblesse oblige_ but it
|
||||
> essentially means that privilege entails responsibility.
|
||||
>
|
||||
> I am privileged, and thus I have responsibilities. I am very fortunate to
|
||||
> have been born in Western Europe, have a good job, and a roof over my head.
|
||||
>
|
||||
> Could I use the money? Yes I could. Do I need the money? No I don’t.
|
||||
>
|
||||
> ##### The value of your support
|
||||
>
|
||||
> The main risk to Freesewing is the same as any open source project out there:
|
||||
> maintainer burnout.
|
||||
>
|
||||
> While I no longer carry Freesewing alone — and I can’t stress enough how much
|
||||
> I value the work of all contributors — that doesn’t make me immune to
|
||||
> feelings of _Why the fuck am I doing this?_
|
||||
>
|
||||
> When people become Patrons (or donate), they give more than money. To me, the
|
||||
> main value is the message they send to me and other people working on this.
|
||||
> And that message is: _Hey, you’re doing a worthwhile thing. Keep up the good
|
||||
> work_.
|
||||
>
|
||||
> ##### The value of your money
|
||||
>
|
||||
> It is not just about the money. But that doesn’t mean the money is not
|
||||
> important. Much to the contrary.
|
||||
>
|
||||
> Raising money by doing something I love and then passing it on to charity
|
||||
> allows me to sleep at night.
|
||||
>
|
||||
> I could volunteer at a soup kitchen, or teach underprivileged children how to
|
||||
> sew. But instead I’m working on Freesewing.
|
||||
>
|
||||
> Which is why all the money raised through freesewing goes to charity. It
|
||||
> makes this project not only fun to do, but also socially responsible. And I
|
||||
> need that to convince myself that yes, it’s OK to spend all my time doing
|
||||
> this, because at the end of the year, I get to write a check to people who
|
||||
> need it so much more.
|
||||
>
|
||||
> ##### Charity is not sexy
|
||||
>
|
||||
> Here’s the tricky part: People donate less once they know the money goes to
|
||||
> charity in the end. I wish it wasn’t the case, but it is.
|
||||
>
|
||||
> So I’m not explicitly mentioning it on our Patrons page, which is presented
|
||||
> like you would see on a business site.
|
||||
>
|
||||
> Yes, everything is free, and the money doesn’t actually go to paying the
|
||||
> server bills (because I choose to pay them out of my pocket for reasons
|
||||
> outlined above). But that doesn’t mean that these contributions are not
|
||||
> crucial to the well-being of the project, or at the very least its maintainer
|
||||
> (that would be me).
|
||||
|
||||
Did you notice that in the text above I mentioned our Patrons page? That is
|
||||
because I've rolled out a bunch of changes today.
|
||||
|
||||
Having taken the time to reflect on the money side of things, I've realized
|
||||
that it's an important factor in the well-being of this project. I also
|
||||
believe that donations -- while motivating and appreciated -- are not the best
|
||||
way to go about this.
|
||||
|
||||
So, as of today, we are calling all Patrons.
|
||||
|
||||
## Become a Patron of Freesewing
|
||||
|
||||
To ensure a sustainable future for freesewing.org, our code, our patterns, and
|
||||
our community, we need to build a bedrock of loyal supporters. Patrons who
|
||||
support us in our core work; Developing an open source platform for
|
||||
made-to-measure sewing patterns.
|
||||
|
||||

|
||||
|
||||
We have different tiers of Patronage, each with their own perks. You can
|
||||
support us for as little as 2€, and it only takes a minute.
|
||||
|
||||
> We are not changing the nature of the site. All patterns, and all our code,
|
||||
> will remain free.
|
||||
|
||||
We are not changing the nature of the site. All patterns, and all our code,
|
||||
will remain free. What we are changing is the way we raise funds. From a
|
||||
system of impulsive donations to a community of caring Patrons. If you are
|
||||
someone who cares, then [check out what we have to offer](/patrons/join).
|
||||
|
||||
I sincerely believe we are doing a worthwhile thing here. If you feel that way
|
||||
too, then I ask you to pledge whatever you can so that we can write many more
|
||||
chapters in this book.
|
||||
|
||||
> ### Become a Patron today #### You can sign up for as little as 2€, and it
|
||||
>
|
||||
> only takes a minute.
|
||||
> [Find out more](/patrons/join)
|
||||
|
||||
Thank you, and have a great year.
|
||||
|
||||
joost
|
||||
|
||||
<small>
|
||||
PS: It would be a shame if there's people out there willing to support us who don't know about
|
||||
this. So perhaps you could share this image on social media?{' '}
|
||||
<i class="fa fa-arrow-down" aria-hidden="true"></i>
|
||||
</small>
|
||||
|
||||

|
|
@ -0,0 +1,63 @@
|
|||
---
|
||||
title: 'Claim your showcase posts for eternal glory'
|
||||
caption: "Who's that cat?"
|
||||
date: '2024-02-25'
|
||||
intro: 'Showcase posts have alwasy been loosely attributed, we want to fix that'
|
||||
authors: 1
|
||||
---
|
||||
|
||||
There are [over 300 showcase posts on FreeSewing.org](/showcase) where our
|
||||
users showcase their makes. That's a truly great thing because it's not only
|
||||
nice to see what people come up with, it also gives new visitors to the site a
|
||||
good idea of what to expect from a given design.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
Showcase posts have been around for a while and they have survived a number of
|
||||
technical overhauls in how things work under the hood. And that's starting to
|
||||
show.
|
||||
|
||||
## Who made what?
|
||||
|
||||
There was a time when showcase posts were attributed by a
|
||||
name or description. Like _tony made this_. At one point, we assigned them to
|
||||
the username, but because users can change their username, such a system decays
|
||||
into chaos over time.
|
||||
|
||||
We'd like to address this growing library of showcase posts and make sure that
|
||||
as many as possible are properly credited to their makers.
|
||||
|
||||
For this reason, we've implemented a few changes:
|
||||
|
||||
- Showcase posts are now assigned to the user's FreeSewing ID.
|
||||
- When a showcase post is credited like this, we'll show the user's bio under
|
||||
the post
|
||||
- When there is no user credited, we will show a button to either claim this
|
||||
post as your own, or suggest another user in case you know who is the maker.
|
||||
|
||||
This way, given some time and collective effort, we hopefully will soon enough
|
||||
have properly credited all posts.
|
||||
|
||||
:::tip What is my FreeSewing ID?
|
||||
You can find your FreeSewing ID on [your
|
||||
account page](/account) or go to [FreeSewing.org/id](/id).
|
||||
:::
|
||||
|
||||
## Next steps The first thing to do is to make sure everything is properly
|
||||
|
||||
credited.
|
||||
|
||||
Afterwards, we can use this link between the showcase post and user to -- for
|
||||
example -- show a list of showcase posts on a user's profile.
|
||||
|
||||
If you have your own showcase posts on FreeSewing, please go ahead and claim
|
||||
them. Or if you know who made them, let us know.
|
||||
|
||||
## Also applies to blog posts
|
||||
|
||||
The same principle applies to blog posts, but since all but 2 posts on the site
|
||||
are written by that same dude, it's not really something where we need you
|
||||
help.
|
||||
|
||||
That being said, it does give you a good idea of what things will look like, as
|
||||
you can see below.
|
92
sites/orgdocs/blog/core-1-8-jaeger-across-back/index.mdx
Normal file
92
sites/orgdocs/blog/core-1-8-jaeger-across-back/index.mdx
Normal file
|
@ -0,0 +1,92 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'This release brought to you from Bangkok'
|
||||
date: '2018-03-21'
|
||||
intro: "We've just pushed the button on core 1.8.0. That bump in minor number is typically because we have a new pattern, but in this case, there's two reasons:"
|
||||
title: 'Freesewing core 1.8: Jaeger Jacket is in, across back measurement is out'
|
||||
---
|
||||
|
||||
We've just pushed the _release_ button on core 1.8.0. That bump in minor number
|
||||
is typically because we have a new pattern, but in this case, there's two
|
||||
reasons:
|
||||
|
||||
- The [Jaeger Jacket](/designs/jaeger) is now available
|
||||
- We've gotten rid of the _across back_ measurement
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
Read on for the details.
|
||||
|
||||
## Announcing the Jaeger Jacket
|
||||
|
||||
For [my refasioners entry last year](/blog/the-refashioners-2017/) I designed a
|
||||
jacket pattern that I intially wanted to release alongside my make. It didn't
|
||||
work out that way, and I asked for a bit more time to get the pattern out the
|
||||
door.
|
||||
|
||||
Turns out that when I say _a bit more time_ it means 6 and a half months, so
|
||||
please forgive me for the delay, but here it is, [the Jaeger
|
||||
Jacket](/designs/jaeger).
|
||||
|
||||

|
||||
|
||||
### Jaeger Sport Coat is not an alliteration
|
||||
|
||||
Jaeger is a sport coat style of jacket. As in, a single-breasted jacket with a
|
||||
2-button closure, and patch pockets.
|
||||
|
||||
In other words, this is a garment that's typically worn on jeans or other
|
||||
trousers, and not as part of a suit.
|
||||
|
||||
### Options galore
|
||||
|
||||
Jaeger comes with 38 options, so you can change _a lot_ about this pattern.
|
||||
|
||||
No need to worry though, it also comes with sensible defaults, so you can just
|
||||
as well ignore all those choices.
|
||||
|
||||
## The across back measurement is no more
|
||||
|
||||
Speaking of sensible defaults, Jaeger is not the only new thing in freesewing
|
||||
core 1.8.0, which is out today.
|
||||
|
||||
We've also gotten rid of the _across back_ measurement.
|
||||
|
||||
The across back measurement was cause of a great deal of confusion among our
|
||||
users. More often than not, when someone contacted us because their pattern
|
||||
looked wonky, an unrealistic across back measurement was to blame.
|
||||
|
||||
The roots of the across back measurement go back to a time when, instead of the
|
||||
_shoulder to shoulder_ measurement we use now, we had the _shoulder length_
|
||||
measurement. That one was also source of some confusion, so we phased it out
|
||||
in favour of the _shoulder to shoulder_ measurement.
|
||||
|
||||
The thing is that if we know the _shoulder to shoulder_ measurement, we can
|
||||
guestimate with reasonable accuracy what the _across back_ measurement will be.
|
||||
So, instead of asking you for it, we simply assume now.
|
||||
|
||||
### But you're dumbing down the pattern
|
||||
|
||||
In case the _this pattern comes with 38 options_ bit above wasn't enough of a
|
||||
giveaway, we're pretty committed here at freesewing to give you all the knobs
|
||||
to tweak your drafts.
|
||||
|
||||
Replacing a measurement with a value calculated based on another measurement
|
||||
may seem to go against that, but there's no need to worry. We've made sure you
|
||||
can still muck about with your across back.
|
||||
|
||||
Patterns that used to require the _across back_ measurement now have a new
|
||||
advanced option: the _across back factor_. It allows you to tweak how we
|
||||
calculate your across back measurement, but does make sure to keep it within
|
||||
boundaries that are sensible.
|
||||
|
||||

|
||||
|
||||
As such, we feel we're preventing mistakes for the casual user, without taking
|
||||
away power from you, the pattern option guru.
|
||||
|
||||
Or to put it differently, you can still muck about with your across back, but
|
||||
by default, you don't have to worry about it anymore.
|
108
sites/orgdocs/blog/core-v1-3-0-is-out/index.mdx
Normal file
108
sites/orgdocs/blog/core-v1-3-0-is-out/index.mdx
Normal file
|
@ -0,0 +1,108 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'Scales, how do they work?'
|
||||
date: '2018-01-04'
|
||||
intro: 'Freesewing core v1.3.0 is out; Comes with fixes so good that we back-ported them to all your drafts'
|
||||
title: 'Freesewing core v1.3.0 is out; Comes with fixes so good that we back-ported them to all your drafts'
|
||||
---
|
||||
|
||||
On the last day of 2017, in our [monthly roundup of all the freesewing
|
||||
news](/blog/roundup-2017-12/) , we wrote about the looming issue with
|
||||
incorrectly scaled drafts, aka [Core issue #204 - The Inkscape default units
|
||||
quandary](https://github.com/freesewing/core/issues/204).
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
I won't go over [all that](/blog/roundup-2017-12/) again, but it boils down to
|
||||
the fact that the [Inkscape](http://inkscape.org/) maintainers have changed
|
||||
Inkscape's internal DPI (dots per inch) from 90 to 96. A change that goes in
|
||||
effect from version 0.92 onwards.
|
||||
|
||||
Left unchecked, this change would cause all freesewing patterns to be
|
||||
incorrectly scaled. That's because we assume 90DPI in our SVG output, and
|
||||
scale accordingly.
|
||||
|
||||

|
||||
|
||||
When the switch to 96DPI goes into effect, all patterns would be off by 6.66%.
|
||||
Which is really the kind of difference that is too small to notice when
|
||||
eyeballing a pattern, yet large enough to completely mess up your garment.
|
||||
|
||||
The issue is also more troublesome than it would seem at the surface. First of
|
||||
all because we can't just switch to 96DPI as there are now two versions out
|
||||
there that use a different default DPI under the hood. We need a solution that
|
||||
works for both.
|
||||
|
||||

|
||||
|
||||
Furthermore, while any fix we implement would apply to new drafts, all existing
|
||||
drafts generated before the fix would still be impacted.
|
||||
|
||||
In other words, if you drafted a pattern last week, or a month ago, that
|
||||
pattern would not scale correctly in a recent version of Inkscape. And since
|
||||
we use Inkscape in our SVG-to-PDF tool-chain, it would also be incorrectly
|
||||
scaled if you came here and downloaded a PDF.
|
||||
|
||||
Clearly, something needed to be done. And fast.
|
||||
|
||||
## The fix for new drafts
|
||||
|
||||
From today's release of core v1.3.0 onwards, our SVG files no longer depend on
|
||||
any DPI setting.
|
||||
|
||||
Rather than use the internal units and apply an SVG transform to scale the
|
||||
entire pattern, we've bolted down the units to mm and updated the SVG viewBox
|
||||
to apply the scaling.
|
||||
|
||||
Obviously, this is how we should have done it from the start. Everyday is a
|
||||
school day.
|
||||
|
||||
If you're worried about the use of mm in your draft (because you're used to
|
||||
imperial units), rest assured that those mm will stay under the hood. You won't
|
||||
be able to tell the difference.
|
||||
|
||||
## The fix for pre-existing drafts
|
||||
|
||||
To avoid problems with pre-existing drafts, we needed to come up with a
|
||||
solution for those too.
|
||||
|
||||
We essentially have two options:
|
||||
|
||||
- Re-draft all those drafts
|
||||
- Patch them in-place without changing the draft itself
|
||||
|
||||
Re-drafting fixes the issue as every new draft will be handled by the latest
|
||||
core version that does include the fix.
|
||||
|
||||
However, core also ships with regular updates, tweaks, and fixes in the
|
||||
patterns themselves. So by re-drafting a draft generated on a previous version
|
||||
of core, there's no guarantee the draft won't change.
|
||||
|
||||
In principle that change would always be an improvement. But one person's bug
|
||||
is another person's feature, and we do prefer not to [move your
|
||||
cheese](https://en.wikipedia.org/wiki/Who_Moved_My_Cheese%3F).
|
||||
|
||||

|
||||
|
||||
So, instead we decided to patch all drafts we have on file in-place with the
|
||||
new scaling code, without touching any other aspect of the draft.
|
||||
|
||||
As you're reading this, this has already been done, and all freesewing drafts
|
||||
should now scale correctly. Everywhere.
|
||||
|
||||
## Also: version awareness
|
||||
|
||||
We've also made changes to our backend systems to store the version of
|
||||
freesewing core that generated your draft.
|
||||
|
||||
If since you generated your draft we've rolled out new features or fixes,
|
||||
you'll be notified that an update is available:
|
||||
|
||||

|
||||
|
||||
Whether you update your draft or not is up to you. If you don't want to loose
|
||||
the info in your _old_ draft, rather than update it in-place, you can fork it.
|
44
sites/orgdocs/blog/cornelius-cycling-breeches/index.mdx
Normal file
44
sites/orgdocs/blog/cornelius-cycling-breeches/index.mdx
Normal file
|
@ -0,0 +1,44 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'Cycling like a true gentlemen'
|
||||
date: '2021-03-06'
|
||||
intro: "Wouter is at it again, this time around he's treating us to classic cycling breeches."
|
||||
title: "These Cornelius cycling breeches are Wouter's latest gift to us all"
|
||||
---
|
||||
|
||||
[Wouter](https://www.instagram.com/wouter.vdub/) is at it again, this time
|
||||
around he's treating us to classic cycling breeches.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
He writes:
|
||||
|
||||
> When I was a child my dad would tell me stories about hiking in the
|
||||
> mountains, something magical for a kid living in The Netherlands. He had a
|
||||
> suitcase with his mountaineering things in it, and part of that were some
|
||||
> 'knickerbockers', baggy trousers that reached down to your calves.
|
||||
>
|
||||
> When I moved to the USA in my thirties and started hiking myself, I would
|
||||
> often reflect on those talks and felt sad that I didn't inherit those
|
||||
> knickerbockers. Then when I discovered sewing, I decided I would make myself
|
||||
> a pair, but no good patterns presented themselves.
|
||||
>
|
||||
> This year someone on the Freesewing discord server posted a link to The
|
||||
> 'Keystone' Systems, Practical methods of cutting, from around the turn of the
|
||||
> century. This contained a drafting system for 'Cycling Breeches', which
|
||||
> seemed to be close to what my father used to wear, and could be translated
|
||||
> into a Freesewing pattern. A project was born, and I'm happy to be able to
|
||||
> present the results to you.
|
||||
|
||||
As Wouter mentioned; This pattern is based on [the Keystone drafting
|
||||
method](https://archive.org/details/keystonesystemsc00heck/page/n5/mode/2up).
|
||||
Not that it matters because as always you get it made-to-measure for you [right
|
||||
here on FreeSewing.org](/designs/cornelius/).
|
||||
|
||||

|
||||
|
||||
Note that you don't have to cycle to wear these. All that's required is a
|
||||
willingness to show of those socks (or calfs).
|
||||
|
||||
Cornelius is available at [/designs/cornelius/](/designs/cornelius/).
|
102
sites/orgdocs/blog/email-breakdown-post-mortem/index.mdx
Normal file
102
sites/orgdocs/blog/email-breakdown-post-mortem/index.mdx
Normal file
|
@ -0,0 +1,102 @@
|
|||
---
|
||||
title: 'Email communication breakdown post-mortem'
|
||||
caption: "I love email, but it's hard to handle a lot of it"
|
||||
date: '2024-01-02'
|
||||
intro: 'From the end of 29 October 2023 until 2 January 2024, some emails sent to me fell between the cracks'
|
||||
authors: 1
|
||||
---
|
||||
|
||||
Between the 29th of October 2023 until the 2nd of January 2024, emails sent to
|
||||
joost@joost.at (my personal email) or various @freesewing.org email addresses
|
||||
went unnoticed. Since noticing the issue today I have gone through the backlog
|
||||
and set aside any messages that I need to deal with.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
However, this is a manual and tedious process so it's possible that I'll miss a
|
||||
few. In addition, it's also very possible that emails sent to me 2 months ago
|
||||
required a speedier response.
|
||||
|
||||
These emails would have included users asking for help, but also notifications
|
||||
about new patrons who've signed up or any donations FreeSewing received.
|
||||
|
||||
I'd like to apologize to all those who I should have been in touch with but
|
||||
didn't. To be as transparent as possible, I will explain in detail what
|
||||
happened below, and outline the steps I've taken to avoid this from happening
|
||||
again in the future.
|
||||
|
||||
## My email setup To understand what happened, I should start by explaining my
|
||||
|
||||
email setup.
|
||||
|
||||
I have historically used joost@decock.org as my personal email. It's tied to
|
||||
Google in the way that is no longer possible today, using one of those
|
||||
grandfathered-in domain setups that they don't allow you to have any longer. I
|
||||
don't trust Google as far as I can throw them, but Gmail is the best mail
|
||||
client for my needs because I don't want to spend my time carefully organizing
|
||||
email, I just want to search and find what I'm looking for. Nothing comes close
|
||||
to Gmail when it comes to that.
|
||||
|
||||
Furthermore, as an Android user, this primary not-really-gmail-but-still-a-bit
|
||||
Google account is also tied to my phone, and a host of other things that are
|
||||
important. In other words, I need to have _some_ Google account, so this is it.
|
||||
|
||||
That being said, I don't trust Google to not one day accidentally disable my
|
||||
account and I know full well that when that happens, I won't have any way of
|
||||
getting it back because Google doesn't do support. And I can't even blame them
|
||||
as I'm not a paying customer. So I want a different email provider, one where
|
||||
I am a paying customer, and that provider is fastmail. I could have migrated
|
||||
the decock.org domain to it, but that poses two problems:
|
||||
|
||||
- I still need a Google account
|
||||
- Some members of my family have a decock.org email address, so I would have to
|
||||
find a solution for them too and they are not too tech-savvy so that would
|
||||
have been a hassle.
|
||||
|
||||
So, a couple of years ago I decided to bite the bullet, bought the joost.at
|
||||
domain, and made that my primary email.
|
||||
|
||||
Obviously, my previous emails is still used by people and companies, and I have
|
||||
to keep the Google account active too, so now I have two inboxes to manage. I
|
||||
thought I had found a clever solution for that, and that's where things went
|
||||
wrong.
|
||||
|
||||
## It worked until it didn't
|
||||
|
||||
I had setup my Google account to pull in email from my fastmail account via
|
||||
POP3. This worked great and since both mailboxes are configured to allow me to
|
||||
send email from both addresses, it's transparent to my correspondents.
|
||||
|
||||
That all worked fine. But if I go into the settings and check that rule today,
|
||||
I see this:
|
||||
|
||||

|
||||
|
||||
Google stopped pulling in these emails, and somehow neglected to notify me of
|
||||
this. Because of this setup, I had not been checking my Fastmail inbox, so
|
||||
from one day to the next I didn't see anything sent to my new email address.
|
||||
|
||||
At this point, you're probably wondering why I didn't notice. The answer is
|
||||
partially that I get a lot of email, but if I'm being honest, at some level I
|
||||
probably suspected something was _off_ but I didn't realize exactly what, and
|
||||
because I was busy looking into it was kicked down the road.
|
||||
|
||||
## Going forward
|
||||
|
||||
Since I cannot trust Google to reliably pull in the emails from my Fastmail
|
||||
inbox, I will instead pivot to a _inbox double-zero_ approach. By which I mean,
|
||||
I will manage both inboxes and apply _inbox-zero_ as that's how I do things.
|
||||
|
||||
Given my neglect of my Fastmail inbox, it had 100k+ unread messages in them. I
|
||||
went through the messages since the end of October and set aside emails that I
|
||||
need to follow-up on. Then I archived the rest and now am back on top of
|
||||
things, albeit with a small pile of backlog to deal with.
|
||||
|
||||
I am particularly sorry for those people who signed up as patrons or donated to
|
||||
FreeSewing and didn't even get as much as an acknowledgment. I admit that this
|
||||
sort of _administrativia_ is not my strong suit, but my response time is not
|
||||
typically measured in months.
|
||||
|
||||
Apologies, and I will try to do better this year.
|
165
sites/orgdocs/blog/email-spam-problems/index.mdx
Normal file
165
sites/orgdocs/blog/email-spam-problems/index.mdx
Normal file
|
@ -0,0 +1,165 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'Would you close a lane because one driver was playing their music too loud?'
|
||||
date: '2017-09-07'
|
||||
intro: "Thanks for nothing Microsoft; Email shouldn't be this hard"
|
||||
title: "Thanks for nothing Microsoft; Email shouldn't be this hard"
|
||||
---
|
||||
|
||||
People with an email address from Microsoft --- think Hotmail, MSN, live.com,
|
||||
outlook.com and their numerous variants --- are significantly less likely to
|
||||
sign up for this website.
|
||||
|
||||
That's because more than 4 times out of 10, they never receive their account
|
||||
activation email.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
## What's going on?
|
||||
|
||||
Let's first look at what's happening. Here's a relevant snippet from the logs:
|
||||
|
||||
`````Failed: postmaster@mg.freesewing.org -> ********@hotmail.co.uk 'Confirm
|
||||
your freesewing account' Server response: 550 5.7.1 Unfortunately, messages
|
||||
from [104.130.122.15] weren't sent. Please contact your Internet service
|
||||
provider since part of their network is on our block list. ````
|
||||
|
||||
What this means is that part of the MailGun network is on their block list. As
|
||||
a result, they (more on who they are later) are not delivering any messages
|
||||
that go out.
|
||||
|
||||
[MailGun](https://www.mailgun.com/) is a popular email service for developers.
|
||||
It's used by this site to send out emails, like the account activation emails.
|
||||
|
||||
Other people use this service too, and perhaps some of them, at some point,
|
||||
delivered some spam messages through mailgun. Or it may just have been some guy
|
||||
with a last name that tends to trigger spam filters.
|
||||
|
||||

|
||||
|
||||
Point is, this IP address or one of its neighbours got *a bad rep*. It happens.
|
||||
But to flat-out refuse to accept any messages from this host (or an entire
|
||||
network of hosts) is the equivalent of shutting down a highway lane (or entire
|
||||
highway) because one car in that lane played its music obnoxiously loud that
|
||||
one time.
|
||||
|
||||
Which brings me to our next question:
|
||||
|
||||
## Who would do something like that?
|
||||
|
||||
Good question. Here are some numbers:
|
||||
|
||||

|
||||
|
||||
The graph above represents emails that were sent out since the launch of this
|
||||
site. The small subsection of the graph that is red are emails that are
|
||||
dropped.
|
||||
|
||||
This website sends out different kinds of email:
|
||||
|
||||
- The account confirmation email
|
||||
- The *I forgot my password* emails
|
||||
- Comment reply notifications
|
||||
|
||||
The graph represents all email, but I'm focussing on the account confirmation
|
||||
emails only. They are the most important after all.
|
||||
|
||||
> Apart from the 1 outlier, every message that was blocked, was blocked by
|
||||
> Microsoft
|
||||
|
||||
Here's a list of all domains that blocked legitimate activation emails to their
|
||||
users:
|
||||
|
||||
- btinternet.com
|
||||
- hotmail.com
|
||||
- hotmail.co.uk
|
||||
- live.ca
|
||||
- live.com
|
||||
- live.com.au
|
||||
- live.nl
|
||||
- msn.com
|
||||
- outlook.com
|
||||
|
||||
Apart from that very first entry in the list (on which only 1 message was
|
||||
blocked) all of these are Microsoft domains.
|
||||
|
||||
Let me restate that: Apart from the 1 outlier, every message that was blocked,
|
||||
was blocked by Microsoft.
|
||||
|
||||
## What's the impact?
|
||||
|
||||
So what sort of impact does that have on people?
|
||||
|
||||
Well, at the time I'm writing this, there are 817 registered users, and about
|
||||
80% (661) have also activated their account.
|
||||
|
||||

|
||||
|
||||
From those people who were able to activate their account, less than 1% (6)
|
||||
have an email address managed by Microsoft. In the group of people who did
|
||||
not, or were not able to, activate their account, more than half have such an
|
||||
address.
|
||||
|
||||
More than 40% of account confirmation emails are simply blocked by Microsoft
|
||||
and, based on the number of activations, it seems likely that even when they
|
||||
aren't block at the SMTP relay, they get filtered somewhere further down the
|
||||
line.
|
||||
|
||||
As things stand, it seems almost impossible for the average
|
||||
hotmail/outlook/live/MSN/... user to sign up for this site.
|
||||
|
||||
## What can we do about it?
|
||||
|
||||
I chose mailgun for a number of reasons. Not having to handle SMTP outselves
|
||||
simplifies the code. Not depending on a local SMTP deamon makes the code more
|
||||
portable, and MailGun has a bunch of cool features that allow you to do things
|
||||
like replying to comments via email.
|
||||
|
||||
Microsoft's crude methods of spam filtering don't invalidate any of those
|
||||
reasons.
|
||||
|
||||
Using MailGun means using their SMTP relays, and being at the mercy of the
|
||||
reputation of that relay. The only way around that is to configure a dedicated
|
||||
relay in MailGun so that freesewing.org traffic is shielded from others, and we
|
||||
become masters of our own reputation.
|
||||
|
||||

|
||||
|
||||
For that priviledge, MailGun charges 59 dollar per month, which amounts to 708
|
||||
dollar yearly. I invite you to take a look at [the donations
|
||||
history](/about/pledge#donations-history), and you'll understand that's not
|
||||
going to happen either.
|
||||
|
||||
I could challenge the block list, and try to get the relay unblocked. But
|
||||
that's pretty much tilting at windmills when the host is not under my control.
|
||||
Not to mention that MailGun doesn't just have that one host.
|
||||
|
||||
It seems that I'm running low on options and quiet frankly, I'm also running
|
||||
out of patience.
|
||||
|
||||
## What I'm going to do about it
|
||||
|
||||
Microsoft is a behemoth, and I'm just a guy. I can't fight them on this.
|
||||
Unless I Titanfall their ass.
|
||||
|
||||

|
||||
|
||||
Do you think Gmail is ever abused to send out spam? You know it is. Do you
|
||||
think they would ever block all email coming from Gmail? You know they won't.
|
||||
|
||||
So last night, I rolled out some changes to work around the issue. If you have
|
||||
a *problemtic* email address, in addition to the regular email, this site will
|
||||
send out a second email through Gmail.
|
||||
|
||||
I'd like to see them block that.
|
||||
|
||||
> ##### Signup trouble? Help is available If you are (still) having problems
|
||||
> signing up, don't hesitate to [get in touch](/contact).
|
||||
|
||||
`````
|
29
sites/orgdocs/blog/facemask-frenzy/index.mdx
Normal file
29
sites/orgdocs/blog/facemask-frenzy/index.mdx
Normal file
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'Dr. Dragnea from Antwerp University hospital wearing a Florence facemask'
|
||||
date: '2020-03-19'
|
||||
intro: "Calling all makers: Here's a 1-page PDF facemask pattern; Now go make some and help beat this thing"
|
||||
title: "Calling all makers: Here's a 1-page PDF facemask pattern; Now go make some and help beat this thing"
|
||||
---
|
||||
|
||||
Well that escalated quickly. We published [our Florence Face Mask
|
||||
pattern](/designs/florence/) at the end of last month, hoping it would be
|
||||
helpful. Now, [hospitals are actively reaching out to people to beg them to
|
||||
make fabric face masks for their staff](https://www.uza.be/mondmaskers).
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
So obviously, we want to help:
|
||||
|
||||
- PDF pattern for our Florence face mask:
|
||||
- A4 facemask pattern
|
||||
- Letter facemask pattern
|
||||
- [Instructions for the facemask pattern](/docs/designs/florence/instructions/)
|
||||
|
||||
No go and make a bunch. Our healthcare workers are counting on you!
|
||||
|
||||
<YouTube id="VcQ69_ANsRA" />
|
||||
|
||||
:::tip
|
||||
You can support us by [becoming a patron](/patrons/join/) ❤️
|
||||
:::
|
47
sites/orgdocs/blog/florence-face-mask/index.mdx
Normal file
47
sites/orgdocs/blog/florence-face-mask/index.mdx
Normal file
|
@ -0,0 +1,47 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'Keep those virus-infesed droplets at bay with our Florence face mask'
|
||||
date: '2020-02-28'
|
||||
intro: 'We just published a face mask pattern, because coronavirus'
|
||||
title: 'We just published a face mask pattern, because coronavirus'
|
||||
---
|
||||
|
||||
The spread of the Covid-19 coronavirus seems relentless and despite the world's
|
||||
best attempts, the possibility of a global pandemic is getting more real every
|
||||
day. Which begs the question, what can we do?
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
Perhaps not much, but we can design patterns. So say hi to the [Florence face
|
||||
mask](/designs/florence/), a simple pattern that allows you make your own face
|
||||
masks. One that you can wear all day, because those medical ones aren't exactly
|
||||
comfortable.
|
||||
|
||||
Whether or not a face mask actually helps is subject of debate. I've been
|
||||
to-ing and fro-ing a bit about whether to publish a pattern for a face mask.
|
||||
Then — earlier today — I read a [Guardian](https://www.theguardian.com/)
|
||||
article called [Yes, it is worse than the flu: busting the coronavirus
|
||||
myths](https://www.theguardian.com/world/2020/feb/28/coronavirus-truth-myths-flu-covid-19-face-masks).
|
||||
It included the following passage under the _Face masks don’t work_ myth:
|
||||
|
||||
:::note Claim: ‘Face masks don’t work’
|
||||
|
||||
_Wearing a face mask is not an iron clad guarantee that you won’t get sick –
|
||||
viruses can also transmit through the eyes and tiny viral particles, known as
|
||||
aerosols, can still penetrate masks. However, masks are effective at
|
||||
capturing droplets, which is the main transmission route of coronavirus, and
|
||||
some studies have estimated a roughly five-fold protection versus no barrier.
|
||||
If you are likely to be in close contact with someone infected, a mask cuts
|
||||
the chance of the disease being passed on._
|
||||
:::
|
||||
|
||||
This only focusses on preventing you from getting coronavirus. There's also
|
||||
the fact that the mask can help (a bit) in keeping you from spreading it
|
||||
further. Because the way things are going right now, it looks like we should
|
||||
do every little thing we can to try to slow this thing down.
|
||||
|
||||
So when I got home, I set out to rush out a face mask pattern. Common sense
|
||||
says it can't hurt, and apparently there's more to it too. If nothing else, I
|
||||
want a cute face mask, not one of the ugly ones you see on the news.
|
||||
|
||||
Stay safe out there.
|
49
sites/orgdocs/blog/florent-flat-cap-beta/index.mdx
Normal file
49
sites/orgdocs/blog/florent-flat-cap-beta/index.mdx
Normal file
|
@ -0,0 +1,49 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'Quentin surrounded by our future robot overlords.'
|
||||
date: '2017-12-06'
|
||||
intro: "The Florent Flat Cap pattern is now available in beta. That's another gift sorted."
|
||||
title: "The Florent Flat Cap pattern is now available in beta. That's another gift sorted."
|
||||
---
|
||||
|
||||
After last month's release of [Benjamin](/designs/benjamin), here's another
|
||||
pattern release to channel the dapper gentleman within: the [Florent Flat
|
||||
Cap](/designs/florent).
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
Like Benjamin, this pattern was contributed by the freesewing community, rather
|
||||
than yours truly. In this case, it was [Quentin Felix](/users/user?id=241) who
|
||||
signed for the design.
|
||||
|
||||
I asked Quentin if he wanted to write this announcement blog post himself, but
|
||||
he argued that it was time I did something too. He did have this to share
|
||||
though, on his reasons for designing this pattern in the first place:
|
||||
|
||||
:::note Quentin on his reasons for designing Florent
|
||||
|
||||
I like wearing flat caps myself. I didn't use to, but I have a friend Florent
|
||||
who inspired me to wear them (now you know where the name comes from).
|
||||
|
||||
The first time I made a flat cap, it took me ages to scale the pattern to an
|
||||
exact fit, involving a lot of messing about with tracing paper. There's a
|
||||
number of patterns available online for flat caps. But they all come in one
|
||||
size only.
|
||||
|
||||
I wanted to make this more accessible to people. And, while I was at it, I
|
||||
also drew on my experience to add some tweaks for a better fit.
|
||||
|
||||
For example, this design extends lower at the back of the head, which gives
|
||||
it better hold.
|
||||
:::
|
||||
|
||||
This _why should we always have to re-invent the wheel?_ could pretty much be
|
||||
freesewing's slogan.
|
||||
|
||||
## It's the season for giving
|
||||
|
||||
Florent requires only one measurement: the head circumference. As such, this
|
||||
release is perfectly timed. With the holiday season coming up, here's another
|
||||
gift you can make yourself.
|
||||
|
||||
Thanks Quentin!
|
66
sites/orgdocs/blog/freesewing-2-19/index.mdx
Normal file
66
sites/orgdocs/blog/freesewing-2-19/index.mdx
Normal file
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'Like history? Then this release is going to be right up your alley.'
|
||||
date: '2021-10-17'
|
||||
intro: "I've just pulled the release lever on version 2.19 of FreeSewing and there's a lot that went into this release. For full details, you can check out the changelog , here I'll stick to the highlights:"
|
||||
title: 'FreeSewing 2.19 brings Bee, Lunetius, Tiberius, Walburga, a new plugin, and a bunch of improvements and fixes'
|
||||
---
|
||||
|
||||
I've just pulled the release lever on version 2.19 of FreeSewing and there's a
|
||||
lot that went into this release. For full details, you can [check out the
|
||||
changelog](https://github.com/freesewing/freesewing/blob/develop/CHANGELOG.md#2190-2021-10-17),
|
||||
here I'll stick to the highlights:
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
## Lunetius, Tiberius, and Walburga
|
||||
|
||||
[Lunetius](/designs/lunetius), [Tiberius](/designs/tiberius/), and
|
||||
[Walburga](/designs/walburga/) are three new patters from **Rika Tamaike** who
|
||||
is the latest addition to our growing team of designers. These are all
|
||||
historical pattern:
|
||||
|
||||
- Lunetius is a lacerna, a historical Roman cloak
|
||||
- Tiberius is a historical Roman tunic
|
||||
- Walburga is a tabard/surcoat, a historical garment from medieval Europe
|
||||
|
||||
I'm not much of a history buff myself, so I'm looking forward to see what these
|
||||
will look like when people are going to start making them. What I can say for
|
||||
sure is that all of these are pretty straight-forward, so they should be fun to
|
||||
make.
|
||||
|
||||
## The Bee bikini
|
||||
|
||||
Also new in this release is [Bee](/designs/bee/), a bikini pattern that you can
|
||||
pair with the [Uma Undies pattern](/designs/uma/). **Bobgeorgethe3rd**
|
||||
signed for the code, the design of the bikini was a collaboration with
|
||||
**PrudenceRabbit**.
|
||||
|
||||
I'm hoping for some people in the Southern hemisphere to make this one because
|
||||
I suspect it might be a while before bikini weather returns to those of use
|
||||
living above the equator.
|
||||
|
||||
This too is a fast and simple make, so go and check it out.
|
||||
|
||||
## The versionfree-svg plugin
|
||||
|
||||
This is a bit more under-the-hood stuff, but we've also published
|
||||
[plugin-versinofree-svg](https://www.npmjs.com/package/@freesewing/plugin-versionfree-svg),
|
||||
a new plugin that will strip the version information from FreeSewing's SVG
|
||||
output.
|
||||
|
||||
This is handy because it allows diffing between different versions. By not
|
||||
including the version information, you can see what (if anything) has changed
|
||||
between different versions of a pattern, something we use ourselved in our QA
|
||||
pipeline.
|
||||
|
||||
## Backported snap options from the v3 roadmap
|
||||
|
||||
Speaking of under-the-hood, the [snap
|
||||
proposal](https://github.com/freesewing/freesewing/discussions/1331) on [our v3
|
||||
roadmap](https://github.com/freesewing/freesewing/discussions/1278) was
|
||||
something we liked so much that we promptly backported it to v2, and it's
|
||||
already being used in different patterns.
|
||||
|
||||
Have fun with the new patterns, and for feedback, questions, or suggestions,
|
||||
[come hang out with us on Discord](https://discord.freesewing.org).
|
66
sites/orgdocs/blog/freesewing-2-21/index.mdx
Normal file
66
sites/orgdocs/blog/freesewing-2-21/index.mdx
Normal file
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: 'A pink Hi and its BLÅHAJ ancestor'
|
||||
date: '2022-06-27'
|
||||
intro: 'FreeSewing 2.21 adds Bob, Hi, Lucy, Noble and Unice designs'
|
||||
title: 'FreeSewing 2.21 adds Bob, Hi, Lucy, Noble and Unice designs'
|
||||
---
|
||||
|
||||
We've rolled out FreeSewing v2.21 today, and it's a massive update with tons of
|
||||
changes, improvements, and behind the scenes work. Check the CHANGELOG if
|
||||
you'd like get all the nitty-gritty detail. For this blog post, I'll focus on
|
||||
what you are probably going to be most interested in: New designs.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
This release brings 5 new designs to our catalog, so let's dive right in:
|
||||
|
||||
## Bob is a bib
|
||||
|
||||
We've been using the construction of a Bib pattern in our [pattern design
|
||||
tutorial](https://freesewing.dev/tutorials/pattern-design) for years. Yet we
|
||||
never added the pattern to our catalog. An oversight that's been corrected now,
|
||||
and we now carry [Bob the bib](/designs/bob) in our collection.
|
||||
|
||||
Perfect for babies and grown-ups who are messy eaters alike, since you can make
|
||||
Bob in any size.
|
||||
|
||||
## Hi is a shark
|
||||
|
||||
It's been kinda hard to contain our excitement about this, but hear me out: A
|
||||
while ago rumours started swirling that IKEA would discontinue it's
|
||||
[BLÅHAJ](https://www.ikea.com/us/en/p/blahaj-soft-toy-shark-90373590/) stuffed
|
||||
shark, which is a universally beloved toy.
|
||||
|
||||
The FreeSewing community wasn't just going to idly stand by while the worlds
|
||||
friendliest shark ran the risk of becoming extinct. A conservation effort
|
||||
gained momentum, and ultimately Wouter matter-of-factively dropped the first
|
||||
**Hi** pictures in our Discord.
|
||||
|
||||
Oh, and you should know that [Hi](/designs/hi) can be made big or small. The
|
||||
patterns scales up to a 5m shark. What are you waiting for?
|
||||
|
||||
## Lucy is a tie-on pocket
|
||||
|
||||
We've seen a number of historical designs recently, specifically from Starf.
|
||||
This time around, it's SeaZeeZee who added [Lucy](/designs/lucy) which is a
|
||||
pattern for a tie-on pocket.
|
||||
|
||||
It's a quick make for cosplay, historical re-enactment, or for all those
|
||||
dresses that don't come with pockets.
|
||||
|
||||
## Noble is a body block with prince(ss) seams
|
||||
|
||||
Wouter (of Hi fame) has another contribution in this release: Noble is a
|
||||
princess seam body block. Blocks tend to be undervalued but they are the
|
||||
foundation that other designs are built on, so having a new body block with
|
||||
prince(ss) seams is very exciting.
|
||||
|
||||
## Unice is for undies
|
||||
|
||||
Unice is a variant of Ursula, another
|
||||
undies pattern. It was designed by Anna who describes it as _the undies for
|
||||
those with significant rear estate_.
|
||||
|
||||
It has a few changes and tweaks in comparison to Ursula, and is specifically
|
||||
intended to fit _any_ body. So if you're rear estate mogul, try these out.
|
148
sites/orgdocs/blog/freesewing-goes-jamstack/index.mdx
Normal file
148
sites/orgdocs/blog/freesewing-goes-jamstack/index.mdx
Normal file
|
@ -0,0 +1,148 @@
|
|||
---
|
||||
authors: 1
|
||||
caption: "Picture by <a href='https://stock.tookapic.com/jenniferforjoy' target='_BLANK' rel='nofollow'>Jennifer</a>"
|
||||
date: '2017-06-12'
|
||||
intro: 'When we released freesewing core at the end of March, my focus immeadiatly shifted to building our front-end so that freesewing.org could fully replace makemypattern.com .'
|
||||
title: "We're JAMstack, we're JAMstack, we're JAMstack, we're JAMstack, we're JAMstack, we're JAMstack, we're JAMstack, and I hope you like JAMstack too"
|
||||
---
|
||||
|
||||
When we released freesewing core at the end of March, my focus immeadiatly
|
||||
shifted to building our front-end so that [freesewing.org](/) could fully
|
||||
replace [makemypattern.com](https://makemypattern.com/).
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
I believe that the value of freesewing lies with the core platform and our
|
||||
patterns. But without a user friendly way to expose that value, it will
|
||||
largely go ignored.
|
||||
|
||||
So we needed a website that lets people generate patterns. Makemypattern.com
|
||||
— arguably the best comparison of something similar — runs on
|
||||
Drupal 7, and my initial idea was to run the new site on Drupal 8. I went down
|
||||
that path far enought to be confident I could get it to work, and hook it up to
|
||||
our backend. At which point I switched gears and turned my attention to what is
|
||||
now known as freesewing core.
|
||||
|
||||
Core took about 7 months to build, and a lot has changed since then. Or perhaps
|
||||
I have changed, I certainly learned a lot along the way. Either way, I've
|
||||
decided to do things different.
|
||||
|
||||
## The problem with a CMS
|
||||
|
||||
I have no beef with Drupal but the idea of managing the freesewing website
|
||||
through any Content Management System (CMS) does not appeal to me.
|
||||
|
||||
One of the main reason is that so much information is stored under an opaque
|
||||
database layer which makes it difficult to manage. That goes for content where
|
||||
posts, metadata, images, and so on is all spread across tables, locations, and
|
||||
folders. But there's also the theme that has a bunch of stuff in it, there's
|
||||
the custom Drupal modules to connect to the backend, and so on and so forth.
|
||||
|
||||
> I wanted that same approach in a website. Except, it can't be static because
|
||||
> it has to, you know, do stuff.
|
||||
|
||||
When we were finalizing core, I built a documentation site for it based on
|
||||
[Jekyll](https://jekyllrb.com/). It felt like a breath of fresh air in
|
||||
comparison. Just a bunch of markdown files, with some SASS, images, and some
|
||||
JavaScript thrown in the mix, and it all compiles into a neat static website.
|
||||
|
||||
It's easy to manage, and it integrates nicely with a GitHub-centered workflow
|
||||
that is going to be famliar to potential contributors.
|
||||
|
||||
I wanted that same approach in a website. Except, it can't be static because it
|
||||
has to, you know, do stuff.
|
||||
|
||||
## An alternative approach: JAMstack
|
||||
|
||||
I first learned about JAMstack when I started looking into hosting for said
|
||||
core documentation site. It was initially hosted on GitHub pages which
|
||||
provides free hosting. They also have SSL or a custom domain name, but you
|
||||
can't have both. Which was kind of a deal breaker.
|
||||
|
||||
Looking for alternatives, I stumbled onto [Netlify](https://www.netlify.com/),
|
||||
who do both SSL and custom domains and have a free-tier for open source
|
||||
projects (thanks guys). Furthermore, [this video by Netlify CEO Mathias
|
||||
Biilmann](https://vimeo.com/163522126) got me really excited about JAMstack.
|
||||
|
||||
Unless you're familiar with JAMstack, I suggest you check out the video, but it
|
||||
boils down to this:
|
||||
|
||||
- **J** = JavaScript
|
||||
- **A** = APIs
|
||||
- **M** = Markup
|
||||
|
||||
The idea is that you build your static site (markup) that you then make
|
||||
interactive with JavaScript that hooks up to one or more APIs.
|
||||
|
||||
So in our case, rather than having a straight-forward documentation site with
|
||||
easy-to-edit markdown and a complex CMS to handle the dymanic stuff, let's just
|
||||
build one simple site that is statically generated, yet uses JavaScript and
|
||||
APIs to do the smart stuff.
|
||||
|
||||
## Running before you can walk
|
||||
|
||||
I must admit that in my enthousiasm to embrace this new approach I got a little
|
||||
ahead of myself. Suddenly, I was no longer building a simple site, but I was
|
||||
up to my eyeballs in isomorphic rendering, client-side routing, React and
|
||||
Redux, Node.js and ES6 transpiling.
|
||||
|
||||
> If you don't know what any of that means, you might get a hint of the
|
||||
> frustration I felt as I was trying to tame all these new beasts.
|
||||
>
|
||||
> If you do know what it all means, where were you back in April when I walked
|
||||
> through the valley of the React of death?
|
||||
|
||||
Point is, I'm not a developer and I was in way over my head. While I was
|
||||
learning new things every day, I wasn't making much progress on the actual task
|
||||
at hand, and felt frustrated with my inability to do even the most mundane
|
||||
things.
|
||||
|
||||
After a month of frustration, loads of trial and seemingly even more error, I
|
||||
threw in the towel. Eff this newfangled shiny JavaScript all the young kids
|
||||
are using, I'll stick to what I know.
|
||||
|
||||
Which is essentially the basics of jQuery. In other words, stuff that was
|
||||
pretty cool 10 years ago.
|
||||
|
||||
## 10 year old jam is still jam right?
|
||||
|
||||
So here we are, freesewing.org is a site powered by the JAMstack. And you know
|
||||
what, it seems to do what it needs to do.
|
||||
|
||||
We have Jekyll build out static site, and when we push to our master branch, it
|
||||
gets autmatically deployed to Netlify.
|
||||
|
||||
> Eff this newfangled shiny JavaScript all the young kids are using
|
||||
|
||||
We have [a brand new data API](https://github.com/freesewing/data) build on
|
||||
[the Slim framework](https://www.slimframework.com/). It handles all user
|
||||
data. Things like accounts, measurements, models, and drafts, but also comments
|
||||
on this website and so on.
|
||||
|
||||
It also talks to core for us, and every time you draft a pattern, we don't just
|
||||
give you the pattern, but we also run a comparison of your pattern to a range
|
||||
of standard sizes, which is kinda cool.
|
||||
|
||||
And we have other cool stuff, like the ability to fork or redraft an existing
|
||||
draft.
|
||||
|
||||
## This is a starting point
|
||||
|
||||
I hope the user experience/interface is not going to be a roadblock for people.
|
||||
I've made a great deal of effort to make the drafting process as intuitive as
|
||||
possible and I think that in comparison to our demo (or the makemypattern
|
||||
interface for that matter) it's a vast improvement.
|
||||
|
||||
Then again, I'm sure things will break left or right, or that some of you don't
|
||||
like the colours or whatnot.
|
||||
|
||||
The point is that I set out to build something that can replace
|
||||
makemypattern.com so that I could tell all of you _Hey, come over and play with
|
||||
this new thing_.
|
||||
|
||||
I think if nothing else, I can do that now. And if you see room for
|
||||
improvement, please join the effort, we're only getting started.
|
||||
|
||||
<small>PS: For those of you wondering about the title of this post:</small>
|
||||
|
||||
<YouTube id="oFRbZJXjWIA" />
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
title: 'FreeSewing is now pay-what-you-want'
|
||||
caption: 'A Person Putting Coin in a Piggy Bank, by Maitree Rimthong'
|
||||
date: '2023-11-03'
|
||||
intro: "We have updated our pricing, here's why"
|
||||
authors: 1
|
||||
---
|
||||
|
||||
I am clearly doing a terrible job at convincing people to [become a FreeSewing
|
||||
patron](/patrons/join), because while user growth is ever increasing, our
|
||||
revenue is not. In addition, inflation is very real, meaning that even when
|
||||
revenue remains the same, we're actually less able to make a difference.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
The rise in users also brings additional costs. Simply put, running
|
||||
FreeSewing.org is getting more expensive year by year, while revenue does not
|
||||
keep up, and that's a trend that has me worried for a while now.
|
||||
|
||||
I considered my options for how to deal with this. I could raise prices, but
|
||||
that seems to punish our patrons who are already supporting us, while the vast
|
||||
majority of users does not contribute. Having more patrons is the obvious
|
||||
answer, but I don't like asking for money and in general seem to be rather bad
|
||||
at this sort of thing.
|
||||
|
||||
So, after thinking it over for a while, I have decided to go the other
|
||||
direction. Rather than raise prices, I have removed pricing altogether.
|
||||
FreeSewing is now pay-what-you-want. Yes, you can still have everything for
|
||||
free, but [please consider supporting us with whatever amount you can
|
||||
spare](/patrons/join).
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue