# LayerForge frontend architecture The TypeScript files under `src/` are the frontend source of truth. The tracked JavaScript files under `js/` are generated by `build.bat` and must not be edited independently. ## Domain responsibilities | Domain | Responsibility | | --- | --- | | `app/` | ComfyUI extension registration, node lifecycle, and application composition | | `canvas/` | Canvas state, layers, rendering, interaction, tools, and layer panel | | `io/` | Input connections, tensor/image transport, and canvas output transport | | `mask/` | Mask editing, pixel processing, SAM, and matting integrations | | `media/` | Image/blob conversion, in-memory image cache, preview, upload, and export helpers | | `persistence/` | IndexedDB state, reference tracking, and state worker | | `shared/` | Cross-domain types and errors | | `utils/` | Small cross-cutting and UI helpers that have not yet earned a domain | | `log_system/` | Canonical logging implementation | ## Canonical modules These modules are the main seams between the frontend domains: - `app/canvas_view.ts` composes the canvas runtime without registering a second ComfyUI extension as an import side effect. - `app/layer_forge_connections.ts` owns graph identity, workflow connections, and ComfyUI event/WebSocket integration. - `canvas/canvas_history.ts` owns bounded undo/redo stacks and snapshot cloning. - `io/canvas_io.ts` owns image input/output transport and render/export coordination. - `media/image_cache.ts` owns in-memory image identity and cache lifetime; IndexedDB persistence remains under `persistence/`. - `mask/mask_result_utils.ts` owns shared mask-result conversion and application; editor-specific side effects stay in the individual integrations. - `persistence/contracts.ts` owns the shared persisted-state and worker-message contracts used by the database and persistence worker. New code should use these seams instead of reaching into another domain's implementation details. If a dependency cannot follow the direction below, introduce a narrow contract or move the shared behavior to the lowest domain that owns it. ## Dependency direction `app/` is the composition layer and may depend on the other frontend domains. The lower-level domains remain independent of application composition: - `shared/` must not import frontend domains at runtime; - `media/` must not import `app/`, `canvas/`, `io/`, `mask/`, or `persistence/`; - `persistence/` must not import `app/`, `io/`, `mask/`, or `media/`; - type-only imports may describe relationships without creating runtime dependencies; - ComfyUI-provided modules under `scripts/` are external runtime dependencies. The root `src/canvas_view.ts` file is the single served bootstrap. It invokes the registration function from `src/app/canvas_view.ts`; the implementation module itself must not register the extension as an import side effect. The dependency rules are covered by `tests/test_architecture_boundaries.mjs`. Frontend contract and characterization tests live in `tests/*.mjs`. Run `npm test`, `npm run lint`, and `npx tsc --noEmit` after frontend changes; run `build.bat` first when TypeScript, CSS, or template sources changed so the tracked `js/` output stays synchronized with `src/`.