Skip to content

Render

The rendering backend turns scenes and visuals into pixels, coordinating slicing requests and per-canvas state.

Managers

cellier.render.RenderManager

Single top-level render-layer object.

Owns the scene registry, canvas registry, shared async slicer, and slice coordinator. Exposes three reslicing entry points that cover the common triggers: all scenes, one scene, or one visual.

Construction is parameter-free; scenes, canvases, and visuals are registered via the add_* methods.

scheduler property

scheduler: ChunkScheduler

The chunk scheduler shared by every multiscale visual.

config property

Current rendering performance configuration.

Reflects live state: mutations via temporal_blend_weight and temporal_enabled setters are visible here immediately.

temporal_blend_weight property writable

temporal_blend_weight: float

EMA floor weight for temporal accumulation.

temporal_enabled property writable

temporal_enabled: bool

Whether the temporal accumulation pass is active.

temporal_frame_count property

temporal_frame_count: int | None

Frames accumulated on the least-converged canvas.

None when there is no canvas. The minimum rather than any one canvas's count, so a GUI reading it reports "settled" only once every canvas is.

ambient_occlusion_enabled property writable

ambient_occlusion_enabled: bool

Whether the ambient occlusion pass is active.

A canvas in 2D never runs the pass whatever this says; see CanvasView.set_ssao_enabled.

ambient_occlusion_radius property writable

ambient_occlusion_radius: float | None

Hemisphere radius in scene units, or None for auto.

ambient_occlusion_strength property writable

ambient_occlusion_strength: float

How far the occlusion multiply is applied, 0 (off) to 1 (full).

ambient_occlusion_power property writable

ambient_occlusion_power: float

Contrast exponent applied to the occlusion before the multiply.

ambient_occlusion_bias property writable

ambient_occlusion_bias: float

Depth-comparison bias, as a fraction of the effective radius.

ambient_occlusion_n_samples property writable

ambient_occlusion_n_samples: int

Hemisphere samples per pixel. Changing this recompiles.

ambient_occlusion_blur_radius property writable

ambient_occlusion_blur_radius: int

Box-blur half-width in internal pixels. Changing this recompiles.

ambient_occlusion_auto_radius_fraction property writable

ambient_occlusion_auto_radius_fraction: float

Fraction of the scene bounding box diagonal used when radius is auto.

ambient_occlusion_effective_radius property

ambient_occlusion_effective_radius: float | None

The occlusion radius actually in use, in scene units.

The explicit config.ambient_occlusion.radius when one is set, otherwise the value derived from the scene bounding box diagonal. None when there is no canvas to ask. Read-only.

outline_enabled property writable

outline_enabled: bool

Whether the screen-space outline pass is active.

outline_boundaries_enabled property writable

outline_boundaries_enabled: bool

Whether the boundaries layer (every outlined region) draws.

outline_selection_enabled property writable

outline_selection_enabled: bool

Whether the selection layer (regions with a palette slot) draws.

connect_event_bus

connect_event_bus(event_bus: EventBus) -> None

Subscribe internal components to event_bus.

loading_progress

loading_progress(visual_id: UUID) -> LoadingProgress | None

A multiscale visual's loading progress, or None (design 5.13).

hold_draws

hold_draws(scene_id: UUID) -> None

Let the canvases of scene_id keep their picture while a read lands.

Called after a dims change has been planned. Each canvas holds its frame for up to config.draw_hold_ms while a visual of the scene that hides until its data loads (one with awaits_data) is still waiting. Visuals that keep their old picture, or fill in as chunks arrive, are not waited for.

invalidate_store

invalidate_store(store_id: UUID, regions: tuple | None = None) -> list[int]

Forget GPU data read from a store, where it changed (design 5.14).

Every scheduled atlas reading the store drops the bricks that overlap regions (all of them for None); wanted ones are fetched again.

Parameters:

Name Type Description Default
store_id UUID

The store that changed.

required
regions tuple of DataRegion or None

Level-0 data regions, as StoreChange.regions carries them.

None

Returns:

Type Description
list[int]

The atlases touched.

reset_temporal_accumulation

reset_temporal_accumulation() -> None

Discard the accumulated history on every canvas.

apply_ambient_occlusion_config

apply_ambient_occlusion_config() -> None

Push the current config.ambient_occlusion onto every canvas's pass.

update_ssao_radius

update_ssao_radius(scene_id: UUID) -> None

Recompute the auto occlusion radius for one scene.

Reads the scene's world bounding box once and hands its diagonal to every canvas showing that scene. An explicit ssao.radius overrides the result, so this is safe to call unconditionally.

Parameters:

Name Type Description Default
scene_id UUID

The scene whose bounding box should be measured. Unknown ids are ignored.

required

apply_outline_config

apply_outline_config() -> None

Push the current config.outline onto every canvas's pass.

set_visual_outline

set_visual_outline(visual_id: UUID, slot: int = 1, placement: str | int = PLACEMENT_INWARD, kind: int = KIND_WHOLE_OBJECT) -> None

Record the outline assignment for one visual.

The GPU table is not written here: it is derived from these assignments once per frame, because cellier rebuilds world objects (2D/3D switches, multiscale brick groups, channel changes) and each rebuild hands out fresh global_ids.

Parameters:

Name Type Description Default
visual_id UUID

The cellier visual to outline.

required
slot int

0 removes the outline. 1..15 selects palette entry slot - 1 for the selection layer; any nonzero slot also makes the visual visible to the boundaries layer.

1
placement str or int

"inward" or "outward" (or the corresponding constant).

PLACEMENT_INWARD
kind int

KIND_WHOLE_OBJECT keys the edge test on the pygfx object id, giving one silhouette per visual. KIND_LABEL keys it on the per-pixel label field instead, so boundaries appear between labels inside one volume, coloured per label. KIND_LABEL_ALL keys on the label too but colours every one of them from slot. Both label kinds require the outline_id target; without it a label visual falls back to a whole-object silhouette.

KIND_WHOLE_OBJECT

Raises:

Type Description
ValueError

If slot or placement is out of range.

get_visual_outline

get_visual_outline(visual_id: UUID) -> tuple[int, int, int] | None

Return (slot, placement, kind) for visual_id, or None.

set_visual_ambient_occlusion

set_visual_ambient_occlusion(visual_id: UUID, enabled: bool | None = None) -> None

Choose whether one visual receives ambient occlusion.

Parameters:

Name Type Description Default
visual_id UUID

The cellier visual.

required
enabled bool or None

None (the default) restores the automatic rule: excluded while the visual renders in the MIP family, included otherwise, re-derived whenever the render mode changes. True and False are explicit and survive a render-mode change.

None
Notes

This controls whether the visual receives occlusion, not whether it casts it: the occlusion loop reads raw depth, so an excluded visual's depth still occludes its neighbours.

get_visual_ambient_occlusion

get_visual_ambient_occlusion(visual_id: UUID) -> bool | None

Return the explicit occlusion setting, or None for auto.

set_label_selection

set_label_selection(visual_id: UUID, selection: dict[int, int]) -> None

Set which label values the selection layer outlines.

Parameters:

Name Type Description Default
visual_id UUID

A labels visual.

required
selection dict[int, int]

{label value: palette slot}, slots in 1..15. An empty dict clears the selection.

required
Notes

Writes into the material's fixed-capacity selection texture rather than replacing it, so a selection change is a data upload and never a pipeline rebuild. Materials that carry no such texture (every non-label visual) are skipped.

add_scene

add_scene(scene_id: UUID, lighting: str = 'none', background: BackgroundAppearance | None = None) -> SceneManager

