@hraness/dawg 0.6.1 → 0.7.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 (253) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/DAWG.md +343 -116
  3. package/README.md +27 -25
  4. package/core/autotune.ts +1119 -0
  5. package/core/chords.ts +271 -23
  6. package/core/clips.ts +499 -0
  7. package/core/diff.ts +182 -104
  8. package/core/expression.ts +15 -0
  9. package/core/fx.ts +99 -29
  10. package/core/instruments.ts +19 -0
  11. package/core/keys.ts +3 -3
  12. package/core/loop.ts +5 -0
  13. package/core/lyrics.ts +297 -0
  14. package/core/master.ts +3 -3
  15. package/core/resonators.ts +16 -2
  16. package/core/routing.ts +165 -0
  17. package/core/score.ts +832 -13
  18. package/core/sdk/eval-child.ts +7 -2
  19. package/core/sdk/eval.ts +35 -6
  20. package/core/sdk/print.ts +276 -3
  21. package/core/sdk/sync-lyrics.ts +49 -0
  22. package/core/sdk/v1.ts +1849 -42
  23. package/core/sections.ts +292 -26
  24. package/core/sing.ts +815 -0
  25. package/core/style-provenance.ts +80 -0
  26. package/core/styles/africa-mena-southasia.ts +2893 -0
  27. package/core/styles/americas.ts +3810 -0
  28. package/core/styles/art.ts +4993 -0
  29. package/core/styles/base.ts +123 -0
  30. package/core/styles/cycles.ts +106 -0
  31. package/core/styles/electronic.ts +2723 -0
  32. package/core/styles/europe-asia-pacific.ts +2838 -0
  33. package/core/styles/excerpt.ts +29 -0
  34. package/core/styles/gamelan.ts +283 -0
  35. package/core/styles/generate.ts +2199 -0
  36. package/core/styles/index.ts +515 -0
  37. package/core/styles/parts.ts +106 -0
  38. package/core/styles/pop.ts +3189 -0
  39. package/core/styles/rock.ts +2993 -0
  40. package/core/styles/roots.ts +4175 -0
  41. package/core/styles/schema.ts +429 -0
  42. package/core/styles/taxonomy.ts +940 -0
  43. package/core/styles/validate.ts +528 -0
  44. package/core/tempo.ts +32 -2
  45. package/core/tuning.ts +19 -3
  46. package/core/vocoder.ts +524 -0
  47. package/guides/agent.md +29 -0
  48. package/guides/arrange.md +30 -0
  49. package/guides/audition.md +20 -14
  50. package/guides/automation.md +12 -7
  51. package/guides/chords.md +15 -15
  52. package/guides/effects.md +17 -16
  53. package/guides/faders.md +20 -16
  54. package/guides/files.md +13 -9
  55. package/guides/getting-started.md +15 -11
  56. package/guides/keys.md +19 -15
  57. package/guides/media.md +17 -12
  58. package/guides/mix.md +12 -6
  59. package/guides/music.md +23 -8
  60. package/guides/notes.md +15 -9
  61. package/guides/performance.md +15 -13
  62. package/guides/play.md +21 -13
  63. package/guides/project.md +25 -8
  64. package/guides/providers.md +20 -14
  65. package/guides/resample.md +15 -9
  66. package/guides/rhythm.md +17 -13
  67. package/guides/sessions.md +17 -7
  68. package/guides/show-me.md +31 -0
  69. package/guides/sound.md +25 -9
  70. package/guides/sounds.md +15 -13
  71. package/guides/styles.md +31 -0
  72. package/guides/tempo.md +15 -10
  73. package/guides/tracks.md +15 -10
  74. package/guides/tuning.md +32 -0
  75. package/guides/voice.md +31 -0
  76. package/guides/web-search.md +18 -8
  77. package/native/prebuilt/darwin-arm64/libdawg_sink.dylib +0 -0
  78. package/native/prebuilt/darwin-x64/libdawg_sink.dylib +0 -0
  79. package/native/prebuilt/linux-arm64/libdawg_sink.so +0 -0
  80. package/native/prebuilt/linux-x64/libdawg_sink.so +0 -0
  81. package/native/prebuilt/manifest.json +21 -0
  82. package/package.json +5 -2
  83. package/src/agent/agent.ts +126 -14
  84. package/src/agent/calibration-tools.ts +53 -0
  85. package/src/agent/clip-tools.ts +453 -0
  86. package/src/agent/command-agent.ts +369 -0
  87. package/src/agent/drum-tools.ts +2 -2
  88. package/src/agent/expression-tools.ts +1 -1
  89. package/src/agent/gateway.ts +246 -60
  90. package/src/agent/models.ts +53 -12
  91. package/src/agent/ops.ts +12 -1
  92. package/src/agent/pack-tools.ts +1 -1
  93. package/src/agent/planner.ts +13 -0
  94. package/src/agent/portable-schema.ts +80 -0
  95. package/src/agent/preview-tool.ts +4 -1
  96. package/src/agent/provider.ts +22 -8
  97. package/src/agent/rhythm-tools.ts +1 -1
  98. package/src/agent/section-tools.ts +1 -1
  99. package/src/agent/show-me.ts +497 -0
  100. package/src/agent/steer.ts +15 -0
  101. package/src/agent/style-tools.ts +217 -0
  102. package/src/agent/tool-error.ts +12 -0
  103. package/src/agent/tools.ts +108 -23
  104. package/src/agent/usage.ts +2 -2
  105. package/src/agent/voice-tools.ts +925 -0
  106. package/src/agent/xcb-agent.ts +11 -7
  107. package/src/argv.ts +38 -0
  108. package/src/audio/analysis.ts +253 -0
  109. package/src/audio/arrange.ts +37 -3
  110. package/src/audio/autotune-engine.ts +101 -0
  111. package/src/audio/autotune.ts +640 -0
  112. package/src/audio/clips.ts +240 -0
  113. package/src/audio/doctor.ts +86 -0
  114. package/src/audio/dsp/bandbank.ts +138 -0
  115. package/src/audio/dsp/envelope.ts +10 -0
  116. package/src/audio/dsp/follow.ts +120 -0
  117. package/src/audio/dsp/formant.ts +427 -0
  118. package/src/audio/dsp/glottal.ts +243 -0
  119. package/src/audio/dsp/interp.ts +7 -2
  120. package/src/audio/dsp/lpc.ts +50 -0
  121. package/src/audio/dsp/periodicity.ts +59 -0
  122. package/src/audio/dsp/pitch.ts +995 -0
  123. package/src/audio/dsp/psola.ts +199 -0
  124. package/src/audio/effects/chain.ts +3 -1
  125. package/src/audio/effects/common.ts +43 -0
  126. package/src/audio/effects/convolution.ts +7 -4
  127. package/src/audio/effects/filter.ts +48 -69
  128. package/src/audio/effects/formant.ts +263 -0
  129. package/src/audio/engine.ts +160 -28
  130. package/src/audio/fit.ts +35 -3
  131. package/src/audio/instrument-check.ts +59 -43
  132. package/src/audio/instruments.ts +4 -0
  133. package/src/audio/keys/calibration.ts +56 -0
  134. package/src/audio/keys/electric.ts +8 -1
  135. package/src/audio/keys/engine.ts +13 -1
  136. package/src/audio/keys/piano.ts +22 -2
  137. package/src/audio/kits.ts +135 -6
  138. package/src/audio/live.ts +114 -20
  139. package/src/audio/native.ts +615 -0
  140. package/src/audio/preview.ts +30 -2
  141. package/src/audio/render-worker.ts +2 -0
  142. package/src/audio/renderer.ts +2 -0
  143. package/src/audio/resample.ts +2 -1
  144. package/src/audio/sampler.ts +85 -4
  145. package/src/audio/samples.ts +20 -2
  146. package/src/audio/sing/analysis.ts +193 -0
  147. package/src/audio/sing/engine.ts +949 -0
  148. package/src/audio/strings/bow.ts +48 -5
  149. package/src/audio/strings/engine.ts +8 -2
  150. package/src/audio/synth/oscillators.ts +31 -21
  151. package/src/audio/synth/voice.ts +34 -1
  152. package/src/audio/vocoder/bank.ts +314 -0
  153. package/src/audio/vocoder/carrier.ts +165 -0
  154. package/src/audio/vocoder/control.ts +68 -0
  155. package/src/audio/vocoder/detect.ts +50 -0
  156. package/src/audio/vocoder/index.ts +304 -0
  157. package/src/audio/vocoder/talkbox.ts +143 -0
  158. package/src/audio/wav.ts +500 -77
  159. package/src/audio/winds/engine.ts +5 -1
  160. package/src/audio/winds/trim.ts +28 -4
  161. package/src/audio/winds/trims1.ts +297 -0
  162. package/src/audio/winds/voice.ts +15 -2
  163. package/src/auth/cli.ts +38 -36
  164. package/src/auth/credentials.ts +30 -1
  165. package/src/auth/login.ts +15 -9
  166. package/src/auth/tui.ts +19 -10
  167. package/src/commands/arrange.ts +44 -29
  168. package/src/commands/autotune.ts +421 -0
  169. package/src/commands/calibration.ts +74 -0
  170. package/src/commands/clips.ts +887 -0
  171. package/src/commands/drums.ts +3 -2
  172. package/src/commands/edit.ts +11 -4
  173. package/src/commands/expression.ts +1 -1
  174. package/src/commands/formant.ts +221 -0
  175. package/src/commands/fx.ts +101 -32
  176. package/src/commands/grammar.ts +558 -0
  177. package/src/commands/help.ts +610 -380
  178. package/src/commands/history.ts +18 -0
  179. package/src/commands/keys.ts +8 -8
  180. package/src/commands/modal.ts +1 -1
  181. package/src/commands/music.ts +1 -1
  182. package/src/commands/nearest.ts +53 -0
  183. package/src/commands/pack.ts +9 -2
  184. package/src/commands/param-range.ts +56 -0
  185. package/src/commands/parses.ts +130 -0
  186. package/src/commands/progression.ts +170 -0
  187. package/src/commands/rhythm.ts +3 -0
  188. package/src/commands/rig.ts +3 -24
  189. package/src/commands/sing.ts +478 -0
  190. package/src/commands/strum.ts +13 -1
  191. package/src/commands/style.ts +415 -0
  192. package/src/commands/time.ts +6 -3
  193. package/src/commands/tuning.ts +3 -3
  194. package/src/commands/vocal-pitch.ts +616 -0
  195. package/src/commands/vocal.ts +147 -0
  196. package/src/commands/vocoder.ts +627 -0
  197. package/src/commands/wind.ts +2 -2
  198. package/src/fs/durable.ts +50 -0
  199. package/src/lang/glossary.ts +493 -0
  200. package/src/launch-args.ts +163 -0
  201. package/src/main.ts +1397 -253
  202. package/src/media/cli.ts +20 -3
  203. package/src/media/import.ts +3 -1
  204. package/src/project/check.ts +21 -2
  205. package/src/project/clip-pins.ts +72 -0
  206. package/src/project/init.ts +23 -8
  207. package/src/project/sync.ts +418 -86
  208. package/src/render.ts +20 -1
  209. package/src/session/daemon.ts +3 -0
  210. package/src/session/meta.ts +14 -0
  211. package/src/session/origin.ts +154 -0
  212. package/src/session/port.ts +22 -4
  213. package/src/session/presence.ts +34 -4
  214. package/src/session/protocol.ts +5 -1
  215. package/src/session/rebase.ts +18 -5
  216. package/src/session/receipt.ts +258 -0
  217. package/src/session/store.ts +65 -43
  218. package/src/tui/arrange-menu.ts +65 -31
  219. package/src/tui/audition.ts +1 -1
  220. package/src/tui/euclid.ts +18 -13
  221. package/src/tui/fader.ts +228 -41
  222. package/src/tui/granular-menu.ts +2 -4
  223. package/src/tui/menu-clips.ts +297 -0
  224. package/src/tui/menu-time.ts +20 -13
  225. package/src/tui/menu-voice.ts +405 -0
  226. package/src/tui/menu.ts +759 -177
  227. package/src/tui/modal-menu.ts +6 -6
  228. package/src/tui/performance-menu.ts +5 -2
  229. package/src/tui/play-chords.ts +4 -2
  230. package/src/tui/play-mode.ts +15 -1
  231. package/src/tui/play-session.ts +47 -7
  232. package/src/tui/sing-menu.ts +278 -0
  233. package/src/tui/style-menu.ts +104 -0
  234. package/src/tui/vocoder-menu.ts +244 -0
  235. package/src/tui/wind-menu.ts +3 -3
  236. package/src/version.ts +8 -0
  237. package/src/web/fetch.ts +115 -29
  238. package/tui/activity.ts +180 -9
  239. package/tui/app.ts +274 -40
  240. package/tui/clip-row.ts +132 -0
  241. package/tui/delight.ts +144 -0
  242. package/tui/drawer.ts +70 -22
  243. package/tui/frame-gate.ts +76 -0
  244. package/tui/grammar.ts +112 -63
  245. package/tui/guide.ts +42 -4
  246. package/tui/highway.ts +269 -25
  247. package/tui/hints.ts +192 -0
  248. package/tui/input.ts +60 -9
  249. package/tui/keys.ts +1 -1
  250. package/tui/play-strip.ts +68 -14
  251. package/tui/prompt.ts +1 -1
  252. package/tui/screen.ts +144 -14
  253. package/tui/theme.ts +27 -0
