tuneframes 0.1.0 → 0.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 (78) hide show
  1. package/LICENSE +167 -199
  2. package/README.md +150 -97
  3. package/examples/example-ai-dj-chill.html +167 -0
  4. package/examples/example-ai-dj-dark.html +167 -0
  5. package/examples/example-ai-dj-energetic.html +167 -0
  6. package/examples/example-ai-dj-happy.html +167 -0
  7. package/examples/example-ai-dj.html +167 -0
  8. package/examples/example-ambient.html +63 -63
  9. package/examples/example-ambient.mp3 +0 -0
  10. package/examples/example-bass.html +48 -0
  11. package/examples/example-lofi.html +45 -45
  12. package/examples/example-lofi.mp3 +0 -0
  13. package/examples/example-minimal.html +21 -19
  14. package/examples/example-minimal.mp3 +0 -0
  15. package/examples/example-orchestral.html +67 -67
  16. package/examples/example-orchestral.mp3 +0 -0
  17. package/examples/example-piano.html +53 -0
  18. package/examples/example-piano.mp3 +0 -0
  19. package/examples/example-techno.html +69 -69
  20. package/examples/example-techno.mp3 +0 -0
  21. package/package.json +42 -24
  22. package/registry/presets/bass-electric.html +67 -0
  23. package/registry/presets/bass-saw.html +22 -0
  24. package/registry/presets/chord-progression.html +22 -0
  25. package/registry/presets/drums-808.html +85 -0
  26. package/registry/presets/drums-lofi.html +35 -0
  27. package/registry/presets/lead-piano.html +26 -0
  28. package/registry/presets/piano-salamander.html +69 -0
  29. package/registry/presets/reverb-warm.html +11 -0
  30. package/registry/samples.json +226 -0
  31. package/skills/audio-ambient/SKILL.md +141 -0
  32. package/skills/audio-ambient/example.html +113 -0
  33. package/skills/audio-boss-battle/SKILL.md +157 -0
  34. package/skills/audio-boss-battle/example.html +185 -0
  35. package/skills/audio-boss-battle/example.mp3 +0 -0
  36. package/skills/audio-chillwave/SKILL.md +142 -0
  37. package/skills/audio-chillwave/example.html +144 -0
  38. package/skills/audio-cinematic/SKILL.md +147 -0
  39. package/skills/audio-cinematic/example.html +123 -0
  40. package/skills/audio-classical/SKILL.md +138 -0
  41. package/skills/audio-classical/example.html +145 -0
  42. package/skills/audio-dnb/SKILL.md +142 -0
  43. package/skills/audio-dnb/example.html +124 -0
  44. package/skills/audio-downtempo/SKILL.md +152 -0
  45. package/skills/audio-downtempo/example.html +164 -0
  46. package/skills/audio-folk/SKILL.md +139 -0
  47. package/skills/audio-folk/example.html +132 -0
  48. package/skills/audio-funk/SKILL.md +149 -0
  49. package/skills/audio-funk/example.html +144 -0
  50. package/skills/audio-future-bass/SKILL.md +163 -0
  51. package/skills/audio-future-bass/example.html +164 -0
  52. package/skills/audio-hip-hop/SKILL.md +133 -0
  53. package/skills/audio-hip-hop/example.html +129 -0
  54. package/skills/audio-house/SKILL.md +147 -0
  55. package/skills/audio-house/example.html +128 -0
  56. package/skills/audio-indie-pop/SKILL.md +150 -0
  57. package/skills/audio-indie-pop/example.html +121 -0
  58. package/skills/audio-jazz/SKILL.md +141 -0
  59. package/skills/audio-jazz/example.html +146 -0
  60. package/skills/audio-lofi/SKILL.md +140 -0
  61. package/skills/audio-lofi/example.html +135 -0
  62. package/skills/audio-minimal/SKILL.md +155 -0
  63. package/skills/audio-minimal/example.html +118 -0
  64. package/skills/audio-orchestral/SKILL.md +156 -0
  65. package/skills/audio-orchestral/example.html +140 -0
  66. package/skills/audio-r-and-b/SKILL.md +134 -0
  67. package/skills/audio-r-and-b/example.html +154 -0
  68. package/skills/audio-r-and-b/example.mp3 +0 -0
  69. package/skills/audio-techno/SKILL.md +140 -0
  70. package/skills/audio-techno/example.html +125 -0
  71. package/skills/audio-trap/SKILL.md +123 -0
  72. package/skills/audio-trap/example.html +119 -0
  73. package/skills/render-retest/example.html +115 -0
  74. package/skills/tuneframes/SKILL.md +221 -0
  75. package/skills/tuneframes-cli/SKILL.md +46 -0
  76. package/skills/verify/example.html +104 -0
  77. package/src/cli.js +261 -89
  78. package/src/render.js +134 -7