Create and register a new scene.

Parameters:

Name Type Description Default
scene_id UUID

Unique identifier for the scene.

required
lighting str

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

'none'
background BackgroundAppearance or None

Background appearance for the scene. None uses the model defaults.

None

Returns:

Type Description
SceneManager

The newly created scene manager.

scene_has_lighting

scene_has_lighting(scene_id: UUID) -> bool

Return True if scene_id was created with lighting enabled.

set_scene_background

set_scene_background(scene_id: UUID, background: BackgroundAppearance) -> None

Apply background to the scene registered under scene_id.

Parameters:

Name Type Description Default
scene_id UUID

ID of the scene to update.

required
background BackgroundAppearance

The background appearance to apply.

required

Raises:

Type Description
KeyError

If scene_id is not registered.

add_canvas

add_canvas(canvas_id: UUID, scene_id: UUID, parent: QWidget | None = None, **canvas_view_kwargs) -> CanvasView

Create a CanvasView, register it, and return it.

The caller embeds canvas_view.widget in their Qt layout.

Parameters:

Name Type Description Default
canvas_id UUID

Unique identifier for this canvas.

required
scene_id UUID

ID of the scene this canvas should render.

required
parent QWidget or None

Parent widget for the underlying QRenderWidget.

None
**canvas_view_kwargs

Additional keyword arguments forwarded to CanvasView.__init__ (e.g. dim, fov, depth_range, gui, size).

{}

Returns:

Type Description
CanvasView

The newly created canvas view.

add_visual

add_visual(scene_id: UUID, visual: _GFXVisual, data_store: BaseDataStore, displayed_axes: tuple[int, ...]) -> None

Register a visual with a scene and its associated data store.

Parameters:

Name Type Description Default
scene_id UUID

ID of the scene to add the visual to.

required
visual _GFXVisual

The render-layer visual object.

required
data_store BaseDataStore

The data store that will serve chunk data for this visual.

required
displayed_axes tuple[int, ...]

Current displayed axes from the scene's dims selection. Passed to SceneManager.add_visual to select the initial node.

required

refresh_visual_axis_extents

refresh_visual_axis_extents(visual_id: UUID) -> None

Re-read a visual's store extent after the store's extent changed.

The scene manager keeps each visual's extent for the out-of-domain check in slice planning, copied when the visual was added; an "extent" store change makes that copy stale. An unknown visual is ignored.

add_canvas_overlay

add_canvas_overlay(canvas_id: UUID, gfx_overlay: GFXCanvasOverlay) -> None

Attach a pre-built GFX overlay to canvas_id.

Parameters:

Name Type Description Default
canvas_id UUID

ID of the canvas that should receive the overlay.

required
gfx_overlay GFXCanvasOverlay

The fully-constructed render-layer overlay.

required

Raises:

Type Description
KeyError

If canvas_id is not registered.

remove_canvas_overlay

remove_canvas_overlay(canvas_id: UUID, gfx_overlay: GFXCanvasOverlay) -> None

Detach a GFX overlay from canvas_id.

Parameters:

Name Type Description Default
canvas_id UUID

ID of the canvas the overlay is attached to. An unknown canvas is ignored -- it has already been torn down.

required
gfx_overlay GFXCanvasOverlay

The render-layer overlay to detach.

required

add_scene_overlay

add_scene_overlay(scene_id: UUID, overlay_id: UUID, gfx_overlay: GFXSceneOverlay) -> None

Attach a pre-built GFX scene overlay to scene_id.

Parameters:

Name Type Description Default
scene_id UUID

ID of the scene that should receive the overlay.

required
overlay_id UUID

ID of the overlay's model.

required
gfx_overlay GFXSceneOverlay

The fully-constructed render-layer overlay.

required

Raises:

Type Description
KeyError

If scene_id is not registered.

remove_scene_overlay

remove_scene_overlay(scene_id: UUID, overlay_id: UUID) -> None

Detach a scene overlay from scene_id.

Parameters:

Name Type Description Default
scene_id UUID

ID of the scene. An unknown scene is ignored -- it has already been torn down.

required
overlay_id UUID

ID of the overlay's model.

required

submit_pick_read

submit_pick_read(requests: list, fetch_fn: Callable, callback: Callable[[list], None], on_complete: Callable[[], None]) -> UUID | None

Read pick values through the slicer, cancellable by the returned id.

Multiscale pick values are read at level 0 through the same cancellable async service as slicing (unified image design 3.7).

Parameters:

Name Type Description Default
requests list[ChunkRequest]

One point request per value, all sharing one slice_request_id.

required
fetch_fn Callable

The store's get_data coroutine.

required
callback Callable[[list], None]

Receives each batch of (request, data) pairs.

required
on_complete Callable[[], None]

Called once every batch has arrived; never after a cancel.

required

Returns:

Type Description
UUID or None

The read's id, for :meth:cancel_pick_read.

cancel_pick_read

cancel_pick_read(read_id: UUID) -> None

Cancel an in-flight pick read. A finished or unknown id is a no-op.

set_pick_details_enabled

set_pick_details_enabled(canvas_id: UUID, enabled: bool) -> None

Enable or disable element-level pick extraction for one canvas.

When disabled (the default), pointer events still carry hit_visual_id but pick_details is left None so non-picking consumers do not pay for the per-type dispatch.

Parameters:

Name Type Description Default
canvas_id UUID

The canvas whose extraction state should change.

required
enabled bool

True to extract typed VisualPickDetails on each pointer event.

required

remove_visual

remove_visual(visual_id: UUID) -> None

Remove a visual from its scene and deregister it.

Parameters:

Name Type Description Default
visual_id UUID

ID of the visual to remove.

required

remove_scene

remove_scene(scene_id: UUID) -> None

Remove a scene and all its visuals and canvases.

Each visual and each canvas is closed explicitly: see :meth:SceneManager.close and :meth:CanvasView.close, which dropping references cannot substitute for.

Parameters:

Name Type Description Default
scene_id UUID

ID of the scene to remove.

required

remove_canvas

remove_canvas(canvas_id: UUID) -> None

Remove a single canvas, closing it and dropping its references.

Parameters:

Name Type Description Default
canvas_id UUID

ID of the canvas to remove.

required

Raises:

Type Description
KeyError

If canvas_id is not registered.

close

close() -> None

Close every canvas and scene, and drop the render references.

The scenes are closed rather than merely forgotten: a closed controller can stay referenced (a reference cycle, a pending task, a traceback), and a multiscale visual's brick cache alone can be a gigabyte. Closing each visual releases its textures now, by refcount, instead of whenever the cyclic garbage collector next gets to the controller.

Safe to call more than once.

reset_frame_counters

reset_frame_counters(scene_id: UUID) -> None

Rewind every per-frame counter that feeds scene_id's pixels.

Three things advance once per rendered frame and so make frame N differ from frame N+1: the temporal accumulation history, the SSAO kernel rotation, and the multiscale brick shader's ray-start jitter. All three are counters rather than random draws, so rewinding them is what turns "draw N frames" into a reproducible picture.

Called before a capture (see cellier.render._capture). The visual counters are shared state -- the scene graph is shared across canvases -- so this also rewinds the jitter sequence any live canvas is drawing. That is harmless: the sequence is dither, not content.

get_scene

get_scene(scene_id: UUID) -> Scene

Return the pygfx Scene for scene_id.

Parameters:

Name Type Description Default
scene_id UUID

ID of the scene to retrieve.

required

Returns:

Type Description
Scene

reslice_scene

