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,133 @@
1
+ ---
2
+ name: audio-hip-hop
3
+ description: Boom Bap Hip Hop — punchy kick, snare on 2 and 4 with reverb tail, shuffled 16th hi-hats with swing, smooth bass line, warm soul-pad. Pete Rock / J Dilla / Madlib head-nod groove.
4
+ ---
5
+
6
+ # TuneFrames — Boom Bap Hip Hop
7
+
8
+ ## Genre Profile
9
+ - BPM range: 80–95 (slow enough to feel heavy)
10
+ - Key characteristics: Heavy kick with short distortion (MembraneSynth), snare strictly on beats 2 and 4 with long reverb tail, 16th-note hi-hats with Tone.Transport swing (0.4–0.6) for the shuffle, smooth chromatic bass line, warm pad chord with slow attack for "sampled soul" texture
11
+ - Typical instruments: MembraneSynth (kick), NoiseSynth (snare), MetalSynth or NoiseSynth (hat), MonoSynth or Synth (bass), PolySynth (pad)
12
+ - Mood: Head-nodding, soulful, heavy, hypnotic, dusty
13
+
14
+ ## Core Pattern
15
+
16
+ ```js
17
+ // Boom Bap — 88 BPM, F minor, 2-bar loop
18
+ // Swing makes this: 16th hat offbeats push back into shuffle territory
19
+ // Kick: beat 1 + syncopated ghost hit | Snare: beats 2 and 4 | Hat: 16ths shuffled
20
+
21
+ Tone.Transport.bpm.value = 88;
22
+ Tone.Transport.swing = 0.5; // full swing — offbeat 16ths pushed back
23
+ Tone.Transport.swingSubdivision = "16n";
24
+
25
+ // Kick: beat 1, "and" of beat 2, beat 3 (classic boom bap syncopation)
26
+ new Tone.Sequence((time, val) => {
27
+ if (val) kick.triggerAttackRelease("C1", "8n", time);
28
+ }, ["C1",null,null,null,null,null,"C1",null,"C1",null,null,null,null,null,null,null], "16n").start(0);
29
+ // beat1 and-of-2 beat3
30
+
31
+ // Snare: strictly 2 and 4
32
+ new Tone.Sequence((time, val) => {
33
+ if (val) snare.triggerAttackRelease("8n", time);
34
+ }, [null,null,null,null,1,null,null,null,null,null,null,null,1,null,null,null], "16n").start(0);
35
+
36
+ // Hi-hat: all 16ths with alternating velocity — swing does the shuffle work
37
+ const hatVels = [0.9,0.45,0.85,0.4,0.9,0.45,0.85,0.4,0.9,0.45,0.9,0.4,0.85,0.45,0.9,0.45];
38
+ let hatStep = 0;
39
+ new Tone.Sequence((time) => {
40
+ hat.triggerAttackRelease("16n", time, hatVels[hatStep++ % 16]);
41
+ }, new Array(16).fill(1), "16n").start(0);
42
+
43
+ Tone.Transport.start();
44
+ ```
45
+
46
+ ## Instrument Configuration
47
+
48
+ ```js
49
+ // Kick — MembraneSynth with slight saturation (the "punchy" sound)
50
+ const kickDist = new Tone.Distortion({ distortion: 0.2, wet: 0.4 }).toDestination();
51
+ const kick = new Tone.MembraneSynth({
52
+ pitchDecay: 0.07,
53
+ octaves: 6,
54
+ envelope: { attack: 0.001, decay: 0.32, sustain: 0, release: 0.1 },
55
+ volume: 0
56
+ }).connect(kickDist);
57
+
58
+ // Snare — white noise with a long reverb tail (the "room" sound)
59
+ const snareVerb = new Tone.Reverb({ decay: 1.8, wet: 0.5 }).toDestination();
60
+ const snare = new Tone.NoiseSynth({
61
+ noise: { type: "white" },
62
+ envelope: { attack: 0.001, decay: 0.2, sustain: 0, release: 0.06 },
63
+ volume: -4
64
+ }).connect(snareVerb);
65
+
66
+ // Hi-hat — crisp, short, metallic
67
+ const hat = new Tone.MetalSynth({
68
+ frequency: 500,
69
+ envelope: { attack: 0.001, decay: 0.04, release: 0.01 },
70
+ harmonicity: 5.1,
71
+ modulationIndex: 24,
72
+ resonance: 4000,
73
+ octaves: 1.2,
74
+ volume: -12
75
+ }).toDestination();
76
+
77
+ // Bass — MonoSynth, smooth but defined
78
+ const bass = new Tone.MonoSynth({
79
+ oscillator: { type: "sawtooth" },
80
+ filter: { Q: 2, type: "lowpass", rolloff: -12 },
81
+ filterEnvelope: { attack: 0.01, decay: 0.2, sustain: 0.4, release: 0.3,
82
+ baseFrequency: 120, octaves: 1.5 },
83
+ envelope: { attack: 0.01, decay: 0.15, sustain: 0.7, release: 0.3 },
84
+ volume: -4
85
+ }).toDestination();
86
+
87
+ // Soul pad — warm PolySynth, slow attack = "reverse sample" texture
88
+ const padVerb = new Tone.Reverb({ decay: 3.5, wet: 0.5 }).toDestination();
89
+ const pad = new Tone.PolySynth(Tone.Synth, {
90
+ oscillator: { type: "triangle" },
91
+ envelope: { attack: 0.6, decay: 0.5, sustain: 0.7, release: 2.0 },
92
+ volume: -14
93
+ }).connect(padVerb);
94
+ ```
95
+
96
+ ## Composition Structure
97
+
98
+ - **Bar 1:** Kick + snare + hat only — establish the swung groove, feel the shuffle
99
+ - **Bars 2–4:** Add bass — smooth line following Fm → Cm → Bb → Eb
100
+ - **Bars 5–8:** Add soul pad — Fm7 chord with slow attack, warm
101
+ - **Bars 9–16:** Full groove — all elements, occasionally double the kick for variation
102
+ - **Half-time bar:** Every 4–8 bars, simplify to kick on beat 1 only — creates space then snaps back
103
+
104
+ Dilla technique: vary the kick pattern slightly each 2 bars instead of looping the exact same hit positions. Use a step counter to swap between two kick pattern arrays.
105
+
106
+ ## Example Variations
107
+
108
+ ### 1 — "Dilla" floating kick (pattern alternates every 2 bars)
109
+ ```js
110
+ const kickPatterns = [
111
+ ["C1",null,null,null,null,null,"C1",null,"C1",null,null,null,null,null,null,null],
112
+ ["C1",null,null,null,null,null,null,null,"C1",null,"C1",null,null,null,null,null],
113
+ ];
114
+ let bar = 0;
115
+ new Tone.Sequence((time, val) => {
116
+ if (val) kick.triggerAttackRelease("C1", "8n", time);
117
+ }, kickPatterns[Math.floor(bar++ / 16) % 2], "16n").start(0);
118
+ ```
119
+
120
+ ### 2 — Swing amount variation (lighter shuffle)
121
+ ```js
122
+ // 0.3 = light shuffle (more "straight"), 0.5 = full triplet swing, 0.15 = barely swung
123
+ Tone.Transport.swing = 0.35; // Pete Rock feel — noticeable but not extreme
124
+ ```
125
+
126
+ ### 3 — Open hi-hat accent on beat 4
127
+ ```js
128
+ // Add an open hi-hat (longer decay) on step 12 for groove
129
+ const openHat = new Tone.MetalSynth({ ...hat options..., envelope: { decay: 0.18 } }).toDestination();
130
+ const openHatSeq = new Tone.Sequence((time, val) => {
131
+ if (val) openHat.triggerAttackRelease("8n", time, 0.7);
132
+ }, [null,null,null,null,null,null,null,null,null,null,null,null,1,null,null,null], "16n").start(0);
133
+ ```
@@ -0,0 +1,129 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>TuneFrames — Boom Bap Hip Hop</title>
6
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.49/Tone.js"></script>
7
+ </head>
8
+ <body>
9
+ <!-- TuneFrames Metadata — must be JSON textContent, not data attributes -->
10
+ <div id="tuneframes" style="display:none">{"bpm":88,"duration":"12s"}</div>
11
+
12
+ <script>
13
+ async function main() {
14
+ await Tone.start();
15
+
16
+ // Set BPM so Tone.Time string values resolve correctly
17
+ Tone.Transport.bpm.value = 88;
18
+
19
+ const beat = Tone.Time("4n").toSeconds(); // ~0.682s at 88 BPM
20
+ const s16 = beat / 4; // 16th note ~0.170s
21
+ const bar = beat * 4; // 1 bar ~2.727s
22
+ const numBars = 4; // 4 bars ~10.9s (fits in 12s)
23
+
24
+ // --- MASTER BUS ---
25
+ const masterLimiter = new Tone.Limiter(-1).toDestination();
26
+ const masterGain = new Tone.Gain(0.82).connect(masterLimiter);
27
+
28
+ // --- KICK — punchy MembraneSynth ---
29
+ const kickDist = new Tone.Distortion({ distortion: 0.2, wet: 0.4 }).connect(masterGain);
30
+ const kickGain = new Tone.Gain(0.88).connect(kickDist);
31
+ const kick = new Tone.MembraneSynth({
32
+ pitchDecay: 0.07,
33
+ octaves: 6,
34
+ envelope: { attack: 0.001, decay: 0.32, sustain: 0, release: 0.1 }
35
+ }).connect(kickGain);
36
+
37
+ // --- SNARE — white noise with reverb tail ---
38
+ const snareVerb = new Tone.Reverb({ decay: 1.8, wet: 0.5 }).connect(masterGain);
39
+ const snareGain = new Tone.Gain(0.52).connect(snareVerb);
40
+ const snare = new Tone.NoiseSynth({
41
+ noise: { type: "white" },
42
+ envelope: { attack: 0.001, decay: 0.2, sustain: 0, release: 0.06 }
43
+ }).connect(snareGain);
44
+
45
+ // --- HI-HAT — MetalSynth, short and crisp ---
46
+ const hatGain = new Tone.Gain(0.28).connect(masterGain);
47
+ const hat = new Tone.MetalSynth({
48
+ frequency: 500,
49
+ envelope: { attack: 0.001, decay: 0.04, release: 0.01 },
50
+ harmonicity: 5.1,
51
+ modulationIndex: 24,
52
+ resonance: 4000,
53
+ octaves: 1.2
54
+ }).connect(hatGain);
55
+
56
+ // --- BASS — MonoSynth with filter envelope ---
57
+ const bassGain = new Tone.Gain(0.7).connect(masterGain);
58
+ const bass = new Tone.MonoSynth({
59
+ oscillator: { type: "sawtooth" },
60
+ filter: { Q: 2, type: "lowpass", rolloff: -12 },
61
+ filterEnvelope: {
62
+ attack: 0.01, decay: 0.2, sustain: 0.4, release: 0.3,
63
+ baseFrequency: 120, octaves: 1.5
64
+ },
65
+ envelope: { attack: 0.01, decay: 0.15, sustain: 0.7, release: 0.3 }
66
+ }).connect(bassGain);
67
+
68
+ // --- SOUL PAD — warm PolySynth, slow attack ---
69
+ const padVerb = new Tone.Reverb({ decay: 3.5, wet: 0.5 }).connect(masterGain);
70
+ const padGain = new Tone.Gain(0.35).connect(padVerb);
71
+ const pad = new Tone.PolySynth(Tone.Synth, {
72
+ oscillator: { type: "triangle" },
73
+ envelope: { attack: 0.6, decay: 0.5, sustain: 0.7, release: 2.0 }
74
+ }).connect(padGain);
75
+
76
+ // --- KICK PATTERN — beat 1, "and" of 2, beat 3 (classic boom bap) ---
77
+ // 16-step grid: positions 0, 6, 8
78
+ for (let b = 0; b < numBars; b++) {
79
+ [0, 6, 8].forEach(step => {
80
+ kick.triggerAttackRelease("C1", beat * 0.5, b * bar + step * s16);
81
+ });
82
+ }
83
+
84
+ // --- SNARE — strictly beats 2 and 4 (steps 4 and 12) ---
85
+ for (let b = 0; b < numBars; b++) {
86
+ [4, 12].forEach(step => {
87
+ snare.triggerAttackRelease(beat * 0.5, b * bar + step * s16);
88
+ });
89
+ }
90
+
91
+ // --- HI-HAT — all 16 steps per bar, velocity variation adds humanity ---
92
+ const hatVels = [0.9,0.45,0.85,0.4,0.9,0.45,0.85,0.4,0.9,0.45,0.9,0.4,0.85,0.45,0.9,0.45];
93
+ for (let b = 0; b < numBars; b++) {
94
+ for (let s = 0; s < 16; s++) {
95
+ hat.triggerAttackRelease(s16 * 0.8, b * bar + s * s16, hatVels[s]);
96
+ }
97
+ }
98
+
99
+ // --- BASS LINE — Fm vamp: 2-bar phrase played twice ---
100
+ // phrase repeats at bars 0-1 and bars 2-3
101
+ const bassPhrase = [
102
+ { step: 0, note: "F1", dur: beat },
103
+ { step: 4, note: "F1", dur: beat * 0.5 },
104
+ { step: 6, note: "C2", dur: beat * 0.5 },
105
+ { step: 8, note: "Eb2", dur: beat * 0.5 },
106
+ { step: 10, note: "D2", dur: beat * 0.5 },
107
+ { step: 12, note: "C2", dur: beat },
108
+ { step: 16, note: "Bb1", dur: beat },
109
+ { step: 20, note: "Bb1", dur: beat * 0.5 },
110
+ { step: 22, note: "F1", dur: beat * 0.5 },
111
+ { step: 24, note: "Ab1", dur: beat * 0.5 },
112
+ { step: 26, note: "G1", dur: beat * 0.5 },
113
+ { step: 28, note: "F1", dur: beat },
114
+ ];
115
+ for (let phrase = 0; phrase < 2; phrase++) {
116
+ bassPhrase.forEach(({ step, note, dur }) => {
117
+ bass.triggerAttackRelease(note, dur, phrase * 2 * bar + step * s16);
118
+ });
119
+ }
120
+
121
+ // --- SOUL PAD — Fm7 bars 0-1, Bbm7 bars 2-3 ---
122
+ pad.triggerAttackRelease(["F3","Ab3","C4","Eb4"], bar * 2, 0);
123
+ pad.triggerAttackRelease(["Bb2","Db3","F3","Ab3"], bar * 2, bar * 2);
124
+ }
125
+
126
+ main();
127
+ </script>
128
+ </body>
129
+ </html>
@@ -0,0 +1,147 @@
1
+ ---
2
+ name: audio-house
3
+ description: Chicago/deep house — 4-on-the-floor kick, clap on 2 and 4, off-beat hi-hat, warm piano chord stabs, bass following the kick. Groovy and soulful.
4
+ ---
5
+
6
+ # TuneFrames — House
7
+
8
+ ## Genre Profile
9
+ - BPM range: 120–128
10
+ - Key characteristics: 4-on-the-floor kick, clap strictly on beats 2 and 4, off-beat open hi-hat on the "and" of every beat, warm chord stabs (7ths and 9ths), bass line locked to kick
11
+ - Typical instruments: MembraneSynth (kick), NoiseSynth (clap), MetalSynth (hi-hat), PolySynth (piano stabs), MonoSynth (bass)
12
+ - Mood: Warm, groovy, hypnotic, soulful, uplifting
13
+
14
+ ## Core Pattern
15
+
16
+ ```js
17
+ // Chicago House — 4/4 at 124 BPM
18
+ // Kick: every beat (1, 2, 3, 4)
19
+ // Clap: beats 2 and 4
20
+ // Hi-hat: off-beat 8th notes ("and" of each beat)
21
+ // Piano stab: 2-bar chord loop with 7th chords
22
+ // Bass: short punchy notes on kick hits + off-beat fills
23
+
24
+ const kick = new Tone.MembraneSynth({
25
+ pitchDecay: 0.05,
26
+ octaves: 6,
27
+ envelope: { attack: 0.001, decay: 0.3, sustain: 0, release: 0.1 }
28
+ }).toDestination();
29
+
30
+ const clap = new Tone.NoiseSynth({
31
+ noise: { type: "white" },
32
+ envelope: { attack: 0.001, decay: 0.12, sustain: 0, release: 0.05 }
33
+ }).toDestination();
34
+
35
+ // Reverb on clap — classic house sound
36
+ const clapReverb = new Tone.Reverb({ decay: 2.5, wet: 0.55 }).toDestination();
37
+ clap.connect(clapReverb);
38
+
39
+ // 16-step kick: 4 on the floor
40
+ new Tone.Sequence((time, val) => {
41
+ if (val) kick.triggerAttackRelease("C1", "8n", time);
42
+ }, ["C1", null, null, null, "C1", null, null, null,
43
+ "C1", null, null, null, "C1", null, null, null], "16n").start(0);
44
+
45
+ // Clap on 2 and 4 (steps 4 and 12 in 16-step)
46
+ new Tone.Sequence((time, val) => {
47
+ if (val) clap.triggerAttackRelease("16n", time);
48
+ }, [null, null, null, null, 1, null, null, null,
49
+ null, null, null, null, 1, null, null, null], "16n").start(0);
50
+
51
+ // Off-beat hi-hat (every other 8th note)
52
+ new Tone.Sequence((time, val) => {
53
+ if (val) hat.triggerAttackRelease("16n", time, 0.6);
54
+ }, [null, null, 1, null, null, null, 1, null,
55
+ null, null, 1, null, null, null, 1, null], "16n").start(0);
56
+
57
+ Tone.Transport.bpm.value = 124;
58
+ Tone.Transport.start();
59
+ ```
60
+
61
+ ## Instrument Configuration
62
+
63
+ ```js
64
+ // Kick — warm, slightly softer than techno
65
+ const kick = new Tone.MembraneSynth({
66
+ pitchDecay: 0.05,
67
+ octaves: 6,
68
+ volume: 0,
69
+ envelope: { attack: 0.001, decay: 0.28, sustain: 0, release: 0.1 }
70
+ }).toDestination();
71
+
72
+ // Clap — snappy noise with heavy reverb tail
73
+ const clapVerb = new Tone.Reverb({ decay: 2.2, wet: 0.5 }).toDestination();
74
+ const clap = new Tone.NoiseSynth({
75
+ noise: { type: "white" },
76
+ envelope: { attack: 0.001, decay: 0.1, sustain: 0, release: 0.04 },
77
+ volume: -4
78
+ }).connect(clapVerb);
79
+
80
+ // Hi-hat — open, airy metallic
81
+ const hat = new Tone.MetalSynth({
82
+ frequency: 300, harmonicity: 3.1, modulationIndex: 16,
83
+ resonance: 3500, octaves: 1.2,
84
+ envelope: { attack: 0.001, decay: 0.08, release: 0.02 },
85
+ volume: -10
86
+ }).toDestination();
87
+
88
+ // Piano stab — warm PolySynth, major 7ths
89
+ const stabChorus = new Tone.Chorus({ frequency: 3, depth: 0.4, wet: 0.3 }).toDestination();
90
+ const stabVerb = new Tone.Reverb({ decay: 1.8, wet: 0.25 }).connect(stabChorus);
91
+ const piano = new Tone.PolySynth(Tone.Synth, {
92
+ oscillator: { type: "triangle" },
93
+ envelope: { attack: 0.01, decay: 0.4, sustain: 0.1, release: 0.6 },
94
+ volume: -8
95
+ }).connect(stabVerb);
96
+
97
+ // Bass — punchy MonoSynth, follows kick
98
+ const bass = new Tone.MonoSynth({
99
+ oscillator: { type: "sawtooth" },
100
+ filter: { Q: 2, type: "lowpass", frequency: 600 },
101
+ filterEnvelope: { attack: 0.001, decay: 0.15, sustain: 0.1, release: 0.2,
102
+ baseFrequency: 100, octaves: 2 },
103
+ envelope: { attack: 0.001, decay: 0.2, sustain: 0.1, release: 0.15 },
104
+ volume: -4
105
+ }).toDestination();
106
+ ```
107
+
108
+ ## Composition Structure
109
+
110
+ - **Bar 1-2:** Kick + hi-hat only — establish 4-on-floor groove
111
+ - **Bar 3-4:** Add clap on 2 and 4 — full drum feel
112
+ - **Bar 5-8:** Add bass — follows kick with short punchy notes
113
+ - **Bar 9-16:** Add piano stabs — 2-bar chord loop, minor 7ths or major 9ths
114
+ - **Bar 17-24:** Full groove — all elements, maybe add a secondary hi-hat accent
115
+ - **Breakdown (bar 25-32):** Drop kick and bass, keep hats + piano — build tension
116
+ - **Drop:** Kick returns hard — full energy re-entry
117
+ - **Outro:** Hi-hat fades, bass drops out, kick last
118
+
119
+ Chord vocabulary (deep house): Fm7 (F-Ab-C-Eb), Bbm9, Ebmaj7, Dbmaj7. Use minor 7ths for darkness, major 7ths for warmth.
120
+
121
+ ## Example Variations
122
+
123
+ ### 1 — Swung 16ths (shuffle feel)
124
+ ```js
125
+ // Apply shuffle to the Transport for a more "human" groove
126
+ Tone.Transport.swing = 0.15;
127
+ Tone.Transport.swingSubdivision = "16n";
128
+ ```
129
+
130
+ ### 2 — Rolling Bass (octave fills between kicks)
131
+ ```js
132
+ // Bass hits on kick + fills in the gaps with octave jumps
133
+ const bassPattern = [
134
+ { note: "A1", dur: "8n" }, { note: null },
135
+ { note: "A2", dur: "16n" }, { note: null }, // octave fill
136
+ { note: "A1", dur: "8n" }, { note: null },
137
+ { note: "A1", dur: "16n" }, { note: "G1", dur: "16n" } // chromatic approach
138
+ ];
139
+ ```
140
+
141
+ ### 3 — Piano Chord Stab Rhythm Variation
142
+ ```js
143
+ // Syncopated stab — off the beat for groove
144
+ // Hit on the "and" of beat 2 and beat 4
145
+ const stabSteps = [null, null, null, null, null, 1, null, null,
146
+ null, null, null, null, null, 1, null, null];
147
+ ```
@@ -0,0 +1,128 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>TuneFrames — House</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":124,"duration":"12s"}</div>
11
+
12
+ <script>
13
+ async function main() {
14
+ await Tone.start();
15
+ Tone.Transport.bpm.value = 124;
16
+
17
+ // --- MASTER BUS ---
18
+ const masterLimiter = new Tone.Limiter(-1).toDestination();
19
+ const masterGain = new Tone.Gain(0.88).connect(masterLimiter);
20
+
21
+ // --- KICK — warm 4-on-the-floor ---
22
+ const kickGain = new Tone.Gain(0.85).connect(masterGain);
23
+ const kick = new Tone.MembraneSynth({
24
+ pitchDecay: 0.055,
25
+ octaves: 6,
26
+ envelope: { attack: 0.001, decay: 0.28, sustain: 0, release: 0.1 }
27
+ }).connect(kickGain);
28
+
29
+ // --- CLAP — white noise with long reverb tail ---
30
+ const clapVerb = new Tone.Reverb({ decay: 2.4, wet: 0.52 }).connect(masterGain);
31
+ const clapGain = new Tone.Gain(0.55).connect(clapVerb);
32
+ const clap = new Tone.NoiseSynth({
33
+ noise: { type: "white" },
34
+ envelope: { attack: 0.001, decay: 0.11, sustain: 0, release: 0.04 }
35
+ }).connect(clapGain);
36
+
37
+ // --- HI-HAT — open off-beat, airy ---
38
+ const hatGain = new Tone.Gain(0.38).connect(masterGain);
39
+ const hat = new Tone.MetalSynth({
40
+ frequency: 300,
41
+ envelope: { attack: 0.001, decay: 0.09, release: 0.025 },
42
+ harmonicity: 3.1,
43
+ modulationIndex: 16,
44
+ resonance: 3600,
45
+ octaves: 1.2
46
+ }).connect(hatGain);
47
+
48
+ // --- PIANO STAB — PolySynth triangle, warm chord stabs ---
49
+ const stabVerb = new Tone.Reverb({ decay: 1.6, wet: 0.28 }).connect(masterGain);
50
+ const stabChorus = new Tone.Chorus({ frequency: 2.5, depth: 0.35, wet: 0.25 }).connect(stabVerb);
51
+ stabChorus.start();
52
+ const stabGain = new Tone.Gain(0.55).connect(stabChorus);
53
+ const piano = new Tone.PolySynth(Tone.Synth, {
54
+ oscillator: { type: "triangle" },
55
+ envelope: { attack: 0.008, decay: 0.35, sustain: 0.08, release: 0.7 },
56
+ volume: 0
57
+ }).connect(stabGain);
58
+
59
+ // --- BASS — punchy, follows kick ---
60
+ const bassGain = new Tone.Gain(0.75).connect(masterGain);
61
+ const bass = new Tone.MonoSynth({
62
+ oscillator: { type: "sawtooth" },
63
+ filter: { Q: 3, type: "lowpass", rolloff: -24 },
64
+ filterEnvelope: {
65
+ attack: 0.001, decay: 0.18, sustain: 0.1, release: 0.2,
66
+ baseFrequency: 90, octaves: 2.2
67
+ },
68
+ envelope: { attack: 0.001, decay: 0.22, sustain: 0.1, release: 0.15 },
69
+ volume: -2
70
+ }).connect(bassGain);
71
+
72
+ // --- SEQUENCES ---
73
+
74
+ // Kick: strict 4-on-the-floor
75
+ const kickSeq = new Tone.Sequence((time) => {
76
+ kick.triggerAttackRelease("C1", "8n", time);
77
+ }, [1, null, null, null, 1, null, null, null,
78
+ 1, null, null, null, 1, null, null, null], "16n");
79
+ kickSeq.start(0);
80
+
81
+ // Clap: beats 2 and 4 only
82
+ const clapSeq = new Tone.Sequence((time, val) => {
83
+ if (val) clap.triggerAttackRelease("16n", time);
84
+ }, [null, null, null, null, 1, null, null, null,
85
+ null, null, null, null, 1, null, null, null], "16n");
86
+ clapSeq.start(0);
87
+
88
+ // Hi-hat: off-beat 8th notes
89
+ const hatSeq = new Tone.Sequence((time, val) => {
90
+ if (val) hat.triggerAttackRelease("16n", time, 0.6);
91
+ }, [null, null, 1, null, null, null, 1, null,
92
+ null, null, 1, null, null, null, 1, null], "16n");
93
+ hatSeq.start(0);
94
+
95
+ // Bass: follows kick + syncopated fills
96
+ // F1 root following the groove
97
+ const bassPattern = [
98
+ "F1", null, null, null, "F1", null, null, "F1",
99
+ "F1", null, "Ab1", null, "F1", null, "Eb1", null
100
+ ];
101
+ const bassSeq = new Tone.Sequence((time, note) => {
102
+ if (note) bass.triggerAttackRelease(note, "16n", time);
103
+ }, bassPattern, "16n");
104
+ bassSeq.start("2m"); // bass enters bar 3
105
+
106
+ // Piano stabs: Fm7 → Bbm7 → Ebmaj7 → Dbmaj7 (2-bar cycle)
107
+ // Deep house chord vocabulary
108
+ const chords = [
109
+ { notes: ["F3", "Ab3", "C4", "Eb4"], time: "4m" }, // Fm7
110
+ { notes: ["Bb2", "Db3", "F3", "Ab3"], time: "4m:2" }, // Bbm7
111
+ { notes: ["Eb3", "G3", "Bb3", "D4"], time: "5m" }, // Ebmaj7
112
+ { notes: ["Db3", "F3", "Ab3", "C4"], time: "5m:2" }, // Dbmaj7
113
+ // repeat
114
+ { notes: ["F3", "Ab3", "C4", "Eb4"], time: "6m" },
115
+ { notes: ["Bb2", "Db3", "F3", "Ab3"], time: "6m:2" },
116
+ { notes: ["Eb3", "G3", "Bb3", "D4"], time: "7m" },
117
+ { notes: ["Db3", "F3", "Ab3", "C4"], time: "7m:2" },
118
+ ];
119
+ chords.forEach(({ notes, time }) => {
120
+ piano.triggerAttackRelease(notes, "4n", time);
121
+ });
122
+
123
+ }
124
+
125
+ main();
126
+ </script>
127
+ </body>
128
+ </html>
@@ -0,0 +1,150 @@
1
+ ---
2
+ name: audio-indie-pop
3
+ description: Indie Pop — jangly pluck arpeggios through chorus/reverb, warm bass, steady kick-snare-hat groove. Vampire Weekend / Tame Impala feel. Major key or Dorian, bright and infectious.
4
+ ---
5
+
6
+ # TuneFrames — Indie Pop
7
+
8
+ ## Genre Profile
9
+ - BPM range: 115–140
10
+ - Key characteristics: Guitar-like arpeggio lines with short pluck envelope (triangle osc, fast decay, low sustain), warm bass on root and 5th, kick on beats 1+3, snare on 2+4, steady 8th-note hi-hat, lush chorus + reverb on guitar synth
11
+ - Typical instruments: PolySynth/Synth (guitar pluck), Synth/MonoSynth (bass), MembraneSynth (kick), NoiseSynth (snare, hat)
12
+ - Mood: Bright, infectious, slightly nostalgic, melodic, danceable
13
+
14
+ ## Core Pattern
15
+
16
+ ```js
17
+ // Indie Pop — 128 BPM, G major
18
+ // Chord progression: G - C - Em - D (4-bar loop)
19
+ // Guitar: 8th note arpeggios with pluck envelope
20
+ // Kick: beats 1 and 3 | Snare: beats 2 and 4 | Hat: 8th notes
21
+
22
+ Tone.Transport.bpm.value = 128;
23
+
24
+ // Effects
25
+ const reverb = new Tone.Reverb({ decay: 2.5, wet: 0.3 }).toDestination();
26
+ const chorus = new Tone.Chorus(3.5, 2.0, 0.6).connect(reverb);
27
+ chorus.start(); // REQUIRED — Chorus LFO must be started manually
28
+
29
+ // Guitar pluck: triangle oscillator, fast attack, short decay, minimal sustain
30
+ const guitar = new Tone.PolySynth(Tone.Synth, {
31
+ oscillator: { type: "triangle" },
32
+ envelope: { attack: 0.005, decay: 0.28, sustain: 0.06, release: 0.7 },
33
+ }).connect(chorus);
34
+
35
+ // 32-note arpeggio grid (8 notes × 4 bars = G, C, Em, D)
36
+ const arpGrid = [
37
+ "G3","B3","D4","G4","D4","B3","G3","B3", // G major
38
+ "C4","E4","G4","C5","G4","E4","C4","E4", // C major
39
+ "E3","G3","B3","E4","B3","G3","E3","G3", // E minor
40
+ "D3","F#3","A3","D4","A3","F#3","D3","F#3", // D major
41
+ ];
42
+ let arpStep = 0;
43
+ const arpSeq = new Tone.Sequence((time) => {
44
+ guitar.triggerAttackRelease(arpGrid[arpStep++ % arpGrid.length], "8n", time);
45
+ }, new Array(8).fill(1), "8n").start(0);
46
+
47
+ // Kick: beats 1 and 3
48
+ new Tone.Sequence((time, val) => {
49
+ if (val) kick.triggerAttackRelease("C1", "8n", time);
50
+ }, ["C1",null,null,null,null,null,null,null,"C1",null,null,null,null,null,null,null], "16n").start(0);
51
+
52
+ // Snare: beats 2 and 4
53
+ new Tone.Sequence((time, val) => {
54
+ if (val) snare.triggerAttackRelease("8n", time);
55
+ }, [null,null,null,null,1,null,null,null,null,null,null,null,1,null,null,null], "16n").start(0);
56
+
57
+ // Hat: 8th notes, quiet
58
+ new Tone.Sequence((time, val) => {
59
+ if (val) hat.triggerAttackRelease("16n", time, 0.5);
60
+ }, [1,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null], "16n").start(0);
61
+
62
+ Tone.Transport.start();
63
+ ```
64
+
65
+ ## Instrument Configuration
66
+
67
+ ```js
68
+ // Guitar pluck — triangle oscillator is key (warmer than sawtooth, brighter than sine)
69
+ const guitarVerb = new Tone.Reverb({ decay: 2.5, wet: 0.3 }).toDestination();
70
+ const guitarChorus = new Tone.Chorus({ frequency: 3.5, delayTime: 2, depth: 0.6, wet: 0.5 }).connect(guitarVerb);
71
+ guitarChorus.start();
72
+ const guitar = new Tone.PolySynth(Tone.Synth, {
73
+ oscillator: { type: "triangle" },
74
+ envelope: { attack: 0.005, decay: 0.28, sustain: 0.06, release: 0.7 },
75
+ volume: -8
76
+ }).connect(guitarChorus);
77
+
78
+ // Bass — sine oscillator for warmth, gentle attack
79
+ const bassVerb = new Tone.Reverb({ decay: 0.6, wet: 0.1 }).toDestination();
80
+ const bass = new Tone.Synth({
81
+ oscillator: { type: "sine" },
82
+ envelope: { attack: 0.05, decay: 0.2, sustain: 0.7, release: 0.4 },
83
+ volume: -4
84
+ }).connect(bassVerb);
85
+
86
+ // Kick — less aggressive than techno, shorter pitch decay
87
+ const kickDist = new Tone.Distortion({ distortion: 0.1, wet: 0.3 }).toDestination();
88
+ const kick = new Tone.MembraneSynth({
89
+ pitchDecay: 0.06, octaves: 5,
90
+ envelope: { attack: 0.001, decay: 0.3, sustain: 0, release: 0.1 },
91
+ volume: -2
92
+ }).connect(kickDist);
93
+
94
+ // Snare — white noise, moderate reverb tail (less than house, more presence)
95
+ const snareVerb = new Tone.Reverb({ decay: 0.8, wet: 0.35 }).toDestination();
96
+ const snare = new Tone.NoiseSynth({
97
+ noise: { type: "white" },
98
+ envelope: { attack: 0.001, decay: 0.15, sustain: 0, release: 0.05 },
99
+ volume: -8
100
+ }).connect(snareVerb);
101
+
102
+ // Hi-hat — highpass filtered noise, quiet
103
+ const hatFilter = new Tone.Filter(7000, "highpass").toDestination();
104
+ const hat = new Tone.NoiseSynth({
105
+ noise: { type: "white" },
106
+ envelope: { attack: 0.001, decay: 0.05, sustain: 0, release: 0.01 },
107
+ volume: -16
108
+ }).connect(hatFilter);
109
+ ```
110
+
111
+ ## Composition Structure
112
+
113
+ - **Bars 1–2:** Guitar arpeggio + hi-hat only — establish the melodic hook
114
+ - **Bars 3–4:** Add kick and snare — drums lock in the groove
115
+ - **Bars 5–8:** Add bass — root + 5th pattern follows chord changes
116
+ - **Bars 9–16:** Full band, all elements — the main verse/chorus loop
117
+ - **Variation:** Add feedback delay on guitar (8th note, 25% wet) for extra spaciousness
118
+ - **Outro:** Drop drums, let guitar arpeggio ring out with reverb tail
119
+
120
+ Chord vocabulary: I–V–vi–IV in any major key (G–D–Em–C is the "axis of awesome"). Dorian mode (e.g., Am–G) adds darkness while keeping the bright groove.
121
+
122
+ ## Example Variations
123
+
124
+ ### 1 — Dorian Mode (darker, Am sound)
125
+ ```js
126
+ // A Dorian: A B C D E F# G — common in Vampire Weekend
127
+ const arpGrid = [
128
+ "A3","C4","E4","A4","E4","C4","A3","C4", // Am
129
+ "G3","B3","D4","G4","D4","B3","G3","B3", // G major
130
+ "D3","F#3","A3","D4","A3","F#3","D3","F#3", // D major
131
+ "E3","G3","B3","E4","B3","G3","E3","G3", // Em
132
+ ];
133
+ ```
134
+
135
+ ### 2 — 16th-note arpeggio (Math rock / faster feel)
136
+ ```js
137
+ // Double the arpeggio speed — 16 notes per bar instead of 8
138
+ const arpGrid = ["G3","B3","D4","G4","D4","B3","G3","B3","D4","G4","B3","D4","G4","B3","D4","G4"]; // G bar
139
+ let arpStep = 0;
140
+ new Tone.Sequence((time) => {
141
+ guitar.triggerAttackRelease(arpGrid[arpStep++ % arpGrid.length], "16n", time);
142
+ }, new Array(16).fill(1), "16n").start(0);
143
+ ```
144
+
145
+ ### 3 — Add feedback delay for shimmer
146
+ ```js
147
+ // Guitar → delay → chorus → reverb
148
+ const delay = new Tone.FeedbackDelay({ delayTime: "8n", feedback: 0.28, wet: 0.22 });
149
+ // Insert: guitar.connect(delay); delay.connect(guitarChorus);
150
+ ```