@bigmistqke/view.gl 0.1.1 → 0.1.3

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.
Files changed (52) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/.github/ISSUE_TEMPLATE/bug-report.yml +31 -0
  3. package/.github/ISSUE_TEMPLATE/feature-request.yml +27 -0
  4. package/.github/workflows/codeql.yml +46 -0
  5. package/.github/workflows/deploy-page.yml +38 -0
  6. package/.github/workflows/format.yml +40 -0
  7. package/README.md +286 -84
  8. package/dev/404.html +19 -0
  9. package/dev/dist/404.html +19 -0
  10. package/dev/dist/assets/bezier-DuLTb2d1.js +294 -0
  11. package/dev/dist/assets/game_of_life-D7qHdFcv.js +202 -0
  12. package/dev/dist/assets/grid-Ie22U_9K.js +173 -0
  13. package/dev/dist/assets/index-0qrXMlfv.js +109 -0
  14. package/dev/dist/assets/index-C2N3u8wj.css +12 -0
  15. package/dev/dist/assets/main-BZ1N6pp6.js +32 -0
  16. package/dev/dist/assets/overview-DAxtMIw5.js +78 -0
  17. package/dev/dist/assets/pix_sim-DIhzM_vu.js +501 -0
  18. package/dev/dist/assets/symbol-BouRL-Ni.js +65 -0
  19. package/dev/dist/assets/tag-C_bg62fD.js +516 -0
  20. package/dev/dist/assets/tetris-IMnkSi9p.js +344 -0
  21. package/dev/dist/assets/utils-CvCgsM08.js +50 -0
  22. package/dev/dist/index.html +51 -0
  23. package/dev/index.html +39 -10
  24. package/dev/{bezier.ts → src/examples/bezier.ts} +1 -1
  25. package/dev/{grid.ts → src/examples/grid.ts} +1 -1
  26. package/dev/{pix_sim.ts → src/examples/pix_sim.ts} +112 -97
  27. package/dev/src/examples/symbol.ts +79 -0
  28. package/dev/{tetris.ts → src/examples/tetris.ts} +1 -0
  29. package/dev/src/index.css +12 -0
  30. package/dev/src/index.ts +69 -0
  31. package/dev/{utils.ts → src/utils.ts} +8 -2
  32. package/dev/vite.config.ts +9 -1
  33. package/dist/index.d.mts +3 -2
  34. package/dist/index.mjs +81 -27
  35. package/dist/index.mjs.map +1 -1
  36. package/dist/tag.d.mts +9 -9
  37. package/dist/tag.mjs +46 -17
  38. package/dist/tag.mjs.map +1 -1
  39. package/dist/{types-DxpS9Bae.d.mts → types-DoFAJoh-.d.mts} +18 -18
  40. package/package.json +20 -7
  41. package/src/index.ts +39 -17
  42. package/src/tag.ts +47 -39
  43. package/src/types.ts +24 -24
  44. package/src/{utils.ts → utils/index.ts} +39 -14
  45. package/src/utils/object.ts +27 -0
  46. package/test/index.test.ts +1017 -0
  47. package/test/mocks/webgl.ts +248 -0
  48. package/test/setup.ts +13 -0
  49. package/test/tag.test.ts +790 -0
  50. package/vitest.config.ts +15 -0
  51. /package/dev/{game_of_life.ts → src/examples/game_of_life.ts} +0 -0
  52. /package/dev/{index.ts → src/examples/overview.ts} +0 -0
@@ -2,6 +2,7 @@ import { FramebufferOptions } from 'src/types'
2
2
  import { createFramebuffer } from 'src/utils'
3
3
  import { view } from 'view.gl'
4
4
  import { attribute, compile, glsl, uniform } from 'view.gl/tag'
5
+ import { createElement } from '../utils'
5
6
 
