paged.image — raster
The raster-image plugin — a Rust/WASM pipeline of GPU kernels with PSD round-trip, dual processing engines, color management, and in-editor ingest into the engine's image scene layer.
In short paged.image is a raster-processing subsystem in Rust/WASM —
GPU-executed adjustment kernels, two processing engines, color management, and
byte-faithful PSD/PSB round-trip ("paged never destroys a PSD"). It's wired into
the editor: place → ingest → GPU adjust → in-frame composite.
What it does
- 131 GPU compute kernels (adjustments, transforms, blurs) with scalar reference twins used only in tests.
- Two engines — a demand-driven streaming pipeline and a persistent tiled buffer.
- PSD/PSB parsing + mutation + preservation-safe round-trip; hybrid color management.
- In-editor ingest: placed-asset bytes → decode → GPU adjust → scene-layer composite → tiles.
- In development: layered PSD import (groups, masks, smart objects, adjustment layers), retouching tools (spot heal, patch, dodge and burn, blur and sharpen brushes, mask painting, red eye), editable adjustment layers, and layers, masks and adjustments as typed objects (the object model).
How it's built
A Cargo workspace (image-core, image-kernels, image-gpu, image-pipeline,
image-psd, image-cms, image-codecs, image-js) plus a TS bundle. A
registry-driven coverage gate requires every kernel to have a test.
Capability state
● shipped & verified · ○ shipped, re-test pending · ◍ shipped, untested · ◐ partial · ✗ failing · · planned
Plugin · image 86 features · 76% green
| Feature | API | Image |
|---|---|---|
A sampled .abr tip paints through the existing stroke accumulatorimage.abr.engine-bridge | ◐ | |
.abr brush-preset reader over a new PSD descriptor readerimage.abr.reader | ◐ | |
The .abr regression gate, split into the two lanes its roles can runimage.abr.regression-gate | ◐ | |
Per-channel statistics, from the same buffer as the histogramimage.channels.readout | ◐ | |
Load a channel as the selection (luminosity masking)image.channels.to-selection | ● | |
CMS display lane — qcms RGB↔RGB (the exact build core ships, page/editor agree)image.cms.display | ◐ | |
CMS behind the swappable CmsEngine seam (D-11: hybrid)image.cms.engine | ◐ | |
CMS rung 1 — the RGB display transform at decodeimage.cms.ingest-transform | ◐ | |
CMS print lane — moxcms per-intent RGB↔RGB + CMYK8→RGBA8 ingestimage.cms.print | ◐ | |
AVIF / JXL / camera-RAW / HEIC — codec verdicts (deferred + explicit non-goals)image.codec.avif | · | |
EXIF/TIFF read — orientation + DPI + color-space tag, auto-orient at ingestimage.codec.exif | ● | |
Codec adapter contract (ImageSource/ImageTarget over sans-IO ByteSource) + PNG + rawimage.codec.traits | ● | |
GPU tests that cannot pass silentlyimage.conformance.gpu-lanes | ◐ | |
Conformance harness — scalar references, gpu↔ref parity, fixture corpusimage.conformance.harness | ◐ | |
Panel + chain integration of the new adjustments and generatorsimage.editor.adjust-breadth | ● | |
Auto-enhance — gray-world WB + percentile auto-levels params from the panel histogramimage.editor.auto-enhance | ● | |
Blur and sharpen brushesimage.editor.blur-sharpen-brush | ● | |
Photoshop .abr brush libraries load and set the brushimage.editor.brush-presets | ◐ | |
Rotate, flip and Canvas Size over all layersimage.editor.canvas-ops | ● | |
Clone stamp — the brush with a sampled paint layerimage.editor.clone-stamp | ● | |
Foreground/background colour, picker and eyedropperimage.editor.color-fg-bg | ◐ | |
Content-aware fill — coarse-to-fine exemplar inpaintingimage.editor.content-aware-fill | ◍ | |
Editor crop + straighten tool — host-agnostic crop machine over the geom.crop windowimage.editor.crop | ● | |
Crop straighten commits (arbitrary-angle rotation resample)image.editor.crop-straighten | ◍ | |
Editor levels/curves/white-balance panel — histogram view + adjust kernelsimage.editor.curves | ◐ | |
K-3 decode worker pool — off-main-thread ingest decode (host.workers consumer)image.editor.decode-pool | ◐ | |
Dodge, burn and spongeimage.editor.dodge-burn | ● | |
Filters — blur / unsharp / hue-rotate / invert in the adjustments panelimage.editor.filters | ● | |
Gradient tool (drag the line)image.editor.gradient-tool | ● | |
Healing brush — a clone tone-matched in the gradient domainimage.editor.healing-brush | ● | |
History panel over the tile journalimage.editor.history-panel | ◍ | |
Host Cmd+Z inside an imageimage.editor.host-undo | ● | |
Hue/Saturation — master, six colour ranges, colorizeimage.editor.hue-saturation | ◐ | |
M4 editor enablement — C-5 placed bytes → decode → adjust → C-1 Stage-A in-frame compositeimage.editor.ingest | ◐ | |
Pixel-layer stack with a compose.* foldimage.editor.layers | ◐ | |
Live adjustment preview on a resampled proxyimage.editor.live-preview | ● | |
Paint on layer masks (Pixels/Mask edit target)image.editor.mask-painting | ● | |
Move tool for pixels and layersimage.editor.move-tool | ● | |
Brush / Pencil / Eraser — the raster paint laneimage.editor.paint | ● | ◐ |
Paint bucketimage.editor.paint-bucket | ◍ | |
Patch toolimage.editor.patch | ● | |
Define pattern, pattern fill and shape blurimage.editor.pattern-fill | ● | |
Median, Maximum, Minimum and Color Lookupimage.editor.rank-filters | ◐ | |
Raster type — shaped glyphs painted into a layerimage.editor.raster-type | ◐ | |
Red eyeimage.editor.red-eye | ● | |
Resample — resize the working image through the registered kernelsimage.editor.resample | ● | |
Spot healing brushimage.editor.spot-heal | ● | |
C-6 tile provider for placed images (host.images.claimImageResource, v44; honest level-0 subset)image.editor.tile-provider | ◐ | |
Raster tool options in the host's tool-options barimage.editor.tool-options | ◐ | |
Bounded COW tile journal — undo/redo for pixel editsimage.editor.undo-journal | ◐ | |
Engine B — persistent buffer graph (invalidation, mip-aware eval, Gestures/Operations)image.graph.engine-b | ◐ | |
16-bit PSD sources open, reduced to 8 and reportedimage.io.depth-16bit-ingest | ◐ | |
Layered PSD exportimage.io.layered-psd | ◐ | |
Commit image edits to the document and reopen themimage.io.persistence | ◐ | |
Save-back — adjusted composite to PSD / PNG / JPEGimage.io.save-back | ● | ◐ |
Kernel breadth — 24 new point/compose/gen kernels (73 → 97)image.kernel.breadth-2026-08 | ◍ | |
T0 generated kernel families (arith/relational/boolean/cast/band/minmax/linear)image.kernel.family-t0 | ◐ | |
T1 crown-jewel kernels (conv/resample/compose — handwritten WGSL modules, ABI v1.1)image.kernel.family-t1 | ◐ | |
T2 editor-bearing kernels (adjust/geom/generators)image.kernel.family-t2 | ◐ | |
T3 breadth kernels (morphology, rank/median, distance transform)image.kernel.family-t3 | ◐ | |
1D and 3D LUT sampler classesimage.kernel.lut-samplers | ◐ | |
General backward-map warpimage.kernel.warp-backward | ◐ | |
Frozen WGSL kernel ABI v1 (4 bind groups, 16×16, mask-mixed pointwise)image.kernel.wgsl-abi | ● | |
Clipping layers — an adjustment confined to the layer beneathimage.layers.clipping | ● | |
Editable adjustment layersimage.layers.editable-adjustments | ◐ | |
The layer fold keeps adjustment layers in f16image.layers.f16-fold | ◍ | |
Layer groups — pass-through and isolated, nesting up to eightimage.layers.groups | ◍ | |
Smart objectsimage.layers.smart-objects | ● | |
Object model — layers, masks, adjustments and smart objects addressable through host.objectsimage.object-model | ● | |
A host path becomes the selectionimage.paths.path-to-selection | ● | |
A raster selection becomes a real vector pathimage.paths.selection-to-path | ◐ | |
Work counters and count budgetsimage.perf.budgets | ● | |
Engine A async sinks — to_buffer_async/to_encoder_async (the wasm32/WebGPU readback lane)image.pipeline.async-sink | ● | |
Engine A — demand-driven streaming pipeline skeletonimage.pipeline.engine-a-skeleton | ● | |
paged.image bundle (media.paged.image) — manifest + activate + panelimage.plugin.bundle-manifest | ◐ | |
PSD structural session — layer list/edit/save reach the editorimage.psd.editor-doors | ◍ | |
PSD import populates the layer stack (declines rather than approximates)image.psd.layer-import | ◐ | |
PSD mutatable — edits re-encode through the preservation writerimage.psd.mutatable | ◐ | |
PSD rendered tier — channel decode + flatten render oracleimage.psd.rendered | ◐ | |
PSD/PSB structural parse + preservation-invariant writerimage.psd.roundtrip | ◐ | |
Reductions — histogram + min/max/mean statisticsimage.reduce.statistics | ◐ | |
Residency Tier 0/1 hardening under working-set pressureimage.residency.tier01 | ● | |
Selection-mask plumbing — the §6.1 mask surfaced end-to-endimage.selection.mask | ● | |
Selection system — marquee/ellipse/lasso/wand over the mask ABIimage.selection.mask-tools | ● | ● |
Selection coverage threaded through the GPU adjust chainimage.selection.masked-pipeline | ● | |
Select ▸ Modify and wand optionsimage.selection.modify | ● |
Recent activity
- 2026-10-18README: moved to paged-media/paged (modules/image) [skip ci]19e3f4c
- 2026-10-13Merge pull request #3 from paged-media/fix/films-bugs4539363
- 2026-10-12fix(persist): a commit after a flat reopen keeps the stored revisions (IMG-4)97c1812
- 2026-10-12release: @paged-media/image 0.1.0-canary.21 so the films fixes shipe4a1efc
- 2026-10-12fix(import): a file opened into an empty frame is placed in it (IMG-2)821c499
- 2026-10-12fix(session): a new image starts clean, so a PSD export keeps its layers (IMG-1)c43f521
- 2026-10-11Merge pull request #2 from paged-media/fix/ui-text-internal-refs5c11fae
- 2026-10-11test(residency): assert the plain Tier-2 wording, not the internal id7ee8c2b
paged.web — HTML/CSS
The web-content plugin — author HTML/CSS as a content type, with a sandboxed preview and on-canvas rendering via a Blitz/WASM lowering to the engine's scene layer.
paged.sheet — spreadsheets
The spreadsheet plugin — a Rust/WASM calc engine with spill, structured tables, charts, and XLSX round-trip, lowered to native print-grade tables and editable in-frame.