Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
239 commits
Select commit Hold shift + click to select a range
5937007
feat: WIP - Add catmaid data source
afonsobspinto Nov 25, 2025
ea43e6a
feat: WIP - Reshape catmaid datasource to segmentation layer
afonsobspinto Nov 27, 2025
ac3e06d
feat: Load catmaid skeletons into neuroglancer
afonsobspinto Nov 30, 2025
9567de8
feat: Disable application of catmaid stack info
afonsobspinto Nov 30, 2025
f52bd13
feat: WIP - Add spatially indexed skeletons
afonsobspinto Dec 11, 2025
b91d088
feat: Create coordinate space based on stack info
afonsobspinto Dec 11, 2025
b1d810a
feat: Add catmaid credentials provider
afonsobspinto Dec 22, 2025
9579b1a
feat: Add chunk fetching via SliceViewSpatiallyIndexedSkeletonLayer
afonsobspinto Dec 23, 2025
f58a399
feat: Draw all nodes without filtering
afonsobspinto Dec 24, 2025
5783674
feat: WIP - Draw all nodes with segment colors
afonsobspinto Dec 24, 2025
e0e1d3d
feat: WIP - Draw all nodes as lines
afonsobspinto Jan 5, 2026
509743f
feat: WIP - Draw segments with correct colors
afonsobspinto Jan 6, 2026
90967bf
feat: Add 'non-chunked' skeleton source
afonsobspinto Jan 8, 2026
f2fed63
chore: Add info and debug logs
afonsobspinto Jan 8, 2026
12c4558
feat: WIP - Add inter-chunk connections
afonsobspinto Jan 13, 2026
b82f5a5
fix: WIP - Correct node color in 2D
afonsobspinto Jan 13, 2026
357d031
feat: WIP - Make visible chunks zoom-relative
afonsobspinto Jan 13, 2026
16575dc
fix: Fix spatially indexed skeleton node colors in 3D viewer
afonsobspinto Jan 15, 2026
1ab935e
feat: Add spatially indexed skeletons to segmentation user controls
afonsobspinto Jan 15, 2026
03c778f
fix: Update skeleton shader to work with alpha values
afonsobspinto Jan 15, 2026
df3fe7b
feat: Use msgpack instead of json
afonsobspinto Jan 20, 2026
cd6b18f
feat: Skip visible segments when both sources are active
afonsobspinto Jan 20, 2026
7dd5bdb
feat: Add new hidden segment opacity slider
afonsobspinto Jan 20, 2026
5695843
feat: Add LOD slider
afonsobspinto Jan 20, 2026
f7a3bcf
feat: Add CatmaidMultiscaleSpatiallyIndexedSkeletonSource
afonsobspinto Jan 21, 2026
e520694
feat: Read extraNodes and limitReached info from catmaid
afonsobspinto Jan 23, 2026
c75998f
feat: Add catmaid stackInfoCache
afonsobspinto Jan 26, 2026
7edb7db
refator: Move interface to skeleton folder
afonsobspinto Jan 26, 2026
6500309
feat: Add cache provider param
afonsobspinto Jan 26, 2026
396def5
feat: Rework spatially indexed skeleton rendering to build a single f…
afonsobspinto Feb 3, 2026
449039f
feat: Add inter-chunk connectivity
afonsobspinto Feb 4, 2026
e883f8b
feat: Add resolution sliders
afonsobspinto Feb 4, 2026
343e5e1
feat: Update resolution sliders base variable
afonsobspinto Feb 4, 2026
c3b8275
feat: Split 2D and 3D resolution sliders effect
afonsobspinto Feb 4, 2026
2bb161d
feat: Update catmaid's project bounds calculation
afonsobspinto Feb 10, 2026
c91e58a
feat: Use RenderScaleHistogram as base for catmaid resolution sliders
afonsobspinto Feb 11, 2026
a9ec128
feat: Add special handling of catmaid's no provider errors
afonsobspinto Feb 11, 2026
cea3fae
feat: Re-evaluated 2D source selection when renderScaleTarget changes.
afonsobspinto Feb 11, 2026
5bea93f
chore: Remove logs
afonsobspinto Feb 12, 2026
d8e91af
chore: Have catmaid respect SpatiallyIndexedSkeletonSource interface
afonsobspinto Feb 12, 2026
0f7b436
Update src/skeleton/frontend.ts
afonsobspinto Feb 12, 2026
0ea1537
chore: Remove expensive gl.getError() call
afonsobspinto Feb 12, 2026
48dd890
Update src/skeleton/skeleton_chunk_serialization.ts
afonsobspinto Feb 12, 2026
81dac0d
refactor: Make activateDataSubsources type-safe
afonsobspinto Feb 12, 2026
25c2dc1
fix: Update shader to branch alpha by view type
afonsobspinto Feb 12, 2026
a83e865
refactor: Emit new segmentation keys only when spatial skeleton funct…
afonsobspinto Feb 12, 2026
7f8c36a
fix: Rollback opacity shader changes
afonsobspinto Feb 12, 2026
08f3349
refactor: Replace named attribute by explicit flag
afonsobspinto Feb 12, 2026
d747542
refactor: Rollback behaviour changes for graphene
afonsobspinto Feb 12, 2026
c13964e
refactor: Add singlenton pattern to Unpackr and CatmaidClient
afonsobspinto Feb 13, 2026
ca5e345
refactor: Extract debounce time to a variable
afonsobspinto Feb 13, 2026
70b87bb
feat: Maintain global node lookup cache until rebuild is needed
afonsobspinto Feb 13, 2026
14de40e
feat: Add debounce to slice view
afonsobspinto Feb 13, 2026
daa7879
fix: Fix resolution sliders disappearing on skeleton subsource toggle
afonsobspinto Feb 13, 2026
b74a2b7
feat: Add edit tab and edit mode
afonsobspinto Feb 16, 2026
c1d886d
feat: Add new nodes
afonsobspinto Feb 18, 2026
bf1183e
feat: Add border to selected node
afonsobspinto Feb 18, 2026
ded83bd
chore: Remove debug overlay and debug logs
afonsobspinto Feb 18, 2026
6734436
feat: Allow spatially indexed skeletons to show/hide seg ID on double…
afonsobspinto Feb 18, 2026
3d0111f
feat: Update skeleton edit tab
afonsobspinto Feb 18, 2026
47a0c44
feat: Add tree representation to skeleton tab
afonsobspinto Feb 18, 2026
645b3bb
feat: Add delete node action
afonsobspinto Feb 18, 2026
6fd5b97
feat: Implement navigation icons
afonsobspinto Feb 18, 2026
9cace3d
feat: Update delete node action
afonsobspinto Feb 19, 2026
f2771ae
feat: Update add node action
afonsobspinto Feb 25, 2026
3c157fa
feat: Update add new skeleton node action
afonsobspinto Feb 25, 2026
9c03078
feat: Update move node action shortcut
afonsobspinto Feb 25, 2026
276d56a
feat: Update picking logic
afonsobspinto Mar 2, 2026
1c7f920
feat: Pull full skeleton data on segment activation
afonsobspinto Mar 2, 2026
a075aaf
feat: Update navigation logic
afonsobspinto Mar 2, 2026
c788301
feat: Simplify picking strategy
afonsobspinto Mar 2, 2026
9f6bc5c
feat: Force 2D max grid level to enable edit mode
afonsobspinto Mar 2, 2026
42d6185
feat: Add split and merge
afonsobspinto Mar 9, 2026
3a555e8
feat: WIP - Update navigation buttons
afonsobspinto Mar 11, 2026
6b8e311
feat: Improve node movement
afonsobspinto Mar 11, 2026
d318bdf
feat: Reverse order in resolution sliders
afonsobspinto Mar 11, 2026
d8a59ac
feat: Rename edit actions
afonsobspinto Mar 11, 2026
1e30b7e
feat: Update selection visual feedback
afonsobspinto Mar 12, 2026
91996c9
Revert "feat: Reverse order in resolution sliders"
afonsobspinto Mar 12, 2026
85b7a10
feat: Improve spatially indexed skeletons performance
afonsobspinto Mar 12, 2026
91c4a11
feat: Converge spatially indexed skeletons strategies to match with a…
afonsobspinto Mar 12, 2026
03666cb
feat: Add node locator index
afonsobspinto Mar 12, 2026
ca7fa07
refactor: Merges 2D/3D layers into one shared one with projections
afonsobspinto Mar 13, 2026
38bc3db
feat: Add parentId -> chunk map
afonsobspinto Mar 13, 2026
b231f2f
feat: Keep visibility/color/alpha in shared GPU lookup state instead …
afonsobspinto Mar 13, 2026
c7a6909
refactor: Add small algorithm optimizations and extract common functions
afonsobspinto Mar 13, 2026
af64e95
feat: Make chunk data immutable and use temp overlay instead
afonsobspinto Mar 13, 2026
229b56b
refactor: Use UINT32 instead of FLOAT32 for segment id
afonsobspinto Mar 13, 2026
c40bd62
refactor: Simpliofy edit flow
afonsobspinto Mar 13, 2026
beb45c0
feat: Have structural edits invalidate all spatial sources
afonsobspinto Mar 13, 2026
c07f438
refactor: Update spatially indexed skeletons api
afonsobspinto Mar 13, 2026
f70ee08
refactor: Update isReady for spatially indexed skeletons
afonsobspinto Mar 13, 2026
2e324b5
feat: Implement add/move simplification
afonsobspinto Mar 13, 2026
01ad06e
feat: Return cached buffer immediately
afonsobspinto Mar 13, 2026
223e0e8
feat: Update navigation icons
afonsobspinto Mar 16, 2026
96abf28
feat: Update active skeletons section styles
afonsobspinto Mar 16, 2026
183e7a1
feat: Add node properties dialog
afonsobspinto Mar 16, 2026
a96bf8f
feat: Update node row selection shortcuts
afonsobspinto Mar 16, 2026
47a5844
feat: Add node description
afonsobspinto Mar 16, 2026
7f5f4f1
feat: WIP - Improve performance
afonsobspinto Mar 16, 2026
ecccda9
feat: WIP - Improve performance
afonsobspinto Mar 16, 2026
72f2166
feat: Improve edit mode performance
afonsobspinto Mar 16, 2026
7c89d4b
fix: Correct copyToGPU & freeGPUMemory flow
afonsobspinto Mar 17, 2026
e0c28bc
Merge branch 'master' into feature/edit-mode
afonsobspinto Mar 17, 2026
22e03b8
feat: Have left click in node row "move-to-and-pin"
afonsobspinto Mar 17, 2026
d5d62e2
feat: Have navigation buttons move us to the new position
afonsobspinto Mar 17, 2026
1d6af6a
feat: Update getFlatListNodeIds ordering
afonsobspinto Mar 17, 2026
7ee9da8
feat: Remove next branch and previous branch buttons
afonsobspinto Mar 17, 2026
d392c80
feat: Update navigation buttons
afonsobspinto Mar 18, 2026
6036201
feat: Remove node properties dialog
afonsobspinto Mar 18, 2026
8220503
feat: Align skeleton selection controls
afonsobspinto Mar 18, 2026
f5d1e87
chore: Update tool messages
afonsobspinto Mar 18, 2026
513e552
fix: Correct picking formulas
afonsobspinto Mar 19, 2026
093f9a7
feat: Automatically set lines and points to 3D rendering
afonsobspinto Mar 19, 2026
141044d
feat: Update spatially skeletons selection to be part of state
afonsobspinto Mar 19, 2026
56bdc31
feat: Update new tool messages and add confirm dialog
afonsobspinto Mar 20, 2026
cbf40fd
feat: Make add node overlay only
afonsobspinto Mar 20, 2026
bdfc329
feat: Update graph ordering
afonsobspinto Mar 20, 2026
b7a1545
feat: Add delete confirm dialog
afonsobspinto Mar 20, 2026
efe728e
fix: Correct skeleton colors after merge
afonsobspinto Mar 20, 2026
149b7fe
feat: Cancel stale spatially indexed skeleton downloads
afonsobspinto Mar 20, 2026
9e15584
fix: Update spatially indexed skeletons chunk prioritization
afonsobspinto Mar 20, 2026
0256f3b
fix: Update chunk stats calculation for resolution slider
afonsobspinto Mar 20, 2026
99925a7
feat: Add node type filter
afonsobspinto Mar 20, 2026
f6fc2e3
Merge branch 'master' into feature/edit-mode
afonsobspinto Mar 23, 2026
c0be8aa
feat: Remove max LOD checks
afonsobspinto Mar 24, 2026
b9fc73d
feat: Update new tools messages
afonsobspinto Mar 24, 2026
bfb8f7f
feat: Add new show segments filter
afonsobspinto Mar 24, 2026
1b030f5
feat: Update search filter
afonsobspinto Mar 24, 2026
3231acb
fix: Correct node type filter
afonsobspinto Mar 24, 2026
4a6ba2e
feat: Add node type selector on selection widget
afonsobspinto Mar 24, 2026
b54958e
fix: Store skeleton selection ids as strings
afonsobspinto Mar 25, 2026
21aecd8
feat: Set both 3D and 2D to lines and points
afonsobspinto Mar 25, 2026
54083e1
feat: Update skeleton sorting
afonsobspinto Mar 27, 2026
dc36299
feat: Make go to child pick a random child
afonsobspinto Mar 27, 2026
952b5ad
feat: Add sorting cache
afonsobspinto Mar 27, 2026
39d73eb
feat: Add move to new node automatically
afonsobspinto Mar 27, 2026
b323932
feat: Block adding new nodes to true end nodes
afonsobspinto Mar 27, 2026
4dcbc5b
feat: Move to parent on delete
afonsobspinto Mar 30, 2026
ab48857
feat: Update search to show only matches (no ancestors)
afonsobspinto Mar 30, 2026
3072b0e
feat: Add node has description filter
afonsobspinto Mar 30, 2026
3fe7075
feat: Add node has description filter
afonsobspinto Mar 30, 2026
bd0df73
feat: Remove confirmation dialogs
afonsobspinto Mar 30, 2026
51b7682
Merge branch 'feature/edit-mode' of github.com:MetaCell/neuroglancer …
afonsobspinto Mar 30, 2026
aa63bec
feat: Add node re-rooting
afonsobspinto Mar 30, 2026
dc13aa1
feat: Update confidence mapping
afonsobspinto Mar 30, 2026
73db63b
feat: Allow ctrl+right click on seg Ids to pin
afonsobspinto Mar 30, 2026
08daac3
feat: WIP - Add catmaid state context
afonsobspinto Apr 8, 2026
13d1fcc
feat: Add catmaid state context
afonsobspinto Apr 9, 2026
5b74728
refactor: Simplify node/list parsing and remove state from label updates
afonsobspinto Apr 9, 2026
446a55b
fix: Correct unfinished node navigation
afonsobspinto Apr 9, 2026
32442b4
fix: Keep visible segment ids on nodes refresh
afonsobspinto Apr 9, 2026
249d669
fix: correct moving to node position
seankmartin Apr 9, 2026
21f32e7
fix: also correct global position in picking
seankmartin Apr 9, 2026
ebf2fec
chore: remove comment as used in more than one place
seankmartin Apr 9, 2026
a3bb499
fix: apply transform and local to global permutation on mouse position
seankmartin Apr 10, 2026
800ca08
refactor: clean up the loop of setting position
seankmartin Apr 10, 2026
daab5e8
refactor: minor, but rename DEBUG to match more common ng pattern
seankmartin Apr 10, 2026
0a8cfab
fix: set position on move correctly and remove duplicate call
seankmartin Apr 10, 2026
41ed4af
revert: undo accidental change back of naming
seankmartin Apr 10, 2026
37ac4b2
feat: follow the pattern in annotation.ts to cache the chunkTransform
seankmartin Apr 10, 2026
f42e897
fix: use chunk transform for mouse
seankmartin Apr 10, 2026
0b5545e
perf: cache a float array for chunk pos
seankmartin Apr 10, 2026
6767d98
fix: don't set failed click to new array
seankmartin Apr 10, 2026
6aa9950
fix: map move node to correct spaces
seankmartin Apr 10, 2026
3f6cf3a
refactor: rename click pos to model space
seankmartin Apr 10, 2026
ba2a519
chore: add TODO to come back to
seankmartin Apr 10, 2026
fd53b78
perf: remove uneeded vec copy
seankmartin Apr 10, 2026
a803c19
feat: Add undo redo
afonsobspinto Apr 13, 2026
ba22140
feat: Style undo redo buttons
afonsobspinto Apr 13, 2026
09cd399
fix: Fix reroot call
afonsobspinto Apr 13, 2026
528571f
fix: Fix parsing after split
afonsobspinto Apr 14, 2026
dc3399c
fix: Fix split undo
afonsobspinto Apr 14, 2026
43a27f8
fix: Reorder nodes on split undo
afonsobspinto Apr 14, 2026
32eb893
style: Apply format and linting
afonsobspinto Apr 15, 2026
1fe21c1
Merge branch 'master' into feature/edit-mode
afonsobspinto Apr 15, 2026
7ece244
Merge branch 'feature/edit-mode' into fix/set-node-position
afonsobspinto Apr 16, 2026
32e592b
Merge pull request #126 from MetaCell/fix/set-node-position
afonsobspinto Apr 16, 2026
dcf0cff
Merge branch 'feature/edit-mode' into fix/set-node-position
afonsobspinto Apr 16, 2026
c589c24
Merge branch 'fix/set-node-position' into feature/edit-mode
afonsobspinto Apr 16, 2026
4253c16
Merge branch 'fix/set-node-position' into feature/edit-mode
afonsobspinto Apr 16, 2026
372cd08
feat: check if fetch error due to non existant skeleton
seankmartin Apr 16, 2026
0ed6da5
feat: cache non-existant skeletons in skeleton state
seankmartin Apr 16, 2026
39bf063
feat: change replaceCachedSegmentNodes to store empty array in cache …
seankmartin Apr 17, 2026
b4dc503
test: add test for new cache behaviour
seankmartin Apr 17, 2026
a45a745
Merge pull request #127 from MetaCell/fix/NA-691
afonsobspinto Apr 17, 2026
52e2dd9
refactor: Simplify and consolidate spatially indexed skeletons code
afonsobspinto Apr 19, 2026
3462fb2
Merge branch 'feature/edit-mode' of github.com:MetaCell/neuroglancer …
afonsobspinto Apr 19, 2026
4a7dc0a
docs: Add licence to new files
afonsobspinto Apr 19, 2026
242397c
style: Apply frontend linting
afonsobspinto Apr 19, 2026
ae8ec4d
refactor: Remove unnecessary attributes from interfaces
afonsobspinto Apr 19, 2026
372b655
feat: Remove label property
afonsobspinto Apr 20, 2026
c357d26
feat: Clean node anchors for merge on unselection
afonsobspinto Apr 20, 2026
863c3ff
feat: change co-ord display to be in units in both spatial skeletons …
seankmartin Apr 20, 2026
ee880f5
fix: correct layout of header and elements in cells
seankmartin Apr 20, 2026
da64363
fix: don't set state.value to undefined after super.captureSelectionS…
seankmartin Apr 21, 2026
ff0cf72
refactor: change to removing custom captureSelectionState logic
seankmartin Apr 21, 2026
de52e75
feat: Remove node coordinates search
afonsobspinto Apr 21, 2026
0a9b531
Merge pull request #128 from MetaCell/feat/NA-668
afonsobspinto Apr 21, 2026
53ab7fa
Merge pull request #129 from MetaCell/fix/NA-693
seankmartin Apr 21, 2026
6e48ad2
fix: listen to color changes in seg edit tab
seankmartin Apr 22, 2026
08de25e
feat: Allow merge with non-visible node
afonsobspinto Apr 22, 2026
56455e5
Merge branch 'feature/edit-mode' into feature/NA-718
afonsobspinto Apr 22, 2026
ff635b2
feat: Add pending message
afonsobspinto Apr 22, 2026
9ed4f02
feat: Update default grid size and rename catmaid metadata key
afonsobspinto Apr 23, 2026
7ae622e
Merge pull request #130 from MetaCell/fix/NA-664
afonsobspinto Apr 23, 2026
31ba188
Merge pull request #132 from MetaCell/feature/NA-688
seankmartin Apr 23, 2026
61f2a0c
refactor: Simplify root parsing
afonsobspinto Apr 23, 2026
4b63b55
Merge pull request #131 from MetaCell/feature/NA-718
seankmartin Apr 23, 2026
a77e943
refactor: remove mouseState listener in edit tab
seankmartin Apr 24, 2026
5574562
chore: lint and format
seankmartin Apr 24, 2026
3681ee0
merge feature/edit-mode and lint+format again
seankmartin Apr 24, 2026
7185dc4
Merge pull request #134 from MetaCell/chore/lint
seankmartin Apr 24, 2026
e2a1ef0
refactor: extract logic around hovered node into it's own class
seankmartin Apr 24, 2026
4178ba0
merge: merge feature branch
seankmartin Apr 24, 2026
2203fe0
chore: fix lint
seankmartin Apr 24, 2026
5db1b11
fix: Properly rewire children under recreated node (undo delete)
afonsobspinto Apr 24, 2026
080374e
Merge branch 'feature/edit-mode' into feature/NA-721
afonsobspinto Apr 24, 2026
fb4698e
Merge pull request #133 from MetaCell/fix/NA-727
seankmartin Apr 24, 2026
92beea2
feat: warn on too many skel attributes
seankmartin Apr 24, 2026
12d37fc
perf, refactor: don't bind twice for vertex attrs in skel
seankmartin Apr 24, 2026
808df70
Merge pull request #138 from MetaCell/fix/NA-705
afonsobspinto Apr 24, 2026
51812da
Merge pull request #136 from MetaCell/feature/NA-721
seankmartin Apr 24, 2026
5391848
docs: add v1 of spatial edit docs
seankmartin Apr 24, 2026
05dec91
fix: add to index and small accuracy of edit docs
seankmartin Apr 27, 2026
5bcb549
docs: update on actions, chunks, and merge survivor
seankmartin Apr 27, 2026
8657d9f
Merge pull request #139 from MetaCell/feat/NA-701
seankmartin Apr 27, 2026
ff675dd
refactor: Use inline 1e-9 instead of METERS_PER_NANOMETER
afonsobspinto Apr 28, 2026
75936af
refactor: Move cast to getMeshSource
afonsobspinto Apr 28, 2026
291c60d
feat: Move to parent if exists from a undo of an add node
afonsobspinto Apr 28, 2026
e652048
Merge pull request #140 from MetaCell/feature/NA-704
seankmartin Apr 29, 2026
ebfa4ba
Merge pull request #141 from MetaCell/feature/NA-722
seankmartin Apr 29, 2026
631cdcf
feat: Change skeleton viewer to use virtual list; Removes show and ex…
afonsobspinto Apr 29, 2026
c8ac0fd
feat: Make skeleton tab stateful
afonsobspinto Apr 29, 2026
1dfaa6d
fix: Ignore historical labels when parsing description
afonsobspinto Apr 29, 2026
57537af
feat: Simplify selected spatial skeleton node info
afonsobspinto Apr 29, 2026
79ba410
fix: Stop evicting cached full skeleton data for non selected visible…
afonsobspinto Apr 30, 2026
954f21f
feat: Update selection on hover
afonsobspinto Apr 30, 2026
a08b4a9
Merge pull request #144 from MetaCell/feature/NA-753
seankmartin Apr 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Neuroglancer
:caption: User Guide

