From 678a0a40a783a1bc8d67270b37d2d631e472d819 Mon Sep 17 00:00:00 2001 From: syntaxbullet Date: Fri, 10 Jul 2026 23:23:07 +0200 Subject: [PATCH] refactor: update product audit with design recommendations and clarify candidate session handling --- ...026-07-09-product-ux-architecture-audit.md | 220 ++++-------------- 1 file changed, 42 insertions(+), 178 deletions(-) diff --git a/docs/audits/2026-07-09-product-ux-architecture-audit.md b/docs/audits/2026-07-09-product-ux-architecture-audit.md index d2d90d6..06a5f23 100644 --- a/docs/audits/2026-07-09-product-ux-architecture-audit.md +++ b/docs/audits/2026-07-09-product-ux-architecture-audit.md @@ -10,13 +10,13 @@ Implementation update, 2026-07-09: the Phase 0 strict TypeScript baseline has be Image Studio has a substantially better technical foundation than its current interface suggests. The document model supports artboards, nested groups, image and raster layers, masks, transforms, assets, generation provenance, selection, command history, and non-destructive generation candidates. The command-only state write path and read-only renderer are especially valuable foundations for a serious editor. -The main problem is that the product is still expressed as a collection of prototype controls rather than a coherent workflow. Generation is treated simultaneously as a tool, a settings panel, a canvas preview mode, and a dense bottom action bar. Layers, masks, generation candidates, document actions, transform properties, shortcuts, and debug commands compete for attention without a stable hierarchy. The current visual language amplifies this by rendering almost every surface as a translucent rounded island. +The main problem is that the product is still expressed as a collection of prototype controls rather than a coherent workflow. Generation is treated simultaneously as a tool, a settings panel, a canvas preview mode, and a dense bottom action bar. Layers, masks, generation candidates, document actions, transform properties, shortcuts, and debug commands compete for attention without a stable hierarchy. -The recommended direction is a complete visual and workspace redesign while retaining the document, command, input, and renderer foundations. The new product should be organized around three durable concepts: +Further product work should retain the document, command, input, and renderer foundations and organize behavior around three durable concepts: 1. **Document** — artboards, editable layers, masks, groups, transforms, and provenance. 2. **Operation** — select, transform, paint, mask, remove background, inpaint, outpaint, and generate. -3. **Result tray** — temporary model outputs that can be compared, refined, accepted, combined, or dismissed without prematurely mutating the document. +3. **Candidate session** — temporary model outputs that can be compared, refined, accepted, combined, or dismissed without prematurely mutating the document. ## Audit method and limits @@ -70,13 +70,13 @@ Severity meanings: - **P0** — blocks treating the project as safely maintainable. - **P1** — breaks or obscures a primary product workflow. - **P2** — significant friction, inconsistency, or scaling risk. -- **P3** — polish and cleanup that should follow the structural redesign. +- **P3** — lower-priority product polish and cleanup. ### P0 — strict TypeScript validation fails — resolved 2026-07-09 `bunx tsc --noEmit` fails despite tests, ESLint, and the production build passing. Current failures include unsafe layer narrowing, possibly undefined mask access, generic select-menu handlers, canvas typed-array incompatibilities, a resize hook call, input test typing, and the two currently modified Comfy files. -This creates a false-green validation story: production assets can build while the architecture's type contracts are already drifting. Strict type checking should become a required baseline before the redesign begins. +This creates a false-green validation story: production assets can build while the architecture's type contracts are already drifting. Strict type checking should be a required validation baseline. Resolution: the affected layer narrowing, optional mask access, generic select handling, typed-array inference, resize-hook initialization, input-test dispatch typing, and current Comfy adapter typing were corrected without weakening the domain unions. The new `typecheck` and aggregate `check` scripts make the baseline repeatable. @@ -86,7 +86,7 @@ The app can import images and export an artboard PNG, but there is no project sa For a layer-based editor, this is not an optional feature. Without it, the product cannot fulfill “turn an AI image into an editable project” beyond a single browser session. -Redesign implication: the workspace needs document identity and save state in its persistent chrome. The architecture needs an asset persistence strategy before project import/export is presented as complete. +The architecture needs an asset persistence strategy before project import/export is presented as complete. ### P1 — generation mode is hidden while infrastructure settings are promoted @@ -103,15 +103,13 @@ Generation appears as: - A right-side settings sheet. - A bottom action island containing execution, status, candidate navigation, comparison, regeneration, acceptance, mask editing, and dismissal. -These surfaces do not form a legible sequence. “Generate” is closer to a workflow or operation workspace than a pointer mode. Treating it as a normal canvas tool also makes panel visibility and keyboard behavior artificially coupled to `activeTool`. - -Redesign implication: generation should open an operation workspace with a clear input stage and a result stage. The active canvas interaction inside that workspace can still be select, pan, paint-mask, or transform. +These surfaces do not form a legible sequence. “Generate” is closer to an application operation than a pointer mode. Treating it as a normal canvas tool also makes panel visibility and keyboard behavior artificially coupled to `activeTool`. ### P1 — accepting one candidate destroys the entire candidate session — resolved 2026-07-09 Both “accept as layer” and “replace pixels” call `clearCommittedGenerationPreview`, which clears all candidates, not only the accepted candidate. This conflicts with the core use case of combining multiple model outputs. A user who generates several alternatives and accepts one loses the remaining comparison set. -Redesign implication: accepting a candidate should mark or remove only that candidate by default. The result tray should support keeping, pinning, multi-selecting, and clearing the session explicitly. +Accepting a candidate should mark or remove only that candidate by default while preserving the rest of the session. Resolution: both layer acceptance and masked-pixel replacement now remove only the committed candidate, select the nearest remaining candidate, and preserve the active comparison mode while results remain. @@ -125,7 +123,7 @@ Resolution: the picker now renders the complete bounded candidate set in a horiz “Accept variant” creates a standard top-level layer and records `variant-layer` provenance. There is no document-level variant set, linked source, stack semantics, exclusive visibility, or comparison group. The label promises more structure than the product provides. -Redesign implication: either call this “Add as another layer” or introduce a real variant/result-set concept. A result tray can provide variant semantics without forcing them into the document tree prematurely. +Either call this “Add as another layer” or introduce a real variant/result-set concept. Resolution: the duplicate variant action and `variant-layer` provenance value were removed. The UI now describes the real operation as “Add as layer”; refinement layers use the same honest layer acceptance semantics. @@ -149,31 +147,6 @@ Generation jobs are application state, not ephemeral component state. They need Resolution: generation and candidate follow-up work now run through command-driven, bounded job state with stable IDs, lifecycle timestamps, and durable errors. The existing Generate controls consume that state, the top toolbar keeps activity visible across tool and panel changes, concurrent submissions are rejected authoritatively, and document undo/redo no longer rewinds job lifecycle state. Cancellation remains a future adapter capability because the current Comfy request path does not expose cancellation. -### P2 — the workspace lacks stable information architecture - -The current shell is a canvas surrounded by floating islands: - -- Top-right file, generate, export, and layers icons. -- Left vertical tool capsule. -- Right mutually exclusive sheet. -- Bottom contextual control capsule. -- Bottom-left shortcut encyclopedia. - -There is no persistent document header, inspector, operation status area, result tray, or clear distinction between modes, properties, document structure, and global actions. The layout works as a feature demo but will not scale with more editing operations. - -### P2 — the visual system is not actually centralized - -The global stylesheet includes generic shadcn-style light/dark tokens, while the product shell mostly uses raw Tailwind color literals, opacity values, bespoke radii, and repeated class-building functions. The main background uses decorative gradients and most surfaces rely on backdrop blur without a consistent opaque surface color. - -Consequences: - -- Contrast depends on whatever lies behind a control. -- Nearly every component invents its own surface and selected state. -- Rounded pills are used for containers, rows, inputs, menus, buttons, badges, and destructive actions, weakening hierarchy. -- A complete redesign cannot be implemented reliably through token replacement alone. - -Redesign implication: create semantic tokens and primitives after the new workspace hierarchy is approved, not before. Tokens should represent canvas, chrome, panel, raised surface, field, hover, selection, focus, warning, generation status, and mask-edit context. - ### P2 — tool semantics mix modes, operations, and effects The rail places Select, Generate, Brush, Eraser, Chroma Key, Magic Wand, and Pan at the same level. These are not peers: @@ -182,23 +155,15 @@ The rail places Select, Generate, Brush, Eraser, Chroma Key, Magic Wand, and Pan - Brush and Eraser are paint modes whose meaning changes during mask editing. - Magic Wand is a selection/mask operation. - Chroma Key is an effect-to-mask workflow. -- Generate is an AI operation workspace. +- Generate is an AI operation. -The redesign should classify tools by behavior, then decide whether they belong in the global rail, context bar, properties panel, or operation launcher. - -### P2 — layers carry too many actions but too little visual identity - -The Layers sheet includes artboards, tree nesting, visibility, locking, export, grouping, ordering, deletion, mask creation, mask coverage analysis, reveal/hide mode entry, raster mask operations, and rename behavior. Rows lack image or mask thumbnails and do not expose opacity, blend behavior, provenance, or core transform properties. - -The result is a dense management panel that still cannot answer the basic question “which visual element is this?” quickly. - -Redesign implication: use a durable document tree with thumbnails and compact row actions, then move selected-object properties and mask controls into a contextual inspector. Mask editing should become a clear editor mode, not an expanded sub-card full of unrelated actions. +Tool behavior should be classified explicitly so interaction modes and application operations do not share accidental state semantics. ### P2 — panel state ownership is inconsistent — resolved 2026-07-10 Generate visibility is derived from authoritative `activeTool`, while Layers visibility is local React state. `App.tsx` then manually enforces mutual exclusion across buttons, shortcuts, effects, and command-palette callbacks. -This works today but does not scale to more panels, inspectors, result trays, modal operation states, or workspace layouts. Meaningful workspace state should have one model and one transition path. +This works today but does not scale to additional application surfaces or operation states. Meaningful application state should have one model and one transition path. Resolution: workspace panel state and Generate/Layers mutual exclusion now live in `EditorState` and transition only through commands. React consumes the resulting snapshot without corrective panel effects or local application state. @@ -206,7 +171,7 @@ Resolution: workspace panel state and Generate/Layers mutual exclusion now live React/view modules directly orchestrate image decoding, object URLs, network requests, generation preparation, candidate acceptance setup, raster processing, download behavior, and Comfy model discovery. Important examples are `useImageImport.tsx`, `GenerateControls.tsx`, `GenerateActionControls.tsx`, `runGenerate.ts`, and the mask/chroma-key helpers. -These functions are testable only unevenly and blur the intended boundary that React should display state and capture intent. The redesign is an opportunity to introduce explicit application services/jobs without weakening the command-only mutation rule. +These functions are testable only unevenly and blur the intended boundary that React should display state and capture intent. Explicit application services/jobs should own these workflows without weakening the command-only mutation rule. Resolution: explicit `operations/`, `platform/`, and `server/` boundaries now separate application use cases, browser/runtime adapters, and backend integrations. View modules emit intent and retain only UI-local drafts/disclosures; operations are prevented from accessing browser globals by ESLint and continue to write state exclusively through commands. @@ -222,7 +187,7 @@ Resolution: imported files are decoded into serialization-safe data URLs before Undo and redo exist only as shortcuts/commands. Export exists in both the global top bar and every artboard row. Generate exists in both the rail and top bar. Fit/reset/zoom actions are split between transient bottom controls and the command palette. The command palette also exposes debug commands in the normal product surface. -The redesign should establish a predictable location for document actions and reserve the command palette for acceleration rather than compensating for missing UI. +Document actions should have one canonical invocation path, with the command palette acting as an accelerator rather than a separate source of behavior. ### P2 — accessibility is inconsistent @@ -241,105 +206,14 @@ Several files combine multiple responsibilities: - `commands/generation.ts` — 315 lines. - `view/bottom-controls/ChromaKeyControls.tsx` — 313 lines. -Line count alone is not a defect, but these files are already coordinating distinct concepts. The redesign should split by product responsibility rather than by arbitrary component size. +Line count alone is not a defect, but these files are already coordinating distinct concepts. Modules should split by product responsibility rather than by arbitrary component size. Resolution: document-tree mutation helpers, WebGL texture programs, command-palette item construction, layer mask controls, server routes, and browser raster adapters now have focused modules. The remaining larger files represent cohesive command or rendering orchestration rather than mixing those extracted responsibilities. -### P3 — prototype identity remains in project metadata and chrome +### P3 — prototype identity remains in project metadata The package is still named `bun-react-template`, the document defaults to “Untitled” without displaying that identity, the app has no visible product title, and debug palette items ship beside user actions. These details reinforce the prototype feel. -### P3 — the shortcut panel dominates the workspace - -The shortcut reference defaults open, occupies a 30rem-wide floating panel, and competes with the canvas. Shortcuts should be discoverable through tooltips, menus, a compact help entry, and an on-demand reference—not persistent primary chrome. - -## Proposed information architecture - -This is a structural proposal, not a visual design. - -### Persistent application frame - -**Top bar** - -- Product/document identity. -- Save state and project actions. -- Undo/redo. -- Export/share. -- Background job status. -- Command palette and help. - -**Left tool rail** - -- Select/transform. -- Pan/hand as a temporary or secondary navigation mode. -- Paint. -- Mask/select region. -- AI operation launcher. -- Tool groups can expand, but only true interaction modes remain persistently active. - -**Left or right document tree** - -- Artboards, groups, layers, and masks. -- Thumbnails and clear hierarchy. -- Compact visibility/lock state. -- Creation, grouping, ordering, and deletion. -- No model configuration or mask-processing controls. - -**Context inspector** - -- Selected object properties. -- Transform, opacity, mask relationship, provenance, and operation-specific parameters. -- Clear empty and multi-selection states. - -**Canvas** - -- The document and direct manipulation overlays. -- Temporary generation previews and compare affordances. -- Explicit mask-edit and operation states. - -**Result tray** - -- All current candidates, not an arbitrary subset. -- Selection, multi-select, pin, compare, dismiss, and accept. -- Candidate metadata on demand. -- Accept as layer, replace region, create masked refinement layer, or keep as reference. -- Remains visible while the user inspects document context. - -### AI operation workspace - -The user should begin with an operation, not a backend: - -1. Generate new image. -2. Transform selected image. -3. Replace or repair region. -4. Extend canvas. -5. Remove/replace background. -6. Create variations. - -Each operation declares: - -- Required document context. -- Prompt and references. -- Output frame and placement. -- Quality/profile preset. -- Optional advanced model controls. -- Expected result behavior. - -The product can then select a compatible architecture and expose technical overrides only when requested. - -## Visual redesign principles - -The new visual system should be created from scratch after wireframes validate the information architecture. - -1. **Canvas first, not chrome first.** UI surfaces should frame the work rather than float decoratively over it. -2. **Hierarchy through structure, not universal pills.** Use shape, spacing, typography, surface level, and borders intentionally. -3. **Stable panels for stable concepts.** Document tree and inspector should not appear and disappear like temporary tooltips. -4. **Context is explicit.** Mask edit, generation preview, job progress, and destructive replacement must be visibly distinct states. -5. **Progressive disclosure follows expertise.** Operation and intent first; sampler, scheduler, encoder, and VAE later. -6. **Generated results look provisional.** Candidates need a clear visual status distinct from accepted document layers. -7. **Every icon-only control has a name.** Labels, tooltips, focus states, and shortcuts are part of the component contract. -8. **Density is deliberate.** The layer tree can be compact; prompts and comparison views need space; destructive choices need clarity. - ## Architecture recommendations ### Preserve @@ -352,7 +226,7 @@ The new visual system should be created from scratch after wireframes validate t - Generation candidate and provenance concepts. - Nested group and mask invariants. -### Refine before UI migration +### Refine - Restore strict TypeScript cleanliness. - Model workspace/panel state consistently. @@ -363,13 +237,12 @@ The new visual system should be created from scratch after wireframes validate t - Separate application services from React presentation. - Add operation precondition selectors with user-facing reasons. -### Avoid during redesign +### Avoid -- Rewriting the renderer solely to support new styling. -- Encoding new visual layout concepts in the core document model. +- Rewriting the renderer without a product or performance requirement. +- Encoding presentation concepts in the core document model. - Adding more one-off local panel booleans. -- Treating every AI workflow as another permanent tool-rail icon. -- Building a large component library before the workspace wireframe is approved. +- Treating every AI workflow as a distinct persistent interaction mode. ## Recommended implementation sequence @@ -389,32 +262,33 @@ The new visual system should be created from scratch after wireframes validate t - Define operation-specific placement and prerequisites. - Define project persistence and asset lifecycle. -### Phase 2 — low-fidelity redesign +### Phase 2 — operation contracts -- Produce workspace wireframes for empty document, layered composition, mask edit, generation setup, generation running, candidate comparison, and candidate acceptance. -- Validate control ownership before choosing colors or component styling. -- Run the pending live visual/interaction audit against the old UI for comparison. +- Add operation precondition selectors with actionable failure reasons. +- Define output placement for text-to-image, image-to-image, inpaint, and outpaint. +- Define the valid acceptance actions for each candidate type. +- Add focused tests for missing context and placement behavior. -### Phase 3 — visual system +### Phase 3 — project persistence -- Choose the approved visual direction. -- Create semantic tokens. -- Build the application frame, buttons, fields, tree rows, inspector sections, menus, tooltips, dialogs, status elements, and result cards. -- Document accessibility and interaction states as part of each primitive. +- Define a versioned project serialization format. +- Persist asset data with explicit ownership and cleanup rules. +- Implement save, open, autosave, and recovery behavior. +- Add round-trip and migration tests. -### Phase 4 — shell migration +### Phase 4 — candidate-session capabilities -- Implement the new app frame around the existing canvas. -- Migrate document actions, tool modes, document tree, and inspector. -- Keep old workflow surfaces behind temporary boundaries until replaced. +- Support explicit session clearing and individual candidate dismissal. +- Add pinning and multi-selection only if concrete workflows require them. +- Surface provenance and reuse-settings actions through application operations. +- Keep candidate state provisional until an explicit acceptance command runs. -### Phase 5 — AI workflow migration +### Phase 5 — workflow consolidation -- Implement the operation launcher and context checks. -- Move generation settings into intent-first flows. -- Implement durable jobs and the result tray. -- Surface provenance and “reuse settings.” -- Retire the old Generate sheet and bottom candidate action island. +- Remove duplicate invocation paths that implement the same action differently. +- Keep model compatibility and defaults in shared application logic. +- Ensure generation jobs remain observable independently of mounted React controls. +- Verify undo/redo boundaries around accepted results and asynchronous jobs. ### Phase 6 — persistence and production hardening @@ -437,14 +311,4 @@ Run on 2026-07-09: ## Immediate next deliverable -Create low-fidelity wireframes for seven canonical states: - -1. Empty/new project. -2. Imported image with layers visible. -3. Selected layer with transform properties. -4. Mask editing. -5. AI operation setup. -6. Generation running with persistent job status. -7. Candidate comparison and multi-result acceptance. - -The wireframes should intentionally ignore the existing floating-island styling. They should test information architecture and control ownership before visual direction is explored. +Define and test operation preconditions and output-placement rules for text-to-image, image-to-image, inpaint, and outpaint. Each operation should report missing context explicitly and produce candidates with deterministic document placement.