hyperframes 0.6.97 → 0.6.98

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 (77) hide show
  1. package/dist/beat-analyzer.global.js +326 -0
  2. package/dist/cli.js +2479 -1961
  3. package/dist/commands/layout-audit.browser.js +86 -0
  4. package/dist/hyperframe-runtime.js +22 -22
  5. package/dist/hyperframe.manifest.json +1 -1
  6. package/dist/hyperframe.runtime.iife.js +22 -22
  7. package/dist/skills/hyperframes-cli/SKILL.md +67 -103
  8. package/dist/skills/hyperframes-cli/references/doctor-browser.md +45 -0
  9. package/dist/skills/hyperframes-cli/references/init-and-scaffold.md +51 -0
  10. package/dist/skills/hyperframes-cli/references/lambda.md +132 -0
  11. package/dist/skills/hyperframes-cli/references/lint-validate-inspect.md +93 -0
  12. package/dist/skills/hyperframes-cli/references/preview-render.md +107 -0
  13. package/dist/skills/hyperframes-cli/references/upgrade-info-misc.md +75 -0
  14. package/dist/studio/assets/hyperframes-player-DgsMQSvV.js +418 -0
  15. package/dist/studio/assets/index-B62bDCQv.css +1 -0
  16. package/dist/studio/assets/index-Ce3pBm_I.js +252 -0
  17. package/dist/studio/assets/{index-HveJ0MuV.js → index-D-ET9M0b.js} +1 -1
  18. package/dist/studio/assets/index-D-bS9Dxx.js +1 -0
  19. package/dist/studio/index.html +2 -2
  20. package/dist/templates/_shared/AGENTS.md +46 -21
  21. package/dist/templates/_shared/CLAUDE.md +16 -14
  22. package/package.json +3 -2
  23. package/dist/pngDecodeBlitWorker.js +0 -239
  24. package/dist/skills/gsap/SKILL.md +0 -240
  25. package/dist/skills/gsap/references/effects.md +0 -297
  26. package/dist/skills/gsap/scripts/extract-audio-data.py +0 -188
  27. package/dist/skills/hyperframes/SKILL.md +0 -491
  28. package/dist/skills/hyperframes/data-in-motion.md +0 -19
  29. package/dist/skills/hyperframes/house-style.md +0 -73
  30. package/dist/skills/hyperframes/palettes/bold-energetic.md +0 -14
  31. package/dist/skills/hyperframes/palettes/clean-corporate.md +0 -14
  32. package/dist/skills/hyperframes/palettes/dark-premium.md +0 -14
  33. package/dist/skills/hyperframes/palettes/jewel-rich.md +0 -14
  34. package/dist/skills/hyperframes/palettes/monochrome.md +0 -14
  35. package/dist/skills/hyperframes/palettes/nature-earth.md +0 -14
  36. package/dist/skills/hyperframes/palettes/neon-electric.md +0 -14
  37. package/dist/skills/hyperframes/palettes/pastel-soft.md +0 -14
  38. package/dist/skills/hyperframes/palettes/warm-editorial.md +0 -14
  39. package/dist/skills/hyperframes/patterns.md +0 -191
  40. package/dist/skills/hyperframes/references/audio-reactive.md +0 -76
  41. package/dist/skills/hyperframes/references/beat-direction.md +0 -171
  42. package/dist/skills/hyperframes/references/captions.md +0 -163
  43. package/dist/skills/hyperframes/references/css-patterns.md +0 -373
  44. package/dist/skills/hyperframes/references/design-picker.md +0 -117
  45. package/dist/skills/hyperframes/references/dynamic-techniques.md +0 -102
  46. package/dist/skills/hyperframes/references/html-in-canvas-patterns.md +0 -507
  47. package/dist/skills/hyperframes/references/motion-principles.md +0 -150
  48. package/dist/skills/hyperframes/references/narration.md +0 -92
  49. package/dist/skills/hyperframes/references/prompt-expansion.md +0 -68
  50. package/dist/skills/hyperframes/references/techniques.md +0 -525
  51. package/dist/skills/hyperframes/references/text-effects.md +0 -64
  52. package/dist/skills/hyperframes/references/transcript-guide.md +0 -107
  53. package/dist/skills/hyperframes/references/transitions/catalog.md +0 -117
  54. package/dist/skills/hyperframes/references/transitions/css-3d.md +0 -12
  55. package/dist/skills/hyperframes/references/transitions/css-blur.md +0 -51
  56. package/dist/skills/hyperframes/references/transitions/css-cover.md +0 -43
  57. package/dist/skills/hyperframes/references/transitions/css-destruction.md +0 -95
  58. package/dist/skills/hyperframes/references/transitions/css-dissolve.md +0 -66
  59. package/dist/skills/hyperframes/references/transitions/css-distortion.md +0 -45
  60. package/dist/skills/hyperframes/references/transitions/css-grid.md +0 -10
  61. package/dist/skills/hyperframes/references/transitions/css-light.md +0 -49
  62. package/dist/skills/hyperframes/references/transitions/css-mechanical.md +0 -30
  63. package/dist/skills/hyperframes/references/transitions/css-other.md +0 -25
  64. package/dist/skills/hyperframes/references/transitions/css-push.md +0 -41
  65. package/dist/skills/hyperframes/references/transitions/css-radial.md +0 -37
  66. package/dist/skills/hyperframes/references/transitions/css-scale.md +0 -24
  67. package/dist/skills/hyperframes/references/transitions.md +0 -138
  68. package/dist/skills/hyperframes/references/typography.md +0 -175
  69. package/dist/skills/hyperframes/references/video-composition.md +0 -62
  70. package/dist/skills/hyperframes/scripts/animation-map.mjs +0 -601
  71. package/dist/skills/hyperframes/scripts/contrast-report.mjs +0 -348
  72. package/dist/skills/hyperframes/scripts/package-loader.mjs +0 -269
  73. package/dist/skills/hyperframes/templates/design-picker.html +0 -1432
  74. package/dist/skills/hyperframes/visual-styles.md +0 -443
  75. package/dist/studio/assets/hyperframes-player-Daj5djxa.js +0 -418
  76. package/dist/studio/assets/index-B0twsRu0.css +0 -1
  77. package/dist/studio/assets/index-Cfye9xzo.js +0 -251
