Launch OpenGPEX

OpenGPEX 1.x documentation (legacy editor).

v2 Docs

Service Facades

Specifications for the utility service facades accessed via useEditorServices().


PixelService (pixels)

The unified pixel processing facade. Handles coordinate projection between the three physical spaces, and organizes pixel operations into domain-specific namespaces.

Three-Space Coordinate Projection

OpenGPEX defines three coordinate spaces:

Space Origin Unit Use Case
Screen (S) Browser viewport top-left CSS pixels Mouse events, UI positioning
World (W) Canvas geometric center Physical pixels Layer transforms, alignment
Local (L) Canvas content top-left Physical pixels Crop boxes, brush strokes, export

Projection lives on the geometry service, under geometry.space.* — every method takes the active frame (and optionally a camera):

Method From → To Description
geometry.space.screenToLocal(vx, vy, frame, camera?) Screen → Local Recommended. Mouse pos → canvas pixel. For crop, brush, selection.
geometry.space.localToScreen(px, py, frame, camera?) Local → Screen Canvas pixel → viewport pos. For tooltip placement.
geometry.space.screenToWorld(vx, vy, frame, camera?) Screen → World Mouse pos → center-origin world. For layer drag.
geometry.space.worldToLocal(wx, wy, frame) World → Local Center-origin → top-left pixel.
geometry.space.localToWorld(px, py, frame) Local → World Top-left pixel → center-origin.

Rect variants also exist (localToScreenRect, worldToScreenRect, worldToLocalRect, localToWorldRect).

⚠️ Never manually calculate zoom offsets (e.g. e.clientX / camera.k). Always use the projection APIs.

pixels.image — Bitmap Loading & Caching

Method Description Returns
loadBitmap(src) Async decode + cache ImageBitmap Promise<ImageBitmap>
cacheBitmap(src, blob) Pre-warm cache from existing Blob Promise<void>
ensureBitmap(src) Sync probe (hit → bitmap, miss → fires background fetch) ImageBitmap | undefined

pixels.render — Compositing

All methods accept options?: { precision?: 8 | 16; dpr?: number }.

Method Description Returns
compositeFrame(frame, roi?, options?) Composite all visible non-group layers of a frame Promise<CompositeResult>
compositeLayers(layers, frame, roi?, options?) Composite specific layers Promise<{ result, bounds: { w, h, cx, cy } }>
compositeResizedLayers(layers, frame, outputSize) Composite + scale in one Worker round-trip Promise<{ result }>
registerEncoder(mimeType, encoder) Register a custom encoder; returns unregister function () => void

There is also a low-level unified entry point: pixels.composite(request) → Promise<CompositeResult>.

pixels.rasterize — Layer Rasterization

Method Description Returns
layer(layer, opts?) Rasterize any layer type to a bitmap asset (opts?: { dpr?: number }) Promise<{ assetId, url }>

pixels.utils

Method Description
fetchFromUrl(url) Fetch a URL into a File
download(blob, filename) Trigger a browser download

pixels.fileIO — Worker-based File I/O (wasm-vips)

Method Description Returns
decodeTiff(bytes, options?) Decode TIFF via wasm-vips ({ preserveColorSpace? }) Promise<{ width, height, data }>
encodeTiff(rgbaData, w, h, options) Encode RGBA to TIFF Promise<Uint8Array>
getPageCount(bytes) Get multi-page TIFF info Promise<{ pages, pageWidth, pageHeight }>
decodePage(bytes, page) Decode specific TIFF page Promise<{ width, height, data }>
iccToSrgb(bytes) Convert non-sRGB ICC pixels to sRGB RGBA (returns ICC bytes) Promise<{ width, height, data, iccProfileData? }>
srgbToIcc(rgbaData, w, h, iccProfileData) Convert sRGB pixels back to target ICC space Promise<{ data }>
encodeAvif(rgbaData, w, h, options) Encode RGBA to AVIF Promise<Uint8Array>

CompositeResult

All composite operations return a CompositeResult (a PixelResult subclass) with lazy consumption:

interface CompositeResult {
  toBlob(format?: string): Promise<Blob>;
  toImageData(): Promise<ImageData>;
  toAsset(): Promise<AssetRef>;  // { assetId, url, dimensions } — auto-registers + warms caches
  dimensions: { w: number; h: number };
  trimmed(): Promise<{ result: CompositeResult; offset: { x: number; y: number } } | null>;
}

RenderToBlobOptions

Rich export configuration:

interface RenderToBlobOptions {
  format?: string;              // MIME type, or 'raw' to receive an ImageBitmap (no encoding)
  quality?: number;             // 0..1 (default 0.92)
  exportBitDepth?: 8 | 16;     // 16 requests the vips-native lane when eligible
  metadata?: ImageMetadata;     // EXIF/ICC passthrough
  exportConfig?: {
    dpi?: number;
    preserveExif?: boolean;
    embedIcc?: boolean;
    frameColorSpace?: 'srgb' | 'display-p3' | 'adobe-rgb' | 'prophoto-rgb';
    tiffCompression?: string;   // 'lzw' | 'deflate' | 'none'
    pngCompression?: number;    // 0..9
    jpegQuality?: number;       // 1..100 (overrides `quality`)
    resize?: { w: number; h: number };
  };
  layerIds?: string[];          // Selective layer rendering
}

LayerService (layers)

Safe, high-level layer operations with built-in validation. Prefer these over raw actions.addLayers etc.

Method Description Safety Check
layers.addLayer(frameId, layer) Add a layer Auto-expands composite (group) layers
layers.activate(frameId, layerId) Set active layer Guards non-activatable layers (masks, sub-layers)
layers.removeLayers(frameId, layerIds) Remove layers Cascade-deletes children, auto-migrates focus

GeometryService (geometry)

Coordinate transforms, bounding boxes, hit testing, snapping, and camera math. The full surface is grouped into namespaces: geometry.space, geometry.transform, geometry.camera, geometry.snapping, geometry.shape, plus a geometry.Matrix constructor.

Key Methods

Method Description
geometry.space.screenToLocal(vx, vy, frame, camera?) Viewport physical coords → layer-local coords (and all sibling projection methods)
geometry.getLayerBoundingBox(layer, extraOverride?) Get layer world bounding box (WorldRect)
geometry.space.testLayerHit(pos, layer) Hit-test a world point against a layer
geometry.space.pickTopLayer(pos, layers) Topmost layer under a world point
geometry.snapping.snapRect(rect, frame, options?) Rect alignment snapping with smart guides
geometry.camera.getFitCamera(viewport, content, options?) Compute the camera that fits content in view

AssetService (assets)

Content-Addressable Storage (CAS) for image blobs, persisted in IndexedDB (OpenGPEXAssets / Assets_V2 store via localforage). Assets are indexed by SHA-256 hash; associated lossless "raw" originals are stored under the raw:${assetId} key topology.

Key Methods

Method Description Returns
register(blob, dimensions, options?) Register blob → SHA-256 hash → AssetRef (options?: { dprScale?, precomputedHash? }) Promise<AssetRef>
storeRaw(rawBlob) Persist lossless original under raw:${assetId} Promise<string | undefined>
inject(assetId, blob, tileMeta) Direct store when hash is known Promise<string>
get(assetId) Get asset entry info AssetEntryInfo | undefined
getURL(assetId) Get ObjectURL for asset string | undefined
resolve(assetId?, fallbackSrc?) Resolve to URL with fallback string
sweep(activeIds, force?) GC unused assets void
hydrate(activeIds?) Restore assets from IndexedDB Promise<void>
getPool() Snapshot of all asset entries Record<string, AssetEntryInfo>
setCallbacks({ onRegistered?, onReleased? }) Hook asset lifecycle (used to warm/evict render caches) void
clear() Clear all assets void

AssetRef

interface AssetRef {
  assetId: string;                 // SHA-256 hash
  url: string;                     // ObjectURL
  dimensions: { w: number; h: number };
}

PluginService (plugins)

Plugin lifecycle management, command registry, and busy state.

Key Methods

Method Description
plugins.getPlugin(uid) Get a plugin by UID
plugins.getCommand(uid) Look up a command by UID
plugins.getShortcutLabel(cmdUid, all?) Get formatted shortcut label
plugins.getAllPlugins() Get all registered plugins
plugins.isBusy(uid) Check if a plugin is in busy state
plugins.subscribe(cb) Subscribe to plugin list changes
plugins.registerPlugin(plugin) Register a new plugin
plugins.unregisterPlugin(uid) Remove a plugin

ClipboardService (clipboard)

System clipboard interaction.

Method Description
writeBlob(blob, metadata) Write image + metadata to clipboard
writeByUrl(url, metadata) Download URL then write to clipboard
read(event?) Read image data from clipboard

StateStorage (storage)

Editor state persistence via localforage (IndexedDB, OpenGPEX / State_V1 store).

Method Description
save(state) Persist editor state (EditorData)
restore() Restore editor state (Promise<EditorData | null>)
gc(state, force?) Garbage collect orphan data
export(frame) Export a frame to { state, assets: Record<string, Blob> }
import(state) Import exported state back into a Frame
clear() Clear all stored state

Last updated: 2026-07-30