Skip to content
Sealpixel
de

Edit small. Render big. Identical.

Your users edit a working copy in the browser. Your backend renders the same edit log on the 80-megapixel original, with the same core the browser runs. Same original, same log, same bytes. Verified by hash.

Everything below is CSS. Copy it, paste it into your app, done.

Preset
<sealpixel-editor theme="dark" locale="en">
  • 139

    golden renders

    edit logs and plans with pinned hashes

  • 136

    CLI parity cases

    native Rust and Node produce the same bytes

  • 130

    browser test runs

    across 3 engines, on every commit

  • 397 KB

    compressed core

    1.3 MB raw, one binary for every runtime

Runs identically on Chrome, Safari, Firefox, Node.js, Deno, Bun, AWS Lambda

The browser edits a working copy. Your backend renders the original.

Above 16 megapixels, by default, the editor keeps only a working copy of at most 2048 px and previews every edit on it. Your backend takes the edit log and renders the full resolution with @sealpixel/render, the same core the browser runs.

In the browser

2048 × 1537

3.15 MP working copy. The browser decodes the original once and keeps only this.

Over the wire

561 bytes

Not an image. Five operations, in coordinates that don’t care about resolution.

On your backend

10328 × 7752

80.1 MP from the original, in about 2,178 MB: 24 bytes per pixel plus 256 MB. No browser runtime.

The full edit log

561 bytes serialised

{
  "version": 1,
  "source": {
    "id": "dsc-4821", "width": 10328, "height": 7752,
    "hash": "9f2a7c4e18b3d05a6e1f8c2b47d930ae5c86f1b2093d4e7a8c5b1f6d2e0a3947"
  },
  "ops": [
    { "type": "crop.set",     "id": "c1", "rect": { "x": 0.08, "y": 0.12, "width": 0.8, "height": 0.72 } },
    { "type": "finetune.set", "id": "f1", "params": { "contrast": 0.18, "saturation": 0.22 } },
    { "type": "redact.add",   "id": "r1", "region": { "kind": "rect", "rect": { "x": 0.42, "y": 0.31, "width": 0.07, "height": 0.09 } }, "mode": "pixelate", "amount": 64 },
    { "type": "filter.set",   "id": "p1", "preset": "warm", "strength": 0.4 },
    { "type": "resize.set",   "id": "s1", "width": 3000 }
  ]
}

A 30 MB original against the handful of bytes that say what to do with it. That ratio is the architecture.

Your backend renders what the browser showed

@sealpixel/render is a building block, not a server. Your route, function or job passes the original’s bytes and the edit log. The renderer checks both, renders with the same WebAssembly binary as the browser and returns the bytes, their hash, the size and the timings. Routing, storage and retries stay in your code.

  • Limits before the decode: file size, pixel count from the header, log size
  • The log belongs to its original: another sha256 or another size is refused
  • Same plugins, same options: a log that breaks the editor’s rules is refused
  • No routing, no CORS, no storage: you pass every byte, fonts included

Try it in the demo →Read the render guide →

import { createRenderer, estimateMemoryMB } from '@sealpixel/render';
import { defaultPlugins } from '@sealpixel/plugins';

// Once per process, in your own route, function or job.
const renderer = createRenderer({
  plugins: defaultPlugins,         // the list the editor registers
  limits: { maxMegapixels: 100 },  // default 80; this photo has 80.1
});

const { log, index } = saved;      // from the editor's getEditLog()
const result = await renderer.render({
  original,                        // Uint8Array, byte for byte
  editLog: log,
  upTo: index,
  output: { format: 'image/jpeg', quality: 0.92 },
});
// { bytes, stream(), hash, width, height, mimeType, timings }
// result.hash equals a browser export of the same original and log

estimateMemoryMB(10328, 7752);     // 2178

One component. Three products.

The same element with different plugins, themes and languages. No fork, no build step: attributes and CSS.

Profile photo

A signup flow: round crop, brighten, done. Two tools, light theme, no export button; the export keeps only the circle.

Marketing studio

A content team building campaign images: every tool, dark graphite, pill buttons.

Compliance desk

A compliance team pixelating personal data in scanned forms. Redact, annotate and watermark, high-contrast theme, German UI.