reslice_scene(scene_id: UUID, dims_state: DimsState, visual_configs: dict[UUID, VisualRenderConfig] | None = None, target_visual_ids: frozenset[UUID] | None = None, selections: Mapping[UUID, RegionSelection] | None = None) -> None

Reslice all visuals in one scene.

One reslicing request is submitted per registered canvas so that each canvas uses its own camera state for LOD and frustum-culling decisions.

Parameters:

Name Type Description Default
scene_id UUID

ID of the scene to reslice.

required
dims_state DimsState

Current dimension display state.

required
visual_configs dict[UUID, VisualRenderConfig] or None

Per-visual render configuration. None falls back to defaults.

None
selections Mapping[UUID, RegionSelection] or None

The region each canvas is showing, keyed by canvas id. Built by the controller, which owns the rendered coordinate systems; the render manager only routes them.

None
target_visual_ids frozenset[UUID] or None

None reslices all visuals in the scene.

None

reslice_visual

reslice_visual(visual_id: UUID, dims_state: DimsState, visual_config: VisualRenderConfig | None = None, selections: Mapping[UUID, RegionSelection] | None = None) -> None

Reslice one visual.

Looks up which scene owns visual_id, then submits one ReslicingRequest per registered canvas so that each canvas uses its own camera state.

Parameters:

Name Type Description Default
visual_id UUID

ID of the visual to reslice.

required
dims_state DimsState

Current dimension display state.

required
visual_config VisualRenderConfig or None

Render configuration for this visual. None uses defaults.

None
selections Mapping[UUID, RegionSelection] or None

The region each canvas is showing, keyed by canvas id.

None

look_at_visual

look_at_visual(visual_id: UUID, canvas_id: UUID, view_direction: tuple[float, float, float] = (-1, -1, -1), up: tuple[float, float, float] = (0, 0, 1)) -> None

Fit a canvas camera to a visual's bounding box.

Parameters:

Name Type Description Default
visual_id UUID

ID of the target visual.

required
canvas_id UUID

ID of the canvas whose camera should be fitted.

required
view_direction tuple[float, float, float]

Camera look direction vector (need not be normalized).

(-1, -1, -1)
up tuple[float, float, float]

Camera up vector.

(0, 0, 1)

set_dims_scrubbing

set_dims_scrubbing(scene_id: UUID, scrubbing: bool) -> None

Record whether a scene's dims are being scrubbed.

Driven by the controller's dims tracker: True when a scrub starts, False when it ends, before the reslice the transition causes. Visuals with prepare_draw read it in each frame of the scene's canvases (a mesh with levels of detail draws its coarse level during a scrub that does not change it). Capture canvases are not told.

Parameters:

Name Type Description Default
scene_id UUID

ID of the scene.

required
scrubbing bool

Whether its dims are being scrubbed.

required

set_visual_lod

set_visual_lod(visual_id: UUID, lod: Any) -> None

Hand a visual its level-of-detail settings; ignored if it has none.

set_visual_clipping_planes

set_visual_clipping_planes(visual_id: UUID, planes: Any) -> None

Hand a visual its clipping planes; ignored if it takes none.

set_visual_render_planes

set_visual_render_planes(visual_id: UUID, planes: Any) -> None

Hand a visual its render planes; ignored if it draws none.

set_plane_outline_kinds

set_plane_outline_kinds(scene_id: UUID, kinds: Mapping[UUID, Collection[str]]) -> bool

Say which planes each visual of a scene shows outlines of.

The outlines are computed again and drawn (plane outline design 6.4). Between calls the scene keeps them up to date itself as its visuals' planes and placement change.

Parameters:

Name Type Description Default
scene_id UUID

The scene. An unknown scene is ignored.

required
kinds Mapping[UUID, Collection[str]]

{visual id: kinds}; "render" shows the outlines of the visual's render planes and "clipping" those of its clipping planes. A visual left out shows none.

required

Returns:

Type Description
bool

Whether anything drawn changed.

clipping_planes_affect_request

clipping_planes_affect_request(visual_id: UUID) -> bool

Whether a change of planes changes what visual_id reads.

clipping_plane_hidden_axes

clipping_plane_hidden_axes(visual_id: UUID, item: Any) -> list[int]

The data axes a plane has a component on that the 3D view hides.

A plane gizmo cannot express such a plane.

Raises:

Type Description
ValueError

If the visual is not drawn in 3D.

reduce_clipping_plane

reduce_clipping_plane(visual_id: UUID, item: Any) -> tuple[tuple[float, float, float], float]

One plane of a visual in its 3D view's rendered space.

Parameters:

Name Type Description Default
visual_id UUID

The visual the plane belongs to.

required
item ClippingPlane

The plane. Its enabled flag is not looked at.

required

Returns:

Type Description
tuple[tuple[float, float, float], float]

(normal, offset) in pygfx (x, y, z) order: the plane keeps normal . r >= offset.

Raises:

Type Description
ValueError

If the visual is not drawn in 3D.

expand_rendered_plane

expand_rendered_plane(visual_id: UUID, point: Any, normal: Any) -> tuple[ndarray, float]

A rendered-space plane in a visual's level-0 data coordinates.

The inverse of :meth:reduce_clipping_plane.

Parameters:

Name Type Description Default
visual_id UUID

The visual whose data coordinates to use.

required
point array - like

A point on the plane and its normal, in rendered (x, y, z).

required
normal array - like

A point on the plane and its normal, in rendered (x, y, z).

required

Returns:

Type Description
tuple[ndarray, float]

The normal, one entry per data axis, and the offset.

Raises:

Type Description
ValueError

If the visual is not drawn in 3D, or normal is zero.

visual_rendered_bounds

visual_rendered_bounds(visual_id: UUID) -> ndarray | None

The bounding box of a visual's 3D node, in rendered (x, y, z).

Returns:

Type Description
ndarray or None

[[low x, low y, low z], [high x, high y, high z]]; None when the node has no bounds (nothing drawn yet).

canvas_dim

canvas_dim(canvas_id: UUID) -> str

"2d" or "3d": which camera a canvas draws with.

canvas_orbit_point

canvas_orbit_point(canvas_id: UUID) -> tuple[float, float, float] | None

The point a canvas's 3D camera orbits about; None in 2D.

reduce_render_plane

reduce_render_plane(visual_id: UUID, plane: Any) -> tuple[ndarray, ndarray, ndarray]

One render plane of a visual in its 3D view's rendered space.

Parameters:

Name Type Description Default
visual_id UUID

The visual the plane belongs to.

required
plane RenderPlane

The plane. Its enabled flag is not looked at.

required

Returns:

Type Description
tuple[ndarray, ndarray, ndarray]

(origin, in_plane_axis_0, in_plane_axis_1) in pygfx (x, y, z) order.

Raises:

Type Description
ValueError

If the visual is not drawn in 3D, or the view does not display the plane's three axes.

expand_rendered_frame

expand_rendered_frame(visual_id: UUID, axes: Any, point: Any, in_plane_axis_0: Any, in_plane_axis_1: Any) -> tuple[ndarray, ndarray, ndarray]

A rendered-space frame on three named world axes.

The inverse of :meth:reduce_render_plane: world to rendered is a reorder of the displayed axes.

Raises:

Type Description
ValueError

If the visual is not drawn in 3D, or the view does not display axes.

add_plane_gizmo

add_plane_gizmo(canvas_id: UUID, gizmo_id: UUID, point: Any, normal: Any, *, screen_size: float = 100.0, in_plane_axes: tuple[Any, Any] | None = None, scale_axes: Any = ()) -> None

Draw a plane gizmo in a canvas, placed at a rendered-space pose.

