@bigmistqke/view.gl 0.1.7 → 0.1.9

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.
@@ -5,7 +5,8 @@
5
5
  "Bash(grep:*)",
6
6
  "Bash(npm test:*)",
7
7
  "Bash(npm run build:*)",
8
- "Bash(rg:*)"
8
+ "Bash(rg:*)",
9
+ "Bash(npm run lint:*)"
9
10
  ],
10
11
  "deny": []
11
12
  }
package/README.md CHANGED
@@ -1,56 +1,62 @@
1
1
  # 👁️ @bigmistqke/view.gl
2
2
 
3
- 🔧 Minimal library for managing WebGL uniforms / (interleaved) attributes / buffers / ...
3
+ 🔧 Utilities for managing WebGL resources: uniforms, (interleaved) attributes and buffers.
4
4
 
5
5
  - schema-based resource management [`view-gl`](#️-viewgl)
6
- - type-safe GLSL template literals to compose schemas [`view-gl/tag`](#️-viewgltag)
6
+ - compose schema and shader simultaneously via a tag template literal [`view-gl/tag`](#️-viewgltag)
7
7
 
8
8
  ## Table of Contents
9
9
 
10
- - [📦 Install](#-install)
11
- - [👁️ view.gl](#️-viewgl)
12
- - [🚀 Basic Usage](#-basic-usage)
13
- - [👁️ view](#️-view)
14
- - [📋 ViewSchema](#-viewschema)
15
- - [👀 Resource Views](#-resource-views)
16
- - [🎯 uniformView](#-uniformview)
17
- - [📋 UniformSchema](#-uniformschema)
18
- - [📝 attributeView](#-attributeview)
19
- - [📋 AttributeSchema](#-attributeschema)
20
- - [🔗 interleavedAttributeView](#-interleavedattributeview)
21
- - [📋 InterleavedAttributeSchema](#-interleavedattributeschema)
22
- - [🗂️ bufferView](#-bufferview)
23
- - [📋 BufferSchema](#-bufferschema)
24
- - [🏷️ view.gl/tag](#️-viewgltag)
25
- - [🚀 Basic Usage](#-basic-usage-1)
26
- - [📝 glsl](#-glsl)
27
- - [🧩 GLSL Fragment](#-glsl-fragment)
28
- - [🔒 Symbol Variables](#-symbol-variables)
10
+ - 📦 [Install](#-install)
11
+ - 👁️ [view.gl](#️-viewgl)
12
+ - 🚀 [Basic Usage](#-basic-usage)
13
+ - 👁️ [view](#️-view)
14
+ - 📋 [ViewSchema](#-viewschema)
15
+ - 👀 [Resource Views](#-resource-views)
16
+ - 🎯 [uniformView](#-uniformview)
17
+ - 📋 [UniformSchema](#-uniformschema)
18
+ - 📝 [attributeView](#-attributeview)
19
+ - 📋 [AttributeSchema](#-attributeschema)
20
+ - 🔗 [interleavedAttributeView](#-interleavedattributeview)
21
+ - 📋 [InterleavedAttributeSchema](#-interleavedattributeschema)
22
+ - 🗂️ [bufferView](#-bufferview)
23
+ - 📋 [BufferSchema](#-bufferschema)
24
+ - 🏷️ [view.gl/tag](#️-viewgltag)
25
+ - 🚀 [Basic Usage](#-basic-usage-1)
26
+ - 📝 [glsl](#-glsl)
27
+ - 🧩 [GLSL Fragment](#-glsl-fragment)
28
+ - 🔒 [Symbol Variables](#-symbol-variables)
29
29
  - [WebGL Version Support](#webgl-version-support)
30
- - [⚙️ Resource Tags](#️-resource-tags)
31
- - [🎯 uniform[kind](name, options?)](#-uniformkindname-options)
32
- - [📝 attribute[kind](name, options?)](#-attributekindname-options)
33
- - [🔗 interleave(name, layout, options?)](#-interleavename-layout-options)
34
- - [⚙️ compile(gl, vertex, fragment)](#️-compilegl-vertex-fragment)
35
- - [🔍 compile.toString(shader)](#-compiletostringshader)
36
- - [📋 compile.toSchema(shader)](#-compiletoschemaschader)
37
- - [🛠️ Utils](#️-utils)
38
- - [🏗️ createProgram](#️-createprogram)
39
- - [🖼️ createTexture](#️-createtexture)
40
- - [🖥️ createFramebuffer](#️-createframebuffer)
41
- - [🔍 WebGL Type Compatibility](#-webgl-type-compatibility)
42
- - [🎯 Uniform Types](#-uniform-types)
43
- - [📝 Attribute Types](#-attribute-types)
30
+ - 🏷️ [Resource Tokens](#️-resource-tokens)
31
+ - 🎯 [uniform[kind](name, options?)](#-uniformkindname-options)
32
+ - 📝 [attribute[kind](name, options?)](#-attributekindname-options)
33
+ - 🔗 [interleave(name, layout, options?)](#-interleavename-layout-options)
34
+ - ⚙️ [compile(gl, vertex, fragment)](#️-compilegl-vertex-fragment)
35
+ - 🔄 [compile.toQuad(gl, fragment)](#-compiletoquadgl-fragment-options)
36
+ - 🔍 [compile.toString(shader)](#-compiletostringshader)
37
+ - 📋 [compile.toSchema(shader)](#-compiletoschemaschader)
38
+ - 🛠️ [Utils](#️-utils)
39
+ - 🏗️ [createProgram](#️-createprogram)
40
+ - 🖼️ [createTexture](#️-createtexture)
41
+ - 🖥️ [createFramebuffer](#️-createframebuffer)
42
+ - 🔍 [WebGL Type Compatibility](#-webgl-type-compatibility)
43
+ - 🎯 [Uniform Types](#-uniform-types)
44
+ - 📝 [Attribute Types](#-attribute-types)
44
45
 
45
46
  ## 📦 Install
46
47
 
47
48
  ```shell
48
49
  npm install @bigmistqke/view.gl
49
- # or
50
+ ```
51
+ ```shell
50
52
  pnpm add @bigmistqke/view.gl
51
- # or
53
+ ```
54
+ ```shell
52
55
  yarn add @bigmistqke/view.gl
53
56
  ```
57
+ ```shell
58
+ bun add @bigmistqke/view.gl
59
+ ```
54
60
 
55
61
  ## 👁️ view.gl
56
62
 
@@ -314,7 +320,7 @@ type BufferSchema = Record<string | symbol, BufferDefinition>
314
320
 
315
321
  ## 🏷️ view.gl/tag
316
322
 
317
- Type-safe GLSL template literals with automatic schema extraction.
323
+ Type-safe GLSL template literals with automatic schema extraction and view creation.
318
324
 
319
325
  - **Embedded Resources**: Define uniforms, attributes, and interleaved layouts directly in GLSL
320
326
  - **Type Inference**: Automatically infers schema types and creates type-safe view
@@ -448,9 +454,9 @@ const shader = glsl`#version 300 es
448
454
  `
449
455
  ```
450
456
 
451
- ### ⚙️ Resource Tags
457
+ ### 🏷️ Resource Tokens
452
458
 
453
- Functions for defining WebGL resources directly in GLSL templates. These tags generate GLSL declarations and automatically extract type-safe schemas for use with the view system.
459
+ Utilities for defining WebGL resources directly in GLSL templates. These create metadata that the [`compile`](#️-compilegl-vertex-fragment-overrideschema) consumes to generate the typesafe schema and view.
454
460
 
455
461
  #### 🎯 uniform[kind](name, options?)
456
462
 
@@ -543,15 +549,48 @@ const vertexShader = glsl`
543
549
 
544
550
  ### ⚙️ compile(gl, vertex, fragment, overrideSchema?)
545
551
 
546
- Compiles shaders and extracts schema from embedded resources. Returns both the compiled program and a ready-to-use view.
552
+ Compiles shaders to a `WebGLProgram` and extracts typesafe schema and view.
553
+
554
+ ### 🔄 compile.toQuad(gl, fragment, options?)
555
+
556
+ Convenient helper for fullscreen quad rendering with fragment shaders. Automatically creates a vertex shader with a quad geometry and handles vertex buffer setup.
557
+
558
+ ```typescript
559
+ const { program, schema, view } = compile.toQuad(gl, fragmentShader)
560
+
561
+ // Ready to render - no vertex setup required
562
+ view.uniforms.time.set(performance.now())
563
+ gl.drawArrays(gl.TRIANGLES, 0, 6)
564
+ ```
565
+
566
+ **Perfect for:**
567
+ - Fragment shader effects (ray-marching, post-processing, etc.)
568
+ - Fullscreen compute-style shaders
569
+ - Quick prototyping and experimentation
570
+
571
+ **Generated vertex shader:**
572
+ - Creates `a_quad` attribute automatically
573
+ - Outputs `uv` varying (same as vertex position: `[-1,1]` range)
574
+ - Sets up clip-space quad covering the entire screen
575
+
576
+ **Parameters:**
577
+ - `gl`: WebGL rendering context
578
+ - `fragment`: Fragment shader with embedded resources
579
+ - `options`: Optional compilation options (same as `compile()`)
580
+
581
+ **Returns:** Same as `compile()` with pre-configured quad rendering
547
582
 
548
583
  ```typescript
549
- const { program, schema, view } = compile(gl, vertexShader, fragmentShader)
584
+ const { program, schema, view, vertex, fragment } = compile(gl, vertexShader, fragmentShader)
550
585
 
551
586
  // Use the view directly
552
587
  view.uniforms.time.set(performance.now())
553
588
  view.attributes.position.set(vertexData).bind()
554
589
 
590
+ // Access the compiled shader strings
591
+ console.log(vertex) // Compiled vertex shader GLSL
592
+ console.log(fragment) // Compiled fragment shader GLSL
593
+
555
594
  // Or access the extracted schema
556
595
  console.log(schema.uniforms) // { time: { kind: 'float' }, ... }
557
596
  console.log(schema.attributes) // { position: { kind: 'vec3' }, ... }
@@ -583,6 +622,8 @@ view.buffers.indices.set(indexData).bind()
583
622
  - `program`: Compiled WebGL program
584
623
  - `schema`: Merged schema (extracted + override)
585
624
  - `view`: Ready-to-use view with type-safe resource access
625
+ - `vertex`: Compiled vertex shader GLSL string
626
+ - `fragment`: Compiled fragment shader GLSL string
586
627
 
587
628
  #### 🔍 compile.toString(shader)
588
629
 
@@ -1,8 +1,8 @@
1
1
  import { attribute, compile, glsl, interleave, uniform } from 'view.gl/tag'
2
- import { createElement, cursor } from '../utils'
2
+ import { cursor, dom } from '../utils'
3
3
 
4
4
  // Create canvas and WebGL context
5
- const canvas = createElement('canvas')
5
+ const canvas = dom('canvas', { parentElement: document.body })
6
6
  canvas.width = window.innerWidth
7
7
  canvas.height = window.innerHeight
8
8
  const gl = canvas.getContext('webgl2', { antialias: true })!
@@ -357,6 +357,7 @@ updateLineData()
357
357
  /**********************************************************************************/
358
358
 
359
359
  function render() {
360
+ console.log('render!')
360
361
  // Update canvas size if window was resized
361
362
  if (canvas.width !== window.innerWidth || canvas.height !== window.innerHeight) {
362
363
  canvas.width = window.innerWidth
@@ -1,10 +1,11 @@
1
1
  import { FramebufferDefinition } from 'src/types'
2
2
  import { createFramebuffer } from 'src/utils'
3
- import { attribute, compile, glsl, uniform } from 'view.gl/tag'
3
+ import { compile, glsl, uniform } from 'view.gl/tag'
4
+ import { dom } from '../utils'
4
5
 
5
6
  let playing = false
6
7
 
7
- const canvas = document.createElement('canvas')
8
+ const canvas = dom('canvas')
8
9
  const gl = canvas.getContext('webgl', { antialias: false })!
9
10
  if (!gl) {
10
11
  throw new Error('WebGL not supported')
@@ -85,18 +86,6 @@ canvas.height = 256 * 2
85
86
  const WIDTH = canvas.width
86
87
  const HEIGHT = canvas.height
87
88
 
88
- // --- Shaders ---
89
-
90
- // Vertex shader (simple fullscreen quad)
91
- const vertex = glsl`
92
- ${attribute.vec2('a_vertex')}
93
- varying vec2 v_uv;
94
- void main() {
95
- v_uv = a_vertex * 0.5 + 0.5;
96
- gl_Position = vec4(a_vertex, 0, 1);
97
- }
98
- `
99
-
100
89
  // Fragment shader for Game of Life step
101
90
  // We read from u_texture the current state
102
91
  // Alive cells are red > 0.5, dead < 0.5
@@ -115,15 +104,17 @@ const stepFragment = glsl`
115
104
  }
116
105
 
117
106
  void main() {
107
+ vec2 uv = v_uv * 0.5 + 0.5;
108
+
118
109
  int sum = 0;
119
110
  // Iterate neighbors -1,0,1
120
111
  for (int y = -1; y <= 1; y++) {
121
112
  for (int x = -1; x <= 1; x++) {
122
113
  if (x == 0 && y == 0) continue;
123
- sum += getCell(v_uv + vec2(float(x), float(y)) * u_texelSize);
114
+ sum += getCell(uv + vec2(float(x), float(y)) * u_texelSize);
124
115
  }
125
116
  }
126
- int current = getCell(v_uv);
117
+ int current = getCell(uv);
127
118
 
128
119
  int nextState = 0;
129
120
  if (current == 1) {
@@ -144,22 +135,14 @@ const renderFragment = glsl`
144
135
  ${uniform.sampler2D('u_texture')}
145
136
 
146
137
  void main() {
147
- float cell = texture2D(u_texture, v_uv).r;
138
+ vec2 uv = v_uv * 0.5 + 0.5;
139
+ float cell = texture2D(u_texture, uv).r;
148
140
  gl_FragColor = vec4(vec3(cell), 1.0);
149
141
  }`
150
142
 
151
143
  // --- Create programs ---
152
- const { program: stepProgram, view: stepView } = compile(gl, vertex, stepFragment)
153
- const { program: renderProgram, view: renderView } = compile(gl, vertex, renderFragment, {
154
- attributes: {
155
- a_vertex: {
156
- buffer: stepView.attributes.a_vertex.buffer,
157
- },
158
- },
159
- })
160
-
161
- // Setup quad
162
- stepView.attributes.a_vertex.set(new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]))
144
+ const { program: stepProgram, view: stepView } = compile.toQuad(gl, stepFragment)
145
+ const { program: renderProgram, view: renderView } = compile.toQuad(gl, renderFragment)
163
146
 
164
147
  // Initialize two framebuffers (with their respective texture) for ping-pong
165
148
  const framebufferOptions = {
@@ -210,7 +193,7 @@ function step() {
210
193
  stepView.uniforms.u_texture.set(0)
211
194
  stepView.uniforms.u_texelSize.set(1 / WIDTH, 1 / HEIGHT)
212
195
 
213
- stepView.attributes.a_vertex.bind()
196
+ stepView.attributes.a_quad.bind()
214
197
 
215
198
  gl.drawArrays(gl.TRIANGLES, 0, 6)
216
199
  }
@@ -225,7 +208,7 @@ function render() {
225
208
  gl.bindTexture(gl.TEXTURE_2D, write.texture)
226
209
  renderView.uniforms.u_texture.set(0)
227
210
 
228
- renderView.attributes.a_vertex.bind()
211
+ renderView.attributes.a_quad.bind()
229
212
 
230
213
  gl.drawArrays(gl.TRIANGLES, 0, 6)
231
214
  }
@@ -8,13 +8,13 @@
8
8
  */
9
9
 
10
10
  import { attribute, compile, glsl, uniform } from 'view.gl/tag'
11
- import { createElement } from '../utils'
11
+ import { dom } from '../utils'
12
12
 
13
- const canvas = createElement('canvas', {
13
+ const canvas = dom('canvas', {
14
14
  width: window.innerWidth,
15
15
  height: window.innerHeight,
16
16
  parentElement: document.body,
17
- style: 'width: 100%; height: 100%',
17
+ style: { width: '100%' },
18
18
  })
19
19
 
20
20
  const gl = canvas.getContext('webgl2')!
@@ -1,7 +1,11 @@
1
1
  import { attribute, compile, glsl, uniform } from 'view.gl/tag'
2
- import { createElement, cursor } from '../utils'
2
+ import { cursor, dom } from '../utils'
3
3
 
4
- const canvas = createElement('canvas', { width: window.innerWidth, height: window.innerHeight })
4
+ const canvas = dom('canvas', {
5
+ width: window.innerWidth,
6
+ height: window.innerHeight,
7
+ parentElement: document.body,
8
+ })
5
9
  const gl = canvas.getContext('webgl2', { antialias: false })!
6
10
 
7
11
  if (!gl) {
@@ -14,7 +18,7 @@ const state = {
14
18
  elements: [] as Array<ReturnType<typeof createGridElement>>,
15
19
  }
16
20
 
17
- const container = createElement('div')
21
+ const container = dom('div', { parentElement: document.body })
18
22
  state.elements.push(createGridElement({ x: 100, y: 100 }))
19
23
 
20
24
  /**********************************************************************************/
@@ -29,28 +33,30 @@ function createGridElement(position = { x: 0, y: 0 }) {
29
33
  y: (position.y - state.position.y) / state.scale,
30
34
  }
31
35
 
32
- const element = createElement('div', {
36
+ const div = dom('div', {
33
37
  innerText: 'HALLO WORLD',
34
- style: `position: fixed;
35
- z-index: 10;
36
- left: 0px;
37
- top: 0px;
38
- transform-origin: top left;
39
- background: white;
40
- padding: 2px;
41
- border-radius: 2px;`,
38
+ style: {
39
+ position: 'fixed',
40
+ zIndex: '10',
41
+ left: '0px',
42
+ top: '0px',
43
+ transformOrigin: 'top left',
44
+ background: 'white',
45
+ padding: '2px',
46
+ borderRadius: '2px',
47
+ },
42
48
  parentElement: container,
43
49
  })
44
50
 
45
51
  function update() {
46
- element.style.transform = `translate3d(${state.position.x + position.x * state.scale}px,${
52
+ div.style.transform = `translate3d(${state.position.x + position.x * state.scale}px,${
47
53
  state.position.y + position.y * state.scale
48
54
  }px,0) scale(${state.scale})`
49
55
  }
50
56
  update()
51
57
 
52
58
  return {
53
- element,
59
+ element: div,
54
60
  position,
55
61
  update,
56
62
  }
@@ -1,7 +1,7 @@
1
1
  import { FramebufferDefinition } from 'src/types'
2
2
  import { createFramebuffer } from 'src/utils'
3
3
  import { attribute, compile, glsl, uniform } from 'view.gl/tag'
4
- import { createElement } from '../utils'
4
+ import { dom } from '../utils'
5
5
 
6
6
  export const MATERIALS = {
7
7
  SAND: {
@@ -24,36 +24,41 @@ let playing = false
24
24
  let currentMaterial: (typeof MATERIALS)[keyof typeof MATERIALS]['id'] = MATERIALS.SAND.id
25
25
 
26
26
  // Create UI container
27
- const container = createElement('div', {
28
- style: 'display: flex; flex-direction: column; align-items: center; gap: 10px;',
27
+ const container = dom('div', {
28
+ style: {
29
+ display: 'flex',
30
+ flexDirection: 'column',
31
+ alignItems: 'center',
32
+ gap: '10px',
33
+ },
29
34
  parentElement: document.body,
30
35
  })
31
36
 
32
37
  // Create material buttons
33
- const buttonContainer = createElement('div', {
38
+ const buttonContainer = dom('div', {
34
39
  style: 'display: flex; gap: 10px; margin-bottom: 10px;',
35
40
  parentElement: container,
36
41
  })
37
42
 
38
43
  Object.entries(MATERIALS).forEach(([name, material]) => {
39
- createElement('button', {
40
- textContent: name.toLowerCase(),
44
+ dom('button', {
41
45
  'data-name': name,
42
46
  'data-id': material.id.toString(),
43
- style: `padding: 5px 10px;
44
- font-size: 14px;
45
- font-family: arial;
46
- cursor: pointer;
47
- color: black;
48
- background: ${
49
- currentMaterial === material.id
50
- ? `rgb(${material.color.map(c => Math.floor(c * 255)).join(',')})`
51
- : `rgba(${material.color.map(c => Math.floor(c * 255)).join(',')}, 0.75)`
52
- };
53
- border-color: ${name === 'SAND' ? 'black' : 'white'};
54
- border: 2px solid rgb(${material.color.map(c => Math.floor(c * 255)).join(',')});
55
- border-radius: 2px;
56
- `,
47
+ textContent: name.toLowerCase(),
48
+ style: {
49
+ padding: '5px 10px',
50
+ fontSize: '14px',
51
+ fontFamily: 'arial',
52
+ cursor: 'pointer',
53
+ color: 'black',
54
+ background:
55
+ currentMaterial === material.id
56
+ ? `rgb(${material.color.map(c => Math.floor(c * 255)).join(',')})`
57
+ : `rgba(${material.color.map(c => Math.floor(c * 255)).join(',')}, 0.75)`,
58
+ borderColor: name === 'SAND' ? 'black' : 'white',
59
+ border: `2px solid rgb(${material.color.map(c => Math.floor(c * 255)).join(',')})`,
60
+ borderRadius: '2px',
61
+ },
57
62
  onclick() {
58
63
  currentMaterial = material.id
59
64
  // Update all button borders
@@ -79,7 +84,7 @@ function spray() {
79
84
  return Math.floor(Math.random() * 8) * (Math.random() < 0.5 ? 1 : -1)
80
85
  }
81
86
 
82
- const canvas = createElement('canvas', {
87
+ const canvas = dom('canvas', {
83
88
  parentElement: container,
84
89
  onmousedown() {
85
90
  const rect = canvas.getBoundingClientRect()
@@ -462,7 +467,9 @@ void main() {
462
467
  // --- Create programs ---
463
468
  const { program: stepProgram, view: stepView } = compile(gl, vertex, stepFragment)
464
469
  const { program: renderProgram, view: renderView } = compile(gl, vertex, renderFragment, {
465
- attributes: { a_vertex: { buffer: stepView.attributes.a_vertex.buffer } },
470
+ schema: {
471
+ attributes: { a_vertex: { buffer: stepView.attributes.a_vertex.buffer } },
472
+ },
466
473
  })
467
474
 
468
475
  gl.useProgram(renderProgram)