Skip to content

Scene

The scene groups the cameras, canvas, and dimension management that together define what is rendered and how it is viewed.

Cameras

cellier.scene.CameraType module-attribute

CameraType = Annotated[Union[PerspectiveCamera, OrthographicCamera], Field(discriminator='camera_type')]

cellier.scene.OrthographicCamera

Bases: BaseCamera

2D orthographic camera state.

Parameters:

Name Type Description Default
camera_type Literal['orthographic']

Discriminator field. Always "orthographic".

required
width float

Width of the view volume. Default 10.0.

required
height float

Height of the view volume. Default 10.0.

required
zoom float

Zoom level. Default 1.0.

required
near_clipping_plane float

Near clipping distance. Default -500.0.

required
far_clipping_plane float

Far clipping distance. Default 500.0.

required
position NumpyFloat32Array

World-space camera position, shape (3,).

required
rotation NumpyFloat32Array

Quaternion [x, y, z, w], shape (4,).

required

model_post_init

model_post_init(__context: Any) -> None

Wire controller event relay after model initialization.

cellier.scene.PerspectiveCamera

Bases: BaseCamera

3D perspective camera state.

Parameters:

Name Type Description Default
camera_type Literal['perspective']

Discriminator field. Always "perspective".

required
fov float

Field of view in degrees. Default 70.0.

required
zoom float

Zoom level. Default 1.0.

required
near_clipping_plane float

Near clipping distance. Default 1.0.

required
far_clipping_plane float

Far clipping distance. Default 8000.0.

required
position NumpyFloat32Array

World-space camera position, shape (3,).

required
rotation NumpyFloat32Array

Quaternion [x, y, z, w], shape (4,).

required
up_direction NumpyFloat32Array

World-space up vector, shape (3,).

required
frustum NumpyFloat32Array

Near and far plane corners, shape (2, 4, 3).

required

model_post_init

model_post_init(__context: Any) -> None

Wire controller event relay after model initialization.

Camera controllers

cellier.scene.CameraControllerType module-attribute

CameraControllerType = Annotated[Union[OrbitCameraController, PanZoomCameraController], Field(discriminator='controller_type')]

cellier.scene.OrbitCameraController

Bases: BaseCameraController

Config for a 3D orbit camera controller.

Parameters:

Name Type Description Default
controller_type Literal['orbit']

Discriminator field. Always "orbit".

required

cellier.scene.PanZoomCameraController

Bases: BaseCameraController

Config for a 2D pan/zoom camera controller.

Parameters:

Name Type Description Default
controller_type Literal['pan_zoom']

Discriminator field. Always "pan_zoom".

required

Canvas

cellier.scene.Canvas

Bases: EventedModel

One rendered canvas, holding one or more cameras.

Parameters:

Name Type Description Default
id UUID4

Unique identifier. Auto-generated.

required
cameras dict[str, CameraType]

Mapping of "2d" and/or "3d" to camera models. At least one entry is required.

required
overlays list[CanvasOverlayType]

Screen-space overlays attached to this canvas. Rendered as post-passes on top of the main scene. Default empty list.

required

model_post_init

model_post_init(__context: Any) -> None

Wire camera event relays after model initialization.

Dims

cellier.scene.DimsManager

Bases: EventedModel

Tracks which axes are displayed and the slice index for non-displayed axes.

Single source of truth for render dimensionality, and -- since D2 -- the owner of the scene's world coordinate system. One DimsManager per Scene, so there is no second claimant for the world to arbitrate against.

Parameters:

Name Type Description Default
id UUID4

Unique identifier. Auto-generated.

required
world_coordinate_system WorldCoordinateSystem

The scene's world axes. Frozen: changing the axes means assigning a replacement (D7), which is why there is no event relay onto it.

required
selection SelectionType

The current axis selection (axis-aligned or plane).

required
slider_overrides dict[int, bool]

Per world axis, whether to force its slider shown (True) or hidden (False). An axis absent from the mapping is automatic: it gets a slider when a visual slices it. Only the overrides are stored; the effective set is Scene.slider_axes, which is derived from the visuals and never serialized (D23).

required

axis_labels property

axis_labels: tuple[str, ...]

The world axis names, in order.

ndim property

ndim: int

The number of world axes.

model_post_init

model_post_init(__context: Any) -> None

Wire event relays after model initialization.

Only the selection needs one. world_coordinate_system is a frozen BaseModel with no events group: it cannot change in place, and assigning a replacement already emits this model's own field signal.

to_state

to_state() -> DimsState

Return an immutable snapshot of the current dims state.

to_selection

to_selection(rendered_coordinate_system: RenderedCoordinateSystem, rendered_to_world: AffineTransform) -> RegionSelection

Emit the region one canvas is showing, as the artifact the slicer takes.

This model is the editor -- it holds an index and a thickness, the thing a GUI binds to -- and the slicer consumes one type regardless of which editor produced it (D43, R6). An oblique editor would hold a plane and emit the same type.

The rendered system arrives as an argument rather than being reached for: it is per canvas and is not model state, and this way the model layer never reaches into the render layer.

