Extension points overview#
This page describes the supported extension points for contributors: how to add features without breaking performance, persistence, or UI modularity.
If you want step-by-step “do exactly this” guides, jump to:
Action layer, state domains and history (“How to add an action”, “How to add a piece of state”)
At a glance#
Audience
Developers extending Cellucid: read fully.
Golden rules (avoid common architectural mistakes)#
Keep boundaries crisp
UI modules own DOM and dispatch actions; an action’s implementation calls the state/viewer APIs. A control calls no mutating state method.
State owns typed arrays and emits events.
Viewer owns WebGL resources and render loops.
Never add per-frame DOM work
If it needs to update frequently, it belongs in the renderer or a debounced UI update.
Avoid hot-path allocations
Reuse typed arrays and scratch buffers.
Benchmark before/after for large datasets.
Think about the history and persistence on day one
Every change a person can make is an action, so it is undoable and replays; what it changes belongs to a state domain, so a step, an undo and a session hold it.
If something should not be kept, exclude it explicitly so users aren’t surprised.
Document edge cases and failure modes
Especially for: filters ↔ highlights ↔ multiview ↔ analysis ↔ export ↔ sessions.
Extension point categories#
2) Add an analysis mode / plot / compute operation#
When you want:
a new analysis UI mode (e.g. new “tab” in the Analysis panel)
a new plot type
a new transform/statistical test
Go to:
Key files involved:
cellucid/assets/js/app/analysis/comparison-module.jscellucid/assets/js/app/analysis/ui/analysis-ui-manager.jscellucid/assets/js/app/analysis/plots/types/*cellucid/assets/js/app/analysis/compute/*
3) Add an export renderer#
When you want:
a new SVG renderer variant
a new PNG exporter option
a new file format (e.g. PDF-like vector output, if supported)
Go to:
Key files involved:
cellucid/assets/js/app/ui/modules/figure-export/figure-export-engine.jscellucid/assets/js/app/ui/modules/figure-export/renderers/*
4) Add a new data source#
Pick the smallest of three extension points:
A new host for links (a repository or cloud drive): one provider module under
cellucid/assets/js/data/sources/providers/plus one line inDEFAULT_PROVIDERS(data/sources/registry.js, whose header states the provider contract). A provider only says where the bytes are; it never parses a format.A new file format: one entry in
cellucid/assets/js/data/input-formats.js(regeneratetests/fixtures/input-formats.json, which Python and R read), plus a layout view underdata/anndata/views/for a format read in place, or a transcoder underdata/anndata/transcode/for one read once.A new kind of source (beyond local-demo/local-user/remote/link/jupyter): start with
cellucid/assets/js/data/data-source-manager.jsandcellucid/assets/js/data/data-source.js(contracts + validation), then wire it intocellucid/assets/js/app/main.jsand the dataset connections UI.
5) Add an action#
When you want:
a new change a person, an agent, or a Python or R host can make (it becomes one undoable history step, an agent tool, a Python method and an R function)
a new read an agent or a host can ask for
Go to:
Action layer, state domains and history (“How to add an action”)
Key files involved:
cellucid/assets/js/app/actions/definitions/<area>.js(the definition)the module that owns the state (
getActions().provide(type, handler))cellucid/scripts/generate-action-catalog.mjs,cellucid-python/scripts/generate_actions.py,cellucid-r/tools/generate-actions.R,cellucid/scripts/generate-relay-bundle.mjs(regenerate every surface)
6) Add a piece of persisted state#
When you add state that should be undone and saved:
make it a state domain’s value, or part of one (
cellucid/assets/js/app/state/domains/): the history, the autosave and the session file hold it with no encoder of their ownevery action that can change it names the domain in
touches
See:
Action layer, state domains and history (“How to add a piece of state”)
“Should this be state, UI, or viewer?”#
Use this decision checklist:
If it is a user preference or UI selection → UI module + (maybe)
DataStatefield; a stable sidebar control is a setting (settingsdomain) with no code.If it affects which points are visible or colored →
DataState(typed arrays) + viewer update calls.If it affects how pixels are drawn (shader, buffers, per-frame loops) → rendering layer.
If it is a derived artifact (analysis result, export output) → keep it off the hot path; compute on-demand.