Stock Paper.js redraws the whole scene into a canvas on every frame, so panning a document
with tens of thousands of items costs a full scene traversal per frame. This fork adds a
second renderer that mirrors the scene graph into a native SVG DOM tree and keeps one node per
item alive. Moving the camera then costs a single transform attribute — no matter how many items there are.
npm i github:Typogram/paper.js#dist-only Source on GitHub →Upstream Paper.js 0.12.18 plus the renderer. Same API, same items, same hit-testing, same
events — a drop-in replacement for the paper package, and it installs under that
name, so nothing that imports paper has to change.
The same scene and the same auto-pan through both renderers, one at a time so each is measured on its own frames. Drag to pan, scroll to zoom, or switch Drag to Select and click an item — hit-testing and selection handles work the same either way.
import paper from 'paper';
paper.setup(canvas);
new paper.Path.Circle({
center: [80, 50],
radius: 35,
fillColor: 'red'
}); Items, styles, tools, events, hitTest(), import and export are all upstream
Paper.js. The renderer is the only thing that changed.
// per scope, before setup()
paper.settings.renderer = 'canvas';
// or per view
<canvas data-paper-renderer="canvas"> SVG is the default here. A view that needs the canvas back — to read its pixels, say — opts out on its own, and everything else keeps rendering as SVG.
One node per item, kept alive and updated in place. The view learns what changed through Paper.js's own change tracking, so an update touches the items that actually changed rather than walking the scene.
The view matrix lives on the root <g>. A pan or zoom writes transform="matrix(…)" and nothing else — no item is visited, no path rebuilt.
The browser keeps the rasterized geometry and skips what is off screen.
Setup time and memory: 100,000 live nodes is a real burden, and changing every item in one frame is more expensive here than a redraw. It trades per-frame work for per-change work, which is the trade an editor wants.
<canvas>, the view replaces
it with an <svg> and puts the original back on remove(). Code holding its own reference to that canvas — a framework ref, listeners
bound to it, or canvas.toDataURL() for a thumbnail — should render an <svg> element itself, or opt that view out. To read pixels, go through Item#rasterize(), which makes its own canvas either way.add maps to CSS plus-lighter and the other 15 map to the CSS mode of
the same name, but subtract, average, pin-light and negation have no CSS equivalent — Paper.js emulates those in JavaScript for the canvas
renderer, which a DOM tree cannot do.PointText bounds. It is the only
canvas left in the rendering path.