@davmash/bygone 0.9.7 → 0.10.0

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 (68) hide show
  1. package/CHANGELOG.md +30 -1
  2. package/README.md +74 -1
  3. package/cli/commandSpec.js +2 -0
  4. package/cli/completions.js +3 -3
  5. package/cli/present.js +28 -10
  6. package/cli/tour.js +22 -1
  7. package/cli/tourExport.js +147 -0
  8. package/cli/tourFile.js +109 -4
  9. package/cli/tourHistory.js +31 -1
  10. package/completions/_bygone +1 -1
  11. package/completions/bygone +1 -1
  12. package/completions/bygone.fish +1 -1
  13. package/docs/change-tour-format.md +86 -67
  14. package/docs/explore.md +14 -3
  15. package/docs/generating-change-tours.md +84 -46
  16. package/docs/present.md +103 -14
  17. package/docs/product-surface.md +19 -8
  18. package/docs/sharing-tours.md +95 -0
  19. package/docs/visual-walkthrough/README.md +89 -0
  20. package/docs/visual-walkthrough/build-tour.mjs +54 -0
  21. package/docs/visual-walkthrough/capture-desktop.cjs +42 -0
  22. package/docs/visual-walkthrough/capture-desktop.mjs +21 -0
  23. package/docs/visual-walkthrough/captures.md +49 -0
  24. package/docs/visual-walkthrough/create-demo.mjs +57 -0
  25. package/docs/visual-walkthrough/deconstructed-demo.bygone +100 -0
  26. package/docs/visual-walkthrough/images/01-two-files.png +0 -0
  27. package/docs/visual-walkthrough/images/02-many-panels.png +0 -0
  28. package/docs/visual-walkthrough/images/03-directories.png +0 -0
  29. package/docs/visual-walkthrough/images/04-search.png +0 -0
  30. package/docs/visual-walkthrough/images/05-repository-history.png +0 -0
  31. package/docs/visual-walkthrough/images/06-file-history.png +0 -0
  32. package/docs/visual-walkthrough/images/07-branch-review.png +0 -0
  33. package/docs/visual-walkthrough/images/08-tour-reader.png +0 -0
  34. package/docs/visual-walkthrough/images/09-focused-step.png +0 -0
  35. package/docs/visual-walkthrough/images/10-deconstructed.png +0 -0
  36. package/docs/visual-walkthrough/images/11-exploration.png +0 -0
  37. package/docs/visual-walkthrough/images/12-authoring.png +0 -0
  38. package/docs/visual-walkthrough/images/13-export.png +0 -0
  39. package/docs/visual-walkthrough/images/14-vscode.png +0 -0
  40. package/docs/visual-walkthrough/images/15-cli.png +0 -0
  41. package/docs/visual-walkthrough/narrative.md +134 -0
  42. package/docs/visual-walkthrough/outline.md +52 -0
  43. package/docs/visual-walkthrough/walkthrough.bygone +340 -0
  44. package/docs/walkthrough.md +6 -101
  45. package/examples/bygone-history.bygone +11 -44
  46. package/examples/marker-focus.bygone +116 -0
  47. package/examples/navigation-lab.bygone.yaml +401 -336
  48. package/examples/tour-orientation.bygone +349 -0
  49. package/media/diff.worker.js +13 -3
  50. package/media/webview.css +1 -1
  51. package/media/webview.js +394 -319
  52. package/out/changeTour.js +865 -397
  53. package/out/deepLink.js +167 -0
  54. package/out/historyDirectory.js +66 -0
  55. package/out/standalone-main.js +20515 -16822
  56. package/out/tourCoverage.js +850 -386
  57. package/out/tourDocument.js +97 -0
  58. package/package.json +1 -1
  59. package/schemas/change-tour-source.schema.json +91 -64
  60. package/skills/pr-tour-guide/SKILL.md +144 -128
  61. package/skills/pr-tour-guide/references/expectations-and-feedback.md +57 -0
  62. package/standalone/index.html +10 -25
  63. package/web/export-bootstrap.js +62 -0
  64. package/web/export-licenses.txt +78 -0
  65. package/web/export-runtime.json +12 -0
  66. package/web/index.html +54 -47
  67. package/web/presenter.css +337 -176
  68. package/web/web-host.js +239 -137
@@ -1,420 +1,485 @@
1
- version: 3
2
- title: Navigation lab
1
+ version: 5
2
+ title: Explore a tour without losing your place
3
3
  windowTitle: Bygone navigation lab
4
+ opening:
5
+ title: Leave step 3. Come back to step 3.
6
+ summary: >-
7
+ You pause at a code step to read the chapter overview. Returning should bring you back to that
8
+ step, with its code still in view. Two Bygone commits address those two needs: one remembers the
9
+ return destination; the next prevents layout changes from disturbing it. We’ll follow the saved
10
+ position, then the scroll guard. This tour examines an earlier viewer implementation.
11
+ conclusion:
12
+ title: A saved step also needs stable code focus
13
+ summary: >-
14
+ Opening an overview keeps the selected step; returning resumes it before advancing. The URL
15
+ preserves both choices across reload. Separately, the scroll guard prevents layout-only
16
+ notifications from invoking synchronization. The source explains the return path, and callback
17
+ tests check the guard. Neither demonstrates the complete interaction: refresh, return, and
18
+ resize still need a browser check.
4
19
  range:
5
20
  base: 1f8fdc07d56fc7a0e50dcab0383a63159c77178c
6
21
  head: 901a193203e4840dbf6e06c6a273fac7f2d713bd
7
22
  anchors:
8
- path-host:
9
- file: web/index.html
10
- revision: head
11
- contains: <nav id="tour-reading-path" class="tour-reading-path" aria-label="Reading hierarchy"></nav>
12
- path-levels:
13
- file: web/host.js
14
- revision: head
15
- contains: " if (tour.scenes.length > 1) levels.push(['tour', tour.title]);\n if (tour.chapters.length\
16
- \ > 1 && chapter && (chapter.sceneIds.length > 1 || state.narrativeParent === 'chapter')) levels.push(['chapter',\
17
- \ chapter.title]);\n levels.push(['scene', scene.title]);\n if (hasStep) levels.push(['step',\
18
- \ `Step ${state.activeStepIndex + 1}`]);"
19
23
  path-children:
20
24
  file: web/host.js
21
25
  revision: head
22
- contains: " children.append(readingButton(item.title, `Read chapter: ${item.title}`,\
23
- \ () => {\n if (!item.sceneIds.includes(scene.id)) showTourScene(first, 0,\
24
- \ { userNavigation: true, showIntro: true });\n setNarrativeView(item.sceneIds.length\
25
- \ > 1 ? 'chapter' : 'scene');\n }));"
26
+ contains: |2-
27
+ children.append(readingButton(item.title, `Read chapter: ${item.title}`, () => {
28
+ if (!item.sceneIds.includes(scene.id)) showTourScene(first, 0, { userNavigation: true, showIntro: true });
29
+ setNarrativeView(item.sceneIds.length > 1 ? 'chapter' : 'scene');
30
+ }));
26
31
  remember-step:
27
32
  file: web/host.js
28
33
  revision: head
29
- contains: " if (step) parameters.set('step', step.id);\n else parameters.delete('step');\n\
30
- \ if (state.narrativeParent) parameters.set('view', state.narrativeParent);\n else\
31
- \ if (step && state.sceneIntroVisible) parameters.set('view', 'overview');\n else parameters.delete('view');"
34
+ contains: |2-
35
+ if (step) parameters.set('step', step.id);
36
+ else parameters.delete('step');
37
+ if (state.narrativeParent) parameters.set('view', state.narrativeParent);
38
+ else if (step && state.sceneIntroVisible) parameters.set('view', 'overview');
39
+ else parameters.delete('view');
32
40
  resume-parent:
33
41
  file: web/host.js
34
42
  revision: head
35
- contains: " if (direction === 1 && state.narrativeParent) {\n showTourScene(state.activeSceneIndex,\
36
- \ state.activeStepIndex, { userNavigation: true, showIntro: false });\n return true;\n\
37
- \ }"
43
+ contains: |2-
44
+ if (direction === 1 && state.narrativeParent) {
45
+ showTourScene(state.activeSceneIndex, state.activeStepIndex, { userNavigation: true, showIntro: false });
46
+ return true;
47
+ }
38
48
  restore-parent:
39
49
  file: web/host.js
40
50
  revision: head
41
- contains: ' if ([''tour'', ''chapter''].includes(parameters.get(''view''))) setNarrativeView(parameters.get(''view''));'
51
+ contains: |2-
52
+ const requestedPosition = resolveTourPosition(
53
+ state.tour.scenes,
54
+ parameters.get('scene'),
55
+ parameters.get('step')
56
+ );
57
+ showTourScene(requestedPosition.sceneIndex, requestedPosition.stepIndex, {
58
+ showIntro: parameters.get('view') === 'overview' || !parameters.get('step')
59
+ });
60
+ if (['tour', 'chapter'].includes(parameters.get('view'))) setNarrativeView(parameters.get('view'));
42
61
  ignore-layout:
43
62
  file: media/script.js
44
63
  revision: head
45
- contains: " if (suppressEditorEvents || (!event.scrollTopChanged && !event.scrollLeftChanged))\
46
- \ {\n connectorController.scheduleDrawConnections();\n return;\n }"
47
- keep-sync:
48
- file: media/script.js
49
- revision: head
50
- contains: " if (editorMode === MODE_MULTI_WAY) {\n synchronizeMultiScroll(editor);\n\
51
- \ } else {\n synchronizeEditorScroll(editor);\n }"
64
+ contains: |2-
65
+ if (suppressEditorEvents || (!event.scrollTopChanged && !event.scrollLeftChanged)) {
66
+ connectorController.scheduleDrawConnections();
67
+ return;
68
+ }
52
69
  width-test:
53
70
  file: test/runTests.js
54
71
  revision: head
55
- contains: " assert.deepEqual(\n invokeScrollHandler({ scrollTopChanged: false, scrollLeftChanged:\
56
- \ false, scrollWidthChanged: true }),\n ['draw']\n );"
57
- vertical-test:
72
+ contains: |2-
73
+ assert.deepEqual(
74
+ invokeScrollHandler({ scrollTopChanged: false, scrollLeftChanged: false, scrollWidthChanged: true }),
75
+ ['draw']
76
+ );
77
+ real-scroll-tests:
58
78
  file: test/runTests.js