package/tui/grammar.ts CHANGED
@@ -14,6 +14,52 @@
14
14
  */
15
15
  import { displayWidth } from "./text.ts";
16
16
 
17
+ // ── key sets: the one definition every screen imports ─────────────────
18
+
19
+ type Keys = ReadonlySet<string>;
20
+ const keys = (...values: string[]): Keys => Object.freeze(new Set(values));
21
+
22
+ /** The raw arrow sequences, for code that synthesizes a key press. */
23
+ export const ARROW_UP = "\u001b[A";
24
+ export const ARROW_DOWN = "\u001b[B";
25
+ /** ↑ k: move up (a row, a voice, a param). */
26
+ export const KEY_UP = keys(ARROW_UP, "\u001bOA", "k");
27
+ /** ↓ j: move down. */
28
+ export const KEY_DOWN = keys(ARROW_DOWN, "\u001bOB", "j");
29
+ /** ← h - _: back on a row that is not a value; adjust down on a value. */
30
+ export const KEY_LEFT = keys("\u001b[D", "\u001bOD", "h", "-", "_");
31
+ /** → l + =: go in or apply; adjust up on a value. */
32
+ export const KEY_RIGHT = keys("\u001b[C", "\u001bOC", "l", "+", "=");
33
+ /** ← h only: the keys that go back from a row that is not a value. */
34
+ export const KEY_BACK = keys("\u001b[D", "\u001bOD", "h");
35
+ /** → l only: the keys that go into a row that is not a value. */
36
+ export const KEY_FORWARD = keys("\u001b[C", "\u001bOC", "l");
37
+ /** Tab: the next field (fader, rhythm editor, forms). */
38
+ export const KEY_TAB = keys("\t");
39
+ /** Shift-tab: the previous field. */
40
+ export const KEY_BACKTAB = keys("\u001b[Z");
41
+ /** Enter: open or confirm, everywhere. */
42
+ export const KEY_ENTER = keys("\r", "\n");
43
+ export const KEY_BACKSPACE = keys("\u007f", "\b");
44
+ /** x d Delete: reset a value (delete an automation point, turn a row off). */
45
+ export const KEY_RESET = keys("x", "d", "\u001b[3~");
46
+ /** Shift-← → { }: a coarse step. */
47
+ export const KEY_COARSE_LEFT = keys("\u001b[1;2D", "{");
48
+ export const KEY_COARSE_RIGHT = keys("\u001b[1;2C", "}");
49
+ /** [ ] alt-← →: a fine step (skips detents). */
50
+ export const KEY_FINE_LEFT = keys("\u001b[1;3D", "\u001b[1;5D", "\u001bb", "[");
51
+ export const KEY_FINE_RIGHT = keys(
52
+ "\u001b[1;3C",
53
+ "\u001b[1;5C",
54
+ "\u001bf",
55
+ "]",
56
+ );
57
+ export const KEY_PAGE_UP = keys("\u001b[5~");
58
+ export const KEY_PAGE_DOWN = keys("\u001b[6~");
59
+ export const KEY_HOME = keys("\u001b[H", "\u001bOH", "\u001b[1~");
60
+ export const KEY_END = keys("\u001b[F", "\u001bOF", "\u001b[4~");
61
+ export const KEY_ESC = "\u001b";
62
+
17
63
  /** A `key action` pair for the `?` panel. */
