diff --git a/README.md b/README.md index 2b223ba..e4db6b7 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,15 @@ Draw perfect pressure-sensitive freehand lines. 🔗 Try out a [demo](https://perfect-freehand-example.vercel.app/). +🕊 Flutter dev? Check out the [dart version](https://pub.dev/packages/perfect_freehand) of this library. + 💰 Using this library in a commercial product? Consider [becoming a sponsor](https://github.com/sponsors/steveruizok?frequency=recurring&sponsor=steveruizok). ## Table of Contents - [Installation](#installation) - [Usage](#usage) +- [Documentation](#documentation) - [Support](#support) - [Discussion](#discussion) - [Author](#author) @@ -26,33 +29,125 @@ or yarn add perfect-freehand ``` -## Usage +## Introduction + +This package exports a function named `getStroke` that will generate the points for a polygon based on an array of points. + +![Screenshot](process.gif "A GIF showing a stroke's input points, outline points, and a curved path connecting these points") -This package exports a function named `getStroke` that: +To do this work, `getStroke` first creates a set of spline points (red) based on the input points (grey) and then creates outline points (blue). You can render the result any way you like, using whichever technology you prefer. -- accepts an array of points and an (optional) options object -- returns a stroke outline as an array of points formatted as `[x, y]` +[![Edit perfect-freehand-example](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/perfect-freehand-example-biwyi?fontsize=14&hidenavigation=1&theme=dark) + +## Usage + +To use this library, import the `getStroke` function and pass it an array of **input points**, such as those recorded from a user's mouse movement. The `getStroke` function will return a new array of **outline points**. These outline points will form a polygon (called a "stroke") that surrounds the input points. ```js import { getStroke } from 'perfect-freehand' + +const inputPoints = [ + [0, 0], + [10, 5], + [20, 8], + // ... +] + +const outlinePoints = getStroke(inputPoints) +``` + +You then can **render** your stroke points using your technology of choice. See the [Rendering](#rendering) section for examples in SVG and HTML Canvas. + +You can **customize** the appearance of the stroke shape by passing `getStroke` a second parameter: an options object containing one or more options. See the [Options](#options) section for a full list of available options. + +```js +const stroke = getStroke(myPoints, { + size: 32, + thinning: 0.7, +}) ``` -You may format your input points as array _or_ an object. In both cases, the value for pressure is optional (it will default to `.5`). +The appearance of a stroke is effected by the **pressure** associated with each input point. By default, the `getStroke` function will simulate pressure based on the distance between input points. + +To use **real pressure**, such as that from a pen or stylus, provide the pressure as the third number for each input point, and set the `simulatePressure` option to `false`. ```js -getStroke([ - [0, 0, 0], - [10, 5, 0.5], - [20, 8, 0.3], -]) - -getStroke([ - { x: 0, y: 0, pressure: 0 }, - { x: 10, y: 5, pressure: 0.5 }, - { x: 20, y: 8, pressure: 0.3 }, -]) +const inputPoints = [ + [0, 0, 0.5], + [10, 5, 0.7], + [20, 8, 0.8], + // ... +] + +const outlinePoints = getStroke(inputPoints, { + simulatePressure: false, +}) +``` + +In addition to providing points as an array of arrays, you may also provide your points as an **array of objects** as show in the example below. In both cases, the value for pressure is optional (it will default to `.5`). + +```js +const inputPoints = [ + { x: 0, y: 0, pressure: 0.5 }, + { x: 10, y: 5, pressure: 0.7 }, + { x: 20, y: 8, pressure: 0.8 }, + // ... +] + +const outlinePoints = getStroke(inputPoints, { + simulatePressure: false, +}) +``` + +**Note:** Internally, the `getStroke` function will convert your object points to array points, which will have an effect on performance. If you're using this library ambitiously and want to format your points as objects, consider modifying this library's `getStrokeOutlinePoints` to use the object syntax instead (e.g. replacing all `[0]` with `.x`, `[1]` with `.y`, and `[2]` with `.pressure`). + +## Example + +```jsx +import * as React from 'react' +import { getStroke } from 'perfect-freehand' +import { getSvgPathFromStroke } from './utils' + +export default function Example() { + const [points, setPoints] = React.useState([]) + + function handlePointerDown(e) { + e.target.setPointerCapture(e.pointerId) + setPoints([[e.pageX, e.pageY, e.pressure]]) + } + + function handlePointerMove(e) { + if (e.buttons !== 1) return + setPoints([...points, [e.pageX, e.pageY, e.pressure]]) + } + + const stroke = getStroke(points, { + size: 16, + thinning: 0.5, + smoothing: 0.5, + streamline: 0.5, + }) + + const pathData = getSvgPathFromStroke(stroke) + + return ( + + {points && } + + ) +} ``` +> **Tip:** For implementations in Typescript, see the example project included in this repository. + +[![Edit perfect-freehand-example](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/perfect-freehand-example-biwyi?fontsize=14&hidenavigation=1&theme=dark) + +## Documentation + ### Options The options object is optional, as are each of its properties. @@ -107,6 +202,58 @@ getStroke(myPoints, { > **Tip:** To create a stroke that gets thinner with pressure instead of thicker, use a negative number for the `thinning` option. +### Other Exports + +For advanced usage, the library also exports smaller functions that `getStroke` uses to generate its outline points. + +#### `getStrokePoints` + +A function that accepts an array of points (formatted either as `[x, y, pressure]` or `{ x: number, y: number, pressure: number}`) and (optionally) an options object. Returns a set of adjusted points as `{ point, pressure, vector, distance, runningLength }`. The path's total length will be the `runningLength` of the last point in the array. + +```js +import { getStrokePoints } from 'perfect-freehand' +import samplePoints from "./samplePoints.json' + +const strokePoints = getStrokePoints(samplePoints) +``` + +#### `getOutlinePoints` + +A function that accepts an array of points (formatted as `{ point, pressure, vector, distance, runningLength }`, i.e. the output of `getStrokePoints`) and (optionally) an options object, and returns an array of points (`[x, y]`) defining the outline of a pressure-sensitive stroke. + +```js +import { getStrokePoints, getOutlinePoints } from 'perfect-freehand' +import samplePoints from "./samplePoints.json' + +const strokePoints = getStrokePoints(samplePoints) + +const outlinePoints = getOutlinePoints(strokePoints) +``` + +**Note:** Internally, the `getStroke` function passes the result of `getStrokePoints` to `getStrokeOutlinePoints`, just as shown in this example. This means that, in this example, the result of `myOutlinePoints` will be the same as if the `samplePoints` array had been passed to `getStroke`. + +#### `StrokeOptions` + +A TypeScript type for the options object. Useful if you're defining your options outside of the `getStroke` function. + +```ts +import { StrokeOptions, getStroke } from 'perfect-freehand' + +const options: StrokeOptions = { + size: 16, +} + +const stroke = getStroke(options) +``` + +## Tips & Tricks + +### Freehand Anything + +While this library was designed for rendering the types of input points generated by the movement of a human hand, you can pass any set of points into the library's functions. For example, here's what you get when running [Feather Icons](https://feathericons.com/) through `getStroke`. + +![Icons](icons.png) + ### Rendering While `getStroke` returns an array of points representing the outline of a stroke, it's up to you to decide how you will render these points. @@ -131,23 +278,21 @@ function getSvgPathFromStroke(stroke) { } ``` -To use this function, first use perfect-freehand to turn your input points into a stroke outline, then pass the result to `getSvgPathFromStroke`. +To use this function, first run your input points through `getStroke`, then pass the result to `getSvgPathFromStroke`. ```js -import { getStroke } from 'perfect-freehand' +const outlinePoints = getStroke(inputPoints) -const myStroke = getStroke(myInputPoints) - -const pathData = getSvgPathFromStroke(myStroke) +const pathData = getSvgPathFromStroke(outlinePoints) ``` -You could then pass this string either to an [SVG path](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d) element: +You could then pass this string of SVG path data either to an [SVG path](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d) element: ```jsx ``` -Or, if you are rendering with HTML Canvas, you can pass the result to a [`Path2D` constructor](https://developer.mozilla.org/en-US/docs/Web/API/Path2D/Path2D#using_svg_paths)). +Or, if you are rendering with HTML Canvas, you can pass the string to a [`Path2D` constructor](https://developer.mozilla.org/en-US/docs/Web/API/Path2D/Path2D#using_svg_paths)). ```js const myPath = new Path2D(pathData) @@ -157,113 +302,24 @@ ctx.fill(myPath) ### Flattening -To render a stroke as a "flattened" polygon, add the [`polygon-clipping`](https://github.com/mfogel/polygon-clipping) package and use the following function together with the `getSvgPathFromStroke`. +By default, the polygon's paths include self-crossings. You may wish to remove these crossings and render a stroke as a "flattened" polygon. To do this, install the [`polygon-clipping`](https://github.com/mfogel/polygon-clipping) package and use the following function together with the `getSvgPathFromStroke`. ```js import polygonClipping from 'polygon-clipping' function getFlatSvgPathFromStroke(stroke) { - const poly = polygonClipping.union([stroke]) + const faces = polygonClipping.union([stroke]) const d = [] - for (let face of poly) { - for (let points of face) { + faces.forEach((face) => + face.forEach((points) => { d.push(getSvgPathFromStroke(points)) - } - } - - return d.join(' ') -} -``` - -> **Tip:** For implementations in Typescript, see the example project included in this repository. - -### Example - -```jsx -import * as React from 'react' -import { getStroke } from 'perfect-freehand' -import { getSvgPathFromStroke } from './utils' - -export default function Example() { - const [points, setPoints] = React.useState([]) - - function handlePointerDown(e) { - e.target.setPointerCapture(e.pointerId) - setPoints([[e.pageX, e.pageY, e.pressure]]) - } - - function handlePointerMove(e) { - if (e.buttons !== 1) return - setPoints([...points, [e.pageX, e.pageY, e.pressure]]) - } - - const stroke = getStroke(points, { - size: 16, - thinning: 0.5, - smoothing: 0.5, - streamline: 0.5, - }) - - const pathData = getSvgPathFromStroke(stroke) - - return ( - - {points && } - + }) ) -} -``` - -[![Edit perfect-freehand-example](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/perfect-freehand-example-biwyi?fontsize=14&hidenavigation=1&theme=dark) - -### Advanced Usage - -For advanced usage, the library also exports smaller functions that `getStroke` uses to generate its outline points. - -#### `getStrokePoints` - -A function that accepts an array of points (formatted either as `[x, y, pressure]` or `{ x: number, y: number, pressure: number}`) and (optionally) an options object. Returns a set of adjusted points as `{ point, pressure, vector, distance, runningLength }`. The path's total length will be the `runningLength` of the last point in the array. - -```js -import { getStrokePoints } from 'perfect-freehand' -import samplePoints from "./samplePoints.json' - -const strokePoints = getStrokePoints(samplePoints) -``` - -#### `getOutlinePoints` -A function that accepts an array of points (formatted as `{ point, pressure, vector, distance, runningLength }`, i.e. the output of `getStrokePoints`) and (optionally) an options object, and returns an array of points (`[x, y]`) defining the outline of a pressure-sensitive stroke. - -```js -import { getStrokePoints, getOutlinePoints } from 'perfect-freehand' -import samplePoints from "./samplePoints.json' - -const strokePoints = getStrokePoints(samplePoints) - -const outlinePoints = getOutlinePoints(strokePoints) -``` - -**Note:** Internally, the `getStroke` function passes the result of `getStrokePoints` to `getStrokeOutlinePoints`, just as shown in this example. This means that, in this example, the result of `myOutlinePoints` will be the same as if the `samplePoints` array had been passed to `getStroke`. - -#### `StrokeOptions` - -A TypeScript type for the options object. Useful if you're defining your options outside of the `getStroke` function. - -```ts -import { StrokeOptions, getStroke } from 'perfect-freehand' - -const options: StrokeOptions = { - size: 16, + return d.join(' ') } - -const stroke = getStroke(options) ``` ## Support diff --git a/icons.png b/icons.png new file mode 100644 index 0000000..9122f0a Binary files /dev/null and b/icons.png differ diff --git a/packages/perfect-freehand/README.md b/packages/perfect-freehand/README.md index e43eadc..e4db6b7 100644 --- a/packages/perfect-freehand/README.md +++ b/packages/perfect-freehand/README.md @@ -4,12 +4,15 @@ Draw perfect pressure-sensitive freehand lines. 🔗 Try out a [demo](https://perfect-freehand-example.vercel.app/). +🕊 Flutter dev? Check out the [dart version](https://pub.dev/packages/perfect_freehand) of this library. + 💰 Using this library in a commercial product? Consider [becoming a sponsor](https://github.com/sponsors/steveruizok?frequency=recurring&sponsor=steveruizok). ## Table of Contents - [Installation](#installation) - [Usage](#usage) +- [Documentation](#documentation) - [Support](#support) - [Discussion](#discussion) - [Author](#author) @@ -26,33 +29,125 @@ or yarn add perfect-freehand ``` -## Usage +## Introduction + +This package exports a function named `getStroke` that will generate the points for a polygon based on an array of points. + +![Screenshot](process.gif "A GIF showing a stroke's input points, outline points, and a curved path connecting these points") -This package exports a function named `getStroke` that: +To do this work, `getStroke` first creates a set of spline points (red) based on the input points (grey) and then creates outline points (blue). You can render the result any way you like, using whichever technology you prefer. -- accepts an array of points and an (optional) options object -- returns a stroke outline as an array of points formatted as `[x, y]` +[![Edit perfect-freehand-example](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/perfect-freehand-example-biwyi?fontsize=14&hidenavigation=1&theme=dark) + +## Usage + +To use this library, import the `getStroke` function and pass it an array of **input points**, such as those recorded from a user's mouse movement. The `getStroke` function will return a new array of **outline points**. These outline points will form a polygon (called a "stroke") that surrounds the input points. ```js import { getStroke } from 'perfect-freehand' + +const inputPoints = [ + [0, 0], + [10, 5], + [20, 8], + // ... +] + +const outlinePoints = getStroke(inputPoints) ``` -You may format your input points as array _or_ an object. In both cases, the value for pressure is optional (it will default to `.5`). +You then can **render** your stroke points using your technology of choice. See the [Rendering](#rendering) section for examples in SVG and HTML Canvas. + +You can **customize** the appearance of the stroke shape by passing `getStroke` a second parameter: an options object containing one or more options. See the [Options](#options) section for a full list of available options. ```js -getStroke([ - [0, 0, 0], - [10, 5, 0.5], - [20, 8, 0.3], -]) - -getStroke([ - { x: 0, y: 0, pressure: 0 }, - { x: 10, y: 5, pressure: 0.5 }, - { x: 20, y: 8, pressure: 0.3 }, -]) +const stroke = getStroke(myPoints, { + size: 32, + thinning: 0.7, +}) ``` +The appearance of a stroke is effected by the **pressure** associated with each input point. By default, the `getStroke` function will simulate pressure based on the distance between input points. + +To use **real pressure**, such as that from a pen or stylus, provide the pressure as the third number for each input point, and set the `simulatePressure` option to `false`. + +```js +const inputPoints = [ + [0, 0, 0.5], + [10, 5, 0.7], + [20, 8, 0.8], + // ... +] + +const outlinePoints = getStroke(inputPoints, { + simulatePressure: false, +}) +``` + +In addition to providing points as an array of arrays, you may also provide your points as an **array of objects** as show in the example below. In both cases, the value for pressure is optional (it will default to `.5`). + +```js +const inputPoints = [ + { x: 0, y: 0, pressure: 0.5 }, + { x: 10, y: 5, pressure: 0.7 }, + { x: 20, y: 8, pressure: 0.8 }, + // ... +] + +const outlinePoints = getStroke(inputPoints, { + simulatePressure: false, +}) +``` + +**Note:** Internally, the `getStroke` function will convert your object points to array points, which will have an effect on performance. If you're using this library ambitiously and want to format your points as objects, consider modifying this library's `getStrokeOutlinePoints` to use the object syntax instead (e.g. replacing all `[0]` with `.x`, `[1]` with `.y`, and `[2]` with `.pressure`). + +## Example + +```jsx +import * as React from 'react' +import { getStroke } from 'perfect-freehand' +import { getSvgPathFromStroke } from './utils' + +export default function Example() { + const [points, setPoints] = React.useState([]) + + function handlePointerDown(e) { + e.target.setPointerCapture(e.pointerId) + setPoints([[e.pageX, e.pageY, e.pressure]]) + } + + function handlePointerMove(e) { + if (e.buttons !== 1) return + setPoints([...points, [e.pageX, e.pageY, e.pressure]]) + } + + const stroke = getStroke(points, { + size: 16, + thinning: 0.5, + smoothing: 0.5, + streamline: 0.5, + }) + + const pathData = getSvgPathFromStroke(stroke) + + return ( + + {points && } + + ) +} +``` + +> **Tip:** For implementations in Typescript, see the example project included in this repository. + +[![Edit perfect-freehand-example](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/perfect-freehand-example-biwyi?fontsize=14&hidenavigation=1&theme=dark) + +## Documentation + ### Options The options object is optional, as are each of its properties. @@ -107,6 +202,58 @@ getStroke(myPoints, { > **Tip:** To create a stroke that gets thinner with pressure instead of thicker, use a negative number for the `thinning` option. +### Other Exports + +For advanced usage, the library also exports smaller functions that `getStroke` uses to generate its outline points. + +#### `getStrokePoints` + +A function that accepts an array of points (formatted either as `[x, y, pressure]` or `{ x: number, y: number, pressure: number}`) and (optionally) an options object. Returns a set of adjusted points as `{ point, pressure, vector, distance, runningLength }`. The path's total length will be the `runningLength` of the last point in the array. + +```js +import { getStrokePoints } from 'perfect-freehand' +import samplePoints from "./samplePoints.json' + +const strokePoints = getStrokePoints(samplePoints) +``` + +#### `getOutlinePoints` + +A function that accepts an array of points (formatted as `{ point, pressure, vector, distance, runningLength }`, i.e. the output of `getStrokePoints`) and (optionally) an options object, and returns an array of points (`[x, y]`) defining the outline of a pressure-sensitive stroke. + +```js +import { getStrokePoints, getOutlinePoints } from 'perfect-freehand' +import samplePoints from "./samplePoints.json' + +const strokePoints = getStrokePoints(samplePoints) + +const outlinePoints = getOutlinePoints(strokePoints) +``` + +**Note:** Internally, the `getStroke` function passes the result of `getStrokePoints` to `getStrokeOutlinePoints`, just as shown in this example. This means that, in this example, the result of `myOutlinePoints` will be the same as if the `samplePoints` array had been passed to `getStroke`. + +#### `StrokeOptions` + +A TypeScript type for the options object. Useful if you're defining your options outside of the `getStroke` function. + +```ts +import { StrokeOptions, getStroke } from 'perfect-freehand' + +const options: StrokeOptions = { + size: 16, +} + +const stroke = getStroke(options) +``` + +## Tips & Tricks + +### Freehand Anything + +While this library was designed for rendering the types of input points generated by the movement of a human hand, you can pass any set of points into the library's functions. For example, here's what you get when running [Feather Icons](https://feathericons.com/) through `getStroke`. + +![Icons](icons.png) + ### Rendering While `getStroke` returns an array of points representing the outline of a stroke, it's up to you to decide how you will render these points. @@ -131,23 +278,21 @@ function getSvgPathFromStroke(stroke) { } ``` -To use this function, first use perfect-freehand to turn your input points into a stroke outline, then pass the result to `getSvgPathFromStroke`. +To use this function, first run your input points through `getStroke`, then pass the result to `getSvgPathFromStroke`. ```js -import { getStroke } from 'perfect-freehand' - -const myStroke = getStroke(myInputPoints) +const outlinePoints = getStroke(inputPoints) -const pathData = getSvgPathFromStroke(myStroke) +const pathData = getSvgPathFromStroke(outlinePoints) ``` -You could then pass this string either to an [SVG path](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d) element: +You could then pass this string of SVG path data either to an [SVG path](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d) element: ```jsx ``` -Or, if you are rendering with HTML Canvas, you can pass the result to a [`Path2D` constructor](https://developer.mozilla.org/en-US/docs/Web/API/Path2D/Path2D#using_svg_paths)). +Or, if you are rendering with HTML Canvas, you can pass the string to a [`Path2D` constructor](https://developer.mozilla.org/en-US/docs/Web/API/Path2D/Path2D#using_svg_paths)). ```js const myPath = new Path2D(pathData) @@ -157,110 +302,24 @@ ctx.fill(myPath) ### Flattening -To render a stroke as a "flattened" polygon, add the [`polygon-clipping`](https://github.com/mfogel/polygon-clipping) package and use the following function together with the `getSvgPathFromStroke`. +By default, the polygon's paths include self-crossings. You may wish to remove these crossings and render a stroke as a "flattened" polygon. To do this, install the [`polygon-clipping`](https://github.com/mfogel/polygon-clipping) package and use the following function together with the `getSvgPathFromStroke`. ```js import polygonClipping from 'polygon-clipping' function getFlatSvgPathFromStroke(stroke) { - const poly = polygonClipping.union([stroke]) + const faces = polygonClipping.union([stroke]) const d = [] - for (let face of poly) { - for (let points of face) { + faces.forEach((face) => + face.forEach((points) => { d.push(getSvgPathFromStroke(points)) - } - } - - return d.join(' ') -} -``` - -> **Tip:** For implementations in Typescript, see the example project included in this repository. - -### Example - -```jsx -import * as React from 'react' -import { getStroke } from 'perfect-freehand' -import { getSvgPathFromStroke } from './utils' - -export default function Example() { - const [points, setPoints] = React.useState([]) - - function handlePointerDown(e) { - e.target.setPointerCapture(e.pointerId) - setPoints([[e.pageX, e.pageY, e.pressure]]) - } - - function handlePointerMove(e) { - if (e.buttons !== 1) return - setPoints([...points, [e.pageX, e.pageY, e.pressure]]) - } - - const stroke = getStroke(points, { - size: 16, - thinning: 0.5, - smoothing: 0.5, - streamline: 0.5, - }) - - const pathData = getSvgPathFromStroke(stroke) - - return ( - - {points && } - + }) ) -} -``` -[![Edit perfect-freehand-example](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/perfect-freehand-example-biwyi?fontsize=14&hidenavigation=1&theme=dark) - -### Advanced Usage - -For advanced usage, the library also exports smaller functions that `getStroke` uses to generate its SVG data. While you can use `getStroke`'s data to render strokes with an HTML canvas (via the Path2D element) or with SVG paths, these new functions will allow you to create paths in other rendering technologies. - -#### `getStrokePoints` - -A function that accepts an array of points (formatted either as `[x, y, pressure]` or `{ x: number, y: number, pressure: number}`) and a streamline value. Returns a set of adjusted points as `{ point, pressure, vector, distance, runningLength }`. The path's total length will be the `runningLength` of the last point in the array. - -```js -import { getStrokePoints } from 'perfect-freehand' -import samplePoints from "./samplePoints.json' - -const strokePoints = getStrokePoints(samplePoints) -``` - -#### `getOutlinePoints` - -A function that accepts an array of points (formatted as `{ point, pressure, vector, distance, runningLength }`, i.e. the output of `getStrokePoints`) and returns an array of points (`[x, y]`) defining the outline of a pressure-sensitive stroke. - -```js -import { getStrokePoints, getOutlinePoints } from 'perfect-freehand' -import samplePoints from "./samplePoints.json' - -const strokePoints = getStrokePoints(samplePoints) -const outlinePoints = getOutlinePoints(strokePoints) -``` - -#### `StrokeOptions` - -A TypeScript type for the options object. Useful if you're defining your options outside of the `getStroke` function. - -```ts -import { StrokeOptions, getStroke } from 'perfect-freehand' - -const options: StrokeOptions = { - size: 16, + return d.join(' ') } - -const stroke = getStroke(options) ``` ## Support diff --git a/packages/perfect-freehand/src/getStrokeOutlinePoints.ts b/packages/perfect-freehand/src/getStrokeOutlinePoints.ts index ef648b1..12aec43 100644 --- a/packages/perfect-freehand/src/getStrokeOutlinePoints.ts +++ b/packages/perfect-freehand/src/getStrokeOutlinePoints.ts @@ -2,11 +2,8 @@ import { getStrokeRadius } from './getStrokeRadius' import type { StrokeOptions, StrokePoint } from './types' import { add, - dist, dist2, - div, dpr, - isEqual, lrp, med, mul, diff --git a/packages/perfect-freehand/src/icons.png b/packages/perfect-freehand/src/icons.png new file mode 100644 index 0000000..9122f0a Binary files /dev/null and b/packages/perfect-freehand/src/icons.png differ diff --git a/packages/perfect-freehand/src/process.gif b/packages/perfect-freehand/src/process.gif new file mode 100644 index 0000000..93759e5 Binary files /dev/null and b/packages/perfect-freehand/src/process.gif differ diff --git a/process.gif b/process.gif new file mode 100644 index 0000000..93759e5 Binary files /dev/null and b/process.gif differ diff --git a/tutorial/script.md b/tutorial/script.md index 3d5cbae..2495f6e 100644 --- a/tutorial/script.md +++ b/tutorial/script.md @@ -1,6 +1,6 @@ # Perfect Freehand Tutorial (Script) -`WIP` +`WIP, for a Tutorial Video` [Starter File](https://stackblitz.com/edit/js-vtm7xh) [Easing Functions](https://gist.github.com/steveruizok/c331cd1fb30563aec51f7223e25d0afd)