# Entities and Components

## Retained data, immediate drawing

`Canvas_Scene` stores an arena-backed array of `Canvas_Entity`. Each entity has:

- a stable `id` for external resources such as browser views;
- `type`, world `position`, and world `size`;
- generic semantic fields: `text`, `value`, and `active`;
- optional rich-context fields such as a conversation title and agent working
  state;
- interaction/animation state;
- pinning state in both world and screen coordinates.

The scene is retained, but the draw list is rebuilt every frame. This keeps
interaction and context state stable while allowing normal Raylib immediate-mode
drawing.

Each entity also owns lifecycle state. `visibility_amount` eases from zero to
one after creation. Delete and developer Clear mark entities as `removing`, ease
them back to zero, then compact the retained array. Raylib colors, native CEF
texture tints, and WebAssembly overlay opacity all consume the same eased value.

Treat animation as part of every entity state transition, not optional polish.
State changes set retained targets; frame updates ease visual geometry and
opacity toward those targets. Do not snap expandable, collapsible, selected,
hovered, created, removed, or otherwise stateful entities between layouts.
Conversation collapse/expand uses the same smoothstep height interpolation as
accordions, while preserving its final semantic `active` state for context.

## Adding a component

Wire every relevant surface, not only drawing:

1. Add the enum value in `canvas.h`.
2. Set useful size, text, and state defaults in `Canvas_Scene_Add()`.
3. Add bounds/picking behavior in `Canvas_Entity_Bounds()` and
   `Canvas_Entity_Contains()`.
4. Add click behavior in `Canvas_Scene_Activate()` and specialized update logic
   in `Canvas_Scene_Update_Interaction()` when needed.
5. Draw it in `Canvas_Draw_Entity()` and support selection in
   `Canvas_Draw_Selection()`.
6. Return a readable label from `Canvas_Entity_Type_Name()`.
7. Serialize meaningful state in `Canvas_Context_Append_Entity_State()`.
8. Add focused tests in `canvas_test.c`.
9. If it owns external pixels or DOM, extend both web-surface backends and key
   resources by stable entity ID.

Prefer a single entity for large compound views. The Lucide gallery is one
entity with virtualized internal rows, not 1,767 independently draggable scene
objects.

## Input ownership

Input is resolved from most specialized to most general:

- developer UI;
- focused native CEF content;
- the canvas URL editor or local dictation bridge;
- hovered/pressed scene entity;
- camera.

Open developer dropdowns and the snapshot-name editor are modal because Raygui
consumes keyboard or outside-click input while editing. While either is open,
native web surfaces, canvas entities, dictation hotkeys, and camera movement do
not receive that input.

Text editing blocks WASD/arrow camera movement. Scrollable entities consume an
unmodified wheel. Ctrl/Cmd + wheel remains available to the camera for anchored
zoom; an unmodified wheel outside a scrollable entity pans vertically.

Text areas keep cursor, selection anchor, and vertical scroll state on the
entity. Their visual-line layout is shared by drawing, hit testing, vertical
cursor movement, and caret visibility, so wrapped text and mouse selection use
the same geometry. Ctrl on Windows/Linux and Cmd on macOS drive select/copy/
cut/paste shortcuts; Ctrl or Option performs word navigation. A selected text
area exposes a bottom-right resize handle. Dragging it changes both dimensions,
reflows wrapped lines immediately, and keeps the caret within the scrollable
viewport.

## Snapshot boundary

Developer Controls saves named native snapshots under the user state directory
as versioned `.zmap` files. The encoder writes explicit little-endian fields
rather than copying `Canvas_Entity` memory, then uses a payload checksum,
bounded entity count, finite geometry validation, and an atomic temporary-file
rename. Loading is transactional: the live scene is not cleared until the
entire snapshot validates.

The current snapshot preserves numeric canvas entity IDs because conversation
routing uses them. Those IDs are canvas-local handles, not final
cross-workspace identities. Domain data should eventually normalize into
stable keys such as `conversation_id`, `asset_id`, and `component_id`; an
entity snapshot should retain only the typed key plus its visual state.

Transient pointers, CEF surfaces, Copilot SDK sessions, hover state, active
agent work, and removal animations are never serialized. Browser and image
surfaces reconstruct from their retained HTTP(S) source after load.
