@faceless-photolib/engine-api
The main public entry point for the faceless-photolib engine: open a document, edit its layer stack with named commands, and render/export through a pluggable backend (CPU reference today, GPU later).
The main public entry point for faceless-photolib — a headless, color-managed, GPU-accelerated image-editing engine.
createEngine() gives you the engine capability surface: open a stored document, apply named
commands to its layer stack, render a viewport region on a backend, export the document to an
encoded image, subscribe to committed changes, and run headless crop/transform interactions.
Every operation returns a canonical Result/Resource and never throws across the boundary — each
request is safeParsed before any side effect. The same surface is also exposed over a JSON-RPC wire
via createWireTransport(). In this layer only the CPU reference backend is wired in-process;
requesting "webgpu" or "webgl2" returns backend-unavailable (never blank or substituted pixels).
Install
pnpm add @faceless-photolib/engine-apiUsage
import { createEngine, type Command } from "@faceless-photolib/engine-api";
const engine = createEngine();
// Validate + load a stored document payload (versioned, migrated, asset-checked).
const opened = await engine.openDocument(storedDocumentJson);
if (opened.kind !== "ok") throw new Error(`open failed: ${opened.kind}`);
const doc = opened.value;
// Edit the layer stack with a named command (immer produces a fresh document value).
const setOpacity: Command = { op: "setOpacity", layerId, opacity: 0.5 };
const edited = await engine.applyCommand(doc.id, setOpacity);
// Render a viewport region on the CPU reference backend; observe via a Resource.
const render = engine.renderRegion(doc.id, { x: 0, y: 0, width: 512, height: 512, scale: 1 }, "cpu");
if (render.status === "ready") {
// render.value is the RenderResult
}
// Export the full canvas to an encoded image.
const exported = await engine.exportImage(doc.id, { format: "png" });
if (exported.kind === "ok") {
// exported.value is the encoded Uint8Array
}API
| Export | Description |
|---|---|
createEngine(deps?) | Constructs the in-process engine. Optional EngineDeps inject a resolveSource, codec, assetStore, textRasterizer, or surface. |
Engine | The capability surface: openDocument, applyCommand, renderRegion, exportImage, subscribe, beginInteraction. |
EngineDeps | Optional dependencies wired into the engine (source resolver, codec, asset store, text rasterizer, surface). |
ChangeEvent / Subscription | Events on the subscribe stream (documentChanged / renderProgress) and the unsubscribe handle. |
InteractionSession | A headless crop/transform/straighten/resize session from beginInteraction (state / send / commit / cancel). |
Command / CommandSchema | The named document op-set (addLayer, removeLayer, reorder, setBlendMode, setOpacity, setFill, transform, addAdjustment, group, clip, setMask) plus its Zod schema. |
createWireTransport(engine, opts?) | Wraps an Engine as a JSON-RPC wire transport (WireMessage in, WireResponse out). |
WIRE_VERSION / WireMessage / TransportRequest (+ schemas) | The wire protocol version and message/request envelopes. |
ok / notFound / invalidRequest / validationError / rejected / conflict / backendUnavailable | Canonical result constructors, re-exported from the authority. |
Result / Resource / Issue / RejectReason | The canonical result vocabulary types. |
engine-api is the semantic authority for the canonical result vocabulary; the Zod shapes live in
@faceless-photolib/schemas and are re-exported here so callers import them from one place.
License
MIT
API reference
19 public exports · 15 documented · generated from source.
createEnginefunctioncreateEngine(deps?: EngineDeps): EngineConstruct the in-process engine. Optional {@link EngineDeps} inject the source resolver / codec / surface; the zero-arg `createEngine()` call stays valid (an image render then fails loud for want of resolvable pixels, never faked).
createWireTransportfunctioncreateWireTransport(engine: Engine, options?: WireTransportOptions): WireTransportCreate the wire transport over an existing in-process engine. If no `onNotify` is supplied, change events for wire `subscribe`-d documents have no channel to be pushed through — so the default forwarder fires a `warnNotImplemented` beacon naming the missing server→client notification message (the frozen `WireMessage` schema defines none) rather than dropping the event silently. Listed in notImplementedRemaining as the wire-notification channel.
Engineinterfaceinterface EngineThe engine capability surface. Identical in-process and over JSON-RPC. Every operation returns a canonical `Result`/`Resource`, never throws across the boundary, and validates its request with `safeParse` before any side effect.
EngineDepsinterfaceinterface EngineDepsDependencies the in-process engine wires together. All are optional so the frozen zero-arg `createEngine()` call sites stay source-compatible (mirroring `backend-cpu`'s `createBackend(resolveSource?)` — the sanctioned injection pattern for inputs the frozen signatures cannot carry). The frozen `GpuBackend` port and the `Engine` surface carry no asset-bytes ingestion point (CAS references assets by hash), and `codec.decode` is async while the CPU `SourceResolver` is synchronous — so source pixels must be injected up front. With no resolver, an image-layer render fails loud (`error`) exactly like `unresolvedSource()`, never fabricated pixels.
InteractionSessioninterfaceinterface InteractionSessionAn in-progress interaction session opened by `beginInteraction`.
Subscriptioninterfaceinterface SubscriptionUnsubscribe handle returned by `subscribe`.
WireTransportinterfaceinterface WireTransportThe wire transport: dispatch an untrusted message against the wrapped engine.
WireTransportOptionsinterfaceinterface WireTransportOptionsOptions for {@link createWireTransport}.
ChangeEventtypetype ChangeEventA change event emitted on the `subscribe` stream.
Commandtypetype CommandInsertPositiontypetype InsertPositionTransportRequesttypetype TransportRequestWireMessagetypetype WireMessageWireResponsetypetype WireResponseA wire-dispatch outcome. Synchronous operations (`renderRegion`, `subscribe`, `beginInteraction`) and async ones (`openDocument`, `applyCommand`, `exportImage`) all flow through a single `Promise`-returning dispatch, so the transport surface is uniform. The payload is the canonical `Result`/`Resource` the matching `Engine` method returns; a session/ subscription handle is non-serializable, so the wire transport reports the establishment outcome as a canonical `Result` carrying the live handle for the in-process embedder (a network transport would substitute a token).
CommandSchemaconstconst CommandSchemaThe named command op-set as a discriminated union keyed on `op`, mirroring document-model's `DocumentOp` 1:1 (engine-api spec: "ApplyCommand Exposes the Named Document Op-Set" lists all 11 ops). The original frozen stub carried only the seven scalar ops whose payloads need no full `Layer`/`InsertPosition` shape; the four structural ops (`addLayer`, `reorder`, `addAdjustment`, `group`) are added here so the typed `Command` covers the whole spec op-set and the acceptance test's `applyCommand(addLayer)` is expressible. The additive members leave every prior constructor unchanged.
InsertPositionSchemaconstconst InsertPositionSchemaWhere to insert a layer relative to the stack/group (index 0 = bottom). The Zod mirror of document-model's `InsertPosition` so the structural-add ops (`addLayer`, `addAdjustment`) and `reorder` carry a `safeParse`-able target.
TransportRequestSchemaconstconst TransportRequestSchemaThe full request union accepted at a transport boundary.
WIRE_VERSIONconstWIRE_VERSION: 1The wire protocol version this build advertises.
WireMessageSchemaconstconst WireMessageSchemaAn envelope wrapping a request with the wire version for negotiation.