user-guide/navigation
user-guide/skeleton_editing

.. toctree::
:hidden:
Expand Down Expand Up @@ -42,4 +43,3 @@ Neuroglancer
Neuroglancer is a WebGL-based viewer for volumetric data. It is capable of
displaying arbitrary (non axis-aligned) cross-sectional views of volumetric
data, as well as 3-D meshes and line-segment based models (skeletons).

167 changes: 167 additions & 0 deletions docs/spatial_skeleton_refresh_nodes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# Why `refreshNodes()` Is Called So Often

This note documents every current `refreshNodes()` call site in `src/ui/spatial_skeleton_edit_tab.ts` and whether it is strictly required by the current implementation.

## What `refreshNodes()` actually recomputes

`refreshNodes()` is not just a repaint helper. It rebuilds the tab's backing data by:

- Recomputing `activeSegmentIds` from `getVisibleSegments(...)`.
- Resolving the current spatial skeleton render layer and CATMAID client.
- Clearing the full-skeleton cache when `layer.spatialSkeletonNodeDataVersion` changes.
- Fetching full CATMAID skeletons for every active segment.
- Fetching CATMAID "true end" labels and applying them to the node list.
- Rebuilding `nodesBySegment`, `allNodes`, the summary text, and the selected node fallback.

Because of that, a refresh is only fundamentally needed when one of those inputs changes.