6
7
  export const MATERIALS = {
7
8
  SAND: {
@@ -21,126 +22,140 @@ export const MATERIALS = {
21
22
  const MATERIAL_SIZE = Object.keys(MATERIALS).length
22
23
 
23
24
  let playing = false
24
- let currentMaterial = MATERIALS.SAND.id
25
-
26
- const canvas = document.createElement('canvas')
27
- const gl = canvas.getContext('webgl2', { antialias: false })!
28
- if (!gl) {
29
- throw new Error('WebGL not supported')
30
- }
25
+ let currentMaterial: (typeof MATERIALS)[keyof typeof MATERIALS]['id'] = MATERIALS.SAND.id
31
26
 
32
27
  // Create UI container
33
- const container = document.createElement('div')
34
- container.style.cssText = 'display: flex; flex-direction: column; align-items: center; gap: 10px;'
28
+ const container = createElement('div', {
29
+ style: 'display: flex; flex-direction: column; align-items: center; gap: 10px;',
30
+ parentElement: document.body,
31
+ })
35
32
 
36
33
  // Create material buttons
37
- const buttonContainer = document.createElement('div')
38
- buttonContainer.style.cssText = 'display: flex; gap: 10px; margin-bottom: 10px;'
34
+ const buttonContainer = createElement('div', {
35
+ style: 'display: flex; gap: 10px; margin-bottom: 10px;',
36
+ parentElement: container,
37
+ })
39
38
 
40
39
  Object.entries(MATERIALS).forEach(([name, material]) => {
41
- const button = document.createElement('button')
42
- button.textContent = name.toLowerCase()
43
- button.style.cssText = `
44
- padding: 5px 10px;
40
+ createElement('button', {
41
+ textContent: name.toLowerCase(),
42
+ 'data-name': name,
43
+ 'data-id': material.id.toString(),
44
+ style: `padding: 5px 10px;
45
45
  font-size: 14px;
46
- font-family: times new roman;
46
+ font-family: arial;
47
47
  cursor: pointer;
48
+ color: black;
48
49
  background: ${
49
50
  currentMaterial === material.id
50
51
  ? `rgb(${material.color.map(c => Math.floor(c * 255)).join(',')})`
51
- : 'transparent'
52
+ : `rgba(${material.color.map(c => Math.floor(c * 255)).join(',')}, 0.75)`
52
53
  };
53
54
  border-color: ${name === 'SAND' ? 'black' : 'white'};
54
55
  border: 2px solid rgb(${material.color.map(c => Math.floor(c * 255)).join(',')});
55
56
  border-radius: 2px;
56
- `
57
- button.onclick = () => {
58
- currentMaterial = material.id
59
- // Update all button borders
60
- buttonContainer.querySelectorAll('button').forEach((btn, idx) => {
61
- btn.style.background =
62
- idx === material.id - 1
63
- ? `rgb(${material.color.map(c => Math.floor(c * 255)).join(',')})`
64
- : 'transparent'
65
- })
66
- }
67
- buttonContainer.appendChild(button)
57
+ `,
58
+ onclick() {
59
+ currentMaterial = material.id
60
+ // Update all button borders
61
+ buttonContainer.querySelectorAll('button').forEach(btn => {
62
+ const name = btn.getAttribute('data-name') as keyof typeof MATERIALS
63
+ const id = btn.getAttribute('data-id')
64
+ if (id === currentMaterial.toString()) {
65
+ btn.style.background = `rgb(${MATERIALS[name].color
66
+ .map(c => Math.floor(c * 255))
67
+ .join(',')})`
68
+ } else {
69
+ btn.style.background = `rgba(${MATERIALS[name].color
70
+ .map(c => Math.floor(c * 255))
71
+ .join(',')}, 0.75)`
72
+ }
73
+ })
74
+ },
75
+ parentElement: buttonContainer,
76
+ })
68
77
  })
69
78
 
70
- container.appendChild(canvas)
71
- container.appendChild(buttonContainer)
72
- document.body.append(container)
73
-
74
79
  function spray() {
75
80
  return Math.floor(Math.random() * 8) * (Math.random() < 0.5 ? 1 : -1)
76
81
  }
77
82
 
78
- canvas.addEventListener('mousedown', event => {
79
- const rect = canvas.getBoundingClientRect()
80
- const controller = new AbortController()
81
- // playing = false
82
- window.addEventListener(
83
- 'mousemove',
84
- event => {
85
- const x = Math.floor((event.clientX - rect.left + spray()) * (canvas.width / rect.width))
86
- const y = Math.floor((rect.bottom - event.clientY + spray()) * (canvas.height / rect.height))
87
-
88
- const dimensions = [8, 8] as const
89
-
90
- // Encode selected material using bit encoding
91
- const data = new Uint8Array(
92
- (function* () {
93
- for (let i = 0; i < dimensions[0] * dimensions[1]; i++) {
94
- yield (currentMaterial & 1) * 255 // Red channel (bit 0)
95
- yield ((currentMaterial >> 1) & 1) * 255 // Green channel (bit 1)
96
- yield ((currentMaterial >> 2) & 1) * 255 // Blue channel (bit 2)
97
- yield 255 // Alpha channel
98
- }
99
- })(),
100
- )
101
-
102
- // Update both read and write textures
103
- gl.bindTexture(gl.TEXTURE_2D, read.texture)
104
- gl.texSubImage2D(
105
- gl.TEXTURE_2D,
106
- 0,
107
- Math.max(0, Math.min(WIDTH - dimensions[0], x)),
108
- Math.max(0, Math.min(HEIGHT - dimensions[1], y)),
109
- dimensions[0],
110
- dimensions[1],
111
- gl.RGBA,
112
- gl.UNSIGNED_BYTE,
113
- data,
114
- )
115
-
116
- gl.bindTexture(gl.TEXTURE_2D, write.texture)
117
- gl.texSubImage2D(
118
- gl.TEXTURE_2D,
119
- 0,
120
- Math.max(0, Math.min(WIDTH - dimensions[0], x)),
121
- Math.max(0, Math.min(HEIGHT - dimensions[1], y)),
122
- dimensions[0],
123
- dimensions[1],
124
- gl.RGBA,
125
- gl.UNSIGNED_BYTE,
126
- data,
127
- )
128
-
129
- render()
130
- },
131
- controller,
132
- )
133
- window.addEventListener(
134
- 'mouseup',
135
- () => {
136
- controller.abort()
137
- // playing = true
138
- // animate()
139
- },
140
- controller,
141
- )
83
+ const canvas = createElement('canvas', {
84
+ parentElement: container,
85
+ onmousedown() {
86
+ const rect = canvas.getBoundingClientRect()
87
+ const controller = new AbortController()
88
+ // playing = false
89
+ window.addEventListener(
90
+ 'mousemove',
91
+ event => {
92
+ const x = Math.floor((event.clientX - rect.left + spray()) * (canvas.width / rect.width))
93
+ const y = Math.floor(
94
+ (rect.bottom - event.clientY + spray()) * (canvas.height / rect.height),
95
+ )
96
+
97
+ const dimensions = [8, 8] as const
98
+
99
+ // Encode selected material using bit encoding
100
+ const data = new Uint8Array(
101
+ (function* () {
102
+ for (let i = 0; i < dimensions[0] * dimensions[1]; i++) {
103
+ yield (currentMaterial & 1) * 255 // Red channel (bit 0)
104
+ yield ((currentMaterial >> 1) & 1) * 255 // Green channel (bit 1)
105
+ yield ((currentMaterial >> 2) & 1) * 255 // Blue channel (bit 2)
106
+ yield 255 // Alpha channel
107
+ }
108
+ })(),
109
+ )
110
+
111
+ // Update both read and write textures
112
+ gl.bindTexture(gl.TEXTURE_2D, read.texture)
113
+ gl.texSubImage2D(
114
+ gl.TEXTURE_2D,
115
+ 0,
116
+ Math.max(0, Math.min(WIDTH - dimensions[0], x)),
117
+ Math.max(0, Math.min(HEIGHT - dimensions[1], y)),
118
+ dimensions[0],
119
+ dimensions[1],
120
+ gl.RGBA,
121
+ gl.UNSIGNED_BYTE,
122
+ data,
123
+ )
124
+
125
+ gl.bindTexture(gl.TEXTURE_2D, write.texture)
126
+ gl.texSubImage2D(
127
+ gl.TEXTURE_2D,
128
+ 0,
129
+ Math.max(0, Math.min(WIDTH - dimensions[0], x)),
130
+ Math.max(0, Math.min(HEIGHT - dimensions[1], y)),
131
+ dimensions[0],
132
+ dimensions[1],
133
+ gl.RGBA,
134
+ gl.UNSIGNED_BYTE,
135
+ data,
136
+ )
137
+
138
+ render()
139
+ },
140
+ controller,
141
+ )
142
+ window.addEventListener(
143
+ 'mouseup',
144
+ () => {
145
+ controller.abort()
146
+ // playing = true
147
+ // animate()
148
+ },
149
+ controller,
150
+ )
151
+ },
142
152
  })
143
153
 
154
+ const gl = canvas.getContext('webgl2', { antialias: false })!
155
+ if (!gl) {
156
+ throw new Error('WebGL not supported')
157
+ }
158
+
144
159
  canvas.width = 256 * 2
145
160
  canvas.height = 256 * 2
146
161
  const WIDTH = canvas.width
@@ -0,0 +1,79 @@
1
+ import { view } from 'view.gl'
2
+ import { attribute, compile, glsl, uniform } from 'view.gl/tag'
3
+ import { createElement } from '../utils'
4
+
5
+ const canvas = createElement('canvas', {
6
+ width: window.innerWidth,
7
+ height: window.innerHeight,
8
+ parentElement: document.body,
9
+ style: 'width: 100%; height: 100%',
10
+ })
11
+
12
+ new ResizeObserver(() => {
13
+ canvas.width = window.innerWidth
14
+ canvas.height = window.innerHeight
15
+ gl.viewport(0, 0, canvas.width, canvas.height)
16
+ draw(performance.now())
17
+ }).observe(canvas)
18
+
19
+ const gl = canvas.getContext('webgl2')!
20
+ gl.viewport(0, 0, canvas.width, canvas.height)
21
+
22
+ const vertex = glsl`
23
+ precision mediump float;
24
+
25
+ ${attribute.vec2('a_vertex')}
26
+ ${uniform.float('u_time')}
27
+
28
+ void main() {
29
+ float s = sin(u_time);
30
+ float c = cos(u_time);
31
+ mat2 rotation = mat2(
32
+ c, -s,
33
+ s, c
34
+ );
35
+ vec2 position = a_vertex * rotation;
36
+ gl_Position = vec4(position, 0.0, 1.0);
37
+ }`
38
+
39
+ const u_color = Symbol('color')
40
+
41
+ const fragment = glsl`
42
+ precision mediump float;
43
+
44
+ ${uniform.vec3(u_color)}
45
+
46
+ void main() {
47
+ gl_FragColor = vec4(${u_color}, 1.0);
48
+ }`
49
+
50
+ const { program, schema } = compile(gl, vertex, fragment)
51
+ const { attributes, uniforms } = view(gl, program, schema)
52
+
53
+ gl.useProgram(program)
54
+
55
+ uniforms[u_color].set(0, 255, 0)
56
+
57
+ // Create triangle vertex buffer
58
+ attributes.a_vertex
59
+ .set(
60
+ new Float32Array([
61
+ // top
62
+ 0.0, 1.0,
63
+ // bottom left
64
+ -1.0, -1.0,
65
+ // bottom right
66
+ 1.0, -1.0,
67
+ ]),
68
+ )
69
+ .bind()
70
+
71
+ function draw(delta: number) {
72
+ requestAnimationFrame(draw)
73
+
74
+ // Set uniform
75
+ uniforms.u_time.set(delta / 1_000)
76
+
77
+ gl.drawArraysInstanced(gl.TRIANGLES, 0, 3, 100)
78
+ }
79
+ requestAnimationFrame(draw)
@@ -429,6 +429,7 @@ function createTetris() {
429
429
  if (checkCollision()) {
430
430
  next()
431
431
  }
432
+ render()
432
433
  animationTimeout.set(animate, 1_000)
433
434
  }
434
435
  setTimeout(animate, 1_000)
@@ -0,0 +1,12 @@
1
+ body {
2
+ display: flex;
3
+ justify-content: center;
4
+ align-items: center;
5
+ margin: 0px;
6
+ height: 100%;
7
+ overscroll-behavior-y: none;
8
+ }
9
+ canvas {
10
+ margin: auto;
11
+ image-rendering: pixelated;
12
+ }
@@ -0,0 +1,69 @@
1
+ import css from './index.css?url'
2
+ import { createElement } from './utils'
3
+
4
+ const iframe = document.querySelector('iframe')!
5
+ const nav = document.querySelector('nav')!
6
+
7
+ createElement('h3', { innerText: 'Examples', parentElement: nav })
8
+
9
+ const urls = Object.fromEntries(
10
+ Object.entries(import.meta.glob('./examples/*.ts', { eager: false })).map(([key, entry]) => {
11
+ const name = key.split('/').pop()!.replace('.ts', '')
12
+ const chunk = entry.toString().match(/import\(['"]([^'"]+)['"]/)![1]!
13
+ return [name, chunk] as const
14
+ }),
15
+ )
16
+
17
+ Object.entries(urls).forEach(([name, localUrl]) => {
18
+ createElement('button', {
19
+ onclick(event) {
20
+ event.preventDefault()
21
+ load(name, localUrl)
22
+ },
23
+ innerHTML: name,
24
+ parentElement: nav,
25
+ 'data-route': name,
26
+ })
27
+ })
28
+
29
+ function load(name: string, url: string) {
30
+ // Use hash routing instead of pushState for GitHub Pages compatibility
31
+ window.location.hash = name
32
+
33
+ URL.revokeObjectURL(iframe.src)
34
+
35
+ nav.querySelectorAll('button').forEach(button => {
36
+ if (button.getAttribute('data-route') === name) {
37
+ button.classList.add('active')
38
+ } else {
39
+ button.classList.remove('active')
40
+ }
41
+ })
42
+
43
+ iframe.src = URL.createObjectURL(
44
+ new Blob(
45
+ [
46
+ `<head>
47
+ <link rel="stylesheet" href="${new URL(css, import.meta.url).href}"></link>
48
+ <script type="module" src="${new URL(url, import.meta.url).href}"></script></head>`,
49
+ ],
50
+ {
51
+ type: 'text/html',
52
+ },
53
+ ),
54
+ )
55
+ }
56
+
57
+ // Handle hash-based routing
58
+ const hash = window.location.hash.slice(1) // Remove #
59
+ if (hash && hash in urls) {
60
+ load(hash, urls[hash]!)
61
+ }
62
+
63
+ // Listen for hash changes
64
+ window.addEventListener('hashchange', () => {
65
+ const hash = window.location.hash.slice(1)
66
+ if (hash && hash in urls) {
67
+ load(hash, urls[hash]!)
68
+ }
69
+ })
@@ -48,11 +48,17 @@ export function createElement<T extends keyof HTMLElementTagNameMap>(
48
48
  {
49
49
  parentElement,
50
50
  ...options
51
- }: Partial<Omit<HTMLElementTagNameMap[T], 'style'> & { style: string }> = {},
51
+ }: Partial<Omit<HTMLElementTagNameMap[T], 'style'> & { style: string }> &
52
+ Record<`data-${string}`, string> = {},
52
53
  ) {
53
54
  const element = document.createElement(tag)
55
+
54
56
  for (const key in options) {
55
- element[key] = options[key]
57
+ if (key.startsWith('data-')) {
58
+ element.setAttribute(key, options[key])
59
+ } else {
60
+ element[key] = options[key]
61
+ }
56
62
  }
57
63
 
58
64
  ;(parentElement ?? document.body).appendChild(element)
@@ -2,7 +2,7 @@ import { defineConfig } from 'vite'
2
2
  import tsconfigPaths from 'vite-tsconfig-paths'
3
3
 
4
4
  export default defineConfig({
5
- base: './',
5
+ base: process.env.GITHUB_ACTIONS ? 'https://bigmistqke.github.io/view.gl/' : undefined,
6
6
  assetsInclude: ['assets/**/*'],
7
7
  plugins: [
8
8
  tsconfigPaths(),
@@ -38,5 +38,13 @@ export default defineConfig({
38
38
  build: {
39
39
  target: 'esnext',
40
40
  minify: false,
41
+ rollupOptions: {
42
+ input: {
43
+ main: './dev/index.html',
44
+ index: './dev/src/index.ts', // Separate entry for index.ts
45
+ utils: './dev/src/utils.ts', // Separate entry for utils.ts
46
+ 404: './dev/404.html',
47
+ },
48
+ },
41
49
  },
42
50
  })
package/dist/index.d.mts CHANGED
@@ -1,5 +1,6 @@
1
- import { V as ViewSchema, G as GL, a as ViewOptions, b as View, U as UniformSchema, c as UniformView, A as AttributeSchema, d as AttributeView, I as InterleavedAttributeSchema, e as InterleavedAttributeView, B as BufferSchema, f as BufferView } from './types-DxpS9Bae.mjs';
1
+ import { V as ViewSchema, G as GL, a as ViewOptions, b as View, U as UniformSchema, c as UniformView, A as AttributeSchema, d as AttributeView, I as InterleavedAttributeSchema, e as InterleavedAttributeView, B as BufferSchema, f as BufferView } from './types-DoFAJoh-.mjs';
2
2
 
3
+ declare function toID(key: string | number | symbol): any;
3
4
  /**********************************************************************************/
4
5
  /**********************************************************************************/
5
6
  declare function view<T extends ViewSchema>(gl: GL, program: WebGLProgram, schema: T, options?: ViewOptions): View<T>;
@@ -14,4 +15,4 @@ declare function interleavedAttributeView<T extends InterleavedAttributeSchema>(
14
15
  /**********************************************************************************/
15
16
  declare function bufferView<T extends BufferSchema>(gl: GL, schema: T, { signal }?: ViewOptions): BufferView<T>;
16
17
 
17
- export { attributeView, bufferView, interleavedAttributeView, uniformView, view };
18
+ export { attributeView, bufferView, interleavedAttributeView, toID, uniformView, view };
package/dist/index.mjs CHANGED
@@ -1,3 +1,9 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name2 in all)
4
+ __defProp(target, name2, { get: all[name2], enumerable: true });
5
+ };
6
+
1
7
  // src/features.ts
2
8
  var INSTANCED_ARRAYS_WRAPPER_MAP = /* @__PURE__ */ new WeakMap();
3
9
  function getInstancedArrays(gl) {
@@ -30,12 +36,32 @@ function getVertexArrayObject(gl) {
30
36
  return wrapper;
31
37
  }
32
38
 
33
- // src/utils.ts
34
- function mapObject(value, callback) {
35
- return Object.fromEntries(
36
- Object.entries(value).map(([key, value2], index) => [key, callback(value2, key, index)])
37
- );
39
+ // src/utils/object.ts
40
+ var object_exports = {};
41
+ __export(object_exports, {
42
+ forEach: () => forEach,
43
+ map: () => map
44
+ });
45
+ function forEach(value, callback) {
46
+ let index2 = 0;
47
+ for (const key in value) {
48
+ callback(value[key], key, index2);
49
+ index2++;
50
+ }
51
+ for (const key of Object.getOwnPropertySymbols(value)) {
52
+ callback(value[key], key, index2);
53
+ index2++;
54
+ }
55
+ }
56
+ function map(value, callback) {
57
+ const result = {};
58
+ forEach(value, (value2, key, index2) => {
59
+ result[key] = callback(value2, key, index2);
60
+ });
61
+ return result;
38
62
  }
63
+
64
+ // src/utils/index.ts
39
65
  function assertedNotNullish(value, message) {
40
66
  if (value === void 0 || value === null) throw new Error(message);
41
67
  return value;
@@ -71,17 +97,47 @@ var kindToSize = (kind) => {
71
97
  switch (kind[0]) {
72
98
  case "m":
73
99
  const [a, b] = kind.match(/\d+/g).map(Number);
74
- return a * (b || a);
100
+ return a * (b ?? a);
75
101
  case "v":
76
- return +kind.match(/\d/)[0];
102
+ case "i":
103
+ case "b":
104
+ case "u":
105
+ const match = kind.match(/\d/);
106
+ return match ? +match[0] : 1;
77
107
  default:
78
108
  return 1;
79
109
  }
80
110
  };
81
111
  var isMatKind = (kind) => kind.includes("mat");
82
112
  var isSamplerKind = (kind) => kind.includes("sampler");
113
+ function createUpsertMap(constructor) {
114
+ const map2 = new (constructor ?? Map)();
115
+ return Object.assign(map2, {
116
+ getOrInsert(key, value) {
117
+ let result = map2.get(key);
118
+ if (result) {
119
+ return result;
120
+ }
121
+ result = value();
122
+ map2.set(key, result);
123
+ return result;
124
+ }
125
+ });
126
+ }
83
127
 
84
128
  // src/index.ts
129
+ var index = 0;
130
+ var PREFIX = "VIEW_GL_ALIAS";
131
+ var SYMBOL_MAP = createUpsertMap(WeakMap);
132
+ function toID(key) {
133
+ if (typeof key === "string") {
134
+ return key;
135
+ }
136
+ if (typeof key === "symbol") {
137
+ return SYMBOL_MAP.getOrInsert(key, () => `${PREFIX}_${index++}`);
138
+ }
139
+ return key.toString();
140
+ }
85
141
  function view(gl, program, schema, options) {
86
142
  return {
87
143
  uniforms: !schema.uniforms ? void 0 : uniformView(gl, program, schema.uniforms),
@@ -91,7 +147,8 @@ function view(gl, program, schema, options) {
91
147
  };
92
148
  }
93
149
  function uniformView(gl, program, schema) {
94
- return mapObject(schema, ({ kind, size }, name2) => {
150
+ return object_exports.map(schema, ({ kind, size }, key) => {
151
+ const name2 = toID(key);
95
152
  const location = gl.getUniformLocation(program, name2);
96
153
  if (isSamplerKind(kind)) {
97
154
  return {
@@ -124,9 +181,10 @@ function handleAttribute(gl, location, size, stride, offset, type, instanced) {
124
181
  }
125
182
  }
126
183
  function attributeView(gl, program, schema, { signal } = {}) {
127
- const attributes = mapObject(
184
+ const attributes = object_exports.map(
128
185
  schema,
129
- ({ kind, instanced, buffer = assertedNotNullish(gl.createBuffer()) }, name2) => {
186
+ ({ kind, instanced, buffer = assertedNotNullish(gl.createBuffer()) }, key) => {
187
+ const name2 = toID(key);
130
188
  const location = gl.getAttribLocation(program, name2);
131
189
  if (location < 0) {
132
190
  throw new Error(`Attribute '${name2}' not found`);
@@ -151,27 +209,26 @@ function attributeView(gl, program, schema, { signal } = {}) {
151
209
  }
152
210
  );
153
211
  signal?.addEventListener("abort", function dispose() {
154
- for (const name2 in attributes) {
155
- attributes[name2].dispose();
156
- }
212
+ object_exports.forEach(attributes, (value) => value.dispose());
157
213
  });
158
214
  return attributes;
159
215
  }
160
216
  function interleavedAttributeView(gl, program, schema, { signal } = {}) {
161
- const interleavedAttributes = mapObject(schema, ({ layout, instanced }) => {
162
- let index = 0;
217
+ const interleavedAttributes = object_exports.map(schema, ({ layout, instanced }) => {
218
+ let index2 = 0;
163
219
  const handles = layout.map((layout2) => {
164
- const location = gl.getAttribLocation(program, layout2.name);
220
+ const name2 = toID(layout2.key);
221
+ const location = gl.getAttribLocation(program, name2);
165
222
  if (location < 0) {
166
- throw new Error(`Attribute '${layout2.name}' not found`);
223
+ throw new Error(`Attribute '${name2}' not found`);
167
224
  }
168
225
  const size = kindToSize(layout2.kind);
169
- const offset = index;
226
+ const offset = index2;
170
227
  const type = layout2.kind.startsWith("i") ? "INT" : "FLOAT";
171
- index += size * 4;
228
+ index2 += size * 4;
172
229
  return () => handleAttribute(gl, location, size, stride, offset, type, instanced);
173
230
  });
174
- const stride = index;
231
+ const stride = index2;
175
232
  const buffer = assertedNotNullish(gl.createBuffer());
176
233
  let vao = void 0;
177
234
  const feature = getVertexArrayObject(gl);
@@ -231,14 +288,12 @@ function interleavedAttributeView(gl, program, schema, { signal } = {}) {
231
288
  };
232
289
  });
233
290
  signal?.addEventListener("abort", function dispose() {
234
- for (const name2 in interleavedAttributes) {
235
- interleavedAttributes[name2].dispose();
236
- }
291
+ object_exports.forEach(interleavedAttributes, (value) => value.dispose());
237
292
  });
238
293
  return interleavedAttributes;
239
294
  }
240
295
  function bufferView(gl, schema, { signal } = {}) {
241
- const buffers = mapObject(schema, ({ target = "ARRAY_BUFFER", usage = "STATIC_DRAW" }) => {
296
+ const buffers = object_exports.map(schema, ({ target = "ARRAY_BUFFER", usage = "STATIC_DRAW" }) => {
242
297
  const buffer = assertedNotNullish(gl.createBuffer());
243
298
  return {
244
299
  bind() {
@@ -254,9 +309,7 @@ function bufferView(gl, schema, { signal } = {}) {
254
309
  };
255
310
  });
256
311
  signal?.addEventListener("abort", function dispose() {
257
- for (const name2 in buffers) {
258
- buffers[name2].dispose();
259
- }
312
+ object_exports.forEach(buffers, (value) => value.dispose());
260
313
  });
261
314
  return buffers;
262
315
  }
@@ -264,6 +317,7 @@ export {
264
317
  attributeView,
265
318
  bufferView,
266
319
  interleavedAttributeView,
320
+ toID,
267
321
  uniformView,
268
322
  view
269
323
  };