emery-editor
v0.7.0
Published
Emery — embeddable, framework-agnostic, non-destructive image editor for the web. Layers, masks and adjustments as a serializable document.
Maintainers
Readme
Emery
An embeddable, framework-agnostic, non-destructive image editor for the web. Layers, masks and adjustments are a serializable document — not baked pixels — so an edit made last week can be reopened and changed.
Emery is the abrasive you finish work with — emery boards, emery cloth. It smooths and polishes; it doesn't cut the piece down. That's the idea here: nothing you do to an image is destructive.
Installed as emery-editor.
Status: 0.7.0, alpha. Phases 1–6 work; the API does not hold still. Crop, straighten, rotate, flip, thirteen adjustments including curves, levels and HSL with a live histogram, text in host-supplied fonts with bold and italic, shapes, arrows, icons and free drawing, a layer stack with blend modes, opacity, locking and reordering, undo/redo, export, and a headless renderer whose output is byte-identical to the editor's own, masking with lasso and wand selection, and a foreground/background colour pair on the toolbar driving an eyedropper, bucket fill and a mask-painting eraser, and host-supplied presets for text styles, adjustment stacks, watermarks and brand palettes. The API is unstable, there is no support, and the document format is still a draft. Please don't build on it until 1.0. See Roadmap.
Why this exists
The niche is genuinely empty. As of August 2026:
| Project | Why it doesn't fit |
| --- | --- |
| tui.image-editor | Last release 2022-04-25, 289 open issues. Pins fabric ^4.2.0, so consumers can't take fabric's security fixes. Still ~37k downloads/week — a stranded audience. |
| Filerobot | Actively maintained, but React-first (react + react-dom + react-konva + styled-components) and npm latest is a beta. |
| Pintura | Excellent. Commercial. |
| miniPaint | An application, not an embeddable component; license unasserted. |
| fabric / Konva / cropper.js | Canvas frameworks or single-purpose widgets, not editors. |
None of them is embeddable and framework-agnostic and non-destructive and openly licensed. That's the gap.
Design in one paragraph
An edit document (versioned JSON) describes the source image, a transform, and an ordered stack of layers — raster, adjustment, or vector. Rendering is a pure function of that document. Two surfaces cooperate: a WebGL compositor handles raster layers, adjustments and masks; a transparent fabric.js 7 canvas on top handles vector objects (text, shapes, callouts) and all the selection and transform handles. Export composites both. The same document can be rendered headlessly, with no UI and no interaction, which is how a host application regenerates derivatives.
See docs/DOCUMENT-SCHEMA.md — the document format is the highest-stakes part of the public API, higher than any method name, because once third parties store documents in it we own migrations forever.
Intended usage
import { createEditor } from "emery-editor";
const editor = await createEditor({
container: document.querySelector("#editor"),
source: blobOrUrl, // or { document } to reopen a previous edit
fabric, // the peer dependency, if you serve it yourself
});
editor.on("change", () => saveDraft(editor.getDocument()));
const blob = await editor.export({ format: "image/webp", quality: 0.9 });
editor.destroy();Headless, for regenerating an export server-side or in a worker:
import { renderDocument } from "emery-editor/render";
const blob = await renderDocument(doc, { resolve: (ref) => fetchBlob(ref) });Full surface: docs/API.md.
Try it
npm install # fabric, for the demo and the tests
npx http-server -c-1 # or any static server, from the repo rootThen open demo/index.html. It serves src/ directly — no build step, which
is a constraint the library keeps for its consumers too.
npm test runs the suite: geometry, document operations, history, the shader
generator, and vector rendering (which runs in Node, because fabric ships a
Node build, so the maths that decides where a watermark lands is testable
without a GPU).
Boundaries (what this library will never do)
It takes an image and a document, and returns an image and a document. It has
no opinion about your auth, your storage, your upload pipeline, your quota
accounting or your design system. Theming is CSS custom properties; strings go
through a t() you supply. Host integration happens through adapters that you
write, not through configuration we invent.
This is deliberate: the library was extracted from a real application, and the boundary is what keeps it honest.
Dependencies
One peer dependency: fabric ^7 (MIT,
itself dependency-free). Nothing else, ever — no framework, no build step
required for consumers. The src/ tree is standard ES modules and can be served
directly.
Source, and getting in touch
Source lives at git.peopoli.com/code/emery-editor — clone it anonymously, no account needed.
There is deliberately no issue tracker yet. The API is unstable until 1.0 and contributions aren't open, so a tracker would only collect reports against a surface that is still moving. Security problems are the exception: see SECURITY.md, and please email rather than post.
Contributing
Not yet — the API is still moving. When it opens, the scope policy in docs/CONTRIBUTING.md applies: this stays a focused editor component, and features outside that scope get a polite no. An unmaintained library with 289 open issues is the outcome we're explicitly trying not to repeat.
License
MIT
