@maccesar/titools 5.1.0 → 5.2.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 (85) hide show
  1. package/README.md +44 -12
  2. package/agents/ti-pro.md +4 -0
  3. package/commands/ti-audit.md +4 -0
  4. package/lib/config.js +2 -0
  5. package/package.json +1 -1
  6. package/skills/purgetss/SKILL.md +4 -4
  7. package/skills/purgetss/references/EXAMPLES.md +3 -3
  8. package/skills/purgetss/references/adopting-purgetss.md +2 -2
  9. package/skills/purgetss/references/animation-advanced.md +2 -2
  10. package/skills/purgetss/references/arbitrary-values.md +8 -5
  11. package/skills/purgetss/references/class-categories.md +5 -5
  12. package/skills/purgetss/references/class-index-properties.md +6 -6
  13. package/skills/purgetss/references/class-index.md +2 -2
  14. package/skills/purgetss/references/cli-commands.md +2 -2
  15. package/skills/purgetss/references/dynamic-component-creation.md +2 -2
  16. package/skills/purgetss/references/grid-layout.md +1 -1
  17. package/skills/purgetss/references/migration-guide.md +34 -4
  18. package/skills/purgetss/references/multi-density-images.md +6 -6
  19. package/skills/purgetss/references/platform-modifiers.md +21 -0
  20. package/skills/purgetss/references/ui-ux-design.md +1 -1
  21. package/skills/purgetss/references/version-history.md +9 -4
  22. package/skills/ti-admob-unified/SKILL.md +44 -0
  23. package/skills/ti-admob-unified/agents/openai.yaml +4 -0
  24. package/skills/ti-admob-unified/assets/example/app.js +1003 -0
  25. package/skills/ti-admob-unified/assets/example/lib/ads.js +618 -0
  26. package/skills/ti-admob-unified/assets/example/library-usage.js +104 -0
  27. package/skills/ti-admob-unified/references/api-reference.md +592 -0
  28. package/skills/ti-admob-unified/references/banners.md +435 -0
  29. package/skills/ti-admob-unified/references/contributing.md +228 -0
  30. package/skills/ti-admob-unified/references/dependencies.md +85 -0
  31. package/skills/ti-admob-unified/references/fullscreen.md +223 -0
  32. package/skills/ti-admob-unified/references/game-monetization.md +17 -0
  33. package/skills/ti-admob-unified/references/getting-started.md +275 -0
  34. package/skills/ti-admob-unified/references/index.md +30 -0
  35. package/skills/ti-admob-unified/references/integration.md +85 -0
  36. package/skills/ti-admob-unified/references/library.md +189 -0
  37. package/skills/ti-admob-unified/references/mediation.md +132 -0
  38. package/skills/ti-admob-unified/references/migration.md +255 -0
  39. package/skills/ti-admob-unified/references/module-changelog.md +54 -0
  40. package/skills/ti-admob-unified/references/module-license.txt +21 -0
  41. package/skills/ti-admob-unified/references/privacy.md +254 -0
  42. package/skills/ti-admob-unified/references/roadmap.md +146 -0
  43. package/skills/ti-admob-unified/references/source-notes.md +33 -0
  44. package/skills/ti-admob-unified/references/source-snapshot.json +440 -0
  45. package/skills/ti-admob-unified/references/third-party-notices.md +22 -0
  46. package/skills/ti-game/SKILL.md +10 -1
  47. package/skills/ti-game/references/api.md +10 -2
  48. package/skills/ti-game/references/debugging-performance.md +6 -0
  49. package/skills/ti-game/references/examples.md +11 -1
  50. package/skills/ti-game/references/patterns.md +24 -2
  51. package/skills/ti-game/references/physics.md +502 -0
  52. package/skills/ti-game/references/project-setup.md +23 -1
  53. package/skills/ti-game/references/recipes-action.md +46 -14
  54. package/skills/ti-game/references/recipes-adventure-effects.md +12 -1
  55. package/skills/ti-game/references/roadmap.md +2 -2
  56. package/skills/ti-game/references/tilemaps.md +2 -1
  57. package/skills/ti-game-assets/SKILL.md +53 -0
  58. package/skills/ti-game-assets/agents/openai.yaml +4 -0
  59. package/skills/ti-game-assets/references/alpha.md +26 -0
  60. package/skills/ti-game-assets/references/art-direction.md +37 -0
  61. package/skills/ti-game-assets/references/integration.md +49 -0
  62. package/skills/ti-game-assets/references/manifest.example.json +429 -0
  63. package/skills/ti-game-assets/references/manifest.md +39 -0
  64. package/skills/ti-game-assets/references/offline-audio.md +33 -0
  65. package/skills/ti-game-assets/references/prompts.md +33 -0
  66. package/skills/ti-game-assets/references/repeating-textures.md +17 -0
  67. package/skills/ti-game-assets/references/responsible-ads.md +31 -0
  68. package/skills/ti-game-assets/references/sound-assets.md +42 -0
  69. package/skills/ti-game-assets/references/vector-sources.md +21 -0
  70. package/skills/ti-game-assets/scripts/alpha_tools.py +160 -0
  71. package/skills/ti-game-assets/scripts/requirements.txt +1 -0
  72. package/skills/ti-game-assets/scripts/validate_manifest.py +267 -0
  73. package/skills/ti-synthengine/SKILL.md +37 -13
  74. package/skills/ti-synthengine/references/api.md +397 -31
  75. package/skills/ti-synthengine/references/audio-engine.md +235 -14
  76. package/skills/ti-synthengine/references/examples.md +396 -17
  77. package/skills/ti-synthengine/references/guide.md +331 -12
  78. package/skills/ti-synthengine/references/recipes.md +212 -22
  79. package/skills/ti-synthengine/references/recommendations.md +53 -16
  80. package/skills/ti-synthengine/references/sound-design.md +359 -15
  81. package/skills/ti-synthengine/references/source-notes.md +121 -0
  82. package/skills/ti-synthengine/references/source-snapshot.json +105 -0
  83. package/skills/ti-synthengine/references/stats-performance.json +2992 -0
  84. package/skills/ti-synthengine/references/stats-performance.md +38 -0
  85. package/skills/ti-synthengine/references/troubleshooting.md +61 -4