Its drags are reported as PlaneGizmoMovedEvent with gizmo_id.

Parameters:

Name Type Description Default
canvas_id UUID

The canvas, and the id the gizmo's events carry.

required
gizmo_id UUID

The canvas, and the id the gizmo's events carry.

required
point array - like

A point on the plane and its normal, in rendered (x, y, z).

required
normal array - like

A point on the plane and its normal, in rendered (x, y, z).

required
screen_size float

The gizmo's size on screen, in logical pixels.

100.0
in_plane_axes tuple[array - like, array - like] or None

The gizmo's two in-plane axes. Given, they fix its whole frame and normal is not used.

None
scale_axes Iterable[int]

The in-plane axes (1 and 2) that get a scale handle.

()

Raises:

Type Description
KeyError

If canvas_id is not registered.

ValueError

If the canvas already has a gizmo with that id.

set_plane_gizmo_frame

set_plane_gizmo_frame(canvas_id: UUID, gizmo_id: UUID, point: Any, in_plane_axis_0: Any, in_plane_axis_1: Any) -> None

Give a plane gizmo a whole frame; a gizmo that is gone is ignored.

set_plane_gizmo_scale_axes

set_plane_gizmo_scale_axes(canvas_id: UUID, gizmo_id: UUID, axes: Any) -> None

Choose which in-plane axes of a gizmo have a scale handle.

reset_plane_gizmo_scale

reset_plane_gizmo_scale(canvas_id: UUID, gizmo_id: UUID) -> None

Put a gizmo's scale back to 1; a gizmo that is gone is ignored.

set_plane_gizmo_pose

set_plane_gizmo_pose(canvas_id: UUID, gizmo_id: UUID, point: Any, normal: Any) -> None

Move a plane gizmo; a canvas or gizmo that is gone is ignored.

remove_plane_gizmo

remove_plane_gizmo(canvas_id: UUID, gizmo_id: UUID) -> None

Remove a plane gizmo; a canvas or gizmo that is gone is ignored.

set_camera_moving

set_camera_moving(canvas_id: UUID, moving: bool) -> None

Record whether a canvas's camera is in motion.

Driven by the controller's camera tracker: True when a motion starts, False when it ends. The flag is CanvasView.camera_moving, which per-frame draw choices read in the frame it changes.

Parameters:

Name Type Description Default
canvas_id UUID

ID of the canvas. An unknown id is ignored.

required
moving bool

Whether the camera is moving.

required

request_frame

request_frame(canvas_id: UUID) -> None

Ask one canvas for a frame, keeping its accumulation history.

Parameters:

Name Type Description Default
canvas_id UUID

ID of the canvas. An unknown id is ignored.

required

set_camera_depth_range

set_camera_depth_range(canvas_id: UUID, depth_range: tuple[float, float]) -> None

Set the near/far clip distances for a canvas camera.

Parameters:

Name Type Description Default
canvas_id UUID

ID of the target canvas.

required
depth_range tuple[float, float]

(near, far) clip distances in world units.

required

cellier.render.SceneManager

Owns one pygfx gfx.Scene and the registry of visuals attached to it.

Which node (2D or 3D) is active is determined at runtime from the dims_state carried by each ReslicingRequest, not fixed at construction time.

Parameters:

Name Type Description Default
scene_id UUID

Unique identifier for this scene.

required
lighting str

"none" (default) or "default".

'none'
background BackgroundAppearance or None

Background appearance to apply at construction. None uses the model defaults.

None

background property

background: Background

The pygfx background object drawn behind this scene's visuals.

has_lighting property

has_lighting: bool

True if this scene was created with lighting enabled.

scene_id property

scene_id: UUID

Unique identifier for this scene.

scene property

scene: Scene

The pygfx Scene object. Passed to CanvasView via get_scene_fn.

visual_ids property

visual_ids: list[UUID]

IDs of all registered visuals.

plane_outlines property

plane_outlines: GFXPlaneOutlines

The outlines of the visuals' planes drawn in this scene.

set_background

set_background(appearance: BackgroundAppearance) -> None

Apply appearance to the scene's background object.

The whole model is applied rather than a single field so the render layer never has to dispatch on field names -- set_colors takes a different number of colors per mode, so a per-field push would have to reconstruct the others anyway.

Parameters:

Name Type Description Default
appearance BackgroundAppearance

The background appearance to apply.

required

add_visual

add_visual(visual: _GFXVisual, displayed_axes: tuple[int, ...], axis_extents: Sequence[tuple[float, float]] | None = None) -> None

Register a visual and add its initial node to the scene graph.

Calls visual.get_node_for_dims(displayed_axes) to select the correct node, then stores it in _active_nodes and adds it to the pygfx scene.

Parameters:

Name Type Description Default
visual _GFXVisual

The GFX visual to register.

required
displayed_axes tuple[int, ...]

Current displayed axes from the scene's dims selection.

required
axis_extents Sequence[tuple[float, float]] or None

The backing store's per-axis extents in level-0 data coordinates, used to decide whether this visual has any data at a given slice position. None means "not known", and such a visual is never skipped.

None

Raises:

Type Description
ValueError

If get_node_for_dims returns None.

set_axis_extents

set_axis_extents(visual_id: UUID, axis_extents: Sequence[tuple[float, float]] | None) -> None

Replace a visual's store extents after its store's extent changed.

Parameters:

Name Type Description Default
visual_id UUID

ID of a registered visual. An unknown id is ignored.

required
axis_extents Sequence[tuple[float, float]] or None

The store's new level-0 extents, or None for "not known".

required

get_active_node

get_active_node(visual_id: UUID) -> WorldObject | None

Return the node currently active in the scene for visual_id.

Returns None if the visual has not yet been registered or if its active node is None.

Parameters:

Name Type Description Default
visual_id UUID

ID of the visual to query.

required

swap_node

swap_node(visual_id: UUID, new_node: WorldObject | None) -> None

Replace the active scene-graph node for visual_id.

Removes the previously active node and adds new_node. If old_node is new_node (single-node visuals such as mesh and lines), the scene graph is not touched — the node stays in the scene and the subsequent reslice updates its content.

Parameters:

Name Type Description Default
visual_id UUID

ID of the visual whose node is being swapped.

required
new_node WorldObject or None

The node that should be active after this call.

required

add_overlay

add_overlay(overlay_id: UUID, overlay: GFXSceneOverlay) -> None

Register a scene overlay and add its node to the scene graph.

Parameters:

Name Type Description Default
overlay_id UUID

ID of the overlay's model.

required
overlay GFXSceneOverlay

The render-layer overlay.

required

remove_overlay

remove_overlay(overlay_id: UUID) -> None

Unregister a scene overlay and remove its node from the scene graph.

Parameters:

Name Type Description Default
overlay_id UUID

ID of the overlay's model. An unknown id is ignored.

required

set_plane_outline_kinds

set_plane_outline_kinds(kinds: Mapping[UUID, Collection[str]]) -> bool

Say which planes each visual shows outlines of, and redraw them.

Parameters:

Name Type Description Default
kinds Mapping[UUID, Collection[str]]

{visual id: kinds}, a kind being "render" for the visual's render planes or "clipping" for its clipping planes. A visual left out shows none: it is hidden, or not drawn in a way that shows its planes.

required

Returns:

Type Description
bool

Whether anything drawn changed.

get_overlay

get_overlay(overlay_id: UUID) -> GFXSceneOverlay | None

Return the render-layer scene overlay for overlay_id, if any.

remove_visual

remove_visual(visual_id: UUID) -> None