## Call sites

### 1. `deleteNode(...)` success path

Why it is called:

- Deleting a node changes the local skeleton layer immediately.
- A delete can also split one skeleton into new segment ids, so the active visible segment set may change.
- The tab wants to re-fetch the authoritative CATMAID skeleton after the mutation instead of trusting only local chunk edits.

Assessment:

- Reasonable as an eager refresh.
- Probably redundant in practice, because the same code path also updates `visibleSegments` and bumps `layer.spatialSkeletonNodeDataVersion`, and both already have refresh listeners below.

### 2. `layer.displayState.segmentSelectionState.changed`

Why it is called today:

- Most likely defensive: segment selection changes often happen while the user is interacting with the Seg tab.

Assessment:

- This does not look required by the current code.
- `refreshNodes()` does not read `segmentSelectionState`.
- If only the selected segment changes while the visible segment set stays the same, the node list inputs have not changed.

### 3. `segmentationGroupState.visibleSegments.changed`

Why it is called:

- This is a direct dependency.
- `refreshNodes()` derives `activeSegmentIds` from the visible segment set, so adding or removing visible skeletons must rebuild the node list.

Assessment:

- Required.

### 4. `segmentationGroupState.temporaryVisibleSegments.changed`

Why it is called:

- Merge/split previews can populate the temporary visible segment set.
- When the tab is currently using the temporary set, those preview edits change which skeletons should be shown.

