arrayview 0.20.0__tar.gz → 0.21.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. arrayview-0.21.0/.agents/skills/frontend-designer/SKILL.md +56 -0
  2. arrayview-0.21.0/.agents/skills/modes-consistency/SKILL.md +67 -0
  3. {arrayview-0.20.0 → arrayview-0.21.0}/.agents/skills/ui-consistency-audit/SKILL.md +10 -0
  4. arrayview-0.21.0/.agents/skills/visual-bug-fixing/SKILL.md +80 -0
  5. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/AGENTS.md +3 -2
  6. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/ROUTER.md +23 -2
  7. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/context/architecture.md +4 -3
  8. arrayview-0.21.0/.mex/context/frontend.md +83 -0
  9. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/context/project-state.md +2 -2
  10. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/patterns/INDEX.md +1 -0
  11. arrayview-0.21.0/.mex/patterns/debug-vscode-extension-python.md +95 -0
  12. arrayview-0.21.0/.mex/patterns/frontend-change.md +72 -0
  13. {arrayview-0.20.0 → arrayview-0.21.0}/AGENTS.md +10 -0
  14. arrayview-0.21.0/DESIGN.md +121 -0
  15. {arrayview-0.20.0 → arrayview-0.21.0}/PKG-INFO +1 -1
  16. arrayview-0.21.0/plans/refactoring_plan.md +194 -0
  17. {arrayview-0.20.0 → arrayview-0.21.0}/pyproject.toml +1 -1
  18. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/__init__.py +1 -1
  19. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_config.py +4 -23
  20. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_diff.py +3 -22
  21. arrayview-0.21.0/src/arrayview/_imaging.py +24 -0
  22. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_launcher.py +20 -5
  23. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_render.py +39 -27
  24. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_routes_rendering.py +3 -23
  25. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_routes_websocket.py +1 -10
  26. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_server.py +11 -24
  27. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_stdio_server.py +1 -12
  28. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_viewer.html +1366 -245
  29. arrayview-0.21.0/src/arrayview/_vscode.py +31 -0
  30. arrayview-0.21.0/src/arrayview/_vscode_browser.py +176 -0
  31. arrayview-0.21.0/src/arrayview/_vscode_extension.py +342 -0
  32. arrayview-0.21.0/src/arrayview/_vscode_shm.py +77 -0
  33. arrayview-0.20.0/src/arrayview/_vscode.py → arrayview-0.21.0/src/arrayview/_vscode_signal.py +3 -513
  34. arrayview-0.21.0/src/arrayview/arrayview-opener.vsix +0 -0
  35. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_api.py +52 -8
  36. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_backend_shared.py +47 -0
  37. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_browser.py +33 -4
  38. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_interactions.py +168 -0
  39. {arrayview-0.20.0 → arrayview-0.21.0}/uv.lock +1 -1
  40. {arrayview-0.20.0 → arrayview-0.21.0}/vscode-extension/extension.js +5 -2
  41. {arrayview-0.20.0 → arrayview-0.21.0}/vscode-extension/package.json +1 -1
  42. arrayview-0.20.0/.agents/skills/frontend-designer/SKILL.md +0 -127
  43. arrayview-0.20.0/.agents/skills/modes-consistency/SKILL.md +0 -126
  44. arrayview-0.20.0/.agents/skills/visual-bug-fixing/SKILL.md +0 -154
  45. arrayview-0.20.0/.mex/context/frontend.md +0 -157
  46. arrayview-0.20.0/.mex/patterns/frontend-change.md +0 -99
  47. arrayview-0.20.0/src/arrayview/arrayview-opener.vsix +0 -0
  48. {arrayview-0.20.0 → arrayview-0.21.0}/.agents/skills/invocation-consistency/SKILL.md +0 -0
  49. {arrayview-0.20.0 → arrayview-0.21.0}/.agents/skills/playwright-cli/SKILL.md +0 -0
  50. {arrayview-0.20.0 → arrayview-0.21.0}/.agents/skills/playwright-cli/references/element-attributes.md +0 -0
  51. {arrayview-0.20.0 → arrayview-0.21.0}/.agents/skills/playwright-cli/references/playwright-tests.md +0 -0
  52. {arrayview-0.20.0 → arrayview-0.21.0}/.agents/skills/playwright-cli/references/request-mocking.md +0 -0
  53. {arrayview-0.20.0 → arrayview-0.21.0}/.agents/skills/playwright-cli/references/running-code.md +0 -0
  54. {arrayview-0.20.0 → arrayview-0.21.0}/.agents/skills/playwright-cli/references/session-management.md +0 -0
  55. {arrayview-0.20.0 → arrayview-0.21.0}/.agents/skills/playwright-cli/references/storage-state.md +0 -0
  56. {arrayview-0.20.0 → arrayview-0.21.0}/.agents/skills/playwright-cli/references/test-generation.md +0 -0
  57. {arrayview-0.20.0 → arrayview-0.21.0}/.agents/skills/playwright-cli/references/tracing.md +0 -0
  58. {arrayview-0.20.0 → arrayview-0.21.0}/.agents/skills/playwright-cli/references/video-recording.md +0 -0
  59. {arrayview-0.20.0 → arrayview-0.21.0}/.agents/skills/todo-workflow/SKILL.md +0 -0
  60. {arrayview-0.20.0 → arrayview-0.21.0}/.agents/skills/viewer-ui-checklist/SKILL.md +0 -0
  61. {arrayview-0.20.0 → arrayview-0.21.0}/.github/copilot-instructions.md +0 -0
  62. {arrayview-0.20.0 → arrayview-0.21.0}/.github/workflows/docs.yml +0 -0
  63. {arrayview-0.20.0 → arrayview-0.21.0}/.github/workflows/python-publish.yml +0 -0
  64. {arrayview-0.20.0 → arrayview-0.21.0}/.gitignore +0 -0
  65. {arrayview-0.20.0 → arrayview-0.21.0}/.ignore +0 -0
  66. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/SETUP.md +0 -0
  67. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/SYNC.md +0 -0
  68. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/context/conventions.md +0 -0
  69. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/context/decisions.md +0 -0
  70. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/context/render-pipeline.md +0 -0
  71. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/context/setup.md +0 -0
  72. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/context/stack.md +0 -0
  73. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/patterns/README.md +0 -0
  74. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/patterns/add-file-format.md +0 -0
  75. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/patterns/add-server-endpoint.md +0 -0
  76. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/patterns/animation-verify.md +0 -0
  77. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/patterns/debug-render.md +0 -0
  78. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/patterns/extract-server-route-module.md +0 -0
  79. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/setup.sh +0 -0
  80. {arrayview-0.20.0 → arrayview-0.21.0}/.mex/sync.sh +0 -0
  81. {arrayview-0.20.0 → arrayview-0.21.0}/.opencode/opencode.json +0 -0
  82. {arrayview-0.20.0 → arrayview-0.21.0}/.python-version +0 -0
  83. {arrayview-0.20.0 → arrayview-0.21.0}/.vscode/settings.json +0 -0
  84. {arrayview-0.20.0 → arrayview-0.21.0}/CONTRIBUTING.md +0 -0
  85. {arrayview-0.20.0 → arrayview-0.21.0}/LICENSE +0 -0
  86. {arrayview-0.20.0 → arrayview-0.21.0}/README.md +0 -0
  87. {arrayview-0.20.0 → arrayview-0.21.0}/docs/comparing.md +0 -0
  88. {arrayview-0.20.0 → arrayview-0.21.0}/docs/configuration.md +0 -0
  89. {arrayview-0.20.0 → arrayview-0.21.0}/docs/display.md +0 -0
  90. {arrayview-0.20.0 → arrayview-0.21.0}/docs/index.md +0 -0
  91. {arrayview-0.20.0 → arrayview-0.21.0}/docs/loading.md +0 -0
  92. {arrayview-0.20.0 → arrayview-0.21.0}/docs/logo.png +0 -0
  93. {arrayview-0.20.0 → arrayview-0.21.0}/docs/measurement.md +0 -0
  94. {arrayview-0.20.0 → arrayview-0.21.0}/docs/remote.md +0 -0
  95. {arrayview-0.20.0 → arrayview-0.21.0}/docs/stylesheets/extra.css +0 -0
  96. {arrayview-0.20.0 → arrayview-0.21.0}/docs/viewing.md +0 -0
  97. {arrayview-0.20.0 → arrayview-0.21.0}/matlab/arrayview.m +0 -0
  98. {arrayview-0.20.0 → arrayview-0.21.0}/mkdocs.yml +0 -0
  99. {arrayview-0.20.0 → arrayview-0.21.0}/plans/2026-04-14-immersive-animation.md +0 -0
  100. {arrayview-0.20.0 → arrayview-0.21.0}/plans/webview/LOG.md +0 -0
  101. {arrayview-0.20.0 → arrayview-0.21.0}/scripts/demo.py +0 -0
  102. {arrayview-0.20.0 → arrayview-0.21.0}/scripts/release.sh +0 -0
  103. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/ARCHITECTURE.md +0 -0
  104. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/__main__.py +0 -0
  105. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_analysis.py +0 -0
  106. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_app.py +0 -0
  107. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_icon.png +0 -0
  108. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_io.py +0 -0
  109. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_overlays.py +0 -0
  110. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_platform.py +0 -0
  111. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_routes_analysis.py +0 -0
  112. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_routes_export.py +0 -0
  113. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_routes_loading.py +0 -0
  114. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_routes_persistence.py +0 -0
  115. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_routes_preload.py +0 -0
  116. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_routes_query.py +0 -0
  117. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_routes_segmentation.py +0 -0
  118. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_routes_state.py +0 -0
  119. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_routes_vectorfield.py +0 -0
  120. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_segmentation.py +0 -0
  121. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_session.py +0 -0
  122. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_shell.html +0 -0
  123. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_torch.py +0 -0
  124. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/_vectorfield.py +0 -0
  125. {arrayview-0.20.0 → arrayview-0.21.0}/src/arrayview/gsap.min.js +0 -0
  126. {arrayview-0.20.0 → arrayview-0.21.0}/tests/capture_v_animation.py +0 -0
  127. {arrayview-0.20.0 → arrayview-0.21.0}/tests/conftest.py +0 -0
  128. {arrayview-0.20.0 → arrayview-0.21.0}/tests/make_vectorfield_test_arrays.py +0 -0
  129. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_cli.py +0 -0
  130. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_command_reachability.py +0 -0
  131. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_config.py +0 -0
  132. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_cross_mode_parametrized.py +0 -0
  133. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_large_arrays.py +0 -0
  134. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_loading_server.py +0 -0
  135. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_mode_consistency.py +0 -0
  136. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_mode_entry_batching.py +0 -0
  137. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_mode_matrix.py +0 -0
  138. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_mode_roundtrip.py +0 -0
  139. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_nifti_meta.py +0 -0
  140. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_rgb_pixel_art.py +0 -0
  141. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_torch.py +0 -0
  142. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_view_component_integration.py +0 -0
  143. {arrayview-0.20.0 → arrayview-0.21.0}/tests/test_view_component_unit.py +0 -0
  144. {arrayview-0.20.0 → arrayview-0.21.0}/tests/ui_audit.py +0 -0
  145. {arrayview-0.20.0 → arrayview-0.21.0}/tests/v_anim_frames/.gitkeep +0 -0
  146. {arrayview-0.20.0 → arrayview-0.21.0}/tests/visual_smoke.py +0 -0
  147. {arrayview-0.20.0 → arrayview-0.21.0}/vscode-extension/AGENTS.md +0 -0
  148. {arrayview-0.20.0 → arrayview-0.21.0}/vscode-extension/LICENSE +0 -0
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: frontend-designer
3
+ description: Use when making styling or layout changes to `_viewer.html`. Keeps UI work aligned with arrayview's established visual language without dragging in release-only or cross-mode audit steps by default.
4
+ ---
5
+
6
+ # ArrayView Frontend Design Skill
7
+
8
+ ## Fast Path
9
+
10
+ Use this for real styling/layout work.
11
+ For behavior-only edits, code cleanup, or tiny copy changes with no design decision, do not expand beyond this file unless blocked.
12
+
13
+ ## Design Direction
14
+
15
+ Minimal chrome. The array is the product.
16
+
17
+ - Controls stay dim or hidden until interaction
18
+ - Text is small and monospaced
19
+ - No decorative chrome
20
+ - All four themes must work
21
+
22
+ ## Core Rules
23
+
24
+ - Use existing CSS vars only. Especially: `--surface`, `--border`, `--text`, `--muted`, `--active-dim`, `--overlay-bg`, `--radius`, `--radius-lg`.
25
+ - Never hardcode colors.
26
+ - Typography is always monospace:
27
+ `'SF Mono', ui-monospace, 'Cascadia Code', 'JetBrains Mono', monospace`
28
+ - Match the existing size scale. Most UI text is `10px` to `13px`; headers are `15px` to `16px`.
29
+ - Keep inactive UI dimmed with color/opacity, not permanent visibility.
30
+ - Prefer opacity/color transitions over motion that changes layout.
31
+ - Canvas dimensions are owned by JS layout functions, not CSS.
32
+ - Test themes with `T`.
33
+
34
+ ## Defaults
35
+
36
+ - Passive info: `var(--muted)`
37
+ - Active text: `var(--text)`
38
+ - Selected/highlighted state: `var(--active-dim)`
39
+ - Panel/overlay: `var(--surface)` + `1px solid var(--border)` + `var(--radius-lg)`
40
+ - Modal backdrop: `var(--overlay-bg)` with the existing blur treatment
41
+
42
+ ## Avoid
43
+
44
+ - Persistent toolbar-style controls
45
+ - New font families
46
+ - New one-off sizes or accent colors
47
+ - Layout animations that fight canvas sizing
48
+
49
+ ## Before Shipping
50
+
51
+ - [ ] All four themes still look correct
52
+ - [ ] No hardcoded color values
53
+ - [ ] Font and sizing match existing UI
54
+ - [ ] New panels/overlays use existing surface/border/radius tokens
55
+ - [ ] `viewer-ui-checklist` is used only if the user asked for docs/help/test sync or this is release prep
56
+ - [ ] `modes-consistency` is used if canvas/colorbar/layout behavior crosses modes
@@ -0,0 +1,67 @@
1
+ ---
2
+ name: modes-consistency
3
+ description: Use when a visual feature touches canvas rendering, zoom, eggs, colorbars, shortcuts, or layout across modes. Keeps implementation and verification consistent without escalating to a full audit by default.
4
+ ---
5
+
6
+ # ArrayView Modes Consistency Checklist
7
+
8
+ ## Fast Path
9
+
10
+ Use this when a change can affect more than one viewing mode.
11
+ Skip it for tiny local text/style tweaks that do not touch canvas behavior, colorbars, shortcuts, layout, or mode transitions.
12
+ If the user explicitly asks for a full visual audit or release validation, use `ui-consistency-audit` instead.
13
+
14
+ ## Rule
15
+
16
+ If a feature applies to more than one mode, implement it for all applicable modes now. Shipping “normal mode only” is a bug.
17
+
18
+ ## Mode Map
19
+
20
+ | Mode | Main owner |
21
+ |------|------------|
22
+ | Normal | `scaleCanvas()` |
23
+ | Multi-view | `mvScaleAllCanvases()` |
24
+ | Compare / Diff / Registration | `compareScaleCanvases()` |
25
+ | qMRI | `qvScaleAllCanvases()` |
26
+
27
+ ## Check These Areas
28
+
29
+ - Zoom or canvas sizing: update every relevant scale function
30
+ - Eggs: update `positionEggs()` branches
31
+ - Colorbars and range interaction: check each per-mode colorbar path
32
+ - Shortcuts: guard by mode and update help/registry consistently
33
+ - Canvas listeners: attach to the correct canvas set, not just `#canvas`
34
+ - New UI state: persist it through snapshot/restore if needed
35
+
36
+ ## Backend Note
37
+
38
+ If the feature changes rendered image composition, check the rendering backend in:
39
+
40
+ - `_routes_rendering.py` for `/slice`, `/diff`, and related routes
41
+ - `_render.py` / `_overlays.py` for overlay compositing such as `_composite_overlay_mask()`
42
+
43
+ Do not treat `_app.py` as the implementation surface; it is a compat shim.
44
+
45
+ ## Minimal Workflow
46
+
47
+ 1. Identify which modes the feature should affect.
48
+ 2. Implement normal mode first.
49
+ 3. Implement compare-family behavior.
50
+ 4. Implement multiview behavior.
51
+ 5. Implement qMRI behavior if applicable.
52
+ 6. Verify snapshot/restore if new state was added.
53
+
54
+ ## Red Flags
55
+
56
+ - Only normal mode was changed
57
+ - Similar logic diverges between `scaleCanvas()` and `compareScaleCanvases()`
58
+ - A listener was attached only to `#canvas`
59
+ - Render-route params changed in one backend path but not the others
60
+
61
+ ## Verification
62
+
63
+ - [ ] Works in normal view
64
+ - [ ] Works in compare or diff if applicable
65
+ - [ ] Works in multiview if applicable
66
+ - [ ] Works in qMRI if applicable
67
+ - [ ] Eggs/colorbars/layout anchors still line up after the change
@@ -5,6 +5,16 @@ description: Use when the user explicitly requests a full visual audit, when val
5
5
 
