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,121 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>TuneFrames — Indie Pop</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":128,"duration":"12s"}</div>
11
+
12
+ <script>
13
+ async function main() {
14
+ await Tone.start();
15
+ Tone.Transport.bpm.value = 128;
16
+
17
+ // --- MASTER BUS ---
18
+ const masterLimiter = new Tone.Limiter(-1).toDestination();
19
+ const masterGain = new Tone.Gain(0.85).connect(masterLimiter);
20
+
21
+ // --- GUITAR — jangly pluck through chorus + reverb ---
22
+ const guitarVerb = new Tone.Reverb({ decay: 2.5, wet: 0.35 }).connect(masterGain);
23
+ const guitarChorus = new Tone.Chorus({ frequency: 3.5, delayTime: 2, depth: 0.6, wet: 0.5 }).connect(guitarVerb);
24
+ guitarChorus.start();
25
+ const guitarGain = new Tone.Gain(0.55).connect(guitarChorus);
26
+ const guitar = new Tone.PolySynth(Tone.Synth, {
27
+ oscillator: { type: "triangle" },
28
+ envelope: { attack: 0.005, decay: 0.28, sustain: 0.06, release: 0.7 },
29
+ volume: 0
30
+ }).connect(guitarGain);
31
+
32
+ // --- BASS — warm sine, root movement ---
33
+ const bassVerb = new Tone.Reverb({ decay: 0.6, wet: 0.1 }).connect(masterGain);
34
+ const bassGain = new Tone.Gain(0.65).connect(bassVerb);
35
+ const bass = new Tone.Synth({
36
+ oscillator: { type: "sine" },
37
+ envelope: { attack: 0.05, decay: 0.2, sustain: 0.7, release: 0.4 },
38
+ volume: 0
39
+ }).connect(bassGain);
40
+
41
+ // --- KICK — punchy but not hard ---
42
+ const kickDist = new Tone.Distortion({ distortion: 0.1, wet: 0.3 }).connect(masterGain);
43
+ const kickGain = new Tone.Gain(0.75).connect(kickDist);
44
+ const kick = new Tone.MembraneSynth({
45
+ pitchDecay: 0.06,
46
+ octaves: 5,
47
+ envelope: { attack: 0.001, decay: 0.3, sustain: 0, release: 0.1 }
48
+ }).connect(kickGain);
49
+
50
+ // --- SNARE — white noise with moderate reverb ---
51
+ const snareVerb = new Tone.Reverb({ decay: 0.9, wet: 0.38 }).connect(masterGain);
52
+ const snareGain = new Tone.Gain(0.45).connect(snareVerb);
53
+ const snare = new Tone.NoiseSynth({
54
+ noise: { type: "white" },
55
+ envelope: { attack: 0.001, decay: 0.15, sustain: 0, release: 0.05 }
56
+ }).connect(snareGain);
57
+
58
+ // --- HI-HAT — highpass filtered, airy ---
59
+ const hatFilter = new Tone.Filter(7000, "highpass").connect(masterGain);
60
+ const hatGain = new Tone.Gain(0.22).connect(hatFilter);
61
+ const hat = new Tone.NoiseSynth({
62
+ noise: { type: "white" },
63
+ envelope: { attack: 0.001, decay: 0.05, sustain: 0, release: 0.01 }
64
+ }).connect(hatGain);
65
+
66
+ // --- ARPEGGIO — 4-bar G–C–Em–D chord cycle, 8th note grid ---
67
+ // 8 notes per bar × 4 bars = 32-note grid, loops seamlessly
68
+ const arpGrid = [
69
+ // Bar 0: G major
70
+ "G3","B3","D4","G4","D4","B3","G3","B3",
71
+ // Bar 1: C major
72
+ "C4","E4","G4","C5","G4","E4","C4","E4",
73
+ // Bar 2: E minor
74
+ "E3","G3","B3","E4","B3","G3","E3","G3",
75
+ // Bar 3: D major
76
+ "D3","F#3","A3","D4","A3","F#3","D3","F#3",
77
+ ];
78
+ let arpStep = 0;
79
+ const arpSeq = new Tone.Sequence((time) => {
80
+ guitar.triggerAttackRelease(arpGrid[arpStep % arpGrid.length], "8n", time);
81
+ arpStep++;
82
+ }, new Array(8).fill(1), "8n");
83
+ arpSeq.start(0);
84
+
85
+ // --- BASS — root + 5th pattern per chord, enters bar 3 ---
86
+ const bassPart = new Tone.Part((time, note) => {
87
+ bass.triggerAttackRelease(note, "4n", time);
88
+ }, [
89
+ ["0:0:0","G2"], ["0:2:0","D2"],
90
+ ["1:0:0","C2"], ["1:2:0","G2"],
91
+ ["2:0:0","E2"], ["2:2:0","B2"],
92
+ ["3:0:0","D2"], ["3:2:0","A2"],
93
+ ]);
94
+ bassPart.loopEnd = "4m";
95
+ bassPart.loop = true;
96
+ bassPart.start("2m");
97
+
98
+ // --- KICK — beats 1 and 3, enters bar 3 ---
99
+ const kickSeq = new Tone.Sequence((time, val) => {
100
+ if (val) kick.triggerAttackRelease("C1", "8n", time);
101
+ }, ["C1",null,null,null,null,null,null,null,"C1",null,null,null,null,null,null,null], "16n");
102
+ kickSeq.start("2m");
103
+
104
+ // --- SNARE — beats 2 and 4, enters bar 3 ---
105
+ const snareSeq = new Tone.Sequence((time, val) => {
106
+ if (val) snare.triggerAttackRelease("8n", time);
107
+ }, [null,null,null,null,1,null,null,null,null,null,null,null,1,null,null,null], "16n");
108
+ snareSeq.start("2m");
109
+
110
+ // --- HI-HAT — 8th notes throughout ---
111
+ const hatSeq = new Tone.Sequence((time, val) => {
112
+ if (val) hat.triggerAttackRelease("16n", time, 0.5);
113
+ }, [1,null,1,null,1,null,1,null,1,null,1,null,1,null,1,null], "16n");
114
+ hatSeq.start(0);
115
+
116
+ }
117
+
118
+ main();
119
+ </script>
120
+ </body>
121
+ </html>
@@ -0,0 +1,141 @@
1
+ ---
2
+ name: audio-jazz
3
+ description: Jazz — ii-V-I changes, extended chords, walking bass, swing feel, bebop melody
4
+ ---
5
+
6
+ # TuneFrames — Jazz
7
+
8
+ ## Genre Profile
9
+ - BPM range: 100–180 (ballad 60–90, bebop 180–240)
10
+ - Key characteristics: ii-V-I progressions, extended/altered chords (maj7, min7, dom7, dim7), swing 8th notes, call-and-response phrasing
11
+ - Typical instruments: Piano (PolySynth), walking upright bass (Synth sine), ride cymbal (MetalSynth), brush snare (NoiseSynth), optional vibraphone
12
+ - Mood: Sophisticated, improvisatory, warm, intellectually alive
13
+
14
+ ## Core Pattern
15
+
16
+ ```js
17
+ // Jazz core: 120 BPM swing, Dm7–G7–Cmaj7 (ii-V-I in C major)
18
+ async function main() {
19
+ await Tone.start();
20
+ Tone.Transport.bpm.value = 120;
21
+
22
+ const reverb = new Tone.Reverb({ decay: 1.8, wet: 0.3 }).toDestination();
23
+
24
+ // ── Piano voicings (shell voicings: root + 3rd + 7th) ─────────────────
25
+ const piano = new Tone.PolySynth(Tone.Synth, {
26
+ oscillator: { type: 'triangle' },
27
+ envelope: { attack: 0.01, decay: 0.4, sustain: 0.5, release: 1.2 }
28
+ }).connect(reverb);
29
+ piano.volume.value = -10;
30
+
31
+ const bar = Tone.Time('1n').toSeconds(); // 1 bar in seconds
32
+
33
+ // ii–V–I–I in C (shell voicings)
34
+ const changes = [
35
+ ['D3','F3','C4'], // Dm7 (ii)
36
+ ['G3','B3','F4'], // G7 (V)
37
+ ['C3','E3','B3'], // Cmaj7 (I)
38
+ ['C3','E3','G3','B3'], // Cmaj7 full (I hold)
39
+ ];
40
+ changes.forEach((ch, i) => piano.triggerAttackRelease(ch, '1n', i * bar));
41
+
42
+ // ── Walking bass (quarter notes, chromatic approach notes) ────────────
43
+ const bass = new Tone.Synth({
44
+ oscillator: { type: 'sine' },
45
+ envelope: { attack: 0.01, decay: 0.1, sustain: 0.6, release: 0.2 }
46
+ }).connect(reverb);
47
+ bass.volume.value = -8;
48
+
49
+ // Classic walking line: D–F–A–C / G–B–D–F / C–E–G–B / C–E–G–C
50
+ const walk = ['D2','F2','A2','C3','G2','B2','D3','F3','C2','E2','G2','B2','C2','E2','G2','C3'];
51
+ const q = Tone.Time('4n').toSeconds();
52
+ walk.forEach((n, i) => bass.triggerAttackRelease(n, '4n', i * q));
53
+
54
+ // ── Ride cymbal (swing pattern: 1–2–ah–3–4–ah) ────────────────────────
55
+ const ride = new Tone.MetalSynth({
56
+ frequency: 250, harmonicity: 5.1, modulationIndex: 16,
57
+ resonance: 4000, octaves: 1.5,
58
+ envelope: { attack: 0.001, decay: 0.3, release: 0.1 }
59
+ }).connect(reverb);
60
+ ride.volume.value = -22;
61
+
62
+ // Swing ride: beats 1, 2 triplet-late, 3, 4 triplet-late
63
+ const swingOffset = q * 0.67; // triplet-swing "ah"
64
+ for (let i = 0; i < 4; i++) {
65
+ ride.triggerAttackRelease('8n', i * bar);
66
+ ride.triggerAttackRelease('8n', i * bar + swingOffset);
67
+ ride.triggerAttackRelease('8n', i * bar + q * 2);
68
+ ride.triggerAttackRelease('8n', i * bar + q * 2 + swingOffset);
69
+ }
70
+ }
71
+ ```
72
+
73
+ ## Instrument Configuration
74
+
75
+ ```js
76
+ // Jazz piano — triangle wave (mellow, not harsh), moderate decay
77
+ const piano = new Tone.PolySynth(Tone.Synth, {
78
+ oscillator: { type: 'triangle' },
79
+ envelope: { attack: 0.01, decay: 0.4, sustain: 0.5, release: 1.2 }
80
+ });
81
+
82
+ // Upright bass feel — pure sine, tight decay, no sustain tail
83
+ const bass = new Tone.Synth({
84
+ oscillator: { type: 'sine' },
85
+ envelope: { attack: 0.01, decay: 0.08, sustain: 0.55, release: 0.15 }
86
+ });
87
+
88
+ // Ride cymbal — low frequency MetalSynth, long decay
89
+ const ride = new Tone.MetalSynth({
90
+ frequency: 250, harmonicity: 5.1, modulationIndex: 16,
91
+ resonance: 4000, octaves: 1.5,
92
+ envelope: { attack: 0.001, decay: 0.3, release: 0.1 }
93
+ });
94
+
95
+ // Brush snare — bandpass-filtered white noise
96
+ const snare = new Tone.NoiseSynth({
97
+ noise: { type: 'white' },
98
+ envelope: { attack: 0.005, decay: 0.1, sustain: 0, release: 0.05 }
99
+ });
100
+ const snareFilter = new Tone.Filter(2500, 'bandpass');
101
+ snare.connect(snareFilter);
102
+
103
+ // Room reverb — short, warm
104
+ const reverb = new Tone.Reverb({ decay: 1.8, wet: 0.3 }).toDestination();
105
+ ```
106
+
107
+ ## Composition Structure
108
+
109
+ 1. **Head in (0–4s):** Piano states the changes, bass walks, ride establishes swing
110
+ 2. **Melody chorus (4–8s):** Bebop-style single-note melody over the changes (arpeggiated +chromatic passing tones)
111
+ 3. **Reharmonization (8–12s):** Tritone sub on the V chord (Db7 instead of G7), piano plays richer voicings
112
+ 4. **Tag / turnaround:** Quick ii-V back to the top, ritardando on the final bar
113
+
114
+ ## Example Variations
115
+
116
+ ### 1 — Tritone substitution on V (G7 → Db7)
117
+ ```js
118
+ // Replace G7 shell with Db7 shell (tritone sub)
119
+ const changes = [
120
+ ['D3','F3','C4'], // Dm7
121
+ ['Db3','F3','B3'], // Db7 (tritone sub for G7)
122
+ ['C3','E3','B3'], // Cmaj7
123
+ ];
124
+ ```
125
+
126
+ ### 2 — Ballad tempo (70 BPM) with rubato melody
127
+ ```js
128
+ Tone.Transport.bpm.value = 70;
129
+ // Hold each chord for 2 bars, melody uses longer note values ('2n', '1n')
130
+ ```
131
+
132
+ ### 3 — Vibraphone color (add shimmer on the I chord)
133
+ ```js
134
+ const vibe = new Tone.PolySynth(Tone.Synth, {
135
+ oscillator: { type: 'sine' },
136
+ envelope: { attack: 0.005, decay: 1.5, sustain: 0.2, release: 2.0 }
137
+ });
138
+ const vibeVib = new Tone.Vibrato({ frequency: 5, depth: 0.05 }).connect(reverb);
139
+ vibe.connect(vibeVib);
140
+ vibe.triggerAttackRelease(['C4','E4','G4','B4'], '2n', barStart);
141
+ ```
@@ -0,0 +1,146 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>TuneFrames — Jazz</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":132,"duration":"12s"}</div>
9
+ <script>
10
+ async function main() {
11
+ await Tone.start();
12
+ Tone.Transport.bpm.value = 132;
13
+
14
+ // ── Effects ─────────────────────────────────────────────────────────
15
+ const reverb = new Tone.Reverb({ decay: 1.6, preDelay: 0.01, wet: 0.28 }).toDestination();
16
+ await reverb.ready;
17
+
18
+ // ── Piano — shell voicings (3rd + 7th on top) ───────────────────────
19
+ const piano = new Tone.PolySynth(Tone.Synth, {
20
+ oscillator: { type: 'triangle' },
21
+ envelope: { attack: 0.008, decay: 0.35, sustain: 0.5, release: 1.4 }
22
+ }).connect(reverb);
23
+ piano.volume.value = -10;
24
+
25
+ const bar = Tone.Time('1n').toSeconds();
26
+ const q = Tone.Time('4n').toSeconds();
27
+
28
+ // ii–V–I–vi turnaround in C major (2 full passes = 8 bars)
29
+ // Bar layout: Dm7 | G7 | Cmaj7 | Am7 | repeat
30
+ const changes = [
31
+ { chord: ['D3','F3','C4'], dur: '1n' }, // Dm7
32
+ { chord: ['G2','B2','F3'], dur: '1n' }, // G7
33
+ { chord: ['C3','E3','B3'], dur: '1n' }, // Cmaj7
34
+ { chord: ['A2','C3','G3','E4'], dur: '1n' }, // Am7
35
+ { chord: ['D3','F3','C4'], dur: '1n' }, // Dm7 (repeat)
36
+ { chord: ['Db3','F3','B3'], dur: '1n' }, // Db7 (tritone sub)
37
+ { chord: ['C3','E3','B3','G4'], dur: '2n' }, // Cmaj7
38
+ { chord: ['G2','B2','F3'], dur: '2n' }, // G7 (turnaround)
39
+ ];
40
+ let t = 0;
41
+ changes.forEach(({ chord, dur }) => {
42
+ piano.triggerAttackRelease(chord, dur, t);
43
+ t += Tone.Time(dur).toSeconds();
44
+ });
45
+
46
+ // ── Walking bass ────────────────────────────────────────────────────
47
+ const bass = new Tone.Synth({
48
+ oscillator: { type: 'sine' },
49
+ envelope: { attack: 0.008, decay: 0.09, sustain: 0.55, release: 0.15 }
50
+ }).connect(reverb);
51
+ bass.volume.value = -6;
52
+
53
+ // 8-bar walking line (one note per beat = 32 quarter notes)
54
+ const walkLine = [
55
+ // Bar 1 Dm7
56
+ 'D2','F2','A2','C3',
57
+ // Bar 2 G7
58
+ 'G2','B2','D3','F3',
59
+ // Bar 3 Cmaj7
60
+ 'C3','E2','G2','B2',
61
+ // Bar 4 Am7
62
+ 'A2','C3','E3','G2',
63
+ // Bar 5 Dm7 (chromatic approach)
64
+ 'D2','Eb2','E2','F2',
65
+ // Bar 6 Db7 (tritone)
66
+ 'Db3','Ab2','F2','Eb2',
67
+ // Bar 7 Cmaj7
68
+ 'C2','G2','E2','B2',
69
+ // Bar 8 G7
70
+ 'G2','Ab2','A2','B2',
71
+ ];
72
+ walkLine.forEach((n, i) => bass.triggerAttackRelease(n, '4n', i * q));
73
+
74
+ // ── Ride cymbal (jazz swing pattern) ────────────────────────────────
75
+ const ride = new Tone.MetalSynth({
76
+ frequency: 240, harmonicity: 5.1, modulationIndex: 16,
77
+ resonance: 4000, octaves: 1.5,
78
+ envelope: { attack: 0.001, decay: 0.28, release: 0.08 }
79
+ }).connect(reverb);
80
+ ride.volume.value = -22;
81
+
82
+ // Swing triplet feel: beat 1, beat 2-and (triplet late), beat 3, beat 4-and
83
+ const swingLate = q * 0.67;
84
+ for (let b = 0; b < 8; b++) {
85
+ const base = b * bar;
86
+ ride.triggerAttackRelease('8n', base);
87
+ ride.triggerAttackRelease('8n', base + swingLate);
88
+ ride.triggerAttackRelease('8n', base + q * 2);
89
+ ride.triggerAttackRelease('8n', base + q * 2 + swingLate);
90
+ }
91
+
92
+ // ── Brush snare on 2 and 4 ──────────────────────────────────────────
93
+ const snareBp = new Tone.Filter(2800, 'bandpass').connect(reverb);
94
+ const snare = new Tone.NoiseSynth({
95
+ noise: { type: 'white' },
96
+ envelope: { attack: 0.004, decay: 0.09, sustain: 0, release: 0.04 }
97
+ }).connect(snareBp);
98
+ snare.volume.value = -26;
99
+
100
+ for (let b = 0; b < 8; b++) {
101
+ snare.triggerAttackRelease('8n', b * bar + q); // beat 2
102
+ snare.triggerAttackRelease('8n', b * bar + q * 3); // beat 4
103
+ }
104
+
105
+ // ── Bebop melody (enters bar 3) ─────────────────────────────────────
106
+ const melody = new Tone.Synth({
107
+ oscillator: { type: 'triangle' },
108
+ envelope: { attack: 0.005, decay: 0.15, sustain: 0.4, release: 0.5 }
109
+ }).connect(reverb);
110
+ melody.volume.value = -12;
111
+
112
+ // Classic bebop phrase: arpeggiated chords + chromatic passing tones
113
+ const phrase = [
114
+ // Over Cmaj7 (bar 3)
115
+ { note: 'G4', time: bar * 2, dur: '8n' },
116
+ { note: 'E4', time: bar * 2 + q * 0.5, dur: '8n' },
117
+ { note: 'C5', time: bar * 2 + q, dur: '8n' },
118
+ { note: 'B4', time: bar * 2 + q * 1.5, dur: '8n' },
119
+ { note: 'A4', time: bar * 2 + q * 2, dur: '8n' },
120
+ { note: 'G4', time: bar * 2 + q * 2.5, dur: '8n' },
121
+ { note: 'F4', time: bar * 2 + q * 3, dur: '4n' },
122
+ // Over Am7 (bar 4)
123
+ { note: 'E4', time: bar * 3 + q * 0.5, dur: '8n' },
124
+ { note: 'C5', time: bar * 3 + q, dur: '8n' },
125
+ { note: 'B4', time: bar * 3 + q * 1.5, dur: '8n' },
126
+ { note: 'A4', time: bar * 3 + q * 2, dur: '4n' },
127
+ { note: 'G4', time: bar * 3 + q * 3, dur: '4n' },
128
+ // Over Dm7 again (bar 5)
129
+ { note: 'D5', time: bar * 4, dur: '8n' },
130
+ { note: 'C5', time: bar * 4 + q * 0.5, dur: '8n' },
131
+ { note: 'A4', time: bar * 4 + q, dur: '8n' },
132
+ { note: 'F4', time: bar * 4 + q * 1.5, dur: '8n' },
133
+ { note: 'E4', time: bar * 4 + q * 2, dur: '4n' },
134
+ { note: 'Eb4', time: bar * 4 + q * 3, dur: '8n' }, // chromatic
135
+ { note: 'D4', time: bar * 4 + q * 3.5, dur: '8n' },
136
+ // Over Db7 (bar 6) — altered sound
137
+ { note: 'Ab4', time: bar * 5, dur: '8n' },
138
+ { note: 'F4', time: bar * 5 + q * 0.5, dur: '8n' },
139
+ { note: 'Db4', time: bar * 5 + q, dur: '4n' },
140
+ { note: 'C4', time: bar * 5 + q * 2, dur: '2n' }, // resolve to C
141
+ ];
142
+ phrase.forEach(({ note, time, dur }) => melody.triggerAttackRelease(note, dur, time));
143
+ }
144
+ </script>
145
+ </body>
146
+ </html>
@@ -0,0 +1,140 @@
1
+ ---
2
+ name: audio-lofi
3
+ description: Lo-fi Hip Hop — dusty jazzy chords, soft keys, muffled drums, chill study vibe
4
+ ---
5
+
6
+ # TuneFrames — Lo-fi Hip Hop
7
+
8
+ ## Genre Profile
9
+ - BPM range: 70–90
10
+ - Key characteristics: Jazz-adjacent chord progressions (Am–F–C–G or ii–V–I extensions), swung/lazy 8th-note feel, heavy reverb + slight LP filter on everything, vinyl warmth
11
+ - Typical instruments: Rhodes/electric piano (PolySynth triangle/sine), soft bass (Synth), MembraneSynth kick filtered low, closed hi-hat (MetalSynth), pad layer
12
+ - Mood: Nostalgic, cozy, introspective, study-focus
13
+
14
+ ## Core Pattern
15
+
16
+ ```js
17
+ // Lo-fi core: 80 BPM, Am–F–C–G, 4 chords × 2 beats each
18
+ async function main() {
19
+ await Tone.start();
20
+ Tone.Transport.bpm.value = 80;
21
+
22
+ // ── Effects chain (everything runs warm and muffled) ──────────────────
23
+ const reverb = new Tone.Reverb({ decay: 3.5, wet: 0.55 }).toDestination();
24
+ const lpFilter = new Tone.Filter(1800, 'lowpass').connect(reverb);
25
+ // Optional: slight tape distortion
26
+ const warm = new Tone.Distortion(0.04).connect(lpFilter);
27
+
28
+ // ── Rhodes-style chords ───────────────────────────────────────────────
29
+ const keys = new Tone.PolySynth(Tone.Synth, {
30
+ oscillator: { type: 'triangle' },
31
+ envelope: { attack: 0.04, decay: 0.3, sustain: 0.7, release: 1.8 }
32
+ }).connect(warm);
33
+ keys.volume.value = -10;
34
+
35
+ // ii–V–I–VI in A minor
36
+ const chords = [
37
+ ['A3','C4','E4'], // Am
38
+ ['F3','A3','C4'], // F maj
39
+ ['C3','E3','G3'], // C maj
40
+ ['G3','B3','D4'], // G maj
41
+ ];
42
+ const step = Tone.Time('2n').toSeconds(); // 2 beats each chord
43
+ chords.forEach((ch, i) => keys.triggerAttackRelease(ch, '2n', i * step));
44
+
45
+ // ── Walking bass ──────────────────────────────────────────────────────
46
+ const bass = new Tone.Synth({
47
+ oscillator: { type: 'sine' },
48
+ envelope: { attack: 0.02, decay: 0.1, sustain: 0.5, release: 0.4 }
49
+ }).connect(lpFilter);
50
+ bass.volume.value = -8;
51
+
52
+ const bassNotes = ['A2', 'F2', 'C2', 'G2'];
53
+ bassNotes.forEach((n, i) => bass.triggerAttackRelease(n, '4n', i * step));
54
+
55
+ // ── Muffled kick (MembraneSynth + deep LP) ────────────────────────────
56
+ const kickFilter = new Tone.Filter(200, 'lowpass').connect(reverb);
57
+ const kick = new Tone.MembraneSynth({
58
+ pitchDecay: 0.05, octaves: 5,
59
+ envelope: { attack: 0.001, decay: 0.4, sustain: 0, release: 0.4 }
60
+ }).connect(kickFilter);
61
+ kick.volume.value = -14;
62
+
63
+ // Kick on beats 1 and 3 (seconds at 80 BPM: beat = 0.75s)
64
+ const beat = 60 / 80;
65
+ [0, beat * 2, beat * 4, beat * 6].forEach(t => kick.triggerAttackRelease('C1', '8n', t));
66
+
67
+ // ── Soft hi-hat ───────────────────────────────────────────────────────
68
+ const hat = new Tone.MetalSynth({
69
+ frequency: 400, envelope: { attack: 0.001, decay: 0.08, release: 0.01 },
70
+ harmonicity: 5.1, modulationIndex: 32, resonance: 4000, octaves: 1.5
71
+ }).connect(reverb);
72
+ hat.volume.value = -24;
73
+
74
+ for (let i = 0; i < 8; i++) {
75
+ hat.triggerAttackRelease('8n', i * beat * 0.5);
76
+ }
77
+ }
78
+ ```
79
+
80
+ ## Instrument Configuration
81
+
82
+ ```js
83
+ // Rhodes feel — triangle oscillator, slow attack, long release
84
+ const keys = new Tone.PolySynth(Tone.Synth, {
85
+ oscillator: { type: 'triangle' },
86
+ envelope: { attack: 0.04, decay: 0.3, sustain: 0.7, release: 1.8 }
87
+ });
88
+
89
+ // Tape warmth — very light distortion before the LP filter
90
+ const tape = new Tone.Distortion(0.04);
91
+ const lp = new Tone.Filter(1800, 'lowpass'); // cuts harsh highs
92
+
93
+ // Lush room reverb
94
+ const reverb = new Tone.Reverb({ decay: 3.5, preDelay: 0.01, wet: 0.55 });
95
+
96
+ // Chain: keys → tape → lp → reverb → destination
97
+ keys.connect(tape); tape.connect(lp); lp.connect(reverb); reverb.toDestination();
98
+
99
+ // Muffled kick — very tight low-pass (200 Hz)
100
+ const kickLp = new Tone.Filter(200, 'lowpass').toDestination();
101
+ const kick = new Tone.MembraneSynth({ pitchDecay: 0.05, octaves: 5 }).connect(kickLp);
102
+
103
+ // Airy hat — kept very quiet, short decay
104
+ const hat = new Tone.MetalSynth({ frequency: 400, envelope: { decay: 0.08 } });
105
+ hat.volume.value = -24;
106
+ hat.connect(reverb);
107
+ ```
108
+
109
+ ## Composition Structure
110
+
111
+ 1. **Intro (0–2s):** Keys enter alone with chord 1, bass follows on beat 2
112
+ 2. **Main loop (2–8s):** Full Am–F–C–G cycle, kick on 1+3, hat 8ths, bass walks roots
113
+ 3. **Variation (8–10s):** Add a simple melody fragment (C5–E5–G5–A5) over the progression
114
+ 4. **Outro:** Let chords ring out with long release, hat fades (volume ramp)
115
+
116
+ ## Example Variations
117
+
118
+ ### 1 — Jazzier chord voicings (7ths)
119
+ ```js
120
+ const chords = [
121
+ ['A3','C4','E4','G4'], // Am7
122
+ ['F3','A3','C4','E4'], // Fmaj7
123
+ ['C3','E3','G3','B3'], // Cmaj7
124
+ ['G3','B3','D4','F4'], // G7
125
+ ];
126
+ ```
127
+
128
+ ### 2 — Slower, dreamier (70 BPM + delay)
129
+ ```js
130
+ Tone.Transport.bpm.value = 70;
131
+ const delay = new Tone.FeedbackDelay('8n.', 0.3).connect(reverb);
132
+ keys.connect(delay); // dotted-8th echo
133
+ ```
134
+
135
+ ### 3 — Add a simple vinyl-crackle effect (noise burst)
136
+ ```js
137
+ const noise = new Tone.Noise('pink').connect(new Tone.Filter(600, 'lowpass').toDestination());
138
+ noise.volume.value = -40;
139
+ noise.start(0).stop('+10');
140
+ ```