Unregister a visual and remove its node from the scene graph.

Uses _active_nodes to identify which node is currently in the scene and removes only that one. Dropping the visual from _visuals releases references to both node_3d and node_2d so GC can collect both nodes' GPU resources (pygfx has no explicit destroy API).

Parameters:

Name Type Description Default
visual_id UUID

ID of the visual to remove.

required

close

close() -> None

Remove every visual and overlay, releasing their GPU resources.

Something may still reference this scene manager after its scene is gone -- a closed controller kept alive, a pending slice task -- so the visuals are released here rather than left for when the manager dies. Safe to call more than once.

get_visual_id_for_node

get_visual_id_for_node(node: WorldObject) -> UUID | None

Return the visual_id whose active scene-graph node is node.

The pick buffer returns leaf nodes (e.g. gfx.Image inside a gfx.Group), while _active_nodes stores the top-level group. This method walks up the parent chain of node until it finds a registered active node, then returns its visual_id. Returns None if no ancestor belongs to any registered visual.

Parameters:

Name Type Description Default
node WorldObject

The pygfx object returned by the pick buffer.

required

get_visual

get_visual(visual_id: UUID) -> _GFXVisual

Return the registered visual for visual_id.

Parameters:

Name Type Description Default
visual_id UUID

ID of the visual to retrieve.

required

Returns:

Type Description
_GFXVisual

Raises:

Type Description
KeyError

If visual_id is not registered in this scene.

build_slice_requests

build_slice_requests(request: ReslicingRequest, visual_configs: dict[UUID, VisualRenderConfig]) -> dict[UUID, list[ChunkRequest]]

Collect ChunkRequests from all (or targeted) registered visuals.

Dispatches to the 2D or 3D planning path based on scene dimensionality.

Parameters:

Name Type Description Default
request ReslicingRequest

The reslicing request.

required
visual_configs dict[UUID, VisualRenderConfig]

Per-visual render configuration.

required

Returns:

Type Description
dict[UUID, list[ChunkRequest]]

Mapping of visual_model_id to that visual's ChunkRequests.

plan_chunked

plan_chunked(request: ReslicingRequest, visual_configs: dict[UUID, VisualRenderConfig]) -> tuple[dict[UUID, list[DesiredSet]], set[UUID]]

Plan every targeted chunked visual (design 5.3), 2D or 3D.

Parameters:

Name Type Description Default
request ReslicingRequest

A 2D or 3D request.

required
visual_configs dict[UUID, VisualRenderConfig]

Per-visual render configuration.

required

Returns:

Name Type Description
planned dict[UUID, list[DesiredSet]]

Desired sets per visual that planned anything.

idle set[UUID]

Targeted chunked visuals that draw nothing now -- slicing disabled (hidden), no data here, or a slice that misses the data. Their atlases should be retired.

cellier.render.SliceCoordinator

Thin orchestrator owned by RenderManager.

Given a ReslicingRequest, it looks up the target SceneManager, runs the synchronous planning phase, cancels in-flight tasks for the affected visuals, and submits new async load tasks.

One AsyncSlicer task maps to one (scene_id, canvas_id, visual_id) triple. A dict keyed by this triple tracks active slice IDs so that per-visual cancellation can cancel only the affected task while leaving other visuals — and other canvases — in the same scene running.

Chunked visuals (is_chunked_visual: the multiscale image and labels, and the mesh) take a different path, 2D and 3D (plans/progressive_loading_ design_v3.md 4.2): they are planned into desired sets and handed to the shared :class:~cellier.render.scheduling.ChunkScheduler, which never cancels. The coordinator keeps the scheduler's cache registrations in step with each visual's atlases, retires the atlases of a visual that draws nothing (and those of the mode not drawn), and turns the scheduler's per-atlas completion into ResliceCompletedEvent, and its per-atlas progress into ResliceProgressEvent and BackstopCompleteEvent per visual (design 5.13).

Parameters:

Name Type Description Default
scenes dict[UUID, SceneManager]

Shared scene registry from RenderManager.

required
slicer AsyncSlicer

Shared async slicer instance.

required
data_stores dict[UUID, MultiscaleZarrDataStore]

Mapping of visual_model_id to the data store for that visual.

required
scheduler ChunkScheduler or None

The chunk scheduler. None routes every visual to the slicer.

None

submit

submit(request: ReslicingRequest, visual_configs: dict[UUID, VisualRenderConfig]) -> None

Execute the full reslicing cycle for the scene in request.scene_id.

Cancels in-flight tasks for visuals that will be re-submitted, subject to each visual's cancellable property. Visuals with cancellable = False are never cancelled; their tasks run to completion so every intermediate position reaches the GPU. This is the case for the in-memory lines and points visuals. The mesh is not among them: it is a chunked visual, loaded by the scheduler. The image and label visuals -- both in-memory (GFXImageMemoryVisual, GFXLabelMemoryVisual) and multiscale (GFXMultiscaleImageVisual, GFXMultiscaleLabelVisual) -- default to cancellable = True, so a superseding reslice cancels their in-flight reads. All render-layer visual classes must expose cancellable as part of their public API; an AttributeError indicates a missing implementation.

Parameters:

Name Type Description Default
request ReslicingRequest

The reslicing request to process.

required
visual_configs dict[UUID, VisualRenderConfig]

Per-visual render configuration.

required

cancel_all

cancel_all() -> None

Cancel every in-flight slice task, across every scene.

cancel_scene can only reach what _active_slice_ids still names, which at teardown is not everything: submit deliberately lets a non-cancellable visual finish rather than cancelling it, then overwrites that key, so the predecessor task becomes unreachable from here. Cancelling the tracked requests first keeps the per-visual GPU slot release running for them; the sweep afterwards catches the rest.

cancel_scene

cancel_scene(scene_id: UUID) -> None

Cancel all in-flight tasks for a scene.

Parameters:

Name Type Description Default
scene_id UUID

ID of the scene whose tasks should be cancelled.

required

cancel_visual

cancel_visual(scene_id: UUID, canvas_id: UUID, visual_id: UUID) -> None

Cancel the in-flight task for one visual on one canvas.

Also calls visual.cancel_pending() or cancel_pending_2d() to release any GPU slots reserved during the last planning phase that were never committed.

Parameters:

Name Type Description Default
scene_id UUID

ID of the scene containing the visual.

required
canvas_id UUID

ID of the canvas whose request should be cancelled.

required
visual_id UUID

ID of the visual to cancel.

required

forget_visual

forget_visual(visual_id: UUID) -> None

Drop a chunked visual's atlases from the scheduler (visual removal).

on_cache_complete

on_cache_complete(cache_id: int, generation: int) -> None

Scheduler callback: a cache's latest pass is resident or given up.

When every atlas of the owning visual is complete, answer each ResliceStartedEvent announced for it since the last completion.

visual_progress

visual_progress(visual_id: UUID) -> LoadingProgress | None

A chunked visual's progress, summed over its drawn atlases.

Retired atlases (a hidden visual, an undrawn channel, the mode not drawn) are left out: nothing of theirs is wanted. None for a visual that has no atlas in the scheduler.

on_cache_progress

on_cache_progress(cache_id: int) -> None

Scheduler callback: a cache's counts may have changed.

Marks the owning visual and flushes on the next loop iteration, so a commit round over several atlases (or a pass and a round in one iteration) emits one ResliceProgressEvent per visual.

on_cache_backstop_complete

on_cache_backstop_complete(cache_id: int, generation: int) -> None

Scheduler callback: a cache's backstop is resident or given up.