59
79
  revision: head
60
- contains: " assert.deepEqual(\n invokeScrollHandler({ scrollTopChanged: true, scrollLeftChanged:\
61
- \ false }),\n ['two-way-scroll', 'draw']\n );"
62
- horizontal-test:
63
- file: test/runTests.js
80
+ contains: |2-
81
+ assert.deepEqual(
82
+ invokeScrollHandler({ scrollTopChanged: true, scrollLeftChanged: false }),
83
+ ['two-way-scroll', 'draw']
84
+ );
85
+ assert.deepEqual(
86
+ invokeScrollHandler({ scrollTopChanged: false, scrollLeftChanged: true }, 'multi-way'),
87
+ ['multi-scroll', 'draw']
88
+ );
89
+ parent-view:
90
+ file: web/host.js
64
91
  revision: head
65
- contains: " assert.deepEqual(\n invokeScrollHandler({ scrollTopChanged: false, scrollLeftChanged:\
66
- \ true }, 'multi-way'),\n ['multi-scroll', 'draw']\n );"
92
+ contains: |2-
93
+ if (view === 'tour' || view === 'chapter') {
94
+ state.narrativeParent = view;
95
+ renderNarrativeViewControls();
96
+ renderTourProgress();
97
+ updateTourLocationUrl();
98
+ } else {
67
99
  connections: []
68
100
  chapters:
69
- - id: reading
70
- title: Reading levels
71
- scenes:
72
- - id: reading-path
73
- overview:
74
- kind: directory-diff
75
- title: Explore the reading path
76
- summary: The directory comparison shows the combined changes across this scene’s constructed stages. Open a file to inspect it, then select Overview above the diff to return; Start steps follows the explanation. Use the breadcrumb above this text to move through Tour, Chapter, Scene, and Step. The sidebar
77
- provides a second route to the same content.
78
- bullets: []
79
- tags:
80
- - navigation-demo
81
- takeaway: Mode chooses the representation of the change; the breadcrumb chooses your reading depth
82
- within it.
83
- steps:
84
- - id: path-host
85
- title: Keep navigation beside narration
86
- body: The reading path occupies the same toolbar as narration, so moving up a level does not require
87
- opening another panel. Try hiding narration to give the path more room.
88
- focus: path-host
89
- - id: path-levels
90
- title: Show levels with useful choices
91
- body: This tour has two chapters with two scenes each, so every parent level appears. A smaller
92
- tour omits levels that add no navigation choice.
93
- focus: path-levels
94
- - id: path-children
95
- title: Let a parent show its children
96
- body: Select the chapter title above to see its scenes, or select the tour title to see both chapters.
97
- These buttons enter the selected chapter while keeping the current scene when it already belongs
98
- there.
99
- focus: path-children
100
- kind: deconstructed-diff
101
- base: 1f8fdc07d56fc7a0e50dcab0383a63159c77178c
102
- target: 901a193203e4840dbf6e06c6a273fac7f2d713bd
103
- stack:
104
- - id: before
105
- ref: 1f8fdc07d56fc7a0e50dcab0383a63159c77178c
106
- label: Before hierarchy
107
- - id: hierarchy
108
- ref: a50c2a6f58a2dfd7f85039105a27e4b92b98a3f7
109
- label: Hierarchy added
110
- - id: marker
111
- ref: 901a193203e4840dbf6e06c6a273fac7f2d713bd
112
- label: Marker fix added
113
- stages:
114
- - id: surface
115
- title: Place the reading controls
116
- narration: Add the breadcrumb, parent container, child list, and their styling. These are synthetic
117
- cumulative panels, not historical commits.
118
- changes:
119
- - file: web/index.html
120
- hunks:
121
- - hunk-2828c9627055
122
- - hunk-68a3bdc9f262
123
- - hunk-ad7073e10ed7
124
- - file: web/presenter.css
125
- hunks:
126
- - hunk-3d4093808d4b
127
- - id: navigation
128
- title: Connect parents and return positions
129
- narration: Wire the hierarchy to the selected scene and step, then document the reading behavior.
130
- changes:
131
- - file: docs/present.md
132
- hunks:
133
- - hunk-5b7f86aadb64
134
- - hunk-635769fc5c13
135
- - hunk-d3f94ec64c1f
136
- - file: web/host.js
137
- hunks:
138
- - hunk-3bd48ca387ae
139
- - hunk-069a2fee2f36
140
- - hunk-e7def68037d5
141
- - hunk-755dbc1b8067
142
- - hunk-82249952520f
143
- - hunk-db24a55e418e
144
- - hunk-87209fb2e340
145
- - hunk-5ebccafb6522
146
- - hunk-b62a3aedf12b
147
- - hunk-50d651bf7762
148
- - hunk-3a1c863cc48a
149
- - hunk-1d2fb5f32ab9
150
- - hunk-df6ed3ebba70
151
- - hunk-5106426d3c27
152
- - hunk-8d0ffe62e5b7
153
- - hunk-fc04b2890333
154
- - id: focus
155
- title: Protect the code marker
156
- narration: Ignore layout-only scroll events so revealing a marker is not undone by panel resizing.
157
- changes:
158
- - file: media/script.js
159
- hunks:
160
- - hunk-636df0304da5
161
- - id: proof
162
- title: Check scrolling behavior
163
- narration: Test that width-only changes redraw connectors while actual scrolling still synchronizes
164
- editors.
165
- changes:
166
- - file: test/runTests.js
167
- hunks:
168
- - hunk-acbf72ffb0da
169
- - hunk-c6c53c72b8b1
170
- - id: return-position
171
- title: Return without losing your place
172
- summary: Move to a later step, select its scene or chapter in the breadcrumb, then use Resume. Refresh
173
- the parent view to exercise the saved URL position.
174
- bullets: []
175
- tags:
176
- - navigation-demo
177
- takeaway: The reading level and the return step are separate pieces of state.
178
- steps:
179
- - id: remember-step
180
- title: Keep your step ready to resume
181
- body: Selecting a parent keeps your current step ready to resume. The URL preserves the step and
182
- selected reading level, so refreshing restores both.
183
- focus: remember-step
184
- - id: resume-parent
185
- title: Resume from a parent
186
- body: Next from a parent returns to the remembered step instead of advancing past it. The button
187
- label becomes Resume to make that behavior explicit.
188
- focus: resume-parent
189
- - id: restore-parent
190
- title: Restore the parent after refresh
191
- body: Loading the URL restores the selected tour or chapter view after establishing the saved scene
192
- and step. Try refreshing while viewing this chapter.
193
- focus: restore-parent
194
- - id: evidence
195
- title: Code focus
196
- scenes:
197
- - id: marker-focus
198
- title: Keep the marker in view
199
- summary: Panel layout changes can emit scroll events without a scroll-position change. The renderer
200
- must not treat those events as reader navigation.
201
- bullets: []
202
- tags:
203
- - navigation-demo
204
- takeaway: The fix filters layout noise without disabling synchronized scrolling.
205
- steps:
206
- - id: ignore-layout
207
- title: Ignore extent-only scroll events
208
- body: The guard exits when neither vertical nor horizontal position changed. A panel-width change
209
- therefore cannot synchronize an old position back into the focused editor.
210
- focus: ignore-layout
211
- - id: keep-sync
212
- title: Continue synchronizing real scrolling
213
- body: After the guard, actual scroll events still dispatch to the appropriate two-panel or multi-panel
214
- synchronization path.
215
- focus: keep-sync
216
- - id: scroll-proof
217
- title: Inspect the regression checks
218
- summary: These tests invoke the renderer scroll callback with different event shapes. Use the Files
219
- section to explore the complete change set, then return to the tour.
220
- bullets: []
221
- tags:
222
- - navigation-demo
223
- takeaway: Use the mode buttons to open either tour or live History. To inspect the final result without narration,
224
- open Compare and choose Final diff.
225
- steps:
226
- - id: width-test
227
- title: A width change only redraws
228
- body: A width-only event must draw connectors without requesting either kind of synchronized scroll.
229
- focus: width-test
230
- - id: vertical-test
231
- title: Vertical scrolling still synchronizes
232
- body: A real vertical movement in a two-panel comparison still synchronizes and redraws.
233
- focus: vertical-test
234
- - id: horizontal-test
235
- title: Multi-panel scrolling still synchronizes
236
- body: A horizontal movement in multi-panel mode reaches the multi-panel synchronizer. This is callback
237
- coverage; the panel-switch landing was also checked manually in the browser.
238
- focus: horizontal-test
239
-
101
+ - id: reading
102
+ title: Remember where to return
103
+ scenes:
104
+ - id: reading-path
105
+ title: An overview changes the view, not the selected step
106
+ summary: >-
107
+ Suppose you are reading step 3 and open its chapter overview. The viewer needs to change
108
+ what it explains while keeping step 3 as the return destination. We’ll trace that
109
+ separation, then the boundary: choosing a different chapter deliberately selects a new
110
+ destination.
111
+ bullets: []
112
+ tags:
113
+ - navigation-demo
114
+ takeaway: >-
115
+ Opening the current chapter preserves its selection; choosing another chapter starts
116
+ there.
117
+ steps:
118
+ - id: parent-view
119
+ title: Change the view without resetting the selection
120
+ body: >-
121
+ Opening a tour or chapter overview sets narrativeParent and redraws the navigation.
122
+ This branch does not change the active scene or step. Step 3 can therefore remain
123
+ selected while the reader sees its broader context.
124
+ focus: parent-view
125
+ - id: path-children
126
+ title: A different chapter needs a different destination
127
+ body: >-
128
+ The chapter button checks whether it contains the current scene. If it does, the
129
+ selection stays put. If it does not, the button selects that chapter’s first scene at
130
+ step 1 before opening its overview. Preserving your place applies to stepping outward;
131
+ it does not prevent deliberate navigation elsewhere.
132
+ focus: path-children
133
+ - id: return-position
134
+ title: Return to the saved step—even after a reload
135
+ summary: >-
136
+ The selection survives in memory, but it also has to survive returning and reloading.
137
+ Still in the same comparison, follow the two values into the URL, the forward action, and
138
+ startup. Together they explain why an overview need not become a dead end.
139
+ bullets: []
140
+ tags:
141
+ - navigation-demo
142
+ takeaway: Save both the step to resume and the view to show; restoring either alone is insufficient.
143
+ steps:
144
+ - id: remember-step
145
+ title: "Save two facts: where to return, and what to show"
146
+ body: >-
147
+ The URL keeps the selected step while view records the open overview. In our example,
148
+ it needs both “step 3” and “chapter view.” Saving only the chapter would lose the
149
+ return destination; saving only the step would reopen code instead of the overview.
150
+ focus: remember-step
151
+ - id: resume-parent
152
+ title: Resume step 3 before considering step 4
153
+ body: >-
154
+ The forward action checks for a parent view before normal advancement. It opens the
155
+ saved scene and step, then returns immediately. From the chapter overview, that means
156
+ resume step 3—not skip ahead to step 4.
157
+ focus: resume-parent
158
+ - id: restore-parent
159
+ title: Reload the destination, then reopen the overview
160
+ body: >-
161
+ Startup first resolves the scene and step from the URL and selects them. Only then
162
+ does it apply the parent view. That order restores a return destination underneath the
163
+ overview. The code establishes this sequence; a reload-and-return interaction remains
164
+ the browser check.
165
+ focus: restore-parent
166
+ - id: evidence
167
+ title: Keep that code in view
168
+ scenes:
169
+ - id: marker-focus
170
+ title: A resize notification is not necessarily a scroll
171
+ summary: >-
172
+ A saved step is not enough if resizing the panels moves its highlighted code off-screen.
173
+ Monaco can report a changed scrollable area even when the scroll position stays put. The
174
+ old handler could synchronize that notification. This scene follows the new guard and
175
+ checks that real scrolling still works.
176
+ bullets: []
177
+ tags:
178
+ - navigation-demo
179
+ takeaway: >-
180
+ A change in scrollable size needs a redraw; an unsuppressed position change still needs
181
+ synchronization.
182
+ steps:
183
+ - id: ignore-layout
184
+ title: Redraw layout changes without moving the other panels
185
+ body: >-
186
+ The new condition asks whether either scroll position changed. If neither did, it
187
+ redraws the lines connecting matching code and returns before synchronization.
188
+ Existing event suppression also takes this early exit. Unsuppressed movement still
189
+ reaches the synchronizer, so fixing the resize case does not require disabling linked
190
+ scrolling.
191
+ focus: ignore-layout
192
+ - id: width-test
193
+ title: A wider scrollable area must not move the code
194
+ body: >-
195
+ The test changes the scrollable width while leaving both position flags false. It
196
+ expects only a connector redraw. Calling a synchronizer here would reopen the route by
197
+ which layout changes can disturb a code reveal.
198
+ focus: width-test
199
+ - id: real-scroll-tests
200
+ title: Real movement must still keep panels together
201
+ body: >-
202
+ Skipping synchronization for every scroll event would pass the previous check but
203
+ break linked scrolling. These assertions rule that out: vertical movement in two-panel
204
+ mode and horizontal movement in multi-panel mode each synchronize, then redraw. Panel
205
+ mode selects the synchronizer; the direction of movement does not. These tests check
206
+ callback routing, not on-screen marker visibility.
207
+ focus: real-scroll-tests
240
208
  tours:
241
209
  historical:
210
+ opening:
211
+ title: Leave step 3. Come back to step 3.
212
+ summary: >-
213
+ You pause at a code step to read the chapter overview. Returning should bring you back to
214
+ that step, with its code still in view. Two Bygone commits address those two needs: one
215
+ remembers the return destination; the next prevents layout changes from disturbing it. We’ll
216
+ follow the saved position, then the scroll guard. This tour examines an earlier viewer
217
+ implementation.
218
+ conclusion:
219
+ title: A saved step also needs stable code focus
220
+ summary: >-
221
+ Opening an overview keeps the selected step; returning resumes it before advancing. The URL
222
+ preserves both choices across reload. Separately, the scroll guard prevents layout-only
223
+ notifications from invoking synchronization. The source explains the return path, and
224
+ callback tests check the guard. Neither demonstrates the complete interaction: refresh,
225
+ return, and resize still need a browser check.
242
226
  chapters:
243
- - id: historical-reading
244
- title: The hierarchy commit
227
+ - id: reading
228
+ title: Remember where to return
245
229
  scenes:
246
- - id: hierarchy-revision
247
- overview:
248
- kind: directory-diff
249
- path: web
250
- comparison:
251
- from: before
252
- to: hierarchy
253
- kind: stacked-diff
254
- title: Add reading levels in a real commit
230
+ - id: reading-path
231
+ title: An overview changes the view, not the selected step
255
232
  summary: >-
256
- This overview compares the web directory before and after the hierarchy commit. Open a file without leaving the overview, or start the steps to see the real revision panels. Its changes to markup, styling, and
257
- navigation landed together; they are split into conceptual stages only in
258
- Deconstructed tour.
233
+ Suppose you are reading step 3 and open its chapter overview. The viewer needs to
234
+ change what it explains while keeping step 3 as the return destination. We’ll trace
235
+ that separation, then the boundary: choosing a different chapter deliberately selects
236
+ a new destination.
259
237
  bullets: []
260
238
  tags:
261
- - real-revisions
262
239
  - navigation-demo
263
240
  takeaway: >-
264
- Historical tour keeps the real commit boundaries, even when one commit contains
265
- several concepts.
266
- stack:
267
- - id: before
268
- ref: 1f8fdc07d56fc7a0e50dcab0383a63159c77178c
269
- label: Before hierarchy
270
- - id: hierarchy
271
- ref: a50c2a6f58a2dfd7f85039105a27e4b92b98a3f7
272
- label: Hierarchy added
273
- - id: marker
274
- ref: 901a193203e4840dbf6e06c6a273fac7f2d713bd
275
- label: Marker fix added
276
- files:
277
- - web/index.html
278
- - web/host.js
279
- - web/presenter.css
241
+ Opening the current chapter preserves its selection; choosing another chapter starts
242
+ there.
280
243
  steps:
281
- - id: historical-markup
282
- title: Give the hierarchy a home
244
+ - id: parent-view
245
+ title: Change the view without resetting the selection
283
246
  body: >-
284
- The hierarchy commit adds the reading path and parent-view containers to the
285
- presenter. This is the same committed markup shown in the synthetic surface stage,
286
- now in its original revision context.
287
- file: web/index.html
288
- pair:
289
- - before
290
- - hierarchy
291
- side: right
292
- - id: historical-behavior
293
- title: Connect the reading levels
294
- body: >-
295
- The same commit wires parent navigation and return positions in the host. The
296
- hierarchy was introduced as a coherent UI change, rather than as separate Git
297
- commits for each explanation stage.
298
- file: web/host.js
299
- pair:
300
- - before
301
- - hierarchy
302
- side: right
303
- - id: historical-style
304
- title: Style the parent choices
247
+ Opening a tour or chapter overview sets narrativeParent and redraws the
248
+ navigation. This branch does not change the active scene or step. Step 3 can
249
+ therefore remain selected while the reader sees its broader context.
250
+ focus: parent-view
251
+ - id: path-children
252
+ title: A different chapter needs a different destination
305
253
  body: >-
306
- The reading controls and child choices receive their layout in this commit as
307
- well. Change modes to Deconstructed to inspect those changes in a different
308
- teaching order.
309
- file: web/presenter.css
310
- pair:
311
- - before
312
- - hierarchy
313
- side: right
314
- - id: historical-return
315
- title: Return without losing your place
254
+ The chapter button checks whether it contains the current scene. If it does, the
255
+ selection stays put. If it does not, the button selects that chapter’s first scene
256
+ at step 1 before opening its overview. Preserving your place applies to stepping
257
+ outward; it does not prevent deliberate navigation elsewhere.
258
+ focus: path-children
259
+ - id: return-position
260
+ title: Return to the saved step—even after a reload
316
261
  summary: >-
317
- Move to a later step, select its scene or chapter in the breadcrumb, then use Resume.
318
- Refresh the parent view to exercise the saved URL position.
262
+ The selection survives in memory, but it also has to survive returning and reloading.
263
+ Still in the same comparison, follow the two values into the URL, the forward action,
264
+ and startup. Together they explain why an overview need not become a dead end.
319
265
  bullets: []
320
266
  tags:
321
267
  - navigation-demo
322
- takeaway: The reading level and the return step are separate pieces of state.
268
+ takeaway: >-
269
+ Save both the step to resume and the view to show; restoring either alone is
270
+ insufficient.
323
271
  steps:
324
272
  - id: remember-step
325
- title: Keep your step ready to resume
273
+ title: "Save two facts: where to return, and what to show"
326
274
  body: >-
327
- Selecting a parent keeps your current step ready to resume. The URL preserves the step and
328
- selected reading level, so refreshing restores both.
275
+ The URL keeps the selected step while view records the open overview. In our
276
+ example, it needs both “step 3” and “chapter view.” Saving only the chapter would
277
+ lose the return destination; saving only the step would reopen code instead of the
278
+ overview.
329
279
  focus: remember-step
330
280
  - id: resume-parent
331
- title: Resume from a parent
281
+ title: Resume step 3 before considering step 4
332
282
  body: >-
333
- Next from a parent returns to the remembered step instead of advancing past it.
334
- The button label becomes Resume to make that behavior explicit.
283
+ The forward action checks for a parent view before normal advancement. It opens
284
+ the saved scene and step, then returns immediately. From the chapter overview,
285
+ that means resume step 3—not skip ahead to step 4.
335
286
  focus: resume-parent
336
287
  - id: restore-parent
337
- title: Restore the parent after refresh
288
+ title: Reload the destination, then reopen the overview
338
289
  body: >-
339
- Loading the URL restores the selected tour or chapter view after establishing the
340
- saved scene and step. Try refreshing while viewing this chapter.
290
+ Startup first resolves the scene and step from the URL and selects them. Only then
291
+ does it apply the parent view. That order restores a return destination underneath
292
+ the overview. The code establishes this sequence; a reload-and-return interaction
293
+ remains the browser check.
341
294
  focus: restore-parent
342
- - id: historical-correction
343
- title: The follow-up correction
295
+ - id: evidence
296
+ title: Keep that code in view
344
297
  scenes:
345
- - id: marker-revision
346
- kind: stacked-diff
347
- title: Fix marker focus after the hierarchy change
298
+ - id: marker-focus
299
+ title: A resize notification is not necessarily a scroll
348
300
  summary: >-
349
- The last panel is a separate follow-up commit. It changes scroll-event handling and
350
- adds regression assertions; it does not rewrite the earlier hierarchy implementation.
301
+ Now isolate the second commit: navigation is already in place, but a panel resize can
302
+ still disturb the highlighted code. Monaco reports changes in scrollable size through
303
+ its scroll callback, even without a position change. The guard separates those
304
+ notifications from movement; the tests check both paths.
351
305
  bullets: []
352
306
  tags:
353
- - real-revisions
354
307
  - navigation-demo
355
- takeaway: The later commit repairs code focus while retaining the new reading hierarchy.
356
- stack:
357
- - id: before
358
- ref: 1f8fdc07d56fc7a0e50dcab0383a63159c77178c
359
- label: Before hierarchy
360
- - id: hierarchy
361
- ref: a50c2a6f58a2dfd7f85039105a27e4b92b98a3f7
362
- label: Hierarchy added
363
- - id: marker
364
- ref: 901a193203e4840dbf6e06c6a273fac7f2d713bd
365
- label: Marker fix added
366
- files:
367
- - media/script.js
368
- - test/runTests.js
308
+ takeaway: >-
309
+ A change in scrollable size needs a redraw; an unsuppressed position change still
310
+ needs synchronization.
369
311
  steps:
370
312
  - id: historical-marker
371
- title: Ignore layout-only scroll events
313
+ title: Redraw layout changes without moving the other panels
372
314
  body: >-
373
- Panel resizing can emit scroll events without moving either scroll position. This
374
- revision redraws connections and returns early for those events, preserving the
375
- tour marker focus.
315
+ The new condition asks whether either scroll position changed. If neither did, it
316
+ redraws the lines connecting matching code and returns before synchronization.
317
+ Existing event suppression also takes this early exit. Unsuppressed movement still
318
+ reaches the synchronizer, so fixing the resize case does not require disabling
319
+ linked scrolling.
376
320
  file: media/script.js
377
321
  pair:
378
322
  - hierarchy
379
323
  - marker
380
324
  side: right
381
325
  - id: historical-proof
382
- title: Keep actual scrolling synchronized
326
+ title: Reject layout-only events without breaking linked scrolling
383
327
  body: >-
384
- The follow-up includes assertions for width-only events and real vertical or
385
- horizontal scrolling. These checks distinguish a layout update from a user scroll
386
- that must still synchronize editors.
328
+ In the same commit comparison, this file checks both sides of the guard. A
329
+ width-only event must call draw alone. Vertical movement in two-panel mode and
330
+ horizontal movement in multi-panel mode must each synchronize, then draw. The
331
+ positive cases matter: disabling all synchronization would also pass the
332
+ width-only check. These assertions verify routing, not visible marker behavior.
387
333
  file: test/runTests.js
388
334
  pair:
389
335
  - hierarchy
390
336
  - marker
391
337
  side: right
392
- - id: historical-checks
393
- title: Inspect the regression checks
338
+ kind: stacked-diff
339
+ stack:
340
+ - id: before
341
+ ref: 1f8fdc07d56fc7a0e50dcab0383a63159c77178c
342
+ label: Before hierarchy
343
+ - id: hierarchy
344
+ ref: a50c2a6f58a2dfd7f85039105a27e4b92b98a3f7
345
+ label: Hierarchy added
346
+ - id: marker
347
+ ref: 901a193203e4840dbf6e06c6a273fac7f2d713bd
348
+ label: Marker fix added
349
+ files:
350
+ - media/script.js
351
+ - test/runTests.js
352
+ deconstructed:
353
+ opening:
354
+ title: Leave step 3. Come back to step 3.
355
+ summary: >-
356
+ You pause at a code step to read the chapter overview. Returning should bring you back to
357
+ that step, with its code still in view. Two Bygone commits address those two needs: one
358
+ remembers the return destination; the next prevents layout changes from disturbing it. We’ll
359
+ follow the saved position, then the scroll guard. This tour examines an earlier viewer
360
+ implementation.
361
+ conclusion:
362
+ title: A saved step also needs stable code focus
363
+ summary: >-
364
+ Opening an overview keeps the selected step; returning resumes it before advancing. The URL
365
+ preserves both choices across reload. Separately, the scroll guard prevents layout-only
366
+ notifications from invoking synchronization. The source explains the return path, and
367
+ callback tests check the guard. Neither demonstrates the complete interaction: refresh,
368
+ return, and resize still need a browser check.
369
+ chapters:
370
+ - id: reading
371
+ title: Remember where to return
372
+ scenes:
373
+ - id: reading-path
374
+ title: Make the overview reachable, then make the return reliable
375
+ summary: >-
376
+ Leave step 3 for its chapter overview: the controls expose the overview, while
377
+ separate view and selection state preserve the way back. Returning resumes step 3
378
+ before advancing. Reload restores the selection before reopening the overview;
379
+ choosing another chapter deliberately selects a new destination. These two constructed
380
+ stages separate controls from behavior, not commit history. The next scene returns to
381
+ committed evidence for the scroll guard.
382
+ bullets: []
383
+ tags:
384
+ - navigation-demo
385
+ takeaway: >-
386
+ The controls let the reader step outward; separate view and selection state make the
387
+ trip reversible.
388
+ kind: deconstructed-diff
389
+ base: 1f8fdc07d56fc7a0e50dcab0383a63159c77178c
390
+ target: 901a193203e4840dbf6e06c6a273fac7f2d713bd
391
+ stages:
392
+ - id: surface
393
+ title: Give the reader a way to step outward
394
+ narration: >-
395
+ The markup and styling provide parent navigation and destination lists. The next
396
+ stage supplies the behavior that preserves the return destination.
397
+ changes:
398
+ - file: web/index.html
399
+ hunks:
400
+ - hunk-2828c9627055
401
+ - hunk-68a3bdc9f262
402
+ - hunk-ad7073e10ed7
403
+ - file: web/presenter.css
404
+ hunks:
405
+ - hunk-3d4093808d4b
406
+ - id: navigation
407
+ title: Keep the selected step underneath the overview
408
+ narration: >-
409
+ The parent view changes independently of the selected step. Saving both lets
410
+ return and reload preserve the reader’s place.
411
+ changes:
412
+ - file: docs/present.md
413
+ hunks:
414
+ - hunk-5b7f86aadb64
415
+ - hunk-635769fc5c13
416
+ - hunk-d3f94ec64c1f
417
+ - file: web/host.js
418
+ hunks:
419
+ - hunk-3bd48ca387ae
420
+ - hunk-069a2fee2f36
421
+ - hunk-e7def68037d5
422
+ - hunk-755dbc1b8067
423
+ - hunk-82249952520f
424
+ - hunk-db24a55e418e
425
+ - hunk-87209fb2e340
426
+ - hunk-5ebccafb6522
427
+ - hunk-b62a3aedf12b
428
+ - hunk-50d651bf7762
429
+ - hunk-3a1c863cc48a
430
+ - hunk-1d2fb5f32ab9
431
+ - hunk-df6ed3ebba70
432
+ - hunk-5106426d3c27
433
+ - hunk-8d0ffe62e5b7
434
+ - hunk-fc04b2890333
435
+ exclusions:
436
+ - file: media/script.js
437
+ reason: >-
438
+ The marker correction is explained with exact committed evidence in the following
439
+ scene.
440
+ - file: test/runTests.js
441
+ reason: >-
442
+ The scroll callback assertions are explained beside the guard in the following
443
+ scene.
444
+ - id: evidence
445
+ title: Keep that code in view
446
+ scenes:
447
+ - id: marker-focus
448
+ title: A resize notification is not necessarily a scroll
394
449
  summary: >-
395
- These tests invoke the renderer scroll callback with different event shapes. Use the
396
- Files section to explore the complete change set, then return to the tour.
450
+ A saved step is not enough if resizing the panels moves its highlighted code
451
+ off-screen. Monaco can report a changed scrollable area even when the scroll position
452
+ stays put. The old handler could synchronize that notification. This scene follows the
453
+ new guard and checks that real scrolling still works.
397
454
  bullets: []
398
455
  tags:
399
456
  - navigation-demo
400
457
  takeaway: >-
401
- Use the mode buttons to open either tour or live History. To inspect the final result without
402
- narration, open Compare and choose Final diff.
458
+ A change in scrollable size needs a redraw; an unsuppressed position change still
459
+ needs synchronization.
403
460
  steps:
461
+ - id: ignore-layout
462
+ title: Redraw layout changes without moving the other panels
463
+ body: >-
464
+ The new condition asks whether either scroll position changed. If neither did, it
465
+ redraws the lines connecting matching code and returns before synchronization.
466
+ Existing event suppression also takes this early exit. Unsuppressed movement still
467
+ reaches the synchronizer, so fixing the resize case does not require disabling
468
+ linked scrolling.
469
+ focus: ignore-layout
404
470
  - id: width-test
405
- title: A width change only redraws
471
+ title: A wider scrollable area must not move the code
406
472
  body: >-
407
- A width-only event must draw connectors without requesting either kind of
408
- synchronized scroll.
473
+ The test changes the scrollable width while leaving both position flags false. It
474
+ expects only a connector redraw. Calling a synchronizer here would reopen the
475
+ route by which layout changes can disturb a code reveal.
409
476
  focus: width-test
410
- - id: vertical-test
411
- title: Vertical scrolling still synchronizes
412
- body: A real vertical movement in a two-panel comparison still synchronizes and redraws.
413
- focus: vertical-test
414
- - id: horizontal-test
415
- title: Multi-panel scrolling still synchronizes
477
+ - id: real-scroll-tests
478
+ title: Real movement must still keep panels together
416
479
  body: >-
417
- A horizontal movement in multi-panel mode reaches the multi-panel synchronizer.
418
- This is callback coverage; the panel-switch landing was also checked manually in
419
- the browser.
420
- focus: horizontal-test
480
+ Skipping synchronization for every scroll event would pass the previous check but
481
+ break linked scrolling. These assertions rule that out: vertical movement in
482
+ two-panel mode and horizontal movement in multi-panel mode each synchronize, then
483
+ redraw. Panel mode selects the synchronizer; the direction of movement does not.
484
+ These tests check callback routing, not on-screen marker visibility.
485
+ focus: real-scroll-tests