Assessment:

- Required for preview mode correctness.

### 5. `segmentationGroupState.useTemporaryVisibleSegments.changed`

Why it is called:

- `getVisibleSegments(...)` switches between the normal and temporary visible sets based on this flag.
- Flipping the flag changes the source of truth for `activeSegmentIds` even if neither set changed contents.

Assessment:

- Required.

### 6. `layer.layersChanged`

Why it is called:

- `refreshNodes()` resolves the active spatial skeleton render layer on every run.
- If render layers are rebuilt, added, removed, or swapped, the tab may need a different skeleton layer or CATMAID client.

Assessment:

- Required.

### 7. `layer.manager.chunkManager.layerChunkStatisticsUpdated`

Why it is called today:

- Probably to keep the tab in sync with spatial skeleton loading progress.

Assessment:

- `updateGateStatus()` is definitely needed here because action availability depends on chunk loading.
- The `refreshNodes()` part does not look required by the current implementation.
- `refreshNodes()` does not consume chunk statistics directly; it fetches full skeletons from CATMAID based on visible segments.
- This looks like defensive overlap or a holdover from an older "loaded nodes" model.

### 8. `layer.displayState.spatialSkeletonGridLevel2d.changed`

Why it is called today:

- Likely meant to react when the user changes the skeleton grid resolution used by the render layers.

