@actis/core 26.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 ADDED
@@ -0,0 +1,129 @@
1
+ # SOHNE | Actis
2
+
3
+ [![NPM version][npm-image]][npm-url]
4
+ [![PR Welcome][npm-downloads-image]][npm-downloads-url]
5
+
6
+ `Actis` is a lightweight WebGL rendering library designed to make it easy to work with WebGL fragment shaders, passes, and textures. It integrates seamlessly with React for modern web development.
7
+
8
+ ## Features
9
+
10
+ - Simple API for setting up WebGL rendering contexts
11
+ - Support for multiple rendering passes and shaders
12
+ - Integration with React for easy use in web applications
13
+
14
+ ## Installation
15
+
16
+ You can install `Actis` via npm:
17
+
18
+ ```bash
19
+ npm install @actis/core
20
+ ```
21
+
22
+ or via yarn:
23
+
24
+ ```bash
25
+ yarn add @actis/core
26
+ ```
27
+
28
+ ## Usage
29
+
30
+ ### Basic Usage
31
+
32
+ Here's a simple example to get you started:
33
+
34
+ ```tsx
35
+ import WebGLRenderer from '@actis/core'
36
+ import React, { useEffect, useRef } from 'react'
37
+
38
+ // Main React functional component
39
+ function App() {
40
+ const canvasRef = useRef<HTMLCanvasElement>(null) // Reference to the canvas element
41
+ const rendererRef = useRef<WebGLRenderer>() // Reference to the WebGL renderer
42
+
43
+ useEffect(() => {
44
+ rendererRef.current = new WebGLRenderer(canvasRef.current) // Initialize the renderer with the canvas element
45
+ const passes = {
46
+ passes: [
47
+ {
48
+ name: 'bufferA',
49
+ fragmentShader: `
50
+ #ifdef GL_ES
51
+ precision mediump float;
52
+ #endif
53
+
54
+ uniform vec2 u_resolution;
55
+ uniform float u_time;
56
+ uniform vec2 u_mouse;
57
+
58
+ float sdCircle(in vec2 p, in float r) {
59
+ return length(p) - r;
60
+ }
61
+
62
+ void main() {
63
+ vec2 p = (2. * gl_FragCoord.xy - u_resolution.xy) / u_resolution.y;
64
+ vec2 m = (2. * u_mouse.xy - u_resolution.xy) / u_resolution.y;
65
+ vec3 color = vec3(.0);
66
+ float d = sdCircle(p - m, .125);
67
+ color = mix(color, vec3(1.), 1.0 - smoothstep(0.0, 0.01, d));
68
+ gl_FragColor = vec4(color, 1.);
69
+ }
70
+ `,
71
+ textures: [],
72
+ },
73
+ {
74
+ name: 'bufferB',
75
+ fragmentShader: `
76
+ precision highp float;
77
+ uniform sampler2D u_texture0;
78
+ uniform vec2 u_resolution;
79
+ void main() {
80
+ vec2 uv = gl_FragCoord.xy / u_resolution;
81
+ vec4 color = texture2D(u_texture0, uv);
82
+ float smoothValue = smoothstep(0.0, 1.0, color.r);
83
+ gl_FragColor = vec4(smoothValue, 0.0, 0.0, 1.0);
84
+ }
85
+ `,
86
+ textures: ['bufferA'],
87
+ },
88
+ {
89
+ name: 'MainBuffer',
90
+ fragmentShader: `
91
+ precision highp float;
92
+ uniform sampler2D u_texture0;
93
+ uniform vec2 u_resolution;
94
+ void main() {
95
+ vec2 uv = gl_FragCoord.xy / u_resolution;
96
+ vec4 color = texture2D(u_texture0, uv);
97
+ gl_FragColor = color;
98
+ }
99
+ `,
100
+ textures: ['bufferB'],
101
+ },
102
+ ],
103
+ textures: [],
104
+ }
105
+ rendererRef.current.setup(passes) // Setup the renderer with the passes
106
+ requestAnimationFrame(rendererRef.current.render) // Start the rendering loop
107
+ }, [])
108
+
109
+ // Render the canvas element
110
+ return <canvas ref={canvasRef} width={800} height={600} />
111
+ }
112
+
113
+ export default App
114
+ ```
115
+
116
+ ### Advanced Usage
117
+
118
+ For more advanced usage, such as adding multiple passes and using textures, refer to the [API documentation](#advanced-usage) ~in a near future~.
119
+
120
+ ## Contributing
121
+
122
+ Contributions are welcome! Please open an issue or submit a pull request on GitHub.
123
+
124
+ [//]: (Externals)
125
+ [npm-image]: https://img.shields.io/npm/v/@actis/core.svg?style=flat-square&logo=npm
126
+ [npm-url]: https://npmjs.org/package/@actis/core
127
+ [npm-downloads-image]: https://img.shields.io/npm/dm/@actis/core.svg
128
+ [npm-downloads-url]: https://npmcharts.com/compare/@actis/core?minimal=true
129
+ [//]: (EOF)
package/dist/index.cjs ADDED
@@ -0,0 +1,343 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/pass/Pass.ts
3
+ /**
4
+ * Represents a render pass in the WebGL pipeline.
5
+ * Responsible for managing framebuffer, texture, and draw calls for a single pass.
6
+ */
7
+ var Pass = class {
8
+ constructor(gl, shader, width, height, offscreen = true, textures = []) {
9
+ this.gl = gl;
10
+ this.shader = shader;
11
+ this.width = width;
12
+ this.height = height;
13
+ this.texture = this.createTexture();
14
+ this.framebuffer = this.createFramebuffer(this.texture);
15
+ this.next = null;
16
+ this.offscreen = offscreen;
17
+ this.textures = textures;
18
+ this.positionAttributeLocation = this.shader.getAttribLocation("a_position");
19
+ this.positionBuffer = this.createPositionBuffer();
20
+ }
21
+ use() {
22
+ this.shader.use();
23
+ if (this.offscreen) {
24
+ this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.framebuffer);
25
+ this.gl.viewport(0, 0, this.width, this.height);
26
+ } else {
27
+ this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null);
28
+ this.gl.viewport(0, 0, this.gl.canvas.width, this.gl.canvas.height);
29
+ }
30
+ }
31
+ resize(width, height) {
32
+ this.width = width;
33
+ this.height = height;
34
+ if (this.offscreen) {
35
+ this.texture = this.createTexture();
36
+ this.framebuffer = this.createFramebuffer(this.texture);
37
+ }
38
+ }
39
+ draw() {
40
+ const positions = new Float32Array([
41
+ -1,
42
+ -1,
43
+ 1,
44
+ -1,
45
+ -1,
46
+ 1,
47
+ -1,
48
+ 1,
49
+ 1,
50
+ -1,
51
+ 1,
52
+ 1
53
+ ]);
54
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.positionBuffer);
55
+ this.gl.bufferData(this.gl.ARRAY_BUFFER, positions, this.gl.STATIC_DRAW);
56
+ this.gl.enableVertexAttribArray(this.positionAttributeLocation);
57
+ this.gl.vertexAttribPointer(this.positionAttributeLocation, 2, this.gl.FLOAT, false, 0, 0);
58
+ this.textures.forEach((texture, index) => {
59
+ this.gl.activeTexture(this.gl.TEXTURE0 + index);
60
+ this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
61
+ this.shader.setUniform(`u_texture${index}`, "1i", index);
62
+ });
63
+ this.gl.drawArrays(this.gl.TRIANGLES, 0, positions.length / 2);
64
+ }
65
+ createTexture() {
66
+ const texture = this.gl.createTexture();
67
+ this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
68
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
69
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
70
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
71
+ this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
72
+ this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.width, this.height, 0, this.gl.RGBA, this.gl.UNSIGNED_BYTE, null);
73
+ return texture;
74
+ }
75
+ createFramebuffer(texture) {
76
+ const framebuffer = this.gl.createFramebuffer();
77
+ this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, framebuffer);
78
+ this.gl.framebufferTexture2D(this.gl.FRAMEBUFFER, this.gl.COLOR_ATTACHMENT0, this.gl.TEXTURE_2D, texture, 0);
79
+ this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, null);
80
+ return framebuffer;
81
+ }
82
+ createPositionBuffer() {
83
+ const buffer = this.gl.createBuffer();
84
+ this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
85
+ return buffer;
86
+ }
87
+ };
88
+ //#endregion
89
+ //#region src/shader/Shader.ts
90
+ const ERROR_LOG_REGEX = /ERROR: 0:(\d+): (.*)(?=\n|$)/;
91
+ /**
92
+ * Compiles and manages a WebGL shader program.
93
+ * Responsible for compiling, linking, and providing access to uniforms and attributes.
94
+ */
95
+ var Shader = class {
96
+ constructor(gl, vertexSource, fragmentSource, onError, passName) {
97
+ this.gl = gl;
98
+ this.onError = onError;
99
+ this.passName = passName;
100
+ this.uniformLocations = /* @__PURE__ */ new Map();
101
+ const vertexShader = this.compileShader(vertexSource || this.defaultVertexShader(), gl.VERTEX_SHADER);
102
+ const fragmentShader = this.compileShader(fragmentSource, gl.FRAGMENT_SHADER);
103
+ this.program = this.linkProgram(vertexShader, fragmentShader);
104
+ }
105
+ compileShader(source, type) {
106
+ const shader = this.gl.createShader(type);
107
+ if (!shader) throw new Error("Failed to create shader");
108
+ this.gl.shaderSource(shader, source);
109
+ this.gl.compileShader(shader);
110
+ if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
111
+ const log = this.gl.getShaderInfoLog(shader);
112
+ this.gl.deleteShader(shader);
113
+ const coords = this.extractErrorCoords(log || "");
114
+ this.onError({
115
+ passName: this.passName,
116
+ coords
117
+ });
118
+ throw new Error(`Failed to compile shader: ${log}`);
119
+ }
120
+ return shader;
121
+ }
122
+ extractErrorCoords(log) {
123
+ const match = ERROR_LOG_REGEX.exec(log);
124
+ if (match) return {
125
+ line: Number.parseInt(match[1], 10),
126
+ message: match[2]
127
+ };
128
+ return {
129
+ line: 0,
130
+ message: ""
131
+ };
132
+ }
133
+ linkProgram(vertexShader, fragmentShader) {
134
+ const program = this.gl.createProgram();
135
+ if (!program) throw new Error("Failed to create program");
136
+ if (vertexShader) this.gl.attachShader(program, vertexShader);
137
+ this.gl.attachShader(program, fragmentShader);
138
+ this.gl.linkProgram(program);
139
+ if (!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) {
140
+ const log = this.gl.getProgramInfoLog(program);
141
+ this.gl.deleteProgram(program);
142
+ throw new Error(`Failed to link program: ${log}`);
143
+ }
144
+ return program;
145
+ }
146
+ use() {
147
+ this.gl.useProgram(this.program);
148
+ }
149
+ setUniform(name, type, ...values) {
150
+ let location = this.uniformLocations.get(name);
151
+ if (!location) {
152
+ location = this.gl.getUniformLocation(this.program, name);
153
+ this.uniformLocations.set(name, location);
154
+ }
155
+ switch (type) {
156
+ case "1f":
157
+ this.gl.uniform1f(location, values[0]);
158
+ break;
159
+ case "1i":
160
+ this.gl.uniform1i(location, values[0]);
161
+ break;
162
+ case "2fv":
163
+ this.gl.uniform2fv(location, values[0]);
164
+ break;
165
+ case "3fv":
166
+ this.gl.uniform3fv(location, values[0]);
167
+ break;
168
+ case "4fv":
169
+ this.gl.uniform4fv(location, values[0]);
170
+ break;
171
+ }
172
+ }
173
+ getAttribLocation(name) {
174
+ return this.gl.getAttribLocation(this.program, name);
175
+ }
176
+ defaultVertexShader() {
177
+ return `
178
+ attribute vec4 a_position;
179
+ void main() {
180
+ gl_Position = a_position;
181
+ }`;
182
+ }
183
+ };
184
+ //#endregion
185
+ //#region src/engine/WebGLRenderer.ts
186
+ /**
187
+ * Renderer class responsible for managing the WebGL context, render passes, and animation loop.
188
+ */
189
+ var WebGLRenderer = class {
190
+ constructor(canvas, onError) {
191
+ this.canvas = canvas;
192
+ this.animationRequestID = -1;
193
+ this.gl = this.initializeWebGLContext(canvas);
194
+ this.passes = null;
195
+ this.textureMap = /* @__PURE__ */ new Map();
196
+ this.now = /* @__PURE__ */ new Date();
197
+ this.onError = onError;
198
+ this.mouseX = 0;
199
+ this.mouseY = 0;
200
+ this.time = 0;
201
+ this.timeDelta = 0;
202
+ this.realToCSSPixels = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
203
+ this.paused = false;
204
+ this.playbackTime = 0;
205
+ this.lastTime = 0;
206
+ this.frameRate = 0;
207
+ this.currentFrame = 0;
208
+ this.currentTime = 0;
209
+ this.startTime = 0;
210
+ this.initMouseEvents();
211
+ if (typeof window !== "undefined") window.addEventListener("resize", this.resizeCanvasToDisplaySize.bind(this));
212
+ }
213
+ initializeWebGLContext(canvas) {
214
+ const opts = {
215
+ alpha: false,
216
+ depth: false,
217
+ stencil: false,
218
+ premultipliedAlpha: false,
219
+ antialias: false,
220
+ preserveDrawingBuffer: true,
221
+ powerPreference: "high-performance"
222
+ };
223
+ const gl = canvas.getContext("webgl2", opts) || canvas.getContext("experimental-webgl2", opts) || canvas.getContext("webgl", opts) || canvas.getContext("experimental-webgl", opts);
224
+ if (!gl) throw new Error("WebGL not supported");
225
+ return gl;
226
+ }
227
+ initMouseEvents() {
228
+ this.canvas.addEventListener("mousemove", this.setMousePosition.bind(this));
229
+ this.canvas.addEventListener("touchstart", this.preventDefault, { passive: false });
230
+ this.canvas.addEventListener("touchmove", this.handleTouchMove.bind(this), { passive: false });
231
+ }
232
+ setMousePosition(e) {
233
+ const mouse = {
234
+ x: e.clientX || e.pageX,
235
+ y: e.clientY || e.pageY
236
+ };
237
+ const rect = this.canvas.getBoundingClientRect();
238
+ if (mouse.x >= rect.left && mouse.x <= rect.right && mouse.y >= rect.top && mouse.y <= rect.bottom) {
239
+ this.mouseX = (mouse.x - rect.left) * this.realToCSSPixels;
240
+ this.mouseY = this.canvas.height - (mouse.y - rect.top) * this.realToCSSPixels;
241
+ }
242
+ }
243
+ handleTouchMove(e) {
244
+ e.preventDefault();
245
+ if (e.touches.length > 0) this.setMousePosition(e.touches[0]);
246
+ }
247
+ preventDefault(e) {
248
+ e.preventDefault();
249
+ }
250
+ addPass(pass) {
251
+ if (this.passes) {
252
+ let current = this.passes;
253
+ while (current.next) current = current.next;
254
+ current.next = pass;
255
+ } else this.passes = pass;
256
+ }
257
+ resizeCanvasToDisplaySize() {
258
+ const displayWidth = Math.floor(this.canvas.clientWidth * this.realToCSSPixels);
259
+ const displayHeight = Math.floor(this.canvas.clientHeight * this.realToCSSPixels);
260
+ if (this.canvas.width !== displayWidth || this.canvas.height !== displayHeight) {
261
+ this.canvas.width = displayWidth;
262
+ this.canvas.height = displayHeight;
263
+ let current = this.passes;
264
+ while (current) {
265
+ current.resize(displayWidth, displayHeight);
266
+ current = current.next;
267
+ }
268
+ }
269
+ }
270
+ updateUniforms(pass) {
271
+ pass.shader.setUniform("u_date", "4fv", [
272
+ this.now.getFullYear(),
273
+ this.now.getMonth() + 1,
274
+ this.now.getDate(),
275
+ this.now.getHours() * 3600 + this.now.getMinutes() * 60 + this.now.getSeconds() + this.now.getMilliseconds() / 1e3
276
+ ]);
277
+ pass.shader.setUniform("u_frame", "1i", this.currentFrame);
278
+ pass.shader.setUniform("u_time", "1f", this.currentTime);
279
+ pass.shader.setUniform("u_timeDelta", "1f", this.timeDelta);
280
+ pass.shader.setUniform("u_frameRate", "1f", this.frameRate);
281
+ pass.shader.setUniform("u_resolution", "2fv", [pass.width, pass.height]);
282
+ pass.shader.setUniform("u_mouse", "2fv", [this.mouseX, this.mouseY]);
283
+ }
284
+ updateTime(currentTime) {
285
+ if (this.paused) {
286
+ this.timeDelta = 0;
287
+ return;
288
+ }
289
+ const t = currentTime ?? (typeof performance !== "undefined" ? performance.now() : Date.now());
290
+ if (this.startTime === 0) this.startTime = t;
291
+ if (this.lastTime === 0) this.lastTime = t;
292
+ this.timeDelta = (t - this.startTime) / 1e3;
293
+ this.currentTime += this.timeDelta;
294
+ this.frameRate = 1 / this.timeDelta;
295
+ this.currentFrame++;
296
+ this.startTime = t;
297
+ }
298
+ render(currentTime) {
299
+ this.updateTime(currentTime);
300
+ this.resizeCanvasToDisplaySize();
301
+ let current = this.passes;
302
+ while (current) {
303
+ current.use();
304
+ this.updateUniforms(current);
305
+ current.draw();
306
+ current = current.next;
307
+ }
308
+ if (typeof requestAnimationFrame !== "undefined") this.animationRequestID = requestAnimationFrame(this.render.bind(this));
309
+ }
310
+ setup(config) {
311
+ const displayWidth = Math.floor(this.canvas.clientWidth * this.realToCSSPixels);
312
+ const displayHeight = Math.floor(this.canvas.clientHeight * this.realToCSSPixels);
313
+ config.passes.forEach((passConfig) => {
314
+ try {
315
+ const shader = new Shader(this.gl, passConfig.vertexShader, passConfig.fragmentShader, this.onError, passConfig.name);
316
+ const offscreen = passConfig.offscreen || passConfig.name !== "MainBuffer";
317
+ const pass = new Pass(this.gl, shader, displayWidth, displayHeight, offscreen, passConfig.textures.map((textureName) => this.textureMap.get(textureName)));
318
+ this.addPass(pass);
319
+ this.textureMap.set(passConfig.name, pass.texture);
320
+ } catch (error) {
321
+ console.error(`Error in pass ${passConfig.name}: ${error.message}`);
322
+ }
323
+ });
324
+ }
325
+ play() {
326
+ this.paused = false;
327
+ this.animationRequestID = requestAnimationFrame(this.render.bind(this));
328
+ }
329
+ pause() {
330
+ this.paused = true;
331
+ cancelAnimationFrame(this.animationRequestID);
332
+ }
333
+ reset() {
334
+ this.playbackTime = 0;
335
+ this.currentFrame = 0;
336
+ this.lastTime = 0;
337
+ this.frameRate = 0;
338
+ }
339
+ };
340
+ //#endregion
341
+ exports.Pass = Pass;
342
+ exports.Shader = Shader;
343
+ exports.WebGLRenderer = WebGLRenderer;
@@ -0,0 +1,117 @@
1
+ //#region src/types/renderer.d.ts
2
+ type PassConfig = {
3
+ name: string;
4
+ fragmentShader: string;
5
+ vertexShader?: string;
6
+ offscreen?: boolean;
7
+ textures: string[];
8
+ };
9
+ type RendererConfig = {
10
+ passes: PassConfig[];
11
+ };
12
+ //#endregion
13
+ //#region src/types/shader.d.ts
14
+ type ShaderError = {
15
+ passName: string;
16
+ coords: {
17
+ line: number;
18
+ message: string;
19
+ };
20
+ };
21
+ type UniformType = '1f' | '1i' | '2fv' | '3fv' | '4fv';
22
+ //#endregion
23
+ //#region src/shader/Shader.d.ts
24
+ /**
25
+ * Compiles and manages a WebGL shader program.
26
+ * Responsible for compiling, linking, and providing access to uniforms and attributes.
27
+ */
28
+ declare class Shader {
29
+ private gl;
30
+ private program;
31
+ private uniformLocations;
32
+ private onError;
33
+ private passName;
34
+ constructor(gl: WebGLRenderingContext, vertexSource: string | undefined, fragmentSource: string, onError: (details: ShaderError) => void, passName: string);
35
+ private compileShader;
36
+ private extractErrorCoords;
37
+ private linkProgram;
38
+ use(): void;
39
+ setUniform(name: string, type: UniformType, ...values: any[]): void;
40
+ getAttribLocation(name: string): number;
41
+ private defaultVertexShader;
42
+ }
43
+ //#endregion
44
+ //#region src/pass/Pass.d.ts
45
+ /**
46
+ * Represents a render pass in the WebGL pipeline.
47
+ * Responsible for managing framebuffer, texture, and draw calls for a single pass.
48
+ */
49
+ declare class Pass {
50
+ gl: WebGLRenderingContext;
51
+ shader: Shader;
52
+ width: number;
53
+ height: number;
54
+ texture: WebGLTexture;
55
+ framebuffer: WebGLFramebuffer;
56
+ next: Pass | null;
57
+ offscreen: boolean;
58
+ textures: WebGLTexture[];
59
+ positionBuffer: WebGLBuffer;
60
+ positionAttributeLocation: number;
61
+ constructor(gl: WebGLRenderingContext, shader: Shader, width: number, height: number, offscreen?: boolean, textures?: WebGLTexture[]);
62
+ use(): void;
63
+ resize(width: number, height: number): void;
64
+ draw(): void;
65
+ private createTexture;
66
+ private createFramebuffer;
67
+ private createPositionBuffer;
68
+ }
69
+ //#endregion
70
+ //#region src/engine/WebGLRenderer.d.ts
71
+ /**
72
+ * Renderer class responsible for managing the WebGL context, render passes, and animation loop.
73
+ */
74
+ declare class WebGLRenderer {
75
+ private gl;
76
+ private passes;
77
+ private canvas;
78
+ private animationRequestID;
79
+ private textureMap;
80
+ private now;
81
+ private onError;
82
+ mouseX: number;
83
+ mouseY: number;
84
+ time: number;
85
+ timeDelta: number;
86
+ realToCSSPixels: number;
87
+ paused: boolean;
88
+ playbackTime: number;
89
+ lastTime: number;
90
+ frameRate: number;
91
+ currentFrame: number;
92
+ currentTime: number;
93
+ startTime: number;
94
+ constructor(canvas: HTMLCanvasElement, onError: (details: {
95
+ passName: string;
96
+ coords: {
97
+ line: number;
98
+ message: string;
99
+ };
100
+ }) => void);
101
+ private initializeWebGLContext;
102
+ private initMouseEvents;
103
+ private setMousePosition;
104
+ private handleTouchMove;
105
+ private preventDefault;
106
+ addPass(pass: Pass): void;
107
+ private resizeCanvasToDisplaySize;
108
+ private updateUniforms;
109
+ private updateTime;
110
+ render(currentTime: number): void;
111
+ setup(config: RendererConfig): void;
112
+ play(): void;
113
+ pause(): void;
114
+ reset(): void;
115
+ }
116
+ //#endregion
117
+ export { Pass, type PassConfig, type RendererConfig, Shader, WebGLRenderer };
@@ -0,0 +1,117 @@
1
+ //#region src/types/renderer.d.ts
2
+ type PassConfig = {
3
+ name: string;
4
+ fragmentShader: string;
5
+ vertexShader?: string;
6
+ offscreen?: boolean;
7
+ textures: string[];
8
+ };
9
+ type RendererConfig = {
10
+ passes: PassConfig[];
11
+ };
12
+ //#endregion
13
+ //#region src/types/shader.d.ts
14
+ type ShaderError = {
15
+ passName: string;
16
+ coords: {
17
+ line: number;
18
+ message: string;
19
+ };
20
+ };
21
+ type UniformType = '1f' | '1i' | '2fv' | '3fv' | '4fv';
22
+ //#endregion
23
+ //#region src/shader/Shader.d.ts
24
+ /**
25
+ * Compiles and manages a WebGL shader program.
26
+ * Responsible for compiling, linking, and providing access to uniforms and attributes.
27
+ */
28
+ declare class Shader {
29
+ private gl;
30
+ private program;
31
+ private uniformLocations;
32
+ private onError;
33
+ private passName;
34
+ constructor(gl: WebGLRenderingContext, vertexSource: string | undefined, fragmentSource: string, onError: (details: ShaderError) => void, passName: string);
35
+ private compileShader;
36
+ private extractErrorCoords;
37
+ private linkProgram;
38
+ use(): void;
39
+ setUniform(name: string, type: UniformType, ...values: any[]): void;
40
+ getAttribLocation(name: string): number;
41
+ private defaultVertexShader;
42
+ }
43
+ //#endregion
44
+ //#region src/pass/Pass.d.ts
45
+ /**
46
+ * Represents a render pass in the WebGL pipeline.
47
+ * Responsible for managing framebuffer, texture, and draw calls for a single pass.
48
+ */
49
+ declare class Pass {
50
+ gl: WebGLRenderingContext;
51
+ shader: Shader;
52
+ width: number;
53
+ height: number;
54
+ texture: WebGLTexture;
55
+ framebuffer: WebGLFramebuffer;
56
+ next: Pass | null;
57
+ offscreen: boolean;
58
+ textures: WebGLTexture[];
59
+ positionBuffer: WebGLBuffer;
60
+ positionAttributeLocation: number;
61
+ constructor(gl: WebGLRenderingContext, shader: Shader, width: number, height: number, offscreen?: boolean, textures?: WebGLTexture[]);
62
+ use(): void;
63
+ resize(width: number, height: number): void;
64
+ draw(): void;
65
+ private createTexture;
66
+ private createFramebuffer;
67
+ private createPositionBuffer;
68
+ }
69
+ //#endregion
70
+ //#region src/engine/WebGLRenderer.d.ts
71
+ /**
72
+ * Renderer class responsible for managing the WebGL context, render passes, and animation loop.
73
+ */
74
+ declare class WebGLRenderer {
75
+ private gl;
76
+ private passes;
77
+ private canvas;
78
+ private animationRequestID;
79
+ private textureMap;
80
+ private now;
81
+ private onError;
82
+ mouseX: number;
83
+ mouseY: number;
84
+ time: number;
85
+ timeDelta: number;
86
+ realToCSSPixels: number;
87
+ paused: boolean;
88
+ playbackTime: number;
89
+ lastTime: number;
90
+ frameRate: number;
91
+ currentFrame: number;
92
+ currentTime: number;
93
+ startTime: number;
94
+ constructor(canvas: HTMLCanvasElement, onError: (details: {
95
+ passName: string;
96
+ coords: {
97
+ line: number;
98
+ message: string;
99
+ };
100
+ }) => void);
101
+ private initializeWebGLContext;
102
+ private initMouseEvents;
103
+ private setMousePosition;
104
+ private handleTouchMove;
105
+ private preventDefault;
106
+ addPass(pass: Pass): void;
107
+ private resizeCanvasToDisplaySize;
108
+ private updateUniforms;
109
+ private updateTime;
110
+ render(currentTime: number): void;
111
+ setup(config: RendererConfig): void;
112
+ play(): void;
113
+ pause(): void;
114
+ reset(): void;
115
+ }
116
+ //#endregion
117
+ export { Pass, type PassConfig, type RendererConfig, Shader, WebGLRenderer };