Skip to content

Document the feature-table association split and core/layers responsibilities - #40

Merged
xinaesthete merged 8 commits into
mainfrom
codex/refactor-spatialcanvas-logic
Jun 8, 2026
Merged

Document the feature-table association split and core/layers responsibilities#40
xinaesthete merged 8 commits into
mainfrom
codex/refactor-spatialcanvas-logic

Conversation

@xinaesthete

@xinaesthete xinaesthete commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Clarify Python spatialdata as the source of truth for feature/table association semantics in the docs.
  • Document @spatialdata/core as the owner of FeatureTableAlignment and the row-alignment helpers, with @spatialdata/layers consuming resolved alignment for colour encoding.
  • Update the SpatialCanvas, layers, and MDV roadmap docs to reflect the current split and remaining tooltip/pick resolution work.

Testing

  • pnpm --filter docs build passed.
  • Earlier implementation verification remains green: @spatialdata/core, @spatialdata/layers, and @spatialdata/vis tests/builds passed, plus targeted Biome checks on the touched implementation files.

Summary by CodeRabbit

  • New Features

    • Public table-association helpers for resolving feature→row alignment
    • Shape color-encoding utilities for per-feature RGBA mapping with configurable palettes/ramps
    • SpatialViewer and a headless viewer/API for controlled 2D rendering
  • Documentation

    • Expanded guides on table/feature association semantics, headless usage, color-encoding best practices, demos, and release checklist
  • Updates

    • Demo app adds headless route and fixtures; site copy and package description refreshed; local fixture server port/config exposed

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 879eb4f8-3b43-46b5-8579-9f6178e0e1cf

📥 Commits

Reviewing files that changed from the base of the PR and between c40fbee and 036ffeb.

📒 Files selected for processing (1)
  • scripts/fixture-server-port.mjs

📝 Walkthrough

Walkthrough

This PR extracts feature→table row resolution into a core resolver (createFeatureTableAlignment), refactors shape color encoding to use pre-resolved indices and palettes, updates SpatialCanvas to consume shared helpers and re-export SpatialViewer, and expands docs, demos, and fixture/server tooling.

Changes

Feature-Table Alignment Refactor