6
6
  # ArrayView UI Consistency Audit
7
7
 
8
+ ## Read Budget
9
+
10
+ On entry, read only:
11
+
12
+ - `Rule`
13
+ - `Phase 1`
14
+ - the tier commands in `Phase 2`
15
+
16
+ Treat the mode matrix and rule catalog below as reference sections to revisit only if the task actually reaches the full audit stage.
17
+
8
18
  ## Rule
9
19
 
10
20
  This is the **full** visual audit path. Do not invoke it by default for every UI change. During normal feature development, do targeted verification for the specific area touched. Use this skill when the user explicitly asks for a broad visual check, when a regression spans modes/layouts, or when validating UI work for a release. This skill has two phases: a **proactive phase** (before coding) that plans the cross-mode behavior, and a **reactive phase** (after coding) that runs an automated visual audit.
@@ -0,0 +1,80 @@
1
+ ---
2
+ name: visual-bug-fixing
3
+ description: Use when fixing a real visual bug, layout glitch, rendering artifact, or UI regression in arrayview. Requires visual evidence, but keeps the default path targeted unless the bug has broad cross-mode risk.
4
+ ---
5
+
6
+ # Visual Bug Fixing
7
+
8
+ ## Rule
9
+
10
+ Fix visual bugs with evidence, not guesswork. Capture the broken state, fix the cause, capture the result, then run only as much regression coverage as the risk justifies.
11
+
12
+ ## Use This When
13
+
14
+ - The user reports a visual bug
15
+ - You see a layout/rendering regression while working
16
+ - A screenshot-based test or `tests/ui_audit.py` fails
17
+
18
+ Do not use this for brand-new feature design or docs/test sync work.
19
+
20
+ ## Targeted Path
21
+
22
+ For a small bug in one known area:
23
+
24
+ 1. Capture one baseline screenshot of the broken state
25
+ 2. Inspect the owning code path
26
+ 3. Apply the smallest real fix
27
+ 4. Capture one post-fix screenshot
28
+ 5. Check the most likely neighboring mode(s)
29
+
30
+ Escalate to the broader audit path only when the bug touches shared layout, shared chrome, zoom, or multiple modes.
31
+
32
+ ## Where To Look
33
+
34
+ | Area | Owner |
35
+ |------|-------|
36
+ | UI structure, CSS, JS layout | `_viewer.html` |
37
+ | Rendering routes | `_server.py` + `_routes_rendering.py` |
38
+ | Render/compositing helpers | `_render.py`, `_overlays.py` |
39
+ | Colorbar behavior | `ColorBar` class in `_viewer.html` |
40
+
41
+ Do not treat `_app.py` as the implementation surface; it is a compat shim.
42
+
43
+ ## Diagnose First
44
+
45
+ - CSS positioning / overflow / z-index problem?
46
+ - Layout calculation bug in a mode-specific scale function?
47
+ - Missing branch for compare, multiview, or qMRI?
48
+ - Zoom-specific issue?
49
+ - Animation/timing issue? If yes, use the animation verification pattern instead of static screenshots alone.
50
+
51
+ ## Common Fix Patterns
52
+
53
+ - Overlap bug: inspect bounds and z-order
54
+ - Wrong size: trace the relevant scale/layout function
55
+ - Mode-only regression: find the missing mode branch
56
+ - Render mismatch: inspect route params and backend render helpers
57
+
58
+ ## Broader Audit Path
59
+
60
+ Use this when the bug has shared-chrome or cross-mode risk:
61
+
62
+ ```bash
63
+ uv run python tests/ui_audit.py --tier 1
64
+ ```
65
+
66
+ Go to tier 2 only when the affected feature or regression area actually needs it.
67
+
68
+ ## Red Flags
69
+
70
+ - The fix works only in normal mode
71
+ - The patch hides the symptom instead of fixing placement/ownership
72
+ - Verification skipped screenshots entirely
73
+ - `_app.py` was edited for new behavior
74
+
75
+ ## Verification
76
+
77
+ - [ ] Baseline screenshot captured
78
+ - [ ] Post-fix screenshot captured
79
+ - [ ] Nearby modes checked based on risk
80
+ - [ ] `tests/ui_audit.py --tier 1` run if the bug touched shared layout/chrome/cross-mode behavior
@@ -1,11 +1,12 @@
1
1
  ---
