|
336 | 336 |
|
337 | 337 | // ── Buffers ────────────────────────────────────────── |
338 | 338 | let accum =new Float32Array(PIX*4); |
| 339 | +let accumInited=false; |
339 | 340 | let prev =new Uint8ClampedArray(PIX*4); |
340 | 341 | let prev2 =new Uint8ClampedArray(PIX*4); |
341 | 342 | let motX =new Float32Array(PIX); |
|
580 | 581 | // ── Datamosh ───────────────────────────────────────── |
581 | 582 | function fxDatamosh(src,p){ |
582 | 583 | const d=src.data; |
| 584 | + // Seed accum with the first real frame so the image is never black |
| 585 | + if(!accumInited){for(let i=0;i<d.length;i++)accum[i]=d[i];accumInited=true;} |
583 | 586 | for(let i=0;i<d.length;i+=4){ |
584 | 587 | const dr=d[i]-prev[i],dg=d[i+1]-prev[i+1],db=d[i+2]-prev[i+2]; |
585 | 588 | const m=(Math.abs(dr)+Math.abs(dg)+Math.abs(db))/3; |
586 | | - const bl=m>p.threshold?(1-p.blend)*.4:(1-p.blend)*.018; |
587 | | - accum[i]=accum[i]*p.decay+d[i]*bl; |
588 | | - accum[i+1]=accum[i+1]*p.decay+d[i+1]*bl; |
589 | | - accum[i+2]=accum[i+2]*p.decay+d[i+2]*bl; |
| 589 | + // Proper lerp — (1-rate)+rate == 1.0, so accum converges to full pixel value |
| 590 | + // High motion → accum follows new scene faster; low motion → holds old scene (datamosh) |
| 591 | + const rate=m>p.threshold?(1-p.blend)*0.55:(1-p.blend)*0.04; |
| 592 | + accum[i] +=( d[i] -accum[i] )*rate; |
| 593 | + accum[i+1]+=(d[i+1]-accum[i+1])*rate; |
| 594 | + accum[i+2]+=(d[i+2]-accum[i+2])*rate; |
590 | 595 | } |
591 | 596 | const out=new ImageData(W,H); |
592 | 597 | for(let i=0;i<d.length;i+=4){ |
593 | | - const dr=(d[i]-prev[i])*p.motAmp,dg=(d[i+1]-prev[i+1])*p.motAmp,db=(d[i+2]-prev[i+2])*p.motAmp; |
594 | | - out.data[i]=clamp(accum[i]+dr,0,255);out.data[i+1]=clamp(accum[i+1]+dg,0,255); |
595 | | - out.data[i+2]=clamp(accum[i+2]+db,0,255);out.data[i+3]=255; |
| 598 | + const dr=(d[i] -prev[i] )*p.motAmp; |
| 599 | + const dg=(d[i+1]-prev[i+1])*p.motAmp; |
| 600 | + const db=(d[i+2]-prev[i+2])*p.motAmp; |
| 601 | + out.data[i] =clamp(accum[i] +dr,0,255); |
| 602 | + out.data[i+1]=clamp(accum[i+1]+dg,0,255); |
| 603 | + out.data[i+2]=clamp(accum[i+2]+db,0,255); |
| 604 | + out.data[i+3]=255; |
596 | 605 | } |
597 | 606 | return out; |
598 | 607 | } |
|
973 | 982 | } |
974 | 983 |
|
975 | 984 | function resetAccum(){ |
976 | | - accum.fill(0);motX.fill(0);motY.fill(0);fhist.length=0;chrR.length=0;chrG.length=0;chrB.length=0; |
| 985 | + accum.fill(0);accumInited=false;motX.fill(0);motY.fill(0);fhist.length=0;chrR.length=0;chrG.length=0;chrB.length=0; |
977 | 986 | scanL.length=0;prev.fill(0);prev2.fill(0);fc=0;sessStart=Date.now();waveT=0;bendRng=1234567; |
978 | 987 | setState('ACCUM CLEARED'); |
979 | 988 | } |
|
0 commit comments