18
64
  export type KeyRow = readonly [keys: string, action: string];
19
65
  export type KeySection = Readonly<{ title: string; rows: readonly KeyRow[] }>;
@@ -75,40 +121,47 @@ export const HINTS = {
75
121
  " ↑↓ hear · enter keep · space loop · a A/B · c mix · / filter · esc back · ? keys ",
76
122
  filtering: " type to filter · enter choose · esc clear · ? keys ",
77
123
  menu: " ↑↓ move · enter open · / filter · esc back · ? keys ",
78
- value: " ←→ adjust · enter type · x reset · esc back · ? keys ",
124
+ value: " ←→ adjust · enter open · 0-9 type · x reset · esc back · ? keys ",
79
125
  point: " ←→ adjust · enter type · x delete · esc back · ? keys ",
80
126
  action: " ↑↓ move · enter apply · / filter · esc back · ? keys ",
81
- typing: " type a value · enter apply · esc cancel ",
127
+ typing: " type a value · enter apply · esc clear ",
82
128
  euclid:
83
- " ↑↓ voice · ←→ adjust · tab field · space loop · x off · esc back · ? keys ",
129
+ " ↑↓ drum · ←→ adjust · tab field · space loop · x off · esc back · ? keys ",
84
130
  text: " ↑↓ scroll · pgup pgdn page · esc back · ? keys ",
85
131
  log: " ↑↓ scroll · / filter · esc back · ? keys ",
86
- keys: " any key closes ",
132
+ keys: " esc or ? closes ",
87
133
  } as const;
