faceless-photolib

Overview

A content-addressed, history-preserving, LLM-native successor to OpenRaster — and why this repo builds it.

FPD (working name — see Naming below) is a native document format for layered image editing: content-addressed, branching-history, worker-hosted, and built to make an AI-assisted edit ("same mask, three models, three results") a first-class, losslessly-storable fact rather than something every tool reinvents. faceless-photolib — the headless, color-managed, GPU-accelerated engine documented in /docs — is the format's reference implementation: it already ships a reference renderer (CPU golden backend + WebGPU, with conformance gates), which is exactly what a new format needs to avoid the fate described below.

Why a new format

OpenRaster (ORA) is the closest prior art — an open, layered, zip-based interchange format — and it stalled at v0.0.6 with no steward. Research into why (see Positioning) converged on one lesson: ORA tried to be a universal layered-image file with no dominant reference renderer, so no two apps agreed on how a document should actually look. PSD stayed relevant not because it is elegant but because apps depended on it. Meanwhile, nobody ships an open, layered format that also stores generative provenance — the prompt, the mask, the model, and a branching history of results — even though every AI image tool (ComfyUI, Firefly, Krita AI Diffusion) now generates exactly that payload with nowhere durable to put it.

Positioning

This section's content is a direct build-out of the llm-native-media-format research (OMEG) and the in-repo native-file-format change built on it. The research's own framing:

Not "PSD but open." The sharpest v0 is "a content-addressed, GPU-ready, history-preserving media document for AI-assisted image creation" — an immutable object graph with a mutable head pointer, not a giant editable ZIP.

Concretely, that means:

  • Reference-first, not file-first. A document is a small manifest plus a graph of typed refs into a content-addressed blob store — see Package anatomy. Directory-on-disk and single-file .fpd are two envelopes around the identical logical package, not two formats.
  • History is a persistent, branching DAG, not linear undo. The same parent state can produce three sibling results (three different models given the same mask) without duplicating anything they share — see History-DAG model.
  • A format without a reference renderer loses. faceless-photolib ships the renderer, golden images, and conformance gates before the format's spec was even frozen — the format is downstream of a working engine, not the other way around.

Ten invariants (research summary)

The full research fanned out ten parallel investigation streams plus two independently-produced from-scratch designs (the user's prior "OMEG" and an independent "Luma" design) that converged on the same architecture. The invariants that shape every decision in this /format section:

#Invariant
1Reference-first: manifest + graph of refs into content-addressed blobs, not "one big file."
2Manifest-prefix + content-addressed blobs: identify the file and locate the preview from the first few KB.
3Extensibility is a mechanism (skippable, versioned, preserve-unknown), not a wishlist — ORA died from unratified proposals.
4Master ≠ GPU cache ≠ preview: multiple representations per resource, never conflated.
5History = a persistent content-addressed DAG, not linear undo. Branches are sibling nodes sharing a parent.
6Store intent and result: the prompt/mask is scope, the rendered pixels are the source of truth.
7Filters: one declarative representation runs on CPU and GPU; WASM is an escape hatch, never canonical.
8Provenance: embed C2PA rather than reinvent it (schema envelope reserved; emission is out of v0).
9Wide gamut done right: linear-light, premultiplied, Rec.2020/ACEScg compositing — matches this engine's existing pipeline.
10A format without a reference renderer loses. Ship the renderer + golden images + validator first.

What ships in v0 — and what's explicitly deferred

The native-file-format change builds the format core; migration importers and this documentation are sibling changes. In scope for v0:

  • Canonical JSON + BLAKE3 content hashing with versioned ref strings (Ref grammar).
  • The package layout, validator, and golden fixtures (Package anatomy).
  • The branching history DAG with named heads, intent envelopes, and publish-time redaction (History-DAG model).
  • All format I/O (open/save/validate/preview) in a Web Worker behind a typed protocol (Worker API), with a standalone CLI validator (Validator usage).
  • DocV2: image-layer sources become a discriminated union that can carry a typed content ref, with a real DocV1 → DocV2 migration.

Explicitly out of v0 (per the research's own second-pass review and two external consultant passes): KTX2 tiled GPU pyramids, a custom binary container (the .fpd zip envelope is a placeholder — blobs stay byte-addressable so it can be re-enveloped later without rewriting them), C2PA emission (the intent envelope reserves the shape), full generative-provenance workflow round-tripping, and CRDT/multi-writer editing. PSD/ORA/Krita/flat-image import is the sibling format-migration-importers change — see the migration guides for the policy those importers ship under.

Planned: video layers

Video/animation functionality (video-layers, video-timeline in the corpus feature registry) is registered ahead of the engine implementation. The samples block below states that status explicitly — corpus samples tagged with a planned feature run as typed planned-feature checks in the Test Lab, never a silent skip, and become enforcing the moment the feature ships (its registry status flips, nothing else changes).

Samples — video-layersplanned
Run checks in Test Lab
Feature video-layers is planned — samples are registered ahead of the engine implementation and run as typed planned-feature checks, never a silent skip.

Preparing sample list…

Naming

The working extension is .fpd ("Faceless Photo Document"). The research's own working name, OMEG, collides with the unrelated OME-Zarr bioimaging community, so this repo does not use it; final naming is an open question in the native-file-format change's design doc.

Where to go next