@@ -1,188 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Extract per-frame audio visualization data from an audio or video file.
4
-
5
- Outputs JSON with RMS amplitude and frequency band data at the target FPS,
6
- ready to embed in a HyperFrames composition.
7
-
8
- Usage:
9
- python extract-audio-data.py input.mp3 -o audio-data.json
10
- python extract-audio-data.py input.mp4 --fps 30 --bands 16 -o audio-data.json
11
-
12
- Requirements:
13
- - Python 3.9+
14
- - ffmpeg (for decoding audio)
15
- - numpy (pip install numpy)
16
- """
17
-
18
- import argparse
19
- import json
20
- import subprocess
21
- import sys
22
-
23
- import numpy as np
24
-
25
- # ---------------------------------------------------------------------------
26
- # FFT parameters
27
- #
28
- # A 4096-sample window gives ~10.8 Hz per bin at 44100Hz — enough to resolve
29
- # low-frequency bands cleanly. The per-frame audio slice (44100/30 = 1470
30
- # samples at 30fps) is too small and causes low bands to map to the same bins.
31
- #
32
- # Frequency range 30Hz–16kHz covers the useful range for music. Below 30Hz is
33
- # sub-bass most speakers can't reproduce; above 16kHz is noise/harmonics that
34
- # don't contribute to perceived rhythm or melody.
35
- # ---------------------------------------------------------------------------
36
-
37
- SAMPLE_RATE = 44100
38
- FFT_SIZE = 4096
39
- MIN_FREQ = 30.0
40
- MAX_FREQ = 16000.0
41
-
42
-
43
- def decode_audio(path: str) -> np.ndarray:
44
- """Decode audio to mono float32 samples via ffmpeg."""
45
- cmd = [
46
- "ffmpeg", "-i", path,
47
- "-vn", "-ac", "1", "-ar", str(SAMPLE_RATE),
48
- "-f", "s16le", "-acodec", "pcm_s16le",
49
- "-loglevel", "error",
50
- "pipe:1",
51
- ]
52
- result = subprocess.run(cmd, capture_output=True)
53
- if result.returncode != 0:
54
- print(f"ffmpeg error: {result.stderr.decode()}", file=sys.stderr)
55
- sys.exit(1)
56
- return np.frombuffer(result.stdout, dtype=np.int16).astype(np.float32) / 32768.0
57
-
58
-
59
- def compute_band_edges(n_bands: int) -> np.ndarray:
60
- """Logarithmically-spaced frequency band edges from MIN_FREQ to MAX_FREQ."""
61
- return np.array([
62
- MIN_FREQ * (MAX_FREQ / MIN_FREQ) ** (i / n_bands)
63
- for i in range(n_bands + 1)
64
- ])
65
-
66
-
67
- def compute_fft_bands(
68
- windowed: np.ndarray, freq_per_bin: float, n_bins: int,
69
- band_edges: np.ndarray, n_bands: int,
70
- ) -> np.ndarray:
71
- """Compute peak magnitude in logarithmically-spaced frequency bands."""
72
- magnitudes = np.abs(np.fft.rfft(windowed))
73
-
74
- bands = np.zeros(n_bands)
75
- for b in range(n_bands):
76
- low_bin = max(0, int(band_edges[b] / freq_per_bin))
77
- high_bin = min(n_bins, int(band_edges[b + 1] / freq_per_bin))
78
- if high_bin <= low_bin:
79
- high_bin = low_bin + 1
80
- # Clamp to valid range to avoid empty slices
81
- low_bin = min(low_bin, n_bins - 1)
82
- high_bin = min(high_bin, n_bins)
83
- bands[b] = np.max(magnitudes[low_bin:high_bin])
84
-
85
- return bands
86
-
87
-
88
- def extract(path: str, fps: int, n_bands: int) -> dict:
89
- """Extract per-frame audio data."""
90
- print(f"Decoding audio from {path}...", file=sys.stderr)
91
- samples = decode_audio(path)
92
- duration = len(samples) / SAMPLE_RATE
93
- frame_step = SAMPLE_RATE // fps
94
- total_frames = int(duration * fps)
95
-
96
- print(f"Duration: {duration:.1f}s, {total_frames} frames at {fps}fps", file=sys.stderr)
97
- print(f"FFT window: {FFT_SIZE} samples ({SAMPLE_RATE / FFT_SIZE:.1f} Hz/bin)", file=sys.stderr)
98
- print(f"Frequency range: {MIN_FREQ:.0f}-{MAX_FREQ:.0f} Hz, {n_bands} bands", file=sys.stderr)
99
-
100
- # Precompute constants
101
- hann = np.hanning(FFT_SIZE)
102
- band_edges = compute_band_edges(n_bands)
103
- freq_per_bin = SAMPLE_RATE / FFT_SIZE
104
- n_bins = FFT_SIZE // 2 + 1
105
- half_fft = FFT_SIZE // 2
106
-
107
- # Pass 1: extract raw values
108
- rms_values = np.zeros(total_frames)
109
- band_values = np.zeros((total_frames, n_bands))
110
-
111
- for f in range(total_frames):
112
- # RMS from the frame's audio slice
113
- rms_start = f * frame_step
114
- rms_end = rms_start + frame_step
115
- frame_slice = samples[rms_start:min(rms_end, len(samples))]
116
- if len(frame_slice) > 0:
117
- rms_values[f] = np.sqrt(np.mean(frame_slice ** 2))
118
-
119
- # FFT from a centered 4096-sample window
120
- center = rms_start + frame_step // 2
121
- win_start = center - half_fft
122
- win_end = center + half_fft
123
-
124
- if win_start >= 0 and win_end <= len(samples):
125
- window = samples[win_start:win_end] * hann
126
- else:
127
- # Zero-pad at edges
128
- padded = np.zeros(FFT_SIZE)
129
- src_start = max(0, win_start)
130
- src_end = min(len(samples), win_end)
131
- dst_start = src_start - win_start
132
- dst_end = dst_start + (src_end - src_start)
133
- padded[dst_start:dst_end] = samples[src_start:src_end]
134
- window = padded * hann
135
-
136
- band_values[f] = compute_fft_bands(window, freq_per_bin, n_bins, band_edges, n_bands)
137
-
138
- # Pass 2: normalize
139
- peak_rms = rms_values.max() if total_frames > 0 else 1.0
140
- if peak_rms > 0:
141
- rms_values /= peak_rms
142
-
143
- # Per-band normalization so treble is visible alongside louder bass
144
- band_peaks = band_values.max(axis=0)
145
- band_peaks[band_peaks == 0] = 1.0
146
- band_values /= band_peaks
147
-
148
- # Build output
149
- frames = []
150
- for f in range(total_frames):
151
- frames.append({
152
- "time": round(f / fps, 4),
153
- "rms": round(float(rms_values[f]), 4),
154
- "bands": [round(float(b), 4) for b in band_values[f]],
155
- })
156
-
157
- return {
158
- "duration": round(duration, 4),
159
- "fps": fps,
160
- "bands": n_bands,
161
- "totalFrames": total_frames,
162
- "frames": frames,
163
- }
164
-
165
-
166
- def main():
167
- parser = argparse.ArgumentParser(description="Extract per-frame audio visualization data")
168
- parser.add_argument("input", help="Audio or video file")
169
- parser.add_argument("-o", "--output", default="audio-data.json", help="Output JSON path")
170
- parser.add_argument("--fps", type=int, default=30, help="Frames per second (default: 30)")
171
- parser.add_argument("--bands", type=int, default=16, help="Number of frequency bands (default: 16)")
172
- args = parser.parse_args()
173
-
174
- if args.fps < 1:
175
- parser.error("--fps must be at least 1")
176
- if args.bands < 1:
177
- parser.error("--bands must be at least 1")
178
-
179
- data = extract(args.input, args.fps, args.bands)
180
-
181
- with open(args.output, "w") as f:
182
- json.dump(data, f)
183
-
184
- print(f"Wrote {args.output} ({data['totalFrames']} frames, {data['bands']} bands)", file=sys.stderr)
185
-
186
-
187
- if __name__ == "__main__":
188
- main()