Assessment:

- Not a direct dependency of `refreshNodes()`.
- Grid level changes do affect edit eligibility and chunk loading, but those are already covered by `spatialSkeletonActionsAllowed`, `layersChanged`, and chunk-stat updates.
- For the current CATMAID-backed full-skeleton list, this refresh looks likely redundant.

### 9. `layer.displayState.spatialSkeletonGridLevel3d.changed`

Why it is called today:

- Same rationale as the 2D grid-level watcher.

Assessment:

- Same conclusion as above: likely redundant for the current implementation.

### 10. `layer.spatialSkeletonNodeDataVersion.changed`

Why it is called:

- This is the main explicit invalidation channel for real skeleton edits.
- When the version changes, `refreshNodes()` clears the full-skeleton cache and re-fetches from CATMAID.
- Other tools rely on this after add, move, merge, and split operations.

Assessment:

- Required.
- This is the cleanest "the node topology changed" signal in the file.

### 11. Constructor tail: initial `refreshNodes()`

Why it is called:

- The tab needs an initial population pass after wiring observers.
- Without it, the list would stay empty until some later state change happens.

Assessment:

- Required.

## Practical takeaway

The clearly justified refresh triggers are:

- `visibleSegments.changed`
- `temporaryVisibleSegments.changed`
- `useTemporaryVisibleSegments.changed`
- `layersChanged`
- `spatialSkeletonNodeDataVersion.changed`
- the initial constructor call