@@ -0,0 +1,145 @@
1
+ <div id="tuneframes" style="display:none">{"bpm":104,"duration":"12s"}</div>
2
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.49/Tone.js"></script>
3
+ <script>
4
+ // TuneFrames — Classical Piano
5
+ // C major, Allegro moderato (104 BPM)
6
+ // Right hand: melodic line with ornamental turn
7
+ // Left hand: Alberti bass (bass-upper-inner-upper pattern)
8
+ // Harmony: I → V → vi → IV → V → I (complete progression)
9
+
10
+ async function main() {
11
+ await Tone.start();
12
+
13
+ Tone.Transport.bpm.value = 104;
14
+
15
+ const beat = 60 / 104; // 0.577s per quarter note
16
+ const eighth = beat / 2; // 0.288s per eighth note
17
+ const sixteenth = beat / 4; // 0.144s per sixteenth note
18
+
19
+ // ── Small room reverb — a piano in a parlour, not a concert hall ──────────
20
+ const reverb = new Tone.Reverb({ decay: 1.1, preDelay: 0.008, wet: 0.22 });
21
+ await reverb.generate();
22
+ reverb.toDestination();
23
+
24
+ // ── Right hand — melody voice, triangle wave ──────────────────────────────
25
+ const rh = new Tone.Synth({
26
+ oscillator: { type: 'triangle' },
27
+ envelope: { attack: 0.006, decay: 0.22, sustain: 0.18, release: 1.4 },
28
+ volume: -4,
29
+ });
30
+ rh.connect(reverb);
31
+
32
+ // ── Left hand single notes (bass) — slightly softer, same timbre ─────────
33
+ const lhBass = new Tone.Synth({
34
+ oscillator: { type: 'triangle' },
35
+ envelope: { attack: 0.008, decay: 0.35, sustain: 0.12, release: 1.0 },
36
+ volume: -10,
37
+ });
38
+ lhBass.connect(reverb);
39
+
40
+ // ── Left hand chord notes (inner voices of Alberti) ───────────────────────
41
+ const lhChord = new Tone.PolySynth(Tone.Synth, {
42
+ oscillator: { type: 'triangle' },
43
+ envelope: { attack: 0.008, decay: 0.3, sustain: 0.1, release: 0.9 },
44
+ volume: -13,
45
+ });
46
+ lhChord.connect(reverb);
47
+
48
+ // ─────────────────────────────────────────────────────────────────────────
49
+ // Helper: schedule an Alberti bass pattern for one bar using direct time
50
+ // root = bass note (e.g. 'C3'), inner = e.g. 'E3', upper = e.g. 'G3'
51
+ // Pattern of 8 eighth notes: root upper inner upper root upper inner upper
52
+ // ─────────────────────────────────────────────────────────────────────────
53
+ function alberti(root, inner, upper, startTime) {
54
+ const pattern = [root, upper, inner, upper, root, upper, inner, upper];
55
+ pattern.forEach((note, i) => {
56
+ const t = startTime + i * eighth;
57
+ if (i % 2 === 0) {
58
+ lhBass.triggerAttackRelease(note, '8n', t);
59
+ } else {
60
+ lhChord.triggerAttackRelease(note, '8n', t);
61
+ }
62
+ });
63
+ }
64
+
65
+ // ─────────────────────────────────────────────────────────────────────────
66
+ // Harmony plan (one bar each, 4 beats = beat*4 per bar):
67
+ // Bar 1: I — C major (C3 E3 G3)
68
+ // Bar 2: V — G major (G2 B2 D3)
69
+ // Bar 3: vi — A minor (A2 C3 E3)
70
+ // Bar 4: IV — F major (F2 A2 C3)
71
+ // Bar 5: V — G major (G2 B2 D3)
72
+ // Bar 6: I — C major (C3 E3 G3) — final resolution
73
+ // ─────────────────────────────────────────────────────────────────────────
74
+ const barLen = beat * 4;
75
+
76
+ alberti('C3', 'E3', 'G3', 0); // I
77
+ alberti('G2', 'B2', 'D3', barLen); // V
78
+ alberti('A2', 'C3', 'E3', barLen * 2); // vi
79
+ alberti('F2', 'A2', 'C3', barLen * 3); // IV
80
+ alberti('G2', 'B2', 'D3', barLen * 4); // V
81
+ alberti('C3', 'E3', 'G3', barLen * 5); // I (final)
82
+
83
+ // ─────────────────────────────────────────────────────────────────────────
84
+ // Right hand melody — stepwise, fits the chord above
85
+ // Phrase 1 (bars 1-2): C major scale ascending, quarter + eighth mix
86
+ // Phrase 2 (bars 3-4): descent with ornamental turn on E5
87
+ // Phrase 3 (bars 5-6): cadential figure, landing on C5
88
+ // ─────────────────────────────────────────────────────────────────────────
89
+
90
+ // Phrase 1: ascending C major scale with rhythmic variety
91
+ const phrase1 = [
92
+ { note: 'C5', dur: '4n', t: 0 },
93
+ { note: 'D5', dur: '8n', t: beat },
94
+ { note: 'E5', dur: '8n', t: beat + eighth },
95
+ { note: 'F5', dur: '4n', t: beat * 2 },
96
+ { note: 'G5', dur: '4n', t: beat * 3 },
97
+ // Bar 2: hold G5, then step up to A5
98
+ { note: 'G5', dur: '8n', t: barLen },
99
+ { note: 'A5', dur: '8n', t: barLen + eighth },
100
+ { note: 'G5', dur: '4n', t: barLen + beat },
101
+ { note: 'F5', dur: '4n', t: barLen + beat * 2 },
102
+ { note: 'E5', dur: '4n', t: barLen + beat * 3 },
103
+ ];
104
+
105
+ // Phrase 2: ornamental turn on E5 (F E D E), then descent
106
+ const turnStart = barLen * 2;
107
+ const turn = [
108
+ { note: 'F5', dur: '16n', t: turnStart },
109
+ { note: 'E5', dur: '16n', t: turnStart + sixteenth },
110
+ { note: 'D5', dur: '16n', t: turnStart + sixteenth * 2 },
111
+ { note: 'E5', dur: '8n', t: turnStart + sixteenth * 3 },
112
+ ];
113
+ const phrase2 = [
114
+ ...turn,
115
+ { note: 'D5', dur: '4n', t: turnStart + beat },
116
+ { note: 'C5', dur: '4n', t: turnStart + beat * 2 },
117
+ { note: 'B4', dur: '4n', t: turnStart + beat * 3 },
118
+ // Bar 4:
119
+ { note: 'A4', dur: '4n', t: barLen * 3 },
120
+ { note: 'G4', dur: '8n', t: barLen * 3 + beat },
121
+ { note: 'A4', dur: '8n', t: barLen * 3 + beat + eighth },
122
+ { note: 'C5', dur: '2n', t: barLen * 3 + beat * 2 },
123
+ ];
124
+
125
+ // Phrase 3: cadential figure V → I landing
126
+ const p3start = barLen * 4;
127
+ const phrase3 = [
128
+ { note: 'B4', dur: '4n', t: p3start },
129
+ { note: 'D5', dur: '4n', t: p3start + beat },
130
+ { note: 'G5', dur: '4n', t: p3start + beat * 2 },
131
+ { note: 'F5', dur: '4n', t: p3start + beat * 3 },
132
+ // Bar 6: resolution to I — long final note
133
+ { note: 'E5', dur: '8n', t: barLen * 5 },
134
+ { note: 'D5', dur: '8n', t: barLen * 5 + eighth },
135
+ { note: 'C5', dur: '2n', t: barLen * 5 + beat },
136
+ ];
137
+
138
+ // Schedule all right hand notes using direct time offsets (seconds)
139
+ [...phrase1, ...phrase2, ...phrase3].forEach(({ note, dur, t }) => {
140
+ if (t < 12) {
141
+ rh.triggerAttackRelease(note, dur, t);
142
+ }
143
+ });
144
+ }
145
+ </script>
@@ -0,0 +1,142 @@
1
+ ---
2
+ name: audio-dnb
3
+ description: Drum and Bass — syncopated Amen-style breakbeat, reese bass with chorus and filter, atmospheric pad, heavy sub frequencies. Hard hitting and kinetic.
4
+ ---
5
+
6
+ # TuneFrames — Drum and Bass
7
+
8
+ ## Genre Profile
9
+ - BPM range: 165–180
10
+ - Key characteristics: Complex syncopated breakbeat (kick not on the beat — that's the point), heavy Reese bass (sawtooth + chorus + filter), atmospheric pad underneath, powerful sub frequencies, kinetic forward momentum
11
+ - Typical instruments: MembraneSynth (kick), NoiseSynth (snare), MetalSynth (hi-hat), FMSynth or MonoSynth (Reese bass), PolySynth (pad)
12
+ - Mood: Intense, kinetic, dark, cerebral, euphoric at the peak
13
+
14
+ ## Core Pattern
15
+
16
+ ```js
17
+ // Drum and Bass — 174 BPM
18
+ // Breakbeat: kick/snare NOT on beats 1,2,3,4 — syncopated Amen-style
19
+ // Reese bass: sawtooth + heavy chorus = that "wobble" character
20
+ // Pad: slow attack, atmospheric underneath
21
+
22
+ // Classic DnB breakbeat (Amen-style, 16-step)
23
+ // K=kick, S=snare, .=rest
24
+ // K . . S . K K S . . K . S . K S (feel, not strict)
25
+ const breakPattern = [
26
+ "kick", null, null, "snare", null, "kick", "kick", "snare",
27
+ null, null, "kick", null, "snare", null, "kick", "snare"
28
+ ];
29
+
30
+ new Tone.Sequence((time, hit) => {
31
+ if (hit === "kick") kick.triggerAttackRelease("C1", "8n", time);
32
+ if (hit === "snare") snare.triggerAttackRelease("16n", time);
33
+ }, breakPattern, "16n").start(0);
34
+
35
+ // Reese bass — sawtooth through chorus
36
+ const chorus = new Tone.Chorus({ frequency: 1.8, delayTime: 3.5, depth: 0.7, wet: 0.7 });
37
+ const filter = new Tone.Filter({ frequency: 800, type: "lowpass", Q: 2 });
38
+ const reese = new Tone.MonoSynth({
39
+ oscillator: { type: "sawtooth" },
40
+ envelope: { attack: 0.01, decay: 0.5, sustain: 0.8, release: 0.3 },
41
+ volume: -4
42
+ }).chain(chorus, filter, Tone.Destination);
43
+ chorus.start();
44
+
45
+ Tone.Transport.bpm.value = 174;
46
+ Tone.Transport.start();
47
+ ```
48
+
49
+ ## Instrument Configuration
50
+
51
+ ```js
52
+ // Kick — short, punchy, low
53
+ const kick = new Tone.MembraneSynth({
54
+ pitchDecay: 0.04,
55
+ octaves: 5,
56
+ envelope: { attack: 0.001, decay: 0.2, sustain: 0, release: 0.08 },
57
+ volume: 2
58
+ }).toDestination();
59
+
60
+ // Snare — crisp, with slight room
61
+ const snareVerb = new Tone.Reverb({ decay: 0.5, wet: 0.15 }).toDestination();
62
+ const snare = new Tone.NoiseSynth({
63
+ noise: { type: "white" },
64
+ envelope: { attack: 0.001, decay: 0.12, sustain: 0, release: 0.04 },
65
+ volume: -2
66
+ }).connect(snareVerb);
67
+
68
+ // Hi-hat — very fast, adds texture between beats
69
+ const hat = new Tone.MetalSynth({
70
+ frequency: 500, harmonicity: 5.1, modulationIndex: 32,
71
+ resonance: 4500, octaves: 1.5,
72
+ envelope: { attack: 0.001, decay: 0.035, release: 0.01 },
73
+ volume: -12
74
+ }).toDestination();
75
+
76
+ // Reese bass — the DnB defining sound
77
+ // Two detuned sawtooths + heavy chorus + filter
78
+ const reeseLimiter = new Tone.Limiter(-4).toDestination();
79
+ const reeseFilter = new Tone.Filter({ frequency: 700, type: "lowpass", Q: 3 }).connect(reeseLimiter);
80
+ const reeseChorus = new Tone.Chorus({
81
+ frequency: 1.8, // slow chorus = the "reese" movement
82
+ delayTime: 3.5,
83
+ depth: 0.75,
84
+ wet: 0.75
85
+ }).connect(reeseFilter);
86
+ reeseChorus.start();
87
+ const reese = new Tone.MonoSynth({
88
+ oscillator: { type: "sawtooth" },
89
+ filter: { Q: 1, type: "lowpass", frequency: 2000 },
90
+ filterEnvelope: { attack: 0.02, decay: 0.5, sustain: 0.5, release: 0.5,
91
+ baseFrequency: 200, octaves: 2 },
92
+ envelope: { attack: 0.01, decay: 0.3, sustain: 0.8, release: 0.3 },
93
+ volume: -2
94
+ }).connect(reeseChorus);
95
+
96
+ // Atmospheric pad — slow attack, long release
97
+ const padVerb = new Tone.Reverb({ decay: 5.0, wet: 0.7 }).toDestination();
98
+ const pad = new Tone.PolySynth(Tone.Synth, {
99
+ oscillator: { type: "sawtooth4" },
100
+ envelope: { attack: 0.6, decay: 1.0, sustain: 0.6, release: 2.5 },
101
+ volume: -14
102
+ }).connect(padVerb);
103
+ ```
104
+
105
+ ## Composition Structure
106
+
107
+ - **Bar 1-2:** Breakbeat only — establish the syncopated groove immediately
108
+ - **Bar 3-4:** Add hi-hat fills between kick/snare — density builds
109
+ - **Bar 5-8:** Add Reese bass — low sustained notes, filter opens slowly
110
+ - **Bar 9-16:** Full arrangement — breakbeat + Reese + atmospheric pad
111
+ - **Variation bar:** Every 4 bars, drop a kick or add a snare roll for surprise
112
+ - **Reese movement:** Filter automation — close at bar 5, sweep open over bar 6-8, close and re-open
113
+ - **Outro:** Break strip — just pad remains, then breakbeat returns for exit
114
+
115
+ The breakbeat is the identity. The kick landing OFF the downbeat is what separates DnB from techno — resist putting the kick on beat 1. The snare DOES land around beats 2 and 4 but offset slightly.
116
+
117
+ ## Example Variations
118
+
119
+ ### 1 — Half-time feel bridge
120
+ ```js
121
+ // Every 8 bars, drop to a 2-step pattern (kick-snare only) for 1 bar
122
+ // Builds tension before the full break returns
123
+ const halfTimeBar = ["kick", null, null, null, null, null, null, null,
124
+ null, null, null, null, "snare", null, null, null];
125
+ ```
126
+
127
+ ### 2 — Reese filter wobble (1/4 note LFO)
128
+ ```js
129
+ // LFO modulating the Reese filter — creates rhythmic wobble
130
+ const lfo = new Tone.LFO({ frequency: "4n", min: 200, max: 2000, type: "sine" });
131
+ lfo.connect(reeseFilter.frequency);
132
+ lfo.start();
133
+ ```
134
+
135
+ ### 3 — Snare roll into drop
136
+ ```js
137
+ // 16th-note snare roll over the last bar before a new section
138
+ // Schedule 8 snare hits in last bar
139
+ for (let i = 0; i < 8; i++) {
140
+ snare.triggerAttackRelease("32n", `${barStart} + ${i * 0.107}`, 0.3 + i * 0.087);
141
+ }
142
+ ```
@@ -0,0 +1,124 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>TuneFrames — Drum and Bass</title>
6
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.49/Tone.js"></script>
7
+ </head>
8
+ <body>
9
+ <!-- TuneFrames Metadata -->
10
+ <div id="tuneframes" style="display:none">{"bpm":174,"duration":"12s"}</div>
11
+
12
+ <script>
13
+ async function main() {
14
+ await Tone.start();
15
+ Tone.Transport.bpm.value = 174;
16
+
17
+ // --- MASTER BUS ---
18
+ const masterLimiter = new Tone.Limiter(-1).toDestination();
19
+ const masterGain = new Tone.Gain(0.87).connect(masterLimiter);
20
+
21
+ // --- KICK — short, punchy, sub-heavy ---
22
+ const kickGain = new Tone.Gain(0.9).connect(masterGain);
23
+ const kick = new Tone.MembraneSynth({
24
+ pitchDecay: 0.038,
25
+ octaves: 5,
26
+ envelope: { attack: 0.001, decay: 0.18, sustain: 0, release: 0.07 }
27
+ }).connect(kickGain);
28
+
29
+ // --- SNARE — crisp white noise ---
30
+ const snareVerb = new Tone.Reverb({ decay: 0.45, wet: 0.14 }).connect(masterGain);
31
+ const snareGain = new Tone.Gain(0.65).connect(snareVerb);
32
+ const snare = new Tone.NoiseSynth({
33
+ noise: { type: "white" },
34
+ envelope: { attack: 0.001, decay: 0.11, sustain: 0, release: 0.035 }
35
+ }).connect(snareGain);
36
+
37
+ // --- HI-HAT — fast texture between beats ---
38
+ const hatGain = new Tone.Gain(0.28).connect(masterGain);
39
+ const hat = new Tone.MetalSynth({
40
+ frequency: 520,
41
+ envelope: { attack: 0.001, decay: 0.032, release: 0.01 },
42
+ harmonicity: 5.1,
43
+ modulationIndex: 32,
44
+ resonance: 4600,
45
+ octaves: 1.5
46
+ }).connect(hatGain);
47
+
48
+ // --- REESE BASS — MonoSynth sawtooth + Chorus + Filter ---
49
+ // The Reese is the defining DnB sound: two slightly detuned saws = chorus
50
+ const reeseLimiter = new Tone.Limiter(-4).connect(masterGain);
51
+ const reeseFilter = new Tone.Filter({ frequency: 500, type: "lowpass", Q: 2.5 }).connect(reeseLimiter);
52
+ const reeseChorus = new Tone.Chorus({
53
+ frequency: 1.7,
54
+ delayTime: 3.5,
55
+ depth: 0.78,
56
+ wet: 0.72
57
+ }).connect(reeseFilter);
58
+ reeseChorus.start();
59
+ const reese = new Tone.MonoSynth({
60
+ oscillator: { type: "sawtooth" },
61
+ filter: { Q: 1.5, type: "lowpass", frequency: 3000 },
62
+ filterEnvelope: {
63
+ attack: 0.02, decay: 0.6, sustain: 0.5, release: 0.4,
64
+ baseFrequency: 180, octaves: 2.5
65
+ },
66
+ envelope: { attack: 0.008, decay: 0.4, sustain: 0.8, release: 0.35 },
67
+ volume: 0
68
+ }).connect(reeseChorus);
69
+
70
+ // --- ATMOSPHERIC PAD — slow attack, very wet reverb ---
71
+ const padVerb = new Tone.Reverb({ decay: 5.5, wet: 0.72 }).connect(masterGain);
72
+ const padGain = new Tone.Gain(0.45).connect(padVerb);
73
+ const pad = new Tone.PolySynth(Tone.Synth, {
74
+ oscillator: { type: "sawtooth4" },
75
+ envelope: { attack: 0.7, decay: 1.2, sustain: 0.6, release: 3.0 },
76
+ volume: -2
77
+ }).connect(padGain);
78
+
79
+ // --- BREAKBEAT PATTERN — syncopated Amen-style ---
80
+ // K=kick, S=snare, h=hat, .=rest
81
+ // Pattern: . . S . K K S . . K . S K . S h
82
+ const breakSeq = new Tone.Sequence((time, hit) => {
83
+ if (hit === "K") kick.triggerAttackRelease("C1", "8n", time);
84
+ if (hit === "S") snare.triggerAttackRelease("16n", time, 0.85);
85
+ if (hit === "s") snare.triggerAttackRelease("16n", time, 0.45); // ghost snare
86
+ if (hit === "h") hat.triggerAttackRelease("32n", time, 0.5);
87
+ }, [
88
+ null, "h", "S", null, "K", "K", "S", null,
89
+ "h", "K", null, "S", "K", "h", "S", "h"
90
+ ], "16n");
91
+ breakSeq.start(0);
92
+
93
+ // --- REESE BASS LINE — D minor, sustained long notes ---
94
+ // Reese bass plays whole-bar notes — the filter movement IS the melody
95
+ const reeseLine = [
96
+ { note: "D1", dur: "1m", time: "2m" },
97
+ { note: "C1", dur: "1m", time: "3m" },
98
+ { note: "Bb0", dur: "1m", time: "4m" },
99
+ { note: "A0", dur: "1m", time: "5m" },
100
+ { note: "D1", dur: "1m", time: "6m" },
101
+ { note: "F1", dur: "1m", time: "7m" },
102
+ ];
103
+ reeseLine.forEach(({ note, dur, time }) => {
104
+ reese.triggerAttackRelease(note, dur, time);
105
+ });
106
+
107
+ // Filter sweep on Reese — opens over bars 3-5, closes back bar 6-7
108
+ const sweepStart = Tone.Time("2m").toSeconds();
109
+ reeseFilter.frequency.setValueAtTime(300, sweepStart);
110
+ reeseFilter.frequency.exponentialRampToValueAtTime(2200, sweepStart + 4);
111
+ reeseFilter.frequency.exponentialRampToValueAtTime(250, sweepStart + 5.5);
112
+ reeseFilter.frequency.exponentialRampToValueAtTime(1800, sweepStart + 9);
113
+
114
+ // --- PAD — atmospheric Dm chord, enters at bar 4 ---
115
+ const padNotes = ["D3", "F3", "A3", "C4"]; // Dm7
116
+ pad.triggerAttackRelease(padNotes, "4m", "3m");
117
+ pad.triggerAttackRelease(["C3", "Eb3", "G3", "Bb3"], "4m", "7m"); // Cm7
118
+
119
+ }
120
+
121
+ main();
122
+ </script>
123
+ </body>
124
+ </html>
@@ -0,0 +1,152 @@
1
+ ---
2
+ name: audio-downtempo
3
+ description: Downtempo / Trip-Hop — dark cinematic groove, Portishead/Massive Attack vibes, breakbeat swing, vinyl texture, sub bass
4
+ ---
5
+
6
+ # TuneFrames — Downtempo / Trip-Hop
7
+
8
+ ## Genre Profile
9
+ - BPM range: 70-90 (always swung — 16th notes have a lazy late feel)
10
+ - Key characteristics: heavy breakbeat (kick NOT on every beat — syncopated), vinyl noise texture, sub bass movement on root notes, eerie/minor melodic line, gritty filter on everything
11
+ - Typical instruments: MembraneSynth kick, NoiseSynth snare + crackle, MonoSynth sub bass with lowpass filter, AMSynth for eerie melody, BitCrusher for lo-fi grit
12
+ - Mood: gritty, hypnotic, paranoid, late-night cinematic
13
+
14
+ ## Core Pattern
15
+
16
+ ```js
17
+ // Trip-hop breakbeat — NOT four-on-the-floor
18
+ // Kick: 0, 3, 5 (in 8ths) — heavy, off-balance feel
19
+ // Snare: 2, 6 (on 2 and 4 but swung)
20
+ // BPM = 82, swung feel via manual timing offsets
21
+ Tone.Transport.bpm.value = 82;
22
+
23
+ // Lo-fi grit filter
24
+ const bitCrusher = new Tone.BitCrusher(6).toDestination();
25
+ const reverb = new Tone.Reverb({ decay: 4.0, wet: 0.6 });
26
+ reverb.toDestination();
27
+ const filter = new Tone.Filter({ frequency: 2000, type: 'lowpass', rolloff: -24 });
28
+ filter.connect(reverb);
29
+
30
+ // Sub bass — the backbone
31
+ const bass = new Tone.MonoSynth({
32
+ oscillator: { type: 'sine' },
33
+ filter: { Q: 2, frequency: 120, type: 'lowpass' },
34
+ envelope: { attack: 0.02, decay: 0.3, sustain: 0.6, release: 0.4 },
35
+ volume: -4,
36
+ }).toDestination();
37
+
38
+ // Eerie melody — AMSynth gives that trembling quality
39
+ const melody = new Tone.AMSynth({
40
+ harmonicity: 2.5,
41
+ envelope: { attack: 0.15, decay: 0.5, sustain: 0.3, release: 1.0 },
42
+ volume: -12,
43
+ });
44
+ melody.connect(filter);
45
+
46
+ // Breakbeat kick — syncopated
47
+ const kick = new Tone.MembraneSynth({
48
+ pitchDecay: 0.08, octaves: 10,
49
+ envelope: { attack: 0.001, decay: 0.5, sustain: 0, release: 0.1 },
50
+ volume: -2,
51
+ }).toDestination();
52
+
53
+ // Schedule kick on syncopated positions (seconds at 82 BPM, 1 beat = ~0.73s)
54
+ // Pattern over 2 bars (~5.85s): kick on beat 1, the "and" of 2, beat 3.5
55
+ const beatLen = 60 / 82;
56
+ [0, beatLen * 1.5, beatLen * 3, beatLen * 4, beatLen * 5.5, beatLen * 7].forEach(t => {
57
+ Tone.Transport.scheduleOnce(time => kick.triggerAttackRelease('C1', '8n', time), t);
58
+ });
59
+ ```
60
+
61
+ ## Instrument Configuration
62
+
63
+ ```js
64
+ // BitCrusher — vinyl artifact simulation
65
+ const bitCrusher = new Tone.BitCrusher(7); // lower = grittier
66
+ bitCrusher.toDestination();
67
+
68
+ // Dark reverb
69
+ const reverb = new Tone.Reverb({ decay: 5.0, preDelay: 0.03, wet: 0.65 });
70
+ await reverb.generate();
71
+ reverb.toDestination();
72
+
73
+ // Vinyl crackle — pink noise at very low volume, always running
74
+ const crackle = new Tone.NoiseSynth({
75
+ noise: { type: 'pink' },
76
+ envelope: { attack: 0.1, decay: 0.1, sustain: 1.0, release: 0.1 },
77
+ volume: -32,
78
+ }).toDestination();
79
+ crackle.triggerAttack(); // sustain forever
80
+
81
+ // Sub bass — pure sine, filtered hard
82
+ const bass = new Tone.MonoSynth({
83
+ oscillator: { type: 'sine' },
84
+ filter: { Q: 3, frequency: 100, type: 'lowpass', rolloff: -24 },
85
+ filterEnvelope: { attack: 0.05, decay: 0.5, sustain: 0.3, release: 0.8, baseFrequency: 60, octaves: 1.5 },
86
+ envelope: { attack: 0.02, decay: 0.2, sustain: 0.6, release: 0.5 },
87
+ volume: -3,
88
+ }).toDestination();
89
+
90
+ // Eerie lead — AMSynth with tremolo-like modulation
91
+ const lead = new Tone.AMSynth({
92
+ harmonicity: 3,
93
+ oscillator: { type: 'sawtooth' },
94
+ envelope: { attack: 0.2, decay: 0.8, sustain: 0.4, release: 2.0 },
95
+ modulation: { type: 'sine' },
96
+ modulationEnvelope: { attack: 0.5, decay: 0.0, sustain: 1.0, release: 0.5 },
97
+ volume: -14,
98
+ }).connect(reverb);
99
+
100
+ // Heavy kick
101
+ const kick = new Tone.MembraneSynth({
102
+ pitchDecay: 0.1, octaves: 12,
103
+ envelope: { attack: 0.001, decay: 0.6, sustain: 0, release: 0.15 },
104
+ volume: -1,
105
+ }).toDestination();
106
+
107
+ // Snare — layered noise (pink for body, white for crack)
108
+ const snare = new Tone.NoiseSynth({
109
+ noise: { type: 'pink' },
110
+ envelope: { attack: 0.001, decay: 0.18, sustain: 0, release: 0.12 },
111
+ volume: -8,
112
+ }).toDestination();
113
+ ```
114
+
115
+ ## Composition Structure
116
+
117
+ 1. **Crackle intro (0-2s):** Vinyl crackle only — establishes grit and atmosphere.
118
+ 2. **Bass enters (2-4s):** Sub bass plays the root. No other elements yet. Heavy.
119
+ 3. **Beat drop (4-6s):** Kick + snare syncopated breakbeat joins. Still just bass + beat.
120
+ 4. **Melody (6-12s):** AMSynth eerie melody over the groove. Should feel like it doesn't quite fit — that's correct.
121
+ 5. **Full loop (12s+):** All elements. Melody repeats with slight variation.
122
+
123
+ **Bass movement (minor feel):**
124
+ - Root: D2 → A2 → F2 → G2 (4 beats each)
125
+ - Melody follows but at half speed — slower, more ominous
126
+
127
+ ## Example Variations
128
+
129
+ ### Variation 1: Pure Portishead (drum + bass only)
130
+ ```js
131
+ // No melody — just kick, snare, bass, crackle
132
+ // Bass line has more movement: D2 → C2 → Bb1 → A1 (descending chromatic minor)
133
+ // Snare gets a slight BitCrusher: bitCrusher.connect(snare output)
134
+ // This is the most "hip-hop foundation" version
135
+ ```
136
+
137
+ ### Variation 2: Cinematic (add string texture)
138
+ ```js
139
+ // PolySynth triangle wave simulating strings
140
+ // Very long attack: 3.0s, release: 4.0s
141
+ // Notes: Dm chord sustaining throughout (D3, F3, A3)
142
+ // Volume: -20 — barely audible shimmer behind the groove
143
+ ```
144
+
145
+ ### Variation 3: Faster / more aggressive
146
+ ```js
147
+ Tone.Transport.bpm.value = 92;
148
+ // BitCrusher lower: 5 (crunchier)
149
+ // Kick volume: 0 (0dB — very present)
150
+ // Add 16th hi-hats at -24dB just for texture
151
+ // Lead melody shorter notes: 0.1s decay instead of 0.8s
152
+ ```