The Swiss Army Knife of Vector Graphics Scripting – Scriptographer ported to JavaScript and the browser, using HTML5 Canvas. Created by @lehni & @puckey


Paper.js - The Swiss Army Knife of Vector Graphics Scripting Build Status NPM

If you want to work with Paper.js, simply download the latest "stable" version from

Installing Paper.js

The recommended way to install and maintain Paper.js as a dependency in your project is through the Node.js Package Manager (NPM) for browsers, Node.js or Electron.

If NPM is already installed, simply type one of these commands in your project folder:

npm install paper

Upon execution, you will find a paper folder inside the project's node_modules folder.

For more information on how to install Node.js and NPM, read the chapter Installing Node.js and NPM.

Which Version to Use

The various distributions come with two different pre-build versions of Paper.js, in minified and normal variants:

  • paper-full.js – The full version for the browser, including PaperScript support and Acorn.js
  • paper-core.js – The core version for the browser, without PaperScript support nor Acorn.js. You can use this to shave off some bytes and compilation time when working with JavaScript directly.

Installing Node.js and NPM

Node.js comes with the Node Package Manager (NPM). There are many tutorials explaining the different ways to install Node.js on different platforms. It is generally not recommended to install Node.js through OS-supplied package managers, as the its development cycles move fast and these versions are often out-of-date.

On macOS, Homebrew is a good option if one version of Node.js that is kept up to date with brew upgrade is enough:

NVM can be used instead to install and maintain multiple versions of Node.js on the same platform, as often required by different projects:

Homebrew is recommended on macOS also if you intend to install Paper.js with rendering to the Canvas on Node.js, as described in the next paragraph.

For Linux, see to locate 32-bit and 64-bit Node.js binaries as well as sources, or use NVM, as described in the paragraph above.

Installing Paper.js Using NPM

Paper.js comes in three different versions on NPM: paper, paper-jsdom and paper-jsdom-canvas. Depending on your use case, you need to required a different one:

  • paper is the main library, and can be used directly in a browser context, e.g. a web browser or worker.
  • paper-jsdom is a shim module for Node.js, offering headless use with SVG importing and exporting through jsdom.
  • paper-jsdom-canvas is a shim module for Node.js, offering canvas rendering through Node-Canvas as well as SVG importing and exporting through jsdom.

In order to install paper-jsdom-canvas, you need the Cairo Graphics library installed in your system:

Installing Native Dependencies

Paper.js relies on Node-Canvas for rendering, which in turn relies on the native libraries Cairo and Pango.

Installing Native Dependencies on macOS

Paper.js relies on Node-Canvas for rendering, which in turn relies on Cairo and Pango. The easiest way to install Cairo is through Homebrew, by issuing the command:

brew install cairo pango

Note that currently there is an issue on macOS with Cairo. If the above causes errors, the following will most likely fix it:

PKG_CONFIG_PATH=/opt/X11/lib/pkgconfig/ npm install paper

Also, whenever you would like to update the modules, you will need to execute:

PKG_CONFIG_PATH=/opt/X11/lib/pkgconfig/ npm update

If you keep forgetting about this requirement, or would like to be able to type simple and clean commands, add this to your .bash_profile file:

# PKG Config for Pango / Cairo
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:/opt/X11/lib/pkgconfig

After adding this line, your commands should work in the expected way:

npm install paper
npm update

Installing Native Dependencies on Debian/Ubuntu Linux

sudo apt-get install pkg-config libcairo2-dev libpango1.0-dev libssl-dev libjpeg62-dev libgif-dev

You might also need to install the build-essential package if you don't usually build from c++ sources:

sudo apt-get install build-essential

Installing Native Dependencies for Electron

In order to build Node-Canvas for use of paper-jsdom-canvas in Electron, which is likely to use a different version of V8 than the Node binary installed in your system, you need to manually specify the location of Electron’s headers. Follow these steps to do so:

Electron — Using Native Node Modules

After Native Dependencies have been installed

You should now be able to install the Paper.js module with jsdom and Canvas rendering from NPM:

npm install paper-jsdom-canvas


The main Paper.js source tree is hosted on GitHub. git is required to create a clone of the repository, and can be easily installed through your preferred package manager on your platform.

Get the Source

git clone --recursive git://
cd paper.js

To refresh your clone and fetch changes from origin, run:

git fetch origin

To update the jsdoc-toolkit submodule, used to generate the documentation, run:

git submodule update  --init --recursive

Setting Up For Building

Paper.js uses Gulp.js for building, and has a couple of dependencies as NPM modules. Read the chapter Installing Node.js and NPM if you still need to install these.

Due to a conflict in Gulp 3 that could only be resolved using package resolution, we recently switched from NPM to yarn for development, which also needs to be installed now. See Installing Yarn for details.

In order to be able to build Paper.js, after checking out the repository, paper has dependencies that need to be installed. Install them by issuing the following commands from the Paper.js directory:

yarn install

Building the Library

The Paper.js sources are distributed across many separate files, organised in subfolders inside the src folder. To compile them all into distributable files, you can run the build task:

yarn build

You will then find the built library files inside the dist folder, named paper-full.js and paper-core.js, along with their minified versions. Read more about this in Which Version to Use?.

Running Directly from Separate Source Files

As a handy alternative to building the library after each change to try it out in your scripts, there is the load task, that replaces the built libraries with symbolic links to the scrc/load.js script. This script then load the library directly from all the separate source files in the src folder, through the Prepro.js JavaScript preprocessing library.

This means you can switch between loading from sources and loading a built library simply by running.

yarn load

And to go back to a built library

yarn build

Note that your PaperScripts examples do not need to change, they can keep loading dist/paper-full.js, which will always do the right thing. Note also that src/load.js handles both browsers and Node.js, as supported by Prepro.js.

Other Build Tasks

Create a final zipped distribution file inside the dist folder:

yarn dist

Branch structure

Since the release of version 0.9.22, Paper.js has adopted aspects of the Git- Flow workflow. All development is taking place in the develop branch, which is only merged into master when a new release occurs.

As of version 0.9.26, the dist folder is excluded on all branches, and the building is now part of the yarn publish process by way of the prepublish script.

We also offer prebuilt versions of the latest state of the develop branch on prebuilt/module and prebuilt/dist.

Building the Documentation

Similarly to building the library, you can run the docs task to build the documentation:

yarn docs

Your docs will then be located at dist/docs.


Paper.js was developed and tested from day 1 using proper unit testing through jQuery's Qunit. To run the tests after any change to the library's source, simply open index.html inside the test folder in your web browser. There should be a green bar at the top, meaning all tests have passed. If the bar is red, some tests have not passed. These will be highlighted and become visible when scrolling down.

If you are testing on Chrome, some of the tests will fail due to the browser's CORS restrictions. In order to run the browser based tests on Chrome, you need to run a local web-server through Gulp.js. The following command will handle it for you, and will also open the browser at the right address straight away:

yarn test:browser

You can also run the unit tests through PhantomJS in Gulp directly on the command line:

yarn test:phantom

To test the Node.js version of Paper.js, use this command:

yarn test:node

And to test both the PhantomJS and Node.js environments together, simply run:

yarn test

Contributing Open Source Helpers

The main Paper.js source tree is hosted on GitHub, thus you should create a fork of the repository in which you perform development. See

We prefer that you send a pull request on GitHub which will then be merged into the official main line repository. You need to sign the Paper.js CLA to be able to contribute (see below).

Also, in your first contribution, add yourself to the end of (which of course is optional).

In addition to contributing code you can also triage issues which may include reproducing bug reports or asking for vital information, such as version numbers or reproduction instructions. If you would like to start triaging issues, one easy way to get started is to subscribe to paper.js on CodeTriage.

Get the source (for contributing):

If you want to contribute to the project you will have to make a fork. Then do this:

git clone --recursive [email protected]:yourusername/paper.js.git
cd paper.js
git remote add upstream git://

To then fetch changes from upstream, run

git fetch upstream

Creating and Submitting a Patch

As mentioned above, we prefer that you send a pull request on GitHub:

  1. Create a fork of the upstream repository by visiting If you feel insecure, here's a great guide:

  2. Clone of your repository: git clone https://[email protected]/yourusername/paper.js.git

  3. This is important: Create a so-called topic branch based on the develop branch: git checkout -tb name-of-my-patch develop where name-of-my-patch is a short but descriptive name of the patch you're about to create. Don't worry about the perfect name though -- you can change this name at any time later on.

  4. Hack! Make your changes, additions, etc., commit them then push them to your GitHub fork: git push origin name-of-my-patch

  5. Send a pull request to the upstream repository's owner by visiting your repository's site at GitHub (i.e. and press the "Pull Request" button. Make sure you are creating the pull request to the develop branch, not the master branch. Here's a good guide on pull requests:

Use one topic branch per feature:

Don't mix different kinds of patches in the same branch. Instead, merge them all together into your develop branch (or develop everything in your develop branch and then cherry-pick-and-merge into the different topic branches). Git provides for an extremely flexible workflow, which in many ways causes more confusion than it helps you when new to collaborative software development. The guides provided by GitHub at are a really good starting point and reference. If you are fixing an issue, a convenient way to name the branch is to use the issue number as a prefix, like this: git checkout -tb issue-937-feature-add-text-styling.

Contributor License Agreement

Before we can accept any contributions to Paper.js, you need to sign this CLA:

Contributor License Agreement

The purpose of this agreement is to clearly define the terms under which intellectual property has been contributed to Paper.js and thereby allow us to defend the project should there be a legal dispute regarding the software at some future time.

For a list of authors and contributors, please see AUTHORS.


Distributed under the MIT license. See LICENSE for details.

  • Boolean Intersections inside overlap ranges need special handling

    Boolean Intersections inside overlap ranges need special handling

    That's why this special case is misbehaving: It has two intersections inside the overlap range, and currently deals with them wrongly:

    var path1 = new Path({
        pathData: "M495.9,1693.5c-42.2-203.5-64.5-304.9-78-299.9 c-1.7,0.6-0.3,6.7,5.3,22.5l209.4-74.8l75.8,303.9L495.9,1693.5z",
        fillColor: 'red'
    var path2 = new Path({
        pathData: "M632.6,1341.2l-209.4,74.9c95.4,267,135.6,201-60.1-144.5l202.9-85.7 L632.6,1341.2z",
        fillColor: 'blue'
    }); = project.activeLayer.position;
    var res = path1.unite(path2);
    res.fillColor = new Color(1, 1, 0, 0.5);
    res.fullySelected = true;
    cat: boolean-operations 
    opened by lehni 225
  • Optimize propagateWinding(), and improve confidence.

    Optimize propagateWinding(), and improve confidence.

    @iconexperience I think we should devote an issue to the attempt to reduce the amount of winding "sampling" per curve. At the moment, it checks three evenly distributed locations along a chain, and then takes the average winding. This is weird and probably also a bit slow due to the call to getWinding(), but has worked well so far for us.

    If I reduce the amount of samples to just one in the middle of the chain, I get only one failing test. But if I increase the samples to 4 or more, I get the exact same test failing. Even with 10 samples, it's the only test that fails. This has me thinking that using a value of 3 is actually hiding another issue in this one test, and we may be better off finding out what that is?

    cat: boolean-operations type: feature 
    opened by lehni 93
  • Fat-line clipping algorithm sometimes finds intersections and wrong parameters.

    Fat-line clipping algorithm sometimes finds intersections and wrong parameters.

    This is probably the reason why example 23 fails in #784: Demo Sketch


    Found 2 intersections:
    Intersection 0:
    Path ID: 1, parameter: 0, point: { x: 628.03547, y: 243.03686 }
    Path ID: 3, parameter: 1, point: { x: 628.03547, y: 243.03686 }
    Intersection 1:
    Path ID: 1, parameter: 5.668521207979893e-13, point: { x: 628.03547, y: 243.03686 }
    Path ID: 3, parameter: 0.9434552849029103, point: { x: 628.035, y: 242.8367 }

    Notice how in the second intersection, the first location on Path 1 is basically the same as in the first intersection, while the location on Path 3 varies. And there is definitely no intersection at parameter 0.9434552849029103 on Path 3!

    @iconexperience let me know if you feel like debugging this one, since you have some experience with the fat-line clipping code. This may well be the source of some of the other failing edge cases too.


    view._matrix = new Matrix([28.421709430404007, 0, 0, 28.421709430404007, -17483.40878872569, -6705.654159277673]);
    var curve1 = new Curve(628.0354673841999, 243.03685701873312, 628.0044262657246, 253.72314203550712, 419.2789142850017, 364.27077547853787, 419.2789142850017, 364.27077547853787);
    var curve2 = new Curve(619.5200435607698, 221.87571045051882, 619.5200435607698, 221.87571045051882, 628.0657700157852, 232.60480515822775, 628.0354673841999, 243.03685701876972);
    function createPath(curve, color) {
        return new Path({
            segments: [curve.segment1, curve.segment2],
            strokeColor: color,
            strokeScaling: false
    function createCircle(inter) {
        var path = inter.path;
        console.log('Path ID: ' +
            + ', parameter: ' + inter.parameter
            + ', point: ' + inter.point);
        return new Path.Circle({
            center: inter.point,
            radius: 0.1,
            strokeColor: path.strokeColor,
            strokeScaling: false
    var path1 = createPath(curve1, 'red');
    var path2 = createPath(curve2, 'blue');
    var intersections = path1.getIntersections(path2);
    console.log('Found ' + intersections.length + ' intersections:');
    intersections.forEach(function(inter, i) {
        console.log('Intersection ' + i + ':');
    cat: boolean-operations cat: curve-intersection 
    opened by lehni 74
  • Problem with multiple paths exclude

    Problem with multiple paths exclude

    Actual result:

    Expected result:

    rectangle 1

    cat: boolean-operations 
    opened by tomashanacek 72
  • Unite operation wrongly fills inner path

    Unite operation wrongly fills inner path

    Here is an example that may be caused by the tracePath() function. The unite operation should result in a path with a rectangular hole, but the hole is filled instead:

    var p1 = new paper.Path({segments:[
         [150, 120], 
         [150, 85], 
         [178, 85],
         [178, 110], 
         [315, 110], 
         [315, 85], 
         [342, 85],
         [342, 120],
         ], closed:true})
    var p2 = new paper.Path({segments:[
        [350, 60],
        [350, 125],
        [315, 125],
        [315, 85],
        [178, 85], 
        [178, 125], 
        [140, 125], 
        [140, 60]
        ], closed:true})
    var r = p1.unite(p2);
    r.fillColor = new Color(1, 1, 0, .2);
    p2.strokeColor = "red";
    p1.strokeColor = "green";

    Here is the sketch

    Expected result: image

    Actual result: image

    cat: boolean-operations type: bug 
    opened by iconexperience 71
  • Optimize boolean operations when there are no crossings.

    Optimize boolean operations when there are no crossings.

    When there are no crossings, the result can already be known ahead of tracePaths(), probably leading to a massive speed-up:

    • intersect: return null
    • unite: return a compound path with both operands
    • subtract: return the first operand
    • exclude: same as unite.
    • divide: no change needed, since it redirects to the other methods.
    cat: boolean-operations type: improvement 
    opened by lehni 66
  • Subtract operation fails

    Subtract operation fails

    Here is another bug where the subtraction fails. An error message is generated and the result of the operation is not correct. This bug is very similar to #889 , but it is not fixed by d89995a

    var p1 = new CompoundPath();
    p1.addChild(new Path({segments:[
        [676, 396.8],
        [445.78, 396.8],
        [426, 260]
    ], closed:true}));
    p1.addChild(new Path({segments:[
        [672, 550.4, 0, 0, 31.74000000000001, 0],
        [633.5999999999999, 732.8, 0, 26.519999999999982]
    ], closed:true}));
    var p2 = new Path({segments:[
        [732, 418, 0, 0, 0, 52.45802606694065],
        [676.3444534355956, 552.3444534355972, 34.385686865893945, -34.38568686589349],
        [630, 704],
        [400, 704],
        [542, 228]
    ], closed:true});
    var res = p1.subtract(p2);
    p1.strokeColor = "red";
    p2.strokeColor = "green";
    res.fullySelected = true;

    Here is the Sketch

    cat: boolean-operations 
    opened by iconexperience 64
  • Unable to install v0.12.11

    Unable to install v0.12.11

    Description/Steps to reproduce

    On install of [email protected] I get this error message when trying to install with PowerShell on Windows:

    Command: [[ $npm_config_heading == 'npm' ]] && npx npm-force-resolutions || true
    Directory: C:\Users\Nathan\Documents\project\node_modules\paper
    '[[' is not recognized as an internal or external command,
    operable program or batch file.
    'true' is not recognized as an internal or external command,
    operable program or batch file.

    Link to reproduction test-case

    Expected result

    Successful installation.

    Additional information

    Windows 10 Pro 18363.900 yarn v1.22.4 PowerShell 5.1.18362.752

    type: bug pri: critical cat: install 
    opened by Methuselah96 63
  • New #resolveCrossing() does not handle 'nonzero' fill-rule properly.

    New #resolveCrossing() does not handle 'nonzero' fill-rule properly.


    var data = "M356.6,301.2L356.6,336Q356.6,343.2,353,351.4Q349.4,359.6,341.8,366.6Q334.2,373.6,322.2,378.2Q310.2,382.8,293.4,382.8Q285.8,382.8,278.4,381.2Q271,379.6,265.6,376Q260.2,372.4,256.8,366.6Q253.4,360.8,253.4,352.4Q253.4,339.6,259.2,332.2Q265,324.8,274.2,320.8Q283.4,316.8,295,315Q306.6,313.2,318,311.8Q329.4,310.4,339.8,308.2Q350.2,306,356.6,301.2Z M313,196.4Q295.8,196.4,280.2,200Q264.6,203.6,252.6,211.8Q240.6,220,233.4,233.2Q226.2,246.4,225.4,265.6L259.4,265.6Q260.6,242.8,275,234.6Q289.4,226.4,311,226.4Q319,226.4,327.2,227.6Q335.4,228.8,342,232.4Q348.6,236,352.8,242.8Q357,249.6,357,260.8Q357,270.4,351.4,275.4Q345.8,280.4,336.2,283Q326.6,285.6,314,287Q301.4,288.4,287.4,291.2Q274.2,293.6,261.6,297.2Q249,300.8,239.2,307.8Q229.4,314.8,223.4,326Q217.4,337.2,217.4,354.8Q217.4,370.4,222.8,381.4Q228.2,392.4,237.6,399.4Q247,406.4,259.4,409.4Q271.8,412.4,285.8,412.4Q307.4,412.4,326,405Q344.6,397.6,358.6,380.8Q358.6,397.6,366.4,405Q374.2,412.4,387.4,412.4Q403,412.4,411.8,407.2L411.8,380.8Q405.8,382.8,401.4,382.8Q393.4,382.8,392,377.2Q390.6,371.6,390.6,359.6L390.6,253.2Q390.6,235.2,383.8,224Q377,212.8,365.8,206.6Q354.6,200.4,340.8,198.4Q327,196.4,313,196.4Z";
    var path1 = new CompoundPath(data);
    path1.fillColor = 'red';


    screen shot 2015-12-27 at 23 22 00 cat: boolean-operations 
    opened by lehni 59
  • Improve and CurveLocation.equals() to respect circular nature of closed path

    Improve and CurveLocation.equals() to respect circular nature of closed path

    The functions CurveLocation.equals() are implemented for using sorting and binary searching of curve locations. This usually works well, but it will fail if one location is at the end of the last curve in the path and the other one is at the beginning of the first path, because they do not respect the circular nature of paths.

    Search can be improved by comparing agains the first/last element when we reach the end/beginning.

    One case where this problem occurs is this:

    var path1 = new Path({segments:[
    [255.25224104545694, 206.56224024492892, 0, 0, 16.68595677007133, 1.8409632269558927],
    [277.79318931146304, 219.9760029310676, 3.7208630240332923, 4.838358092973152, 0, 0],
    [252.76462261689747, 239.22382762052413, 0, 0, 0, 0]
    ], closed:true});
    var path2 = new Path({segments:[
    [277.7931893114634, 219.97600293106805, 0, 0, 0.7613133898479418, 0.9899603337364908],
    [272.37296700852835, 216.3030317897695, 3.9784444252700837, 1.5352586995409467, 0, 0],
    [260, 230, 0, 0, 0, 0]
    ], closed:true});
    window.reportIntersections = false;
    var result = path1.unite(path2);

    Here is the output from the example:

    Intersection 6 id 5 i 0 t 0.9874834926032252 o false p { x: 277.9266687620355, y: 220.1477641676552 } Other 7 id 7 i 0 t 0.6435479647840718 o false p { x: 277.9266687620355, y: 220.1477641676553 }
    Intersection 4 id 5 i 1 t 0 o false p { x: 277.7931893114631, y: 219.9760029310676 } Other 5 id 7 i 0 t 0 o false p { x: 277.7931893114634, y: 219.9760029310681 }
    Intersection 10 id 5 i 1 t 0 o false p { x: 277.7931893114631, y: 219.9760029310676 } Other 11 id 7 i 1 t 0.9999971256286861 o false p { x: 277.7931893114631, y: 219.9760029310683 }
    Intersection 14 id 5 i 1 t 0.012819003417486376 o false p { x: 277.7809561606656, y: 219.9854106428564 } Other 15 id 7 i 0 t 0.9975534217978637 o false p { x: 277.7809561606656, y: 219.9854106428571 }

    Intersections 4 and 10 are identical, but their "counter" intersections 5 and 7 have different curves and are at different ends of the curve. But since intersections 5 and 7 are actually very close together, comparing them through the equals() function returns true.

    The problem is that does not respect the circular nature of the intersections on a path. Intersection 4 is found first and it is added to the array of intersections, because no equal intersection is found. This is correct so far. But when intersection 10 is added to the array of intersections, the binary search faild to compared it to intersection 4, so it gets added, too, although an equal intersection already exists.

    cat: boolean-operations cat: curve-intersection 
    opened by iconexperience 57
  • Zones and intersection

    Zones and intersection


    Good afternoon!

    I need to draw three polygons - outer and two inner ones. They can be edited.

    All three polygons form zones. I marked them - 1, 2, 3.

    I need to be able to switch between zones and look for the intersection of each of the zones with a moving point, for example, the mouse cursor.

    Can you please tell me if your library will help me?

    opened by svk-man 1
  • how does generateBezier work

    how does generateBezier work

    Can anyone explain to me the logic of the generateBezier function? This is inside PathFitter.js Sorry for putting this in the Issues section, but no one responded on the Gitter.


    opened by sickopickle 0
  • Custom Font Not Shown in PaperJS view.draw() Render (until Resize)

    Custom Font Not Shown in PaperJS view.draw() Render (until Resize)


    Here, PaperJS is being used directly in JS, using view.draw().

    When drawing with a custom font, the font initially does not take effect (especially in Chrome, Edge). I tried adding an empty/dummy font in an earlier DIV which references the font and that also didn't help.

    Resizing the window in any way does show the custom font (e.g., double-clicking the title bar in the above fiddle or clicking "Run" after the initial render).

    opened by eugeneborodkin2 0
  • Pass props to Path constructor in createPath

    Pass props to Path constructor in createPath


    Described in #2012.

    Related issues

    • Relates to issue #2012
    • Relates to PR #1988


    • [ ] New tests added or existing tests modified to cover all changes
    • [x] Code conforms with the JSHint rules (yarn run jshint passes)
    opened by HriBB 0
  • Props are not passed down to Path constructor

    Props are not passed down to Path constructor

    This is bug report - a continuation of #1988.

    Description/Steps to reproduce

    It's hard to reproduce, so I will try to explain.

    Problem is the createPath function in src/path/Path.Constructors.js

    function createPath(segments, closed, args) {
        var props = Base.getNamed(args),
            path = new Path(props && ( // <---- THIS SHOULD BE new Path(props)
                props.insert == true ? Item.INSERT
                : props.insert == false ? Item.NO_INSERT
                : null
        // No need to use setter for _closed since _add() called _changed().
        path._closed = closed;
        // Set named arguments at the end, since some depend on geometry to be
        // defined (e.g. #clockwise)
        return path.set(props, Item.INSERT);

    I am hitting this because I have insertItems set to false in my PaperScope.settings. Then I am applying project in my renderer

    createInstance: (type: Type, instanceProps: Props, scope: Container) => {
      const props: Props = { ...instanceProps, project: scope.project }
      let instance: Instance
      switch (type) {
        case Item.View:
          instance = scope.view
          instance.project = scope.project
        case Item.Layer:
          instance = new scope.Layer(props)
        case Item.Group:
          instance = new scope.Group(props)
        case Item.Path:
          instance = new scope.Path(props)
        case Item.Circle:
          instance = new scope.Path.Circle(props)

    But props are never passed down to Item._initialize and my code throws an Error.

    Link to reproduction test-case

    Unfortunately I don't have a reproduction test case available ATM, but I can make a PR ;)

    Expected result

    props are correctly passed down.

    Additional information

    PaperJS version 0.12.15



    As you can see in the image below, both props and project are null.


    opened by HriBB 0
  • Allow paper to be required in node REPL

    Allow paper to be required in node REPL

    Attempting to require paper outside of a file context (i.e the node command line repl) leads to an error loading the path because parent.filename is undefined.

    TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received null
        at __node_internal_captureLargerStackTrace (node:internal/errors:477:5)
        at new NodeError (node:internal/errors:387:5)
        at validateString (node:internal/validators:115:11)
        at Object.dirname (node:path:1276:5)
        at Object.<anonymous> (/.../node_modules/paper/dist/node/self.js:22:48)

    This adds a short-circuit check which seems to fix the issue.

    opened by akre54 0
  • v0.12.15(Mar 17, 2021)

  • v0.12.13(Mar 16, 2021)

  • v0.12.12(Mar 12, 2021)


    • Fix installation problems on Windows by switching from NPM to yarn for development (#1833).


    • Change Item#raster({ resolution, insert }) to receive options object, while remaining backward compatible.
    • Change Raster#smoothing to support the values 'low', 'medium', 'high' and 'off'. Setting to a boolean value is still supported, translating false'off' and true'low'.


    • Allow reusing of raster items in Item#rasterize({ raster }): By providing an existing raster in options.raster, the raster and maybe even its underlying canvas can be reused, as long as the rasterized size doesn't change between rasterizations. This allows for big performance improvements.
    Source code(tar.gz)
    Source code(zip) MB)
  • v0.12.11(Jun 19, 2020)

  • v0.12.9(Jun 19, 2020)


    • Export CanvasProvider to allow experimenting with on Node.js


    • Fix Path.strokeBounds that was incorrect for certain paths (#1824).
    • Fix Gulp 3 issues to be able to run Travis CI tests on Node.js 10, 12, 13 and 14.
    Source code(tar.gz)
    Source code(zip) MB)
  • v0.12.8(Jun 3, 2020)


    • TypeScript: Fix returned instance type (#1796).
    • Fix Path#strokeBounds for open paths (#1817).
    • Fix animation progress handling in Tween.update().
    • Fix setting Item#scaling to a new value after it was set to zero (#1816).
    • SVG Import: Fully support SVG strings with leading line-breaks (#1813).
    • Docs: Improve Raster#initialize(object) documentation (#1815, #1782).
    • Docs: Fix Item#getItem(options) documentation.
    Source code(tar.gz)
    Source code(zip) MB)
  • v0.12.7(May 23, 2020)

  • v0.12.6(May 23, 2020)

  • v0.12.5(May 23, 2020)


    • PaperScript: Add option options.paperFeatures.operatorOverloading to control operator overloading.


    • Fix new Raster(HTMLCanvasElement) constructor (#1745).
    • Handle CurveLocation on paths with only one segment.
    • Fix recently introduced error in (#1769).
    • Clamp opacity values to [0, 1] (#1814).
    • Support closed Path items with blend mode and no segments (#1763).
    • Fix error in getCrossingSegments() (#1773).
    • SVG Import: Support SVG strings with leading line-breaks (#1813).
    • Docs: Improve documentation for Raster#drawImage(CanvasImageSource) (#1784).


    • Use 'paper-' prefix in generated view ids.
    Source code(tar.gz)
    Source code(zip) MB)
  • v0.12.4(Dec 15, 2019)


    • Allow paper core import in TypeScript (#1713).
    • Boolean: Improve performance from O(n^2) to nearly O(n) by the use of the sweep and prune algorithm (#1737).
    • Docs: Add support for nullable values.


    • Fix PathItem#getCrossing() to not return overlaps (#1409).
    • Fix regression in Curve.getIntersections() (#1638).
    • Fix edge cases in CurveLocation.isCrossing() (#1419, #1263).
    • Fix SymbolItem#hitTestAll() to return only one match per symbol item (#1680).
    • Fix handling of negative Shape sizes (#1733).
    • Fix parsing of RGB Color strings with percentages (#1736).
    • Fix Shape bounds when passing position in constructor (#1686).
    • Prevent nested group matrix from reset when transforming parent (#1711).
    • Boolean: Fix edge cases in overlap detection (#1262).
    • Boolean: Add check for paths with only one segment (#1351).
    • Boolean: Correctly handle open filled paths (#1647).
    • Boolean: Avoid winding number edge cases (#1619).
    • Docs: Fix some documentation return types (#1679).
    Source code(tar.gz)
    Source code(zip) MB)
  • v0.12.3(Jun 22, 2019)


    • Add documentation for Item#internalBounds.


    • Fix regression in Color change propagation (#1672, #1674).
    • SVG Export: Fix viewport size of exported Symbol (#1668).
    • Handle non-invertible matrices in Item#contains() (#1651).
    • Improve documentation for Item#clipMask (#1673).
    • Improve TypeScript definitions (#1659, #1663, #1664, #1667).
    Source code(tar.gz)
    Source code(zip) MB)
  • v0.12.2(Jun 13, 2019)


    • Fix drawing with compound-paths as clip-items (#1361).
    • Fix drawing of path selection with small handle size (#1327).
    • Do not ignore Group#clipItem.matrix in Group#internalBounds (#1427).
    • Correctly calculate bounds with nested empty items (#1467).
    • Fix color change propagation on groups (#1152).
    • Fix Path#arcTo() where from and to points are equal (#1613).
    • Improve new Raster(size[, position]) constructor (#1621).
    • SVG Export: Fix error when Item#matrix is not invertible (#1580).
    • SVG Export: Include missing viewBox attribute (#1576).
    • SVG Import: Use correct default values for gradients (#1632, #1660).
    • SVG Import: Add basic <switch/> support (#1597).
    • JSON Import: Prevent Item#insert() method from being overridden (#1392).
    • PaperScript: Fix issues with increment/decrement operators (#1450, #1611).
    Source code(tar.gz)
    Source code(zip) MB)
  • v0.12.1(Jun 5, 2019)


    • Add TypesScript definition, automatically generated from JSDoc comments (#1612).
    • Support new Raster(size) constructor.
    • Expose Raster#context accessor.
    • Implement Raster#clear() method to clear associated canvas context.
    • Node.js: Add support for Node.js v11 and v12.


    • Fix parsing of CSS colors with spaces in parentheses (#1629).
    • Improve Color.random() documentation.
    • Fix Tween#then() documentation.


    • Node.js: Remove support for Node.js v6.
    Source code(tar.gz)
    Source code(zip) MB)
  • v0.12.0(Dec 3, 2018)


    Another release, another new member on the team: Please welcome @arnoson, who has worked hard on the all new animation support, exposed through the Tween class and its various methods on the Item class, see below for details:


    • Add new Tween class and related methods on Item, to animate and interpolate their various properties, including colors, sub-properties, etc.: Item#tween(from, to, options), Item#tween(to, options), Item#tween(options), Item#tweenFrom(from, options), Item#tweenTo(to, options)


    • Only draw Raster if image is not empty (#1320).
    • Emit mousedrag events on correct items when covered by other items (#1465).
    • Fix drawing issues of bounds and position with Group#selectedColor (#1571).
    • Fix Item.once() to actually only emit event once.
    • Various documentation fixes and improvements (#1399).
    Source code(tar.gz)
    Source code(zip) MB)
  • v0.11.8(Oct 17, 2018)


    This is the first release in quite a while, and it was made possible thanks to two new people on the team:

    A warm welcome to @sasensi and @sapics, the two new and very active maintainers / contributors! :tada:

    Their efforts mean that many issues are finally getting proper attention and solid fixes, as we are paving the way for the upcoming release of 1.0.0. Here the fixes and additions from the past two weeks:


    • Prevent paper object from polluting the global scope (#1544).
    • Make sure Path#arcTo() always passes through the provide through point (#1477).
    • Draw shadows on Raster images (#1437).
    • Fix boolean operation edge case (#1506, #1513, #1515).
    • Handle closed paths with only one segment in Path#flatten() (#1338).
    • Remove memory leak on gradient colors (#1499).
    • Support alpha channel in CSS colors (#1468, #1539, #1565).
    • Improve color CSS string parsing and documentation.
    • Improve caching of item positions (#1503).
    • Always draw selected position in global coordinates system (#1545).
    • Prevent empty Symbol items from causing issues with transformations (#1561).
    • Better detect when a cached global matrix is not valid anymore (#1448).
    • Correctly draw selected position when item is in a group with matrix not applied (#1535).
    • Improve handling of huge amounts of segments in paths (#1493).
    • Do not trigger error messages about passive event listeners on Chrome (#1501).
    • Fix errors with event listeners on mobile (#1533).
    • Prevent first mouse drag event from being emitted twice (#1553).
    • Support optional arguments in translate and rotate statements in SVG Import (#1487).
    • Make sure SVG import always applies imported attributes (#1416).
    • Correctly handle Raster images positions in SVG import (#1328).
    • Improve documentation for Shape#toPath() (#1374).
    • Improve documentation of hit test coordinate system (#1430).
    • Add documentation for Item#locked (#1436).
    • Support Webpack bundling in Node.js server (#1482).
    • Travis CI: Get unit tests to run correctly again.
    • Travis CI: Remove Node 4 and add Node 9.


    • Curve#getTimesWithTangent() and Path#getOffsetsWithTangent() as a way to get the curve-times / offsets where the path is tangential to a given vector.
    • Raster#smoothing to control if pixels should be blurred or repeated when a raster is scaled up (#1521).
    • Allow PaperScriptto export from executed code, supporting export default, named exports, as well as module.exports.
    Source code(tar.gz)
    Source code(zip) MB)
  • v0.11.5(Oct 8, 2017)


    • Fix Curve#isSelected() to correctly reflect the state of #handle1 (#1378).
    • Key Events: Fix auto-filling issue on Chrome (#1358, #1365).
    • Boolean: Check that overlaps are on the right path (#1321).
    • Boolean: Add better filtering for invalid segments (#1385).


    • Node.js: Add JPEG support to exportFrames() (#1166).
    Source code(tar.gz)
    Source code(zip) MB)
  • v0.11.4(Oct 8, 2017)

  • v0.11.3(Apr 23, 2017)


    • Mouse Events: Fix item-based doubleclick events (#1316).

    • Overhaul the caching of bounds and matrix decomposition, improving reliability of Item#rotation and #scaling and fixing situations caused by wrongly caching Item#position and #bounds values.

    • Prevent consumed properties in object literal constructors from being set on the instance.


    • Make all functions and accessors enumerable on all Paper.js classes.
    Source code(tar.gz)
    Source code(zip) MB)
  • v0.11.2(Apr 20, 2017)

  • v0.11.1(Apr 20, 2017)

  • v0.11.0(Apr 19, 2017)


    • Separate paper module on NPM into: paper, paper-jsdom and paper-jsdom-canvas (#1252):
      • paper is the main library, and can be used directly in a browser context, e.g. a web browser or worker.
      • paper-jsdom is a shim module for Node.js, offering headless use with SVG importing and exporting through jsdom.
      • paper-jsdom-canvas is a shim module for Node.js, offering canvas rendering through Node-Canvas as well as SVG importing and exporting through jsdom.


    • PaperScript: Support newer, external versions of Acorn.js for PaperScript parsing, opening the doors to ES 2015 (#1183, #1275).
    • Hit Tests: Implement options.position to hit Item#position (#1249).
    • Split Item#copyTo() into #addTo() and #copyTo().


    • Intersections: Bring back special handling of curve end-points (#1284).
    • Intersections: Correctly handle Item#applyMatrix = false (#1289).
    • Boolean: Bring back on-path winding handling (#1281).
    • Boolean: Pass on options in PathItem#subtract(path, options) (#1221).
    • Boolean: Implement options.trace as a way to perform boolean operations on the strokes / traces instead of the fills / areas of the involved paths (#1221).
    • Boolean: Always return `CompoundPath items (#1221).
    • Style: Fix handling of gradient matrices when Item#applyMatrix = false (#1238).
    • Style: Prevent cleaning pre-existing styles when setting Item#style to an object (#1277).
    • Mouse Events: Only handle dragItem if the hitItem responds to mousedrag events (#1247, #1286).
    • Bounds: Clear parent's bounds cache when item's visibility changes (#1248).
    • Bounds: Fix calculation of internal bounds with children and Item#applyMatrix = false (#1250).
    • Hit-Tests: Fix issue with non-invertible matrices ( #1271).
    • SVG Import: Improve handling of sizes in percent (#1242).
    • Rectangle: Improve handling of dimension properties, dealing better with left / top / right / bottom / center values (#1147).
    • Scene Graph: Do not allow inserting same item as child multiple times.
    • Path: Fix handling of insert = false in new Path.Constructor() initialization (#1305).
    • PaperScript: Fix positive unary operator.
    • Docs: Fix parameter sequence in Matrix constructor (#1273).
    • Docs: Add documentation for options.bound and options.matrix in #exportSVG() (#1254).
    • Docs: Fix wrong @link references to bean properties.
    Source code(tar.gz)
    Source code(zip) MB)
  • v0.10.3(Apr 19, 2017)


    • Node.js: Support v7, and keep testing v4 up to v7 in Travis CI.
    • Node.js: Loosely couple Node.js / Electron code to Canvas module, and treat its absence like a headless web worker context in the browser (#1103).
    • Clean up handling of Item#_set(), #set() and #initialize():
      • Use #_set() for actually setting internal properties, e.g. on Point, Size, so that derived classes can reuse other parts without having to override each individual function (e.g. in SegmentPoint)
      • Define #set() as a shortcut to #initialize() on all basic types, to offer the same amount of flexibility when setting values, accepting object literals as well as lists of value arguments.
    • SVG Export: Add support for shorter h / v commands for horizontal / vertical lines in SVG output.
    • JSON Import / Export: Implement new and shorter segments array notation:
      • Close paths by including true as the last entry
      • Allow nested segment arrays to be passed to PathItem.create() as well as the CompoundPath constructor to create all sub-paths.
    • Reflect View#zoom and View#center through matrix decomposition, and implement additional decomposed properties such as #scaling and #rotation.
    • Reduce various internal epsilon values for general improved precision while maintaining reliability.
    • Split PathItem#resolveCrossings() into #resolveCrossings() and #reorient() (#973).


    • Implement Path#divideAt(location), in analogy to Curve#divideAt(location).
    • Add PathItem#compare() as a way to compare the geometry of two paths to see if they describe the same shape, handling cases where paths start in different segments or use different amounts of curves to describe the same shape.
    • Implement Curve#hasLength() as an optimized check for curve-length (#1109).
    • Implement Curve#classify() to determine the type of cubic Bézier curve via discriminant classification, based on an approach described by Loop and Blinn, and use it to simplify curve self-intersection handling (#773, #1074, #1235).
    • Add Curve.getPeaks() as a fast way to retrieve points that are often similar to the more costly curvature extrema for use in curve offsetting.
    • Expose Curve. getCurveLineIntersections() for use in curve offsetting.
    • Add Line.getDistance() and use it in Curve.getOverlaps() (#1253).
    • Implement Segment#isSmooth() and use it in handling of stroke-joins.
    • Bring back caching of Item#rotation and #scaling, but only allow matrix decomposition-based properties on items with #applyMatrix = false (#1004, #1177).


    • Many improvements to boolean operations:
      • Improve performance of boolean operations when there no actual crossings between the paths, but paths may be contained within each other.
      • Improve path tracing approach by implementing a branching structure and sorting segments according to their reliability as starting points for traces (#1073).
      • Improve calculation and reliability of winding contributions.
      • Improve code that resolves crossings and reorients compound-paths based on how the sub-paths are nested.
      • Fix issue where unite operation wrongly fills inner path (#1075).
      • Better handle cases where one Path is open and the other closed (#1089).
      • Solve null exceptions during complex boolean operations (#1091).
      • Improve bidirectional curve-time rescaling in divideLocations() (#1191).
      • Improve handling of intersections between touching curves (#1165).
      • Improve reliability of Curve#getIntersections() (#1174).
      • Fix getOverlaps() to always return overlaps in correct sequence (#1223).
      • Improve handling of multiple crossings on the same curve.
    • Improve tangent direction handling in CurveLocation#isCrossing(), by finding unambiguous vectors, taking the curve's loop, cusp, inflection, and "peak" points into account (#1073, #1074).
    • Prevent Path#getStrokeBounds(matrix) from accidentally modifying segments (#1102).
    • Improve compatibility with JSPM (#1104).
    • SVG Import: Correctly handle multiple sequential move commands (#1134).
    • SVG Export: Properly handle generated IDs (#1138).
    • SVG Export: Support multiple gradient offsets at 0 (#1241).
    • Fix imprecision in Numerical.findRoot() (#1149).
    • PaperScript: Prevent invalid JavaScript in assignment operators (#1151).
    • Hit Tests: Improve handling of SymbolItem in#hitTestAll() (#1199).
    • Hit Tests: Fix stroke hit-testing for rounded shape items (#1207).
    • Fix matrix cloning for groups with #applyMatrix = false ( #1225).
    • Correctly handle offset in Curve#divideAt(offset) (#1230).
    • Fix issue with Curve#isStraight() where handles were checked incorrectly for collinearity (#1269).
    • Fix Line#getSide() imprecisions when points are on the line.
    • Docs: Fix documentation of Project#hitTestAll() (#536).
    • Docs: Improve description of option.class value in Project#hitTest() (#632).


    • Remove Numerical.TOLERANCE = 1e-6 as there is no internal use for it anymore.
    Source code(tar.gz)
    Source code(zip) MB)
  • v0.10.2(Apr 19, 2017)

  • v0.10.1(Apr 19, 2017)

  • v0.10.0(Apr 19, 2017)


    This is a huge release for Paper.js as we aim for a version 1.0.0 release later this year. As of this version, all notable changes are documented in the change-log following common CHANGELOG conventions. Paper.js now also adheres to Semantic Versioning.

    There are many items in the changelog (and many more items not in the changelog) so here a high-level overview to frame the long list of changes:

    • Boolean operations have been improved and overhauled for reliability and efficiency. These include the path functions to unite, intersect, subtract, exclude, and divide with another path.

    • There was a large amount of work implementing test coverage under QUnit.

    • Mouse and key handling has been re-engineered and extended to work with view. Many outstanding bugs have been fixed with mouse and key handling.

    • Many SVG-handling enhancements and bug-fixes, including handling browser- specific interpretations of the SVG standard, have been added.

    • There are API name changes for more consistency as well as some required by changes in the EcmaScript 6 standard (e.g., SymbolSymbolDefinition).

    • Even though it is not new, since version 0.9.22 Paper.js no longer resizes the canvas to match the view. The canvas must be resized independently.

    Thank you all for using Paper.js, submitting bugs and ideas, and all those that contribute to the code.


    • Significant overhaul and improvements of boolean path operations PathItem#unite(), #subtract(), #intersect(), #exclude(), #divide():
      • Improve handling of self-intersecting paths and non-zero fill-rules.
      • Handle operations on identical paths.
      • Improve handling of near-collinear lines.
      • Handle self-intersecting paths that merely "touch" themselves.
      • Handle situations where all encountered intersections are part of overlaps.
    • Methods that accepted a time parameter or boolean second parameter causing the argument to be interpreted as curve-time instead of offset are now separate functions with distinct names (#563):
      • Curve#getNormalAt(time, true)#getNormalAtTime(true)
      • Curve#divide()#divideAt(offset) / #divideAtTime(time)
      • Curve#split()#splitAt(offset) / #splitAtTime(time)
      • Curve#getParameterAt(offset)#getTimeAt(offset)
      • Curve#getParameterOf(point)getTimeOf(point)
      • Curve#getPointAt(time, true)#getPointAtTime(time)
      • Curve#getTangentAt(time, true)#getTangenttTime(time)
      • Curve#getNormalAt(time, true)#getNormalAtTime(time)
      • Curve#getCurvatureAt(time, true)#getCurvatureAtTime(time)
      • CurveLocation#parameter#time
      • Path#split(offset/location)#splitAt(offset/location)
    • Significant improvement of reliability of bezier fat-line clipping code in PathItem#getIntersections() and #getCrossings().
    • PathItem#smooth() now accepts an options.type string specifying which smoothing algorithm to use: 'asymmetric' (default), 'continuous', 'catmull-rom', and 'geometric' (#338).
    • PathItem#flatten(): argument has been changed from tolerance (maximum allowed distance between points) to flatness (maximum allowed error) (#618).
    • Update internal Acorn JavaScript parser to 0.5.0, the last small version.
    • Transition to Gulp based build process.
    • Update QUnit to 1.20.0.
    • Update to JSDOM 8.3.0, to benefit from integrated image and canvas support.
    • Complete refactoring of keyboard event handling to increase reliably when handling special keys.
    • Complete refactoring of mouse-event handling on item and view, to better handle event propagation, default behavior and Item#removeOn() calls.
    • Simplify and streamline the mouse-handling code on Tool (#595).
    • Mouse handlers can to return false to call event.stop(), stopping event propagation and prevent the default browser behavior.
    • event.preventDefault() is called by default after any handled mouse mouse events, except 'mousemove', and only on a 'mousedown' event if the view or tool respond to 'mouseup'.
    • Switch to the new HTML5 Page Visibility API when detecting invisible documents and canvases.
    • Rename #windingRule to #fillRule on Item and Style.
    • Do not replace existing named child reference on Item#children with new one when the name is identical.
    • Limit the effects of #strokeScaling to PathItem and Shape (#721).
    • Throw an exception if arguments to #smooth() are segments or curves from incorrect paths.
    • Rename Matrix#concatenate() to #append() and preConcatenate() to #prepend().
    • Make Matrix#shiftless() and #orNullIfIdentity() internal functions.
    • De-bounce internal View#update() calls to minimize the number of times a canvas is redrawn (#830, #925).
    • Symbol now clashes with ES6 definition of Symbol and has been changed (#770):
      • SymbolSymbolDefinition
      • PlacedSymbolSymbolItem
      • Symbol#definitionSymbolDefinition#item
      • PlacedSymbol#symbolSymbolItem#definition
    • Don't serialize deprecated Style#font property.
    • Don't serialize text-styles in non-text items (#934).
    • Changed argument parameter to time for Postscript-style drawing commands.
    • Item#clone(): optional argument is now an options object with defaults {insert: true, deep: true}. insert controls whether the clone is inserted into the project and deep controls whether the item's children are cloned. The previous boolean optional argument is still interpreted as the insert option (#941).
    • Matrix properties #b and #c have been reversed to match common standard.
    • #importSVG(): improve handling of style inheritance for nested <defs>.
    • Move PaperScript#execute() URL argument into options.url (#902).
    • PaperScript: Only translate == to equals() calls forPoint,SizeandColor` (#1043).


    • Use unified code-base for browsers, Node.js, Electron, and anything in-between, and enable npm install for browser use (#739).
    • Start using automatic code testing and deployment of prebuilt versions through Travis CI.
    • Reach JSHint compliance and include regular linting in Travis CI tests.
    • Use QUnit tests for leaked globals.
    • Define code format standards in .editorconfig file
    • Add support for running without a canvas for Web Workers, Node.js (#561, #582, #634).
    • Add support for all common mouse events to View.
    • Add support for 'keydown' and 'keyup' events to View (#896).
    • Add View#requestUpdate() function to minimize number of actual canvas redraw.
    • Add View#matrix to allow matrix transformation to be accessed and modified directly on the view (#832).
    • Multiple additions to SVG export (#exportSVG()):
      • Support { precision: value } option.
      • Support #fillRule through the SVG fill-rule attribute.
      • Support #blendMode through the CSS mix-blend-mode attribute.
    • Various additions to #getItems() on Project and Item:
      • Add support for { recursive: false } as a way to prevent iterating over all children of children.
      • Add support for { match: function() {} }, so the match function can be passed in combination with other options.
    • Add Item#copyAttributes() and Item#copyContent(), and use them in Item#clone().
    • Add optional insert boolean argument to Path#toShape(), Shape#toPath(), Item#rasterize(). Default is to insert, set to false to prevent the created item from being inserted into the scene graph.
    • Add visual item comparison to QUnit, through rasterization and Resemble.js diffing.
    • Add many unit tests for known edge cases in boolean operations and curve intersections.
    • Add Project#addLayer() and Project#insertLayer() (#903).
    • Layers may now be given names and be accessed through project.layers[name] (#491).
    • Add Matrix#prepended() and #appended() to return copies of the modified matrix.
    • Shape#hitTest(): Add boolean option options.stroke (#911).
    • Insert version number into docs.
    • Support Raster#onLoad() events on Raster#setImage() now (#924).
    • Add Raster#onError() event support (#849).
    • Allow the control of automatic updating of the canvas through View#autoUpdate (default: true)(#921).
    • Set 1px default strokeWidth for SVG imports to fix IE/Edge default (#467).
    • ImportSVG() passes imported SVG data to onLoad callback as second parameter.
    • Add #interpolate for Segment, Path, and CompoundPath (#624).
    • Implement CompoundPath#flatten(), #simplify(), #smooth() (#727).
    • Implement #hitTestAll() to return all items that were hit (#536).
    • #importSVG() implements option.onError callback (#969).
    • settings.insertItems controls whether newly created items are inserted or not (default: true).
    • Add #importSVG() option.insert (default: true) to control insertion (#763).
    • Add new options to #exportSVG() to control output bounds and transformation matrix (#972).
    • Allow Item#position to be selected via Item#position.selected (#980).
    • Add tolerance argument to Path#join(path, tolerance).
    • Add Curve#getOffsetAtTime(time), as the reverse of Curve#getTimeAt(offset).
    • Add Raster#loaded to reflect the loading state of its image.


    • Fix calculations of Item#strokeBounds for all possible combinations of Item#strokeScaling and Item#applyMatrix for Path, Shape and SymbolItem, along with correct handling of such strokes in Item#hitTest() (#697, #856, #1014).
    • Make new code-base unified for Node.js/browser work with module bundlers like Webpack (#986).
    • Improve hit-testing and #contains() checks on path with horizontal lines (#819).
    • Improve reliability of Path#getInteriorPoint() in rare edge-cases.
    • Handle non-reversible matrices in Item#hitTest() (#617).
    • Fix various issues with adding and removing of segments in paths (#815).
    • Support bubbling up of doubleclick events on Group (#834).
    • Fix wrong #key values in key-events that do not match character (#881).
    • Fix keyboard event handling of control and meta keyboard sequences and special character handling (#860).
    • Handle incorrect mouse event on ctrl-alt-del key sequence on Chrome/Windows (#800).
    • Do not rasterize items if the resulting raster will be empty (#828).
    • Fix SVG serialization in JSDOM 7.0.0 and newer (#821).
    • Correctly handle gradients in SVG import on Firefox (#666).
    • Consistently interpret curves as straight or not-straight (#838).
    • Switch blendMode to 'lighter' in Candy Crash example for better performance (#453).
    • Don't block touch actions when using paper in JavaScript mode (#686).
    • Convert touch event coordinates to project coordinates (#633).
    • Fix exceptions when a top-level layer is selected.
    • Don't allow layers to turn up in hit-tests (#608).
    • Maintain Raster#source correctly on Node.js (#914).
    • Boolean operations correctly handle open Path items within CompoundPath (#912).
    • Don't modify an array of child items passed to CompoundPath#insertChildren() when it is a child items array of a CompoundPath.
    • Correctly handle #strokeScaling in Shape hit-tests (#697).
    • Support clip-masks in hit-testing (#671).
    • Fix incorrect #hitTest() and #contains() cases (#819, #884).
    • Update documentation to note appropriate use for #simplify() (#920).
    • #importSVG() now supports percentage dimensions and gradientUnits="objectBoundingBox". (#954, #650).
    • Group items with clip-masks now calculate correct bounding boxes (#956).
    • Calling event.stopPropagation() in 'mousedown' handler no longer prevents 'mousedrag' events (#952).
    • Draw Item shadows when #shadowBlur is zero (#955).
    • Fixes for web site examples (#967).
    • Prevent Item bounds from permanently collapsing to 0 when applying non- invertible transformations (#558).
    • Scaling shadows now works correctly with browser- and view-zoom (#831).
    • Path#arcTo() correctly handles zero sizes.
    • #importSVG() handles onLoad and onError callbacks for string inputs that load external resources (#827).
    • #importJSON() and #exportJSON() now handle non-Item objects correctly (#392).
    • #exportSVG() now exports empty paths if used as a clip-mask.
    • #importJSON() no longer generates callstack exceeded exceptions (#764).
    • Fix problems with group selection structures after Group#importJSON() (#785).
    • Fix an issue in Item#importJSON() where #parent is null when calling it on existing, already inserted items (#1041).
    • Correct issue when using paper-core in Node.js (#975).
    • Fix on mousedrag events (#981).
    • Improve handling of XML attribute namespaces for IE's XMLSerializer() (#984).
    • Make sure Item#removeChildren() fully removes children (#991).
    • Improve handling of event propagation on View and Item (#995).
    • #importSVG(): Improve handling of viewBox.
    • Make sure all named item lookup structures are kept in sync (#1009).
    • Convert absolute local gradient URLs to relative ones (#1001).
    • Fix TypeError in Path#unite() (#1000).
    • Allow the selection of a Path item's bounds without selecting the segments (#769).
    • Fix wrong indices in Item#insertChildren(), when inserting children that were previously inserted in the same parent (#1015).
    • Add capability to PathItem#closePath() to handle imprecise SVG data due to rounding (#1045).
    • Improve reliability of fat-line clipping for curves that are very similar (#904).
    • Improve precision of Numerical.solveQuadratic() and Numerical.solveCubic() for edge-cases (#1085).


    • Canvas attributes "resize" and "data-paper-resize" no longer cause paper to resize the canvas when the viewport size changes; Additional CSS styles are required since 0.9.22, e.g.:

      /* Scale canvas with resize attribute to full size */
      canvas[resize] {
          width: 100%;
          height: 100%;
    • Legacy Color constructors (removed in 0.9.25): GrayColor, RgbColor, HsbColor, HslColor, and GradientColor. These have been replaced with corresponding forms of the Color constructor.

    • Undocumented function Project#addChild() that added a layer to a project. It is replaced by Project#addLayer() and Project#insertLayer().


    • #windingRule on Item and Style#fillRule
    • Curve#getNormalAt(time, true)#getNormalAtTime(true)
    • Curve#divide()#divideAt(offset) / #divideAtTime(time)
    • Curve#split()#splitAt(offset) / #splitAtTime(time)
    • Curve#getParameterAt(offset)#getTimeAt(offset)
    • Curve#getParameterOf(point)getTimeOf(point)
    • Curve#getPointAt(time, true)#getPointAtTime(time)
    • Curve#getTangentAt(time, true)#getTangenttTime(time)
    • Curve#getNormalAt(time, true)#getNormalAtTime(time)
    • Curve#getCurvatureAt(time, true)#getCurvatureAtTime(time)
    • CurveLocation#parameter#time
    • Path#split(offset/location)#splitAt(offset/location)
    • SymbolSymbolDefinition
    • PlacedSymbolSymbolItem
    • Symbol#definitionSymbolDefinition#item
    • PlacedSymbol#symbolSymbolItem#definition
    • Project#symbols#symbolDefinitions
    • Matrix#concatenate#append
    • Matrix#preConcatenate#prepend
    • Matrix#chain#appended
    • GradientStop#rampPoint#offset
    Source code(tar.gz)
    Source code(zip) MB)
React + Canvas = Love. JavaScript library for drawing complex canvas graphics using React.

React Konva React Konva is a JavaScript library for drawing complex canvas graphics using React. It provides declarative and reactive bindings to the

konva 4.9k Jan 9, 2023
Javascript Canvas Library, SVG-to-Canvas (& canvas-to-SVG) Parser

Fabric.js Fabric.js is a framework that makes it easy to work with HTML5 canvas element. It is an interactive object model on top of canvas element. I

Fabric.js 23.6k Jan 3, 2023
Javascript Canvas Library, SVG-to-Canvas (& canvas-to-SVG) Parser

Fabric.js Fabric.js is a framework that makes it easy to work with HTML5 canvas element. It is an interactive object model on top of canvas element. I

Fabric.js 23.6k Jan 3, 2023
Konva.js is an HTML5 Canvas JavaScript framework that extends the 2d context by enabling canvas interactivity for desktop and mobile applications.

Konva Konva is an HTML5 Canvas JavaScript framework that enables high performance animations, transitions, node nesting, layering, filtering, caching,

konva 8.7k Jan 8, 2023
An implementation of Bézier curve rendering and manipulation, using the HTML5 Canvas API.

Bézier Curves An implementation of Bézier curve rendering and manipulation, using the HTML5 Canvas API. How does it work? Bézier curves can be simply

nethe550 1 Apr 13, 2022
📸 Generate image using HTML5 canvas and SVG

egami → image README | 中文文档 Generate image using HTML5 canvas and SVG Fork from html-to-image Installation pnpm pnpm add egami npm npm i egami Usage i

weng 12 Jan 3, 2023
Simple HTML5 Charts using the tag

Simple yet flexible JavaScript charting for designers & developers Documentation Currently, there are two versions of the library (2.9.4 and 3.x.x). V

Chart.js 59.4k Jan 7, 2023
🔥 JavaScript Library for HTML5 canvas based heatmaps

heatmap.js Dynamic Heatmaps for the Web. How to get started The fastest way to get started is to install heatmap.js with bower. Just run the following

Patrick Wied 5.9k Jan 2, 2023
Javascript game using Three.JS and WebGL, inspired by Geometry Dash, the Dinosaur Game, and a music video by our graphics professor (2021)

jumpy-abe By Sophia Oguri ([email protected]), Luke Kratsios ([email protected]), Isha Chirimar ([email protected]), Jacob Hocking ([email protected]

null 1 Dec 21, 2021
Canvas rendering library, Sprite manipulation of canvas

el-canvas Canvas rendering library, Sprite manipulation of canvas hello world <div id="app"><div></div></div> yarn add elem-canvas or npm i

null 15 Apr 13, 2022
Financial lightweight charts built with HTML5 canvas

Lightweight Charts Demos | Documentation | Discord community TradingView Lightweight Charts are one of the smallest and fastest financial HTML5 charts

TradingView, Inc. 5.8k Jan 9, 2023
An HTML5/Canvas implementation of 8-bit color cycling

Overview Here is the JavaScript and C++ source code to my color cycling engine, written in 2010. I am releasing it under the LGPL v3.0. The package co

Joseph Huckaby 8 Dec 1, 2022
JavaScript Vector Library

Raphaël: Cross-browser vector graphics the easy way Visit the library website for more information: https://dmitrybaranovskiy.git

Dmitry Baranovskiy 11.2k Jan 3, 2023
The JavaScript library for modern SVG graphics.

Snap.svg · A JavaScript SVG library for the modern web. Learn more at Follow us on Twitter. Install Bower - bower install snap.svg npm - n

Adobe Web Platform 13.6k Dec 30, 2022
A lightweight JavaScript graphics library with the intuitive API, based on SVG/VML technology.

GraphicsJS GraphicsJS is a lightweight JavaScript graphics library with the intuitive API, based on SVG/VML technology. Overview Quick Start Articles

AnyChart 973 Jan 3, 2023
A lightweight JavaScript graphics library with the intuitive API, based on SVG/VML technology.

GraphicsJS GraphicsJS is a lightweight JavaScript graphics library with the intuitive API, based on SVG/VML technology. Overview Quick Start Articles

AnyChart 937 Feb 5, 2021
A library optimized for concise and principled data graphics and layouts.

MetricsGraphics is a library built for visualizing and laying out time-series data. At around 15kB (gzipped), it provides a simple way to produce comm

Metrics Graphics 7.5k Dec 22, 2022
A library optimized for concise and principled data graphics and layouts.

MetricsGraphics is a library built for visualizing and laying out time-series data. At around 15kB (gzipped), it provides a simple way to produce comm

Metrics Graphics 7.5k Dec 22, 2022
A tiny TypeScript library for 2D vector math.

Vecti A tiny TypeScript library for 2D vector math. Documentation Features ?? Addition, subtraction, multiplication and division ✨ Dot, cross and Hada

Jan Müller 17 Nov 30, 2022