OpenMerch SDK

Editor refactor program · branch feat/openmerch-sdk · last update 2026-07-11, physical ink rendering shipped — gates 5/5, visual matrix clean

Phases

0 · Git hygiene + branch outdone
1 · Baseline visual QA + feature matrix (3 surfaces)done
2 · SDK architecture spec + adversarial reviewdone
3 · Scaffold @openmerch/* + headless coredone
4 · Port studio surfacedone
5 · Port /design + delete Yjs/collab stackdone
6 · Port /customize buyer surfacedone
7 · Legacy sweep of next-appdone
8 · Final QA: golden E2E + visual diff + docsdone
9 · Extract @openmerch/garment-3d (WebGPU twin)done
10 · Direct-on-garment mm editingdone
11 · Print-process realismin progress

Decisions

Updates

2026-07-11 · Physically honest ink rendering shipped — every technique looks like its process

Step 3 of print realism is live. Committed prints now render through a real ink model instead of a flat decal: linear-light compositing with a white underbase on dark garments (visible as a physically plausible halo on jet black), per-technique film coverage and roughness, embroidery as analytic 0.4mm stitch rows whose thread direction and specular follow the artwork rotation, and weave that continues under thin ink instead of stopping at the print edge. A 36-shot evidence matrix (5 techniques × light/dark × 4 camera angles) was captured through the production preview page and inspected shot by shot — zero blocking defects; measured pixels match the spec equations by hand. The heavier material compile exposed a hidden timing assumption in the placement E2E gate (it probed before the twin was drag-ready and the camera orbited away) — the gate now waits on the viewer's real ready signal, and the full golden suite is 5/5 again. The tank's receiver-overlay art path was restored and smoke-verified live.

2026-07-11 · Print realism under way — spec binding, color + technique contract landed

The print-process realism spec survived two adversarial reviews plus an independent verification pass and is now binding (docs/specs/openmerch-print-process-realism.md). Steps 1–2 of six are shipped. Color foundation: OKLCH utilities with branded encoded/linear types, the faithful Khronos PBR Neutral curve with an analytic inverse, and one shared lightness source — the renderer, colorways, and stage selection all classify dark/light garments through the same OKLCH-L thresholds now (the old loader disagreed with the app about forest and wash-slate). A live emissive color-checker probe renders 16 swatches through the real WebGPU pipeline and round-trips within deltaE 0.0014 (gate: 0.02). Technique contract v2: every print technique (DTG, screen/plastisol, DTF, embroidery, sublimation) is a measured, provenance-commented variant — cured film height in mm, weave show-through, ink roughness, edge profile, underbase behavior — and a shared resolver picks legal techniques per zone with real garment-darkness context (sublimation is excluded on darks). A characterization test pins the render output byte-identical until the step-3 ink core swaps in; a Proxy-based consumption test proves no contract field is decorative. Step 3 (the physically honest ink render path: linear underbase compositing, physical stitch pitch, embroidery anisotropy with a real thread-direction field, weave continuity across the print edge) is implementing now.

2026-07-11 · Direct-on-garment mm editing shipped — placement gate green

All seven steps landed. Users drag, resize, and rotate the committed print directly on the 3D garment with a live mm HUD; the HUD, the WebGPU decal, and the manufacturing export all derive from one panel-space mm frame (derivePanelSpaceExportFrame + compileAreaPlacement), so what you place is what gets printed — parity is asserted by unit fixtures at 0°/30°/90° and non-uniform scales, and out-of-raster placements are refused before Canvas can silently crop. Committed decals now project with true rotation (the old axis-aligned bounds projection stretched rotated art). QA evidence: a new golden gate (openmerch-placement-parity.test.ts) drags on the twin, reads the dock mm, saves, reloads, and requires exact restore; the placement-preview benchmark holds p95 0.5ms / max 0.6ms across 120 frames (4ms budget). The pass also root-caused the flaky Gate 1: the save indicator's exit animation kept the stale "Saved" label visible for ~200ms after an edit, so the E2E's text poll reloaded before the debounced autosave fired and the back-area edit was lost. Save gating now asserts the raw machine via data-save-status — Gate 1 went 5/5 after three consecutive suite failures before the fix.

2026-07-10 · @openmerch/garment-3d extracted — all surfaces QA green

The ~18k-LOC WebGPU garment twin now lives in @openmerch/garment-3d: viewer, loader, surface picker (panel-space mm), print-surface contracts, technique appearance, and the product-neutral color pipeline. The licensing boundary holds — Printify-derived data (asset URLs, receiver-surface registry, print areas, fabric textures) stays in next-app and is injected through four required loader dependencies on the viewer; a boundary scan in the package typecheck keeps it that way. packages/next-app/src/components/3d/webgpu is deleted and all consumers (/customize, /garment-preview, /design-studio, studio mockup scenes) import the package. Verified: package tests 52/52, scoped app suites 36/36, typecheck + boundary scans clean, golden gates 4/4, and hands-on browser QA of all four surfaces with zero page errors — including the authed studio in both 3D modes ("On the item" and the "In use" live scene). Along the way the pre-push preflight got a real fix: a lint chunk containing only biome-ignored markdown files no longer aborts the push. Next: direct-on-garment mm editing on top of the extracted surface picker.

2026-07-07 · Final QA done — golden gates green, program complete

Phase 8 shipped in five commits. 9e2baba368 finishes the interrupted ColorField repair (hex input keeps a focused draft; 3-digit shorthand expands only on blur/Enter — the studio baseline defect — with 7 regression tests). 742137992 lands the golden E2E merge gates (save→reload parity across both print areas, publish gating, tee + cap add-to-cart with metadata) and deletes the five Yjs-era Playwright suites; 4/4 green on three consecutive runs. 4ea5f9f214 fixes three Major /customize baseline defects (hardcoded “tee” CTA, order-summary sliver, artwork/currency honesty on the cart line). 7aaef82af2 fixes a live studio regression the QA pass caught: fill edits updated the panel but never the canvas, because the resolver didn't know EditorProvider-mounted engines — @openmerch/react now exports useOptionalEngine and the resolver checks it. Final-QA evidence (30 shots + defect-disposition matrix vs the 2026-07-05 baseline) lives in harness/evidence/openmerch-final-qa/REPORT.md; SDK docs landed as README.md in @openmerch/core and @openmerch/react. Every Major+ baseline defect in scope is fixed or architecturally eliminated; open remainder is cosmetic polish + the env-lane studio org-drift.

2026-07-06 · Legacy sweep done — 30k lines of editor-era code deleted

Three commits: 28c4ecb892 rewires the bare useCanvas hook through the canvas-service registry (it read a provider no production surface mounts, so shadow/matting/style controls silently no-oped — shadow toggle now verified live on /design); d526f3c291 drops the dead segmentation hook and the CanvasDO-era JWT draft scope; 74ada30b38 deletes 147 orphaned files (29.3k lines): old agent chat panels, fabric-canvas services, mobile tree, template gallery, layers panels, 46 components/editor orphans, 27 ai-elements files, dead canvas hooks and design config. The set was cross-verified by an independent import-graph audit and a clean-config knip scan, and A/B-tested: the full vitest suite is bit-identical with and without the deleted files (56 pre-existing environment failures, logged for final QA). All three surfaces smoke clean. Deferred: ~160 unused files outside the editor scope (landing pages, explore, ecom, social, dev tools) — dead but not editor legacy; separate cleanup decision.

2026-07-06 · /customize runs on the SDK — all three surfaces ported

Commit 94a12d6f62. The buyer studio's workplane dropped its bespoke snapshot-array undo/redo and now mounts a per-zone CanvasService: object add/delete/duplicate, z-reorder, clear-all, and history all go through the engine managers, with history:update driving both the button state and the debounced commit back to the garment (that last part covers undo-to-empty, where no object events fire). The port surfaced two engine-level findings. One in the app: fabric v6 IText measures ~2x too wide before it's attached to a canvas, so computing a centered position up front mis-placed text — placement now adds first, then centers. One real bug in core: history restore passed a completion callback as loadFromJSON's second argument, which fabric v6 treats as a per-object reviver — the final render never ran, leaving the visible canvas stale after every undo/redo (and permanently blank on undo-to-empty). Completion is the returned promise; fixed at the source with tests moved to the promise contract. Live QA on :3005, zero page errors throughout: add text/shape, ink recolor, font swap, duplicate, reorder, delete, clear-all, undo/redo round-trips (both workplane and garment texture), Front↔Back zone switching with design restore, and the Done handoff — the Art panel picks up the studio artwork with placement controls live.

2026-07-06 · the Yjs/collab stack is gone

Commit cb30fe6eb2 deletes multiplayer end to end. next-app lost src/sync (orchestrator, yjs adapter, awareness, predictive sync, telemetry), the collaboration components/hooks, the proof-snapshot JWT plumbing, the /api/canvasdo routes, and the whole orchestrator/awareness/collaborator slice of the editor store — undo/redo and the history timeline now run purely on the SDK CanvasService registry. shared dropped its yjs mapping modules. In worker-editor the 1,800-line CanvasDOYjs durable object is deleted; the MCP session/actions API it secretly hosted was re-homed verbatim into a dedicated McpSessionStore DO (wrangler migration v8-mcp-session-store), and jwt-auth lost its proof-scope and DO-name path sniffing. yjs, y-protocols, y-websocket, and lib0 are out of every package.json. Verified live: worker boots, MCP session create→action→readback round-trips on :5173, /design renders and edits with zero console errors on :3005. next-app + shared + worker typechecks clean; 155/155 worker tests and 25/25 touched next-app tests green, including new McpSessionStore coverage.

2026-07-06 · studio runs on the SDK, live-verified

The studio surface is the first consumer of the full SDK stack: @openmerch/react is real (EditorProvider + hooks, its own boundary rules and tests), and studio's save path now flows through the DocumentController — DesignDocument in/out, a rolling design_versions row per draft, thumbnails to Cloudflare Images, old payload shapes folded forward on read with their writer deleted. Live parity gate caught two real engine bugs before sign-off: the mount baseline marked every freshly opened document dirty (phantom autosave on open), and undo was off-by-one — the first click restored the state you were already in. Both fixed at the source: history is now an explicit checkpoint model where mount re-baselines and a lone baseline is not undoable. Verified in the browser: open→idle, edit→Unsaved changes→Saving…→Saved, reload persists the design with undo/redo correctly disabled, single-click undo/redo round-trips. 497 core + 3 react tests green.

2026-07-06 · the engine lives in the SDK now

The whole canvas engine — Fabric object model, CanvasService with all its managers, event bridge, snapshot/export, guides — moved out of the app into @openmerch/core. ~40k lines, originals deleted, 168 app files rewritten to import the SDK, Tilpas-branded engine names neutralized. The engine's last app couplings (zustand stores, the dead multiplayer seam, a server action) were severed first in a separate surgical pass. Verified end to end: core's boundary check + 483 unit tests green, app typecheck green, and a live browser run — editor boots, draft creates, a rectangle lands on the canvas and in the layer list with zero page errors (screenshot below). Test debt went down, not up: 26 previously-failing fabric tests now pass under core's test setup.

2026-07-06 · @openmerch/core is real

First SDK code landed. @openmerch/core now holds the versioned document schema (one document owning N print-area subtrees), the save-state machine where "Saved" can only ever mean an acknowledged write (unit-tested), typed redacted error envelopes, and all five provider seams: persistence, asset storage, AI image ops, fonts, POD. Import boundaries are enforced in CI from the first commit — core physically cannot import React, Next, or app code. garment-ir is renamed to @openmerch/garment-ir. Now extracting the ~40k-line canvas engine out of the app: a surgical pass is severing its store/sync couplings in place, then the wholesale move into core.

2026-07-06 · spec reviewed and hardened, scaffolding starts

Adversarial review done: an independent gpt-5.5 pass produced 20 evidence-backed findings; all folded into the spec. Biggest upgrades: a save-state machine where "Saved" only ever means an acknowledged write, versioned document schema with migrations, full undo/history semantics (batching, branch-aware, selection excluded), typed + redacted error envelopes on every provider seam, and a hard ordering rule — the SDK save path must prove save→reload parity before Yjs gets deleted. Now scaffolding @openmerch/* and the headless core.

2026-07-06 · baseline QA complete, big catch on /design

All three surfaces baselined with reports + ~70 screenshots (committed + pushed). Headline finds: /design autosave is silently broken — saves ride the Yjs websocket, the client falls back to an anonymous token before the user session hydrates, and the worker rejects every connection; the UI shows "Saving…" forever and a reload loses your edits. Strongest possible validation of the "delete Yjs, save through an explicit persistence adapter" decision. Also root-caused the editor boot hang: worker-editor was missing its Printify API key (env drift — fixed, boot passes now). /customize has a squeezed order-summary line + hardcoded "tee" CTA; studio's hex input mangles 3-digit colors; /design's crop inputs render garbled digits. Full defect tables live in harness/evidence/openmerch-baseline/.

2026-07-05 · baseline QA running

Found your pnpm dev next-app had died (port 3000 is your MedicalTextbook dev server); tilpas now runs on :3005 against the hosted dev Supabase. Provisioned QA fixture user qa-openmerch@tilpas.test via admin API. Three parallel QA agents are now exercising /customize, /tilpas/studio, and /design end to end with screenshot evidence, while a fourth maps all editor code for the SDK spec.

2026-07-05 · kickoff

Repo cleaned: recovered the uncommitted buyer-pack task, deploy hygiene, and docs into three grouped commits on codex/sota-garment-twin-plan, then branched feat/openmerch-sdk. Code-map agent is sweeping all editor code; baseline QA of the three surfaces starts now.

Screenshots

/customize on the SDK: studio→Art panel handoff
studio on the SDK: Saved after reload parity
/design running on @openmerch/core
/design editor (baseline)
/design image AI tools
/design branch-aware history
studio 3D on-the-item
/customize buyer surface
defect: boot gate dead-end (root-caused)