Editing UI & Canvas¶
The most reused-from-existing-code area of this whole design and, in terms of an actual screen anyone could look at, still the least designed. Real, verified reuse exists for most of it; what's net new is the property panel, the layer list, undo/redo, the promote-selection-to-Element step, and three concrete requirements that surfaced from working through Element mechanics rather than from a wireframe.
Reuse map¶
Checked directly against the code rather than assumed:
| Existing code | Generalises into |
|---|---|
| Template Editor's Library | The Element picker |
| Campaign Editor's sticker mechanism | Canvas placement |
| Template Editor's board | Scene sequencing |
| Template Builder's publish step | Publishing |
Template Builder's EditStep (minus PSD parsing) plus pieces of Campaign Editor |
The Element-authoring tool — a new tool, not a repurposed Sticker Builder |
A genuine shared core already exists underneath both current canvases — CanvasSelectionOverlay.tsx
(hit-testing, per-layer selection boxes, locked-layer handling, and a shipped
renderPrimaryManipulator extension seam), the anchor/geometry helpers, the guides overlay — and
Composer's canvas can build on it directly. The geometry it draws a ring around comes from the same
solveScene / animateScene the renderer uses under the engine, which retires useLayerLayouts's
own interpolation copy (Resolver Engine → The Motion Graph) — the only way a flow or pin
layer's ring can be right.
Sticker Builder (NEO-1315) is not the base for Element authoring
It parameterises existing SVG artwork (no blank canvas; editing means promoting specific SVG nodes into slots) rather than composing a structured layer tree, and its document schema stores raw SVG as a string — a genuinely incompatible data model to Composer's typed primitives. Its wizard/slot-editing UX is worth borrowing conceptually, nothing more. Its code is still relevant to one narrower question — migrating today's existing sticker definitions into the Element system — assessed only by reputation so far, never actually read.
The Element-authoring tool: extract TemplateBuilder's core¶
Investigated before assuming this needs building from scratch: the two missing pieces mostly already
exist as working code. TemplateBuilder's EditStep already places and configures primitives —
canvas, layer list, add-layer menu, layout and timing editors — on the exact layer schema Composer's
Elements use; its ManifestBindingsEditor already does the "mark this property exposed, choose its
control, label it" workflow Element authoring needs. AddedLayerEditor already lets users place and
configure typed primitives directly in a Scene today, so users placing primitives is not new
ground.
What's missing is the outer container, not the core: EditStep is built around a whole Template
document rather than an Element-scoped one; its save path targets the existing template tables
rather than Composer's identity/version tables
(Identity, Versions & Schema Versioning); its access today
is a blunt route-level super-admin gate rather than a real capability check
(Permissions & Enforcement); and there's no existing concept of
promoting a selection into one saved, reusable, versioned unit — that promotion step is
genuinely new. Everything else is an extraction and retargeting job.
Promotion flattens; it never nests
Because an Element can never contain another Element, promotion cannot simply wrap the selected
instances. It flattens them: the selected wrapper Elements' internals are copied into the new
Element's own layer list, their layer ids re-scoped to it, their manifest bindings merged into
one manifest, and each instance's setInstanceField / setInstanceLayout overrides folded into
the layer values they were overriding. A selection containing a genuinely authored (non-wrapper)
Element is rejected rather than silently inlined, since flattening it would fork a shared
Element's contents away from the Element that owns them. Promotion needs Element create
permission, plus the composing rung to have selected the instances in the first place.
Not a separable side project
This is part of the same undesigned canvas/UI work this page flags as needing its own planning session (Blair's call, below), not a parallel track with its own timeline — and it needs the tier design as well as the schema, since it's gated by three real permissions.
What's net new¶
The property/field panel, the layer list, undo/redo, and the promotion step above. The first three
exist today as two separate implementations, not a DRY violation waiting to be deleted: Template
Builder's useDocumentHistory (whole-document snapshot) versus Campaign Editor's
useRetailStudioStore operation-log; RetailStudioPropertyPanel (tier-gated via
useEffectiveLayoutMode) versus EditStep's inline equivalent; BuilderLayerList.tsx versus
RetailStudioLayerPanel.tsx. Composer's are realistically a third, purpose-built implementation
borrowing the tier-gating pattern from Campaign Editor and the richer transform concepts from
Template Builder. Matthew has flagged this category of work as having a rough historical track
record for this team.
Decided: undo/redo is an operation log whose entries are Changes
A session-local, uncompacted history of what the editor emitted, stepped backward and forward —
not a second, TemplateBuilder-style whole-document-snapshot stack, and not the fork's stored
Change[], which is compacted and has no sequence to step through
(The Change Model).
Each entry is a { change, inverse } pair captured at emit time, not a bare Change: a
setInstanceField carries the new value and not the old one, so the inverse has to be recorded
when the editor still knows what it replaced. A compound action — the agent's "swap Element A
for B" (AI / Agent Forward-Compatibility) — is one entry holding
several pairs, so it undoes in one step; pushFieldBatchUndo in useRetailStudioStore is the
existing precedent for exactly that batching.
Three requirements surfaced from Element mechanics¶
A placement-resize control on the authoring canvas¶
The authoring canvas needs a resize control that simulates placement-time resizing, independent of whatever default size the Element ships with, since that's the only way to verify its internal layers respond correctly once placed at a size other than the one it was authored against (Elements, Scenes & Projects).
The schema-migration placement dialog¶
Placing a reference whose schemaVersion.major is behind current needs a confirmation dialog
offering migration, and placement must still succeed if the user dismisses it or lacks permission to
migrate. The mechanism, the prompt, the minor-behind exemption, and why it never gates are on
Identity, Versions & Schema Versioning;
what belongs here is only that the dialog is a screen someone has to build.
A standalone migration action outside placement¶
Whatever view already lets a user browse or manage an Element / Scene / Project's own identity — a catalogue or library screen — needs a "run migration" action reachable there directly, independent of placing anything: the same action, the same fork-and-commit, the same permission as the dialog; the only new UI surface is where it's reachable from. Why it's needed is on Identity, Versions & Schema Versioning.
Deferred: PSD import¶
Importing a PSD gets harder under the Element model: a Scene is built from Element instances rather than bare primitives, and matching an arbitrary PSD's layers against a whole library of authored Elements is a real recognition problem that doesn't exist today. Not a blocker — anything unmatched can become its own trivial, single-primitive Element via the wrapper mechanism — it just loses Composer's actual point for that layer. Picked back up at a later date.
Design-system consistency¶
This is Shane's domain. Beyond the reuse/net-new split above, Composer's UI needs clear component/pattern reuse rules so it stays visually and interaction-consistent with Neosframe's established design system — a consistency concern, not just code reuse for engineering convenience.
Decided: the existing Neosframe Component Library
The same Figma library the design-standards gate already references, no separate
Composer-specific artifact.
Risks¶
- A specific, undiagnosed recurring failure pattern behind the team's historically rough UI work — never explicitly named, only referenced as a pattern to avoid repeating.
- Whether real usage friction from today's existing sticker feature (which nobody has formally reviewed) already predicts problems Composer's canvas is about to reinherit.
Open questions¶
- How much of the underlying system — schema, Change model, permissions, storage — needs to exist before UI work can meaningfully start, versus how much can be explored in parallel against a moving target. Needs a dedicated planning session the team hasn't had yet, and now also determines when the Element-authoring tool can begin. Blair's call, not this brief's.
- No wireframe or concrete flow exists yet for any Composer-specific screen.
- The actual UI and permission wiring for user-facing Element authoring, and how the tier design carries the three Element permissions.