Layer / File(s) Summary
Core feature-table alignment contract and resolver
packages/core/src/tableAssociations.ts, packages/core/tests/tableAssociations.spec.ts
New FeatureTableAlignment types and createFeatureTableAlignment() factory provide a shared row-index resolver with fallback priority: explicit rowIndex, featureIndex-based lookup, then featureId-based lookup. Tests validate each path and ensure numeric feature-id collisions do not override index-based resolution.
Shape color encoding refactor and customization
packages/layers/src/shapeColorEncoding.ts, packages/layers/src/index.ts, packages/layers/tests/shapeColorEncoding.spec.ts
buildShapeFillColorByFeatureId now depends on pre-resolved rowIndexByFeatureIndex from core (removes local rowIndexByFeatureId parameter), adds optional categoricalPalette and numericRamp overrides, introduces ShapeRgbColor/ShapeRgbaColor types, and exports default color constants. Tests confirm only resolved features appear in output and custom palettes drive returned RGBA values.
SpatialCanvas integration with core alignment
packages/vis/src/SpatialCanvas/types.ts, packages/vis/src/SpatialCanvas/useLayerData.ts, packages/vis/src/SpatialCanvas/public.ts, packages/vis/src/index.ts, packages/vis/tests/index.spec.tsx
useLayerData.ts imports core and layers helpers instead of local logic, removes rowIndexByFeatureId from buildShapeFillColorByFeatureId calls, uses ShapeFillColorMode from layers. SpatialViewer and SpatialViewerProps are added to public exports; tests confirm SpatialViewer export.
Architecture documentation and release tracking
docs/docs/core/overview.mdx, docs/docs/layers/overview.mdx, docs/docs/vis/feature-table-associations.mdx, docs/docs/vis/layer-prop-flow.mdx, docs/docs/vis/mdv-release-checklist.mdx, docs/docs/vis/spatial-canvas-status.mdx, plus new headless docs
Design docs expanded to describe the new alignment resolver contract and package boundaries (core resolves associations, layers convert resolved rows to per-feature colors, vis consumes helpers), introduce headless usage docs and demos, clarify region/region_key/instance_key semantics, and update MDV release/checklist items.
Headless demo and examples
packages/vis/demo/src/*
Adds headless blobs demo, headless layer builder, fixture URL helper, and demo routing to exercise headless viewer workflows.
Fixture server and dev tooling
scripts/*, packages/vis/vite.config.demo.ts, packages/vis/scripts/dev.mjs, tests/integration/*, README.md
Introduces fixture-server port defaults and helpers, updates test server to use the port constant, configures Vite dev proxy for /test-fixtures, starts fixture server in dev scripts, and updates tests/README to use the new port helper.
CI, editor, and site metadata
docs/docusaurus.config.ts, docs/src/pages/index.tsx, package.json, .github/workflows/test.yml, .vscode/settings.json, README.md
Updates site tagline and homepage title, package description, CI readiness probe port, VS Code settings, and README test-server docs.

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly Related PRs

🐰 A row index resolver hops in,
Features map to table tips,
Colors encode with cleaner grip—
Core and layers skip their flip,
Canvas consumes the shared script. 🎨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the primary change: documenting how feature-table association responsibilities are split between core and layers packages.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/refactor-spatialcanvas-logic

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
docs/src/pages/index.tsx (1)

26-26: ⚡ Quick win

Simplify by removing unnecessary template literal.

The template literal ${siteConfig.title} adds no value since you're only interpolating a single variable. Direct property access is cleaner.

♻️ Simplify to direct property access
-      title={`${siteConfig.title}`}
+      title={siteConfig.title}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/src/pages/index.tsx` at line 26, Replace the unnecessary template
literal in the JSX prop so title uses direct property access: change
title={`${siteConfig.title}`} to title={siteConfig.title} (locate the JSX where
the title prop is set and update the expression).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/tests/tableAssociations.spec.ts`:
- Around line 69-72: Replace the unsafe type assertion at the SpatialData
constructor call by ensuring the fixture object rootStore is declared with a
structural check using the TypeScript "satisfies ConsolidatedStore" operator
instead of "as ConsolidatedStore"; locate the test fixture that constructs new
SpatialData('https://example.com/mock.zarr', rootStore as ConsolidatedStore,
[...]) and change the declaration of rootStore (not the call site) so it uses
"satisfies ConsolidatedStore" to validate its shape while keeping its inferred
type for downstream code.

In `@packages/layers/src/shapeColorEncoding.ts`:
- Around line 126-127: The code currently indexes into categoricalPalette
without checking for emptiness, causing NaN/undefined colors; update the logic
around the mapping that sets colors[featureId] to first validate
categoricalPalette and fall back to the default palette variable (or a
predefined default) when categoricalPalette.length === 0, then compute
paletteColor = palette[index % palette.length] and call rgba(paletteColor,
alpha) so colors[featureId] always receives a valid color; modify the block that
assigns paletteColor and uses rgba to reference the safe palette instead of
categoricalPalette.

---

Nitpick comments:
In `@docs/src/pages/index.tsx`:
- Line 26: Replace the unnecessary template literal in the JSX prop so title
uses direct property access: change title={`${siteConfig.title}`} to
title={siteConfig.title} (locate the JSX where the title prop is set and update
the expression).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 37655351-0716-4fed-bf40-3b195b1881ed

📥 Commits

Reviewing files that changed from the base of the PR and between 000bb0b and a417028.

📒 Files selected for processing (19)
  • docs/docs/core/overview.mdx
  • docs/docs/layers/overview.mdx
  • docs/docs/vis/feature-table-associations.mdx
  • docs/docs/vis/layer-prop-flow.mdx
  • docs/docs/vis/mdv-release-checklist.mdx
  • docs/docs/vis/spatial-canvas-status.mdx
  • docs/docusaurus.config.ts
  • docs/src/pages/index.tsx
  • package.json
  • packages/core/src/tableAssociations.ts
  • packages/core/tests/tableAssociations.spec.ts
  • packages/layers/src/index.ts
  • packages/layers/src/shapeColorEncoding.ts
  • packages/layers/tests/shapeColorEncoding.spec.ts
  • packages/vis/src/SpatialCanvas/public.ts
  • packages/vis/src/SpatialCanvas/types.ts
  • packages/vis/src/SpatialCanvas/useLayerData.ts
  • packages/vis/src/index.ts
  • packages/vis/tests/index.spec.tsx

Comment on lines +69 to +72
return new SpatialData('https://example.com/mock.zarr', rootStore as ConsolidatedStore, [
'shapes',
'tables',
]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify current cast usage and inspect SpatialData constructor declaration.
fd 'tableAssociations.spec.ts$' packages/core/tests --exec rg -n -C2 'rootStore as ConsolidatedStore|new SpatialData'
fd 'index.ts$' packages/core/src/store --exec rg -n -C3 'class SpatialData|constructor\s*\('

Repository: Taylor-CCB-Group/SpatialData.js

Length of output: 605


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the fixture definition and imports in the spec
spec_file="packages/core/tests/tableAssociations.spec.ts"
echo "---- $spec_file (context around rootStore) ----"
rg -n "const rootStore|ConsolidatedStore|new SpatialData" "$spec_file" -n
echo "---- $spec_file (lines 50-95) ----"
nl -ba "$spec_file" | sed -n '50,95p'

# Locate the ConsolidatedStore type and see its required shape
echo "---- ConsolidatedStore definition (search) ----"
fd 'ConsolidatedStore' packages/core/src --exec rg -n "export (type|interface) ConsolidatedStore|class ConsolidatedStore|type ConsolidatedStore|interface ConsolidatedStore" 

# Also search within store directory for ConsolidatedStore usage / type exports
fd 'index.ts$' packages/core/src/store --exec rg -n "ConsolidatedStore" -S

# Try to open the file that actually declares ConsolidatedStore (best-effort)
# (Use rg to capture the file path from matches)
match_path="$(rg -n "export (type|interface) ConsolidatedStore|type ConsolidatedStore|interface ConsolidatedStore" packages/core/src/store -S --files-with-matches | head -n 1 || true)"
echo "---- candidate file: $match_path ----"
if [ -n "$match_path" ] && [ -f "$match_path" ]; then
  nl -ba "$match_path" | sed -n '1,200p'
fi

Repository: Taylor-CCB-Group/SpatialData.js

Length of output: 476


🏁 Script executed:

#!/bin/bash
set -euo pipefail

spec_file="packages/core/tests/tableAssociations.spec.ts"
echo "---- $spec_file (context around rootStore and cast) ----"
rg -n "const rootStore|ConsolidatedStore|as ConsolidatedStore|new SpatialData" "$spec_file"
echo "---- $spec_file (lines 40-90) ----"
nl -ba "$spec_file" | sed -n '40,90p'

echo "---- Searching for ConsolidatedStore declaration ----"
# Find the actual declaration location(s)
rg -n "export (type|interface) ConsolidatedStore|type ConsolidatedStore|interface ConsolidatedStore" packages/core/src/store -S --files-with-matches | head -n 20

declare_file="$(rg -n "export (type|interface) ConsolidatedStore|type ConsolidatedStore|interface ConsolidatedStore" packages/core/src/store -S --files-with-matches | head -n 1 || true)"
echo "---- candidate ConsolidatedStore file: $declare_file ----"
if [ -n "$declare_file" ] && [ -f "$declare_file" ]; then
  nl -ba "$declare_file" | sed -n '1,220p'
fi

echo "---- Checking SpatialData import of ConsolidatedStore (store/index etc) ----"
rg -n "ConsolidatedStore" packages/core/src -S | head -n 50

Repository: Taylor-CCB-Group/SpatialData.js

Length of output: 485


🏁 Script executed:

#!/bin/bash
set -euo pipefail

spec="packages/core/tests/tableAssociations.spec.ts"
echo "---- $spec (line count) ----"
wc -l "$spec"

echo "---- $spec (lines 1-40) ----"
awk 'NR>=1 && NR<=40 {print NR ":" $0}' "$spec"

echo "---- $spec (lines 55-85) ----"
awk 'NR>=55 && NR<=85 {print NR ":" $0}' "$spec"

echo "---- Occurrences of ConsolidatedStore casts ----"
rg -n "as\s+ConsolidatedStore" "$spec"

Repository: Taylor-CCB-Group/SpatialData.js

Length of output: 2532


Replace the rootStore as ConsolidatedStore cast with satisfies ConsolidatedStore in the fixture.
SpatialData’s constructor takes rootStore: ConsolidatedStore, and the test fixture currently uses as at the call site, which can mask fixture structural drift.

Suggested diff
-  const rootStore = {
+  const rootStore = {
     tree: {
       shapes: {
         cells: {
           [ATTRS_KEY]: {
             'encoding-type': 'ngff:shapes',
           },
         },
         cell_circles: {
           [ATTRS_KEY]: {
             'encoding-type': 'ngff:shapes',
           },
         },
         nuclei: {
           [ATTRS_KEY]: {
             'encoding-type': 'ngff:shapes',
           },
         },
       },
       tables: {
         cells_table: {
           [ATTRS_KEY]: {
             instance_key: 'cell_id',
             region: 'cells',
             region_key: 'region',
             'spatialdata-encoding-type': 'ngff:regions_table',
           },
         },
         path_table: {
           ...
         },
         xenium_table: {
           [ATTRS_KEY]: {
             instance_key: 'cell_id',
             region: ['cells', 'cell_circles'],
             region_key: 'region',
             'spatialdata-encoding-type': 'ngff:regions_table',
           },
         },
       },
     },
     zarritaStore: {},
-  };
+  } satisfies ConsolidatedStore;
 
-  return new SpatialData('https://example.com/mock.zarr', rootStore as ConsolidatedStore, [
+  return new SpatialData('https://example.com/mock.zarr', rootStore, [
     'shapes',
     'tables',
   ]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/tests/tableAssociations.spec.ts` around lines 69 - 72, Replace
the unsafe type assertion at the SpatialData constructor call by ensuring the
fixture object rootStore is declared with a structural check using the
TypeScript "satisfies ConsolidatedStore" operator instead of "as
ConsolidatedStore"; locate the test fixture that constructs new
SpatialData('https://example.com/mock.zarr', rootStore as ConsolidatedStore,
[...]) and change the declaration of rootStore (not the call site) so it uses
"satisfies ConsolidatedStore" to validate its shape while keeping its inferred
type for downstream code.

Comment on lines +126 to 127
const paletteColor = categoricalPalette[index % categoricalPalette.length];
colors[featureId] = rgba(paletteColor, alpha);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Empty categoricalPalette causes invalid color output.

If a caller passes an empty categoricalPalette, index % 0 yields NaN, and categoricalPalette[NaN] returns undefined. This propagates invalid values into the color map.

Consider validating the palette or falling back to the default when empty.

Proposed guard
 export function buildShapeFillColorByFeatureId({
   featureIds,
   rowIndexByFeatureIndex,
   column,
   mode,
   alpha,
   categoricalPalette = DEFAULT_SHAPE_CATEGORICAL_PALETTE,
   numericRamp = DEFAULT_SHAPE_NUMERIC_RAMP,
 }: BuildShapeFillColorByFeatureIdOptions): Record<string, ShapeRgbaColor> {
   if (!column) return {};
+  const palette = categoricalPalette.length > 0 ? categoricalPalette : DEFAULT_SHAPE_CATEGORICAL_PALETTE;

Then use palette instead of categoricalPalette at line 126.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/layers/src/shapeColorEncoding.ts` around lines 126 - 127, The code
currently indexes into categoricalPalette without checking for emptiness,
causing NaN/undefined colors; update the logic around the mapping that sets
colors[featureId] to first validate categoricalPalette and fall back to the
default palette variable (or a predefined default) when
categoricalPalette.length === 0, then compute paletteColor = palette[index %
palette.length] and call rgba(paletteColor, alpha) so colors[featureId] always
receives a valid color; modify the block that assigns paletteColor and uses rgba
to reference the safe palette instead of categoricalPalette.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
packages/vis/demo/src/HeadlessBlobsDemo.tsx (1)

25-27: ⚡ Quick win

Remove the debug table lookup/log from render path.

This work is unused and logs on every render, which adds noise and unnecessary overhead.

🧹 Proposed cleanup
-  const tables = spatialData?.getAssociatedTables("shapes", "blobs_multipolygons");
-  console.log(tables);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/vis/demo/src/HeadlessBlobsDemo.tsx` around lines 25 - 27, Remove the
debug lookup and console.log from the render path: delete the call that assigns
tables from spatialData?.getAssociatedTables("shapes", "blobs_multipolygons")
and the subsequent console.log(tables) in the HeadlessBlobsDemo component so you
no longer perform an unused lookup or log on every render; if the lookup is
needed for future debugging, move it behind a conditional or into a
callback/handler (or a useEffect with appropriate deps) and replace console.log
with proper logging only where required.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/test.yml:
- Around line 75-76: Replace the hardcoded port literal "38473" used in the curl
readiness probes with the shared fixture-port variable so the CI uses the
canonical port value; update the two curl invocations (the lines containing
"curl -sSf http://localhost:38473/" and "curl -sSf
http://localhost:38473/v0.5.0/blobs.zarr/zmetadata") and the other occurrences
noted (around the same block) to reference the existing fixture-port variable
(use the correct expansion for the workflow context, e.g. ${{ env.FIXTURE_PORT
}} or $FIXTURE_PORT depending on whether the line runs in a step shell) so all
probes derive from the single source of truth instead of the literal 38473.

In `@docs/docs/vis/spatial-canvas-status.mdx`:
- Line 19: The 3D limitation sentence is missing a verb and reads awkwardly;
update the bullet for SpatialCanvas/SpatialCanvasViewer to read clearly (e.g.,
replace "3D is not supported for MDV v1 integration, but a high priority
following that." with "3D is not supported for MDV v1 integration, but it is a
high priority for future work.") and ensure the surrounding references to Viv
DetailView, ViewState3D, and the MDV v1 integration remain intact and accurate.

In `@scripts/fixture-server-port.mjs`:
- Around line 8-10: The exported FIXTURE_SERVER_PORT currently uses Number(...)
directly which can produce NaN, 0, negatives or non-integers; change the
initialization to parse the chosen env var as an integer (e.g. parseInt on
process.env.SPATIALDATA_FIXTURE_PORT ?? process.env.PORT ??
DEFAULT_FIXTURE_SERVER_PORT), then validate with Number.isInteger and a port
range (1–65535) and if invalid throw a clear Error (e.g. "Invalid
FIXTURE_SERVER_PORT: ...") so the process fails fast; keep
DEFAULT_FIXTURE_SERVER_PORT as the fallback value and ensure the final exported
FIXTURE_SERVER_PORT is a validated integer.

---

Nitpick comments:
In `@packages/vis/demo/src/HeadlessBlobsDemo.tsx`:
- Around line 25-27: Remove the debug lookup and console.log from the render
path: delete the call that assigns tables from
spatialData?.getAssociatedTables("shapes", "blobs_multipolygons") and the
subsequent console.log(tables) in the HeadlessBlobsDemo component so you no
longer perform an unused lookup or log on every render; if the lookup is needed
for future debugging, move it behind a conditional or into a callback/handler
(or a useEffect with appropriate deps) and replace console.log with proper
logging only where required.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bf77ec53-c8ac-4eeb-885e-747d08f51139

📥 Commits

Reviewing files that changed from the base of the PR and between a417028 and c40fbee.

📒 Files selected for processing (22)
  • .github/workflows/test.yml
  • .vscode/settings.json
  • README.md
  • docs/docs/core/overview.mdx
  • docs/docs/intro.mdx
  • docs/docs/layers/overview.mdx
  • docs/docs/vis/headless-viewer.mdx
  • docs/docs/vis/mdv-integration.mdx
  • docs/docs/vis/mdv-release-checklist.mdx
  • docs/docs/vis/overview.mdx
  • docs/docs/vis/spatial-canvas-status.mdx
  • packages/core/README.md
  • packages/vis/demo/src/App.tsx
  • packages/vis/demo/src/HeadlessBlobsDemo.tsx
  • packages/vis/demo/src/buildHeadlessLayers.ts
  • packages/vis/demo/src/fixtureUrls.ts
  • packages/vis/scripts/dev.mjs
  • packages/vis/vite.config.demo.ts
  • scripts/fixture-server-defaults.mjs
  • scripts/fixture-server-port.mjs
  • scripts/test-server.js
  • tests/integration/fixtures.test.ts
✅ Files skipped from review due to trivial changes (12)
  • .vscode/settings.json
  • docs/docs/vis/overview.mdx
  • packages/core/README.md
  • packages/vis/demo/src/fixtureUrls.ts
  • packages/vis/demo/src/buildHeadlessLayers.ts
  • scripts/fixture-server-defaults.mjs
  • docs/docs/layers/overview.mdx
  • docs/docs/vis/headless-viewer.mdx
  • README.md
  • docs/docs/intro.mdx
  • docs/docs/vis/mdv-integration.mdx
  • docs/docs/vis/mdv-release-checklist.mdx

Comment on lines +75 to +76
if curl -sSf http://localhost:38473/ >/dev/null && \
curl -sSf http://localhost:38473/v0.5.0/blobs.zarr/zmetadata >/dev/null; then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Avoid hardcoding fixture port in CI probe.

The workflow duplicates 38473 instead of deriving from one variable, so it can drift from the shared fixture-port config and break readiness checks.

Suggested fix
       - name: Run integration tests with local server
         shell: bash
         run: |
+          FIXTURE_PORT="${SPATIALDATA_FIXTURE_PORT:-38473}"
+
           # Verify fixtures exist before starting server
           if [ ! -d "test-fixtures/v0.5.0/blobs.zarr" ]; then
             echo "Error: Fixtures not found at test-fixtures/v0.5.0/blobs.zarr"
             echo "Listing test-fixtures directory:"
             ls -la test-fixtures/ || echo "test-fixtures directory does not exist"
             exit 1
           fi
           
           # Start test server in background
-          pnpm test:server &
+          SPATIALDATA_FIXTURE_PORT="$FIXTURE_PORT" pnpm test:server &
           SERVER_PID=$!
@@
-            if curl -sSf http://localhost:38473/ >/dev/null && \
-               curl -sSf http://localhost:38473/v0.5.0/blobs.zarr/zmetadata >/dev/null; then
+            if curl -sSf "http://localhost:${FIXTURE_PORT}/" >/dev/null && \
+               curl -sSf "http://localhost:${FIXTURE_PORT}/v0.5.0/blobs.zarr/zmetadata" >/dev/null; then
               echo "Test server is up and serving fixtures"
               break
             fi
-            echo "Waiting for test server on http://localhost:38473/ ..."
+            echo "Waiting for test server on http://localhost:${FIXTURE_PORT}/ ..."
             sleep 1
           done
@@
-          # Run integration tests (will hit http://localhost:38473/…)
+          # Run integration tests (will hit http://localhost:${FIXTURE_PORT}/…)
           pnpm test:integration

Also applies to: 80-80, 87-87

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/test.yml around lines 75 - 76, Replace the hardcoded port
literal "38473" used in the curl readiness probes with the shared fixture-port
variable so the CI uses the canonical port value; update the two curl
invocations (the lines containing "curl -sSf http://localhost:38473/" and "curl
-sSf http://localhost:38473/v0.5.0/blobs.zarr/zmetadata") and the other
occurrences noted (around the same block) to reference the existing fixture-port
variable (use the correct expansion for the workflow context, e.g. ${{
env.FIXTURE_PORT }} or $FIXTURE_PORT depending on whether the line runs in a
step shell) so all probes derive from the single source of truth instead of the
literal 38473.


## Known limitations

- **No 3D rendering:** `SpatialCanvas`, `SpatialCanvasViewer`, and the underlying Viv/deck stack are **2D Cartesian only**. The viewer uses Viv `DetailView` (orthographic pan/zoom), not `OrbitView` or volume rendering. You can select an image **`z`** slice (or `c` / `t`) through `LayerConfig.channels`, but that is OME axis indexing — not 3D scene navigation. `ViewState` includes a `ViewState3D` type stub, but pitch, bearing, and orbit state are not wired through to rendering. **3D is not supported for MDV v1 integration, but a high priority following that.**

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the broken sentence in the 3D limitation bullet.

The clause reads awkwardly and drops a verb (“but a high priority…”), which hurts docs clarity.

✏️ Proposed wording fix
-- **No 3D rendering:** `SpatialCanvas`, `SpatialCanvasViewer`, and the underlying Viv/deck stack are **2D Cartesian only**. The viewer uses Viv `DetailView` (orthographic pan/zoom), not `OrbitView` or volume rendering. You can select an image **`z`** slice (or `c` / `t`) through `LayerConfig.channels`, but that is OME axis indexing — not 3D scene navigation. `ViewState` includes a `ViewState3D` type stub, but pitch, bearing, and orbit state are not wired through to rendering. **3D is not supported for MDV v1 integration, but a high priority following that.**
+- **No 3D rendering:** `SpatialCanvas`, `SpatialCanvasViewer`, and the underlying Viv/deck stack are **2D Cartesian only**. The viewer uses Viv `DetailView` (orthographic pan/zoom), not `OrbitView` or volume rendering. You can select an image **`z`** slice (or `c` / `t`) through `LayerConfig.channels`, but that is OME axis indexing — not 3D scene navigation. `ViewState` includes a `ViewState3D` type stub, but pitch, bearing, and orbit state are not wired through to rendering. **3D is not supported for MDV v1 integration, but it is a high priority afterward.**
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **No 3D rendering:** `SpatialCanvas`, `SpatialCanvasViewer`, and the underlying Viv/deck stack are **2D Cartesian only**. The viewer uses Viv `DetailView` (orthographic pan/zoom), not `OrbitView` or volume rendering. You can select an image **`z`** slice (or `c` / `t`) through `LayerConfig.channels`, but that is OME axis indexing — not 3D scene navigation. `ViewState` includes a `ViewState3D` type stub, but pitch, bearing, and orbit state are not wired through to rendering. **3D is not supported for MDV v1 integration, but a high priority following that.**
- **No 3D rendering:** `SpatialCanvas`, `SpatialCanvasViewer`, and the underlying Viv/deck stack are **2D Cartesian only**. The viewer uses Viv `DetailView` (orthographic pan/zoom), not `OrbitView` or volume rendering. You can select an image **`z`** slice (or `c` / `t`) through `LayerConfig.channels`, but that is OME axis indexing — not 3D scene navigation. `ViewState` includes a `ViewState3D` type stub, but pitch, bearing, and orbit state are not wired through to rendering. **3D is not supported for MDV v1 integration, but it is a high priority afterward.**
🧰 Tools
🪛 LanguageTool

[uncategorized] ~19-~19: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...supported for MDV v1 integration, but a high priority following that.** - **Channel UI is bas...

(EN_COMPOUND_ADJECTIVE_INTERNAL)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/docs/vis/spatial-canvas-status.mdx` at line 19, The 3D limitation
sentence is missing a verb and reads awkwardly; update the bullet for
SpatialCanvas/SpatialCanvasViewer to read clearly (e.g., replace "3D is not
supported for MDV v1 integration, but a high priority following that." with "3D
is not supported for MDV v1 integration, but it is a high priority for future
work.") and ensure the surrounding references to Viv DetailView, ViewState3D,
and the MDV v1 integration remain intact and accurate.

Comment thread scripts/fixture-server-port.mjs
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@xinaesthete
xinaesthete merged commit 5d1a450 into main Jun 8, 2026
2 checks passed
@xinaesthete
xinaesthete deleted the codex/refactor-spatialcanvas-logic branch June 8, 2026 15:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant