0xa89f3db4…071asent to0xecb92cc7…1463·#25,210,177·view on Etherscan
ams={...this.getDefaultParams(),...i}}getDefaultParams(){return{}}setParameter(e,t){this.params[e]=t}update(e,t){}draw(e){}resize(e,t){this.width=e,this.height=t}dispose(){}}class DirectionalPlayback extends BaseComponent{static category="timing";static isAudioReactive=!1;static displayName="Directional Playback";static description="Cursor-controlled forward/reverse for audio, video, and animations";constructor(e,t,i={}){super(e,t,i),this.direction=1,this.transitionProgress=1,this.arrowPhase=0,this._lastDirection=1,this._audioInitialized=!1}getDefaultParams(){return{controlAudio:!0,controlVideo:!0,showIndicator:!1,indicatorStyle:"arrows",indicatorOpacity:.5,indicatorColor:"#ffffff",splitPosition:.5,smoothTransition:!0,transitionSpeed:.1,arrowCount:3,arrowSize:30,arrowSpeed:.05}}getParameters(){return[{name:"controlAudio",type:"boolean",label:"Control Audio Direction"},{name:"controlVideo",type:"boolean",label:"Control Video Direction"},{name:"showIndicator",type:"boolean",label:"Show Direction Indicator"},{name:"indicatorStyle",type:"select",label:"Indicator Style",options:[{value:"arrows",label:"Arrows"},{value:"gradient",label:"Gradient"},{value:"line",label:"Center Line"},{value:"minimal",label:"Minimal"}]},{name:"indicatorOpacity",type:"range",min:.1,max:1,step:.1,label:"Indicator Opacity"},{name:"indicatorColor",type:"color",label:"Indicator Color"},{name:"splitPosition",type:"range",min:.2,max:.8,step:.05,label:"Split Position"},{name:"smoothTransition",type:"boolean",label:"Smooth Transition"},{name:"transitionSpeed",type:"range",min:.02,max:.3,step:.02,label:"Transition Speed"},{name:"arrowCount",type:"range",min:1,max:5,step:1,label:"Arrow Count"},{name:"arrowSize",type:"range",min:15,max:60,step:5,label:"Arrow Size"},{name:"arrowSpeed",type:"range",min:.01,max:.15,step:.01,label:"Arrow Animation Speed"}]}update(e,t){const i=this.params;this._metrics=e;const a=(e?.mouseXNorm||.5)>i.splitPosition?1:-1;if(i.smoothTransition?(this.transitionProgress+=(a-this.transitionProgress)*i.transitionSpeed,this.direction=this.transitionProgress>0?1:-1):(this.direction=a,this.transitionProgress=a),window._playbackDirection=this.direction,window._playbackProgress=this.transitionProgress,i.controlAudio){const e=this.direction!==this._lastDirection,t=!this._audioInitialized&&void 0!==audioEngine&&(audioEngine.hasAudio?audioEngine.hasAudio():audioEngine.isLoaded);(e||t)&&this._updateAudioDirection()}i.controlVideo&&this.direction!==this._lastDirection&&this._updateVideoDirection(),this._lastDirection=this.direction,this.arrowPhase+=i.arrowSpeed*this.direction}async _updateAudioDirection(){if(void 0===audioEngine)return;const e=audioEngine.hasAudio?audioEngine.hasAudio():audioEngine.isLoaded;!this._audioInitialized&&e&&(await audioEngine.initDirectionalPlayback(),this._audioInitialized=!0),audioEngine.isDirectionalEnabled()&&audioEngine.isPlaying&&audioEngine.setDirection(this.direction)}_updateVideoDirection(){if("undefined"==typeof layerManager)return;const e=layerManager.getLayers();for(const t of e)t.component&&"VideoLayer"===t.component.constructor.name&&this._setVideoDirection(t.component,this.direction)}_setVideoDirection(e,t){if(!e._video)return;const i=e._video.elt;if(!i)return;const a=Math.abs(e.params.playbackRate||1);if(t<0)try{i.playbackRate=-a}catch(e){i.playbackRate=0,this._stepVideoBackward(i)}else i.playbackRate=a}_stepVideoBackward(e){const t=Math.max(0,e.currentTime-1/30);e.currentTime=t}draw(e){const t=this.params;if(!t.showIndicator)return;const i=this.hexToRgb(t.indicatorColor),a=255*t.indicatorOpacity;switch(e.push(),t.indicatorStyle){case"arrows":this.drawArrows(e,i,a);break;case"gradient":this.drawGradient(e,i,a);break;case"line":this.drawCenterLine(e,i,a);break;case"minimal":this.drawMinimal(e,i,a)}e.pop()}drawArrows(e,t,i){const a=this.params,o=this.height/2,s=a.arrowSize,n=1.5*s;e.noFill(),e.strokeWeight(3),e.strokeCap(e.ROUND),e.strokeJoin(e.ROUND);for(let r=0;r<a.arrowCount;r++){const l=((this.arrowPhase+r/a.arrowCount)%1-.5)*n*a.arrowCount,h=i*(.3+.7*Math.abs(this.transitionProgress));if(this.direction>0){const i=.75*this.width+l;e.stroke(t.r,t.g,t.b,h),e.beginShape(),e.vertex(i-s/2,o-s/2),e.vertex(i+s/2,o),e.vertex(i-s/2,o+s/2),e.endShape()}else{const i=.25*this.width-l;e.stroke(t.r,t.g,t.b,h),e.beginShape(),e.vertex(i+s/2,o-s/2),e.vertex(i-s/2,o),e.vertex(i+s/2,o+s/2),e.endShape()}}}drawGradient(e,t,i){const a=100;for(let o=0;o<a;o++){const s=(1-o/a)*i*(this.direction<0?.8:.2);e.stroke(t.r,t.g,t.b,s),e.line(o,0,o,this.height)}for(let o=0;o<a;o++){const s=this.width-a+o,n=o/a*i*(this.direction>0?.8:.2);e.stroke(t.r,t.g,t.b,n),e.line(s,0,s,this.height)}}drawCenterLine(e,t,i){const a=this.params,o=this.width*a.splitPosition;e.stroke(t.r,t.g,t.b,.5*i),e.strokeWeight(2),e.line(o,0,o,this.height);const s=this.direction>0?o+30:o-30;e.noStroke(),e.fill(t.r,t.g,t.b,i),e.ellipse(s,this.height/2,10,10)}drawMinimal(e,t,i){const a=this.direction>0?this.width-20-20:20;e.noStroke(),e.fill(t.r,t.g,t.b,i),this.direction>0?e.triangle(a,20,a,40,a+20,30):e.triangle(a+20,20,a+20,40,a,30)}hexToRgb(e){const t=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return t?{r:parseInt(t[1],16),g:parseInt(t[2],16),b:parseInt(t[3],16)}:{r:255,g:255,b:255}}dispose(){delete window._playbackDirection,delete window._playbackProgress}}class VideoLoop extends BaseComponent{static category="media";static isAudioReactive=!1;static displayName="Video Loop";static description="Forward-looping video, no direction control. Smooth & cheap — use for simple video playback.";getDefaultParams(){return{videoFile:null,videoUrl:"",fit:"contain",mute:!0,volume:.5,playbackRate:1,autoplay:!0,paused:!1}}getParameters(){return[{name:"videoFile",type:"file",accept:"video/*",buttonLabel:"Choose Video",label:"Local File (transient)"},{name:"videoUrl",type:"text",label:"Video URL"},{name:"fit",type:"select",label:"Fit Mode",options:[{value:"contain",label:"Contain (letterbox, no crop)"},{value:"cover",label:"Cover (fill canvas, may crop)"},{value:"stretch",label:"Stretch (no aspect preservation)"}]},{name:"mute",type:"boolean",label:"Mute"},{name:"volume",type:"range",min:0,max:1,step:.05,label:"Volume (if unmuted)"},{name:"playbackRate",type:"range",min:.25,max:4,step:.05,label:"Playback Rate"},{name:"autoplay",type:"boolean",label:"Autoplay When Loaded"},{name:"paused",type:"boolean",label:"Paused"}]}constructor(e,t,i){super(e,t,i),this._video=null,this._objectUrl=null,this._lastSrc=null,this._loadFailed=!1,this._loopWatchId=null,this._scratch=null,this._scratchCtx=null,this._hasCachedFrame=!1,this._useVfc=!1,this._postWrapHoldUntil=0,this._lastWatchedCT=null,this.params.videoUrl&&"string"==typeof this.params.videoUrl&&this._loadSrc(this.params.videoUrl)}onParameterChange(e,t){if("videoUrl"===e){const e="string"==typeof t?t.trim():"";e&&this._loadSrc(e)}else"videoFile"===e&&t instanceof File?this._loadFile(t):"mute"===e&&this._video?this._video.muted=!!t:"volume"===e&&this._video&&!this._video.muted?this._video.volume=Math.max(0,Math.min(1,Number(t)||0)):"playbackRate"===e&&this._video?this._video.playbackRate=Math.max(.25,Math.min(4,Number(t)||1)):"paused"===e&&this._video?t&&!this._video.paused?this._video.pause():!t&&this._video.paused&&this._video.play().catch(()=>{}):"autoplay"===e&&this._video&&t&&this._video.paused&&!this.params.paused&&this._video.play().catch(()=>{})}_loadFile(e){if("undefined"!=typeof URL){if(this._objectUrl)try{URL.revokeObjectURL(this._objectUrl)}catch(e){}this._objectUrl=URL.createObjectURL(e),this.params.videoUrl=this._objectUrl,this._loadSrc(this._objectUrl)}}loadVideo(e){return e?e instanceof Blob?(this._loadFile(e),new Promise((e,t)=>{if(!this._video)return t(new Error("video element missing"));const i=()=>{this._video.removeEventListener("loadeddata",i),this._video.removeEventListener("error",a),e()},a=()=>{this._video.removeEventListener("loadeddata",i),this._video.removeEventListener("error",a),t(new Error("video load failed"))};this._video.addEventListener("loadeddata",i,{once:!0}),this._video.addEventListener("error",a,{once:!0})})):Promise.reject(new Error("loadVideo: expected File/Blob")):Promise.reject(new Error("loadVideo: no file given"))}_loadSrc(e){if("undefined"!=typeof document&&(e!==this._lastSrc||!this._video||this._loadFailed)){if(this._lastSrc=e,this._loadFailed=!1,!this._video){const e=document.createElement("video");e.crossOrigin="anonymous",e.playsInline=!0,e.loop=!1,e.preload="auto",e.muted=!!this.params.mute,e.volume=Math.max(0,Math.min(1,Number(this.params.volume)||0)),e.playbackRate=Math.max(.25,Math.min(4,Number(this.params.playbackRate)||1)),e.style.position="fixed",e.style.left="-9999px",e.style.top="-9999px",e.style.width="2px",e.style.height="2px",e.style.pointerEvents="none",e.style.opacity="0",document.body.appendChild(e),e.addEventListener("error",()=>{this._loadFailed=!0,console.error("[VideoLoop] load error",e.error)}),e.addEventListener("loadeddata",()=>{this.params.autoplay&&!this.params.paused&&e.play().catch(e=>{console.warn("[VideoLoop] autoplay blocked:",e&&e.message)}),"undefined"!=typeof window&&window.renderEngine&&"function"==typeof window.renderEngine.notifyMediaLoaded&&window.renderEngine.notifyMediaLoaded()});const t=.04,i=()=>{this._postWrapHoldUntil=("undefined"!=typeof performance?performance.now():Date.now())+350},a=()=>{const e=this._video;if(e){if(!e.paused&&!e.seeking){const a=e.duration;if(isFinite(a)&&a>2*t&&e.currentTime>=a-t){try{e.currentTime=.001}catch(e){}i()}null!=this._lastWatchedCT&&e.currentTime<this._lastWatchedCT-.3&&i(),this._lastWatchedCT=e.currentTime}this._loopWatchId=requestAnimationFrame(a)}};if(this._loopWatchId=requestAnimationFrame(a),e.addEventListener("ended",()=>{try{e.currentTime=.001}catch(e){}i(),this.params.paused||e.play().catch(()=>{})}),this._shouldHoldScratch=()=>0!==this._postWrapHoldUntil&&(("undefined"!=typeof performance?performance.now():Date.now())>=this._postWrapHoldUntil?(this._postWrapHoldUntil=0,!1):!(e.c