Thickness comes from the stored mapping, and an axis without an entry is a plane. The region says exactly what the user asked for, and nothing when they asked for nothing. Each visual family then draws what its kind draws from that region: an image or labels visual one plane within it, a geometry visual what lies in it.

Displayed axes are left unbounded, although they keep a stored position (D36). Bounding one is the viewport-crop follow-up; the region type already expresses it (R3).

Parameters:

Name Type Description Default
rendered_coordinate_system RenderedCoordinateSystem

The system the canvas draws in, in cellier displayed order.

required
rendered_to_world AffineTransform

The D34 embedding. Its constant column carries the slice positions.

required

Returns:

Type Description
RegionSelection

The transform and the region, in world coordinates.

Raises:

Type Description
NotImplementedError

If the selection is not axis aligned.

cellier.scene.AxisAlignedSelection

Bases: EventedModel

Mutable selection model for axis-aligned slicing.

Parameters:

Name Type Description Default
selector_type Literal['axis_aligned']

Discriminator field.

required
displayed_axes tuple[int, ...]

Indices into the coordinate system that are rendered. Length 2 -> 2D; length 3 -> 3D.

required
slice_indices dict[int, float]

Mapping of axis index -> world-space slice position, for every world axis, displayed or not (unified image design D36). A displayed axis keeps the position it slices at once it stops being displayed, so a 3D -> 2D switch needs no bookkeeping. A world position, not a voxel index: an integer-valued slider on a 0.5 world-unit-per-voxel axis cannot address the odd-numbered planes (D3).

required
thickness dict[int, float]

Mapping of axis index -> half-thickness in world units. An axis absent from the mapping has thickness 0: a plane. This is the only thickness in the slicing path; no visual family adds one. Per axis rather than scalar because one number means three frames on a 0.5 s/frame time axis and a quarter of a voxel on a 2 um/voxel spatial one (D4).

required

to_state

to_state() -> AxisAlignedSelectionState

Return an immutable snapshot of this selection.

cellier.scene.spatial_axes

spatial_axes(*names: str) -> tuple[Axis, ...]

Build spatial axes from their names.

The shorthand for the common all-spatial world -- spatial_axes("z", "y", "x") -- where writing ("z", "space") three times says nothing extra. Mixed worlds spell the non-spatial axes out::

axes = [("t", "time"), ("c", "channel"), *spatial_axes("z", "y", "x")]

Parameters:

Name Type Description Default
*names str

The axis names, in order.

()

Returns:

Type Description
tuple[Axis, ...]

One axis_type="space" axis per name, each with a fresh id.

cellier.scene.world_coordinate_system

world_coordinate_system(axes: WorldAxesLike, name: str = 'world') -> WorldCoordinateSystem

Coerce an axis specification into a world coordinate system.

A :class:WorldCoordinateSystem passes through unchanged, so its axis ids survive -- which matters, because every stored transform names its endpoints by id. Anything else builds a new system with fresh ids.

Parameters:

Name Type Description Default
axes WorldAxesLike

A WorldCoordinateSystem, or a sequence of Axis objects and/or (name, axis_type) pairs.

required
name str

Name for the system when one is built. Ignored when axes is already a WorldCoordinateSystem.

'world'

Returns:

Type Description
WorldCoordinateSystem

The world system.

Raises:

Type Description
TypeError

If an entry is neither an Axis nor a (name, axis_type) pair. A bare string raises here, naming spatial_axes as the fix.

Scene

cellier.scene.Scene

Bases: EventedModel

One rendered scene.

Parameters:

Name Type Description Default
id UUID4

Unique identifier. Auto-generated.

required
name str

Human-readable name, e.g. "main".

required
dims DimsManager

Dimension manager; single source of truth for render dimensionality.

required
visuals list[VisualType]

Discriminated union of visual model types.

required
canvases dict[UUID4, Canvas]

Keyed by canvas.id.

required
render_modes set[Literal['2d', '3d']]

Which rendering modes visuals added to this scene should support. Defaults to {"2d", "3d"}.

required
lighting Literal['none', 'default']

"none" (default) or "default". Pass "default" to add ambient and directional lights — required for MeshPhongAppearance.

required
background BackgroundAppearance

Appearance of the background drawn behind this scene's visuals. Mutating its fields updates the render layer at runtime.

required
overlays list[SceneOverlayType]

World-space overlays attached to this scene, such as a :class:~cellier.visuals.SceneBoundingBox. Drawn by the scene camera in the main pass. Add and remove them through the controller (add_scene_overlay / remove_overlay) so the render layer follows; appending here directly only takes effect when the scene is registered.

required

slider_axes property

slider_axes: tuple[int, ...]

World axes that get a slider when they are not displayed.

Derived from the visuals -- hidden ones included -- and adjusted by dims.slider_overrides: True forces an axis in, False forces it out. A plain property rather than a field, so it is never serialized; the overrides are the only stored state (D23).

Returns:

Type Description
tuple[int, ...]

Sorted world axis indices.

Raises:

Type Description
ValueError

If a visual's transform has no axis correspondence (D37).

model_post_init

model_post_init(__context: Any) -> None

Wire dims, background and visual event relays after initialization.