@rosalana/sandbox 0.0.2 → 0.0.3

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.
package/dist/index.cjs.js CHANGED
@@ -1,8 +1,8 @@
1
- "use strict";var w=Object.defineProperty;var k=(o,t,e)=>t in o?w(o,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):o[t]=e;var i=(o,t,e)=>k(o,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class u{constructor(t,e,r,s){this.target=t,this.type=e,this.listener=r,this.options=s,this.target.addEventListener(this.type,this.listener,this.options)}remove(){this.target.removeEventListener(this.type,this.listener,this.options)}static on(t,e,r,s){return t.addEventListener(e,r,s),()=>t.removeEventListener(e,r,s)}}class l extends Error{constructor(t,e){super(t),this.code=e,this.name="SandboxError"}}class S extends l{constructor(t){const e=t==="not_supported"?"WebGL is not supported in this browser.":"Failed to create WebGL context. The GPU may be unavailable.";super(e,t==="not_supported"?"WEBGL_NOT_SUPPORTED":"CONTEXT_CREATION_FAILED"),this.name="SandboxContextError"}}class L extends l{constructor(t,e){super(`Vertex and fragment shader WebGL versions do not match (${t} vs ${e})`,"SHADER_VERSION_MISMATCH"),this.vertexVersion=t,this.fragmentVersion=e,this.name="SandboxShaderVersionMismatchError"}}class c extends l{constructor(e,r,s){const n=c.parseErrorLines(s),a=n.length>0?` at line(s): ${n.join(", ")}`:"";super(`${e} shader compilation failed${a}
1
+ "use strict";var w=Object.defineProperty;var k=(o,t,e)=>t in o?w(o,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):o[t]=e;var i=(o,t,e)=>k(o,typeof t!="symbol"?t+"":t,e);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class u{constructor(t,e,r,s){this.target=t,this.type=e,this.listener=r,this.options=s,this.target.addEventListener(this.type,this.listener,this.options)}remove(){this.target.removeEventListener(this.type,this.listener,this.options)}static on(t,e,r,s){return t.addEventListener(e,r,s),()=>t.removeEventListener(e,r,s)}}class l extends Error{constructor(t,e){super(t),this.code=e,this.name="SandboxError"}}class S extends l{constructor(t){const e=t==="not_supported"?"WebGL is not supported in this browser.":"Failed to create WebGL context. The GPU may be unavailable.";super(e,t==="not_supported"?"WEBGL_NOT_SUPPORTED":"CONTEXT_CREATION_FAILED"),this.name="SandboxContextError"}}class L extends l{constructor(t,e){super(`Vertex and fragment shader WebGL versions do not match (${t} vs ${e})`,"SHADER_VERSION_MISMATCH"),this.vertexVersion=t,this.fragmentVersion=e,this.name="SandboxShaderVersionMismatchError"}}class f extends l{constructor(e,r,s){const n=f.parseErrorLines(s),a=n.length>0?` at line(s): ${n.join(", ")}`:"";super(`${e} shader compilation failed${a}
2
2
 
3
- ${s}`,"SHADER_COMPILATION_FAILED");i(this,"lines");this.shaderType=e,this.source=r,this.infoLog=s,this.name="SandboxShaderCompilationError",this.lines=n}static parseErrorLines(e){const r=[/ERROR:\s*\d*:(\d+)/g,/(\d+):(\d+)\(\d+\):/g,/^(\d+):/gm],s=new Set;for(const n of r){let a;for(;(a=n.exec(e))!==null;){const f=parseInt(a[1],10);f>0&&s.add(f)}}return[...s].sort((n,a)=>n-a)}}class d extends l{constructor(t){super(`Shader program linking failed
3
+ ${s}`,"SHADER_COMPILATION_FAILED");i(this,"lines");this.shaderType=e,this.source=r,this.infoLog=s,this.name="SandboxShaderCompilationError",this.lines=n}static parseErrorLines(e){const r=[/ERROR:\s*\d*:(\d+)/g,/(\d+):(\d+)\(\d+\):/g,/^(\d+):/gm],s=new Set;for(const n of r){let a;for(;(a=n.exec(e))!==null;){const c=parseInt(a[1],10);c>0&&s.add(c)}}return[...s].sort((n,a)=>n-a)}}class d extends l{constructor(t){super(`Shader program linking failed
4
4
 
5
- ${t}`,"PROGRAM_LINK_FAILED"),this.infoLog=t,this.name="SandboxProgramError"}}class R{constructor(){i(this,"time",0);i(this,"delta",0);i(this,"frame",0);i(this,"running",!1);i(this,"startTime",0);i(this,"lastTime",0);i(this,"rafId",null);i(this,"callback",null);this.loop=this.loop.bind(this)}start(t){if(this.running)return this;this.callback=t,this.running=!0;const e=performance.now();return this.startTime=e,this.lastTime=e,this.rafId=requestAnimationFrame(this.loop),this}stop(){return this.running?(this.running=!1,this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null),this):this}reset(){return this.stop(),this.time=0,this.delta=0,this.frame=0,this}getState(){return{time:this.time,delta:this.delta,frame:this.frame}}tick(t=0){return this.delta=t,this.time+=t,this.frame++,this.callback&&this.callback(this.getState()),this}setTime(t){return this.time=t,this}destroy(){this.stop(),this.callback=null}loop(t){this.running&&(this.delta=(t-this.lastTime)/1e3,this.lastTime=t,this.time=(t-this.startTime)/1e3,this.frame++,this.callback&&this.callback(this.getState()),this.rafId=requestAnimationFrame(this.loop))}}class p{constructor(t){i(this,"gl");i(this,"vao",null);i(this,"vbo",null);i(this,"ibo",null);i(this,"vertexCount",0);i(this,"indexCount",0);i(this,"useIndices",!1);i(this,"vaoExt",null);i(this,"isWebGL2");this.gl=t,this.isWebGL2=t instanceof WebGL2RenderingContext,this.isWebGL2||(this.vaoExt=t.getExtension("OES_vertex_array_object"))}static fullscreenQuad(t){const e=new p(t),r=new Float32Array([-1,-1,0,0,1,-1,1,0,-1,1,0,1,1,1,1,1]),s=new Uint16Array([0,1,2,2,1,3]);return e.setup(r,s),e}setup(t,e){const r=this.gl;return this.createVAO(),this.bindVAO(),this.vbo=r.createBuffer(),r.bindBuffer(r.ARRAY_BUFFER,this.vbo),r.bufferData(r.ARRAY_BUFFER,t,r.STATIC_DRAW),this.vertexCount=t.length/4,e&&(this.ibo=r.createBuffer(),r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,this.ibo),r.bufferData(r.ELEMENT_ARRAY_BUFFER,e,r.STATIC_DRAW),this.indexCount=e.length,this.useIndices=!0),this.unbindVAO(),this}linkAttributes(t){const e=this.gl;this.bindVAO(),e.bindBuffer(e.ARRAY_BUFFER,this.vbo);const r=4*Float32Array.BYTES_PER_ELEMENT,s=this.getPositionLocation(t);s>=0&&(e.enableVertexAttribArray(s),e.vertexAttribPointer(s,2,e.FLOAT,!1,r,0));const n=this.getTexcoordLocation(t);return n>=0&&(e.enableVertexAttribArray(n),e.vertexAttribPointer(n,2,e.FLOAT,!1,r,2*Float32Array.BYTES_PER_ELEMENT)),this.useIndices&&e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this.ibo),this.unbindVAO(),this}bind(){return this.bindVAO(),this}unbind(){return this.unbindVAO(),this}draw(){const t=this.gl;return this.bindVAO(),this.useIndices?t.drawElements(t.TRIANGLES,this.indexCount,t.UNSIGNED_SHORT,0):t.drawArrays(t.TRIANGLE_STRIP,0,this.vertexCount),this}destroy(){const t=this.gl;this.deleteVAO(),this.vbo&&(t.deleteBuffer(this.vbo),this.vbo=null),this.ibo&&(t.deleteBuffer(this.ibo),this.ibo=null)}getPositionLocation(t){let e=t.getAttribLocation("a_position");return e>=0||(e=t.getAttribLocation("aPosition"),e>=0)||(e=t.getAttribLocation("position"),e>=0)?e:-1}getTexcoordLocation(t){let e=t.getAttribLocation("a_texcoord");return e>=0||(e=t.getAttribLocation("aTexCoord"),e>=0)||(e=t.getAttribLocation("texcoord"),e>=0)||(e=t.getAttribLocation("a_uv"),e>=0)?e:-1}createVAO(){this.isWebGL2?this.vao=this.gl.createVertexArray():this.vaoExt&&(this.vao=this.vaoExt.createVertexArrayOES())}bindVAO(){this.vao&&(this.isWebGL2?this.gl.bindVertexArray(this.vao):this.vaoExt&&this.vaoExt.bindVertexArrayOES(this.vao))}unbindVAO(){this.isWebGL2?this.gl.bindVertexArray(null):this.vaoExt&&this.vaoExt.bindVertexArrayOES(null)}deleteVAO(){this.vao&&(this.isWebGL2?this.gl.deleteVertexArray(this.vao):this.vaoExt&&this.vaoExt.deleteVertexArrayOES(this.vao),this.vao=null)}}class h{constructor(t){i(this,"gl");i(this,"program",null);i(this,"vertexShader",null);i(this,"fragmentShader",null);i(this,"version",1);this.gl=t}static detectVersion(t){return/^\s*#version\s+300\s+es/m.test(t)?2:1}compile(t,e){this.destroy();const r=h.detectVersion(t),s=h.detectVersion(e);if(r!=s)throw new L(r,s);return this.version=Math.max(r,s),this.vertexShader=this.compileShader("vertex",t),this.fragmentShader=this.compileShader("fragment",e),this.linkProgram(),this}use(){return this.program&&this.gl.useProgram(this.program),this}getProgram(){return this.program}getVersion(){return this.version}getAttribLocation(t){return this.program?this.gl.getAttribLocation(this.program,t):-1}getUniformLocation(t){return this.program?this.gl.getUniformLocation(this.program,t):null}destroy(){const t=this.gl;this.program&&(this.vertexShader&&t.detachShader(this.program,this.vertexShader),this.fragmentShader&&t.detachShader(this.program,this.fragmentShader),t.deleteProgram(this.program),this.program=null),this.vertexShader&&(t.deleteShader(this.vertexShader),this.vertexShader=null),this.fragmentShader&&(t.deleteShader(this.fragmentShader),this.fragmentShader=null)}compileShader(t,e){const r=this.gl,s=t==="vertex"?r.VERTEX_SHADER:r.FRAGMENT_SHADER,n=r.createShader(s);if(!n)throw new c(t,e,"Failed to create shader object");if(r.shaderSource(n,e),r.compileShader(n),!r.getShaderParameter(n,r.COMPILE_STATUS)){const f=r.getShaderInfoLog(n)||"Unknown error";throw r.deleteShader(n),new c(t,e,f)}return n}linkProgram(){const t=this.gl;if(!this.vertexShader||!this.fragmentShader)throw new d("Shaders not compiled");const e=t.createProgram();if(!e)throw new d("Failed to create program object");if(t.attachShader(e,this.vertexShader),t.attachShader(e,this.fragmentShader),t.linkProgram(e),!t.getProgramParameter(e,t.LINK_STATUS)){const s=t.getProgramInfoLog(e)||"Unknown error";throw t.deleteProgram(e),new d(s)}this.program=e}}class x{constructor(t,e){i(this,"name");i(this,"method");i(this,"isArray");i(this,"isMatrix");i(this,"location",null);i(this,"locationResolved",!1);i(this,"value");this.name=t,this.value=e;const r=x.inferMethodInfo(e);this.method=r.method,this.isArray=r.isArray,this.isMatrix=r.isMatrix}static inferMethodInfo(t){if(typeof t=="boolean")return{method:"uniform1i",isArray:!1,isMatrix:!1};if(typeof t=="number")return{method:"uniform1f",isArray:!1,isMatrix:!1};if(!Array.isArray(t))return{method:"uniform1f",isArray:!1,isMatrix:!1};const e=t.length,r=t[0];if(Array.isArray(r))switch(r.length){case 2:return{method:"uniform2fv",isArray:!0,isMatrix:!1};case 3:return{method:"uniform3fv",isArray:!0,isMatrix:!1};case 4:return{method:"uniform4fv",isArray:!0,isMatrix:!1};default:return{method:"uniform1fv",isArray:!0,isMatrix:!1}}switch(e){case 2:return{method:"uniform2fv",isArray:!1,isMatrix:!1};case 3:return{method:"uniform3fv",isArray:!1,isMatrix:!1};case 4:return{method:"uniform4fv",isArray:!1,isMatrix:!1};case 9:return{method:"uniformMatrix3fv",isArray:!1,isMatrix:!0};case 16:return{method:"uniformMatrix4fv",isArray:!1,isMatrix:!0};default:return{method:"uniform1fv",isArray:!0,isMatrix:!1}}}resolveLocation(t,e){return this.locationResolved||(this.location=t.getUniformLocation(e,this.name),this.locationResolved=!0),this.location}invalidateLocation(){this.location=null,this.locationResolved=!1}setValue(t){this.value=t}getValue(){return this.value}upload(t,e){const r=this.resolveLocation(t,e);if(r===null)return;const s=this.value;let n;switch(typeof s=="boolean"?n=s?1:0:typeof s=="number"?n=s:this.isArray&&Array.isArray(s[0])?n=new Float32Array(s.flat()):n=new Float32Array(s),this.method){case"uniform1f":t.uniform1f(r,n);break;case"uniform1i":t.uniform1i(r,n);break;case"uniform1fv":t.uniform1fv(r,n);break;case"uniform2fv":t.uniform2fv(r,n);break;case"uniform3fv":t.uniform3fv(r,n);break;case"uniform4fv":t.uniform4fv(r,n);break;case"uniformMatrix2fv":t.uniformMatrix2fv(r,!1,n);break;case"uniformMatrix3fv":t.uniformMatrix3fv(r,!1,n);break;case"uniformMatrix4fv":t.uniformMatrix4fv(r,!1,n);break}}}const m=class m{constructor(t){i(this,"gl");i(this,"program",null);i(this,"uniforms",new Map);this.gl=t}attachProgram(t){this.program=t;for(const e of this.uniforms.values())e.invalidateLocation();return this}set(t,e){const r=this.uniforms.get(t);return r?r.setValue(e):this.uniforms.set(t,new x(t,e)),this}setMany(t){for(const[e,r]of Object.entries(t))this.set(e,r);return this}get(t){var e;return(e=this.uniforms.get(t))==null?void 0:e.getValue()}has(t){return this.uniforms.has(t)}delete(t){return this.uniforms.delete(t)}uploadAll(){if(!this.program)return this;for(const t of this.uniforms.values())t.upload(this.gl,this.program);return this}uploadBuiltIns(t,e,r){if(this.set("u_resolution",e),this.set("u_time",t.time),this.set("u_delta",t.delta),this.set("u_mouse",r),this.set("u_frame",t.frame),!this.program)return this;for(const s of m.BUILT_INS){const n=this.uniforms.get(s);n&&n.upload(this.gl,this.program)}return this}clear(){this.uniforms.clear()}destroy(){this.uniforms.clear(),this.program=null}keys(){return this.uniforms.keys()}get size(){return this.uniforms.size}};i(m,"BUILT_INS",new Set(["u_resolution","u_time","u_delta","u_mouse","u_frame"]));let v=m;class A{constructor(){i(this,"hooks",new Map)}id(){return Math.random().toString(36).substring(2,10)}add(t){const e=this.id();return this.hooks.set(e,t),()=>this.remove(e)}remove(t){this.hooks.delete(t)}run(t){for(const[e,r]of this.hooks)r(t)===!1&&this.remove(e)}destroy(){this.hooks.clear()}}class b{constructor(t,e){i(this,"canvas");i(this,"gl");i(this,"options");i(this,"onBeforeHooks",new A);i(this,"onAfterHooks",new A);i(this,"_program");i(this,"_geometry");i(this,"_uniforms");i(this,"_clock");i(this,"_resolution",[1,1]);i(this,"_mouse",[0,0]);i(this,"_version",1);i(this,"playing",!1);this.canvas=t,this.options=e,this.gl=this.initContext(),this.enableExtensions(),this._program=new h(this.gl),this._geometry=p.fullscreenQuad(this.gl),this._uniforms=new v(this.gl),this._clock=new R,this.options.onBeforeRender&&this.onBeforeHooks.add(this.options.onBeforeRender),this.options.onAfterRender&&this.onAfterHooks.add(this.options.onAfterRender),this.onRender=this.onRender.bind(this)}static setup(t,e){const r=new b(t,e);return e.vertex&&e.fragment&&r.shader(e.vertex,e.fragment),e.uniforms&&r._uniforms.setMany(e.uniforms),r}initContext(){const t={antialias:this.options.antialias,preserveDrawingBuffer:this.options.preserveDrawingBuffer,alpha:!0,depth:!1,stencil:!1},e=this.canvas.getContext("webgl2",t);if(e)return this._version=2,e;const r=this.canvas.getContext("webgl",t);if(r)return this._version=1,r;const s=new S("not_supported");throw this.options.onError(s),s}enableExtensions(){this.gl.getExtension("OES_standard_derivatives"),this.gl.getExtension("OES_texture_float"),this.gl.getExtension("OES_texture_float_linear"),this._version===1&&this.gl.getExtension("OES_vertex_array_object")}viewport(t,e,r,s){return this.canvas.width=r,this.canvas.height=s,this.gl.viewport(t,e,r,s),this._resolution=[r,s],this}clock(t){return this._clock.setTime(t),this}mouse(t,e){return this._mouse=[t,e],this}uniform(t,e){return this._uniforms.set(t,e),this}uniforms(t){return this._uniforms.setMany(t),this}getUniform(t){return this._uniforms.get(t)}shader(t,e){try{this._program.compile(t,e),this._version=this._program.getVersion(),this._geometry.linkAttributes(this._program);const r=this._program.getProgram();r&&this._uniforms.attachProgram(r)}catch(r){r instanceof l&&this.options.onError(r)}return this}play(){return this.playing?this:(this.playing=!0,this._clock.start(this.onRender),this)}pause(){if(!this.playing)return this;const t=this._clock.getState();return this.onBeforeHooks.run(t),this.playing=!1,this._clock.stop(),this.onAfterHooks.run(t),this}render(){return this.onRender(this._clock.getState()),this}getContext(){return this.gl}getVersion(){return this._version}destroy(){this.pause(),this._clock.destroy(),this._geometry.destroy(),this._program.destroy(),this._uniforms.destroy(),this.onAfterHooks.destroy(),this.onBeforeHooks.destroy()}onRender(t){const e=this.gl;this.onBeforeHooks.run(t),e.clearColor(0,0,0,0),e.clear(e.COLOR_BUFFER_BIT),this._program.use(),this._uniforms.uploadBuiltIns(t,this._resolution,this._mouse),this._uniforms.uploadAll(),this._geometry.bind(),this._geometry.draw(),this.onAfterHooks.run(t)}}const g=`#ifdef GL_ES
5
+ ${t}`,"PROGRAM_LINK_FAILED"),this.infoLog=t,this.name="SandboxProgramError"}}class R{constructor(){i(this,"time",0);i(this,"delta",0);i(this,"frame",0);i(this,"running",!1);i(this,"startTime",0);i(this,"lastTime",0);i(this,"rafId",null);i(this,"callback",null);this.loop=this.loop.bind(this)}start(t){if(this.running)return this;if(this.callback=t,this.running=!0,this.frame===0){const e=performance.now();this.startTime=e,this.lastTime=e}return this.rafId=requestAnimationFrame(this.loop),this}stop(){return this.running?(this.running=!1,this.rafId!==null&&(cancelAnimationFrame(this.rafId),this.rafId=null),this):this}reset(){return this.stop(),this.time=0,this.delta=0,this.frame=0,this}getState(){return{time:this.time,delta:this.delta,frame:this.frame}}tick(t=0){return this.delta=t,this.time+=t,this.frame++,this.callback&&this.callback(this.getState()),this}setTime(t){return this.time=t,this}destroy(){this.stop(),this.callback=null}loop(t){this.running&&(this.delta=(t-this.lastTime)/1e3,this.lastTime=t,this.time=(t-this.startTime)/1e3,this.frame++,this.callback&&this.callback(this.getState()),this.rafId=requestAnimationFrame(this.loop))}}class p{constructor(t){i(this,"gl");i(this,"vao",null);i(this,"vbo",null);i(this,"ibo",null);i(this,"vertexCount",0);i(this,"indexCount",0);i(this,"useIndices",!1);i(this,"vaoExt",null);i(this,"isWebGL2");this.gl=t,this.isWebGL2=t instanceof WebGL2RenderingContext,this.isWebGL2||(this.vaoExt=t.getExtension("OES_vertex_array_object"))}static fullscreenQuad(t){const e=new p(t),r=new Float32Array([-1,-1,0,0,1,-1,1,0,-1,1,0,1,1,1,1,1]),s=new Uint16Array([0,1,2,2,1,3]);return e.setup(r,s),e}setup(t,e){const r=this.gl;return this.createVAO(),this.bindVAO(),this.vbo=r.createBuffer(),r.bindBuffer(r.ARRAY_BUFFER,this.vbo),r.bufferData(r.ARRAY_BUFFER,t,r.STATIC_DRAW),this.vertexCount=t.length/4,e&&(this.ibo=r.createBuffer(),r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,this.ibo),r.bufferData(r.ELEMENT_ARRAY_BUFFER,e,r.STATIC_DRAW),this.indexCount=e.length,this.useIndices=!0),this.unbindVAO(),this}linkAttributes(t){const e=this.gl;this.bindVAO(),e.bindBuffer(e.ARRAY_BUFFER,this.vbo);const r=4*Float32Array.BYTES_PER_ELEMENT,s=this.getPositionLocation(t);s>=0&&(e.enableVertexAttribArray(s),e.vertexAttribPointer(s,2,e.FLOAT,!1,r,0));const n=this.getTexcoordLocation(t);return n>=0&&(e.enableVertexAttribArray(n),e.vertexAttribPointer(n,2,e.FLOAT,!1,r,2*Float32Array.BYTES_PER_ELEMENT)),this.useIndices&&e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this.ibo),this.unbindVAO(),this}bind(){return this.bindVAO(),this}unbind(){return this.unbindVAO(),this}draw(){const t=this.gl;return this.bindVAO(),this.useIndices?t.drawElements(t.TRIANGLES,this.indexCount,t.UNSIGNED_SHORT,0):t.drawArrays(t.TRIANGLE_STRIP,0,this.vertexCount),this}destroy(){const t=this.gl;this.deleteVAO(),this.vbo&&(t.deleteBuffer(this.vbo),this.vbo=null),this.ibo&&(t.deleteBuffer(this.ibo),this.ibo=null)}getPositionLocation(t){let e=t.getAttribLocation("a_position");return e>=0||(e=t.getAttribLocation("aPosition"),e>=0)||(e=t.getAttribLocation("position"),e>=0)?e:-1}getTexcoordLocation(t){let e=t.getAttribLocation("a_texcoord");return e>=0||(e=t.getAttribLocation("aTexCoord"),e>=0)||(e=t.getAttribLocation("texcoord"),e>=0)||(e=t.getAttribLocation("a_uv"),e>=0)?e:-1}createVAO(){this.isWebGL2?this.vao=this.gl.createVertexArray():this.vaoExt&&(this.vao=this.vaoExt.createVertexArrayOES())}bindVAO(){this.vao&&(this.isWebGL2?this.gl.bindVertexArray(this.vao):this.vaoExt&&this.vaoExt.bindVertexArrayOES(this.vao))}unbindVAO(){this.isWebGL2?this.gl.bindVertexArray(null):this.vaoExt&&this.vaoExt.bindVertexArrayOES(null)}deleteVAO(){this.vao&&(this.isWebGL2?this.gl.deleteVertexArray(this.vao):this.vaoExt&&this.vaoExt.deleteVertexArrayOES(this.vao),this.vao=null)}}class h{constructor(t){i(this,"gl");i(this,"program",null);i(this,"vertexShader",null);i(this,"fragmentShader",null);i(this,"version",1);this.gl=t}static detectVersion(t){return/^\s*#version\s+300\s+es/m.test(t)?2:1}compile(t,e){this.destroy();const r=h.detectVersion(t),s=h.detectVersion(e);if(r!=s)throw new L(r,s);return this.version=Math.max(r,s),this.vertexShader=this.compileShader("vertex",t),this.fragmentShader=this.compileShader("fragment",e),this.linkProgram(),this}use(){return this.program&&this.gl.useProgram(this.program),this}getProgram(){return this.program}getVersion(){return this.version}getAttribLocation(t){return this.program?this.gl.getAttribLocation(this.program,t):-1}getUniformLocation(t){return this.program?this.gl.getUniformLocation(this.program,t):null}destroy(){const t=this.gl;this.program&&(this.vertexShader&&t.detachShader(this.program,this.vertexShader),this.fragmentShader&&t.detachShader(this.program,this.fragmentShader),t.deleteProgram(this.program),this.program=null),this.vertexShader&&(t.deleteShader(this.vertexShader),this.vertexShader=null),this.fragmentShader&&(t.deleteShader(this.fragmentShader),this.fragmentShader=null)}compileShader(t,e){const r=this.gl,s=t==="vertex"?r.VERTEX_SHADER:r.FRAGMENT_SHADER,n=r.createShader(s);if(!n)throw new f(t,e,"Failed to create shader object");if(r.shaderSource(n,e),r.compileShader(n),!r.getShaderParameter(n,r.COMPILE_STATUS)){const c=r.getShaderInfoLog(n)||"Unknown error";throw r.deleteShader(n),new f(t,e,c)}return n}linkProgram(){const t=this.gl;if(!this.vertexShader||!this.fragmentShader)throw new d("Shaders not compiled");const e=t.createProgram();if(!e)throw new d("Failed to create program object");if(t.attachShader(e,this.vertexShader),t.attachShader(e,this.fragmentShader),t.linkProgram(e),!t.getProgramParameter(e,t.LINK_STATUS)){const s=t.getProgramInfoLog(e)||"Unknown error";throw t.deleteProgram(e),new d(s)}this.program=e}}class x{constructor(t,e){i(this,"name");i(this,"method");i(this,"isArray");i(this,"isMatrix");i(this,"location",null);i(this,"locationResolved",!1);i(this,"value");this.name=t,this.value=e;const r=x.inferMethodInfo(e);this.method=r.method,this.isArray=r.isArray,this.isMatrix=r.isMatrix}static inferMethodInfo(t){if(typeof t=="boolean")return{method:"uniform1i",isArray:!1,isMatrix:!1};if(typeof t=="number")return{method:"uniform1f",isArray:!1,isMatrix:!1};if(!Array.isArray(t))return{method:"uniform1f",isArray:!1,isMatrix:!1};const e=t.length,r=t[0];if(Array.isArray(r))switch(r.length){case 2:return{method:"uniform2fv",isArray:!0,isMatrix:!1};case 3:return{method:"uniform3fv",isArray:!0,isMatrix:!1};case 4:return{method:"uniform4fv",isArray:!0,isMatrix:!1};default:return{method:"uniform1fv",isArray:!0,isMatrix:!1}}switch(e){case 2:return{method:"uniform2fv",isArray:!1,isMatrix:!1};case 3:return{method:"uniform3fv",isArray:!1,isMatrix:!1};case 4:return{method:"uniform4fv",isArray:!1,isMatrix:!1};case 9:return{method:"uniformMatrix3fv",isArray:!1,isMatrix:!0};case 16:return{method:"uniformMatrix4fv",isArray:!1,isMatrix:!0};default:return{method:"uniform1fv",isArray:!0,isMatrix:!1}}}resolveLocation(t,e){return this.locationResolved||(this.location=t.getUniformLocation(e,this.name),this.locationResolved=!0),this.location}invalidateLocation(){this.location=null,this.locationResolved=!1}setValue(t){this.value=t}getValue(){return this.value}upload(t,e){const r=this.resolveLocation(t,e);if(r===null)return;const s=this.value;let n;switch(typeof s=="boolean"?n=s?1:0:typeof s=="number"?n=s:this.isArray&&Array.isArray(s[0])?n=new Float32Array(s.flat()):n=new Float32Array(s),this.method){case"uniform1f":t.uniform1f(r,n);break;case"uniform1i":t.uniform1i(r,n);break;case"uniform1fv":t.uniform1fv(r,n);break;case"uniform2fv":t.uniform2fv(r,n);break;case"uniform3fv":t.uniform3fv(r,n);break;case"uniform4fv":t.uniform4fv(r,n);break;case"uniformMatrix2fv":t.uniformMatrix2fv(r,!1,n);break;case"uniformMatrix3fv":t.uniformMatrix3fv(r,!1,n);break;case"uniformMatrix4fv":t.uniformMatrix4fv(r,!1,n);break}}}const m=class m{constructor(t){i(this,"gl");i(this,"program",null);i(this,"uniforms",new Map);this.gl=t}attachProgram(t){this.program=t;for(const e of this.uniforms.values())e.invalidateLocation();return this}set(t,e){const r=this.uniforms.get(t);return r?r.setValue(e):this.uniforms.set(t,new x(t,e)),this}setMany(t){for(const[e,r]of Object.entries(t))this.set(e,r);return this}get(t){var e;return(e=this.uniforms.get(t))==null?void 0:e.getValue()}has(t){return this.uniforms.has(t)}delete(t){return this.uniforms.delete(t)}uploadAll(){if(!this.program)return this;for(const t of this.uniforms.values())t.upload(this.gl,this.program);return this}uploadBuiltIns(t,e,r){if(this.set("u_resolution",e),this.set("u_time",t.time),this.set("u_delta",t.delta),this.set("u_mouse",r),this.set("u_frame",t.frame),!this.program)return this;for(const s of m.BUILT_INS){const n=this.uniforms.get(s);n&&n.upload(this.gl,this.program)}return this}clear(){this.uniforms.clear()}destroy(){this.uniforms.clear(),this.program=null}keys(){return this.uniforms.keys()}get size(){return this.uniforms.size}};i(m,"BUILT_INS",new Set(["u_resolution","u_time","u_delta","u_mouse","u_frame"]));let v=m;class A{constructor(){i(this,"hooks",new Map)}id(){return Math.random().toString(36).substring(2,10)}add(t){const e=this.id();return this.hooks.set(e,t),()=>this.remove(e)}remove(t){this.hooks.delete(t)}run(t){for(const[e,r]of this.hooks)r(t)===!1&&this.remove(e)}destroy(){this.hooks.clear()}}class b{constructor(t,e){i(this,"canvas");i(this,"gl");i(this,"options");i(this,"onBeforeHooks",new A);i(this,"onAfterHooks",new A);i(this,"_program");i(this,"_geometry");i(this,"_uniforms");i(this,"_clock");i(this,"_resolution",[1,1]);i(this,"_mouse",[0,0]);i(this,"_version",1);i(this,"playing",!1);this.canvas=t,this.options=e,this.gl=this.initContext(),this.enableExtensions(),this._program=new h(this.gl),this._geometry=p.fullscreenQuad(this.gl),this._uniforms=new v(this.gl),this._clock=new R,this.options.onBeforeRender&&this.onBeforeHooks.add(this.options.onBeforeRender),this.options.onAfterRender&&this.onAfterHooks.add(this.options.onAfterRender),this.onRender=this.onRender.bind(this)}static setup(t,e){const r=new b(t,e);return e.vertex&&e.fragment&&r.shader(e.vertex,e.fragment),e.uniforms&&r._uniforms.setMany(e.uniforms),r}initContext(){const t={antialias:this.options.antialias,preserveDrawingBuffer:this.options.preserveDrawingBuffer,alpha:!0,depth:!1,stencil:!1},e=this.canvas.getContext("webgl2",t);if(e)return this._version=2,e;const r=this.canvas.getContext("webgl",t);if(r)return this._version=1,r;const s=new S("not_supported");throw this.options.onError(s),s}enableExtensions(){this.gl.getExtension("OES_standard_derivatives"),this.gl.getExtension("OES_texture_float"),this.gl.getExtension("OES_texture_float_linear"),this._version===1&&this.gl.getExtension("OES_vertex_array_object")}viewport(t,e,r,s){return this.canvas.width=r,this.canvas.height=s,this.gl.viewport(t,e,r,s),this._resolution=[r,s],this}clock(t){return this._clock.setTime(t),this}mouse(t,e){return this._mouse=[t,e],this}uniform(t,e){return this._uniforms.set(t,e),this}uniforms(t){return this._uniforms.setMany(t),this}getUniform(t){return this._uniforms.get(t)}shader(t,e){try{this._program.compile(t,e),this._version=this._program.getVersion(),this._geometry.linkAttributes(this._program);const r=this._program.getProgram();r&&this._uniforms.attachProgram(r)}catch(r){r instanceof l&&this.options.onError(r)}return this}play(){return this.playing?this:(this.playing=!0,this._clock.start(this.onRender),this)}pause(){if(!this.playing)return this;const t=this._clock.getState();return this.onBeforeHooks.run(t),this.playing=!1,this._clock.stop(),this.onAfterHooks.run(t),this}render(){return this.onRender(this._clock.getState()),this}getContext(){return this.gl}getVersion(){return this._version}destroy(){this.pause(),this._clock.destroy(),this._geometry.destroy(),this._program.destroy(),this._uniforms.destroy(),this.onAfterHooks.destroy(),this.onBeforeHooks.destroy()}onRender(t){const e=this.gl;this.onBeforeHooks.run(t),e.clearColor(0,0,0,0),e.clear(e.COLOR_BUFFER_BIT),this._program.use(),this._uniforms.uploadBuiltIns(t,this._resolution,this._mouse),this._uniforms.uploadAll(),this._geometry.bind(),this._geometry.draw(),this.onAfterHooks.run(t)}}const g=`#ifdef GL_ES
6
6
  precision mediump float;
7
7
  #endif
8
8
 
@@ -54,4 +54,4 @@ void main() {
54
54
  vec3 color = vec3(uv.x, uv.y, 0.5 + 0.5 * sin(u_time));
55
55
  fragColor = vec4(color, 1.0);
56
56
  }`;class _{constructor(t,e){i(this,"listeners",[]);i(this,"canvas");i(this,"options");i(this,"engine");this.canvas=t,this.options=this.resolveOptions(e),this.engine=b.setup(this.canvas,this.options),this.setupListeners(),this.setViewport(),this.options.onLoad(),this.options.autoplay&&this.play()}static create(t,e){return new _(t,e)}resolveOptions(t){const e={vertex:g,fragment:y,autoplay:!0,pauseWhenHidden:!0,dpr:"auto",preserveDrawingBuffer:!1,antialias:!0,onError:r=>{console.error("Oops!",r,`
57
- You can handle errors programmatically by providing an onError callback to suppress this log and implement custom fallback behavior.`)},onLoad:()=>{},onBeforeRender:null,onAfterRender:null,uniforms:{}};if(t!=null&&t.vertex&&!(t!=null&&t.fragment)){const r=h.detectVersion(t.vertex);e.vertex=t.vertex,e.fragment=r===2?M:y}if(t!=null&&t.fragment&&!(t!=null&&t.vertex)){const r=h.detectVersion(t.fragment);e.fragment=t.fragment,e.vertex=r===2?E:g}return{...e,...t}}setupListeners(){this.listeners.push(u.on(window,"resize",()=>{this.setViewport()}),u.on(this.canvas,"resize",()=>{this.setViewport()}),(()=>{let t=!1;return u.on(document,"scroll",e=>{this.options.pauseWhenHidden&&(this.isInViewport()?t&&!this.isPlaying()&&(this.play(),t=!1):this.isPlaying()&&(this.pause(),t=!0))})})(),u.on(document,"mousemove",t=>{this.setMouse(t.clientX||t.pageX,t.clientY||t.pageY)}),u.on(document,"touchmove",t=>{t.touches.length>0&&this.setMouse(t.touches[0].clientX,t.touches[0].clientY)}))}destroyListeners(){this.listeners.forEach(t=>t()),this.listeners=[]}setViewport(){const t=this.options.dpr==="auto"?Math.min(2,window.devicePixelRatio||1):this.options.dpr,e=this.canvas.clientWidth||this.canvas.width||1,r=this.canvas.clientHeight||this.canvas.height||1;this.engine.viewport(0,0,Math.max(1,Math.floor(e*t)),Math.max(1,Math.floor(r*t)))}isInViewport(){const t=this.canvas.getBoundingClientRect();return t.bottom>=0&&t.right>=0&&t.top<=(window.innerHeight||document.documentElement.clientHeight)&&t.left<=(window.innerWidth||document.documentElement.clientWidth)}setMouse(t,e){const r=this.canvas.getBoundingClientRect();t>=r.left&&t<=r.right&&e>=r.top&&e<=r.bottom&&this.engine.mouse(t-r.left,e-r.top)}setUniform(t,e){return this.engine.uniform(t,e),this}setUniforms(t){return this.engine.uniforms(t),this}getUniform(t){return this.engine.getUniform(t)}setShader(t,e){return this.engine.shader(t,e),this}setFragment(t){const r=this.webglVersion()===1?g:E;return this.engine.shader(r,t),this}hook(t,e="before"){return e==="before"?this.engine.onBeforeHooks.add(t):this.engine.onAfterHooks.add(t)}play(){return this.engine.play(),this}playAt(t){return this.engine.clock(t),this.engine.play(),this}pause(){return this.engine.pause(),this}pauseAt(t){const e=this.hook(r=>{r.time>=t&&(e(),this.pause())},"after");return this}toggle(){return this.engine.playing?this.pause():this.play(),this}time(t){return this.engine.clock(t),this}render(){return this.engine.render(),this}renderAt(t){return this.engine.clock(t),this.engine.render(),this}isPlaying(){return this.engine.playing}webglVersion(){return this.engine.getVersion()}canvasElement(){return this.canvas}destroy(){this.destroyListeners(),this.engine.destroy()}}exports.Sandbox=_;exports.SandboxContextError=S;exports.SandboxError=l;exports.SandboxProgramError=d;exports.SandboxShaderCompilationError=c;exports.SandboxShaderVersionMismatchError=L;
57
+ You can handle errors programmatically by providing an onError callback to suppress this log and implement custom fallback behavior.`)},onLoad:()=>{},onBeforeRender:null,onAfterRender:null,uniforms:{}};if(t!=null&&t.vertex&&!(t!=null&&t.fragment)){const r=h.detectVersion(t.vertex);e.vertex=t.vertex,e.fragment=r===2?M:y}if(t!=null&&t.fragment&&!(t!=null&&t.vertex)){const r=h.detectVersion(t.fragment);e.fragment=t.fragment,e.vertex=r===2?E:g}return{...e,...t}}setupListeners(){this.listeners.push(u.on(window,"resize",()=>{this.setViewport()}),u.on(this.canvas,"resize",()=>{this.setViewport()}),(()=>{let t=!1;return u.on(document,"scroll",e=>{this.options.pauseWhenHidden&&(this.isInViewport()?t&&!this.isPlaying()&&(this.play(),t=!1):this.isPlaying()&&(this.pause(),t=!0))})})(),u.on(document,"mousemove",t=>{this.setMouse(t.clientX||t.pageX,t.clientY||t.pageY)}),u.on(document,"touchmove",t=>{t.touches.length>0&&this.setMouse(t.touches[0].clientX,t.touches[0].clientY)}))}destroyListeners(){this.listeners.forEach(t=>t()),this.listeners=[]}setViewport(){const t=this.options.dpr==="auto"?Math.min(2,window.devicePixelRatio||1):this.options.dpr,e=this.canvas.clientWidth||this.canvas.width||1,r=this.canvas.clientHeight||this.canvas.height||1;this.engine.viewport(0,0,Math.max(1,Math.floor(e*t)),Math.max(1,Math.floor(r*t)))}isInViewport(){const t=this.canvas.getBoundingClientRect();return t.bottom>=0&&t.right>=0&&t.top<=(window.innerHeight||document.documentElement.clientHeight)&&t.left<=(window.innerWidth||document.documentElement.clientWidth)}setMouse(t,e){const r=this.canvas.getBoundingClientRect();t>=r.left&&t<=r.right&&e>=r.top&&e<=r.bottom&&this.engine.mouse(t-r.left,e-r.top)}setUniform(t,e){return this.engine.uniform(t,e),this}setUniforms(t){return this.engine.uniforms(t),this}getUniform(t){return this.engine.getUniform(t)}setShader(t,e){return this.engine.shader(t,e),this}setFragment(t){const r=this.webglVersion()===1?g:E;return this.engine.shader(r,t),this}hook(t,e="before"){return e==="before"?this.engine.onBeforeHooks.add(t):this.engine.onAfterHooks.add(t)}play(){return this.engine.play(),this}playAt(t){return this.engine.clock(t),this.engine.play(),this}pause(){return this.engine.pause(),this}pauseAt(t){const e=this.hook(r=>{r.time>=t&&(e(),this.pause())},"after");return this}toggle(){return this.engine.playing?this.pause():this.play(),this}time(t){return this.engine.clock(t),this}render(){return this.engine.render(),this}renderAt(t){return this.engine.clock(t),this.engine.render(),this}isPlaying(){return this.engine.playing}webglVersion(){return this.engine.getVersion()}canvasElement(){return this.canvas}destroy(){this.destroyListeners(),this.engine.destroy()}}exports.Sandbox=_;exports.SandboxContextError=S;exports.SandboxError=l;exports.SandboxProgramError=d;exports.SandboxShaderCompilationError=f;exports.SandboxShaderVersionMismatchError=L;
package/dist/index.es.js CHANGED
@@ -103,9 +103,11 @@ class R {
103
103
  */
104
104
  start(t) {
105
105
  if (this.running) return this;
106
- this.callback = t, this.running = !0;
107
- const e = performance.now();
108
- return this.startTime = e, this.lastTime = e, this.rafId = requestAnimationFrame(this.loop), this;
106
+ if (this.callback = t, this.running = !0, this.frame === 0) {
107
+ const e = performance.now();
108
+ this.startTime = e, this.lastTime = e;
109
+ }
110
+ return this.rafId = requestAnimationFrame(this.loop), this;
109
111
  }
110
112
  /**
111
113
  * Stop the animation loop.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rosalana/sandbox",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Lightweight WebGL wrapper for simple, beautiful shader effects",
5
5
  "keywords": [
6
6
  "webgl",