@bigmistqke/view.gl 0.1.11 → 0.1.12

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.
@@ -1,9 +1,6 @@
1
1
  type Prettify<T> = {
2
2
  [K in keyof T]: T[K];
3
3
  } & {};
4
- type RemoveSuffix<T, S extends string> = {
5
- [K in keyof T as K extends `${infer Prefix}${S}` ? Prefix : K]: T[K];
6
- };
7
4
  type DeepMerge<A extends readonly [...any]> = A extends [infer L, ...infer R] ? DeepMergeTwo<L, DeepMerge<R>> : unknown;
8
5
  type DeepMergeTwo<TBase, TOverride> = {
9
6
  [K in keyof TBase | keyof TOverride]: K extends keyof TOverride ? K extends keyof TBase ? ShallowMerge<[TBase[K], TOverride[K]]> : TOverride[K] : K extends keyof TBase ? TBase[K] : never;
@@ -22,6 +19,8 @@ type Id<T> = T extends infer U ? {
22
19
  } : never;
23
20
  type ShallowMergeTwo<L, R> = Id<Pick<L, Exclude<keyof L, keyof R>> & Pick<R, Exclude<keyof R, OptionalPropertyNames<R>>> & Pick<R, Exclude<OptionalPropertyNames<R>, keyof L>> & SpreadProperties<L, R, OptionalPropertyNames<R> & keyof L>>;
24
21
 
22
+ /**********************************************************************************/
23
+ /**********************************************************************************/
25
24
  type GL = WebGLRenderingContext | WebGL2RenderingContext;
26
25
  type GLTarget = 'ARRAY_BUFFER' | 'ELEMENT_ARRAY_BUFFER';
27
26
  type GLUsage = 'STATIC_DRAW' | 'DYNAMIC_DRAW' | 'STREAM_DRAW';
@@ -116,8 +115,9 @@ interface KIND_TO_SIZE_MAP {
116
115
  }
117
116
  /**********************************************************************************/
118
117
  /**********************************************************************************/
119
- type UniformFnName = '1f' | '2f' | '3f' | '4f' | '1i' | '2i' | '3i' | '4i' | '1ui' | '2ui' | '3ui' | '4ui' | 'mat2' | 'mat3' | 'mat4' | 'mat2x3' | 'mat2x4' | 'mat3x2' | 'mat3x4' | 'mat4x2' | 'mat4x3' | 'sampler2D' | 'samplerCube' | 'sampler2DArray' | 'isampler2D' | 'isamplerCube' | 'isampler2DArray' | 'usampler2D' | 'usamplerCube' | 'usampler2DArray';
120
- type UniformKind = 'float' | 'vec2' | 'vec3' | 'vec4' | 'int' | 'ivec2' | 'ivec3' | 'ivec4' | 'bool' | 'bvec2' | 'bvec3' | 'bvec4' | 'mat2' | 'mat3' | 'mat4' | 'sampler2D' | 'samplerCube' | 'uint' | 'uvec2' | 'uvec3' | 'uvec4' | 'mat2x3' | 'mat2x4' | 'mat3x2' | 'mat3x4' | 'mat4x2' | 'mat4x3' | 'sampler3D' | 'sampler2DArray' | 'sampler2DShadow' | 'samplerCubeShadow' | 'sampler2DArrayShadow' | 'isampler2D' | 'isampler3D' | 'isamplerCube' | 'isampler2DArray' | 'usampler2D' | 'usampler3D' | 'usamplerCube' | 'usampler2DArray';
118
+ type UniformFnName = KIND_TO_UNIFORM_FN_NAME_MAP[keyof KIND_TO_UNIFORM_FN_NAME_MAP];
119
+ type UniformKind = keyof KIND_TO_UNIFORM_FN_NAME_MAP;
120
+ type MatrixArray<Size extends number> = [Float32Array] | number[];
121
121
  interface UniformKindMap {
122
122
  float: [number];
123
123
  vec2: [number, number];
@@ -135,105 +135,15 @@ interface UniformKindMap {
135
135
  uvec2: [number, number];
136
136
  uvec3: [number, number, number];
137
137
  uvec4: [number, number, number, number];
138
- mat2: [Float32Array] | [
139
- number,
140
- number,
141
- number,
142
- number
143
- ];
144
- mat3: [Float32Array] | [
145
- number,
146
- number,
147
- number,
148
- number,
149
- number,
150
- number,
151
- number,
152
- number,
153
- number
154
- ];
155
- mat4: [Float32Array] | [
156
- number,
157
- number,
158
- number,
159
- number,
160
- number,
161
- number,
162
- number,
163
- number,
164
- number,
165
- number,
166
- number,
167
- number,
168
- number,
169
- number,
170
- number,
171
- number
172
- ];
173
- mat2x3: [Float32Array] | [
174
- number,
175
- number,
176
- number,
177
- number,
178
- number,
179
- number
180
- ];
181
- mat2x4: [Float32Array] | [
182
- number,
183
- number,
184
- number,
185
- number,
186
- number,
187
- number,
188
- number,
189
- number
190
- ];
191
- mat3x2: [Float32Array] | [
192
- number,
193
- number,
194
- number,
195
- number,
196
- number,
197
- number
198
- ];
199
- mat3x4: [Float32Array] | [
200
- number,
201
- number,
202
- number,
203
- number,
204
- number,
205
- number,
206
- number,
207
- number,
208
- number,
209
- number,
210
- number,
211
- number
212
- ];
213
- mat4x2: [Float32Array] | [
214
- number,
215
- number,
216
- number,
217
- number,
218
- number,
219
- number,
220
- number,
221
- number
222
- ];
223
- mat4x3: [Float32Array] | [
224
- number,
225
- number,
226
- number,
227
- number,
228
- number,
229
- number,
230
- number,
231
- number,
232
- number,
233
- number,
234
- number,
235
- number
236
- ];
138
+ mat2: MatrixArray<4>;
139
+ mat3: MatrixArray<9>;
140
+ mat4: MatrixArray<16>;
141
+ mat2x3: MatrixArray<6>;
142
+ mat2x4: MatrixArray<8>;
143
+ mat3x2: MatrixArray<6>;
144
+ mat3x4: MatrixArray<12>;
145
+ mat4x2: MatrixArray<8>;
146
+ mat4x3: MatrixArray<12>;
237
147
  sampler2D: [number];
238
148
  samplerCube: [number];
239
149
  sampler3D: [number];
@@ -255,12 +165,16 @@ interface UniformDefinition {
255
165
  size?: number;
256
166
  }
257
167
  type UniformSchema = Record<string | symbol, UniformDefinition>;
258
- type UniformSchemaPartial = Record<string | symbol, Partial<UniformDefinition>>;
259
- type UniformMethods<TDefinition extends UniformDefinition> = TDefinition['size'] extends number ? {
168
+ /** Methods for a single uniform element */
169
+ type UniformElementMethods<TKind extends UniformKind> = {
170
+ set(...args: UniformKindMap[TKind]): void;
171
+ };
172
+ /** Methods for array uniforms - supports both bulk set and indexed access */
173
+ type UniformArrayMethods<TKind extends UniformKind, TSize extends number> = Array<UniformElementMethods<TKind>> & {
174
+ /** Bulk set all elements at once */
260
175
  set(arg: Float32Array): void;
261
- } : {
262
- set(...args: UniformKindMap[TDefinition['kind']]): void;
263
176
  };
177
+ type UniformMethods<TDefinition extends UniformDefinition> = TDefinition['size'] extends number ? UniformArrayMethods<TDefinition['kind'], TDefinition['size']> : UniformElementMethods<TDefinition['kind']>;
264
178
  type UniformView<T extends UniformSchema> = {
265
179
  [K in keyof T]: UniformMethods<T[K]>;
266
180
  };
@@ -385,11 +299,12 @@ interface ViewSchema {
385
299
  interleavedAttributes?: InterleavedAttributeSchema;
386
300
  buffers?: BufferSchema;
387
301
  }
302
+ type PartialSchema<T> = T extends Record<string | symbol, infer V> ? Record<string | symbol, Partial<V>> : never;
388
303
  interface ViewSchemaPartial {
389
- uniforms?: Record<string | symbol, Partial<UniformDefinition>>;
390
- attributes?: Record<string | symbol, Partial<AttributeDefinition>>;
391
- interleavedAttributes?: Record<string | symbol, Partial<InterleavedAttributeDefinition>>;
392
- buffers?: Record<string | symbol, Partial<BufferDefinition>>;
304
+ uniforms?: PartialSchema<UniformSchema>;
305
+ attributes?: PartialSchema<AttributeSchema>;
306
+ interleavedAttributes?: PartialSchema<InterleavedAttributeSchema>;
307
+ buffers?: PartialSchema<BufferSchema>;
393
308
  }
394
309
  type View<T extends ViewSchema = ViewSchema> = {
395
310
  attributes: T['attributes'] extends AttributeSchema ? Prettify<AttributeView<T['attributes']>> : {};
@@ -403,6 +318,8 @@ interface GLSLResult {
403
318
  program: WebGLProgram;
404
319
  schema: ViewSchema;
405
320
  }
321
+ /**********************************************************************************/
322
+ /**********************************************************************************/
406
323
  type GLSLSlotItem = GLSL | UniformToken | AttributeToken | InterleaveToken | string | number | symbol;
407
324
  type GLSLSlot = GLSLSlotItem | Array<GLSLSlotItem>;
408
325
  interface GLSL<TSlots extends GLSLSlot[] = GLSLSlot[]> {
@@ -443,21 +360,26 @@ type InterleaveToken<TKey extends string | symbol = string | symbol, TLayout ext
443
360
  [TKey in keyof TLayout]: Prettify<Pick<TLayout[TKey], 'kind' | 'key'>>;
444
361
  };
445
362
  };
446
- type GLSLToSchema<T extends GLSL> = FlattenSlots<T> extends infer TSlots ? TSlots extends Array<any> ? GLSLSlotsToSchema<TSlots> : never : never;
363
+ type GLSLToSchema<T extends GLSL> = T extends GLSL<infer TSlots> ? FlattenSlots<TSlots> extends infer TFlatSlots extends Array<GLSLSlot> ? GLSLSlotsToSchema<TFlatSlots> : never : never;
447
364
  type GLSLToView<T extends GLSL> = View<GLSLToSchema<T>>;
365
+ type ExtractTokens<TSlots extends Array<GLSLSlot>, TTokenType> = TSlots[number] extends infer U ? U extends TTokenType ? U : never : never;
448
366
  type GLSLSlotsToSchema<TSlots extends Array<GLSLSlot>> = {
449
367
  uniforms: {
450
- [K in Extract<TSlots[number], UniformToken> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>;
368
+ [K in ExtractTokens<TSlots, UniformToken> as K['key']]: Omit<K, 'type'>;
451
369
  };
452
370
  attributes: {
453
- [K in Extract<TSlots[number], AttributeToken> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>;
371
+ [K in ExtractTokens<TSlots, AttributeToken> as K['key']]: Omit<K, 'type'>;
454
372
  };
455
373
  interleavedAttributes: {
456
- [K in Extract<TSlots[number], InterleaveToken> as K['key']]: Prettify<Omit<K, 'name' | 'type'>>;
374
+ [K in ExtractTokens<TSlots, InterleaveToken> as K['key']]: Omit<K, 'type'>;
457
375
  };
458
376
  };
459
- type FlattenSlots<T> = T extends GLSL<infer TSlots> ? _FlattenSlots<TSlots> : T extends Array<GLSLSlot> ? _FlattenSlots<T> : never;
460
- type _FlattenSlots<T extends Array<GLSLSlot>> = T extends [infer First, ...infer Rest] ? First extends GLSL ? [...FlattenSlots<First>, ...FlattenSlots<Rest>] : First extends unknown[] ? [...FlattenSlots<First>, ...FlattenSlots<Rest>] : [First, ...FlattenSlots<Rest>] : [];
377
+ type FlattenSlots<T, MaxDepth extends Depth = 10> = T extends Array<GLSLSlot> ? _FlattenSlots<T, [], MaxDepth> : T extends GLSL<infer TSlots> ? _FlattenSlots<TSlots, [], MaxDepth> : never;
378
+ type _FlattenSlots<T extends Array<GLSLSlot>, Acc extends Array<any> = [], CurrentDepth extends Depth = 10> = CurrentDepth extends 0 ? [...Acc, ...T] : T extends [infer First, ...infer Rest extends Array<GLSLSlot>] ? First extends GLSL<infer TSlots> ? _FlattenSlots<Rest, [...Acc, ..._FlattenSlots<TSlots, [], Dec<CurrentDepth>>], Dec<CurrentDepth>> : First extends GLSLSlot[] ? _FlattenSlots<Rest, [...Acc, ..._FlattenSlots<First, [], Dec<CurrentDepth>>], Dec<CurrentDepth>> : _FlattenSlots<Rest, [...Acc, First], Dec<CurrentDepth>> : [...Acc, ...T];
379
+ /**********************************************************************************/
380
+ /**********************************************************************************/
381
+ type Depth = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10;
382
+ type Dec<T extends number> = T extends 10 ? 9 : T extends 9 ? 8 : T extends 8 ? 7 : T extends 7 ? 6 : T extends 6 ? 5 : T extends 5 ? 4 : T extends 4 ? 3 : T extends 3 ? 2 : T extends 2 ? 1 : T extends 1 ? 0 : 0;
461
383
  type MergeGLSLSchema<TVertex extends ViewSchema, TFragment extends ViewSchema, TOverrides extends ViewSchemaPartial | undefined = {}> = TOverrides extends ViewSchemaPartial ? {
462
384
  uniforms: Prettify<DeepMerge<[
463
385
  ShallowMerge<[TVertex['uniforms'], TFragment['uniforms']]>,
@@ -484,4 +406,4 @@ type CompileResult<TVertex extends GLSL, TFragment extends GLSL, TOverrideSchema
484
406
  fragment: string;
485
407
  } : never;
486
408
 
487
- export type { GLSL as $, AttributeSchema as A, BufferSchema as B, BufferDefinition as C, BufferMethods as D, Framebuffer as E, FramebufferDefinition as F, GL as G, TextureTarget as H, InterleavedAttributeSchema as I, TextureSchema as J, KIND_TO_UNIFORM_FN_NAME_MAP as K, TextureMethods as L, TextureView as M, TextureParameterName as N, TextureParameterValue as O, TextureParameters as P, InternalFormat as Q, RemoveSuffix as R, Format as S, TextureDefinition as T, UniformSchema as U, ViewSchema as V, PixelType as W, TexImage2DOptions as X, ViewSchemaPartial as Y, GLSLResult as Z, GLSLSlot as _, ViewOptions as a, UniformToken as a0, UniformTokenFn as a1, AttributeToken as a2, AttributeTokenFn as a3, InterleaveToken as a4, GLSLToSchema as a5, GLSLToView as a6, GLSLSlotsToSchema as a7, MergeGLSLSchema as a8, CompileResult as a9, Prettify as aa, View as b, UniformView as c, AttributeView as d, InterleavedAttributeView as e, BufferView as f, GLTarget as g, GLUsage as h, GLTextureTarget as i, GLTextureFormat as j, GLTextureType as k, GLTextureFilter as l, GLTextureWrap as m, KIND_TO_SIZE_MAP as n, UniformFnName as o, UniformKind as p, UniformDefinition as q, UniformSchemaPartial as r, UniformMethods as s, AttributeShortHand as t, AttributeKind as u, AttributeDefinition as v, AttributeMethods as w, InterleavedAttributeLayout as x, InterleavedAttributeDefinition as y, InterleavedAttributeMethods as z };
409
+ export type { GLSL as $, AttributeSchema as A, BufferSchema as B, InterleavedAttributeMethods as C, BufferDefinition as D, BufferMethods as E, FramebufferDefinition as F, GL as G, Framebuffer as H, InterleavedAttributeSchema as I, TextureTarget as J, KIND_TO_UNIFORM_FN_NAME_MAP as K, TextureSchema as L, TextureMethods as M, TextureView as N, TextureParameterName as O, TextureParameterValue as P, TextureParameters as Q, InternalFormat as R, Format as S, TextureDefinition as T, UniformSchema as U, ViewSchema as V, PixelType as W, TexImage2DOptions as X, ViewSchemaPartial as Y, GLSLResult as Z, GLSLSlot as _, ViewOptions as a, UniformToken as a0, UniformTokenFn as a1, AttributeToken as a2, AttributeTokenFn as a3, InterleaveToken as a4, GLSLToSchema as a5, GLSLToView as a6, GLSLSlotsToSchema as a7, FlattenSlots as a8, MergeGLSLSchema as a9, CompileResult as aa, Prettify as ab, View as b, UniformView as c, AttributeView as d, InterleavedAttributeView as e, BufferView as f, GLTarget as g, GLUsage as h, GLTextureTarget as i, GLTextureFormat as j, GLTextureType as k, GLTextureFilter as l, GLTextureWrap as m, KIND_TO_SIZE_MAP as n, UniformFnName as o, UniformKind as p, UniformDefinition as q, UniformElementMethods as r, UniformArrayMethods as s, UniformMethods as t, AttributeShortHand as u, AttributeKind as v, AttributeDefinition as w, AttributeMethods as x, InterleavedAttributeLayout as y, InterleavedAttributeDefinition as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bigmistqke/view.gl",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "👀 Utilities for managing WebGL resources.",
5
5
  "exports": {
6
6
  ".": {
@@ -10,10 +10,6 @@
10
10
  "./tag": {
11
11
  "import": "./dist/tag.mjs",
12
12
  "types": "./dist/tag.d.mts"
13
- },
14
- "./gl": {
15
- "import": "./dist/gl.mjs",
16
- "types": "./dist/gl.d.mts"
17
13
  }
18
14
  },
19
15
  "keywords": [
@@ -23,6 +19,7 @@
23
19
  "license": "ISC",
24
20
  "devDependencies": {
25
21
  "@vitest/ui": "^3.2.4",
22
+ "bumpp": "^10.4.0",
26
23
  "concurrently": "^9.2.1",
27
24
  "happy-dom": "^20.0.0",
28
25
  "prettier": "^3.6.2",
@@ -30,21 +27,20 @@
30
27
  "typescript": "^5.8.3",
31
28
  "vite": "^7.0.2",
32
29
  "vite-tsconfig-paths": "^5.1.4",
33
- "vitest": "^3.2.4",
34
- "bumpp": "^10.3.2"
30
+ "vitest": "^3.2.4"
35
31
  },
36
32
  "scripts": {
37
33
  "build": "tsup",
34
+ "bump": "bumpp",
38
35
  "dev:build": "vite build dev",
39
36
  "dev:preview": "vite preview dev",
40
37
  "dev:watch": "concurrently \"pnpm dev:preview\" \"vite dev:build --watch\"",
41
38
  "dev": "vite serve dev",
42
39
  "format": "prettier -w \"src/**/*.{js,ts,json,css,tsx,jsx}\" \"dev/**/*.{js,ts,json,css,tsx,jsx}\"",
43
- "prepublish": "pnpm test && pnpm build",
44
- "test": "vitest --run",
40
+ "lint:types": "tsc --noEmit",
41
+ "prepublish": "pnpm build",
45
42
  "test:coverage": "vitest run --coverage",
46
43
  "test:ui": "vitest --ui",
47
- "lint:types": "tsc --noEmit",
48
- "bump": "bumpp"
44
+ "test": "vitest --run"
49
45
  }
50
46
  }
@@ -1,49 +1,5 @@
1
1
  import { RemoveSuffix } from './type-utils'
2
- import { GL } from './types'
3
-
4
- export function createShader(gl: GL, type: number, source: string): WebGLShader {
5
- const shader = gl.createShader(type)
6
- if (!shader) throw new Error('Failed to create shader')
7
-
8
- gl.shaderSource(shader, source)
9
- gl.compileShader(shader)
10
-
11
- if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
12
- const info = gl.getShaderInfoLog(shader)
13
- gl.deleteShader(shader)
14
- throw new Error(
15
- `Failed to compile ${type === gl.VERTEX_SHADER ? 'vertex' : 'fragment'} shader: ${info}`,
16
- )
17
- }
18
-
19
- return shader
20
- }
21
-
22
- export function createProgram(gl: GL, vertexSource: string, fragmentSource: string): WebGLProgram {
23
- const program = gl.createProgram()
24
- if (!program) throw new Error('Failed to create WebGL program')
25
-
26
- const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexSource)
27
- const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentSource)
28
-
29
- gl.attachShader(program, vertexShader)
30
- gl.attachShader(program, fragmentShader)
31
- gl.linkProgram(program)
32
-
33
- if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
34
- const info = gl.getProgramInfoLog(program)
35
- gl.deleteProgram(program)
36
- gl.deleteShader(vertexShader)
37
- gl.deleteShader(fragmentShader)
38
- throw new Error(`Failed to link program: ${info}`)
39
- }
40
-
41
- // Clean up shaders after linking
42
- gl.deleteShader(vertexShader)
43
- gl.deleteShader(fragmentShader)
44
-
45
- return program
46
- }
2
+ import type { GL } from './types'
47
3
 
48
4
  const INSTANCED_ARRAYS_WRAPPER_MAP = new WeakMap<
49
5
  GL,
package/src/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { getInstancedArrays, getVertexArrayObject } from './gl'
1
+ import { getInstancedArrays, getVertexArrayObject } from './features'
2
2
  import type {
3
3
  AttributeMethods,
4
4
  AttributeSchema,
@@ -22,9 +22,9 @@ import {
22
22
  isSamplerKind,
23
23
  kindToSize,
24
24
  kindToUniformFnName,
25
+ ObjectUtils,
25
26
  } from './utils'
26
27
  export * from './types'
27
- import * as ObjectUtils from './utils/object'
28
28
 
29
29
  /**********************************************************************************/
30
30
  /* */
@@ -34,12 +34,19 @@ import * as ObjectUtils from './utils/object'
34
34
 
35
35
  let index = 0
36
36
  const PREFIX = 'VIEW_GL_ALIAS'
37
- const IS_FIREFOX = navigator.userAgent.toLowerCase().indexOf('firefox') >= 0
38
-
39
- // NOTE: using symbol as key for WeakMap is currently broken in firefox
40
- // see https://bugzilla.mozilla.org/show_bug.cgi?id=1710433
41
- // fallback to Map will currently cause a memory leak.
42
- const SYMBOL_MAP = createUpsertMap(IS_FIREFOX ? Map<symbol, string> : WeakMap<symbol, string>)
37
+ // Firefox has currently a bug where it can not handle symbol as WeakRef / key for WeakMap
38
+ // see https://bugzilla.mozilla.org/show_bug.cgi?id=1710433
39
+ const HAS_WEAK_SYMBOL = (() => {
40
+ try {
41
+ const symbol = Symbol()
42
+ new WeakMap().set(symbol, '')
43
+ return true
44
+ } catch {
45
+ return false
46
+ }
47
+ })()
48
+ // NOTE: fallback to Map will currently cause a minor memory leak.
49
+ const SYMBOL_MAP = createUpsertMap(HAS_WEAK_SYMBOL ? WeakMap<symbol, string> : Map<symbol, string>)
43
50
 
44
51
  export function toID(key: string | number | symbol) {
45
52
  if (typeof key === 'string') {
@@ -86,12 +93,12 @@ export function uniformView<T extends UniformSchema>(
86
93
  program: WebGLProgram,
87
94
  schema: T,
88
95
  ): InferUniformView<T> {
96
+ // @ts-expect-error - conditional return type based on size is hard to infer
89
97
  return ObjectUtils.map(schema, ({ kind, size }, key) => {
90
98
  const name = toID(key)
91
99
 
92
- const location = gl.getUniformLocation(program, name)
93
-
94
100
  if (isSamplerKind(kind)) {
101
+ const location = gl.getUniformLocation(program, name)
95
102
  return {
96
103
  set(arg: number) {
97
104
  gl.uniform1i(location, arg)
@@ -99,7 +106,39 @@ export function uniformView<T extends UniformSchema>(
99
106
  }
100
107
  }
101
108
 
102
- const fnName = `uniform${kindToUniformFnName(kind)}${size ? 'v' : ''}`
109
+ // Array uniform - support both bulk set and indexed access
110
+ if (size) {
111
+ const bulkFnName = `uniform${kindToUniformFnName(kind)}v`
112
+ // @ts-ignore FIX WEBGL/WEBGL2 TYPES
113
+ const bulkFn = gl[bulkFnName].bind(gl)
114
+ const bulkLocation = gl.getUniformLocation(program, name)
115
+
116
+ const elementFnName = `uniform${kindToUniformFnName(kind)}`
117
+ // @ts-ignore FIX WEBGL/WEBGL2 TYPES
118
+ const elementFn = gl[elementFnName].bind(gl)
119
+
120
+ // Build array of element setters
121
+ const elements: Array<{ set(...args: any[]): void }> = []
122
+ for (let i = 0; i < size; i++) {
123
+ const location = gl.getUniformLocation(program, `${name}[${i}]`)
124
+ elements[i] = {
125
+ set(...args: any[]) {
126
+ elementFn(location, ...args)
127
+ },
128
+ }
129
+ }
130
+
131
+ // Return array-like object with bulk set
132
+ return Object.assign(elements, {
133
+ set(arg: Float32Array) {
134
+ bulkFn(bulkLocation, arg)
135
+ },
136
+ })
137
+ }
138
+
139
+ // Non-array uniform
140
+ const location = gl.getUniformLocation(program, name)
141
+ const fnName = `uniform${kindToUniformFnName(kind)}`
103
142
 
104
143
  // @ts-ignore FIX WEBGL/WEBGL2 TYPES
105
144
  const fn = gl[fnName].bind(gl)
package/src/tag.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { toID, view } from '.'
2
- import { createProgram } from './gl'
3
2
  import type { Prettify } from './type-utils'
4
3
  import type {
5
4
  AttributeDefinition,
@@ -18,9 +17,9 @@ import type {
18
17
  ViewSchema,
19
18
  ViewSchemaPartial,
20
19
  } from './types'
21
- import { createUpsertMap } from './utils'
20
+ import { createProgram, createUpsertMap } from './utils'
22
21
 
23
- export function glsl<TSlot extends GLSLSlot, TSlots extends TSlot[]>(
22
+ export function glsl<TSlot extends GLSLSlot, const TSlots extends TSlot[]>(
24
23
  template: TemplateStringsArray,
25
24
  ...slots: [...TSlots]
26
25
  ): GLSL<TSlots> {