2
2
  name: agents
3
3
  description: Lightweight pointer to ROUTER.md for task routing.
4
- last_updated: 2026-04-29
4
+ last_updated: 2026-05-01
5
5
  ---
6
6
 
7
7
  # arrayview
8
8
 
9
- Use `.mex/ROUTER.md` first when you need project state, routing, or a matching task pattern.
9
+ Use `.mex/ROUTER.md` at the start of a new task or when the task family changes.
10
+ Do not reload it for routine follow-up work in the same area unless blocked.
10
11
  After finishing work, update any stale `.mex` files you touched and run `mex check --quiet`.
11
12
  If drift remains, use `.mex/sync.sh` for the repo-local sync path.
@@ -20,11 +20,20 @@ edges:
20
20
  condition: when working on rendering, colormaps, LUTs, caching, or the render thread
21
21
  - target: patterns/INDEX.md
22
22
  condition: when starting a task — check the pattern index for a matching pattern file
23
- last_updated: 2026-04-29
23
+ - target: ../DESIGN.md
24
+ condition: when the task touches design philosophy — new features, UI changes, mode additions, or interaction model decisions
25
+ last_updated: 2026-05-02
24
26
  ---
25
27
 
26
28
  # arrayview — Router
27
29
 
30
+ ## Fast Path
31
+
32
+ - New task or changed task family: read this file, then load at most one pattern and one context file.
33
+ - Follow-up in the same thread and same subsystem: do **not** reopen this router. Reuse what is already loaded unless blocked.
34
+ - Small localized `_viewer.html` fix with a known symbol: go straight to exact code search. Do **not** auto-load `context/frontend.md`.
35
+ - Normal work should **not** load `.mex/SETUP.md`, `.mex/SYNC.md`, or `patterns/README.md`. Those are scaffold-maintenance files only.
36
+
28
37
  ## What This Is
