@rosalana/sandbox 0.0.1 → 0.0.2
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/README.md +30 -18
- package/dist/index.cjs.js +4 -4
- package/dist/index.es.js +14 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
[](https://github.com/rosalana)
|
|
2
2
|
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@rosalana/sandbox)
|
|
6
|
+
[](https://www.npmjs.com/package/@rosalana/sandbox)
|
|
7
|
+
[](https://github.com/rosalana/sandbox/stargazers)
|
|
8
|
+
[](https://github.com/rosalana/sandbox/blob/master/LICENCE)
|
|
9
|
+
|
|
10
|
+
[](https://codesandbox.io/p/sandbox/nervous-greider-76wsrk)
|
|
11
|
+
[](https://github.com/rosalana/sandbox/issues)
|
|
12
|
+
|
|
13
|
+
</div>
|
|
14
|
+
|
|
3
15
|
**Rosalana Sandbox** is a lightweight WebGL wrapper for **simple, beautiful shader effects**. It focuses on a clean API, type safety, and fast setup so you can go from idea to a shader in minutes.
|
|
4
16
|
|
|
5
17
|
It's **DX‑friendly**, small, and intentionally minimal — perfect for gradients, ambient backgrounds, and animated GLSL experiments. If you're not building a full 3D engine, Sandbox is a delightful alternative to larger libraries like three.js or p5.js.
|
|
6
18
|
|
|
7
19
|
### Bundle size comparison
|
|
8
20
|
|
|
9
|
-
| Library
|
|
10
|
-
|
|
|
11
|
-
| **Sandbox**
|
|
12
|
-
| three.js
|
|
13
|
-
| p5.js
|
|
21
|
+
| Library | Minified | Gzipped |
|
|
22
|
+
| ----------- | -------- | -------- |
|
|
23
|
+
| **Sandbox** | 31 KB | **8 KB** |
|
|
24
|
+
| three.js | 694 KB | 175 KB |
|
|
25
|
+
| p5.js | 1.1 MB | 351 KB |
|
|
14
26
|
|
|
15
27
|
Sandbox is **~22x smaller** than three.js and **~44x smaller** than p5.js.
|
|
16
28
|
|
|
@@ -325,20 +337,20 @@ interface SandboxOptions {
|
|
|
325
337
|
}
|
|
326
338
|
```
|
|
327
339
|
|
|
328
|
-
| Option | Default
|
|
329
|
-
| ----------------------- |
|
|
330
|
-
| `vertex` | built-in
|
|
331
|
-
| `fragment` | built-in
|
|
332
|
-
| `autoplay` | `true`
|
|
333
|
-
| `pauseWhenHidden` | `true`
|
|
334
|
-
| `dpr` | `"auto"`
|
|
335
|
-
| `preserveDrawingBuffer` | `false`
|
|
336
|
-
| `antialias` | `true`
|
|
340
|
+
| Option | Default | Description |
|
|
341
|
+
| ----------------------- | --------------- | ------------------------------- |
|
|
342
|
+
| `vertex` | built-in | Custom vertex shader |
|
|
343
|
+
| `fragment` | built-in | Fragment shader |
|
|
344
|
+
| `autoplay` | `true` | Start rendering immediately |
|
|
345
|
+
| `pauseWhenHidden` | `true` | Pause when scrolled out of view |
|
|
346
|
+
| `dpr` | `"auto"` | Device pixel ratio |
|
|
347
|
+
| `preserveDrawingBuffer` | `false` | Keep buffer for screenshots |
|
|
348
|
+
| `antialias` | `true` | Enable antialiasing |
|
|
337
349
|
| `onError` | `console.error` | Error callback |
|
|
338
|
-
| `onLoad` | —
|
|
339
|
-
| `onBeforeRender` | —
|
|
340
|
-
| `onAfterRender` | —
|
|
341
|
-
| `uniforms` | —
|
|
350
|
+
| `onLoad` | — | Called when ready |
|
|
351
|
+
| `onBeforeRender` | — | Hook before each frame |
|
|
352
|
+
| `onAfterRender` | — | Hook after each frame |
|
|
353
|
+
| `uniforms` | — | Initial uniform values |
|
|
342
354
|
|
|
343
355
|
## Limitations (by design)
|
|
344
356
|
|
package/dist/index.cjs.js
CHANGED
|
@@ -15,7 +15,7 @@ void main() {
|
|
|
15
15
|
v_texcoord = a_texcoord;
|
|
16
16
|
gl_Position = vec4(a_position, 0.0, 1.0);
|
|
17
17
|
}
|
|
18
|
-
`,
|
|
18
|
+
`,y=`#ifdef GL_ES
|
|
19
19
|
precision mediump float;
|
|
20
20
|
#endif
|
|
21
21
|
|
|
@@ -29,7 +29,7 @@ void main() {
|
|
|
29
29
|
vec3 color = vec3(uv.x, uv.y, 0.5 + 0.5 * sin(u_time));
|
|
30
30
|
gl_FragColor = vec4(color, 1.0);
|
|
31
31
|
}
|
|
32
|
-
`,
|
|
32
|
+
`,E=`#version 300 es
|
|
33
33
|
|
|
34
34
|
in vec2 a_position;
|
|
35
35
|
in vec2 a_texcoord;
|
|
@@ -53,5 +53,5 @@ void main() {
|
|
|
53
53
|
vec2 uv = gl_FragCoord.xy / u_resolution;
|
|
54
54
|
vec3 color = vec3(uv.x, uv.y, 0.5 + 0.5 * sin(u_time));
|
|
55
55
|
fragColor = vec4(color, 1.0);
|
|
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:
|
|
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:
|
|
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;
|
package/dist/index.es.js
CHANGED
|
@@ -42,9 +42,9 @@ class k extends u {
|
|
|
42
42
|
), this.vertexVersion = t, this.fragmentVersion = e, this.name = "SandboxShaderVersionMismatchError";
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
class
|
|
45
|
+
class c extends u {
|
|
46
46
|
constructor(e, r, s) {
|
|
47
|
-
const n =
|
|
47
|
+
const n = c.parseErrorLines(s), a = n.length > 0 ? ` at line(s): ${n.join(", ")}` : "";
|
|
48
48
|
super(
|
|
49
49
|
`${e} shader compilation failed${a}
|
|
50
50
|
|
|
@@ -68,8 +68,8 @@ ${s}`,
|
|
|
68
68
|
for (const n of r) {
|
|
69
69
|
let a;
|
|
70
70
|
for (; (a = n.exec(e)) !== null; ) {
|
|
71
|
-
const
|
|
72
|
-
|
|
71
|
+
const f = parseInt(a[1], 10);
|
|
72
|
+
f > 0 && s.add(f);
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
return [...s].sort((n, a) => n - a);
|
|
@@ -365,14 +365,14 @@ class h {
|
|
|
365
365
|
compileShader(t, e) {
|
|
366
366
|
const r = this.gl, s = t === "vertex" ? r.VERTEX_SHADER : r.FRAGMENT_SHADER, n = r.createShader(s);
|
|
367
367
|
if (!n)
|
|
368
|
-
throw new
|
|
368
|
+
throw new c(
|
|
369
369
|
t,
|
|
370
370
|
e,
|
|
371
371
|
"Failed to create shader object"
|
|
372
372
|
);
|
|
373
373
|
if (r.shaderSource(n, e), r.compileShader(n), !r.getShaderParameter(n, r.COMPILE_STATUS)) {
|
|
374
|
-
const
|
|
375
|
-
throw r.deleteShader(n), new
|
|
374
|
+
const f = r.getShaderInfoLog(n) || "Unknown error";
|
|
375
|
+
throw r.deleteShader(n), new c(t, e, f);
|
|
376
376
|
}
|
|
377
377
|
return n;
|
|
378
378
|
}
|
|
@@ -924,9 +924,12 @@ You can handle errors programmatically by providing an onError callback to suppr
|
|
|
924
924
|
this.setViewport();
|
|
925
925
|
}),
|
|
926
926
|
// Visibility check on scroll
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
927
|
+
(() => {
|
|
928
|
+
let t = !1;
|
|
929
|
+
return l.on(document, "scroll", (e) => {
|
|
930
|
+
this.options.pauseWhenHidden && (this.isInViewport() ? t && !this.isPlaying() && (this.play(), t = !1) : this.isPlaying() && (this.pause(), t = !0));
|
|
931
|
+
});
|
|
932
|
+
})(),
|
|
930
933
|
// Mouse tracking
|
|
931
934
|
l.on(document, "mousemove", (t) => {
|
|
932
935
|
this.setMouse(t.clientX || t.pageX, t.clientY || t.pageY);
|
|
@@ -1102,6 +1105,6 @@ export {
|
|
|
1102
1105
|
w as SandboxContextError,
|
|
1103
1106
|
u as SandboxError,
|
|
1104
1107
|
m as SandboxProgramError,
|
|
1105
|
-
|
|
1108
|
+
c as SandboxShaderCompilationError,
|
|
1106
1109
|
k as SandboxShaderVersionMismatchError
|
|
1107
1110
|
};
|