The calls that currently look redundant or at least weakly justified are:

- `segmentSelectionState.changed`
- the `refreshNodes()` inside `layerChunkStatisticsUpdated`
- `spatialSkeletonGridLevel2d.changed`
- `spatialSkeletonGridLevel3d.changed`
- the direct refresh after successful delete, because that path already triggers other refresh signals

If we want to reduce refresh churn safely, those are the first places to verify with tests or manual UI checks.
190 changes: 190 additions & 0 deletions docs/user-guide/skeleton_editing.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
Skeleton Editing
================

Neuroglancer supports interactive editing of skeleton annotations, including
adding, moving, and deleting nodes, as well as merging and splitting skeletons.

.. _skeleton-editing-sources:

Supported Sources
-----------------

Skeleton editing is currently only supported on CATMAID data sources. See the
CATMAID documentation to set up a CATMAID server. At minimum you will need:

- A CATMAID project
- A linked project stack
- ``AnonymousUser`` permissions to read and edit the data on that project
- Skeletons initialised for that project

The project stack dimensions and resolution are used to inform the bounding box
of the data in neuroglancer as their product. Skeletons in CATMAID are in 1 nm
units. Optionally, you can also configure stack metadata, which is intended to be used alongside the CATMAID multiple-LOD cache
grid for faster fetches of spatially indexed skeletons. The stack metadata can specify the key ``spatial_skeleton_chunk_sizes`` to define the chunk sizes at each LOD level in neuroglancer in nm. These chunk sizes are not required to be the same as the CATMAID LOD cache grid chunk sizes, and chunks are not required to have an exact match in the cache. Neuroglancer will always request to CATMAID to provide nodes from a cache if present. In addition, neuroglancer will request chunks at:

.. math::

\mathrm{lod}\!\left(\frac{k}{n - 1}\right)

in CATMAID, where :math:`k` is the LOD index level in neuroglancer, and :math:`n` is the number of LOD levels.

After setting this up, enter ``catmaid:<your-catmaid-server-url>/<your-catmaid-project-id>`` as a data source in neuroglancer.

.. _skeleton-editing-subsources:

Layer Subsources
----------------

The data source exposes two skeleton subsources. The first is a spatially indexed
skeleton source, which is required for editing. The second is the regular skeleton
subsource from the pre-existing pipeline for rendering precomputed format skeletons.

In the **Render** tab you can adjust:

- **Opacity (3d)** — controls the opacity of fully loaded, visible skeletons.
- **Hidden Opacity (3d)** — controls the opacity of hidden skeletons, which represent
LOD-influenced spatial indicators of nodes in space.

When you make a skeleton visible, a full fetch is triggered and you are guaranteed
to see all nodes and details of that skeleton. Otherwise you see whatever is
provided by the LOD spatial information. The selected LOD is controllable via the
**Resoltion (skeleton grid 2D)** and **Resolution (skeleton grid 3D)** resolution settings.

The **Seg** tab works as normal for a segmentation layer, allowing you to set the
visibility of segments/skeletons by their ID or by label if one has been assigned.

.. _skeleton-editing-tab:

Skeleton Tab
------------

The **Skeleton** tab is used for editing and viewing information about skeletons.
It is only available for CATMAID sources with an active spatially indexed skeleton
subsource, and only visible skeletons appear here.

You can find a node by ID or by description, and filter nodes to show only:

- Leaves
- Virtual ends
- True ends
- Nodes with descriptions