29
38
  Python package for interactively viewing multi-dimensional arrays (numpy, NIfTI, zarr, etc.) with a FastAPI backend, single-file HTML/JS frontend, and multi-environment display routing (Jupyter, VS Code, SSH, native window).
30
39
 
@@ -50,6 +59,17 @@ Python package for interactively viewing multi-dimensional arrays (numpy, NIfTI,
50
59
  3. Follow **one extra edge only when blocked**. Do not recursively fan out through second-hop edges.
51
60
  4. Load `context/project-state.md` only when the task depends on current shipped or in-progress work.
52
61
  5. For UI, animation, or behavior bugs: ask plain-English clarification questions **before** reading git history, large diffs, or broad source sweeps.
62
+ 6. For follow-up work in the same thread: prefer reusing already-loaded context over reopening router/context/pattern files.
63
+
64
+ ## Common Cases
65
+
66
+ | Situation | Load |
67
+ |-----------|------|
68
+ | Follow-up in same area, no task-family change | No new `.mex` files by default |
69
+ | Small `_viewer.html` tweak, exact function/id already known | Exact `rg` + narrow code read only |
70
+ | `_viewer.html` change touching modes, reconcilers, keybind registry, or unfamiliar sections | `patterns/frontend-change.md`, then `context/frontend.md` only if still needed |
71
+ | Backend/server change in a known file family | Matching pattern first, then one context file only if blocked |
72
+ | Release validation or broad cross-mode audit | Matching pattern + relevant context file(s) deliberately |
53
73
 
54
74
  ## Current Project State
55
75
 
@@ -71,11 +91,12 @@ Load `context/project-state.md` only when you need active-workstream or recent-s
71
91
  | Adding a server route / WebSocket endpoint | `patterns/add-server-endpoint.md` |
72
92
  | Visual bugs / render artifacts | `patterns/debug-render.md` |
73
93
  | Verifying animation changes | `patterns/animation-verify.md` |
94
+ | Design philosophy, new features, UI changes, mode additions, interaction model | `DESIGN.md` |
74
95
  | Any specific task | Check `patterns/INDEX.md` for a matching pattern |
75
96
 
76
97
  ## Behavioural Contract
77
98
 
78
- 1. **CONTEXT** — Load from the routing table. Start small: this file + one pattern + one context file is the default cap. Do not preload unrelated docs.
99
+ 1. **CONTEXT** — Load from the routing table. Start small: this file + one pattern + one context file is the default cap. Do not preload unrelated docs, and do not reopen docs on routine follow-ups.
79
100
  2. **CLARIFY** — If the task is about UI behavior, animation, or UX expectations, ask plain-English questions before deep investigation.
80
101
  3. **BUILD** — Do the work. If deviating from an established pattern, say so before writing code.
81
102
  4. **VERIFY** — If a pattern file was loaded, use its Verify section. Otherwise use the shared Verify Checklist in `context/conventions.md`.
@@ -18,7 +18,7 @@ edges:
18
18
  condition: when the task involves _viewer.html, modes, reconcilers, or the View Component System
19
19
  - target: context/render-pipeline.md
20
20
  condition: when the task involves slice extraction, colormaps, caching, or the render thread
21
- last_updated: 2026-04-29
21
+ last_updated: 2026-05-05
22
22
  ---
23
23
 
24
24
  # Architecture
@@ -54,11 +54,12 @@ pywebview, or system browser).
54
54
  - **`_server.py`** — FastAPI app initialization, route-registration orchestrator, and infrastructure routes. Feature domains are delegated to `_routes_*.py` modules via `register_*()` calls. Remaining inline routes are `/`, `/ping`, `/colormap/{name}`, `/shell`, and the GSAP asset route that serves `src/arrayview/gsap.min.js`, plus shared helpers like `get_session_or_404()`.