Emits BackstopCompleteEvent once the backstops of every drawn atlas of the visual are, and only when the plan has a backstop.

cellier.render.CanvasView

Owns one rendered canvas: widget, renderer, camera, and controller.

Responsible for rendering one scene from one camera viewpoint. CanvasView does not hold a direct reference to the scene graph; instead it receives a get_scene_fn callable that is invoked each frame so ownership of the scene stays with SceneManager.

Camera change detection is implemented by comparing a cached CameraState snapshot each frame in _draw_frame. The _applying_model_state flag suppresses detection during programmatic camera updates to prevent feedback loops.

The view drives its pygfx camera controllers itself (auto_update=False): each frame it ticks the active controller and applies the state it returns, before the comparison. A moved camera is therefore detected in the frame that draws it, and whether the controller is still driving the camera (a drag held, its damped tail, a wheel or key animation) is known through public pygfx API. Changes of that answer are reported as _CameraControllerEvent.

Attributes:

Name Type Description
camera_moving bool

Whether this canvas's camera is in motion, set by the controller's camera tracker through RenderManager.set_camera_moving. Read by per-frame draw choices (a visual that draws coarse during motion).

Parameters:

Name Type Description Default
canvas_id UUID

Unique identifier for this canvas.

required
scene_id UUID

ID of the scene this canvas renders.

required
get_scene_fn Callable[[UUID], Scene]

Called each frame to retrieve the current scene. Provided by RenderManager at construction time.

required
dim str

Scene dimensionality: "2d" or "3d". Controls which camera type and interaction controller are used.

'3d'
parent QWidget or None

Parent widget for the underlying QRenderWidget.

None
fov float

Vertical field of view in degrees (3D perspective only).

70.0
depth_range tuple[float, float]

Near and far clip distances (near, far).

(1.0, 8000.0)
outline_enabled bool

When True, install a blender carrying the outline_id render target so label outlines have a per-pixel label key. Costs 4 bytes per pixel. Deciding here is the cheap path, not the only one: :meth:ensure_render_targets adds it later for the price of one recompile frame.

False
ambient_occlusion_enabled bool

When True, install a blender carrying the normal render target so cellier's volume shaders can hand the ambient occlusion pass a real surface normal instead of one reconstructed from depth. Costs 8 bytes per pixel, and is addable later by the same route as outline_enabled.

False

connected property

connected: bool

Whether this canvas's front end has reported itself live.

canvas_id property

canvas_id: UUID

Unique identifier for this canvas.

scene_id property

scene_id: UUID

ID of the scene this canvas renders.

widget property

widget: object

The render canvas element to embed in the application layout.

A QRenderWidget for the Qt backend or an AnywidgetRenderCanvas for the anywidget backend.

camera property

camera: Camera

The active pygfx camera for this canvas.

dim property

dim: str

"2d" or "3d": which camera this canvas draws with.

last_camera_state property

last_camera_state: CameraState

The camera state most recently reported or accepted.

close

close() -> None

Close the canvas, stopping its draw loop and releasing the GPU.

Dropping the last Python reference to a CanvasView is not enough to reclaim it. The canvas is a parentless (top-level) render widget, so the backend owns it and keeps it alive; through its draw callback and event filter it in turn pins this view, the WgpuRenderer, and the whole object graph they reach. Closing the canvas is what breaks that chain, after which normal refcounting reclaims everything.

Safe to call more than once, and safe when the GUI backend has already destroyed the canvas itself (e.g. the user closed the window).

capture_reslicing_request

capture_reslicing_request(dims_state: DimsState, selection: RegionSelection | None = None, target_visual_ids: frozenset[UUID] | None = None) -> ReslicingRequest

Snapshot the current camera state into a ReslicingRequest.

All array fields are copied. Screen size is read from the canvas at call time and baked into the returned request.

Parameters:

Name Type Description Default
dims_state DimsState

Current dimension display state.

required
selection RegionSelection or None

The region this canvas is showing, built by the controller from the scene's dims and this canvas's rendered system.

None
target_visual_ids frozenset[UUID] or None

None reslices all visuals in the scene.

None

Returns:

Type Description
ReslicingRequest

Fully populated snapshot with independent array copies.

set_depth_range

set_depth_range(depth_range: tuple[float, float]) -> None

Set the active camera near/far clip distances.

On the 3D camera this is the configured range, which is widened while the field of view is 0; see :meth:_sync_depth_range_3d.

Parameters:

Name Type Description Default
depth_range tuple[float, float]

(near, far) clip distances in world units.

required

set_depth_range_for_dim

set_depth_range_for_dim(dim: str, depth_range: tuple[float, float]) -> None

Set the near/far clip distances on the 2D or 3D camera.

Unlike :meth:set_depth_range, this targets a specific camera regardless of which is currently active. Both the 2D orthographic and 3D perspective cameras are created up front (see __init__), so the reserve camera must have its depth range set independently — otherwise it keeps the active camera's range, which for a 2D->3D toggle leaves the perspective camera with an invalid (e.g. negative) near plane and renders nothing.

Parameters:

Name Type Description Default
dim str

"2d" or "3d".

required
depth_range tuple[float, float]

(near, far) clip distances in world units.

required

show_object

show_object(scene: Scene) -> bool

Fit the camera to the scene bounding box, if there is one.

A scene with nothing in it has no bounding sphere, and pygfx raises rather than guessing. That happens for real: switching a scene's displayed axes rebuilds its visuals' geometry and fits the camera before the reslice that fills them has committed, so for one moment the scene is empty. Refusing to fit -- and, crucially, not marking the dim as fitted -- lets the caller try again once data arrives.

Parameters:

Name Type Description Default
scene Scene

The scene to fit the camera to.

required

Returns:

Type Description
bool

True if the camera was fitted. False if the scene had no bounds yet, in which case nothing was changed.

add_overlay

add_overlay(overlay: GFXCanvasOverlay) -> None

Attach a screen-space overlay to this canvas.

The overlay is rendered as an additional post-pass on top of the main scene each frame. Multiple overlays are rendered in insertion order.

Parameters:

Name Type Description Default
overlay GFXCanvasOverlay

The render-layer overlay to attach.

required

remove_overlay

remove_overlay(overlay: GFXCanvasOverlay) -> None

Detach a screen-space overlay from this canvas.

Parameters:

Name Type Description Default
overlay GFXCanvasOverlay

The render-layer overlay to detach. An overlay that is not attached is ignored.

required

add_plane_gizmo

add_plane_gizmo(gizmo_id: UUID, point, normal, *, screen_size: float = 100.0) -> GFXPlaneGizmo

Add a plane gizmo to this canvas, placed at a pose.

The gizmo is drawn in 3D only, after the scene and under the canvas overlays. Its drags are reported as PlaneGizmoMovedEvent.

Parameters:

Name Type Description Default
gizmo_id UUID

Names the gizmo on its events.

required
point array - like

Where to place it, in rendered (x, y, z): a point on the plane and the plane's normal.

required
normal array - like

Where to place it, in rendered (x, y, z): a point on the plane and the plane's normal.

required
screen_size float

The gizmo's size on screen, in logical pixels.

100.0

Returns:

Type Description
GFXPlaneGizmo

Raises:

Type Description
ValueError

If the canvas already has a gizmo with that id.

remove_plane_gizmo

remove_plane_gizmo(gizmo_id: UUID) -> None

Remove a plane gizmo; a drag in progress is ended and reported.

A gizmo this canvas does not have is ignored.

get_plane_gizmo

get_plane_gizmo(gizmo_id: UUID) -> GFXPlaneGizmo

