@rosalana/sandbox 0.0.5 → 0.1.0
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 +153 -46
- package/dist/errors/base.d.ts +6 -0
- package/dist/errors/context.d.ts +7 -0
- package/dist/errors/index.d.ts +6 -0
- package/dist/errors/module.d.ts +42 -0
- package/dist/errors/program.d.ts +5 -0
- package/dist/errors/shader.d.ts +34 -0
- package/dist/errors/unknown.d.ts +7 -0
- package/dist/globals.d.ts +17 -0
- package/dist/index.cjs.js +834 -8
- package/dist/index.d.ts +43 -1
- package/dist/index.es.js +2292 -387
- package/dist/tools/compilable.d.ts +79 -0
- package/dist/tools/module.d.ts +46 -0
- package/dist/tools/module_registry.d.ts +63 -0
- package/dist/tools/parser.d.ts +32 -0
- package/dist/tools/program.d.ts +1 -12
- package/dist/tools/shader.d.ts +4 -0
- package/dist/tools/uniforms.d.ts +0 -2
- package/dist/tools/web_gl.d.ts +2 -1
- package/dist/types.d.ts +90 -1
- package/package.json +8 -5
- package/dist/errors.d.ts +0 -32
package/README.md
CHANGED
|
@@ -18,13 +18,13 @@ It's **DX‑friendly**, small, and intentionally minimal — perfect for gradien
|
|
|
18
18
|
|
|
19
19
|
### Bundle size comparison
|
|
20
20
|
|
|
21
|
-
| Library | Minified | Gzipped
|
|
22
|
-
| ----------- | -------- |
|
|
23
|
-
| **Sandbox** |
|
|
24
|
-
| three.js | 694 KB | 175 KB
|
|
25
|
-
| p5.js | 1.1 MB | 351 KB
|
|
21
|
+
| Library | Minified | Gzipped |
|
|
22
|
+
| ----------- | -------- | --------- |
|
|
23
|
+
| **Sandbox** | 85 KB | **23 KB** |
|
|
24
|
+
| three.js | 694 KB | 175 KB |
|
|
25
|
+
| p5.js | 1.1 MB | 351 KB |
|
|
26
26
|
|
|
27
|
-
Sandbox is **~
|
|
27
|
+
Sandbox is **~8x smaller** than three.js and **~15x smaller** than p5.js.
|
|
28
28
|
|
|
29
29
|
It works in both **WebGL1 and WebGL2** contexts, with automatic fallback and detection.
|
|
30
30
|
|
|
@@ -35,10 +35,7 @@ It works in both **WebGL1 and WebGL2** contexts, with automatic fallback and det
|
|
|
35
35
|
- [Playback control](#playback-control)
|
|
36
36
|
- [Time control](#time-control)
|
|
37
37
|
- [Static rendering](#static-rendering)
|
|
38
|
-
- [Shaders](#shaders)
|
|
39
|
-
- [WebGL version detection](#webgl-version-detection)
|
|
40
|
-
- [Uniforms](#uniforms)
|
|
41
|
-
- [Built‑in uniforms](#built-in-uniforms)
|
|
38
|
+
- [Sandbox Shaders](#sandbox-shaders)
|
|
42
39
|
- [Hooks](#hooks)
|
|
43
40
|
- [Self-removing hooks](#self-removing-hooks)
|
|
44
41
|
- [Chaining](#chaining)
|
|
@@ -120,76 +117,177 @@ Or render at a specific time — perfect for deterministic, reproducible output:
|
|
|
120
117
|
sandbox.renderAt(1.5);
|
|
121
118
|
```
|
|
122
119
|
|
|
123
|
-
## Shaders
|
|
120
|
+
## Sandbox Shaders
|
|
124
121
|
|
|
125
|
-
|
|
122
|
+
Writing GLSL from scratch means a lot of ceremony — uniform declarations, copy-pasting utility functions, wiring everything together. Sandbox takes care of the boring parts so you can focus on the shader itself.
|
|
126
123
|
|
|
127
|
-
|
|
124
|
+
The idea is simple: define reusable GLSL snippets as **modules**, then `#import` them with a single line. Sandbox resolves dependencies, declares uniforms, and injects everything into the final shader automatically.
|
|
125
|
+
|
|
126
|
+
### Writing shaders
|
|
127
|
+
|
|
128
|
+
You only need to provide a fragment shader. Sandbox ships with a default fullscreen vertex shader and automatically matches WebGL versions — so you can focus on the fun part.
|
|
128
129
|
|
|
129
130
|
```ts
|
|
130
131
|
sandbox.setFragment(fragmentSource);
|
|
131
132
|
```
|
|
132
133
|
|
|
133
|
-
|
|
134
|
+
Need full control over both shaders? No problem:
|
|
134
135
|
|
|
135
136
|
```ts
|
|
136
137
|
sandbox.setShader(vertexSource, fragmentSource);
|
|
137
138
|
```
|
|
138
139
|
|
|
139
|
-
|
|
140
|
+
Sandbox detects WebGL version from your code (`#version 300 es` → WebGL2, no directive → WebGL1) and falls back gracefully. You can always check what you're running:
|
|
140
141
|
|
|
141
|
-
|
|
142
|
+
```ts
|
|
143
|
+
sandbox.version; // 1 or 2
|
|
144
|
+
```
|
|
142
145
|
|
|
143
|
-
-
|
|
144
|
-
- no version directive → WebGL1
|
|
146
|
+
### Built-in uniforms
|
|
145
147
|
|
|
146
|
-
|
|
148
|
+
These uniforms are populated automatically every frame. Just use them in your shader — no declaration or setup needed:
|
|
149
|
+
|
|
150
|
+
| Uniform | Type | Description |
|
|
151
|
+
| -------------- | ----- | --------------------------- |
|
|
152
|
+
| `u_resolution` | vec2 | Canvas size in pixels |
|
|
153
|
+
| `u_time` | float | Elapsed time (seconds) |
|
|
154
|
+
| `u_delta` | float | Delta time since last frame |
|
|
155
|
+
| `u_mouse` | vec2 | Mouse position on canvas |
|
|
156
|
+
| `u_frame` | int | Frame counter |
|
|
157
|
+
|
|
158
|
+
Built-in uniforms are globally available — even inside imported module functions. They're never namespaced, so `u_time` is always just `u_time`, everywhere.
|
|
159
|
+
|
|
160
|
+
### Custom uniforms
|
|
161
|
+
|
|
162
|
+
Need your own data in the shader? Declare the uniform in GLSL, then set it from JavaScript:
|
|
147
163
|
|
|
148
164
|
```ts
|
|
149
|
-
sandbox.
|
|
165
|
+
sandbox.setUniform<number>("u_intensity", 0.8);
|
|
166
|
+
|
|
167
|
+
sandbox.setUniforms({
|
|
168
|
+
u_intensity: 0.75,
|
|
169
|
+
u_color: [1, 0.2, 0.3],
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Read a value back:
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
const intensity = sandbox.getUniform<number>("u_intensity");
|
|
150
177
|
```
|
|
151
178
|
|
|
152
|
-
|
|
179
|
+
Everything is **type-safe** and **chainable**. All numeric values are treated as floats — simple and predictable.
|
|
153
180
|
|
|
154
|
-
|
|
181
|
+
### Modules
|
|
155
182
|
|
|
156
|
-
|
|
183
|
+
> [!IMPORTANT]
|
|
184
|
+
> Sandbox's built-in GLSL modules are still in beta and may change at any time.
|
|
185
|
+
> We published them early to get feedback. If you have ideas for improvements, please open an issue or a PR — we'd love your input.
|
|
186
|
+
|
|
187
|
+
Modules are reusable GLSL snippets that you can import into any shader. Sandbox ships with a built-in `"sandbox"` module, and you can define your own:
|
|
157
188
|
|
|
158
189
|
```ts
|
|
159
|
-
|
|
190
|
+
Sandbox.defineModule("my_effects", myGLSLSource);
|
|
160
191
|
```
|
|
161
192
|
|
|
162
|
-
|
|
193
|
+
Then import any function from it:
|
|
194
|
+
|
|
195
|
+
```glsl
|
|
196
|
+
#import bloom from "my_effects"
|
|
197
|
+
#import hex from "sandbox"
|
|
198
|
+
|
|
199
|
+
void main() {
|
|
200
|
+
vec3 color = hex(0xFF5733);
|
|
201
|
+
fragColor = vec4(bloom(color), 1.0);
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
When you import a function, Sandbox pulls in everything it needs — the function body, any helper functions it calls, and any required uniforms. Each import is fully isolated, so importing the same function twice won't cause conflicts.
|
|
206
|
+
|
|
207
|
+
> [!NOTE]
|
|
208
|
+
> All imported code is namespaced automatically to avoid naming collisions.
|
|
209
|
+
|
|
210
|
+
Module names starting with `"sandbox"` are reserved for built-in modules. Each module can only be defined once — this prevents accidental overwrites.
|
|
211
|
+
|
|
212
|
+
Want to see what's available? Inspect all registered modules at any time:
|
|
163
213
|
|
|
164
214
|
```ts
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
215
|
+
Sandbox.availableModules();
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
You can also preview how your shader will look after processing:
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
Sandbox.compile(shaderSource);
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
This is useful for debugging or precompiling shaders before deploying.
|
|
225
|
+
|
|
226
|
+
### Module options
|
|
227
|
+
|
|
228
|
+
Imported functions can expose configurable options — friendly names that map to GLSL uniforms under the hood. You control them from JavaScript using `sandbox.module()`:
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
sandbox.module("effect", {
|
|
232
|
+
intensity: 0.8,
|
|
171
233
|
});
|
|
172
234
|
```
|
|
173
235
|
|
|
174
|
-
|
|
236
|
+
This is a powerful way to customize imported effects without touching any GLSL code.
|
|
237
|
+
|
|
238
|
+
#### Hardcoded vs. dynamic values
|
|
239
|
+
|
|
240
|
+
By default, a module's uniforms are only included in the final shader when you actually reference them. This gives you a choice — hardcode a value directly, or use the `@` syntax to wire it up as a configurable uniform:
|
|
241
|
+
|
|
242
|
+
```glsl
|
|
243
|
+
#import effect from "my_module"
|
|
244
|
+
|
|
245
|
+
void main() {
|
|
246
|
+
vec3 a = effect(v_texcoord, 2.0); // hardcoded value
|
|
247
|
+
vec3 b = effect(v_texcoord, @effect.intensity); // dynamic — set via sandbox.module()
|
|
248
|
+
fragColor = vec4(a + b, 1.0);
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
The `@effect.intensity` syntax tells Sandbox to inject the uniform and keep it in sync with whatever you set in JavaScript.
|
|
253
|
+
|
|
254
|
+
#### Defining options
|
|
255
|
+
|
|
256
|
+
When defining a module, you declare which options each function supports:
|
|
175
257
|
|
|
176
258
|
```ts
|
|
177
|
-
|
|
259
|
+
Sandbox.defineModule("my_gradient", gradientSource, {
|
|
260
|
+
myFunc: {
|
|
261
|
+
colors: {
|
|
262
|
+
uniform: "u_colors",
|
|
263
|
+
default: [[1, 0, 0], [0, 0, 1]],
|
|
264
|
+
},
|
|
265
|
+
speed: { uniform: "u_speed", default: 1.0 },
|
|
266
|
+
},
|
|
267
|
+
});
|
|
178
268
|
```
|
|
179
269
|
|
|
180
|
-
|
|
270
|
+
Each option has a `uniform` (the GLSL name it maps to) and an optional `default` value applied automatically on import.
|
|
181
271
|
|
|
182
|
-
|
|
272
|
+
If all functions in your module share the same options, use the `default` key to avoid repetition:
|
|
183
273
|
|
|
184
|
-
|
|
274
|
+
```ts
|
|
275
|
+
Sandbox.defineModule("my_module", source, {
|
|
276
|
+
default: {
|
|
277
|
+
colors: {
|
|
278
|
+
uniform: "u_colors",
|
|
279
|
+
default: [[1, 0, 0], [0, 0, 1]],
|
|
280
|
+
},
|
|
281
|
+
speed: { uniform: "u_speed", default: 1.0 },
|
|
282
|
+
},
|
|
283
|
+
specialFunc: {
|
|
284
|
+
speed: { uniform: "u_speed", default: 2.0 },
|
|
285
|
+
// "colors" is inherited from default
|
|
286
|
+
},
|
|
287
|
+
});
|
|
288
|
+
```
|
|
185
289
|
|
|
186
|
-
|
|
187
|
-
| -------------- | ----- | --------------------------- |
|
|
188
|
-
| `u_resolution` | vec2 | Canvas size in pixels |
|
|
189
|
-
| `u_time` | float | Elapsed time (seconds) |
|
|
190
|
-
| `u_delta` | float | Delta time since last frame |
|
|
191
|
-
| `u_mouse` | vec2 | Mouse position on canvas |
|
|
192
|
-
| `u_frame` | int | Frame counter |
|
|
290
|
+
Per-function options always take priority over `default` when both define the same key.
|
|
193
291
|
|
|
194
292
|
## Hooks
|
|
195
293
|
|
|
@@ -264,11 +362,18 @@ Sandbox.create(canvas, {
|
|
|
264
362
|
|
|
265
363
|
The error object includes useful details:
|
|
266
364
|
|
|
267
|
-
- `error.code` — error
|
|
268
|
-
- `error.lines` — line numbers where errors occurred (for compilation errors)
|
|
365
|
+
- `error.code` — error category (see table below)
|
|
366
|
+
- `error.lines` — line numbers where errors occurred (for shader compilation errors)
|
|
269
367
|
- `error.shaderType` — which shader failed (`vertex` or `fragment`)
|
|
270
368
|
|
|
271
|
-
|
|
369
|
+
| Code | When |
|
|
370
|
+
| ------------------ | ------------------------------------------------------------------------------------- |
|
|
371
|
+
| `CONTEXT_ERROR` | WebGL not supported or context creation failed |
|
|
372
|
+
| `SHADER_ERROR` | Shader compilation failed, version mismatch, import syntax error, or missing function |
|
|
373
|
+
| `PROGRAM_ERROR` | Shader program linking failed |
|
|
374
|
+
| `VALIDATION_ERROR` | Vertex/fragment shader version mismatch |
|
|
375
|
+
| `MODULE_ERROR` | Module not found, method not found, forbidden name, or duplicate definition |
|
|
376
|
+
| `UNKNOWN_ERROR` | Unexpected error in callbacks (onLoad, hooks) |
|
|
272
377
|
|
|
273
378
|
## Vue integration
|
|
274
379
|
|
|
@@ -337,6 +442,7 @@ interface SandboxOptions {
|
|
|
337
442
|
onBeforeRender?: HookCallback | null;
|
|
338
443
|
onAfterRender?: HookCallback | null;
|
|
339
444
|
uniforms?: UniformSchema;
|
|
445
|
+
modules?: Record<string, Record<string, AnyUniformValue>>;
|
|
340
446
|
}
|
|
341
447
|
```
|
|
342
448
|
|
|
@@ -355,6 +461,7 @@ interface SandboxOptions {
|
|
|
355
461
|
| `onBeforeRender` | — | Hook before each frame |
|
|
356
462
|
| `onAfterRender` | — | Hook after each frame |
|
|
357
463
|
| `uniforms` | — | Initial uniform values |
|
|
464
|
+
| `modules` | — | Configure module options per imported function |
|
|
358
465
|
|
|
359
466
|
## Limitations (by design)
|
|
360
467
|
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type SandboxErrorCode = "CONTEXT_ERROR" | "VALIDATION_ERROR" | "PROGRAM_ERROR" | "SHADER_ERROR" | "MODULE_ERROR" | "UNKNOWN_ERROR";
|
|
2
|
+
export declare class SandboxError extends Error {
|
|
3
|
+
readonly code: SandboxErrorCode;
|
|
4
|
+
readonly name: string;
|
|
5
|
+
constructor(message: string, code: SandboxErrorCode);
|
|
6
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { SandboxError } from "./base";
|
|
2
|
+
export declare class SandboxModuleNotFoundError extends SandboxError {
|
|
3
|
+
readonly moduleName: string;
|
|
4
|
+
constructor(moduleName: string);
|
|
5
|
+
}
|
|
6
|
+
export declare class SandboxModuleMethodNotFoundError extends SandboxError {
|
|
7
|
+
readonly moduleName: string;
|
|
8
|
+
readonly methodName: string;
|
|
9
|
+
constructor(moduleName: string, methodName: string);
|
|
10
|
+
}
|
|
11
|
+
export declare class SandboxAttemptedToImportMainFunctionError extends SandboxError {
|
|
12
|
+
readonly moduleName: string;
|
|
13
|
+
constructor(moduleName: string);
|
|
14
|
+
}
|
|
15
|
+
export declare class SandboxAttemptedToImportDefaultFunctionError extends SandboxError {
|
|
16
|
+
readonly moduleName: string;
|
|
17
|
+
constructor(moduleName: string);
|
|
18
|
+
}
|
|
19
|
+
export declare class SandboxForbiddenModuleNameError extends SandboxError {
|
|
20
|
+
readonly moduleName: string;
|
|
21
|
+
constructor(moduleName: string);
|
|
22
|
+
}
|
|
23
|
+
export declare class SandboxOverwriteModuleError extends SandboxError {
|
|
24
|
+
readonly moduleName: string;
|
|
25
|
+
constructor(moduleName: string);
|
|
26
|
+
}
|
|
27
|
+
export declare class SandboxMentionUniformNotFoundError extends SandboxError {
|
|
28
|
+
readonly moduleName: string;
|
|
29
|
+
readonly functionName: string;
|
|
30
|
+
readonly uniformName: string;
|
|
31
|
+
constructor(moduleName: string, functionName: string, uniformName: string);
|
|
32
|
+
}
|
|
33
|
+
export declare class SandboxMentionFunctionNotFoundError extends SandboxError {
|
|
34
|
+
readonly functionName: string;
|
|
35
|
+
readonly uniformName: string;
|
|
36
|
+
constructor(functionName: string, uniformName: string);
|
|
37
|
+
}
|
|
38
|
+
export declare class SandboxMentionCouldNotBeReplacedError extends SandboxError {
|
|
39
|
+
readonly mentionName: string;
|
|
40
|
+
readonly calledInFunction: string;
|
|
41
|
+
constructor(mentionName: string, calledInFunction: string);
|
|
42
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { SandboxError } from "./base";
|
|
2
|
+
export declare class SandboxShaderVersionMismatchError extends SandboxError {
|
|
3
|
+
readonly vertexVersion: number;
|
|
4
|
+
readonly fragmentVersion: number;
|
|
5
|
+
constructor(vertexVersion: number, fragmentVersion: number);
|
|
6
|
+
}
|
|
7
|
+
export declare class SandboxGLSLShaderCompilationError extends SandboxError {
|
|
8
|
+
readonly shaderType: "vertex" | "fragment";
|
|
9
|
+
readonly source: string;
|
|
10
|
+
readonly infoLog: string;
|
|
11
|
+
readonly lines: number[];
|
|
12
|
+
constructor(shaderType: "vertex" | "fragment", source: string, infoLog: string);
|
|
13
|
+
private static parseErrorLines;
|
|
14
|
+
}
|
|
15
|
+
export declare class SandboxShaderRequirementMismatchError extends SandboxError {
|
|
16
|
+
readonly requirement: "uniform" | "function";
|
|
17
|
+
readonly name: string;
|
|
18
|
+
readonly expectedType: string;
|
|
19
|
+
readonly actualType: string;
|
|
20
|
+
constructor(requirement: "uniform" | "function", name: string, expectedType: string, actualType: string);
|
|
21
|
+
}
|
|
22
|
+
export declare class SandboxShaderWithoutFunctionError extends SandboxError {
|
|
23
|
+
constructor();
|
|
24
|
+
}
|
|
25
|
+
export declare class SandboxShaderImportSyntaxError extends SandboxError {
|
|
26
|
+
readonly line: number;
|
|
27
|
+
readonly details: string;
|
|
28
|
+
constructor(line: number, details: string);
|
|
29
|
+
}
|
|
30
|
+
export declare class SandboxShaderDuplicateImportNameError extends SandboxError {
|
|
31
|
+
readonly name: string;
|
|
32
|
+
readonly line: number;
|
|
33
|
+
constructor(name: string, line: number);
|
|
34
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { SandboxError } from "./base";
|
|
2
|
+
export declare class SandboxOnLoadCallbackError extends SandboxError {
|
|
3
|
+
constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
export declare class SandboxOnHookCallbackError extends SandboxError {
|
|
6
|
+
constructor(id: string, message: string);
|
|
7
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import ModuleRegistry from "./tools/module_registry";
|
|
2
|
+
/**
|
|
3
|
+
* Default modules bundled with Sandbox.
|
|
4
|
+
* These modules are available for import in shader source without needing to be registered manually.
|
|
5
|
+
* This registry will grow when more modules are defined
|
|
6
|
+
*/
|
|
7
|
+
export declare const modules: ModuleRegistry;
|
|
8
|
+
/**
|
|
9
|
+
* A global registry of modules that are currently in use by the webGL context.
|
|
10
|
+
* This is flushed on every shader switch.
|
|
11
|
+
*/
|
|
12
|
+
export declare const runtime_modules: ModuleRegistry;
|
|
13
|
+
/**
|
|
14
|
+
* Global uniforms that are automatically provided by Sandbox.
|
|
15
|
+
* These uniforms will NOT be renamed during preprocessing.
|
|
16
|
+
*/
|
|
17
|
+
export declare const uniforms: Map<string, import("./types").GLSLType>;
|