55
55
  - **`_routes_*.py`** — Feature-route modules grouped by domain (analysis, loading, persistence, segmentation, state, query, export, preload, vectorfield, rendering, websocket transport). Each module exposes `register_*_routes(app, ...)` and keeps `_server.py` focused on assembly and shared dependencies.
56
56
  - **`_session.py`** — Single source of global mutable state: `SESSIONS`, `SERVER_LOOP`, `VIEWER_SOCKETS`, `VIEWER_SIDS`, `SHELL_SOCKETS`. Owns the render thread (`_RENDER_QUEUE`, `_RENDER_THREAD`), prefetch pool, and the `Session` class with its three LRU caches.
57
- - **`_render.py`** — Stateless rendering functions: `extract_slice()`, `apply_complex_mode()`, `render_rgba()`, `render_rgb_rgba()`, `render_mosaic()`, `extract_projection()`. Owns colormap LUTs (`LUTS` dict, lazy-initialized by `_init_luts()`).
57
+ - **`_render.py`** — Stateless rendering functions: `extract_slice()`, `apply_complex_mode()`, `render_rgba()`, `render_rgb_rgba()`, `render_mosaic()`, `extract_projection()`. Owns colormap LUTs (`LUTS` dict, lazy-initialized by `_init_luts()`). Also provides `_build_mosaic_grid()` (shared grid builder) and `_evict_lru()` (shared cache eviction).
58
+ - **`_imaging.py`** — Shared lazy PIL accessors (`ensure_image()`, `ensure_imageops()`) used by `_diff`, `_server`, `_routes_rendering`, `_routes_websocket`, `_stdio_server`.
58
59
  - **`_analysis.py`, `_diff.py`, `_overlays.py`, `_vectorfield.py`** — Shared backend helpers for metadata, analysis endpoints, compare/diff rendering, overlay compositing, vector field validation, and arrow sampling. Imported by both `_server.py` and `_stdio_server.py`.
59
60
  - **`_io.py`** — All file-format loading behind `load_data(filepath)`. Lazy nibabel import for NIfTI. Handles `.npy`, `.npz`, `.nii` and `.nii.gz`, `.zarr`, `.zarr.zip`, `.pt` and `.pth`, `.h5` and `.hdf5`, `.tif` and `.tiff`, `.mat`. Extensions registered in `_SUPPORTED_EXTS`.
60
61
  - **`_platform.py`** — Environment detection: checks jupyter → vscode → julia → ssh → terminal in priority order. Results cached. Never short-circuit this order.
61
- - **`_vscode.py`** — VS Code extension install/management, signal-file IPC, shared-memory IPC, webview panel and direct webview opening.
62
+ - **`_vscode.py`** — VS Code integration facade. Submodules: `_vscode_extension.py` (install), `_vscode_signal.py` (signal-file IPC), `_vscode_shm.py` (shared-memory transport), `_vscode_browser.py` (browser/SSH guidance).
62
63
  - **`_stdio_server.py`** — Alternative to FastAPI for VS Code tunnel (direct webview): JSON on stdin, length-prefixed binary on stdout.
63
64
  - **`_viewer.html`** — The entire frontend (~24 100 lines). CSS + JS in one file, no build step. Canvas-based rendering, WebSocket binary protocol, all viewing modes, reconcilers, command registry. See `context/frontend.md`.
64
65
 
