Skip to content

Commit 1f02624

Browse files
mbreiserclaude
andcommitted
docs: update quickstart guide and CLAUDE.md for v0.9
- Quickstart: add undo/redo/reset section, keyboard shortcuts, import undo tip, connect command in BiasPlugin list, updated interface diagram - CLAUDE.md: v0.9 architecture, undo/redo system docs with _restoring guard and selection clamping notes, YAML export bug fix docs (empty params, string types, single quotes), duration formula, updated related files and test counts (137 checks, 10 suites) - Close issues #53-60 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 3e527fa commit 1f02624

2 files changed

Lines changed: 42 additions & 15 deletions

File tree

CLAUDE.md

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -438,16 +438,17 @@ The following UI improvements were made on 2026-02-02 and need testing on GitHub
438438

439439
## Experiment Designer
440440

441-
### Architecture (v0.8 — 2026-04-08)
441+
### Architecture (v0.9 — 2026-04-10)
442442
- 3-zone layout: settings panel (280px left), editor with tab bar (flex right), filmstrip with lane view (bottom)
443443
- Single `<script type="module">` importing from `js/arena-configs.js`, `js/protocol-yaml.js`, `js/plugin-registry.js`
444444
- Data model: `experiment` object with `experiment_info`, `arena_info`, `rig_path`, `plugins[]`, `experiment_structure`, phases with `commands[]`, and `conditions[]` with `commands[]`
445+
- Undo/redo: snapshot-based history stack (JSON.stringify/parse of `experiment`, max 50 entries)
445446

446447
### Shared Modules
447448
- **`js/protocol-yaml.js`** — YAML parser (`simpleYAMLParse` with inline comment stripping), v1/v2 generators, string helpers. Dual-export (window.ProtocolYAML + ES6 module). Used by HTML, both test files.
448449
- `yamlStr(str)` — double-quotes strings for YAML
449450
- `yamlPath(str)` — single-quotes paths (no escape sequences, safe for Windows backslashes)
450-
- **`js/plugin-registry.js`** — Built-in plugin definitions (LEDControllerPlugin: 7 commands, BiasPlugin: 6 commands), controller command definitions (6 commands), lookup functions for dropdown population. Dual-export.
451+
- **`js/plugin-registry.js`** — Built-in plugin definitions (LEDControllerPlugin: 7 commands, BiasPlugin: 7 commands incl. connect), controller command definitions (6 commands), lookup functions for dropdown population. Dual-export.
451452
- Plugin config fields use `rigDefined: true` for fields already in rig YAML (ip, port) — these are NOT auto-included in exports
452453
- `createPluginEntry()` skips fields with empty string defaults
453454

@@ -474,6 +475,8 @@ experiment.rig_path = "./configs/rigs/test_rig_1.yaml"
474475
```
475476
Helper functions: `cmdFindTrialParams(commands)`, `condGetDuration(cond)`, `condGetPattern(cond)`, `phaseGetDuration(phase)`.
476477

478+
**Duration formula**: `max(trialParams.duration, sum_of_waits)` — shows the actual wall-clock time. If waits exceed trialParams duration, the condition runs longer than the pattern display (visible to the user as a mismatch).
479+
477480
**Shared command helpers** (used by Commands tab, Table view, and phase editor):
478481
- `buildAddCommandOptions()` — returns HTML `<option>`/`<optgroup>` string for add-command dropdowns
479482
- `createCommandFromSelectValue(value)` — parses `"controller:trialParams"` / `"wait:wait"` / `"plugin:backlight:setRedLEDPower"` into a command object
@@ -482,7 +485,9 @@ Helper functions: `cmdFindTrialParams(commands)`, `condGetDuration(cond)`, `cond
482485
### YAML Export (v2)
483486
- Generates protocol v2 via `generateV2Protocol()` from `js/protocol-yaml.js`
484487
- `rig:` field replaces inline `arena_info`
485-
- **Paths use single quotes** via `yamlPath()` (pattern_library, rig, script_path) — prevents Windows backslash escape issues
488+
- **All string values use single quotes** via `yamlPath()` — pattern filenames, paths, plugin string params — prevents Windows backslash escape issues
489+
- **Empty optional plugin params are omitted** — e.g., an empty `pattern` field is not exported (would cause MATLAB errors)
490+
- **Plugin param types respected**: input handlers consult `getCommandParams()` schema — string-typed params like `pattern: "1010"` are kept as strings, not coerced to numbers
486491
- `plugins:` section lists enabled plugins with class/config — only user-set config values are exported (empty = omit)
487492
- Conditions export full command arrays including plugin commands with params
488493
- Phases export command arrays directly
@@ -501,6 +506,17 @@ The bottom timeline area is a unified scroll container:
501506
- Block widths use `Math.max(48, duration * pxPerSecond)` — lane SVG must match this + account for 2px CSS gap between blocks
502507
- Clicking any filmstrip block switches to the Commands tab
503508

509+
### Undo/Redo System (v0.9)
510+
- **Snapshot stack**: `undoStack[]` and `redoStack[]` store `JSON.stringify(experiment)` snapshots (max 50)
511+
- **`saveSnapshot()`**: Called before every mutation. Pushes current state to undoStack, clears redoStack.
512+
- **`_restoring` guard**: Boolean flag set during `restoreSnapshot()` (wrapped in try/finally). Prevents focus events on re-rendered inputs from calling `saveSnapshot()` and clearing the redo stack.
513+
- **Selection clamping**: `restoreSnapshot()` clamps `selection.index` to valid bounds after restoring, since the restored state may have fewer conditions.
514+
- **Text inputs**: Snapshot on `focus` (not `input`) — one undo step per field visit, not per keystroke. Browser native Ctrl+Z still works inside inputs.
515+
- **Reset button**: Clears conditions/phases/plugins to defaults, keeps settings (experiment_info, arena, rig_path). Clears both undo/redo stacks. Shows confirm dialog.
516+
- **Keyboard**: Ctrl+Z/Cmd+Z (undo), Ctrl+Y/Cmd+Y/Ctrl+Shift+Z (redo) — only fires when focus is not in INPUT/TEXTAREA/SELECT.
517+
518+
**When adding new mutation sites**: Always call `saveSnapshot()` before the mutation. For new text inputs, add a `focus` event listener that calls `saveSnapshot`.
519+
504520
### Key Implementation Notes
505521
- **Must use `<script type="module">`** to import shared modules
506522
- Mode 2 (Constant Rate): `gain` fixed at 0, `frame_rate` editable
@@ -511,20 +527,20 @@ The bottom timeline area is a unified scroll container:
511527
- Plugin config uses `setPluginConfig()` helper that deletes empty values and removes config object when empty
512528

