# Rendering Architecture

TopoVec separates rendering into a small set of layers so that the same scene
and property model can be reused by multiple frontends.

The intended data flow is:

`System` / state -> buffers -> renders -> scene -> image container -> backend adapter

## Layer Roles

### `topovec.core.property`

`Property` objects describe editable parameters independently from any concrete
UI toolkit. They provide:

- a typed snapshot via `spec()`
- a mutation entrypoint via `let(...)`
- an `UpdateMask` describing which parts of the runtime must be refreshed
- optional `param_key` values for shared state across compatible scenes

This layer is backend-agnostic. Marimo widgets, headless helpers, and future
native applications can all consume the same property model.

### `topovec.mgl.buffer`

Buffer classes translate numpy arrays into GPU buffer layouts. They are
responsible for memory shape and upload/download mechanics only, not for scene
semantics or UI state.

### `topovec.mgl.render`

Render classes are the lowest-level ModernGL units. A render owns shaders,
uniform bindings, vertex arrays, and render-specific properties. A render does
not own scene orchestration, camera-slot policy, or backend integration.

### `topovec.mgl.camera`

`Camera` stores a backend-independent view state: orientation, center of view,
scale, and projection mode. Scenes and backends may serialize, restore, cache,
or replace cameras without depending on any specific UI toolkit.

### `topovec.mgl.scene`

A scene composes one or more renders into a user-facing rendering configuration.
It owns:

- the `System`
- scene state and scene-specific property groups
- camera-slot policy
- default camera policy for each camera slot
- upload/render orchestration across child renders

Scenes are the main reusable unit across backends.

### `topovec.mgl.image`

`ImageContainer` is the headless execution shell. It owns a standalone
`moderngl.Context`, framebuffer attachments, and one attached scene. This makes
scene execution usable without notebooks or native windows.

### `topovec.mgl.sugar`

The sugar helpers create standard scene/camera/container combinations. They are
convenience factories, not a separate rendering model.

### `topovec.marimo`

The marimo layer binds the reusable scene/property model to anywidget state.
`RenderSession` is the Python-side source of truth. The widget mirrors
snapshots, dispatches actions, and does not redefine rendering semantics.

### `topovec.viewer` and `topovec.viewer.qt`

The shared viewer layer provides the backend-neutral session and residency
logic used by native frontends. `ViewerSession` owns selected-scene state,
shared property values, camera-slot persistence, and viewer snapshots.

The Qt layer (`topovec view`) binds that shared session model to a dockable PySide6
desktop application. It adds document loading for `.npz` and `.sad` files,
toolbar and menu actions, recent-files history, desktop theming, and native
dock/panel management without redefining scene or property semantics.

## Backend Independence

This separation lets the same `Scene` subclasses and `Property` objects drive:

- headless image generation through `ImageContainer`
- interactive notebook workflows through `topovec.marimo`
- desktop inspection workflows through `topovec view`
- future native or embedded applications that need a different event loop

Backends should adapt the scene model rather than re-implement it.

## Extension Guidelines

- Add new low-level drawing logic as `Render` subclasses.
- Compose user-facing configurations as `Scene` subclasses.
- Expose editable scene/render parameters through `Property` objects.
- Keep backend-specific transport and widget state outside `mgl.scene`.
- Use `mgl.sugar` only for convenience constructors and standard presets.
