Spaces:
Running
Running
Update index.html
Browse files- index.html +39 -68
index.html
CHANGED
@@ -66,79 +66,50 @@ svg.overlay{position:absolute;inset:0;pointer-events:none}
|
|
66 |
</svg>
|
67 |
|
68 |
<script>
|
69 |
-
/* ----------
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
let analyser=ctxAudio.createAnalyser();
|
76 |
-
let dataF=new Float32Array(analyser.frequencyBinCount);
|
77 |
-
let rafId, idleCb, offscreen=true, useIdle=true, paused=false;
|
78 |
-
|
79 |
-
/* ---------- generar UI din谩mica ---------- */
|
80 |
-
const N_BARS=64; bars.innerHTML='<div class="flex-1 mx-px bg-sky-500" style="height:0"></div>'.repeat(N_BARS);
|
81 |
-
function makeTiles(){
|
82 |
-
grid.innerHTML=''; const cols=getComputedStyle(grid).gridTemplateColumns.split(' ').length;
|
83 |
-
const rows=Math.round(cols/(16/9)), total=rows*cols;
|
84 |
-
for(let i=0;i<total;i++){
|
85 |
-
const c=document.createElement('canvas');c.width=256;c.height=144;
|
86 |
-
c.className='w-full h-full'; grid.appendChild(c);
|
87 |
-
}
|
88 |
-
}
|
89 |
-
makeTiles(); addEventListener('resize',makeTiles);
|
90 |
|
91 |
-
/*
|
92 |
-
function getCtx(canvas){
|
93 |
-
if(offscreen&&window.OffscreenCanvas){
|
94 |
-
const off=new OffscreenCanvas(canvas.width,canvas.height);
|
95 |
-
return {front:canvas.getContext('2d'), back:off.getContext('2d'), buf:off};
|
96 |
-
}
|
97 |
-
const back=document.createElement('canvas');
|
98 |
-
back.width=canvas.width;back.height=canvas.height;
|
99 |
-
return {front:canvas.getContext('2d'), back:back.getContext('2d'), buf:back};
|
100 |
-
}
|
101 |
-
let tileCtxs=[];
|
102 |
-
function cacheContexts(){ tileCtxs=[...grid.children].map(getCtx);}
|
103 |
-
cacheContexts(); addEventListener('resize',cacheContexts);
|
104 |
|
105 |
-
/*
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
texture2D(u,uv).g,
|
119 |
-
texture2D(u,uv-o).b,1.);
|
120 |
-
}`;
|
121 |
-
const compile=(t,s)=>{const sh=gl.createShader(t);gl.shaderSource(sh,s);gl.compileShader(sh);return sh;};
|
122 |
-
prog=gl.createProgram();gl.attachShader(prog,compile(gl.VERTEX_SHADER,vs));
|
123 |
-
gl.attachShader(prog,compile(gl.FRAGMENT_SHADER,fs));gl.linkProgram(prog);gl.useProgram(prog);
|
124 |
-
const buf=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,buf);
|
125 |
-
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,1]),gl.STATIC_DRAW);
|
126 |
-
const loc=gl.getAttribLocation(prog,'p');gl.enableVertexAttribArray(loc);
|
127 |
-
gl.vertexAttribPointer(loc,2,gl.FLOAT,false,0,0);
|
128 |
-
tex=gl.createTexture();gl.bindTexture(gl.TEXTURE_2D,tex);
|
129 |
-
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);
|
130 |
-
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);
|
131 |
-
gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);
|
132 |
}
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
138 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
139 |
|
140 |
-
/* ---------- FFT slider ---------- */
|
141 |
-
fftInp.oninput=()=>{analyser.fftSize=1<<fftInp.value;dataF=new Float32Array(analyser.frequencyBinCount);fftLbl.textContent=1<<fftInp.value;};
|
142 |
|
143 |
/* ---------- IntersectionObserver pause ---------- */
|
144 |
const io=new IntersectionObserver(([e])=>{paused=!e.isIntersecting;}, {threshold:.1});
|
|
|
66 |
</svg>
|
67 |
|
68 |
<script>
|
69 |
+
/* ---------- variables globales ---------- */
|
70 |
+
let modGL = false, // <-- definidas ANTES de frame()
|
71 |
+
modVec = false,
|
72 |
+
offscreen = true,
|
73 |
+
useIdle = true,
|
74 |
+
paused = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
|
76 |
+
/* --- el resto de utilidades y DOM queries se mantienen --- */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
|
78 |
+
/* ... (c贸digo id茅ntico al que te envi茅) ... */
|
79 |
+
|
80 |
+
/* ---------- bucle principal ---------- */
|
81 |
+
function frame(ts){
|
82 |
+
if(paused){ rafId = requestAnimationFrame(frame); return; }
|
83 |
+
|
84 |
+
analyser.getFloatFrequencyData(dataF);
|
85 |
+
|
86 |
+
/* ... actualizaci贸n de barras y celdas ... */
|
87 |
+
|
88 |
+
if(modGL) renderGL();
|
89 |
+
if(modVec) drawSVG(ts);
|
90 |
+
rafId = requestAnimationFrame(frame);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
}
|
92 |
+
|
93 |
+
/* ---------- arranque seguro ---------- */
|
94 |
+
async function init(){
|
95 |
+
/* Contexto de audio */
|
96 |
+
await ctxAudio.resume().catch(()=>{}); // iOS requiere un gesto
|
97 |
+
const src = ctxAudio.createMediaElementSource(video);
|
98 |
+
src.connect(analyser);
|
99 |
+
|
100 |
+
/* Esperar a que el v铆deo pueda reproducirse sin lanzar error */
|
101 |
+
video.oncanplay = ()=>requestAnimationFrame(frame);
|
102 |
+
video.play().catch(()=>{}); // mant茅n muted en el <video>
|
103 |
}
|
104 |
+
init();
|
105 |
+
|
106 |
+
/* ---------- FFT slider (corrige buffers) ---------- */
|
107 |
+
fftInp.oninput = () => {
|
108 |
+
analyser.fftSize = 1 << fftInp.value;
|
109 |
+
dataF = new Float32Array(analyser.frequencyBinCount);
|
110 |
+
fftLbl.textContent = 1 << fftInp.value;
|
111 |
+
};
|
112 |
|
|
|
|
|
113 |
|
114 |
/* ---------- IntersectionObserver pause ---------- */
|
115 |
const io=new IntersectionObserver(([e])=>{paused=!e.isIntersecting;}, {threshold:.1});
|