513529
### Related Files
514-
- `experiment_designer.html` — Main tool (v0.8)
515-
- `experiment_designer_quickstart.html` — Step-by-step guide (v0.8)
530+
- `experiment_designer.html` — Main tool (v0.9)
531+
- `experiment_designer_quickstart.html` — Step-by-step guide (v0.9)
516532
- `js/protocol-yaml.js` — Shared YAML parser/generator (added `yamlPath`)
517-
- `js/plugin-registry.js` — Plugin definitions + command schemas (updated defaults)
518-
- `tests/test-protocol-roundtrip.js`130 CI checks (9 suites, v1+v2)
533+
- `js/plugin-registry.js` — Plugin definitions + command schemas (BiasPlugin: connect command added)
534+
- `tests/test-protocol-roundtrip.js`137 CI checks (10 suites, v1+v2 + bug regression)
519535
- `tests/generate-roundtrip-protocol.js` — YAML + manifest generator for MATLAB
520536
- `tests/fixtures/v2_*.yaml` — V2 YAML test fixtures from maDisplayTools
521537
- `docs/experiment-designer-v06-testing.md` — Manual testing checklist
522538
- `docs/protocol-roundtrip-testing.md` — Roundtrip testing architecture
523-
- GitHub Issues: [#33](https://github.com/reiserlab/webDisplayTools/issues/33), [#53](https://github.com/reiserlab/webDisplayTools/issues/53) (hover tooltips), [#54](https://github.com/reiserlab/webDisplayTools/issues/54) (undo/redo)
539+
- GitHub Issues: [#33](https://github.com/reiserlab/webDisplayTools/issues/33), [#53–60 closed](https://github.com/reiserlab/webDisplayTools/issues?q=is%3Aissue+is%3Aclosed) (tooltips, bugs, undo/redo, connect cmd, param backfill)
524540

525-
### Testing & Validation (v0.8)
541+
### Testing & Validation (v0.9)
526542

527-
**Automated:** `node tests/test-protocol-roundtrip.js`130 checks across 9 suites (v1+v2 parse/generate roundtrips). Run after any change to `protocol-yaml.js` or the data model.
543+
**Automated:** `node tests/test-protocol-roundtrip.js`137 checks across 10 suites (v1+v2 parse/generate roundtrips + bug #55-58 regressions). Run after any change to `protocol-yaml.js` or the data model.
528544

529545
**Manual testing checklist (import a v2 YAML like `full_experiment_test.yaml` to populate):**
530546

experiment_designer_quickstart.html

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,13 +215,13 @@
215215
<a href="experiment_designer.html" class="nav-link">&larr; Back to Experiment Designer</a>
216216

217217
<h1>Experiment Designer Quick Start</h1>
218-
<p class="subtitle">v0.8 | 2026-04-08 18:38 ET &mdash; Learn the interface and create your first protocol in minutes.</p>
218+
<p class="subtitle">v0.9 | 2026-04-10 16:37 ET &mdash; Learn the interface and create your first protocol in minutes.</p>
219219

220220
<h2>Interface overview</h2>
221221

222-
<div class="layout-diagram"><span class="hl">Top bar</span>: &larr; Back | Experiment Designer [Quick Start] [Import YAML] [<span class="hl">Export YAML</span>]
222+
<div class="layout-diagram"><span class="hl">Top bar</span>: &larr; Back | Experiment Designer [Undo] [Redo] [Quick Start] [Import YAML] [<span class="hl">Export YAML</span>]
223223
&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;&#9472;
224-
<span class="hl">Left panel</span> &#9474; <span class="hl">Right panel</span>: [COMMANDS] [TABLE]
224+
<span class="hl">Left panel</span> &#9474; <span class="hl">Right panel</span>: [COMMANDS] [TABLE] [<span class="hl">Reset</span>]
225225
&#9474;
226226
Experiment &#9474; Commands: Command card editor
227227
Arena + Rig &#9474; Table: Editable spreadsheet view
@@ -343,7 +343,7 @@ <h2>Walkthrough: create an optomotor protocol</h2>
343343

344344
<h2>Importing an existing protocol</h2>
345345

346-
<p>Click <strong>Import YAML</strong> in the top bar and select any v2 protocol <code>.yaml</code> file. The editor populates with all settings, conditions, plugins, and phases. You can modify and re-export.</p>
346+
<p>Click <strong>Import YAML</strong> in the top bar and select any v2 protocol <code>.yaml</code> file. The editor populates with all settings, conditions, plugins, and phases. You can modify and re-export. <strong>Import is undoable</strong> &mdash; press <code>Ctrl+Z</code> to restore your previous experiment.</p>
347347

348348
<div class="tip-box">
349349
<strong>Try it:</strong> Import one of the example protocols from the maDisplayTools repository, such as <code>full_experiment_test.yaml</code> (9 conditions with camera + backlight plugins) to see a fully populated experiment.
@@ -374,12 +374,23 @@ <h2>Timeline controls</h2>
374374
<li><code>Fit</code> scales the timeline to fit the window</li>
375375
</ul>
376376

377+
<h2>Undo, redo, and reset</h2>
378+
379+
<p>Every edit is tracked in an undo history (up to 50 steps). Use <strong>Undo</strong> / <strong>Redo</strong> in the top bar, or the keyboard shortcuts below.</p>
380+
<ul class="key-list">
381+
<li><strong>Undo / Redo buttons</strong> &mdash; in the top bar, disabled when the stack is empty</li>
382+
<li><strong>Reset button</strong> &mdash; red button in the tab bar (right of Commands / Table). Clears all conditions, phases, and plugins back to defaults. <em>Settings</em> (name, author, arena, rig path) are kept. A confirmation dialog appears first. Reset also clears the undo/redo history.</li>
383+
</ul>
384+
377385
<h2>Keyboard shortcuts</h2>
378386

379387
<ul class="key-list">
388+
<li><code>Ctrl+Z</code> / <code>Cmd+Z</code> Undo last edit (when not typing in a field)</li>
389+
<li><code>Ctrl+Y</code> / <code>Ctrl+Shift+Z</code> Redo</li>
380390
<li><code>Ctrl+E</code> Export YAML</li>
381391
<li><code>Delete</code> Remove selected condition (when not typing in a field)</li>
382392
</ul>
393+
<p class="hint">Inside a text input, Ctrl+Z uses the browser's native undo (reverts the last keystroke within that field).</p>
383394

384395
<h2>Key concepts</h2>
385396

@@ -399,7 +410,7 @@ <h3>Commands</h3>
399410

400411
<h3>Plugins</h3>
401412
<p><strong>LED Backlight</strong> (LEDControllerPlugin): control IR and visible LEDs behind arena panels. Commands: setIRLEDPower, setRedLEDPower, setGreenLEDPower, setBlueLEDPower, turnOnLED, turnOffLED, setVisibleBacklightsOff.</p>
402-
<p><strong>BIAS Camera</strong> (BiasPlugin): video recording and timestamps. Commands: startRecording, stopRecording, startPreview, stopCapture, getTimestamp, disconnect.</p>
413+
<p><strong>BIAS Camera</strong> (BiasPlugin): video recording and timestamps. Commands: connect (manual connection with optional ip/port/config_file), startRecording, stopRecording, startPreview, stopCapture, getTimestamp, disconnect.</p>
403414
<p class="hint">Enable plugins in the left panel to make their commands available in the Add Command dropdown.</p>
404415

405416
<h3>Phases</h3>

0 commit comments

Comments
 (0)