Works on a phone like it works on a desktop.

The same component lays itself out for a phone on its own. No second UI, no mobile flag. Try it in the frame.

  • One component, two layouts

    Below 768 px of container width the toolbar drops to the bottom and the tool panel sits right above it. It follows its container, not the viewport, so a narrow sidebar gets the phone layout too.

  • Touch first

    Pinch to zoom, drag to pan, one finger for crop handles, redaction boxes and annotations. Wheel and trackpad do the same on a desktop.

  • Decode once, then nothing

    The phone decodes the image once and edits from memory. No re-upload between tools, no round trip for a preview. Your battery will notice.

  • Notches and home indicators

    Safe-area insets are respected. show-history="buttons" drops the timeline and show-export="never" hides the export button, so the essentials fit a small screen.

Live editor in a phone frame. Drag, pinch, tap.

The edit log is the image

One log, one core

Every crop, filter and annotation is an operation in a JSON log. A Rust core compiled to WebAssembly runs it in a Web Worker, on Node, Deno, Bun or AWS Lambda. Same bytes in, same bytes out.

Byte-identical, hash-verified

Same source, same log, rendered anywhere: the SHA-256 matches. In the browser, on Node, Deno, Bun or in a Lambda.

Pick up from JSON

Store the original once and the log next to it. Reopen any state on any device, with no generation loss. The log can travel inside the exported PNG, JPEG or WebP.

Every tool your users expect

Eleven plugins ship in the box, ten of them in the default set. Each one is its own package you can drop, replace or extend.

  • Crop

    Rotate by any angle, flip, aspect presets. Handles stay 7 px on every screen.

    @sealpixel/plugin-crop
  • Finetune

    Brightness, contrast, saturation, exposure, gamma, clarity and vignette.

    @sealpixel/plugin-finetune
  • Filter

    Grayscale, sepia, vintage, cool, warm and any 4×5 colour matrix, with strength.

    @sealpixel/plugin-filter
  • Redact

    Pixelate or blur rectangles and freeform regions, then resize or rotate them by handles. Cells snap to the original’s grid, so working copy and original match.

    @sealpixel/plugin-redact
  • Annotate

    Rectangles, ellipses, lines, arrows, freehand paths and text, all resizable and rotatable after the fact. Fonts are hashed assets, so glyphs are identical everywhere.

    @sealpixel/plugin-annotate
  • Sticker

    Place logos and image assets, rotate, flip, set opacity.

    @sealpixel/plugin-sticker
  • Frame

    Solid, inset and polaroid frames.

    @sealpixel/plugin-frame
  • Watermark

    Image or text, anchored to a corner or tiled. Identical in your backend render.

    @sealpixel/plugin-watermark
  • Resize

    Contain, cover and fill to a target size. Lanczos3 down, Catmull-Rom up.

    @sealpixel/plugin-resize
  • Fill

    Background colour for the areas a rotation or crop leaves empty.

    @sealpixel/plugin-fill
  • Assist

    A detector proposes regions on the working copy, a person confirms, and ordinary redactions reach the log. Your own model, loaded on demand. Nothing leaves the browser. Opt-in.

    @sealpixel/plugin-assist

A component for every stack

A Web Component underneath, thin typed wrappers on top. Controlled and uncontrolled edit logs everywhere.

Render on your server

A building block, not a server: call it from your own route, function or job. Node 24+, Deno, Bun and AWS Lambda.

Open in StackBlitz
import { readFile } from 'node:fs/promises';
import { DEFAULT_FONT, defaultPlugins } from '@sealpixel/plugins';
import { createRenderer } from '@sealpixel/render';

// The renderer reads no file. You pass every byte, the font too.
const font = new Uint8Array(await readFile(new URL(DEFAULT_FONT.url)));

// Once per process. Your route, function or job calls render() per request.
const renderer = createRenderer({
  plugins: defaultPlugins,
  assets: [{ id: DEFAULT_FONT.id, bytes: font }],
});

const { bytes, hash } = await renderer.render({ original, editLog: log, upTo: index });

Built for developers, documented like it

Headless core, typed edit log, a plugin SDK with a testing kit, and docs with live editors on every page.