@@ -1,4 +1,4 @@
1
- > Source snapshot: official TiSynthEngine 1.0.0 documentation at commit `6685b81` (2026-08-29).
1
+ > Source snapshot: official TiSynthEngine 1.0.0 beta documentation from the reviewed working tree based on `95901c98af5353b86d9dc7c60b29ab9186b038cd` (2026-10-14), including uncommitted statistics changes. Upstream `documentation/sound-design.md` SHA-256: `4ccbb55b92879c59d20116aff942e16d431c619341b3d4714da4c50c3c691cf9`.
2
2
 
3
3
  # Sound design with TiSynthEngine
4
4
 
@@ -19,9 +19,14 @@ var WAVE = synth.getDefaults().waveTypes
19
19
 
20
20
  - [Notes, frequencies and octaves](#notes-frequencies-and-octaves)
21
21
  - [Waveform and timbre](#waveform-and-timbre)
22
+ - [Filter, pulse width and quantization](#filter-pulse-width-and-quantization)
22
23
  - [Envelope and total duration](#envelope-and-total-duration)
24
+ - [Decay and sustain](#decay-and-sustain)
23
25
  - [Pan and movement](#pan-and-movement)
24
26
  - [Vibrato and the LFO](#vibrato-and-the-lfo)
27
+ - [Resonant filter](#resonant-filter)
28
+ - [Frequency modulation](#frequency-modulation)
29
+ - [Detune](#detune)
25
30
  - [Chords, polyphony and gain](#chords-polyphony-and-gain)
26
31
  - [Mixing profiles and limiter](#mixing-profiles-and-limiter)
27
32
  - [Speakers, headphones and devices](#speakers-headphones-and-devices)
@@ -105,7 +110,28 @@ melodies, pads and xylophone-like sketches.
105
110
  changing that value does not tune the noise. A short envelope turns it into a
106
111
  click, hat or impact layer; a long envelope creates wind or static.
107
112
 
108
- Try every waveform at a moderate level before choosing one:
113
+ `noiseRate` changes the source into variable-rate sample-and-hold noise. Zero
114
+ keeps the white-noise default. Lower rates hold each pseudo-random value longer
115
+ and sound grainier. `noiseRateEnd` moves the rate over the event.
116
+
117
+ ### Wavetable
118
+
119
+ `WAVETABLE` repeats 2 to 64 values supplied in `waveTable`. Values range from
120
+ -1 to 1 and are read as steps, without interpolation. Short asymmetric tables
121
+ are useful for coarse DAC-like voices, buzzy radio tones and original retro
122
+ effects that do not fit the four built-in oscillator shapes.
123
+
124
+ ```javascript
125
+ synth.playTone({
126
+ note: 'D4',
127
+ duration: 600,
128
+ waveType: WAVE.WAVETABLE,
129
+ waveTable: [-1, -0.8, -0.1, 0.9, 0.45, 0.1, -0.25, -0.6],
130
+ bitDepth: 8
131
+ })
132
+ ```
133
+
134
+ Try the built-in sources at a moderate level before choosing one:
109
135
 
110
136
  ```javascript
111
137
  ;[WAVE.SINE, WAVE.SQUARE, WAVE.SAWTOOTH, WAVE.TRIANGLE, WAVE.NOISE]
@@ -123,6 +149,34 @@ Try every waveform at a moderate level before choosing one:
123
149
  })
124
150
  ```
125
151
 
152
+ ## Filter, pulse width and quantization
153
+
154
+ `lowPassHz` enables a per-voice one-pole low-pass filter. It is most obvious on
155
+ noise, square and sawtooth sources. Zero bypasses the filter. For resonance,
156
+ high-pass and band-pass shapes or a moving cutoff, use the
157
+ [resonant filter](#resonant-filter) below.
158
+
159
+ `pulseWidth` controls how much of each square-wave cycle stays high. The 0.5
160
+ default is a normal square. Values closer to 0.05 or 0.95 become thinner and
161
+ brighter. `pulseWidthEnd` creates a linear duty-cycle sweep.
162
+
163
+ ```javascript
164
+ synth.playTone({
165
+ note: 'A3',
166
+ duration: 700,
167
+ release: 180,
168
+ waveType: WAVE.SQUARE,
169
+ pulseWidth: 0.1,
170
+ pulseWidthEnd: 0.86,
171
+ lowPassHz: 4200
172
+ })
173
+ ```
174
+
175
+ `bitDepth` rounds the oscillator or noise amplitude to a fixed number of
176
+ levels before filtering. Values from 2 to 16 are accepted. Zero preserves the
177
+ floating-point signal. Quantization adds harmonic grit; it does not change the
178
+ audio device's output format.
179
+
126
180
  ## Envelope and total duration
127
181
 
128
182
  Every event uses an attack, an implicit sustain section and a release:
@@ -153,6 +207,34 @@ release <= duration - attack
153
207
  Defaults are adjusted internally if a very short duration leaves no room, but
154
208
  values supplied by the caller are never reshaped silently.
155
209
 
210
+ ## Decay and sustain
211
+
212
+ Plucked strings, struck keys and mallets start loud and settle. A flat
213
+ envelope cannot do that, so `decay` and `sustain` add a stage after the attack:
214
+ the level falls from full scale to `sustain` over `decay` milliseconds, then
215
+ holds until the release.
216
+
217
+ ```text
218
+ decay: 0 flat tone, the default
219
+ decay: 260, sustain: 0.18 pluck: loud start, settles low
220
+ decay: 2000, sustain: 0.02 bell or mallet: fades by itself
221
+ ```
222
+
223
+ Practical starting regions:
224
+
225
+ - plucks and keys: attack 2 to 10 ms, decay 100 to 400 ms, sustain 0.1 to 0.4;
226
+ - struck percussion with a pitch drop: decay about half the duration, sustain
227
+ near 0.3;
228
+ - bells and mallets: decay over most of the duration, sustain near 0.
229
+
230
+ `sustain` below 1 needs a nonzero `decay`. Without one the level would jump
231
+ instantly, which clicks, so the call is rejected with `sustain_without_decay`.
232
+
233
+ The release scales the level the note has reached. If the release begins while
234
+ the decay is still running, the note leaves smoothly from that point. The
235
+ decay still has to fit: `attack` plus `decay` cannot exceed `duration`, and the
236
+ 50 ms default attack counts. Set a short `attack` explicitly for a tight pluck.
237
+
156
238
  ## Pan and movement
157
239
 
158
240
  `pan` ranges from -1 on the left to 1 on the right. Zero is centered. Stereo
@@ -209,12 +291,111 @@ A rate around 4 to 7 Hz with a small depth sounds like musical vibrato. A fast
209
291
  rate or large depth becomes an effect. Because depth is measured in hertz, 8 Hz
210
292
  is a larger musical interval on a low note than on a high note.
211
293
 
294
+ ## Resonant filter
295
+
296
+ `filterType` adds a filter that removes or emphasizes part of the spectrum. It
297
+ has 12 dB per octave of slope, twice as steep as the one-pole `lowPassHz`
298
+ filter, and can be combined with it (`lowPassHz` runs first).
299
+
300
+ - `lowpass` darkens the sound. A sawtooth through a closing low-pass reads as a
301
+ zap or a sound moving away; an opening one reads as a swell.
302
+ - `highpass` thins the sound by removing body. It makes hats, hiss and tinny
303
+ effects out of noise.
304
+ - `bandpass` keeps one band around `filterHz`, which gives vocal, nasal and
305
+ wah-like colors.
306
+
307
+ Filters shape harmonics, so give them a source that has some: `SAWTOOTH`,
308
+ `SQUARE` and `NOISE` respond strongly. A sine has only its fundamental, so a
309
+ filter mostly changes its level.
310
+
311
+ `filterQ` is the resonance. The default 0.7071 is flat. Values from 2 to 4 add
312
+ character, and above about 6 the filter whistles around the cutoff. A low-pass
313
+ or high-pass boosts the cutoff region by about `filterQ`, so Q 10 is roughly
314
+ 20 dB. Lower the event `volume` as Q goes up. The limiter catches peaks, but a
315
+ resonance that keeps hitting it makes the whole mix pump. The band-pass keeps
316
+ unity gain at its center for every Q and only narrows.
317
+
318
+ `filterHzEnd` moves the cutoff over the whole event. The motion is exponential,
319
+ so each second covers the same musical distance. Set it above `filterHz` to
320
+ open the filter and below to close it. Zero disables the sweep.
321
+
322
+ ```javascript
323
+ synth.playTone({
324
+ note: 'A2',
325
+ duration: 1000,
326
+ attack: 10,
327
+ release: 200,
328
+ volume: 0.5,
329
+ waveType: WAVE.SAWTOOTH,
330
+ filterType: 'bandpass',
331
+ filterHz: 350,
332
+ filterHzEnd: 2400,
333
+ filterQ: 5
334
+ })
335
+ ```
336
+
337
+ ## Frequency modulation
338
+
339
+ FM makes rich, bright and metallic sounds from a plain sine. A second sine, the
340
+ modulator, bends the pitch of the first one, the carrier. Turn it on with
341
+ `fmDepth` or `fmDepthEnd`, on a `SINE` voice.
342
+
343
+ - `fmRatio` is the modulator frequency as a multiple of the carrier's. Whole
344
+ numbers (1, 2, 3) keep the added overtones on the harmonic series, so the
345
+ pitch stays clear and the sound reads as organ- or piano-like. Fractional
346
+ ratios such as 1.4142 or 3.5 put the overtones between harmonics, which reads
347
+ as bells, glass and metal.
348
+ - `fmDepth` is the modulation index and works like a brightness control. Around
349
+ 0.5 to 1.5 it warms a sine, 2 to 5 makes it bright and rich, and values near
350
+ 10 get harsh.
351
+ - `fmDepthEnd` moves the index over the event. Starting high and ending low
352
+ gives a bright attack that mellows, which is the signature of electric pianos,
353
+ bells and mallets. Pair it with `decay` so the level falls with the brightness.
354
+
355
+ FM does not change the sine's amplitude, so gain staging is the same as for a
356
+ plain sine. There is no band-limiting: a high carrier with a large index and
357
+ ratio puts sidebands above the Nyquist frequency, where they alias into
358
+ inharmonic noise. Keep bell carriers modest, around 500 Hz, or lower the index.
359
+
360
+ ## Detune
361
+
362
+ `detune` shifts a pitch by cents, hundredths of a semitone. Two tones a few
363
+ cents apart drift in and out of phase and beat at a rate close to
364
+ `frequency * (2 ^ (cents / 1200) - 1)`. A 12-cent gap at 440 Hz beats about
365
+ 3 times a second. Slow beating (0.5 to 4 Hz) sounds warm and wide, like a
366
+ chorus; past about 20 cents it starts to sound out of tune.
367
+
368
+ On a single tone, `detune` just retunes it, which is handy for small variations
369
+ so a repeated effect does not sound identical. The effect comes from stacking
370
+ detuned copies. In a chord, give `detunes` one entry per pitch and repeat a
371
+ pitch to thicken it:
372
+
373
+ ```javascript
374
+ synth.playChord({
375
+ frequencies: [440, 440],
376
+ detunes: [-6, 6],
377
+ duration: 2000,
378
+ attack: 200,
379
+ release: 600,
380
+ volume: 0.55,
381
+ waveType: WAVE.SINE
382
+ })
383
+ ```
384
+
385
+ Each repeated pitch is a voice, so size `maxVoices` for the full stack. Protected
386
+ profiles divide per-voice source gain by the square root of the event voice
387
+ count. This reduces buildup; it does not guarantee equal loudness. Correlated
388
+ voices can still reinforce each other, and detuned voices can produce peaks
389
+ as their phases align. `raw` does not apply this event normalization.
390
+
212
391
  ## Chords, polyphony and gain
213
392
 
214
393
  `playChord` is for notes that should start together. The call is placed in the
215
394
  native queue as one event, so the audio callback sees the whole chord or none
216
- of it. Its source gain is divided by the square root of the chord's voice count
217
- to keep power stable.
395
+ of it. In protected profiles, per-voice source gain is divided by the square
396
+ root of the chord's voice count. This approximately stabilizes power for
397
+ uncorrelated voices, not coherent copies; it does not guarantee constant peaks
398
+ or perceived loudness. `raw` bypasses this normalization.
218
399
 
219
400
  ```javascript
220
401
  synth.playChord({
@@ -358,16 +539,18 @@ synth.playPattern({
358
539
  volume: 0.5,
359
540
  waveType: WAVE.SQUARE,
360
541
  steps: [
361
- { note: 'C5', duration: 80 },
362
- { note: 'E5', duration: 80 },
363
- { note: 'G5', duration: 80 },
364
- { note: 'C6', duration: 160, noteValue: '8n' }
542
+ { note: 'C5' },
543
+ { note: 'E5' },
544
+ { note: 'G5' },
545
+ { note: 'C6', noteValue: '8n' }
365
546
  ]
366
547
  })
367
548
  ```
368
549
 
369
- The pattern root does not accept `duration`. Put it on each sounding step when
370
- you want a gate shorter than its rhythmic step.
550
+ The first three steps use sixteenth notes and the last uses an eighth note.
551
+ `release` fades each voice within that rhythmic length. The pattern root does
552
+ not accept `duration`; a step `duration` replaces its rhythmic length as well
553
+ as its voice length. There is no separate gate parameter.
371
554
 
372
555
  ### Noise percussion
373
556
 
@@ -378,17 +561,179 @@ synth.playPattern({
378
561
  waveType: WAVE.NOISE,
379
562
  volume: 0.34,
380
563
  steps: [
381
- { frequency: 220, duration: 65, attack: 1, release: 55 },
564
+ { frequency: 220, attack: 1, decay: 65, sustain: 0, release: 55 },
382
565
  { rest: true },
383
- { frequency: 220, duration: 35, attack: 1, release: 28 },
384
- { frequency: 220, duration: 35, attack: 1, release: 28 }
566
+ { frequency: 220, attack: 1, decay: 35, sustain: 0, release: 28 },
567
+ { frequency: 220, attack: 1, decay: 35, sustain: 0, release: 28 }
385
568
  ]
386
569
  })
387
570
  ```
388
571
 
572
+ The steps keep the eighth-note grid while short decay and `sustain: 0` let
573
+ each hit settle to silence inside its step.
574
+
389
575
  Noise steps still need `frequency` or `note` because every sounding pattern
390
576
  step follows the same shape. The pitch value is not used by the noise source.
391
577
 
578
+ ### Filtered noise burst
579
+
580
+ ```javascript
581
+ synth.playTone({
582
+ frequency: 120,
583
+ duration: 760,
584
+ attack: 1,
585
+ release: 580,
586
+ volume: 0.62,
587
+ waveType: WAVE.NOISE,
588
+ noiseRate: 12000,
589
+ noiseRateEnd: 650,
590
+ lowPassHz: 2500,
591
+ bitDepth: 8
592
+ })
593
+ ```
594
+
595
+ The decreasing update rate makes the texture break into slower chunks while
596
+ the envelope removes energy. Reverse the two rates for an effect that becomes
597
+ more frantic.
598
+
599
+ ### Pluck
600
+
601
+ ```javascript
602
+ synth.playTone({
603
+ note: 'E4',
604
+ duration: 900,
605
+ attack: 2,
606
+ decay: 260,
607
+ sustain: 0.18,
608
+ release: 380,
609
+ volume: 0.6,
610
+ waveType: WAVE.TRIANGLE
611
+ })
612
+ ```
613
+
614
+ ### Electric piano
615
+
616
+ ```javascript
617
+ synth.playTone({
618
+ note: 'E3',
619
+ duration: 1800,
620
+ attack: 3,
621
+ decay: 700,
622
+ sustain: 0.3,
623
+ release: 600,
624
+ volume: 0.55,
625
+ waveType: WAVE.SINE,
626
+ fmRatio: 1,
627
+ fmDepth: 2.2,
628
+ fmDepthEnd: 0.25
629
+ })
630
+ ```
631
+
632
+ The index falls from 2.2 to 0.25 while the level settles, so the attack is
633
+ bright and the sustain is mellow.
634
+
635
+ ### Bell
636
+
637
+ ```javascript
638
+ synth.playTone({
639
+ note: 'C5',
640
+ duration: 2600,
641
+ attack: 1,
642
+ decay: 2000,
643
+ sustain: 0.02,
644
+ release: 500,
645
+ volume: 0.5,
646
+ waveType: WAVE.SINE,
647
+ fmRatio: 3.5,
648
+ fmDepth: 4,
649
+ fmDepthEnd: 0
650
+ })
651
+ ```
652
+
653
+ The fractional ratio makes the overtones inharmonic. Try 1.4142 or 2.76 for a
654
+ different metal.
655
+
656
+ ### Wah
657
+
658
+ The wah in [Resonant filter](#resonant-filter) is also a recipe. Reverse the
659
+ two cutoffs for a sound that closes instead of opening.
660
+
661
+ ### Filtered laser
662
+
663
+ ```javascript
664
+ synth.playTone({
665
+ frequency: 1600,
666
+ frequencyEnd: 160,
667
+ duration: 340,
668
+ attack: 2,
669
+ release: 90,
670
+ volume: 0.4,
671
+ waveType: WAVE.SAWTOOTH,
672
+ filterType: 'lowpass',
673
+ filterHz: 7000,
674
+ filterHzEnd: 500,
675
+ filterQ: 4
676
+ })
677
+ ```
678
+
679
+ ### Hi-hat
680
+
681
+ ```javascript
682
+ synth.playTone({
683
+ duration: 80,
684
+ attack: 1,
685
+ decay: 30,
686
+ sustain: 0.25,
687
+ release: 45,
688
+ volume: 0.45,
689
+ waveType: WAVE.NOISE,
690
+ filterType: 'highpass',
691
+ filterHz: 7000
692
+ })
693
+ ```
694
+
695
+ For an open hat, use `duration: 320`, `decay: 70` and `release: 220`.
696
+
697
+ ### Thick pad
698
+
699
+ ```javascript
700
+ synth.playChord({
701
+ notes: ['A3', 'E4', 'A3', 'E4', 'A3', 'E4'],
702
+ detunes: [-9, -9, 0, 0, 9, 9],
703
+ duration: 3200,
704
+ attack: 700,
705
+ release: 1300,
706
+ volume: 0.5,
707
+ waveType: WAVE.SAWTOOTH,
708
+ filterType: 'lowpass',
709
+ filterHz: 1500,
710
+ panSpread: 0.8
711
+ })
712
+ ```
713
+
714
+ Six voices play two pitches, each in three slightly different tunings. The
715
+ low-pass takes the harshness off the sawtooth stack. Start the engine with
716
+ `maxVoices` of at least 6.
717
+
718
+ ### Kick
719
+
720
+ ```javascript
721
+ synth.playTone({
722
+ frequency: 150,
723
+ frequencyEnd: 42,
724
+ duration: 320,
725
+ attack: 1,
726
+ decay: 150,
727
+ sustain: 0.3,
728
+ release: 140,
729
+ volume: 0.85,
730
+ waveType: WAVE.SINE
731
+ })
732
+ ```
733
+
734
+ The pitch drop is the punch and the decay is the thump. A phone speaker cannot
735
+ reproduce 42 Hz, so raise `frequencyEnd` toward 70 for speaker playback.
736
+
392
737
  ### Simon-style cues
393
738
 
394
739
  Use short, distinct square-wave pitches. Play one tone for the sequence and
@@ -424,5 +769,4 @@ function playAllSimonPads () {
424
769
  For more complete code, continue with [Examples](examples.md) and
425
770
  [Curated sound and interaction recipes](recipes.md). The latter includes retro
426
771
  effects, a playable xylophone, memory-pad timbres, layered chords and timer
427
- ownership. For gain and device-testing advice, see
428
- [Recommendations](recommendations.md).
772
+ ownership. For gain and device-testing advice, see [Recommendations](recommendations.md).
@@ -0,0 +1,121 @@
1
+ # Maintaining the synthesis snapshot
2
+
3
+ The eight official Markdown mirrors and raw statistics comparison are derived
4
+ from the reviewed TiSynthEngine working tree based on the commit in
5
+ [source-snapshot.json](source-snapshot.json). This snapshot includes uncommitted
6
+ native statistics methods, tests and documentation. The commit identifies the
7
+ base; it does not contain all reviewed content. `reviewed_worktree_sha256`
8
+ records the reviewed dirty-state fingerprint, including tracked differences
9
+ and untracked files. The checker verifies that fingerprint in addition to the
10
+ individual source/mirror hashes. A match establishes fidelity to that source
11
+ state; it does not establish that the source is correct, committed, published
12
+ or installed in an app. A different dirty fingerprint requires a fresh review.
13
+ Read the native contracts, command conversion and renderers when auditing
14
+ behavior. The maintainer workflow is `titools-skill-auditor` in this repository.
15
+
16
+ ## Sources and permitted transformations
17
+
18
+ `api.md`, `audio-engine.md`, `examples.md`, `guide.md`, `recommendations.md`,
19
+ `sound-design.md`, `troubleshooting.md` and `stats-performance.md` mirror the
20
+ corresponding upstream `documentation/` files. `stats-performance.json` preserves
21
+ the complete raw trials without Markdown transformations. These nine assets
22
+ each record a full-source SHA-256 and final mirror SHA-256. Markdown provenance
23
+ headers identify the working tree, base commit and full-source hash.
24
+
25
+ Only these transformations are currently declared:
26
+
27
+ - A provenance header and generated `TOC-START`/`TOC-END` navigation.
28
+ - The upstream demo link in `examples.md` is rebased to the last committed
29
+ `example/app.js` at the base commit. Its label explicitly distinguishes that
30
+ demo from the pending statistics example in the reviewed working tree; a
31
+ GitHub commit link cannot expose uncommitted changes. It requires access to
32
+ the official module repository; the runnable app is not bundled here.
33
+ - `examples.md` and `sound-design.md` retain their TiTools links to
34
+ [curated recipes](recipes.md). These additions are recorded as reversible
35
+ `link_fixes`, with the complete original and mirrored Markdown fragments.
36
+
37
+ For Markdown mirrors, the snapshot test removes the header and generated
38
+ navigation, reverses those fragments, and checks the full original source hash.
39
+ The raw JSON is checked byte for byte. Update the declared
40
+ transformations when an intentional source-derived edit is reviewed; never
41
+ regenerate hashes merely to conceal an unexplained difference.
42
+
43
+ ## Protected curated content
44
+
45
+ [recipes.md](recipes.md) is a TiTools contribution, not an official mirror.
46
+ Preserve its recipes, lifecycle patterns and navigation during synchronization.
47
+ Check every native option and envelope against the current contract. The
48
+ rhythm tests execute the Markdown examples and assert their intended note
49
+ onsets, lengths and cancellation behavior; they do not render audio.
50
+
51
+ Do not remove either official mirror's curated recipe link just because the
52
+ upstream source has no equivalent. The snapshot records these intentional
53
+ differences so preservation and source fidelity can both be checked.
54
+
55
+ ## Statistics scope and evidence
56
+
57
+ The reviewed source adds `getStats()`, `resetStats()` and
58
+ `setStatsEnabled(Boolean)` to the previous eight-method API. Detect support
59
+ before using them with older 1.0.0 beta binaries; the version string alone does
60
+ not identify the feature. Basic counters remain available without enabling
61
+ diagnostics. Monotonic-clock render timing and signal measurements are optional
62
+ and default off; missing/unmeasured fields stay `null`, distinct from measured
63
+ zero. Android backend underrun, buffer and latency fields are independent of
64
+ that diagnostics switch and remain best-effort. Poll at a modest rate and
65
+ cancel polling with the owning screen/service.
66
+
67
+ [stats-performance.md](stats-performance.md) and its
68
+ [raw trials](stats-performance.json) document an Android native host comparison
69
+ against the base engine, including variability and excluded costs. They do not
70
+ run the iOS callback, JavaScript bridge or real device stream, and do not prove
71
+ device CPU, battery, heat, latency or physical underrun behavior. Review the
72
+ native statistics contract/publication and tests independently of the benchmark
73
+ percentages; no zero-overhead or unchanged device-performance guarantee follows.
74
+
75
+ ## Upstream documents outside the mirror set
76
+
77
+ The snapshot declares `documentation/index.md` and
78
+ `documentation/third-party-notices.md` in `excluded_documents`, including each
79
+ reviewed hash and reason. SKILL.md supplies the distributed navigation;
80
+ dependency notices accompany the official module and native packages. This
81
+ skill does not distribute Oboe, native binaries or KEMAR impulse responses.
82
+ Changes or deletion of these excluded documents still require review. New
83
+ upstream documents remain visible as new documents until reviewed and mapped
84
+ or explicitly excluded; these records are not a blanket ignore rule.
85
+
86
+ ## Verification after a reviewed update
87
+
88
+ ```bash
89
+ node scripts/verify-module-snapshot.mjs --skill ti-synthengine --source /path/to/TiSynthEngine
90
+ node --test test/ti-synthengine.test.js test/ti-synthengine-recipes.test.js
91
+ ```
92
+
93
+ Run these from TiTools. The checker is read-only: it reports source dirtiness,
94
+ commit drift, source/mirror changes, missing files and new official documents.
95
+ It never fetches, pulls or synchronizes. In the module checkout, also run the
96
+ applicable official documentation, contract and DSP checks described in
97
+ [audio-engine.md](audio-engine.md#regression-coverage).
98
+
99
+ Regenerate navigation only after inspecting the generator's dry run. Refresh
100
+ the snapshot's mirror hashes after navigation and declared additions are final.
101
+ Before committing, inspect source differences and the distributed package;
102
+ neither an old passing test count nor hash equality substitutes for that review.
103
+
104
+ ## Native findings and acceptance boundaries
105
+
106
+ At the 2026-10-14 audit, iOS command construction converted zero attack/release
107
+ to at least one sample; Android preserved zero. The shared envelope therefore
108
+ has a one-sample boundary difference. This remains an upstream implementation
109
+ finding: no native changes were made during the documentation correction.
110
+ Recheck command construction or rendered output before calling it resolved.
111
+
112
+ Java/iOS corpus parity covers validator acceptance/reasons, not rendered
113
+ samples. The shared FIR suite and Android host tests establish narrower DSP
114
+ properties. Inspect their current assertions for rate endpoints and exact
115
+ tail-history coverage rather than assuming every advertised case is tested.
116
+ The JavaScript rhythm checks interpret submitted options; they are not native
117
+ scheduler timing measurements.
118
+
119
+ Device startup/route behavior, iOS rendering, headphone localization, CPU,
120
+ battery and underruns need their own evidence. Contract-valid recipes are not
121
+ automatically pleasant or perceptually well localized.
@@ -0,0 +1,105 @@
1
+ {
2
+ "module": "ti.synthengine",
3
+ "version": "1.0.0 beta",
4
+ "repository": "https://github.com/macCesar/TiSynthEngine",
5
+ "commit": "95901c98af5353b86d9dc7c60b29ab9186b038cd",
6
+ "reviewed_on": "2026-10-14",
7
+ "files": [
8
+ {
9
+ "source": "documentation/api.md",
10
+ "destination": "references/api.md",
11
+ "source_sha256": "60f9eda77f327bad6b66b0b6a49089c383a49a211c0691d09a0d715731434b56",
12
+ "mirrored_sha256": "5c07828516109386224c6380d8e603f6889cb1cbc0f29dd79609db288cabd908",
13
+ "links": [],
14
+ "link_fixes": []
15
+ },
16
+ {
17
+ "source": "documentation/audio-engine.md",
18
+ "destination": "references/audio-engine.md",
19
+ "source_sha256": "7b5707ee22e01a351af3633be14458726f8956069fb9355d1fb31cc4f7b9438a",
20
+ "mirrored_sha256": "22b3665068d9507ef7481a606f8949de24e7429e40609b9760164567220dd8fd",
21
+ "links": [],
22
+ "link_fixes": []
23
+ },
24
+ {
25
+ "source": "documentation/examples.md",
26
+ "destination": "references/examples.md",
27
+ "source_sha256": "53a8bd95215cc24a35776edb8686fa0d60c5399be0b4ff2685eee1563738f6cb",
28
+ "mirrored_sha256": "6679554e7f1df97d45a1e3c5ea842a0999d713933c677fc1a4678e72ca226f63",
29
+ "links": [],
30
+ "link_fixes": [
31
+ {
32
+ "original_markdown": "The complete interactive demo is in [`example/app.js`](../example/app.js).",
33
+ "mirrored_markdown": "The last committed interactive demo is in the upstream [`example/app.js`](https://github.com/macCesar/TiSynthEngine/blob/95901c98af5353b86d9dc7c60b29ab9186b038cd/example/app.js); that commit does not contain the pending statistics example. For additional retro effects, playable xylophone interaction, memory pads, layered polyphony and cancellable repetition, continue with [Curated sound and interaction recipes](recipes.md)."
34
+ }
35
+ ]
36
+ },
37
+ {
38
+ "source": "documentation/guide.md",
39
+ "destination": "references/guide.md",
40
+ "source_sha256": "c5fb4ff34ec425487221b80d6793bda24aa328281ab9ccb02e65b0065e54842e",
41
+ "mirrored_sha256": "d8f58c77c4d622e67ae6e2cafee58a2c24c1c8e31bad719a05ec8a5d968b3d04",
42
+ "links": [],
43
+ "link_fixes": []
44
+ },
45
+ {
46
+ "source": "documentation/recommendations.md",
47
+ "destination": "references/recommendations.md",
48
+ "source_sha256": "0f09ee6ef0876b3a23021fddb509dfd1e1206d08e836acae8f32b58b6481c055",
49
+ "mirrored_sha256": "f2480f455e55e461c880c8614ac383d60abf0ea8e744e3b99deabea290deb6c6",
50
+ "links": [],
51
+ "link_fixes": []
52
+ },
53
+ {
54
+ "source": "documentation/sound-design.md",
55
+ "destination": "references/sound-design.md",
56
+ "source_sha256": "4ccbb55b92879c59d20116aff942e16d431c619341b3d4714da4c50c3c691cf9",
57
+ "mirrored_sha256": "ac716003ff31a9d8dc896faa48ab0a18787a153797b7fa2f77ba0d7a936e8868",
58
+ "links": [],
59
+ "link_fixes": [
60
+ {
61
+ "original_markdown": "For more complete code, continue with [Examples](examples.md). For gain and\ndevice-testing advice, see [Recommendations](recommendations.md).",
62
+ "mirrored_markdown": "For more complete code, continue with [Examples](examples.md) and\n[Curated sound and interaction recipes](recipes.md). The latter includes retro\neffects, a playable xylophone, memory-pad timbres, layered chords and timer\nownership. For gain and device-testing advice, see [Recommendations](recommendations.md)."
63
+ }
64
+ ]
65
+ },
66
+ {
67
+ "source": "documentation/troubleshooting.md",
68
+ "destination": "references/troubleshooting.md",
69
+ "source_sha256": "10949f8f18f9e97933bfb1f025a12217746648c01805ff0fafe2c8e064b1c0cc",
70
+ "mirrored_sha256": "baaa2e31f1c1e0ab8b3dd9924929ec987caa13962b526af1389bdbfb77f4f9af",
71
+ "links": [],
72
+ "link_fixes": []
73
+ },
74
+ {
75
+ "source": "documentation/stats-performance.md",
76
+ "destination": "references/stats-performance.md",
77
+ "source_sha256": "798075f7bec08b4dafcaa46f1c43552d90ba23e2c85b49b4ab1d4ddf72c210df",
78
+ "mirrored_sha256": "40e4dc748379a24a90a812f26177372530a8138324d465a11f75ff7f45c3dc1d",
79
+ "links": [],
80
+ "link_fixes": []
81
+ },
82
+ {
83
+ "source": "documentation/stats-performance.json",
84
+ "destination": "references/stats-performance.json",
85
+ "source_sha256": "bd0cf07295d0d8f1120e66f527e9ca6d9a014efdc43dff5675716e8e26abe5b3",
86
+ "mirrored_sha256": "bd0cf07295d0d8f1120e66f527e9ca6d9a014efdc43dff5675716e8e26abe5b3",
87
+ "links": [],
88
+ "link_fixes": []
89
+ }
90
+ ],
91
+ "excluded_documents": [
92
+ {
93
+ "source": "documentation/index.md",
94
+ "source_sha256": "a1fee9bfc45e461594b54cc226cf21e9ecbee358400b3414643a199c18b1edb2",
95
+ "reason": "Upstream documentation index; SKILL.md is the distributed navigation entry point."
96
+ },
97
+ {
98
+ "source": "documentation/third-party-notices.md",
99
+ "source_sha256": "cff5eb2cb19c9128e33f26d524fac1f7cad43e263693f34413392ead97b0f1c5",
100
+ "reason": "Dependency and KEMAR notices remain with the official module and its binary packages; this skill redistributes documentation, not the native code or HRTF data. Re-review attribution when the source notice changes."
101
+ }
102
+ ],
103
+ "source_state": "working-tree",
104
+ "reviewed_worktree_sha256": "5a5085884d65ec92b6281f2c04cf47adaa864d988e3462fca98340d4a9a27ad9"
105
+ }