88
134
 
89
135
  // ── the `?` panel ─────────────────────────────────────────────────────
136
+ //
137
+ // Each screen lists every key once: a key that means different things on
138
+ // different rows says so on its one line.
90
139
 
91
140
  /** The audition loop's keys, shared by the menu and the rhythm editor. */
92
- const AUDITIONING: readonly KeySection[] = [
93
- {
94
- title: "auditioning",
95
- rows: [
96
- ["space", "loop the focused track · again stops"],
97
- ["c", "solo ↔ in context (the whole mix)"],
98
- ["a", "A/B: committed ↔ staged"],
99
- ["enter", "keep staged changes (one undo step)"],
100
- ["esc", "revert staged changes"],
101
- ],
102
- },
103
- {
104
- title: "every change",
105
- rows: [
106
- ["", "while looping, stages; otherwise runs the command shown"],
107
- ["ctrl-z", "undoes it"],
108
- ],
109
- },
141
+ const AUDITION_ROWS: readonly KeyRow[] = [
142
+ ["space", "loop the track · again stops"],
143
+ ["a", "A/B: committed ↔ staged"],
144
+ ["c", "solo ↔ in context (the whole mix)"],
145
+ ["ctrl-z", "undo a kept change"],
110
146
  ];
111
147
 
148
+ /** The ctrl-k menu roots, in order (src/tui/menu.ts builds them). */
149
+ export const MENU_ROOTS = Object.freeze([
150
+ "Sound",
151
+ "Voice",
152
+ "Effects",
153
+ "Rhythm",
154
+ "Chords and key",
155
+ "Mix",
156
+ "Arrange",
157
+ "Project",
158
+ ]);
159
+
160
+ /** Keys that close the `?` panel; every other key is ignored while open. */
161
+ export function closesKeys(value: string): boolean {
162
+ return value === KEY_ESC || value === "?";
163
+ }
164
+
112
165
  const LIST: readonly KeyRow[] = [
113
166
  ["↑ ↓ j k", "move"],
114
167
  ["pgup pgdn", "page"],
@@ -122,12 +175,9 @@ export const KEYS = {
122
175
  {
123
176
  title: "start here",
124
177
  rows: [
125
- ["type + enter", "ask for a change in plain words, or a command"],
126
- ["ctrl-p", "play notes on the keyboard (chords: q)"],
127
- [
128
- "ctrl-k",
129
- "menu: sound, effects, rhythm, chords, performance, mix, master",
130
- ],
178
+ ["type", "ask in plain words, or type a command"],
179
+ ["ctrl-p", "play mode: notes on the keyboard (chords: q)"],
180
+ ["ctrl-k", `menu: ${MENU_ROOTS.length} sections · /menu <topic>`],
131
181
  ["space", "play / pause (empty prompt)"],
132
182
  ["/help", "what dawg can do · /help <topic> for more"],
133
183
  ],
@@ -137,10 +187,11 @@ export const KEYS = {
137
187
  rows: [
138
188
  ["enter", "send"],
139
189
  ["shift-enter ctrl-j", "new line"],
140
- ["alt-enter ctrl-q", "queue after the current request"],
190
+ ["alt-enter", "send next, after the current request"],
191
+ ["ctrl-q", "switch now/next (what enter does)"],
141
192
  ["ctrl-z ctrl-y", "undo / redo"],
142
193
  ["ctrl-o", "transcript"],
143
- ["esc", "cancel the agent · close a panel"],
194
+ ["esc", "cancel the agent · back from a panel"],
144
195
  ["ctrl-c", "quit"],
145
196
  ],
146
197
  },
@@ -150,7 +201,7 @@ export const KEYS = {
150
201
  ["click ▶/⏸ BPM", "play / pause"],
151
202
  ["click track name", "track list (click one to focus it)"],
152
203
  ["click model", "model picker"],
153
- ["volume · fx filter", "a bare param opens its fader drawer"],
204
+ ["click volume · fx filter", "a bare param opens its fader drawer"],
154
205
  ],
155
206
  },
156
207
  ],
@@ -184,20 +235,18 @@ export const KEYS = {
184
235
  title: "menu",
185
236
  rows: [
186
237
  ["↑ ↓ j k", "move"],
187
- ["enter → l", "open a section"],
188
- ["esc ← h", "back one level"],
238
+ [
239
+ "enter",
240
+ "open · run · value: fader or list · staged: keep (one undo)",
241
+ ],
242
+ ["→ l", "go in · run an action · on a value: adjust up"],
243
+ ["← h", "back one level · on a value: adjust down"],
244
+ ["- +", "adjust a value"],
245
+ ["esc", "revert staged changes, else back (a filter clears first)"],
189
246
  ["/", "filter this level"],
190
- ],
191
- },
192
- {
193
- title: "on a value",
194
- rows: [
195
- ["← → h l - +", "adjust"],
196
- ["0-9", "type a value, enter applies"],
197
- ["enter", "type a value · pick from a list"],
198
- ["space", "toggle on/off (elsewhere: hear the track)"],
199
- ["x delete", "reset to default (deletes an automation point)"],
200
- ["enter (number)", "open its fader drawer"],
247
+ ["0-9 .", "type a value, enter applies"],
248
+ ["x d delete", "reset to default (deletes an automation point)"],
249
+ ...AUDITION_ROWS,
201
250
  ],
202
251
  },
203
252
  {
@@ -207,33 +256,32 @@ export const KEYS = {
207
256
  ["wheel", "move through the list"],
208
257
  ],
209
258
  },
210
- ...AUDITIONING,
211
259
  ],
212
260
  fader: [
213
261
  {
214
262
  title: "fader drawer",
215
263
  rows: [
216
- ["← → - +", "step the value (staged, heard on the loop)"],
217
- ["shift-← → { }", "coarse step (five)"],
218
- ["[ ] alt-← →", "fine step (a tenth)"],
264
+ ["← → h l - +", "step (tempo, meter, bars apply at once)"],
265
+ ["shift-← shift-→ { }", "coarse step (five)"],
266
+ ["[ ] alt-← alt-→", "fine step (a tenth; skips detents)"],
219
267
  ["pgup pgdn", "big step (twenty)"],
220
268
  ["home end", "minimum / maximum"],
221
269
  ["0-9 .", "type an exact value, enter sets it"],
222
- ["0 d", "back to the default"],
223
- ["↑ ↓ tab shift-tab", "next / previous param of this device"],
224
- ["enter", "keep every staged change (one undo step)"],
270
+ ["x d delete", "back to the default"],
271
+ ["↑ ↓ j k tab shift-tab", "previous / next param of this device"],
272
+ ["enter", "keep every staged change (one undo)"],
225
273
  ["esc", "revert and close"],
226
- ["space a c", "loop · A/B · solo ↔ in context"],
274
+ ...AUDITION_ROWS,
227
275
  ],
228
276
  },
229
277
  {
230
278
  title: "mouse",
231
279
  rows: [
232
280
  ["click [−] [+]", "step (shift-click: coarse)"],
233
- ["click / drag bar", "set the value there"],
281
+ ["click or drag the bar", "set the value there"],
234
282
  ["wheel on a fader", "step it (shift: coarse)"],
235
283
  ["click an option", "choose it"],
236
- ["[keep] [revert]", "same as enter / esc"],
284
+ ["click enter keep · esc revert", "same as the keys"],
237
285
  ],
238
286
  },
239
287
  ],
@@ -241,23 +289,24 @@ export const KEYS = {
241
289
  {
242
290
  title: "rhythm editor",
243
291
  rows: [
244
- ["↑ ↓ j k", "voice"],
292
+ ["↑ ↓ j k", "drum"],
245
293
  ["← → h l - +", "adjust the field"],
246
294
  ["tab shift-tab ] [", "next / previous field"],
247
295
  ["0-9", "type a value, enter applies"],
248
- ["enter", "add a row (or type a value)"],
249
- ["x", "turn the row off"],
296
+ ["enter", "add a row (or type a value) · staged: keep"],
297
+ ["x d delete", "turn the row off"],
250
298
  ["f", "freeze into plain hits"],
251
- ["esc", "back"],
299
+ ["esc", "revert staged changes, else back"],
300
+ ...AUDITION_ROWS,
252
301
  ],
253
302
  },
254
- ...AUDITIONING,
255
303
  ],
256
304
  text: [
257
305
  {
258
306
  title: "panel",
307
+ // No j k: the prompt stays live under a panel, so letters type there.
259
308
  rows: [
260
- ["↑ ↓ j k", "scroll"],
309
+ ["↑ ↓", "scroll"],
261
310
  ["pgup pgdn home end", "page"],
262
311
  ["esc", "close"],
263
312
  ],
@@ -295,9 +344,10 @@ export const KEYS = {
295
344
  ["w e t y u o p", "black keys"],
296
345
  ["z x", "octave down / up"],
297
346
  ["c v", "velocity down / up"],
298
- ["shift · tab", "sustain while held · sustain latch"],
347
+ ["shift", "sustain while held"],
348
+ ["tab", "sustain latch (play mode only)"],
299
349
  ["space", "play / pause (with count-in)"],
300
- ["r · R", "record · record replacing"],
350
+ ["r R", "record · record replacing"],
301
351
  ["m", "metronome click"],
302
352
  ["i", "scale degrees ⇄ chromatic (home row in key)"],
303
353
  ["q", "chord mode: auto ⇄ manual"],
@@ -318,7 +368,6 @@ export const KEYS = {
318
368
  ["9", "next perform mode (block, strum, arp…)"],
319
369
  ["b", "next bass mode"],
320
370
  ["n", "play the suggested next chord"],
321
- ["q", "auto (chords fit the key) ⇄ manual"],
322
371
  ],
323
372
  },
324
373
  ],
package/tui/guide.ts CHANGED
@@ -7,6 +7,7 @@
7
7
  * page ↑↓ (j k) scroll · pgup pgdn home end · ← h esc back to the tree
8
8
  */
9
9
  import type { Guide } from "../guides/index.ts";
10
+ import { resolveTopic } from "../src/lang/glossary.ts";
10
11
  import { overlayKey } from "./keys.ts";
11
12
  import { displayWidth } from "./text.ts";
12
13
 
@@ -77,6 +78,36 @@ export function wrapRows(rows: readonly GuideRow[], width: number): GuideRow[] {
77
78
  return out;
78
79
  }
79
80
 
81
+ /**
82
+ * Words that open a child guide rather than their topic's root guide
83
+ * (`/guide expression` is the performance guide, not Sound).
84
+ */
85
+ export const GUIDE_ALIASES: Readonly<Record<string, string>> = {
86
+ expression: "performance",
87
+ instrument: "sounds",
88
+ instruments: "sounds",
89
+ presets: "sounds",
90
+ samples: "media",
91
+ stems: "media",
92
+ grains: "resample",
93
+ granular: "resample",
94
+ scl: "tuning",
95
+ edo: "tuning",
96
+ meter: "tempo",
97
+ time: "tempo",
98
+ style: "styles",
99
+ sections: "music",
100
+ form: "music",
101
+ automate: "automation",
102
+ showme: "show-me",
103
+ model: "providers",
104
+ models: "providers",
105
+ search: "web-search",
106
+ web: "web-search",
107
+ mouse: "faders",
108
+ menu: "audition",
109
+ };
110
+
80
111
  export class GuideBrowser {
81
112
  readonly guides: readonly Guide[];
82
113
  /** Expanded parents in the tree. */
@@ -95,13 +126,20 @@ export class GuideBrowser {
95
126
  if (open) this.open(open);
96
127
  }
97
128
 
98
- /** Open a guide by id or title word (`/guide chords`); false if unknown. */
129
+ /**
130
+ * Open a guide by id, topic alias or title word (`/guide chords`,
131
+ * `/guide scale`, `/guide using`); false if unknown.
132
+ */
99
133
  open(name: string): boolean {
100
- const word = name.trim().toLowerCase();
134
+ const word = name.trim().toLowerCase().replace(/^\//, "");
135
+ const alias = GUIDE_ALIASES[word] ?? resolveTopic(word);
101
136
  const guide =
102
137
  this.guides.find((g) => g.id === word) ??
103
- this.guides.find((g) => g.title.toLowerCase().startsWith(word)) ??
104
- this.guides.find((g) => g.id.includes(word));
138
+ (alias ? this.guides.find((g) => g.id === alias) : undefined) ??
139
+ (word.length >= 3
140
+ ? (this.guides.find((g) => g.title.toLowerCase().startsWith(word)) ??
141
+ this.guides.find((g) => g.id.includes(word)))
142
+ : undefined);
105
143
  if (!guide) return false;
106
144
  for (let p = guide.parent; p; p = this.byId(p)?.parent)
107
145
  this.expanded.add(p);