The same edit log, in your framework

<script type="module">
  import '@sealpixel/element';
  const editor = document.querySelector('sealpixel-editor');
  editor.src = '/photo.jpg';
  editor.addEventListener('sealpixel:process', (e) => {
    const { bytes, hash } = e.detail; // the same hash @sealpixel/render produces
  });
</script>

<sealpixel-editor theme="auto" locale="en"></sealpixel-editor>

Open in StackBlitz

Looks like your app

CSS custom properties for every colour, radius and size. ::part() reaches buttons, nav and stage. Five themes and six languages ship with it.

  • 25

    design tokens

  • 18

    shadow parts

  • 5

    themes

  • 6

    languages

@import '@sealpixel/ui/themes/nocturne.css';

sealpixel-editor {
  --sealpixel-color-accent: #b48cff;
  --sealpixel-radius: 16px;
  --sealpixel-toolbar-size: 72px;
}

sealpixel-editor::part(export) { display: none; }
sealpixel-editor::part(tool) { border-radius: 999px; }

Open the customizer

Extend it, don’t fork it

A plugin is an npm package: operations with Zod schemas, a reducer, a kernel in JavaScript or in Rust compiled to its own WebAssembly module, and an optional tool with panel and gizmo. It runs on the client and on the server without rebuilding the core.

Scaffold one

npm create @sealpixel/plugin acme-spotlight -- --kernel wasm-rust
cd acme-spotlight && npm test   # parity: Node vs Chromium, WebKit, Firefox

Parity and fuzz testing kit included ·Plugin SDK

How it compares

Facts from the vendors’ public pages, September 2026.

SealpixelPinturaIMG.LY CE.SDK
Source codeSource available: read, modify, redistributeClosed source, private npm registryClosed source, escrow for enterprise
Server-side rendering@sealpixel/render on Node, Deno, Bun, Lambda, no browserYes, with a browser runtimeNode.js
Byte-identical client and server outputYes, hash-verifiedNoSame engine, but not published as a guarantee
Serializable edit stateEdit log, typed and validatedimageState objectScene file
Third-party plugin SDKJS and Rust kernelsFixed setPlugin API
React, Vue, Svelte, AstroYes, plus Web ComponentYes, plus Angular, jQueryYes, plus native mobile SDKs
Price under EUR 1M revenueFree€169 per year, one productQuote only
Price per developer, per year€999€749Quote only
Money-back window30 days60 days30-day trial

Free for people. Fair for companies.

One rule: under a million in annual revenue you pay nothing. Above it, you pay per developer who touches the code.

Small

Free

For individuals and for companies under EUR 1,000,000 of annual revenue. Production use and commercial products included.

  • All plugins, wrappers and the render package
  • Every release
  • Community support on GitHub
Get started

Company

€999

per developer seat, per year, plus applicable taxes

Entry tier, 1 to 4 seats. Cheaper per seat from 5 and from 10.

From EUR 1,000,000 of annual revenue. Seats are reassignable and cover every product, domain and environment.

  • Twelve months of updates and email support
  • Every release you received is yours to keep, forever
  • 30-day money-back guarantee
  • Sold and invoiced by Paddle, taxes included where they apply

Buying for a company? Enter your company name and VAT number in the checkout under “Add VAT number”, so the invoice carries them.

Enterprise

On request

From 25 seats, or when procurement needs more than an invoice.

  • Source code escrow
  • Custom terms and SLA
  • Purchase orders, invoicing and bank transfer
Contact us

Volume pricing

The tier follows your total number of seats, and its price applies to every one of them. Seats you add later are prorated to your existing renewal date. If the total reaches a lower tier, that tier applies to every seat from the day you add them: prorated for the rest of the term, in full at the next renewal. The part of the term already gone is not recalculated.

SeatsPer seat and year
1 to 4€999
5 to 9€899
10 to 24€799
25 and moreContact us

Business Source License 1.1, Apache 2.0 after four years. No runtime licence check: the software never phones home. Read the license

Our order process is conducted by our online reseller Paddle.com. Paddle is the Merchant of Record for all our orders and handles VAT, GST and sales tax. We stay the licensor of the software. Paddle Buyer Terms

