tuneframes 0.1.1 → 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 (80) hide show
  1. package/LICENSE +166 -166
  2. package/README.md +158 -55
  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 +47 -47
  11. package/examples/example-lofi.html +45 -45
  12. package/examples/example-lofi.mp3 +0 -0
  13. package/examples/example-minimal.html +20 -20
  14. package/examples/example-orchestral.html +67 -67
  15. package/examples/example-orchestral.mp3 +0 -0
  16. package/examples/example-piano.html +52 -52
  17. package/examples/example-piano.mp3 +0 -0
  18. package/examples/example-techno.html +69 -69
  19. package/examples/example-techno.mp3 +0 -0
  20. package/package.json +42 -37
  21. package/registry/presets/bass-electric.html +67 -0
  22. package/registry/presets/bass-saw.html +22 -0
  23. package/registry/presets/chord-progression.html +22 -0
  24. package/registry/presets/drums-808.html +85 -0
  25. package/registry/presets/drums-lofi.html +35 -0
  26. package/registry/presets/lead-piano.html +26 -0
  27. package/registry/presets/piano-salamander.html +69 -0
  28. package/registry/presets/reverb-warm.html +11 -0
  29. package/registry/samples.json +226 -0
  30. package/skills/audio-ambient/SKILL.md +141 -0
  31. package/skills/audio-ambient/example.html +113 -0
  32. package/skills/audio-boss-battle/SKILL.md +157 -0
  33. package/skills/audio-boss-battle/example.html +185 -0
  34. package/skills/audio-boss-battle/example.mp3 +0 -0
  35. package/skills/audio-chillwave/SKILL.md +142 -0
  36. package/skills/audio-chillwave/example.html +144 -0
  37. package/skills/audio-cinematic/SKILL.md +147 -0
  38. package/skills/audio-cinematic/example.html +123 -0
  39. package/skills/audio-classical/SKILL.md +138 -0
  40. package/skills/audio-classical/example.html +145 -0
  41. package/skills/audio-dnb/SKILL.md +142 -0
  42. package/skills/audio-dnb/example.html +124 -0
  43. package/skills/audio-downtempo/SKILL.md +152 -0
  44. package/skills/audio-downtempo/example.html +164 -0
  45. package/skills/audio-folk/SKILL.md +139 -0
  46. package/skills/audio-folk/example.html +132 -0
  47. package/skills/audio-funk/SKILL.md +149 -0
  48. package/skills/audio-funk/example.html +144 -0
  49. package/skills/audio-future-bass/SKILL.md +163 -0
  50. package/skills/audio-future-bass/example.html +164 -0
  51. package/skills/audio-hip-hop/SKILL.md +133 -0
  52. package/skills/audio-hip-hop/example.html +129 -0
  53. package/skills/audio-house/SKILL.md +147 -0
  54. package/skills/audio-house/example.html +128 -0
  55. package/skills/audio-indie-pop/SKILL.md +150 -0
  56. package/skills/audio-indie-pop/example.html +121 -0
  57. package/skills/audio-jazz/SKILL.md +141 -0
  58. package/skills/audio-jazz/example.html +146 -0
  59. package/skills/audio-lofi/SKILL.md +140 -0
  60. package/skills/audio-lofi/example.html +135 -0
  61. package/skills/audio-minimal/SKILL.md +155 -0
  62. package/skills/audio-minimal/example.html +118 -0
  63. package/skills/audio-orchestral/SKILL.md +156 -0
  64. package/skills/audio-orchestral/example.html +140 -0
  65. package/skills/audio-r-and-b/SKILL.md +134 -0
  66. package/skills/audio-r-and-b/example.html +154 -0
  67. package/skills/audio-r-and-b/example.mp3 +0 -0
  68. package/skills/audio-techno/SKILL.md +140 -0
  69. package/skills/audio-techno/example.html +125 -0
  70. package/skills/audio-trap/SKILL.md +123 -0
  71. package/skills/audio-trap/example.html +119 -0
  72. package/skills/render-retest/example.html +115 -0
  73. package/skills/tuneframes/SKILL.md +221 -0
  74. package/skills/tuneframes-cli/SKILL.md +46 -0
  75. package/skills/verify/example.html +104 -0
  76. package/src/cli.js +260 -151
  77. package/src/render.js +134 -7
  78. package/examples/example-bass.mp3 +0 -0
  79. package/examples/example-demo-beat.wav +0 -0
  80. package/examples/example-orchestral.wav +0 -0
@@ -0,0 +1,149 @@
1
+ ---
2
+ name: audio-funk
3
+ description: Funk — slap bass, brass stabs, 16th-note hi-hats, syncopated groove that snaps
4
+ ---
5
+
6
+ # TuneFrames — Funk
7
+
8
+ ## Genre Profile
9
+ - BPM range: 95–115 (the pocket lives around 100–108)
10
+ - Key characteristics: Syncopated 16th-note grid, everything lands on or anticipates the beat, brass stabs on upbeats, rhythm guitar "chank" on the "and" of 2 and 4, bass owns the low end
11
+ - Typical instruments: Slap bass (Synth with fast attack + filter), brass stabs (PolySynth sawtooth, sharp envelope), rhythm guitar (PolySynth pluck), kick (MembraneSynth), tight snare (NoiseSynth), 16th hi-hats (MetalSynth)
12
+ - Mood: Infectious, locked-in, body-moving, celebratory — James Brown, Parliament, Daft Punk, Vulfpeck
13
+
14
+ ## Core Pattern
15
+
16
+ ```js
17
+ // Funk core: 104 BPM, E minor groove
18
+ async function main() {
19
+ await Tone.start();
20
+ Tone.Transport.bpm.value = 104;
21
+
22
+ const s16 = Tone.Time('16n').toSeconds(); // one 16th note
23
+ const q = Tone.Time('4n').toSeconds(); // one beat
24
+
25
+ const dest = new Tone.Gain(1).toDestination();
26
+ const comp = new Tone.Compressor(-18, 4).connect(dest);
27
+
28
+ // ── Slap bass ────────────────────────────────────────────────────────
29
+ const bass = new Tone.Synth({
30
+ oscillator: { type: 'square' },
31
+ envelope: { attack: 0.001, decay: 0.08, sustain: 0.0, release: 0.05 }
32
+ }).connect(comp);
33
+ bass.volume.value = -6;
34
+
35
+ // Classic one-bar funk bass: E on 1, ghost note 16th early, pop on e2-and
36
+ const bassLine = [
37
+ { note: 'E2', time: 0 },
38
+ { note: 'E2', time: s16 * 2 },
39
+ { note: 'G2', time: s16 * 3 },
40
+ { note: 'E2', time: s16 * 4 },
41
+ { note: 'A2', time: s16 * 6 },
42
+ { note: 'E2', time: s16 * 8 },
43
+ { note: 'D2', time: s16 * 10 },
44
+ { note: 'E2', time: s16 * 12 },
45
+ { note: 'G2', time: s16 * 14 },
46
+ ];
47
+ bassLine.forEach(({ note, time }) => bass.triggerAttackRelease(note, '16n', time));
48
+
49
+ // ── Brass stabs (upbeat hits — "and" of 2 and 4) ──────────────────────
50
+ const brass = new Tone.PolySynth(Tone.Synth, {
51
+ oscillator: { type: 'sawtooth' },
52
+ envelope: { attack: 0.005, decay: 0.12, sustain: 0.0, release: 0.08 }
53
+ }).connect(comp);
54
+ brass.volume.value = -12;
55
+
56
+ // Stab on the "and" of beat 2 (s16*9) and "and" of beat 4 (s16*13)
57
+ brass.triggerAttackRelease(['E4','G4','B4'], '16n', s16 * 9);
58
+ brass.triggerAttackRelease(['E4','G4','B4'], '16n', s16 * 13);
59
+
60
+ // ── Tight kick ────────────────────────────────────────────────────────
61
+ const kick = new Tone.MembraneSynth({
62
+ pitchDecay: 0.04, octaves: 6,
63
+ envelope: { attack: 0.001, decay: 0.25, sustain: 0, release: 0.1 }
64
+ }).connect(dest);
65
+ kick.volume.value = -10;
66
+ kick.triggerAttackRelease('C1', '8n', 0); // beat 1
67
+ kick.triggerAttackRelease('C1', '8n', s16 * 10); // beat 2-and-a (syncopated)
68
+
69
+ // ── Snare on 3 ────────────────────────────────────────────────────────
70
+ const snare = new Tone.NoiseSynth({
71
+ noise: { type: 'white' },
72
+ envelope: { attack: 0.001, decay: 0.1, sustain: 0, release: 0.05 }
73
+ }).connect(new Tone.Filter(3500, 'bandpass').connect(dest));
74
+ snare.volume.value = -14;
75
+ snare.triggerAttackRelease('8n', s16 * 8); // beat 3
76
+
77
+ // ── 16th hi-hats ─────────────────────────────────────────────────────
78
+ const hat = new Tone.MetalSynth({
79
+ frequency: 600, harmonicity: 5.1, modulationIndex: 32,
80
+ resonance: 4000, octaves: 1.5,
81
+ envelope: { attack: 0.001, decay: 0.03, release: 0.01 }
82
+ }).connect(dest);
83
+ hat.volume.value = -20;
84
+ for (let i = 0; i < 16; i++) hat.triggerAttackRelease('32n', i * s16);
85
+ }
86
+ ```
87
+
88
+ ## Instrument Configuration
89
+
90
+ ```js
91
+ // Slap bass — square wave, nearly no sustain (percussive pluck feel)
92
+ const bass = new Tone.Synth({
93
+ oscillator: { type: 'square' },
94
+ envelope: { attack: 0.001, decay: 0.08, sustain: 0.0, release: 0.05 }
95
+ });
96
+
97
+ // Rhythm guitar "chank" — bright pluck, bandpass filtered, chord stab
98
+ const guitar = new Tone.PolySynth(Tone.Synth, {
99
+ oscillator: { type: 'triangle' },
100
+ envelope: { attack: 0.003, decay: 0.15, sustain: 0.0, release: 0.08 }
101
+ });
102
+ const guitarFilter = new Tone.Filter(2500, 'bandpass');
103
+ guitar.connect(guitarFilter);
104
+
105
+ // Brass stabs — sawtooth, instant attack, very short decay (punchy, no tail)
106
+ const brass = new Tone.PolySynth(Tone.Synth, {
107
+ oscillator: { type: 'sawtooth' },
108
+ envelope: { attack: 0.005, decay: 0.12, sustain: 0.0, release: 0.08 }
109
+ });
110
+
111
+ // Bus compressor glues everything together (the "pumping" funk feel)
112
+ const comp = new Tone.Compressor({ threshold: -18, ratio: 4, attack: 0.003, release: 0.1 });
113
+ comp.toDestination();
114
+ // Route everything through comp
115
+ [bass, brass, guitar].forEach(s => s.connect(comp));
116
+ ```
117
+
118
+ ## Composition Structure
119
+
120
+ 1. **Intro (0–2s):** Bass alone on the groove, just root and fifth — establish the pocket
121
+ 2. **Drums in (2–4s):** Kick + snare + 16th hats lock with the bass
122
+ 3. **Full band (4–8s):** Brass stabs enter on upbeats, guitar chank fills the midrange
123
+ 4. **Breakdown (8–10s):** Strip to bass + kick only — tension before the re-hit
124
+ 5. **Re-hit (10–12s):** Everything back, maybe add a filter sweep on the bass up
125
+
126
+ ## Example Variations
127
+
128
+ ### 1 — Open hi-hat accent on beat 4
129
+ ```js
130
+ const openHat = new Tone.MetalSynth({ envelope: { decay: 0.25 } }).connect(dest);
131
+ openHat.volume.value = -18;
132
+ openHat.triggerAttackRelease('8n', q * 3); // beat 4 open
133
+ ```
134
+
135
+ ### 2 — Wah filter on brass (auto-wah effect)
136
+ ```js
137
+ const autoWah = new Tone.AutoFilter({ frequency: 4, baseFrequency: 200, octaves: 4, wet: 0.8 });
138
+ autoWah.connect(dest);
139
+ autoWah.start(0);
140
+ brass.connect(autoWah);
141
+ ```
142
+
143
+ ### 3 — Daft Punk-style filtered house funk
144
+ ```js
145
+ // Add LP filter sweep on the bass from 300 Hz to 2000 Hz over 4 bars
146
+ const bassFilter = new Tone.Filter(300, 'lowpass').connect(comp);
147
+ bass.connect(bassFilter);
148
+ bassFilter.frequency.rampTo(2000, bar * 4);
149
+ ```
@@ -0,0 +1,144 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>TuneFrames — Funk</title>
5
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.49/Tone.js"></script>
6
+ </head>
7
+ <body>
8
+ <div id="tuneframes" style="display:none">{"bpm":104,"duration":"12s"}</div>
9
+ <script>
10
+ async function main() {
11
+ await Tone.start();
12
+ Tone.Transport.bpm.value = 104;
13
+
14
+ const s16 = Tone.Time('16n').toSeconds(); // ~0.144s
15
+ const q = Tone.Time('4n').toSeconds(); // ~0.577s
16
+ const bar = Tone.Time('1n').toSeconds(); // ~2.308s
17
+
18
+ // ── Bus compressor (the funk glue) ──────────────────────────────────
19
+ const comp = new Tone.Compressor({ threshold: -16, ratio: 4, attack: 0.003, release: 0.12 }).toDestination();
20
+ const room = new Tone.Reverb({ decay: 0.6, wet: 0.12 }).connect(comp);
21
+
22
+ // ── Slap bass ───────────────────────────────────────────────────────
23
+ const bassFilter = new Tone.Filter(800, 'lowpass').connect(comp);
24
+ const bass = new Tone.Synth({
25
+ oscillator: { type: 'square' },
26
+ envelope: { attack: 0.001, decay: 0.09, sustain: 0.0, release: 0.04 }
27
+ }).connect(bassFilter);
28
+ bass.volume.value = -4;
29
+
30
+ // One-bar groove in E — repeated 5 times
31
+ const bassPattern = [
32
+ { note: 'E2', t: 0 },
33
+ { note: 'E2', t: s16*2 },
34
+ { note: 'G2', t: s16*3 },
35
+ { note: 'E2', t: s16*4 },
36
+ { note: 'A2', t: s16*6 },
37
+ { note: 'E2', t: s16*8 },
38
+ { note: 'D2', t: s16*10 },
39
+ { note: 'E2', t: s16*12 },
40
+ { note: 'Gb2', t: s16*14 },
41
+ ];
42
+ for (let rep = 0; rep < 5; rep++) {
43
+ bassPattern.forEach(({ note, t }) => bass.triggerAttackRelease(note, '16n', rep * bar + t));
44
+ }
45
+
46
+ // ── Rhythm guitar chank (bandpass, hits on upbeats) ─────────────────
47
+ const guitFilter = new Tone.Filter(2200, 'bandpass').connect(room);
48
+ const guitar = new Tone.PolySynth(Tone.Synth, {
49
+ oscillator: { type: 'triangle' },
50
+ envelope: { attack: 0.003, decay: 0.1, sustain: 0.0, release: 0.06 }
51
+ }).connect(guitFilter);
52
+ guitar.volume.value = -14;
53
+
54
+ // Chank on "and" of 2 (s16*9) and "and" of 4 (s16*13) — classic funk chop
55
+ const chankTimes = [s16 * 9, s16 * 13];
56
+ for (let rep = 0; rep < 5; rep++) {
57
+ chankTimes.forEach(t => {
58
+ guitar.triggerAttackRelease(['E4','G4','B4'], '16n', rep * bar + t);
59
+ });
60
+ }
61
+
62
+ // ── Brass stabs (upbeat, punchy) ────────────────────────────────────
63
+ const brassFilter = new Tone.Filter(4000, 'lowpass').connect(room);
64
+ const brass = new Tone.PolySynth(Tone.Synth, {
65
+ oscillator: { type: 'sawtooth' },
66
+ envelope: { attack: 0.006, decay: 0.13, sustain: 0.0, release: 0.07 }
67
+ }).connect(brassFilter);
68
+ brass.volume.value = -10;
69
+
70
+ // Stabs enter on bar 2 — same upbeat timing as guitar chank
71
+ for (let rep = 1; rep < 5; rep++) {
72
+ [s16 * 9, s16 * 13].forEach(t => {
73
+ brass.triggerAttackRelease(['E4','G4','B4'], '16n', rep * bar + t);
74
+ // Second stab chord a beat later for call-and-response
75
+ brass.triggerAttackRelease(['D4','F4','A4'], '16n', rep * bar + t + s16 * 2);
76
+ });
77
+ }
78
+
79
+ // ── Kick drum ───────────────────────────────────────────────────────
80
+ const kick = new Tone.MembraneSynth({
81
+ pitchDecay: 0.04, octaves: 6,
82
+ envelope: { attack: 0.001, decay: 0.22, sustain: 0, release: 0.08 }
83
+ }).connect(comp);
84
+ kick.volume.value = -8;
85
+
86
+ // Kick pattern: beat 1, then syncopated 16th before beat 3 and on the "a" of 3
87
+ for (let rep = 0; rep < 5; rep++) {
88
+ kick.triggerAttackRelease('C1', '8n', rep * bar); // beat 1
89
+ kick.triggerAttackRelease('C1', '8n', rep * bar + s16 * 7); // "and-a" of 2
90
+ kick.triggerAttackRelease('C1', '8n', rep * bar + s16 * 10); // "and" of 3
91
+ }
92
+
93
+ // ── Snare on 2 and 4 (with ghost notes) ────────────────────────────
94
+ const snareBp = new Tone.Filter(3200, 'bandpass').connect(room);
95
+ const snare = new Tone.NoiseSynth({
96
+ noise: { type: 'white' },
97
+ envelope: { attack: 0.001, decay: 0.11, sustain: 0, release: 0.04 }
98
+ }).connect(snareBp);
99
+ snare.volume.value = -12;
100
+
101
+ const ghostSnare = new Tone.NoiseSynth({
102
+ noise: { type: 'white' },
103
+ envelope: { attack: 0.001, decay: 0.05, sustain: 0, release: 0.02 }
104
+ }).connect(snareBp);
105
+ ghostSnare.volume.value = -26; // quiet ghosts
106
+
107
+ for (let rep = 0; rep < 5; rep++) {
108
+ snare.triggerAttackRelease('8n', rep * bar + q); // beat 2
109
+ snare.triggerAttackRelease('8n', rep * bar + q * 3); // beat 4
110
+ // Ghost notes around beat 3
111
+ ghostSnare.triggerAttackRelease('16n', rep * bar + s16 * 9);
112
+ ghostSnare.triggerAttackRelease('16n', rep * bar + s16 * 11);
113
+ }
114
+
115
+ // ── 16th hi-hats ───────────────────────────────────────────────────
116
+ const hat = new Tone.MetalSynth({
117
+ frequency: 600, harmonicity: 5.1, modulationIndex: 32,
118
+ resonance: 4000, octaves: 1.5,
119
+ envelope: { attack: 0.001, decay: 0.028, release: 0.008 }
120
+ }).connect(comp);
121
+ hat.volume.value = -19;
122
+
123
+ // Full 16th grid, slight accent on quarter notes
124
+ for (let rep = 0; rep < 5; rep++) {
125
+ for (let i = 0; i < 16; i++) {
126
+ hat.triggerAttackRelease('32n', rep * bar + i * s16);
127
+ }
128
+ }
129
+
130
+ // ── Open hi-hat accent on beat 4 of every other bar ────────────────
131
+ const openHat = new Tone.MetalSynth({
132
+ frequency: 400, harmonicity: 3.1, modulationIndex: 12,
133
+ resonance: 2000, octaves: 1.0,
134
+ envelope: { attack: 0.001, decay: 0.22, release: 0.08 }
135
+ }).connect(room);
136
+ openHat.volume.value = -18;
137
+
138
+ for (let rep = 1; rep < 5; rep += 2) {
139
+ openHat.triggerAttackRelease('8n', rep * bar + q * 3);
140
+ }
141
+ }
142
+ </script>
143
+ </body>
144
+ </html>
@@ -0,0 +1,163 @@
1
+ ---
2
+ name: audio-future-bass
3
+ description: Future Bass — wide supersaw chords (fatsawtooth PolySynth), emotional melodic lead, pitched 808 sub, trap-influenced drums, massive chorus/reverb. Flume / San Holo energy. Big, emotional, wide stereo field.
4
+ ---
5
+
6
+ # TuneFrames — Future Bass
7
+
8
+ ## Genre Profile
9
+ - BPM range: 140–160 (half-time groove feel, effective "heard" tempo closer to 70–80)
10
+ - Key characteristics: Supersaw chords (fatsawtooth oscillator, 5–7 unison voices, 30–50 spread), emotional minor-key melody, 808 sub bass (MembraneSynth with long pitchDecay), trap-influenced sparse kick, massive clap with reverb, hi-hat rolls with velocity variation, heavy chorus and reverb on chords
11
+ - Typical instruments: PolySynth/Synth fatsawtooth (supersaw chords), Synth/AMSynth (lead), MembraneSynth (808 + kick), NoiseSynth (clap), MetalSynth (hi-hats)
12
+ - Mood: Euphoric, emotional, uplifting, wide, festival-ready
13
+
14
+ ## Core Pattern
15
+
16
+ ```js
17
+ // Future Bass — 150 BPM, A minor
18
+ // Structure: intro (bars 1–2) → drop (bar 3 onward)
19
+ // Chords: Am – F – C – G (1 bar each, looping)
20
+ // 808 sub follows chord roots with pitch glide
21
+ // Half-time drums: sparse kick, big clap on beat 3
22
+
23
+ Tone.Transport.bpm.value = 150;
24
+
25
+ // Supersaw chord synth — fatsawtooth is the key ingredient
26
+ const chordVerb = new Tone.Reverb({ decay: 4, wet: 0.55 }).toDestination();
27
+ const chordChorus = new Tone.Chorus({ frequency: 0.8, delayTime: 3.5, depth: 0.8, wet: 0.7 }).connect(chordVerb);
28
+ chordChorus.start();
29
+ const chords = new Tone.PolySynth(Tone.Synth, {
30
+ oscillator: { type: "fatsawtooth", count: 5, spread: 40 },
31
+ envelope: { attack: 0.08, decay: 0.2, sustain: 0.75, release: 2.0 },
32
+ volume: -10
33
+ }).connect(chordChorus);
34
+
35
+ // 808 sub — MembraneSynth with long pitch glide
36
+ const sub808Dist = new Tone.Distortion({ distortion: 0.1, wet: 0.25 }).toDestination();
37
+ const sub808 = new Tone.MembraneSynth({
38
+ pitchDecay: 0.45, // the "808 fall" — pitch glides from note down
39
+ octaves: 3,
40
+ envelope: { attack: 0.001, decay: 0.85, sustain: 0, release: 0.4 }
41
+ }).connect(sub808Dist);
42
+
43
+ // Schedule supersaw chords at the drop (bar 3+)
44
+ // One-bar chord stabs with full sustain
45
+ const dropChords = [
46
+ { time: "2m", notes: ["A2","E3","A3","C4","E4"] }, // Am
47
+ { time: "3m", notes: ["F2","C3","F3","A3","C4"] }, // F
48
+ { time: "4m", notes: ["C3","G3","C4","E4","G4"] }, // C
49
+ { time: "5m", notes: ["G2","D3","G3","B3","D4"] }, // G
50
+ ];
51
+ dropChords.forEach(({ time, notes }) => {
52
+ chords.triggerAttackRelease(notes, "1m", time);
53
+ });
54
+
55
+ // 808 bass hits on chord roots — enters with drop
56
+ const subHits = [
57
+ { time: "2m", note: "A2" }, { time: "3m", note: "F2" },
58
+ { time: "4m", note: "C2" }, { time: "5m", note: "G2" },
59
+ ];
60
+ subHits.forEach(({ time, note }) => {
61
+ sub808.triggerAttackRelease(note, "2n", time);
62
+ });
63
+
64
+ Tone.Transport.start();
65
+ ```
66
+
67
+ ## Instrument Configuration
68
+
69
+ ```js
70
+ // Supersaw chords — fatsawtooth + wide chorus is the defining sound
71
+ const chordVerb = new Tone.Reverb({ decay: 4.0, wet: 0.55 }).toDestination();
72
+ const chordChorus = new Tone.Chorus({ frequency: 0.8, delayTime: 3.5, depth: 0.8, wet: 0.7 });
73
+ chordChorus.connect(chordVerb);
74
+ chordChorus.start();
75
+ const chords = new Tone.PolySynth(Tone.Synth, {
76
+ oscillator: { type: "fatsawtooth", count: 5, spread: 40 },
77
+ envelope: { attack: 0.08, decay: 0.2, sustain: 0.75, release: 2.0 },
78
+ volume: -10
79
+ }).connect(chordChorus);
80
+
81
+ // Lead melody — bright, emotional
82
+ const leadVerb = new Tone.Reverb({ decay: 2.5, wet: 0.4 }).toDestination();
83
+ const leadDelay = new Tone.FeedbackDelay({ delayTime: "8n", feedback: 0.3, wet: 0.25 }).connect(leadVerb);
84
+ const lead = new Tone.Synth({
85
+ oscillator: { type: "triangle" },
86
+ envelope: { attack: 0.02, decay: 0.3, sustain: 0.6, release: 1.0 },
87
+ volume: -6
88
+ }).connect(leadDelay);
89
+
90
+ // 808 sub — long pitch decay = the glide
91
+ const sub808Dist = new Tone.Distortion({ distortion: 0.1, wet: 0.25 }).toDestination();
92
+ const sub808 = new Tone.MembraneSynth({
93
+ pitchDecay: 0.45,
94
+ octaves: 3,
95
+ envelope: { attack: 0.001, decay: 0.85, sustain: 0, release: 0.4 },
96
+ volume: 2
97
+ }).connect(sub808Dist);
98
+
99
+ // Trap kick — on beat 1 (half-time feel)
100
+ const kick = new Tone.MembraneSynth({
101
+ pitchDecay: 0.08, octaves: 8,
102
+ envelope: { attack: 0.001, decay: 0.35, sustain: 0, release: 0.1 },
103
+ volume: 0
104
+ }).toDestination();
105
+
106
+ // Clap — big noise transient with long reverb
107
+ const clapVerb = new Tone.Reverb({ decay: 2.8, wet: 0.55 }).toDestination();
108
+ const clap = new Tone.NoiseSynth({
109
+ noise: { type: "white" },
110
+ envelope: { attack: 0.001, decay: 0.18, sustain: 0, release: 0.08 },
111
+ volume: -4
112
+ }).connect(clapVerb);
113
+
114
+ // Hi-hat — trap roll with velocity variation
115
+ const hat = new Tone.MetalSynth({
116
+ frequency: 600, harmonicity: 5.1, modulationIndex: 32,
117
+ resonance: 4500, octaves: 1.5,
118
+ envelope: { attack: 0.001, decay: 0.03, release: 0.01 },
119
+ volume: -12
120
+ }).toDestination();
121
+ ```
122
+
123
+ ## Composition Structure
124
+
125
+ - **Intro (bars 1–2):** Lead melody only with light hi-hats — emotional hook, no chords yet
126
+ - **Build (end of bar 2):** Riser noise (NoiseSynth with rising filter) creates anticipation
127
+ - **Drop (bar 3):** Supersaw chords crash in simultaneously with kick, clap, and 808 sub
128
+ - **Drop loop:** Am–F–C–G chord cycle (1 bar each), 808 follows roots, hats roll
129
+ - **Variation:** Add pitch bend on lead (modulate `lead.detune.value` ±50 cents over 1 bar)
130
+ - **Breakdown:** Mute drums, let chords ring with reverb tail — rebuild tension
131
+ - **Second drop:** Higher register chord voicing, lead octave up
132
+
133
+ Emotional tension technique: during the bar before the drop, cut all sound (or just leave a white noise riser), then everything hits at once — maximum impact.
134
+
135
+ ## Example Variations
136
+
137
+ ### 1 — Wider supersaw (more voices)
138
+ ```js
139
+ // More unison voices = fatter, more expensive but more enormous
140
+ const chords = new Tone.PolySynth(Tone.Synth, {
141
+ oscillator: { type: "fatsawtooth", count: 7, spread: 55 },
142
+ // ...
143
+ });
144
+ ```
145
+
146
+ ### 2 — Filter sweep on drop entry
147
+ ```js
148
+ // Chords start filtered and open up over the first bar of the drop
149
+ const chordFilter = new Tone.Filter({ frequency: 300, type: "lowpass", Q: 2 });
150
+ // chain: chords → chordFilter → chordChorus → chordVerb
151
+ const sweepStart = Tone.Time("2m").toSeconds();
152
+ chordFilter.frequency.setValueAtTime(300, sweepStart);
153
+ chordFilter.frequency.exponentialRampToValueAtTime(12000, sweepStart + Tone.Time("1m").toSeconds());
154
+ ```
155
+
156
+ ### 3 — Pitched chord stab (one-hit per bar)
157
+ ```js
158
+ // Instead of sustained chords, use a sharp pluck attack then let the reverb carry
159
+ const chords = new Tone.PolySynth(Tone.Synth, {
160
+ oscillator: { type: "fatsawtooth", count: 5, spread: 40 },
161
+ envelope: { attack: 0.005, decay: 0.15, sustain: 0, release: 2.5 }, // no sustain = pluck
162
+ });
163
+ ```
@@ -0,0 +1,164 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>TuneFrames — Future 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":150,"duration":"12s"}</div>
11
+
12
+ <script>
13
+ async function main() {
14
+ await Tone.start();
15
+ Tone.Transport.bpm.value = 150;
16
+
17
+ // --- MASTER BUS ---
18
+ const masterLimiter = new Tone.Limiter(-1).toDestination();
19
+ const masterGain = new Tone.Gain(0.82).connect(masterLimiter);
20
+
21
+ // --- SUPERSAW CHORDS — fatsawtooth + wide chorus + huge reverb ---
22
+ const chordVerb = new Tone.Reverb({ decay: 4.0, wet: 0.55 }).connect(masterGain);
23
+ const chordChorus = new Tone.Chorus({ frequency: 0.8, delayTime: 3.5, depth: 0.8, wet: 0.7 }).connect(chordVerb);
24
+ chordChorus.start();
25
+ const chordGain = new Tone.Gain(0.45).connect(chordChorus);
26
+ const chords = new Tone.PolySynth(Tone.Synth, {
27
+ oscillator: { type: "fatsawtooth", count: 5, spread: 40 },
28
+ envelope: { attack: 0.08, decay: 0.2, sustain: 0.75, release: 2.0 },
29
+ volume: 0
30
+ }).connect(chordGain);
31
+
32
+ // --- LEAD — emotional melodic line, triangle + delay ---
33
+ const leadVerb = new Tone.Reverb({ decay: 2.5, wet: 0.4 }).connect(masterGain);
34
+ const leadDelay = new Tone.FeedbackDelay({ delayTime: "8n", feedback: 0.28, wet: 0.25 }).connect(leadVerb);
35
+ const leadGain = new Tone.Gain(0.6).connect(leadDelay);
36
+ const lead = new Tone.Synth({
37
+ oscillator: { type: "triangle" },
38
+ envelope: { attack: 0.02, decay: 0.3, sustain: 0.6, release: 1.0 },
39
+ volume: 0
40
+ }).connect(leadGain);
41
+
42
+ // --- 808 SUB — long pitch glide, saturated ---
43
+ const sub808Dist = new Tone.Distortion({ distortion: 0.12, wet: 0.3 }).connect(masterGain);
44
+ const sub808Gain = new Tone.Gain(0.85).connect(sub808Dist);
45
+ const sub808 = new Tone.MembraneSynth({
46
+ pitchDecay: 0.45,
47
+ octaves: 3,
48
+ envelope: { attack: 0.001, decay: 0.9, sustain: 0, release: 0.4 }
49
+ }).connect(sub808Gain);
50
+
51
+ // --- KICK — trap: sparse, heavy ---
52
+ const kickGain = new Tone.Gain(0.9).connect(masterGain);
53
+ const kick = new Tone.MembraneSynth({
54
+ pitchDecay: 0.08,
55
+ octaves: 8,
56
+ envelope: { attack: 0.001, decay: 0.38, sustain: 0, release: 0.1 }
57
+ }).connect(kickGain);
58
+
59
+ // --- CLAP — big noise with long reverb ---
60
+ const clapVerb = new Tone.Reverb({ decay: 2.8, wet: 0.55 }).connect(masterGain);
61
+ const clapGain = new Tone.Gain(0.55).connect(clapVerb);
62
+ const clap = new Tone.NoiseSynth({
63
+ noise: { type: "white" },
64
+ envelope: { attack: 0.001, decay: 0.18, sustain: 0, release: 0.08 }
65
+ }).connect(clapGain);
66
+
67
+ // --- HI-HAT — trap roll, heavy velocity variation ---
68
+ const hatGain = new Tone.Gain(0.35).connect(masterGain);
69
+ const hat = new Tone.MetalSynth({
70
+ frequency: 600,
71
+ envelope: { attack: 0.001, decay: 0.03, release: 0.01 },
72
+ harmonicity: 5.1,
73
+ modulationIndex: 32,
74
+ resonance: 4500,
75
+ octaves: 1.5
76
+ }).connect(hatGain);
77
+
78
+ // --- PATTERNS ---
79
+
80
+ // Intro lead melody (bars 1–2): emotional minor pentatonic line
81
+ const introLead = [
82
+ { time: "0:0:0", note: "A4", dur: "4n" },
83
+ { time: "0:1:0", note: "G4", dur: "8n" },
84
+ { time: "0:1:2", note: "E4", dur: "8n" },
85
+ { time: "0:2:0", note: "C5", dur: "4n" },
86
+ { time: "0:3:0", note: "A4", dur: "4n" },
87
+ { time: "1:0:0", note: "E4", dur: "2n" },
88
+ { time: "1:2:0", note: "G4", dur: "4n" },
89
+ { time: "1:3:0", note: "A4", dur: "4n" },
90
+ ];
91
+ introLead.forEach(({ time, note, dur }) => {
92
+ lead.triggerAttackRelease(note, dur, time);
93
+ });
94
+
95
+ // Drop lead melody (bars 3–6): brighter, higher register
96
+ const dropLead = [
97
+ { time: "2:0:0", note: "A5", dur: "4n" },
98
+ { time: "2:1:0", note: "G5", dur: "8n" },
99
+ { time: "2:1:2", note: "E5", dur: "8n" },
100
+ { time: "2:2:0", note: "C5", dur: "4n" },
101
+ { time: "2:3:0", note: "A4", dur: "4n" },
102
+ { time: "3:0:0", note: "F5", dur: "2n" },
103
+ { time: "3:2:0", note: "E5", dur: "4n" },
104
+ { time: "3:3:0", note: "D5", dur: "4n" },
105
+ { time: "4:0:0", note: "C5", dur: "2n" },
106
+ { time: "4:2:0", note: "E5", dur: "4n" },
107
+ { time: "4:3:0", note: "G5", dur: "4n" },
108
+ { time: "5:0:0", note: "G5", dur: "2n" },
109
+ { time: "5:2:0", note: "A5", dur: "4n" },
110
+ { time: "5:3:0", note: "G5", dur: "4n" },
111
+ ];
112
+ dropLead.forEach(({ time, note, dur }) => {
113
+ lead.triggerAttackRelease(note, dur, time);
114
+ });
115
+
116
+ // Drop supersaw chords — Am, F, C, G (1 bar each, wide voicings)
117
+ const dropChords = [
118
+ { time: "2m", notes: ["A2","E3","A3","C4","E4"] },
119
+ { time: "3m", notes: ["F2","C3","F3","A3","C4"] },
120
+ { time: "4m", notes: ["C3","G3","C4","E4","G4"] },
121
+ { time: "5m", notes: ["G2","D3","G3","B3","D4"] },
122
+ ];
123
+ dropChords.forEach(({ time, notes }) => {
124
+ chords.triggerAttackRelease(notes, "1m", time);
125
+ });
126
+
127
+ // 808 sub bass — follows chord roots, enters with the drop
128
+ const subHits = [
129
+ { time: "2m", note: "A2" },
130
+ { time: "3m", note: "F2" },
131
+ { time: "4m", note: "C2" },
132
+ { time: "5m", note: "G2" },
133
+ ];
134
+ subHits.forEach(({ time, note }) => {
135
+ sub808.triggerAttackRelease(note, "2n", time);
136
+ });
137
+
138
+ // Kick: half-time feel — beat 1 every bar, plus extra on bar 2 beat 3
139
+ const kickSeq = new Tone.Sequence((time, val) => {
140
+ if (val) kick.triggerAttackRelease("C1", "8n", time);
141
+ }, ["C1",null,null,null,null,null,null,null,"C1",null,null,null,null,null,"C1",null], "16n");
142
+ kickSeq.start("2m");
143
+
144
+ // Clap: half-time snare on beat 3 (step 8 in 16-step)
145
+ const clapSeq = new Tone.Sequence((time, val) => {
146
+ if (val) clap.triggerAttackRelease("8n", time);
147
+ }, [null,null,null,null,null,null,null,null,1,null,null,null,null,null,null,null], "16n");
148
+ clapSeq.start("2m");
149
+
150
+ // Hi-hat: trap roll with velocity variation throughout
151
+ const hatVels = [0.8,0.3,0.7,0.2,0.6,0.3,0.8,0.2,0.7,0.3,0.6,0.2,0.9,0.3,1.0,0.2];
152
+ let hatStep = 0;
153
+ const hatSeq = new Tone.Sequence((time) => {
154
+ hat.triggerAttackRelease("32n", time, hatVels[hatStep % 16]);
155
+ hatStep++;
156
+ }, new Array(16).fill(1), "16n");
157
+ hatSeq.start(0);
158
+
159
+ }
160
+
161
+ main();
162
+ </script>
163
+ </body>
164
+ </html>