feat(editor): add transient app state foundation
This commit is contained in:
34
core/AGENTS.md
Normal file
34
core/AGENTS.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Core Domain Model Rules
|
||||
|
||||
Follow these rules for all changes in `core/`.
|
||||
|
||||
## Purpose
|
||||
- `core/` contains pure domain types for the image editor: documents, artboards, layers, assets, ids, and geometry.
|
||||
- Keep it framework-free, runtime-light, and reusable by renderer, commands, persistence, and tests.
|
||||
|
||||
## Hard Rules
|
||||
- Do not import React, DOM APIs, UI components, storage, networking, filesystem, command handlers, or renderer code.
|
||||
- Do not add side effects, global state, caches, singletons, or environment-dependent behavior.
|
||||
- Prefer exported TypeScript `type`s. Add runtime code only when it is pure, deterministic, and domain-generic.
|
||||
- Keep domain files small and focused. One concept per file; re-export public types from `core/index.ts`.
|
||||
- Use `import type` / `export type` for type-only dependencies.
|
||||
- Preserve discriminated unions. Every `Layer` variant must have a stable `type` string.
|
||||
- Do not weaken domain types with `any`, broad `string | number` unions, optional fields, or nullable values unless the domain truly allows absence.
|
||||
- IDs are opaque aliases from `id.ts`; do not inline plain `string` ID fields in models.
|
||||
- Do not duplicate geometry shapes outside `geometry.ts`. Use `Vec2D`, `Size`, `Rect`, `Bounds`, `Transform`, `Mat2D`, and `CoordinateSpace`.
|
||||
- Avoid app/workflow concerns in names and fields. Domain models describe image-editing state, not UI state.
|
||||
|
||||
## Model Invariants
|
||||
- `ImageDocument` owns `artboards` and shared `assets`.
|
||||
- `Artboard` owns top-level `layers` and has document-space `bounds`.
|
||||
- `LayerGroup.children` owns nested layers; only groups have children.
|
||||
- `ImageLayer.assetId` must reference an `Asset.id` in the same document.
|
||||
- `BaseLayer.opacity` is normalized `0..1`; `visible` and `locked` are explicit booleans.
|
||||
- `Transform` stores position, scale, and rotation only; derived matrices/bounds should not be persisted on models.
|
||||
- `clippingMask.maskLayerId` references another layer by `LayerId`; do not embed mask layer objects.
|
||||
|
||||
## Changing Models
|
||||
- Before adding a field, decide whether it is core persisted state or derived/UI state. Derived/UI state does not belong here.
|
||||
- When adding a new domain type, create a focused file and export it from `index.ts`.
|
||||
- When adding a new layer kind, update the union in `layer.ts`, add a discriminant, and document its required relationships.
|
||||
- Keep names stable and serialization-friendly; assume these types may be saved, loaded, diffed, and migrated.
|
||||
Reference in New Issue
Block a user