Questions

Who gets Sealpixel for free?

Anyone under EUR 1,000,000 of gross annual revenue: individuals, and organizations below that threshold. Production and commercial products are included. Revenue counts across the whole group, so a subsidiary of a large company is not free. For client work the client’s revenue decides, so a freelancer building for a small startup pays nothing and the same freelancer building for a large customer is covered by that customer’s seats.

I am an agency. What do I pay?

One seat per developer who works on codebases that include Sealpixel, regardless of how many clients or products those codebases serve. A seat held by your developer covers all their client work, so your clients need no seats of their own, and none to run the finished application.

How do volume tiers work?

Tell us how many seats you need. 1 to 4 seats cost 999 EUR each per year, 5 to 9 cost 899, 10 to 24 cost 799, and the tier applies to every seat you hold. Seats added later are prorated to the renewal date you already have, and if the total reaches a lower tier, that tier applies to every seat from the day you add them — prorated for the rest of the term and in full at the next renewal. The part of the term already gone is not recalculated. From 25 seats we quote individually.

Can an open-source project use Sealpixel?

Yes. Sealpixel itself is source available under the Business Source License 1.1, not open source, so a project that depends on it inherits those terms: contributors below the revenue threshold need no seats, a company that develops the project needs seats for its developers, and copies and forks stay under the BUSL. Every release becomes Apache 2.0 four years after it was published.

Is Sealpixel open source?

No. Sealpixel is source available under the Business Source License 1.1. The source is public and you may read, modify, fork and redistribute it, and production use is free below the revenue threshold — but the BUSL is not an OSI-approved license, so calling it open source would be wrong. Four years after a version is published it converts to the Apache License 2.0, and that version is then open source in the OSI sense.

What exactly is a developer seat?

A seat belongs to a named person who writes, reviews, tests or integrates code in a project that includes Sealpixel. It can be reassigned when that person leaves. Designers in the codebase and QA engineers count. End users of your application never need a seat, whatever their number, and neither do people who only operate or administer it.

Can I build a SaaS on Sealpixel?

Yes. The only limit is a service whose primary value is the image editor itself, such as a hosted "edit your image" product or an image editing API sold to third parties. A photo-book shop, a CMS, a real-estate portal or a support tool with editing built in are all fine.

Who am I actually buying from, and who sends the invoice?

From Paddle. Our order process is conducted by our online reseller Paddle.com, which is the Merchant of Record for all our orders: you buy the seats from Paddle, Paddle invoices you and calculates, collects and remits VAT, GST or sales tax for your country. Enter your VAT or tax ID at the checkout so the right treatment applies. We stay the producer and licensor of Sealpixel — the software license is granted by us under the Developer Seat License, never by Paddle.

How does the refund work?

Cancel within 30 days of your first purchase and you get the full amount back, by the same route the payment came in. Paddle handles the refund as our Merchant of Record; write to us or to Paddle, we approve it either way. No questions asked.

What exactly is byte-identical?

The same source bytes plus the same edit log rendered through the same core version produce the same output bytes and SHA-256, in every browser, on Node, Deno, Bun and Lambda. So a browser export and a render with @sealpixel/render of the same original match byte for byte. The preview on a working copy is a different input: it has the same composition (same normalized geometry), but not the same bytes as the render of the original. The docs spell this out.

How big is the download?

The WebAssembly core is about 1.3 MB raw and 397 KB with Brotli, loaded lazily when the editor mounts. The Lit UI and the render worker add a few tens of kilobytes. There is a budget check in CI.

Which browsers are supported?

Current Chrome, Edge, Safari and Firefox on desktop and mobile. The core uses WebAssembly SIMD, so the floor is Chrome 91, Firefox 89 and Safari 16.4. Every commit runs the parity suite in Chromium, WebKit and Firefox, and the UI suite in Chromium and WebKit. On iOS Safari the download falls back to the share sheet.

Can I write my own tool?

Yes. npm create @sealpixel/plugin scaffolds a package with operations, a reducer, a JavaScript or Rust kernel and a tool panel. The testing kit renders your plugin in Node and three browsers and asserts equal hashes. Two example plugins ship in the repository.