The plane gizmo with that id.

Raises:

Type Description
KeyError

If this canvas has no such gizmo.

orbit_point

orbit_point() -> tuple[float, float, float] | None

The point the 3D camera orbits about, in rendered (x, y, z).

None in 2D. With no custom target, pygfx's OrbitController.target is the offset from the camera, so the camera's position is added (gizmo design v2, V5).

plane_gizmo_object_ids

plane_gizmo_object_ids() -> set[int]

The pygfx ids of every element of this canvas's plane gizmos.

invalidate_accumulation

invalidate_accumulation() -> None

Discard the temporal accumulation history before the next frame.

Call whenever the image that should be drawn changes, so the next frame is not an average with a picture that no longer applies. Cheap and idempotent: it sets a flag that _draw_frame consumes, and the pass itself only zeroes a counter.

Every content change needs this, not just the conspicuous ones. Hiding a visual is merely the case where the stale average is obvious; a colormap, clim, opacity, transform or data commit leaves the same residue and reads as sluggishness instead.

request_draw

request_draw() -> None

Request a redraw of the canvas.

Cellier calls this for content changes, so it also invalidates the accumulation history. Idle and continuous redraws come from the backend's own scheduler and never reach here, which is what lets them keep accumulating.

request_frame

request_frame() -> None

Ask the canvas for a frame without discarding accumulation.

For a frame whose content did not change: the next step of a camera controller's animation, or the still picture after a camera motion ended. :meth:request_draw is the one for content changes.

accept_camera_state

accept_camera_state() -> bool

Take the camera's current state as the one already reported.

Call after moving the pygfx camera programmatically. The next draw then sees no difference, so the move is not mistaken for camera motion; the caller reports it instead. The accumulation history is discarded, because the camera really did move.

Returns:

Type Description
bool

True if the camera differs from the last reported state. False if nothing moved, in which case nothing is changed.

set_camera_state

set_camera_state(state: CameraState) -> None

Apply a CameraState to the active pygfx camera.

Only the fields of the active camera's kind are applied: a perspective camera takes fov, an orthographic one extent. A perspective camera with a fov of 0 takes extent as well, where the state has one: it is what an orthographic zoom changes. up is not applied: it is the up direction the rotation already gives. The caller reports the move; see :meth:accept_camera_state.

Parameters:

Name Type Description Default
state CameraState

The state to apply.

required

Raises:

Type Description
ValueError

If state is for the other kind of camera than the active one.

set_event_bus

set_event_bus(event_bus: EventBus) -> None

Wire the EventBus after construction.

set_controller_enabled

set_controller_enabled(enabled: bool) -> None

Enable or disable the active camera controller for this canvas.

self._controller already points to the currently active controller (_controller_2d or _controller_3d depending on the canvas dim), so this correctly targets whichever type is in use.

Parameters:

Name Type Description Default
enabled bool

False disables the controller (paint mode active). True restores normal camera interaction.

required

switch_dim

switch_dim(new_dim: str) -> bool

Switch the canvas between "2d" and "3d" rendering modes.

Disables the current controller and enables the one for new_dim. Camera pose is preserved across toggles.

Parameters:

Name Type Description Default
new_dim str

"2d" or "3d".

required

Returns:

Type Description
bool

True if this is the first time new_dim has been activated on this canvas (caller should call show_object to fit the camera). False if the camera pose was already set by a previous visit.

apply_ambient_occlusion_config

apply_ambient_occlusion_config(config: AmbientOcclusionConfig) -> None

Push an AmbientOcclusionConfig onto this canvas's occlusion pass.

Parameters:

Name Type Description Default
config AmbientOcclusionConfig

The configuration to apply. Its enabled flag is recorded as the requested state; the pass itself stays off while the canvas is in 2D.

required

set_ssao_enabled

set_ssao_enabled(enabled: bool) -> None

Request ambient occlusion on this canvas.

Honoured only in 3D. The request is remembered either way, so a canvas switched to 2D and back returns to the requested state.

Parameters:

Name Type Description Default
enabled bool

Whether the caller wants the pass to run.

required

ensure_render_targets

ensure_render_targets(*, outline: bool = False, ssao: bool = False) -> None

Add the render targets a feature needs, after construction.

The targets are chosen at construction from the render config, which is right for a viewer that was configured up front and wrong for one where a user ticks the box later: a feature switched on afterwards would run without its target and quietly degrade -- ambient occlusion to normals reconstructed from depth, outlines to whole-object silhouettes with no per-label boundaries. This adds the missing target instead, at the cost of one recompile frame.

Safe to call repeatedly; it does nothing when the targets are already present, which is the common case. Not safe to call from inside a draw callback -- see :func:ensure_extra_targets.

Parameters:

Name Type Description Default
outline bool

Ensure the outline_id target, for per-label outlines.

False
ssao bool

Ensure the normal target, for occlusion on raymarched isosurfaces.

False

set_scene_extent

set_scene_extent(diagonal: float) -> None

Forward the scene bounding box diagonal to the occlusion pass.

Parameters:

Name Type Description Default
diagonal float

Length of the scene bounding box diagonal, in scene units.

required

capture_camera_state

capture_camera_state() -> CameraState

Snapshot the current pygfx camera into a CameraState NamedTuple.

For the 3D camera depth_range is the configured range, not the one widened for a field of view of 0 (see :meth:_sync_depth_range_3d), and extent is the camera's width and height at a field of view of 0 and (0.0, 0.0) above it.

hold_draws

hold_draws(seconds: float, waiting: Callable[[], bool]) -> None

Let the next frames be skipped while waiting is true.

A frame that comes while waiting returns True is not rendered, so the canvas keeps showing what it last drew. The first frame skipped starts the clock: frames are skipped for at most seconds from it, then one is drawn whatever waiting says. The hold ends with the first frame drawn, or on camera input. Asking again while frames are being skipped does not restart the clock, so no frame is delayed by more than seconds.

Parameters:

Name Type Description Default
seconds float

The longest a frame is delayed; 0 or less does nothing.

required
waiting Callable[[], bool]

Whether there is still something to wait for.

required

release_hold

release_hold() -> None

End a hold: the next frame is drawn.

Config

cellier.render.CameraConfig pydantic-model

Bases: BaseModel

Configuration for camera-driven automatic reslicing.

Parameters:

Name Type Description Default
reslice_enabled bool

When False camera movement never triggers a reslice. Manual calls to CellierController.reslice_scene still work.

required
settle_threshold_s float

The camera tracker's stillness time: seconds without a camera change after which a camera motion ends and camera-sensitive visuals reslice. A motion driven by the camera controller normally ends sooner, in the frame after the controller stops moving the camera (a drag released and its damped tail finished); this is what ends a motion while a drag is held still. Lower values give more responsive LOD updates; higher values reduce redundant I/O.

required

Fields:

  • reslice_enabled (bool)
  • settle_threshold_s (float)

cellier.render.RenderManagerConfig pydantic-model

Bases: BaseModel

Top-level rendering performance configuration.

Pass an instance to CellierController(render_config=...) at construction time. The live state is always accessible and serializable via render_manager.config.

Parameters:

Name Type Description Default
slicing SlicingConfig

Async chunk-slicing pipeline settings (non-chunked visuals).

required
scheduler SchedulerConfig

Chunk scheduler settings (multiscale visuals).

required
temporal TemporalAccumulationConfig

Temporal accumulation pass settings.

required
camera CameraConfig

Camera-driven reslicing settings.

required
outline OutlineConfig

Screen-space outline pass settings. Disabled by default.

required
ambient_occlusion AmbientOcclusionConfig