@@ -0,0 +1,83 @@
1
+ ---
2
+ name: frontend
3
+ description: Deeper _viewer.html map for cross-section frontend work. Do not load for small localized follow-up fixes with a known symbol.
4
+ triggers:
5
+ - "_viewer.html"
6
+ - "reconciler"
7
+ - "command registry"
8
+ - "GUIDE_TABS"
9
+ - "modeManager"
10
+ - "ColorBar class"
11
+ - "LayoutStrategy"
12
+ edges:
13
+ - target: context/architecture.md
14
+ condition: when understanding how the frontend connects to the server
15
+ - target: context/decisions.md
16
+ condition: when understanding why the frontend is a single file or why reconcilers exist
17
+ - target: context/conventions.md
18
+ condition: when writing new frontend code and need section separator conventions
19
+ - target: patterns/frontend-change.md
20
+ condition: when making a concrete change to _viewer.html
21
+ last_updated: 2026-05-01
22
+ ---
23
+
24
+ # Frontend (_viewer.html)
25
+
26
+ Load this only when the task crosses sections or when the relevant symbol is not already known.
27
+ For a small follow-up tweak, prefer exact code search in `_viewer.html` and skip this file.
28
+
29
+ `_viewer.html` is a single-file frontend with inline CSS and JS. No build step.
30
+
31
+ ## Load This When
32
+
33
+ - The change touches reconcilers, mode transitions, `modeManager`, or layout auto-pickers
34
+ - A keybind/command change needs the registry + `GUIDE_TABS` rules
35
+ - The task spans multiple frontend subsystems and local code reads are no longer enough
36
+ - You need the high-level map before editing an unfamiliar area
37
+
38
+ ## Skip This When
39
+
40
+ - The user is asking for ideas, review, or a tiny follow-up fix in one known function/section
41
+ - The target id/function/command is already known and can be reached with one exact `rg`
42
+ - The task is local styling or text copy near an already-known DOM node
43
+
44
+ ## Quick Anchors
45
+
46
+ - Section separators: `/* ── Section Name ── */` in CSS, `// ── Section Name ──` in JS
47
+ - Reconcilers: grep `UI Validation and Reconciliation`, `_reconcileUI`, `_reconcileLayout`
48
+ - Keybinds/help: grep `commands`, `keybinds`, `GUIDE_TABS`, `dispatchCommand`
49
+ - Mode system: grep `Mode Registry`, `modeManager`, `enterMultiView`, `enterCompare`, `enterQmri`
50
+ - Layout/scale: grep `scaleCanvas`, `mvScaleAllCanvases`, `compareScaleCanvases`, `qvScaleAllCanvases`
51
+ - Colorbars: grep `ColorBar class`, `drawSlimColorbar`, `drawMvColorbar`
52
+
53
+ ## Rules That Matter
54
+
55
+ - Visibility changes belong in reconcilers, not scattered `style.display` or `classList` toggles
56
+ - Keybind changes must update both the command/keybind registry and `GUIDE_TABS`
57
+ - Reuse shared layout helpers for viewport/layout decisions; do not add ad hoc per-mode heuristics
58
+ - `ColorBar` usage is mixed legacy/new: stay consistent within the section you touch
59
+ - Canvas dimensions should be owned by the mode scale/layout functions, not ad hoc writes
60
+
61
+ ## Mode Map
62
+
63
+ | Area | Main owner |
64
+ |------|------------|
65
+ | Normal / immersive / compact | `scaleCanvas()` |
66
+ | Multiview / ortho | `mvScaleAllCanvases()` |
67
+ | Compare / diff / registration | `compareScaleCanvases()` |
68
+ | Compare + MV | `compareMvScaleAllCanvases()` |
69
+ | qMRI / qMRI mosaic | `qvScaleAllCanvases()` |
70
+ | MIP | dedicated WebGL path |
71
+
72
+ ## Important Concepts
73
+
74
+ - **Reconcilers** — UI visibility/state should converge here after mode changes
75
+ - **Command registry** — `commands`, `keybinds`, `dispatchCommand`, `GUIDE_TABS`
76
+ - **View component system** — `View`, `Slicer`, `Layer`, `LayoutStrategy`, `modeManager`; still coexists with legacy rendering
77
+ - **Dual-write state** — when legacy globals are changed, matching `displayState` fields may need updating too
78
+ - **Manual range state** — `manualVmin` / `manualVmax` and per-view locked ranges are real state, not derived UI
79
+ - **Tool menu and dynamic island** — central owners for several multi-feature UI surfaces; touch deliberately
80
+
81
+ ## Verification Reminder
82
+
83
+ If a change touches multiple modes, reconcilers, or layout routing, verify cross-mode behavior instead of trusting a single local interaction.
@@ -7,7 +7,7 @@ triggers:
7
7
  - "recent work"
8
8
  - "active feature"
9
9
  - "shipped recently"
10
- last_updated: 2026-04-29
10
+ last_updated: 2026-05-05
11
11
  ---
12
12
 
13
13
  # Project State
@@ -20,7 +20,7 @@ last_updated: 2026-04-29
20
20
  - Rendering pipeline: colormaps, complex modes, mosaic, RGB/RGBA, projections, overlays
21
21
  - Backend transport parity: FastAPI and stdio now share metadata/analysis helpers, compare/diff helpers, overlay compositing, and vector field layout/arrow sampling via `_analysis.py`, `_diff.py`, `_overlays.py`, and `_vectorfield.py`
22
22
  - NIfTI spatial metadata, RAS resampling
23
- - VS Code extension v0.14.5 — stable window ID via `EnvironmentVariableCollection`; `arrayview.openInFloatingWindow` setting moves new tabs to a floating window; `view(arr, floating=True)` and `arrayview file.npy --floating` open in a floating window per-call regardless of global setting; `!vscode.env.remoteName` guard removed (remote VS Code supports floating windows); floating mode now uses a single persistent shell hub panel (`_shell.html`) so all arrays share one floating window as tabs instead of opening separate windows; fixed: second CLI call now injects tab via `new_tab` postMessage relay (extension -> hub wrapper -> shell iframe) instead of relying on WebSocket notify which wasn't sent in VS Code mode
23
+ - VS Code extension v0.14.4 — stable window ID via `EnvironmentVariableCollection`; `arrayview.openInFloatingWindow` setting moves new tabs to a floating window; `view(arr, floating=True)` and `arrayview file.npy --floating` open in a floating window per-call regardless of global setting; `!vscode.env.remoteName` guard removed (remote VS Code supports floating windows); floating mode now uses a single persistent shell hub panel (`_shell.html`) so all arrays share one floating window as tabs instead of opening separate windows; fixed: second CLI call now injects tab via `new_tab` postMessage relay (extension -> hub wrapper -> shell iframe) instead of relying on WebSocket notify which wasn't sent in VS Code mode; custom-editor fallback now pins `uv` to Python 3.12 so tunnel workspaces with older project interpreters still open arrays
24
24
  - Colorbar refactor: `ColorBar` JS class partially migrated (in progress)
