@frapx/core 0.3.0 → 0.5.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/CHANGELOG.md +27 -0
- package/dist/index.d.ts +191 -5
- package/dist/index.js +539 -93
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.0 - 2026-10-15
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `ShaderCompileError` carries `stage` (`"vertex"`, `"fragment"`, `"link"` or `null`) and `lines`: each error the driver's info log locates, with its line number, message, that source line and two lines of context either side (`ShaderErrorLine`). The message is still the raw log.
|
|
8
|
+
- `parseShaderLog(log, source)` for runtimes that compile their own shaders.
|
|
9
|
+
- `keyframes(tracks, { ease })`: a dependency-free `UniformSource` that interpolates float and vec2–vec4 keyframes per component, with `"linear"`, `"smooth"`, `"step"` or custom eases.
|
|
10
|
+
- `createUniformBindings()`: ordered `UniformSource`s merged into normalized uniforms for a time, for runtimes that implement `bindUniforms()`.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- `createProgram()` no longer leaks the compiled vertex shader when the fragment shader fails to compile.
|
|
15
|
+
- After a WebGL context is restored, an instance that was not running (stopped, or on a manual clock) returns to its previous status instead of staying `"context-lost"`, and a stopped realtime instance redraws.
|
|
16
|
+
|
|
17
|
+
## 0.4.0 - 2026-10-13
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Shared program state for runtimes built on the host, moved here from `@frapx/fx-canvas` so `@frapx/fx-passes` can reuse it:
|
|
22
|
+
- Uniform helpers `normalizeUniform`, `applyUniform`, `applyProgramUniform`, `applyUniforms`, `collectUniformLocations` and `createUniformCache`, with the `NormalizedUniform` type and the uniform input types (`UniformInput`, `UniformInputMap`, `UniformRuntimeValue`, `ExplicitUniformInput`, `UniformType`, `UniformScalar`, `UniformVec2`–`UniformVec4`).
|
|
23
|
+
- `createTextureSet(inputs)`: named image textures with texture-unit allocation (`reserveUnit` also covers runtime-owned samplers), superseded-load handling, binding and disposal.
|
|
24
|
+
- `createFullscreenProgram(gl, fragment, vertex?)`: compiles a fragment shader with the matching fullscreen-quad vertex shader and exposes its uniform locations, `use()`, `draw()` and `dispose()`.
|
|
25
|
+
- `rgba32f` render targets (`createRenderTarget` / `createPingPong`), with the same WebGL2 + `EXT_color_buffer_float` requirement as `rgba16f`. They sample with nearest filtering unless `OES_texture_float_linear` is available. `captureFrame({ format: "rgba16f" })` also reads an `rgba32f` capture source.
|
|
26
|
+
- `onCaptureDraw(state, signal)` host option: draws the frame `captureFrame()` reads over several tasks (for example sample accumulation that waits for the GPU between draws). The host holds its render lock until it settles, so other frames do not interleave, and reads the result in the settling task. Resizes requested meanwhile apply after the frame is read, and a context lost (even if restored) meanwhile rejects the capture.
|
|
27
|
+
- `signal` capture option: an aborted signal rejects `captureFrame()` before drawing and is passed to `onCaptureDraw`.
|
|
28
|
+
- `waitForGpu(gl)`: resolves once the GPU has finished the submitted work by polling a fence between tasks, so long renders can yield and avoid the GPU watchdog. Resolves immediately on WebGL1.
|
|
29
|
+
|
|
3
30
|
## 0.3.0 - 2026-10-10
|
|
4
31
|
|
|
5
32
|
### Added
|
package/dist/index.d.ts
CHANGED
|
@@ -23,11 +23,24 @@ type TextureOptions = {
|
|
|
23
23
|
};
|
|
24
24
|
type TextureInput = TextureSource | TextureOptions;
|
|
25
25
|
type TextureMap = Record<string, TextureInput>;
|
|
26
|
+
type UniformScalar = number;
|
|
27
|
+
type UniformVec2 = [number, number] | readonly [number, number];
|
|
28
|
+
type UniformVec3 = [number, number, number] | readonly [number, number, number];
|
|
29
|
+
type UniformVec4 = [number, number, number, number] | readonly [number, number, number, number];
|
|
30
|
+
type UniformType = "float" | "vec2" | "vec3" | "vec4" | "mat3" | "mat4";
|
|
31
|
+
type ExplicitUniformInput = {
|
|
32
|
+
type: UniformType;
|
|
33
|
+
value: number[] | Float32Array;
|
|
34
|
+
};
|
|
35
|
+
type UniformInput = UniformScalar | UniformVec2 | UniformVec3 | UniformVec4 | Float32Array | ExplicitUniformInput;
|
|
36
|
+
type UniformInputMap = Record<string, UniformInput>;
|
|
37
|
+
type UniformRuntimeValue<T> = T extends ExplicitUniformInput ? ExplicitUniformInput : T extends Float32Array ? Float32Array : T extends readonly [number, number] ? UniformVec2 : T extends readonly [number, number, number] ? UniformVec3 : T extends readonly [number, number, number, number] ? UniformVec4 : T extends number ? number : UniformInput;
|
|
26
38
|
/**
|
|
27
|
-
* Storage format of a render target. `rgba16f` (half float)
|
|
28
|
-
* `EXT_color_buffer_float`.
|
|
39
|
+
* Storage format of a render target. `rgba16f` (half float) and `rgba32f`
|
|
40
|
+
* (float) need WebGL2 with `EXT_color_buffer_float`. `rgba32f` is sampled with
|
|
41
|
+
* nearest filtering unless `OES_texture_float_linear` is available.
|
|
29
42
|
*/
|
|
30
|
-
type RenderTargetFormat = "rgba8" | "rgba16f";
|
|
43
|
+
type RenderTargetFormat = "rgba8" | "rgba16f" | "rgba32f";
|
|
31
44
|
type RenderTargetOptions = {
|
|
32
45
|
/** Defaults to `"rgba8"`. */
|
|
33
46
|
format?: RenderTargetFormat;
|
|
@@ -75,6 +88,11 @@ type CaptureFormat = "png" | "rgba8" | "rgba16f";
|
|
|
75
88
|
type CaptureOptions<F extends CaptureFormat = CaptureFormat> = {
|
|
76
89
|
/** Defaults to `"png"`. */
|
|
77
90
|
format?: F;
|
|
91
|
+
/**
|
|
92
|
+
* Rejects the capture with the signal's reason when aborted before drawing,
|
|
93
|
+
* or between the steps of a capture that draws over several tasks.
|
|
94
|
+
*/
|
|
95
|
+
signal?: AbortSignal;
|
|
78
96
|
};
|
|
79
97
|
type CaptureResult<F extends CaptureFormat> = F extends "rgba16f" ? Float32Array : F extends "rgba8" ? Uint8Array : Blob;
|
|
80
98
|
type HostPointer = {
|
|
@@ -142,6 +160,14 @@ type RuntimeHostOptions = {
|
|
|
142
160
|
* precision, if any. `captureFrame({ format: "rgba16f" })` reads from it.
|
|
143
161
|
*/
|
|
144
162
|
captureSource?: () => RenderTarget | null;
|
|
163
|
+
/**
|
|
164
|
+
* Draws the frame `captureFrame()` reads, in place of `onDraw`, when drawing
|
|
165
|
+
* it takes more than one task (such as accumulating samples while waiting
|
|
166
|
+
* for the GPU). The host holds its render lock until the promise settles and
|
|
167
|
+
* reads the result in the task that settled it, so the final draw into the
|
|
168
|
+
* canvas must happen in that task. Receives the capture's abort signal.
|
|
169
|
+
*/
|
|
170
|
+
onCaptureDraw?: (state: HostFrameState, signal: AbortSignal | undefined) => Promise<void>;
|
|
145
171
|
onContextLost?: () => void;
|
|
146
172
|
onContextRestored?: (gl: GLContext, width: number, height: number) => Promise<void> | void;
|
|
147
173
|
onReady?: () => void;
|
|
@@ -182,20 +208,122 @@ type RuntimeHostInstance = {
|
|
|
182
208
|
|
|
183
209
|
declare const createRuntimeHost: (options: RuntimeHostOptions) => RuntimeHostInstance;
|
|
184
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Resolves once the GPU has finished every command submitted so far, polling
|
|
213
|
+
* a fence between tasks. Waiting between heavy draws keeps each submission
|
|
214
|
+
* short, so a long render never trips the browser's GPU watchdog and loses
|
|
215
|
+
* the context. Resolves immediately on WebGL1.
|
|
216
|
+
*/
|
|
217
|
+
declare const waitForGpu: (gl: GLContext) => Promise<void>;
|
|
218
|
+
|
|
185
219
|
declare class ShaderError extends Error {
|
|
186
220
|
constructor(message: string);
|
|
187
221
|
}
|
|
222
|
+
/** One line of a shader compile error, located in the source that was compiled. */
|
|
223
|
+
type ShaderErrorLine = {
|
|
224
|
+
/** 1-based line in the compiled source (after `glsl` template interpolation). */
|
|
225
|
+
line: number;
|
|
226
|
+
message: string;
|
|
227
|
+
/** That line of the source, or "" when the log points past the end. */
|
|
228
|
+
source: string;
|
|
229
|
+
/** Up to two lines either side, with their numbers, the error line included. */
|
|
230
|
+
context: ReadonlyArray<{
|
|
231
|
+
line: number;
|
|
232
|
+
source: string;
|
|
233
|
+
}>;
|
|
234
|
+
};
|
|
235
|
+
/** `"link"` for program link errors, which carry no line numbers. */
|
|
236
|
+
type ShaderStage = "vertex" | "fragment" | "link";
|
|
188
237
|
declare class UnsupportedError extends ShaderError {
|
|
189
238
|
}
|
|
190
239
|
declare class TargetNotFoundError extends ShaderError {
|
|
191
240
|
}
|
|
192
241
|
declare class ShaderCompileError extends ShaderError {
|
|
242
|
+
/** The stage that failed, or `null` for errors not tied to compiling a shader. */
|
|
243
|
+
readonly stage: ShaderStage | null;
|
|
244
|
+
/** Errors located in the source, parsed from the driver's info log. Empty when it had none. */
|
|
245
|
+
readonly lines: readonly ShaderErrorLine[];
|
|
246
|
+
constructor(message: string, details?: {
|
|
247
|
+
stage?: ShaderStage;
|
|
248
|
+
lines?: readonly ShaderErrorLine[];
|
|
249
|
+
});
|
|
193
250
|
}
|
|
194
251
|
declare class TextureLoadError extends ShaderError {
|
|
195
252
|
}
|
|
196
253
|
declare class DestroyedError extends ShaderError {
|
|
197
254
|
}
|
|
198
255
|
|
|
256
|
+
/**
|
|
257
|
+
* Finds the errors in a shader info log and attaches the source lines they
|
|
258
|
+
* point at. Lines the log does not locate are left out; the log itself stays
|
|
259
|
+
* the error message.
|
|
260
|
+
*/
|
|
261
|
+
declare const parseShaderLog: (log: string, source: string) => ShaderErrorLine[];
|
|
262
|
+
|
|
263
|
+
type NormalizedUniform = {
|
|
264
|
+
type: UniformType;
|
|
265
|
+
value: number[] | Float32Array;
|
|
266
|
+
};
|
|
267
|
+
declare const normalizeUniform: (input: UniformInput) => NormalizedUniform;
|
|
268
|
+
declare const applyUniform: (gl: GLContext, location: WebGLUniformLocation, uniform: NormalizedUniform) => void;
|
|
269
|
+
declare const applyProgramUniform: (gl: GLContext, program: WebGLProgram, location: WebGLUniformLocation, uniform: NormalizedUniform) => void;
|
|
270
|
+
/**
|
|
271
|
+
* Uploads every cached uniform to the bound program. Calls `onMissing` with
|
|
272
|
+
* the name of each uniform the program lacks or optimized out.
|
|
273
|
+
*/
|
|
274
|
+
declare const applyUniforms: (gl: GLContext, locations: ReadonlyMap<string, WebGLUniformLocation>, cache: ReadonlyMap<string, NormalizedUniform>, onMissing?: (name: string) => void) => void;
|
|
275
|
+
declare const collectUniformLocations: (gl: GLContext, program: WebGLProgram) => Map<string, WebGLUniformLocation>;
|
|
276
|
+
declare const createUniformCache: (uniforms: Record<string, UniformInput> | undefined) => Map<string, NormalizedUniform>;
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Supplies uniform values for a time, such as a keyframe timeline. Runtimes
|
|
280
|
+
* call `get()` with the same time as `u_time` before drawing.
|
|
281
|
+
*/
|
|
282
|
+
type UniformSource = {
|
|
283
|
+
get(time: number): Readonly<Record<string, UniformInput>>;
|
|
284
|
+
};
|
|
285
|
+
/** Ordered sources whose values override the runtime's own uniforms. */
|
|
286
|
+
type UniformBindings = {
|
|
287
|
+
/** Adds `source`; a later source wins for the same name. Returns its removal. */
|
|
288
|
+
add(source: UniformSource): () => void;
|
|
289
|
+
readonly size: number;
|
|
290
|
+
/** Merged, normalized values at `time`, keyed by uniform name (`u_` prefixed). */
|
|
291
|
+
evaluate(time: number): Map<string, NormalizedUniform>;
|
|
292
|
+
/** A stable string of the values at `time`, to notice when they change. */
|
|
293
|
+
signature(time: number): string;
|
|
294
|
+
};
|
|
295
|
+
declare const createUniformBindings: () => UniformBindings;
|
|
296
|
+
type KeyframeValue = number | readonly [number, number] | readonly [number, number, number] | readonly [number, number, number, number];
|
|
297
|
+
/** `[time in seconds, value]`. */
|
|
298
|
+
type Keyframe = readonly [number, KeyframeValue];
|
|
299
|
+
/**
|
|
300
|
+
* How a segment eases from one key to the next: `"linear"`, `"smooth"`
|
|
301
|
+
* (smoothstep), `"step"` (hold the earlier key), or a function of the
|
|
302
|
+
* segment's 0–1 progress.
|
|
303
|
+
*/
|
|
304
|
+
type Ease = "linear" | "smooth" | "step" | ((t: number) => number);
|
|
305
|
+
type KeyframeTrack = readonly Keyframe[] | {
|
|
306
|
+
keys: readonly Keyframe[];
|
|
307
|
+
ease?: Ease;
|
|
308
|
+
};
|
|
309
|
+
type KeyframeOptions = {
|
|
310
|
+
/** Default ease for tracks that do not set their own. Defaults to `"linear"`. */
|
|
311
|
+
ease?: Ease;
|
|
312
|
+
};
|
|
313
|
+
/**
|
|
314
|
+
* A `UniformSource` that interpolates keyframes per component: floats and
|
|
315
|
+
* vec2–vec4 as tuples. Keys may come in any order; times before the first key
|
|
316
|
+
* or after the last hold that key's value.
|
|
317
|
+
*
|
|
318
|
+
* ```ts
|
|
319
|
+
* fx.bindUniforms(keyframes({
|
|
320
|
+
* camPos: [[0, [0, 1, 6]], [4, [3, 1.5, 2]]],
|
|
321
|
+
* glow: { keys: [[0, 0], [2, 1]], ease: "smooth" }
|
|
322
|
+
* }));
|
|
323
|
+
* ```
|
|
324
|
+
*/
|
|
325
|
+
declare const keyframes: (tracks: Readonly<Record<string, KeyframeTrack>>, options?: KeyframeOptions) => UniformSource;
|
|
326
|
+
|
|
199
327
|
declare const toUniformName: (name: string) => string;
|
|
200
328
|
declare const fromUniformName: (name: string) => string;
|
|
201
329
|
|
|
@@ -228,6 +356,63 @@ type LoadedTexture = {
|
|
|
228
356
|
};
|
|
229
357
|
declare const loadTexture: (gl: GLContext, name: string, input: TextureInput, unit: number) => Promise<LoadedTexture>;
|
|
230
358
|
|
|
359
|
+
type TextureSet = {
|
|
360
|
+
/** The textures loaded so far, by name. */
|
|
361
|
+
readonly textures: ReadonlyMap<string, LoadedTexture>;
|
|
362
|
+
/** Whether `name` was given as an input, loaded or not. */
|
|
363
|
+
hasInput(name: string): boolean;
|
|
364
|
+
/**
|
|
365
|
+
* Returns the texture unit for `name`, taking the lowest free unit on first
|
|
366
|
+
* use. Runtimes reserve units for their own samplers (feedback, pass inputs)
|
|
367
|
+
* here too, so they never collide with image textures.
|
|
368
|
+
*/
|
|
369
|
+
reserveUnit(gl: GLContext, name: string): number;
|
|
370
|
+
/**
|
|
371
|
+
* Loads every input, then replaces the previously loaded textures. Used for
|
|
372
|
+
* the initial load and after a context restore.
|
|
373
|
+
*/
|
|
374
|
+
loadAll(gl: GLContext, isCancelled: () => boolean): Promise<void>;
|
|
375
|
+
/**
|
|
376
|
+
* Loads `input` as `name`. Resolves to the loaded texture, or `null` when a
|
|
377
|
+
* later `set()` for the same name or `isCancelled()` superseded it (its
|
|
378
|
+
* texture is deleted). On failure the unit is released if `name` is unused,
|
|
379
|
+
* and the error is rethrown.
|
|
380
|
+
*/
|
|
381
|
+
set(gl: GLContext, name: string, input: TextureInput, isCancelled: () => boolean): Promise<LoadedTexture | null>;
|
|
382
|
+
/**
|
|
383
|
+
* Binds every loaded texture to its unit and points its sampler uniform at
|
|
384
|
+
* it. Calls `onMissing` with the uniform name when the program lacks it.
|
|
385
|
+
*/
|
|
386
|
+
bind(gl: GLContext, locations: ReadonlyMap<string, WebGLUniformLocation>, onMissing?: (uniformName: string) => void): void;
|
|
387
|
+
/** Deletes every loaded texture. */
|
|
388
|
+
dispose(gl: GLContext): void;
|
|
389
|
+
};
|
|
390
|
+
/**
|
|
391
|
+
* Tracks named image textures and the texture units they occupy, for a
|
|
392
|
+
* runtime that binds them to one or more programs.
|
|
393
|
+
*/
|
|
394
|
+
declare const createTextureSet: (inputs?: TextureMap) => TextureSet;
|
|
395
|
+
|
|
396
|
+
type FullscreenProgram = {
|
|
397
|
+
readonly program: WebGLProgram;
|
|
398
|
+
/** Active uniform locations by name, array uniforms without `[0]`. */
|
|
399
|
+
readonly locations: ReadonlyMap<string, WebGLUniformLocation>;
|
|
400
|
+
/**
|
|
401
|
+
* Binds the program, its quad buffer and `a_position`, so a draw is correct
|
|
402
|
+
* whatever GL state user hooks left behind.
|
|
403
|
+
*/
|
|
404
|
+
use(): void;
|
|
405
|
+
/** Draws the fullscreen quad with the current GL state. */
|
|
406
|
+
draw(): void;
|
|
407
|
+
dispose(): void;
|
|
408
|
+
};
|
|
409
|
+
/**
|
|
410
|
+
* Compiles `fragment` with a fullscreen-quad vertex shader (the GLSL ES 3.00
|
|
411
|
+
* one when `fragment` starts with `#version 300 es`, unless `vertex` is
|
|
412
|
+
* given) and leaves it bound.
|
|
413
|
+
*/
|
|
414
|
+
declare const createFullscreenProgram: (gl: GLContext, fragment: string, vertex?: string) => FullscreenProgram;
|
|
415
|
+
|
|
231
416
|
declare const defaultVertexShader = "\nattribute vec2 a_position;\nvarying vec2 v_uv;\n\nvoid main() {\n v_uv = a_position * 0.5 + 0.5;\n gl_Position = vec4(a_position, 0.0, 1.0);\n}\n";
|
|
232
417
|
declare const defaultVertexShader300 = "#version 300 es\nin vec2 a_position;\nout vec2 v_uv;\n\nvoid main() {\n v_uv = a_position * 0.5 + 0.5;\n gl_Position = vec4(a_position, 0.0, 1.0);\n}\n";
|
|
233
418
|
declare const isGLSL300: (src: string) => boolean;
|
|
@@ -255,7 +440,8 @@ declare const createBlitter: (gl: GLContext) => Blitter;
|
|
|
255
440
|
|
|
256
441
|
/**
|
|
257
442
|
* Whether `format` can be allocated as a color attachment on `gl`. `rgba8` is
|
|
258
|
-
* always available; `rgba16f`
|
|
443
|
+
* always available; `rgba16f` and `rgba32f` need WebGL2 and
|
|
444
|
+
* `EXT_color_buffer_float`.
|
|
259
445
|
* Enables the extension as a side effect when present.
|
|
260
446
|
*/
|
|
261
447
|
declare const supportsRenderTargetFormat: (gl: GLContext, format: RenderTargetFormat) => boolean;
|
|
@@ -276,4 +462,4 @@ declare const createRenderTarget: (gl: GLContext, width: number, height: number,
|
|
|
276
462
|
*/
|
|
277
463
|
declare const createPingPong: (gl: GLContext, width: number, height: number, options?: RenderTargetOptions) => PingPong;
|
|
278
464
|
|
|
279
|
-
export { type Blitter, type CaptureFormat, type CaptureOptions, type CaptureResult, type ClockMode, DestroyedError, type DomSetup, type DprOption, type GLContext, type HostFrameState, type HostPointer, type LoadedTexture, type PingPong, type RenderMode, type RenderTarget, type RenderTargetFormat, type RenderTargetOptions, type Resolution, type RuntimeHostInstance, type RuntimeHostOptions, type SetupCanvasOptions, ShaderCompileError, ShaderError, type ShaderLayer, type ShaderStatus, TargetNotFoundError, type TextureInput, TextureLoadError, type TextureMap, type TextureOptions, type TextureSource, UnsupportedError, createBlitter, createFullscreenBuffer, createPingPong, createProgram, createRenderTarget, createRuntimeHost, defaultVertexShader, defaultVertexShader300, fromUniformName, isGLSL300, isWebGL2Context, loadTexture, resizeCanvasToTarget, resolveDpr, resolveElement, resolveRenderTargetFormat, setupCanvas, supportsRenderTargetFormat, toUniformName };
|
|
465
|
+
export { type Blitter, type CaptureFormat, type CaptureOptions, type CaptureResult, type ClockMode, DestroyedError, type DomSetup, type DprOption, type Ease, type ExplicitUniformInput, type FullscreenProgram, type GLContext, type HostFrameState, type HostPointer, type Keyframe, type KeyframeOptions, type KeyframeTrack, type KeyframeValue, type LoadedTexture, type NormalizedUniform, type PingPong, type RenderMode, type RenderTarget, type RenderTargetFormat, type RenderTargetOptions, type Resolution, type RuntimeHostInstance, type RuntimeHostOptions, type SetupCanvasOptions, ShaderCompileError, ShaderError, type ShaderErrorLine, type ShaderLayer, type ShaderStage, type ShaderStatus, TargetNotFoundError, type TextureInput, TextureLoadError, type TextureMap, type TextureOptions, type TextureSet, type TextureSource, type UniformBindings, type UniformInput, type UniformInputMap, type UniformRuntimeValue, type UniformScalar, type UniformSource, type UniformType, type UniformVec2, type UniformVec3, type UniformVec4, UnsupportedError, applyProgramUniform, applyUniform, applyUniforms, collectUniformLocations, createBlitter, createFullscreenBuffer, createFullscreenProgram, createPingPong, createProgram, createRenderTarget, createRuntimeHost, createTextureSet, createUniformBindings, createUniformCache, defaultVertexShader, defaultVertexShader300, fromUniformName, isGLSL300, isWebGL2Context, keyframes, loadTexture, normalizeUniform, parseShaderLog, resizeCanvasToTarget, resolveDpr, resolveElement, resolveRenderTargetFormat, setupCanvas, supportsRenderTargetFormat, toUniformName, waitForGpu };
|