vireglass 2.1.0 → 2.3.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 +41 -1
- package/dist/{chunk-3PGYF2NK.js → chunk-CTTZNZFV.js} +3 -3
- package/dist/{chunk-3PGYF2NK.js.map → chunk-CTTZNZFV.js.map} +1 -1
- package/dist/{chunk-FL5UZPY5.js → chunk-H5QTBF67.js} +4 -4
- package/dist/{chunk-FL5UZPY5.js.map → chunk-H5QTBF67.js.map} +1 -1
- package/dist/{chunk-TTOKBARR.js → chunk-MMPK6DCK.js} +10 -3
- package/dist/chunk-MMPK6DCK.js.map +1 -0
- package/dist/{chunk-BZC2WHCK.js → chunk-PM2SWCSF.js} +4 -4
- package/dist/{chunk-BZC2WHCK.js.map → chunk-PM2SWCSF.js.map} +1 -1
- package/dist/{chunk-P2ZOODXD.js → chunk-SLRPHDV7.js} +3 -3
- package/dist/{chunk-P2ZOODXD.js.map → chunk-SLRPHDV7.js.map} +1 -1
- package/dist/dom.cjs +48 -20
- package/dist/dom.cjs.map +1 -1
- package/dist/dom.d.cts +15 -3
- package/dist/dom.d.ts +15 -3
- package/dist/dom.js +44 -23
- package/dist/dom.js.map +1 -1
- package/dist/index.cjs +1 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -5
- package/dist/law.cjs +8 -1
- package/dist/law.cjs.map +1 -1
- package/dist/law.d.cts +7 -0
- package/dist/law.d.ts +7 -0
- package/dist/law.js +1 -1
- package/dist/reference.js +2 -2
- package/dist/web/index.cjs +262 -153
- package/dist/web/index.cjs.map +1 -1
- package/dist/web/index.d.cts +88 -2
- package/dist/web/index.d.ts +88 -2
- package/dist/web/index.js +257 -156
- package/dist/web/index.js.map +1 -1
- package/docs/law.md +2 -2
- package/package.json +13 -9
- package/src/dom/body.ts +24 -9
- package/src/dom/index.ts +44 -10
- package/src/dom/probe.ts +27 -3
- package/src/law.ts +7 -0
- package/src/targets/glsl.ts +4 -0
- package/src/web/gl.ts +57 -4
- package/src/web/gpu-timer.ts +111 -0
- package/src/web/index.ts +1 -0
- package/src/web/renderer.ts +305 -218
- package/dist/chunk-TTOKBARR.js.map +0 -1
package/dist/web/index.d.cts
CHANGED
|
@@ -43,6 +43,42 @@ type VireGlassSceneDrawer = (ctx: CanvasRenderingContext2D, width: number, heigh
|
|
|
43
43
|
* on a phone, and an element of the same size looked completely different on the lab bench
|
|
44
44
|
* than on a device. */
|
|
45
45
|
density: number) => void;
|
|
46
|
+
/** The target a `VireGlassBackdropPass` must finish its frame in — the FBO wraps `contentTexture`
|
|
47
|
+
* itself, so drawing into it needs no readback: the very texture the lens samples gets the pixels
|
|
48
|
+
* directly. */
|
|
49
|
+
type VireGlassBackdropTarget = {
|
|
50
|
+
/** Owned by the renderer — the FBO wrapping `contentTexture` itself, recreated on `resize` and
|
|
51
|
+
* freed in `destroy`. The pass must not delete it, and must not hold onto it past the call:
|
|
52
|
+
* the object may be gone or pointing at a different texture by the next `render()`. */
|
|
53
|
+
framebuffer: WebGLFramebuffer;
|
|
54
|
+
width: number;
|
|
55
|
+
height: number;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Alternative to `scene`: draws the backdrop with a GPU pass, in this same WebGL2 context, straight
|
|
59
|
+
* into the texture the lens samples — no offscreen 2D canvas, no `texSubImage2D` readback. The
|
|
60
|
+
* renderer doesn't know or care what's drawn; a fluid sim, a video frame, anything that ends up as
|
|
61
|
+
* pixels.
|
|
62
|
+
*
|
|
63
|
+
* ORIENTATION CONTRACT. `contentTexture` carries the same layout the `scene` path has always
|
|
64
|
+
* produced: uploaded from a 2D canvas without a Y flip, so texel row 0 (`v≈0`) is the scene's TOP
|
|
65
|
+
* row (see `BLIT_FRAGMENT_SOURCE` below) — and that row sits at `gl_FragCoord.y = 0` in this FBO,
|
|
66
|
+
* the window-coordinate BOTTOM, not the top. A pass that copies an ordinary top-row-first image
|
|
67
|
+
* (one loaded the normal way, via `texImage2D` from a canvas or an `<img>`) straight across with
|
|
68
|
+
* `texture(src, gl_FragCoord.xy / vec2(target.width, target.height))` reproduces it correctly,
|
|
69
|
+
* with no flip of its own. A pass that instead treats INCREASING y as its own "up" — the natural
|
|
70
|
+
* convention for a physical simulation — must flip before this final write, or its top ends up
|
|
71
|
+
* stored as the scene's bottom and appears upside down once the lens samples it.
|
|
72
|
+
*
|
|
73
|
+
* The pass may render through as many of its own FBOs first as it likes (a multi-step simulation)
|
|
74
|
+
* and leave the GL context in whatever state suits it; it must finish by drawing into
|
|
75
|
+
* `target.framebuffer` at `viewport(0, 0, target.width, target.height)`. The renderer puts back
|
|
76
|
+
* every piece of state its own remaining steps depend on right after — framebuffer, viewport,
|
|
77
|
+
* blend, scissor, depth/stencil/cull, the vertex array binding, the active texture unit, and the
|
|
78
|
+
* `UNPACK_*` pixel-store flags used to upload `iconMask`/`colorLayer` — so the pass is free to
|
|
79
|
+
* change any of it without arranging its own cleanup.
|
|
80
|
+
*/
|
|
81
|
+
type VireGlassBackdropPass = (gl: WebGL2RenderingContext, target: VireGlassBackdropTarget) => void;
|
|
46
82
|
/** One glass element in the frame. Each has its own material — that's how they're compared side by side. */
|
|
47
83
|
type VireGlassPiece = {
|
|
48
84
|
optics: VireGlassOptics;
|
|
@@ -83,7 +119,14 @@ type VireGlassRenderOptions = {
|
|
|
83
119
|
density: number;
|
|
84
120
|
debug: VireGlassDebugMode;
|
|
85
121
|
pieces: readonly VireGlassPiece[];
|
|
86
|
-
|
|
122
|
+
/** CPU-side backdrop: draws into an offscreen 2D canvas, uploaded via `texSubImage2D`. Exactly
|
|
123
|
+
* one of `scene`/`backdrop` is required — `render()` throws if both or neither are given — see
|
|
124
|
+
* `backdrop` for the GPU alternative. */
|
|
125
|
+
scene?: VireGlassSceneDrawer;
|
|
126
|
+
/** GPU-side backdrop: draws straight into the texture the lens samples, in this context, no
|
|
127
|
+
* readback. Exactly one of `scene`/`backdrop` is required — see `VireGlassBackdropPass` for the
|
|
128
|
+
* orientation contract it must honor. */
|
|
129
|
+
backdrop?: VireGlassBackdropPass | null;
|
|
87
130
|
/** Canvas offset under stationary elements, device-px. */
|
|
88
131
|
offsetX?: number;
|
|
89
132
|
offsetY?: number;
|
|
@@ -116,8 +159,51 @@ type VireGlassRenderResult = {
|
|
|
116
159
|
type VireGlassRenderer = {
|
|
117
160
|
resize(widthPx: number, heightPx: number): void;
|
|
118
161
|
render(options: VireGlassRenderOptions): VireGlassRenderResult;
|
|
162
|
+
/** GPU time of the last `render()` call, milliseconds, via
|
|
163
|
+
* `EXT_disjoint_timer_query_webgl2`. `null` when the extension is unavailable or the sample
|
|
164
|
+
* came back disjoint — never an error either way. */
|
|
165
|
+
getLastGpuMs(): number | null;
|
|
119
166
|
destroy(): void;
|
|
120
167
|
};
|
|
121
168
|
declare function createVireGlassRenderer(canvas: HTMLCanvasElement): VireGlassRenderer;
|
|
122
169
|
|
|
123
|
-
|
|
170
|
+
/** The same trick as in `scripts/check-glsl.mjs`: three vertices with no buffer, indexed by
|
|
171
|
+
* `gl_VertexID`. One vertex shader works for EVERY pass of the pipeline, because each fragment
|
|
172
|
+
* shader pulls its own coordinate from `gl_FragCoord`. */
|
|
173
|
+
declare const FULLSCREEN_TRIANGLE_VERTEX_SOURCE = "#version 300 es\nconst vec2 VG_POS[3] = vec2[3](vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));\nvoid main() {\n gl_Position = vec4(VG_POS[gl_VertexID], 0.0, 1.0);\n}\n";
|
|
174
|
+
declare function compileShader(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader;
|
|
175
|
+
declare function createProgram(gl: WebGL2RenderingContext, vertexSource: string, fragmentSource: string): WebGLProgram;
|
|
176
|
+
/** Draws the fullscreen triangle with the current program. No attributes — the vertices are
|
|
177
|
+
* baked into the shader, so even a VAO isn't needed. */
|
|
178
|
+
declare function drawFullscreenTriangle(gl: WebGL2RenderingContext): void;
|
|
179
|
+
type TextureOptions = {
|
|
180
|
+
width: number;
|
|
181
|
+
height: number;
|
|
182
|
+
/** RGBA8 by default; the probe needs float when it needs more than 8 bits of precision. */
|
|
183
|
+
internalFormat?: number;
|
|
184
|
+
format?: number;
|
|
185
|
+
type?: number;
|
|
186
|
+
/** CLAMP_TO_EDGE by default. A simulation with a periodic domain (a tiling pattern, a torus)
|
|
187
|
+
* wants REPEAT on its own textures instead — applied to both S and T, there's no case here
|
|
188
|
+
* that wants them to differ. */
|
|
189
|
+
wrap?: number;
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* General-purpose texture allocator: LINEAR on MIN and MAG, no mipmaps, CLAMP_TO_EDGE by default.
|
|
193
|
+
* Used throughout `web/` for `contentTexture` and the probe's downsample buffer, and public so a
|
|
194
|
+
* `VireGlassBackdropPass` can build its own textures the same way. LINEAR rather than NEAREST
|
|
195
|
+
* because Skia's `.eval` is bilinear by default — NEAREST would break the disc gather into
|
|
196
|
+
* pixel-stepped bands (spec §4); a pass with different needs overrides `internalFormat`/`format`/
|
|
197
|
+
* `type`/`wrap` directly.
|
|
198
|
+
*/
|
|
199
|
+
declare function createTexture(gl: WebGL2RenderingContext, options: TextureOptions): WebGLTexture;
|
|
200
|
+
type UniformValue = number | readonly number[];
|
|
201
|
+
/** One cache per program: `getUniformLocation` is a name lookup, and every piece re-sets every
|
|
202
|
+
* uniform every frame. */
|
|
203
|
+
declare function locationCache(gl: WebGL2RenderingContext, program: WebGLProgram): (name: string) => WebGLUniformLocation | null;
|
|
204
|
+
declare function setUniform(gl: WebGL2RenderingContext, loc: WebGLUniformLocation | null, value: UniformValue): void;
|
|
205
|
+
declare function createFramebuffer(gl: WebGL2RenderingContext, texture: WebGLTexture): WebGLFramebuffer;
|
|
206
|
+
/** The one texture unit any pipeline pass needs here — a bind with no extra slot bookkeeping. */
|
|
207
|
+
declare function bindTextureAt(gl: WebGL2RenderingContext, unit: number, texture: WebGLTexture, program: WebGLProgram, uniformName: string): void;
|
|
208
|
+
|
|
209
|
+
export { FULLSCREEN_TRIANGLE_VERTEX_SOURCE, PROBE_GRID_HEIGHT, PROBE_GRID_WIDTH, type Probe, type ProbeRect, type ProbeStats, type TextureOptions, type UniformValue, type VireGlassBackdropPass, type VireGlassBackdropTarget, type VireGlassPiece, type VireGlassRenderOptions, type VireGlassRenderResult, type VireGlassRenderer, type VireGlassSceneDrawer, bindTextureAt, compileShader, createFramebuffer, createProbe, createProgram, createTexture, createVireGlassRenderer, drawFullscreenTriangle, locationCache, setUniform };
|
package/dist/web/index.d.ts
CHANGED
|
@@ -43,6 +43,42 @@ type VireGlassSceneDrawer = (ctx: CanvasRenderingContext2D, width: number, heigh
|
|
|
43
43
|
* on a phone, and an element of the same size looked completely different on the lab bench
|
|
44
44
|
* than on a device. */
|
|
45
45
|
density: number) => void;
|
|
46
|
+
/** The target a `VireGlassBackdropPass` must finish its frame in — the FBO wraps `contentTexture`
|
|
47
|
+
* itself, so drawing into it needs no readback: the very texture the lens samples gets the pixels
|
|
48
|
+
* directly. */
|
|
49
|
+
type VireGlassBackdropTarget = {
|
|
50
|
+
/** Owned by the renderer — the FBO wrapping `contentTexture` itself, recreated on `resize` and
|
|
51
|
+
* freed in `destroy`. The pass must not delete it, and must not hold onto it past the call:
|
|
52
|
+
* the object may be gone or pointing at a different texture by the next `render()`. */
|
|
53
|
+
framebuffer: WebGLFramebuffer;
|
|
54
|
+
width: number;
|
|
55
|
+
height: number;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Alternative to `scene`: draws the backdrop with a GPU pass, in this same WebGL2 context, straight
|
|
59
|
+
* into the texture the lens samples — no offscreen 2D canvas, no `texSubImage2D` readback. The
|
|
60
|
+
* renderer doesn't know or care what's drawn; a fluid sim, a video frame, anything that ends up as
|
|
61
|
+
* pixels.
|
|
62
|
+
*
|
|
63
|
+
* ORIENTATION CONTRACT. `contentTexture` carries the same layout the `scene` path has always
|
|
64
|
+
* produced: uploaded from a 2D canvas without a Y flip, so texel row 0 (`v≈0`) is the scene's TOP
|
|
65
|
+
* row (see `BLIT_FRAGMENT_SOURCE` below) — and that row sits at `gl_FragCoord.y = 0` in this FBO,
|
|
66
|
+
* the window-coordinate BOTTOM, not the top. A pass that copies an ordinary top-row-first image
|
|
67
|
+
* (one loaded the normal way, via `texImage2D` from a canvas or an `<img>`) straight across with
|
|
68
|
+
* `texture(src, gl_FragCoord.xy / vec2(target.width, target.height))` reproduces it correctly,
|
|
69
|
+
* with no flip of its own. A pass that instead treats INCREASING y as its own "up" — the natural
|
|
70
|
+
* convention for a physical simulation — must flip before this final write, or its top ends up
|
|
71
|
+
* stored as the scene's bottom and appears upside down once the lens samples it.
|
|
72
|
+
*
|
|
73
|
+
* The pass may render through as many of its own FBOs first as it likes (a multi-step simulation)
|
|
74
|
+
* and leave the GL context in whatever state suits it; it must finish by drawing into
|
|
75
|
+
* `target.framebuffer` at `viewport(0, 0, target.width, target.height)`. The renderer puts back
|
|
76
|
+
* every piece of state its own remaining steps depend on right after — framebuffer, viewport,
|
|
77
|
+
* blend, scissor, depth/stencil/cull, the vertex array binding, the active texture unit, and the
|
|
78
|
+
* `UNPACK_*` pixel-store flags used to upload `iconMask`/`colorLayer` — so the pass is free to
|
|
79
|
+
* change any of it without arranging its own cleanup.
|
|
80
|
+
*/
|
|
81
|
+
type VireGlassBackdropPass = (gl: WebGL2RenderingContext, target: VireGlassBackdropTarget) => void;
|
|
46
82
|
/** One glass element in the frame. Each has its own material — that's how they're compared side by side. */
|
|
47
83
|
type VireGlassPiece = {
|
|
48
84
|
optics: VireGlassOptics;
|
|
@@ -83,7 +119,14 @@ type VireGlassRenderOptions = {
|
|
|
83
119
|
density: number;
|
|
84
120
|
debug: VireGlassDebugMode;
|
|
85
121
|
pieces: readonly VireGlassPiece[];
|
|
86
|
-
|
|
122
|
+
/** CPU-side backdrop: draws into an offscreen 2D canvas, uploaded via `texSubImage2D`. Exactly
|
|
123
|
+
* one of `scene`/`backdrop` is required — `render()` throws if both or neither are given — see
|
|
124
|
+
* `backdrop` for the GPU alternative. */
|
|
125
|
+
scene?: VireGlassSceneDrawer;
|
|
126
|
+
/** GPU-side backdrop: draws straight into the texture the lens samples, in this context, no
|
|
127
|
+
* readback. Exactly one of `scene`/`backdrop` is required — see `VireGlassBackdropPass` for the
|
|
128
|
+
* orientation contract it must honor. */
|
|
129
|
+
backdrop?: VireGlassBackdropPass | null;
|
|
87
130
|
/** Canvas offset under stationary elements, device-px. */
|
|
88
131
|
offsetX?: number;
|
|
89
132
|
offsetY?: number;
|
|
@@ -116,8 +159,51 @@ type VireGlassRenderResult = {
|
|
|
116
159
|
type VireGlassRenderer = {
|
|
117
160
|
resize(widthPx: number, heightPx: number): void;
|
|
118
161
|
render(options: VireGlassRenderOptions): VireGlassRenderResult;
|
|
162
|
+
/** GPU time of the last `render()` call, milliseconds, via
|
|
163
|
+
* `EXT_disjoint_timer_query_webgl2`. `null` when the extension is unavailable or the sample
|
|
164
|
+
* came back disjoint — never an error either way. */
|
|
165
|
+
getLastGpuMs(): number | null;
|
|
119
166
|
destroy(): void;
|
|
120
167
|
};
|
|
121
168
|
declare function createVireGlassRenderer(canvas: HTMLCanvasElement): VireGlassRenderer;
|
|
122
169
|
|
|
123
|
-
|
|
170
|
+
/** The same trick as in `scripts/check-glsl.mjs`: three vertices with no buffer, indexed by
|
|
171
|
+
* `gl_VertexID`. One vertex shader works for EVERY pass of the pipeline, because each fragment
|
|
172
|
+
* shader pulls its own coordinate from `gl_FragCoord`. */
|
|
173
|
+
declare const FULLSCREEN_TRIANGLE_VERTEX_SOURCE = "#version 300 es\nconst vec2 VG_POS[3] = vec2[3](vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));\nvoid main() {\n gl_Position = vec4(VG_POS[gl_VertexID], 0.0, 1.0);\n}\n";
|
|
174
|
+
declare function compileShader(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader;
|
|
175
|
+
declare function createProgram(gl: WebGL2RenderingContext, vertexSource: string, fragmentSource: string): WebGLProgram;
|
|
176
|
+
/** Draws the fullscreen triangle with the current program. No attributes — the vertices are
|
|
177
|
+
* baked into the shader, so even a VAO isn't needed. */
|
|
178
|
+
declare function drawFullscreenTriangle(gl: WebGL2RenderingContext): void;
|
|
179
|
+
type TextureOptions = {
|
|
180
|
+
width: number;
|
|
181
|
+
height: number;
|
|
182
|
+
/** RGBA8 by default; the probe needs float when it needs more than 8 bits of precision. */
|
|
183
|
+
internalFormat?: number;
|
|
184
|
+
format?: number;
|
|
185
|
+
type?: number;
|
|
186
|
+
/** CLAMP_TO_EDGE by default. A simulation with a periodic domain (a tiling pattern, a torus)
|
|
187
|
+
* wants REPEAT on its own textures instead — applied to both S and T, there's no case here
|
|
188
|
+
* that wants them to differ. */
|
|
189
|
+
wrap?: number;
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* General-purpose texture allocator: LINEAR on MIN and MAG, no mipmaps, CLAMP_TO_EDGE by default.
|
|
193
|
+
* Used throughout `web/` for `contentTexture` and the probe's downsample buffer, and public so a
|
|
194
|
+
* `VireGlassBackdropPass` can build its own textures the same way. LINEAR rather than NEAREST
|
|
195
|
+
* because Skia's `.eval` is bilinear by default — NEAREST would break the disc gather into
|
|
196
|
+
* pixel-stepped bands (spec §4); a pass with different needs overrides `internalFormat`/`format`/
|
|
197
|
+
* `type`/`wrap` directly.
|
|
198
|
+
*/
|
|
199
|
+
declare function createTexture(gl: WebGL2RenderingContext, options: TextureOptions): WebGLTexture;
|
|
200
|
+
type UniformValue = number | readonly number[];
|
|
201
|
+
/** One cache per program: `getUniformLocation` is a name lookup, and every piece re-sets every
|
|
202
|
+
* uniform every frame. */
|
|
203
|
+
declare function locationCache(gl: WebGL2RenderingContext, program: WebGLProgram): (name: string) => WebGLUniformLocation | null;
|
|
204
|
+
declare function setUniform(gl: WebGL2RenderingContext, loc: WebGLUniformLocation | null, value: UniformValue): void;
|
|
205
|
+
declare function createFramebuffer(gl: WebGL2RenderingContext, texture: WebGLTexture): WebGLFramebuffer;
|
|
206
|
+
/** The one texture unit any pipeline pass needs here — a bind with no extra slot bookkeeping. */
|
|
207
|
+
declare function bindTextureAt(gl: WebGL2RenderingContext, unit: number, texture: WebGLTexture, program: WebGLProgram, uniformName: string): void;
|
|
208
|
+
|
|
209
|
+
export { FULLSCREEN_TRIANGLE_VERTEX_SOURCE, PROBE_GRID_HEIGHT, PROBE_GRID_WIDTH, type Probe, type ProbeRect, type ProbeStats, type TextureOptions, type UniformValue, type VireGlassBackdropPass, type VireGlassBackdropTarget, type VireGlassPiece, type VireGlassRenderOptions, type VireGlassRenderResult, type VireGlassRenderer, type VireGlassSceneDrawer, bindTextureAt, compileShader, createFramebuffer, createProbe, createProgram, createTexture, createVireGlassRenderer, drawFullscreenTriangle, locationCache, setUniform };
|