25
25
  - Colormap picker: `c` opens an expanded colorbar-island grid without changing the colormap; subsequent `c` taps cycle, hover/hjkl/arrows live-preview, Enter/click commits, Esc cancels, and auto-dismiss pauses while hovered
26
26
  - Cold-start loading spinner in VS Code and native shell
@@ -26,6 +26,7 @@ Lookup table for all pattern files in this directory. Check here before starting
26
26
  | [add-file-format.md](add-file-format.md) | Adding support for a new file format in `_io.py` |
27
27
  | [animation-verify.md](animation-verify.md) | Verifying animation quality after GSAP, rAF, or CSS transition changes |
28
28
  | [add-server-endpoint.md](add-server-endpoint.md) | Adding a new REST or WebSocket route to `_server.py` |
29
+ | [debug-vscode-extension-python.md](debug-vscode-extension-python.md) | Diagnosing VS Code custom-editor failures caused by Python selection, workspace virtualenv drift, or uv fallback behavior |
29
30
  | [debug-render.md](debug-render.md) | Visual rendering failures — wrong colors, blank canvas, artifacts, colormap issues |
30
31
  | [extract-server-route-module.md](extract-server-route-module.md) | Moving an existing route cluster out of `_server.py` into a dedicated `_routes_*.py` module |
31
32
  | [frontend-change.md](frontend-change.md) | Any change to `_viewer.html` — CSS, JS, new mode, keybind, layout, colorbar |