You can also pick a subset of the visible skeletons to display information about in this menu.

Skeleton Navigation
~~~~~~~~~~~~~~~~~~~

The skeleton tab provides buttons for navigating through the skeleton tree:

- Go to the root
- Go to the start of the current branch
- Go to the end of the current branch
- Cycle through nodes at the current level
- Go to the parent or child of the current node (if there are multiple children,
one is chosen at random)
- Go to the nearest node that is a leaf but not marked as a true end

You can also interact with nodes in the details viewer by right-clicking to move
to a node, or left-clicking to select it and move to it.

.. _skeleton-node-types:

Node Types
----------

Nodes use symbols to indicate their type:

- **Root** — the root node of the skeleton
- **Regular node** — an interior node along a branch
- **Branch point** — a node with more than one child
- **Virtual end** — a leaf node that has not been marked as a true end
- **True end** — a leaf node manually marked by a reviewer as the end of a branch

You can toggle a node between virtual end and true end by clicking its type icon
in the skeleton tab table. This only applies to visible segments.

.. _skeleton-node-properties:

Node Properties
---------------

To edit the detailed properties of a node, first make the segment visible, then
select the node by either:

- Right-clicking on it in the viewer while holding :kbd:`Control`
- Left-clicking on it in the skeleton tab table

Once a node is selected, you can:

- Delete the node *
- Change the node type *
- Make the node the root of the skeleton *
- Change the radius
- Change the confidence level
- Add or edit a free-text description

.. note::
* These actions can also be performed from the skeleton tab table.

.. _skeleton-editing-tools:

Editing Tools
-------------

To make structural edits to nodes, you must bind at least some of the editing
tools available in the skeleton tab. The available tools are **Edit**, **Merge**,
and **Split**.

To bind a tool, click on it in the UI and hold down a key. To activate the tool,
press :kbd:`Shift` + the bound key. For example, if you bind :kbd:`E` to the Edit
tool, pressing :kbd:`Shift+E` activates it.

An important concept throughout editing is the *selected node*. The selected node
is highlighted with a border in the viewer, highlighted in the skeleton tab table,
and its details are shown in the selection details panel.

Edit Tool
~~~~~~~~~

With the Edit tool active:

- **Move a node** — select the node, then hold :kbd:`Alt` and left-click and drag
it to the new location. This does not use picking to snap to nearby objects.
- **Add a child node** — select an existing node, then :kbd:`Control`-click where
you want to place the new node. The new node is added as a child of the selected
node.
- **Start a new skeleton** — :kbd:`Control`-click with no node selected to add a
root node with no parent.

Merge Tool
~~~~~~~~~~

With the Merge tool active, select the "from" node first and then the "to" node. You must merge from a visible skeleton, but the "to" node may belong to a non-visible skeleton.
The surviving skeleton ID will be the ID of the skeleton containing the "from"
node. The only exception to this is if the CATMAID skeleton has annotations, and one of the skeletons is annotated as ``stable`` -- in this case, the surviving skeleton ID is from the one that was annotated as ``stable``. It is not currently possible to set these annotations within neuroglancer.

Split Tool
~~~~~~~~~~

With the Split tool active, select the node at which to split. The selected node
is included in the newly created skeleton, not the surviving original skeleton.
The edge between the selected node and its parent is deleted, and the selected
node becomes the root of the new skeleton. A split always produces exactly two
skeletons, regardless of whether the selected node is a branch point or a leaf.
You can only split visible skeletons.

.. _skeleton-editing-undo:

Undo and Redo
-------------

The skeleton tab provides **Undo** and **Redo** buttons. When any operation is
performed, its inverse is stored in the history. Note that the inverse of an
atomic operation is not necessarily atomic: for example, undoing a merge involves
a split followed by a reroot. Without the reroot step, the split skeleton could
end up with a different root than it had before the merge.

Undo does not restore the skeleton ID to its pre-operation value, so a merge
followed by an undo will result in one of the skeletons having a new ID compared
to before the merge (specifically, the skeleton that did not "survive" the
original merge).
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,12 @@
"neuroglancer/datasource/boss:disabled": "./src/util/false.ts",
"default": "./src/datasource/boss/backend.ts"
},
"#datasource/catmaid/backend": {
"default": "./src/datasource/catmaid/backend.ts"
},
"#datasource/catmaid/register_default": {
"default": "./src/datasource/catmaid/register_default.ts"
},
"#datasource/boss/async_computation": {
"neuroglancer/datasource/boss:enabled": "./src/datasource/boss/async_computation.ts",
"neuroglancer/datasource:none_by_default": "./src/util/false.ts",
Expand Down Expand Up @@ -534,4 +540,4 @@
"default": "./src/util/false.ts"
}
}
}
}
Loading
Loading