Screen-space ambient occlusion settings. Disabled by default. The pass that implements it is still called SSAO -- that is the algorithm's name -- but the setting is named for what it does.

required
draw_hold_ms float

After a dims change, how long a canvas may skip frames, keeping its last picture, while a visual that hides until its data loads (a mesh) waits for its read. A read that lands within this time is drawn with no blank frame before it; after it the canvas draws as usual, the visual hidden until it loads. The picture kept is of the position just left, and this is the most the hold delays a frame. A canvas draws about every 33 ms, so a value under that skips one frame at most. 0 turns the hold off. Camera input ends a hold at once.

required

Examples:

Construct with custom settings and serialize:

>>> config = RenderManagerConfig(
...     slicing=SlicingConfig(batch_size=32, render_every=4),
...     temporal=TemporalAccumulationConfig(blend_weight=0.05),
...     camera=CameraConfig(settle_threshold_s=0.5),
... )
>>> json_str = config.model_dump_json()
>>> config2 = RenderManagerConfig.model_validate_json(json_str)

Fields:

cellier.render.SlicingConfig pydantic-model

Bases: BaseModel

Configuration for the async chunk-slicing pipeline.

These parameters are construction-time only. Changing them after RenderManager is created has no effect.

Parameters:

Name Type Description Default
batch_size int

Number of chunks fetched concurrently in each async batch. Higher values increase throughput but raise peak memory pressure.

required
render_every int

Number of completed batches between progressive redraws. 1 = redraw after every batch (lowest latency to first pixels); higher values reduce GPU upload overhead on fast I/O.

required

Fields:

  • batch_size (int)
  • render_every (int)

cellier.render.TemporalAccumulationConfig pydantic-model

Bases: BaseModel

Configuration for the temporal accumulation post-processing pass.

Parameters:

Name Type Description Default
enabled bool

When False the pass is bypassed entirely and each frame is shown raw. Useful for debugging or when jitter is disabled.

required
blend_weight float

Minimum EMA weight given to the current frame. During warm-up the weight is 1 / (frame_count + 1); once that falls below alpha the weight clamps to blend_weight. Lower values give smoother steady-state but slower convergence after a camera move. Must be in (0, 1].

required

Config:

  • validate_assignment: True

Fields:

Requests

cellier.render.DimsState

Bases: NamedTuple

Current dimension display state for a scene.

cellier.render.ReslicingRequest

Bases: NamedTuple

Frozen snapshot driving a complete reslicing cycle.

Constructed by CanvasView.capture_reslicing_request() and consumed by SliceCoordinator. All array fields must be .copy()d by the caller — the NamedTuple does not enforce this.

Parameters:

Name Type Description Default
camera_type str

"perspective" or "orthographic".

required
camera_pos (ndarray, shape(3))

World-space camera position, copy.

required
frustum_corners (ndarray, shape(2, 4, 3))

World-space frustum corners, copy. For orthographic cameras this is set to np.zeros((2, 4, 3)).

required
fov_y_rad float

Vertical field of view in radians. 0.0 for orthographic.

required
screen_size_px tuple[float, float]

Logical (width, height) in pixels, baked in at snapshot time.

required
world_extent tuple[float, float]

Visible (width, height) in world units for orthographic cameras, a 3D camera at a field of view of 0 included. (0.0, 0.0) for perspective cameras.

required
dims_state DimsState

Current dimension display state.

required
selection RegionSelection or None

Where this canvas's slice is and how thick, as one frozen artifact (D43). The transform is the rendered -> world embedding whose constant column carries the slice positions; the region is in world coordinates. None when the controller could not build one -- a scene with no rendered system yet -- in which case the planning phase falls back to dims_state.

required
request_id UUID

Unique identifier per trigger; used for cancellation.

required
scene_id UUID

Which scene this camera belongs to.

required
canvas_id UUID

Which canvas produced this request. Used by SliceCoordinator to key cancellation entries so that requests from different canvases rendering the same scene can be tracked and cancelled independently.

required
target_visual_ids frozenset[UUID] or None

None means reslice all visuals in the scene (camera-moved case). A non-None set means reslice only those specific visuals (data-updated case).

required

Scene config

cellier.render.VisualRenderConfig dataclass

Mutable render settings for one visual.

Passed through the call stack at reslice time. When a visual's ID is absent from the visual_configs dict supplied to SceneManager.build_slice_requests, a default instance is used.

Parameters:

Name Type Description Default
settled_lod_bias float

Level-of-detail bias of a settled plan: a divisor on the LOD thresholds, so values greater than 1.0 favour coarser levels and values less than 1.0 finer ones. Default 1.0 (no bias).

1.0
force_level int or None

When set, all bricks are assigned this 1-based LOD level, bypassing distance-based selection entirely. None restores automatic selection. Default None.

None
frustum_cull bool

When True, bricks outside the camera frustum are skipped. When False, all bricks in the scene are submitted regardless of visibility. Default True.

True
slicing_enabled bool

When False, SceneManager plans no requests for the visual at all, so it keeps showing whatever it last loaded. The controller turns this off for hidden image visuals. Default True.

True
loading ProgressiveLoadingConfig

A multiscale visual's backstop settings (its render_config.loading). Ignored by every other visual.

ProgressiveLoadingConfig()
plan_mode PlanMode

What a multiscale visual plans this reslice: FULL (default), or BACKSTOP_ONLY for any reslice while the scene's dims are being scrubbed, when the visual opted in (its coarsest_while_moving setting for the view, or a mesh's lod.dims_drag="coarse").

FULL

Temporal accumulation

cellier.render.TemporalAccumulationPass

Bases: EffectPass

Post-processing pass that accumulates jittered frames over time.

Insert as the first entry in renderer.effect_passes so it operates on the raw raymarched output before anti-aliasing.

The history is kept in rgba16float rather than in the format of the incoming color texture. pygfx renders effect passes into rgba8unorm_srgb (see its blender.py, which carries a TODO: use half-floats of its own), and an EMA in 8 bits does not converge: one blend step moves a stored value by roughly alpha * (current - history) code values, so any difference under 0.5 / alpha code values rounds away to nothing and the history freezes there permanently. At the default alpha of 0.1 that floor is 4/255 -- a plainly visible ghost that no number of further frames can clear. A float history removes the floor, so a stale image decays continuously to zero at every alpha. It also puts the average in linear space, which is where it belongs.

Parameters:

Name Type Description Default
alpha float

Minimum blend weight for the current frame. During warm-up the weight is 1 / (frame_count + 1); once that falls below alpha the weight clamps to alpha. Lower values give smoother steady-state but slower convergence. Default 0.1 (steady state reached in ~10 still frames).

0.1

frame_count property

frame_count: int

Frames accumulated since the last reset.

The blend weight is 1 / (frame_count + 1) until that falls below alpha, so this is how far through the warm-up the image is: a GUI can turn it into the difference between "settling" and "settled", which is otherwise the one thing about this pass a user cannot see.

blend_weight property writable

blend_weight: float

Minimum blend weight for the current frame (EMA floor).

Lower values give smoother steady-state at the cost of slower convergence after a reset.

reset

reset() -> None

Discard accumulated history.

The next frame's blend weight becomes 1.0, so history is immediately overwritten. No GPU memory is freed or cleared.

Call this whenever the rendered image should no longer be an average with what came before: a camera move, any content change, and re-enabling the pass after a spell switched off (while disabled the pass is skipped entirely, so both the textures and _frame_count freeze -- without a reset the first frame back blends alpha of a picture of arbitrary age, with no warm-up).