-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.html
620 lines (617 loc) · 37.3 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
<!DOCTYPE html>
<html lang="en">
<head>
<title>Langton's Ant Music v2</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta property="og:site_name" content="Langton's Ant Music" />
<meta property="og:title" content="Langton's Ant Music" />
<meta property="og:description" content="Langton's Ant plays the drums!" />
<meta property="og:image" content="langton-150-icon.png" />
<meta property="og:type" content="page" />
<meta property="og:url" content="https://dragoncoder047.github.io/langton-music/index.html" />
<meta property="og:locale" content="America" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Langton's Ant Music" />
<meta name="twitter:description" content="Langton's Ant plays the drums!" />
<meta name="twitter:image" content="langton-150-icon.png" />
<link rel="stylesheet" href="style.css">
<link rel="manifest" href="app.webmanifest">
<link rel="apple-touch-icon" href="langton-150-icon.png">
<link rel="icon" href="langton-150-icon.png">
<script src="https://cdn.jsdelivr.net/npm/tone@14.7.77/build/Tone.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/ace-builds@1.10.0/src-noconflict/ace.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/seedrandom@3.0.5/seedrandom.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mousetrap@1.6.5/mousetrap.min.js"></script>
</head>
<body>
<main class="flex-column">
<div class="heading padding">Langton's Ant Music version 2</div>
<div class="flex-row padding">
<div class="expanding" id="statuswrapper"><output id="statusbar"></output></div>
<a href="#editor">Edit</a> -
<a href="#xml">Formatting</a> -
<a href="#help">Help</a> -
<a href="#kbd">Keyboard Shortcuts</a>
</div>
<div class="flex-row wrapping padding">
<div class="flex-row wrapping padding expanding">
<label>Step: <output id="stepnum"></output></label>
<label>Number of ants: <output id="antscount"></output></label>
</div>
<select id="actions">
<option value="">Actions...</option>
<option value="openclip">Open Clipboard</option>
<option value="savelocal">Save</option>
<option value="share">Share</option>
<option value="copy">Copy as XML</option>
<option value="bbcode">Copy as BBCode</option>
<option value="scrot">Screenshot</option>
</select>
</div>
<div class="flex-row wrapping padding">
<button id="startstop">Start</button>
<button id="step">Step</button>
<label> Speed: <input type="range" value="240" min="10" max="480" step="1"
id="speedslider"><input type="number" min="10" id="speedbox" value="240"></label>
<label> Mute sound <input type="checkbox" id="mutecheck"></label>
</div>
<div class="flex-row wrapping padding">
<button id="fit">Fit to Window</button>
<label><input type="checkbox" checked id="autofit">Autofit</label>
<span> -or- </span>
<label>Follow an ant: <select id="follow">
<option id="nofollow" value="">NONE</option>
</select></label>
</div>
<div class="flex-row wrapping padding">
<label>Tool: <select id="toolselect">
</select></label>
<div id="tooloption"></div>
</div>
<div class="flex-row expanding padding">
<canvas id="playfield"></canvas>
</div>
<div class="flex-row padding" id="debugbar"></div>
</main>
<div id="editor" class="popover">
<div class="flex-column">
<div class="flex-row">
<div id="dumpstatuswrapper" class="expanding padding"></div>
<div><a href="#">X</a></div>
</div>
<div class="flex-row"><button id="loadbtn">Load</button><button id="dumpbtn">Dump</button>
</div>
<div class="expanding">
<div id="textbox"></div>
</div>
<div class="padding flex-row distribute">
<a href="#xml">Formatting/syntax guide</a><a href="/langton-music/interpoltest.html"
target="_blank">Interpolator
test</a>
</div>
</div>
</div>
<div id="xml" class="popover">
<div class="flex-column">
<div class="flex-row">
<span class="expanding">
<h1>Langton-Music Format</h1>
</span>
<p style="text-align: right;"><a href="#">X</a></p>
</div>
<div class="scroller expanding">
<h2>Overview</h2>
<p>The format is based on XML.</p>
<p>The entire document is enclosed in <code><langton></code> tags.</p>
<p>Then there can be 4 things inside that:</p>
<ul>
<li><code><config></code> tags: for metadata/configuration values</li>
<li><code><breed></code> tags: Defining the ant breeds</li>
<li><code><ant></code> tags: instantiating (using) the ant</li>
<li><code><rle></code> tags: RLE data to specify the cells on the grid.</li>
</ul>
<p>Additionally, because it's XML, you can put comments anywhere you like by using
<code><!-- --></code>.
</p>
<h2>Header - <code><config></code> tags</h2>
<p>This is pretty simple. Each tag is formatted like this:
<code><config name="KEY">VALUE</config></code>
</p>
<h3>Supported Header Options</h3>
<table>
<thead>
<tr>
<th style="text-align:center">Option (<code>name</code> attribute)</th>
<th style="text-align:left">Function (content)</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center"><code>bpm</code></td>
<td style="text-align:left">Controls maximum beats per minute of playback.</td>
</tr>
<tr>
<td style="text-align:center"><code>stepCount</code></td>
<td style="text-align:left">Doesn't really do anything, it just changes the initial
step number from the default (zero) when you press LOAD. Useful for
restoring from a dump or save.</td>
</tr>
<tr>
<td style="text-align:center"><code>color<em>NN</em></code></td>
<td style="text-align:left">Fixes the color of the state <code><em>NN</em></code>
to be the color specified, and not use the random number generator
(although as of 2023-01-19 LAM uses a fixed seed so the colors should be
relatively predictable).</td>
</tr>
<tr>
<td style="text-align:center"><code>color_seed</code></td>
<td style="text-align:left">Seeds the random number generator to generate a
different sequence of colors for those not defined by <code><em>colorNN</em></code>
config tags.</td>
</tr>
<tr>
<td style="text-align:center"><code>#<em>(some name)</em></code></td>
<td style="text-align:left">An arbitrary interpolation value (see below).</td>
</tr>
<tr>
<td style="text-align:center"><code>title</code></td>
<td style="text-align:left">The name of the pattern (used in the media controls box).
If omitted it defaults to "Langton's Ant Music".</td>
</tr>
<tr>
<td style="text-align:center"><code>author</code></td>
<td style="text-align:left">The name of the person that created the pattern.
(Used to populate the "artist" field in the media controls.)</td>
</tr>
<tr>
<td style="text-align:center"><code>series</code></td>
<td style="text-align:left">A name for the "series" the pattern is in, maybe like
the type of ant or something. (Used to populate the "album" field in the
media controls.)</td>
</tr>
</tbody>
</table>
<h2>Ant Breeds - <code><breed></code> tag</h2>
<p>This is a little complicated. Let's start with an example, classic Langton's
Ant:</p>
<pre><code class="language-xml">
<breed species="Ant" name="langton">
<case cell="0">
<action>
<command name="put">1</command>
<command name="lt"></command>
<command name="fd"></command>
</action>
</case>
<case cell="1">
<action>
<command name="put">0</command>
<command name="rt"></command>
<command name="fd"></command>
</action>
</case>
</breed>
</code></pre>
<p>Each "breed" of ant is enclosed in <code><breed></code> tags. The
<code>species</code> attribute determines what commands are available, and the
<code>name</code> attribute gives the ant breed a name so it can be referred to
later on.
</p>
<p>Inside the <code><breed></code>, there are one or more
<code><case></code>s. The <code><case></code>s each have a
<code>cell</code> attribute and a <code>state</code> attribute that determines when
the case is applied - <code>state</code> is the <em>internal</em> state that the ant
is in, and <code>cell</code> is the <em>external</em> state of the cell the ant is
sitting on. Both must be numbers; and if <code>state</code> is omitted it defaults
to 1.
</p>
<p>If there is no case for a state:cell pair, the ant will halt and do nothing until
another ant comes and changes the cell. (Multiple ants can occupy the same cell, and
must do so if an ant is to be re-started in this manner, but if two "active"
ants run over each other, you can't control which ant executes its actions "first".)</p>
<p>Within the <code><case></code>s there are <code><action></code>s that
define groups of commands. Each action is queued, and only one action executes per
tick. Case lookup only occurs when the queue is exhausted. Within the action group,
all commands execute at once.</p>
<p>Each <code><command></code> has a <code>name</code> attribute that is the
command. In some cases the command needs an argument; this goes inside the tag.</p>
<p>Scroll to the bottom for the list of supported commands and species of ants.</p>
<h3>Interpolations</h3>
<p>Inside each <code><command></code>, the parameter can also include
interpolations.</p>
<p>There are two types of interpolations: fixed and expressions.</p>
<h4>Fixed Interpolations</h4>
<p>These look like <code>#xxx</code>, where <code>xxx</code> is a name. Some names are
provided by the ant, which take precedence; the rest are user-defined via
<code><config></code>s.
</p>
<table>
<thead>
<tr>
<th style="text-align:center">Fixed Interpolation Name</th>
<th style="text-align:left">Value</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center"><code>dir</code></td>
<td style="text-align:left">0, 1, 2, or 3 depending on the ant's direction.</td>
</tr>
<tr>
<td style="text-align:center"><code>state</code></td>
<td style="text-align:left">Whatever state the ant is in.</td>
</tr>
<tr>
<td style="text-align:center"><code><em>blah</em></code></td>
<td style="text-align:left">Whatever value <code>#<em>blah</em></code> is set to in a
<code><config></code>. (<code><em>blah</em></code> can be anything.)
</td>
</tr>
</tbody>
</table>
<h4>Expression Interpolations</h4>
<p>These are similar to fixed interpolations: They look like <code>#xxx;</code> - the
only difference is a semicolon at the end and the <code>xxx</code>'s are an
expression. Expressions are processed after fixed interpolations; so the former can
include the latter.</p>
<p>The expression language is a crude stack-based (postfix) language that is somewhat
like Befunge; it's not Turing-complete, but it should suffice. The
"returned value" is the top of the stack after the expression is executed.
</p>
<table>
<thead>
<tr>
<th style="text-align:center">Command/Token</th>
<th style="text-align:left">Function</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center"><code>0-9</code> number</td>
<td style="text-align:left">Pushes the arbitrary number to the stack; only integers are
supported.</td>
</tr>
<tr>
<td style="text-align:center"><code>`string`</code></td>
<td style="text-align:left">Pushes the arbitrary string between the backticks.</td>
</tr>
<tr>
<td style="text-align:center"><code>'</code></td>
<td style="text-align:left">No-op. Useful for separating numbers (the parser is greedy
so it needs a non-digit character to stop it).</td>
</tr>
<tr>
<td style="text-align:center"><code>\</code></td>
<td style="text-align:left">Swap top two items on the stack.</td>
</tr>
<tr>
<td style="text-align:center"><code>$</code></td>
<td style="text-align:left">Drops the top item.</td>
</tr>
<tr>
<td style="text-align:center"><code>:</code></td>
<td style="text-align:left">Duplicates the top item.</td>
</tr>
<tr>
<td style="text-align:center"><code>?</code></td>
<td style="text-align:left">Pushes a random integer from 0 to the top number minus 1.
</td>
</tr>
<tr>
<td style="text-align:center"><code>%</code></td>
<td style="text-align:left">Pushes second number mod top number.</td>
</tr>
<tr>
<td style="text-align:center"><code>*</code></td>
<td style="text-align:left">Pushes second number times top number.</td>
</tr>
<tr>
<td style="text-align:center"><code>/</code></td>
<td style="text-align:left">Pushes second number divided by top number.</td>
</tr>
<tr>
<td style="text-align:center"><code>+</code></td>
<td style="text-align:left">Pushes second number plus top number.</td>
</tr>
<tr>
<td style="text-align:center"><code>-</code></td>
<td style="text-align:left">Pushes second number minus top number.</td>
</tr>
<tr>
<td style="text-align:center"><code>~</code></td>
<td style="text-align:left">Pushes negation of top number. Shortcut for
<code>,0\-</code>.
</td>
</tr>
<tr>
<td style="text-align:center"><code>|</code></td>
<td style="text-align:left">Pushes second number bitwise or top number.</td>
</tr>
<tr>
<td style="text-align:center"><code>&</code></td>
<td style="text-align:left">Pushes second number bitwise and top number.</td>
</tr>
<tr>
<td style="text-align:center"><code>^</code></td>
<td style="text-align:left">Pushes second number bitwise xor top number.</td>
</tr>
<tr>
<td style="text-align:center"><code><</code></td>
<td style="text-align:left">Pushes true or false depending on if second number is less
than the top number.</td>
</tr>
<tr>
<td style="text-align:center"><code>></code></td>
<td style="text-align:left">Pushes true or false depending on if second number is
greater than the top number.</td>
</tr>
<tr>
<td style="text-align:center"><code>=</code></td>
<td style="text-align:left">Pushes true or false depending on if second number is equal
to the top number.</td>
</tr>
<tr>
<td style="text-align:center"><code>@</code></td>
<td style="text-align:left">Pushes the third number if the first is true, otherwise the
second.</td>
</tr>
</tbody>
</table>
<p>An (incomplete) test suite is available at <a
href="https://dragoncoder047.github.io/langton-music/interpoltest.html">https://dragoncoder047.github.io/langton-music/interpoltest.html</a>.
</p>
<h2>Actual Ants - <code><ant></code> tag</h2>
<p>Ants are simpler and do not have any contents.</p>
<p>A full <code><ant></code> looks like this:
<code><ant breed="langton" id="ant1" state="1" dir="1" x="0" y="0"></ant></code>.
</p>
<ul>
<li><code>breed</code> is the breed of ant, which references a
<code><breed></code> elsewhere.
</li>
<li><code>id</code> is the "name" of the ant as it appears in the
"Track Ant" pulldown menu. If this is not supplied. a random one will
be generated automatically.</li>
<li><code>state</code> is the initial state of the ant; if omitted it defaults to 1.
</li>
<li><code>dir</code> is the direction of the ant; it is 0, 1, 2, or 3.</li>
<li><code>x</code> and <code>y</code> are the position of the ant.</li>
</ul>
<h2>Cell Data - <code><rle></code> tag</h2>
<p>This is almost like Golly's RLE format, but it has some differences. First, there
is no <code>x = N, y = N, rule = N</code> header line per se. The metadata (x- and
y-offset) is stored in the <code>offsetx</code> and <code>offsety</code> attributes
of the <code><rle></code> tag, and default to 0 if omitted.</p>
<p>Otherwise this is just the same as Golly RLE format:</p>
<blockquote>
<p>For rules with more than two states, a "." represents a zero state;
states 1..24 are represented by "A".."X", states 25..48 by
"pA".."pX", states 49..72 by "qA".."qX",
and on up to states 241..255 represented by "yA".."yO".</p>
</blockquote>
<h2>Supported Ant Species and Commands</h2>
<h3><code>Ant</code> (base class for all)</h3>
<p>(Do note that the parenthesis notation here is used only to save space.
<code>foo(bar)</code> would really be written
<code><command name="foo">bar</command></code>.)
</p>
<table>
<thead>
<tr>
<th style="text-align:center">Command</th>
<th style="text-align:left">What it does</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center"><code>fd(num)</code>, <code>bk(num)</code></td>
<td style="text-align:left">Moves forward or that many cells. Defaults to 1 if argument
is omitted.</td>
</tr>
<tr>
<td style="text-align:center"><code>rt(num)</code>, <code>lt(num)</code></td>
<td style="text-align:left">Turn right or left that many steps (step = 90 degrees).
Defaults to 1 if argument is omitted.</td>
</tr>
<tr>
<td style="text-align:center"><code>dir(num)</code></td>
<td style="text-align:left">Set the direction to <code>num</code>. Use of this command
turns the ant into an <strong>absolute turmite</strong>.</td>
</tr>
<tr>
<td style="text-align:center"><code>put(state)</code></td>
<td style="text-align:left">Set the cell the ant is sitting on to <code>state</code>
(which must be a number).</td>
</tr>
<tr>
<td style="text-align:center"><code>state(num)</code></td>
<td style="text-align:left">Sets the ant's internal state to <code>num</code>. Use
of this command turns the ant into an <strong>turmite</strong>.</td>
</tr>
<tr>
<td style="text-align:center"><code>spawn(breed:dir:state)</code></td>
<td style="text-align:left">Spawn an ant of breed <code>breed</code> here, in state
<code>state</code> and facing in <code>dir</code>. <code>dir</code> is
relative, meaning 0 = same way as me, 1 = right turn from me, etc.
</td>
</tr>
<tr>
<td style="text-align:center"><code>die</code></td>
<td style="text-align:left">Mark this ant as dead, so it will be removed.</td>
</tr>
<tr>
<td style="text-align:center"><code>alert(text)</code></td>
<td style="text-align:left">Shows the text to the user in an alert box. Useful for
debugging.</td>
</tr>
<tr>
<td style="text-align:center"><code>status(text, color)</code></td>
<td style="text-align:left">Puts the text in the status bar. Color is optional,
defaults to black.</td>
</tr>
</tbody>
</table>
<h3><code>Beetle</code> and <code>Cricket</code></h3>
<table>
<thead>
<tr>
<th style="text-align:center">Command</th>
<th style="text-align:left">What it does</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center"><code>play(note:pan)</code></td>
<td style="text-align:left">Play that note for 1 tick. <code>note</code> can be a
number, which is a frequency in hertz, or a note name string such as
<code>Bb5</code> which is converted to the frequency of that piano note.
Support for stereo pan is experimental - defaults to 0.
</td>
</tr>
</tbody>
</table>
<p><code>Beetle</code> (think: "beat") uses a <a
href="https://tonejs.github.io/docs/14.7.77/MembraneSynth"><code>Tone.MembraneSynth</code></a>,
whereas <code>Cricket</code> uses a <a
href="https://tonejs.github.io/docs/14.7.77/AMSynth"><code>Tone.AMSynth</code></a>.
</p>
</div>
</div>
</div>
<div id="help" class="popover">
<div class="flex-column">
<div class="flex-row">
<span class="expanding">
<h1>Help</h1>
</span>
<p style="text-align: right;"><a href="#">X</a></p>
</div>
<div class="scroller expanding">
<h2>Tools</h2>
<h3>Drag Tool</h3>
<p>This allows you to pan around the world and zoom in and out. Click and drag to pan in any
direction, and scroll up and down to zoom.</p>
<p>If you hold down <small>SHIFT</small> this will disable zoom, and it will instead pan up
and down. If you have a mouse that supports left-right scrolling as well (such as a trackpad
or Apple Magic Mouse) you can scroll to pan left and right too.</p>
<h3>Draw Cells tool</h3>
<p>This lets you draw cells under the ants to change what they do. Enter a cell state in the
box, and draw it onto the canvas.</p>
<p>If you start drawing by clicking on the same cell state as the one selected in the box,
you will begin erasing the cells and setting them to state 0.</p>
<p>If you hold down <small>SHIFT</small> and click on a cell, it will become an eyedropper
tool and update the cell state in the box with the one you clicked on instead of drawing.</p>
<h3>Draw Ants tool</h3>
<p>Like the Draw Cells tool, this tool allows you to place ants. Select a breed, state, and
direction, and click on the canvas to place an ant. (You can't drag to place multiple
ants at once; I might add this in the future.)</p>
<p>You can't edit the behavior of the ants with this tool; for that, you will have to use
the raw XML <a href="#editor">editor</a>.</p>
<p>If you hold down <small>SHIFT</small> and click on an ant, it become an eyedropper and
update the ant value pickers similar to the Draw Cells tool.</p>
<p>If you hold down <small>CTRL</small> and click on an ant, the ant will be removed.</p>
<h2>Actions menu</h2>
<h3>Open Clipboard</h3>
<p>This reads your clipboard, and opens the world. (Just a shortcut for opening the
<a href="#editor">editor</a>, selecting everything, paste, and LOAD.)
</p>
<h3>Save</h3>
<p>This saves the world state into your browser's local storage so that you won't lose it when you
close Langton-Music. It will be automatically loaded when you open Langton-Music the next time.
</p>
<p>Nothing is ever sent to any server, it is all stored locally on your computer. This also means
that if you "save" on one device, you won't be able to load it on another device. You'll have to
use some other method to sync your saves between devices; this is outside the scope of
Langton-Music.</p>
<h3>Share</h3>
<p>This lets you share the world state through any tool that your browser supports sharing to, such
as email, iMessage, Discord, etc. The choices of tools is wholly dependent on your browser and
the other apps you have installed -- it may differ between devices.</p>
<h3>Copy as XML</h3>
<p>This copies the XML-serialized state of the world (what you see when you open the <a
href="#editor">editor</a>) to your clipboard.</p>
<h3>Copy as BBCode</h3>
<p>This is the same as the <strong>Copy as XML</strong> option, except it wraps the XML in
<code>[code][/code]</code> tags for easier pasting into a BBCode-enabled forum post.
</p>
<h3>Screenshot</h3>
<p>This captures the current contents of the canvas, and prompts you to download it as a PNG image.
</p>
<h2>Other issues?</h2>
<p>If all else fails, or something appears to be broken, you can
<a href="https://github.com/dragoncoder047/langton-music/issues">report it on Github</a>.</p>
</div>
</div>
</div>
<div id="kbd" class="popover">
<div class="flex-column">
<div class="flex-row">
<span class="expanding">
<h1>Keyboard Shortcuts</h1>
</span>
<p style="text-align: right;"><a href="#">X</a></p>
</div>
<div class="scroller expanding">
<dl>
<dt><kbd>ENTER</kbd></dt>
<dd>Play or pause the pattern.</dd>
<dt><kbd>TAB</kbd></dt>
<dd>Step by one tick.</dd>
<dt><kbd>+</kbd></dt>
<dd>Increase the speed by 10 BPM.</dd>
<dt><kbd>-</kbd></dt>
<dd>Decrease the speed by 10 BPM.</dd>
<dt><kbd>SHIFT</kbd> + <kbd>+</kbd></dt>
<dd>Increase the speed by 100 BPM.</dd>
<dt><kbd>SHIFT</kbd> + <kbd>-</kbd></dt>
<dd>Decrease the speed by 100 BPM.</dd>
<dt><kbd>[</kbd></dt>
<dd>Zoom out.</dd>
<dt><kbd>]</kbd></dt>
<dd>Zoom in.</dd>
<dt><kbd>↑</kbd>/<kbd>→</kbd>/<kbd>↓</kbd>/<kbd>←</kbd></dt>
<dd>Pan around.</dd>
<dt><kbd>a</kbd></dt>
<dd>Toggle autofit.</dd>
<dt><kbd>d</kbd></dt>
<dd>Open the format documentation.</dd>
<dt><kbd>/</kbd></dt>
<dd>Open the keyboard shortcuts (this panel).</dd>
<dt><kbd>?</kbd></dt>
<dd>Open the general help.</dd>
<dt><kbd>e</kbd></dt>
<dd>Open the editor.</dd>
<dt><kbd>ESC</kbd></dt>
<dd>Close any active pop-up window.</dd>
<dt><kbd>s</kbd></dt>
<dd>Save the pattern to local storage.</dd>
<dt><kbd>o</kbd></dt>
<dd>Open your clipboard.</dd>
</dl>
</div>
</div>
</div>
<script src="js/darkmode.js"></script>
<script src="js/actionman.js"></script>
<script src="js/interpol.js"></script>
<script src="js/ant.js"></script>
<script src="js/notes.js"></script>
<script src="js/antsparser.js"></script>
<script src="js/vector.js"></script>
<script src="js/canvastools.js"></script>
<script src="js/world.js"></script>
<script src="js/actions.js"></script>
<script src="js/media.js"></script>
<script src="js/main.js"></script>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XR0F89CCGK"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag("js", new Date());
gtag("config", "G-XR0F89CCGK");
</script>
</body>
</html>