@@ -0,0 +1,95 @@
1
+ ---
2
+ name: debug-vscode-extension-python
3
+ description: Diagnosing VS Code custom-editor or direct-webview failures caused by Python resolution, workspace virtualenv drift, or uv fallback behavior.
4
+ triggers:
5
+ - "ArrayView failed to open"
6
+ - "Python process exited with code 1"
7
+ - "vscode extension"
8
+ - "custom editor"
9
+ - "remote tunnel"
10
+ - "uv run --with arrayview"
11
+ - "python 3.12"
12
+ edges:
13
+ - target: context/conventions.md
14
+ condition: when making code changes after confirming the failure mode
15
+ last_updated: 2026-05-06
16
+ ---
17
+
18
+ # Debug VS Code Extension Python
19
+
20
+ ## Context
21
+
22
+ The VS Code opener extension starts ArrayView in two different ways:
23
+ 1. Signal-file mode from Python (`view(...)`, CLI, Julia, etc.)
24
+ 2. Custom-editor mode when the user clicks `.npy` / `.nii` / similar files in VS Code
25
+
26
+ Custom-editor mode lives in `vscode-extension/extension.js` and spawns:
27
+ - explicit `pythonPath` from a signal file when present
28
+ - workspace `.venv/bin/python` when present
29
+ - `python3`
30
+ - `python`
31
+ - `uv run --python 3.12 --with arrayview python`
32
+
33
+ ArrayView requires Python `>=3.12`. A common tunnel failure is a workspace `.venv`
34
+ or default shell Python at `3.11`, which makes the final `uv` fallback fail with
35
+ an unsatisfiable dependency error.
36
+
37
+ ## Steps
38
+
39
+ 1. **Check the extension log first**
40
+ ```bash
41
+ tail -n 120 ~/.arrayview/extension.log
42
+ ```
43
+ Look for `CUSTOM-EDITOR:`, `PYTHON: spawning`, stderr lines, and the final exit code.
44
+
45
+ 2. **Identify which candidate failed**
46
+ The log shows the exact command order. Typical failure pattern:
47
+ ```
48
+ PYTHON: spawning /path/to/.venv/bin/python -m arrayview --mode stdio file.npy
49
+ PYTHON: ... No module named arrayview
50
+ PYTHON: spawning uv run --python 3.12 --with arrayview python -m arrayview --mode stdio file.npy
51
+ ```
52
+
53
+ 3. **Reproduce from the failing workspace root**
54
+ ```bash
55
+ timeout 10s sh -c 'uv run --python 3.12 --with arrayview python -m arrayview --mode stdio file.npy </dev/null'
56
+ ```
57
+ Success is a `SESSION:{...}` line on stderr. If it exits `1`, keep the stderr.
58
+
59
+ 4. **Check the workspace virtualenv directly**
60
+ ```bash
61
+ .venv/bin/python - <<'PY'
62
+ import arrayview, sys
63
+ print(sys.executable)
64
+ print(arrayview.__file__)
65
+ print(getattr(arrayview, '__version__', 'missing'))
66
+ PY
67
+ ```
68
+ If this raises `ModuleNotFoundError`, the workspace `.venv` exists but does not
69
+ have ArrayView installed.
70
+
71
+ 5. **Interpret the usual root causes**
72
+ - `No module named arrayview` from `.venv/bin/python`: project env exists but lacks ArrayView
73
+ - `current Python version ... does not satisfy Python>=3.12`: the fallback is using an older interpreter
74
+ - `SESSION:{...}` appears: stdio startup is healthy; any remaining issue is on the extension/webview side
75
+
76
+ 6. **If editing `extension.js`**
77
+ Follow the VS Code extension skill checklist: bump `vscode-extension/package.json`, bump `_VSCODE_EXT_VERSION` in `src/arrayview/_vscode_extension.py`, rebuild `src/arrayview/arrayview-opener.vsix`, and verify the embedded version.
78
+
79
+ ## Gotchas
80
+
81
+ - Running `python -m arrayview --mode stdio ...` directly from a shell script without redirecting stdin can feed shell text into the stdio server. Use `</dev/null` for bounded startup checks.
82
+ - In tunnel workspaces, the clicked-file custom editor does **not** use the current repo checkout automatically unless that workspace `.venv` points to it.
83
+ - A reboot or deleting `~/.vscode-server` can change the default interpreter resolution without changing the extension code.
84
+
85
+ ## Verify
86
+
87
+ - [ ] `~/.arrayview/extension.log` shows the expected candidate order
88
+ - [ ] The failing workspace reproducer emits `SESSION:{...}` with the intended interpreter
89
+ - [ ] If `extension.js` changed, `vscode-extension/package.json`, `_VSCODE_EXT_VERSION`, and the VSIX version all match
90
+ - [ ] After reinstalling or reloading, the custom editor opens the target array without `Python process exited with code 1`
91
+
92
+ ## Update Scaffold
93
+ - [ ] Update `.mex/context/project-state.md` if the shipped fallback behavior changed
94
+ - [ ] Update any `.mex/context/` files that are now out of date
95
+ - [ ] Add this pattern to `.mex/patterns/INDEX.md`
@@ -0,0 +1,72 @@
1
+ ---
2
+ name: frontend-change
3
+ description: Editing `_viewer.html`. Prefer exact code-local search first; load deeper frontend context only when the change crosses sections or modes.
4
+ triggers:
5
+ - "_viewer.html"
6
+ - "keyboard shortcut"
7
+ - "layout"
8
+ - "reconciler"
9
+ - "GUIDE_TABS"
10
+ edges:
11
+ - target: context/frontend.md
12
+ condition: when the change spans multiple frontend sections or the target area is not already known
13
+ - target: context/architecture.md
14
+ condition: when understanding how the frontend connects to the server
15
+ - target: context/conventions.md
16
+ condition: for shared conventions and the Verify Checklist
17
+ - target: patterns/debug-render.md
18
+ condition: when the change produces wrong visual output
19
+ last_updated: 2026-05-01
20
+ ---
21
+
22
+ # Frontend Change
23
+
24
+ ## Fast Path
25
+
26
+ - If the target function/id/section is already known, do **not** load extra `.mex` files first.
27
+ - Run one exact `rg`, read one narrow local slice, then edit.
28
+ - Load `context/frontend.md` only if the change touches reconcilers, mode routing, command registry, or another unfamiliar cross-section area.
29
+
30
+ ## Context
31
+
32
+ The frontend lives in `src/arrayview/_viewer.html`. No build step. No separate files.
33
+ Section separators are the navigation primitive:
34
+ - CSS: `/* ── Section Name ── */`
35
+ - JS: `// ── Section Name ──`
36
+
37
+ ## Steps
38
+
39
+ 1. If the desired behavior is still ambiguous, ask 2-3 plain-English clarification questions before reading git history, large diffs, or broad sections of `_viewer.html`.
40
+ 2. Scope the affected modes/panes. If the user explicitly asked for a full visual check, or this is release validation, invoke `ui-consistency-audit`.
41
+ 3. Navigate by exact identifier or section separator, not broad keyword sweeps.
42
+ 4. Read only the local CSS/JS slice you need.
43
+ 5. Make the change in place and preserve section separator style.
44
+ 6. If adding a keyboard shortcut: update both the command/keybind registry and `GUIDE_TABS`.
45
+ 7. If adding a new mode: register it in the `Mode Registry`.
46
+ 8. Run narrow verification for the touched behavior.
47
+ 9. If the change affects mode routing/layout behavior across modes, run the targeted mode test.
48
+ 10. Only run the broader visual audit path when explicitly requested or doing release validation.
49
+
50
+ ## Gotchas
51
+
52
+ - Never sweep `_viewer.html` broadly when a known symbol or section marker can get you there.
53
+ - Modes are exclusive; mode-entry work often needs explicit exit or reconcile logic.
54
+ - The help overlay is static via `GUIDE_TABS`; it is easy to forget.
55
+ - Some colorbars use `ColorBar`, some use legacy code. Do not mix styles within one local path.
56
+ - Reuse shared layout helpers for layout auto-pickers instead of adding new heuristics.
57
+ - Full visual audit is not the default path.
58
+
59
+ ## Verify
60
+
61
+ - [ ] Section separator style matches: `/* ── Section Name ── */` (CSS) or `// ── Section Name ──` (JS)
62
+ - [ ] No new external JS/CSS files created — everything stays in `_viewer.html`
63
+ - [ ] Help overlay updated if a keyboard shortcut was added or changed
64
+ - [ ] Narrow verification for the touched behavior completed
65
+ - [ ] If full visual audit was requested, or this is release validation, `ui-consistency-audit` and `uv run python` on `tests/visual_smoke.py` pass
66
+ - [ ] If mode routing/layout behavior changed across modes, `uv run pytest` on `tests/test_mode_consistency.py` passes
67
+
68
+ ## Debug
69
+
70
+ If `visual_smoke.py` fails: see `patterns/debug-render.md`.
71
+ If the mode doesn't activate: check Mode Registry — the `enter()` function must be registered by exact mode name string.
72
+ If layout breaks in one environment but not others: check mode-specific CSS rules; immersive/compact mode may override your styles.
@@ -32,6 +32,16 @@ Use **subagent-driven development**. Work in **feature branches**.
32
32
 
33
33
  Read `CONTRIBUTING.md` before any user-facing change or PR.
34
34
 
35
+ For follow-up work in `src/arrayview/_viewer.html`, do not run broad searches.
36
+ Do not use regex alternations or generic keyword sweeps across `_viewer.html`.
37
+ Search for one exact identifier at a time: an id, function name, command id, or
38
+ section marker already suggested by the user or current context. After each hit,
39
+ read only one narrow `sed` window around the match. If the needed identifier is
40
+ not known, ask or infer from recent context instead of exploring broadly. If more
41
+ than three exact searches would be needed, stop and explain why before continuing.
42
+ Do not reload `.mex` docs or skills on small follow-up UI fixes unless the task
43
+ clearly needs fresh context.
44
+
35
45
  ## Testing
36
46
 
37
47
  Verify narrowly — do not run the full suite unless asked.