glre 0.38.0 → 0.39.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.
Files changed (49) hide show
  1. package/dist/addons.cjs +2 -0
  2. package/dist/addons.cjs.map +1 -0
  3. package/dist/addons.d.ts +457 -0
  4. package/dist/addons.js +2 -0
  5. package/dist/addons.js.map +1 -0
  6. package/dist/index.cjs +29 -41
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.ts +153 -307
  9. package/dist/index.js +29 -41
  10. package/dist/index.js.map +1 -1
  11. package/dist/native.cjs +1 -48
  12. package/dist/native.cjs.map +1 -1
  13. package/dist/native.d.ts +508 -8
  14. package/dist/native.js +1 -48
  15. package/dist/native.js.map +1 -1
  16. package/dist/node.cjs +40 -0
  17. package/dist/node.cjs.map +1 -0
  18. package/dist/node.d.ts +614 -0
  19. package/dist/node.js +40 -0
  20. package/dist/node.js.map +1 -0
  21. package/dist/react.cjs +1 -48
  22. package/dist/react.cjs.map +1 -1
  23. package/dist/react.d.ts +506 -4
  24. package/dist/react.js +1 -48
  25. package/dist/react.js.map +1 -1
  26. package/dist/solid.cjs +1 -48
  27. package/dist/solid.cjs.map +1 -1
  28. package/dist/solid.d.ts +506 -4
  29. package/dist/solid.js +1 -48
  30. package/dist/solid.js.map +1 -1
  31. package/package.json +56 -3
  32. package/src/addons/index.ts +6 -0
  33. package/src/index.ts +6 -22
  34. package/src/node/{core.ts → build.ts} +3 -7
  35. package/src/node/create.ts +73 -0
  36. package/src/node/index.ts +63 -47
  37. package/src/node/scope.ts +50 -47
  38. package/src/node/types.ts +207 -177
  39. package/src/node/utils/const.ts +62 -2
  40. package/src/node/utils/index.ts +6 -3
  41. package/src/node/utils/infer.ts +17 -29
  42. package/src/node/utils/parse.ts +11 -11
  43. package/src/node/utils/utils.ts +9 -9
  44. package/src/types.ts +2 -4
  45. package/src/utils/pipeline.ts +3 -3
  46. package/src/utils/program.ts +6 -1
  47. package/src/{webgl.ts → utils/webgl.ts} +24 -14
  48. package/src/{webgpu.ts → utils/webgpu.ts} +28 -7
  49. package/src/node/node.ts +0 -65
package/src/node/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { CONSTANTS, CONVERSIONS, FUNCTIONS, OPERATOR_KEYS } from './utils/const'
1
+ import { CONSTANTS, CONVERSIONS, FUNCTIONS, OPERATOR_KEYS, OPERATOR_TYPE_RULES } from './utils/const'
2
2
  import type { GL } from '../types'
3
3
 
4
4
  export type Constants = (typeof CONSTANTS)[number] | 'void'
@@ -11,18 +11,24 @@ export type Operators = (typeof OPERATOR_KEYS)[number]
11
11
  */
12
12
  export interface FnLayout {
13
13
  name: string
14
- type: Constants | 'auto'
14
+ type: C | 'auto'
15
15
  inputs?: Array<{
16
16
  name: string
17
- type: Constants
17
+ type: C
18
18
  }>
19
19
  }
20
20
 
21
- export interface FnType<T extends NodeProxy | StructNode | void, Args extends any[]> {
21
+ export interface FnType<T extends X | Struct | void, Args extends any[]> {
22
22
  (...args: Args): T extends void ? Void : T
23
23
  setLayout(layout: FnLayout): FnType<T, Args>
24
24
  }
25
25
 
26
+ export type StructFields = Record<string, X>
27
+
28
+ export interface StructFactory<T extends StructFields> {
29
+ (initialValues?: StructFields, instanceId?: string): Struct<T>
30
+ }
31
+
26
32
  /**
27
33
  * node
28
34
  */
@@ -55,6 +61,8 @@ export type NodeTypes =
55
61
  | 'switch'
56
62
  | 'declare'
57
63
  | 'return'
64
+ | 'break'
65
+ | 'continue'
58
66
 
59
67
  export interface NodeProps {
60
68
  id?: string
@@ -73,7 +81,7 @@ export interface NodeContext {
73
81
  label?: 'vert' | 'frag' | 'compute'
74
82
  isWebGL?: boolean
75
83
  units?: any // @TODO FIX
76
- infers?: WeakMap<NodeProxy, Constants>
84
+ infers?: WeakMap<X, C>
77
85
  onMount?: (name: string) => void
78
86
  code?: {
79
87
  headers: Map<string, string>
@@ -83,30 +91,24 @@ export interface NodeContext {
83
91
  vertVaryings: Map<string, string>
84
92
  computeInputs: Map<string, string>
85
93
  dependencies: Map<string, Set<string>>
86
- structFields: Map<string, StructFields>
94
+ structStructFields: Map<string, StructFields>
87
95
  }
88
96
  }
89
97
 
90
98
  /**
91
99
  * infer
92
100
  */
93
- type _StringLength<S extends string> = S extends `${infer _}${infer Rest}`
94
- ? Rest extends ''
95
- ? 1
96
- : Rest extends `${infer _}${infer Rest2}`
97
- ? Rest2 extends ''
98
- ? 2
99
- : Rest2 extends `${infer _}${infer Rest3}`
100
- ? Rest3 extends ''
101
- ? 3
102
- : 4
103
- : never
104
- : never
105
- : 0
101
+ // Optimized string length using direct pattern matching
102
+ // prettier-ignore
103
+ type _StringLength<A extends string> =
104
+ A extends `${infer _}${infer A}` ? A extends '' ? 1 :
105
+ A extends `${infer _}${infer B}` ? B extends '' ? 2 :
106
+ B extends `${infer _}${infer C}` ? C extends '' ? 3 :
107
+ 4 : never : never : never
106
108
 
107
109
  // Unified logic with infer.ts inferOperator function
108
110
  // prettier-ignore
109
- type InferOperator<L extends Constants, R extends Constants> =
111
+ type InferOperator<L extends C, R extends C> =
110
112
  L extends R ? L :
111
113
  // broadcast
112
114
  L extends 'float' | 'int' ? R :
@@ -122,19 +124,23 @@ type InferOperator<L extends Constants, R extends Constants> =
122
124
 
123
125
  // Unified logic with infer.ts inferArrayElement function
124
126
  // prettier-ignore
125
- type InferArrayElement<T extends Constants> =
127
+ type InferArrayElement<T extends C> =
126
128
  T extends 'mat4' ? 'vec4' :
127
129
  T extends 'mat3' ? 'vec3' :
128
130
  T extends 'mat2' ? 'vec2' :
129
131
  'float'
130
132
 
131
- type InferSwizzleType<S extends string> = _StringLength<S> extends 4
132
- ? 'vec4'
133
- : _StringLength<S> extends 3
134
- ? 'vec3'
135
- : _StringLength<S> extends 2
136
- ? 'vec2'
137
- : 'float'
133
+ type ExtractPairs<T> = T extends readonly [infer L, infer R, string] ? [L, R] | [R, L] : never
134
+ type OperatorTypeRules = ExtractPairs<(typeof OPERATOR_TYPE_RULES)[number]>
135
+ type IsInRules<L extends C, R extends C> = [L, R] extends OperatorTypeRules ? 1 : 0
136
+ type ValidateOperator<L extends C, R extends C> = L extends R ? 1 : IsInRules<L, R>
137
+
138
+ // prettier-ignore
139
+ type InferSwizzleType<S extends string> =
140
+ _StringLength<S> extends 4 ? 'vec4' :
141
+ _StringLength<S> extends 3 ? 'vec3' :
142
+ _StringLength<S> extends 2 ? 'vec2' :
143
+ 'float'
138
144
 
139
145
  /**
140
146
  * Swizzles
@@ -147,63 +153,34 @@ export type Swizzles =
147
153
  | _Swizzles<'p' | 'q'>
148
154
  | _Swizzles<'s' | 't'>
149
155
 
150
- type NodeProxyMethods =
151
- | Functions
152
- | Operators
153
- | Conversions
154
- | Swizzles
155
- // system property
156
- | '__nodeType'
157
- | 'type'
158
- | 'props'
159
- | 'isProxy'
160
- | 'assign'
161
- | 'toVar'
162
- | 'toString'
163
- | 'element'
164
-
165
- type ReadNodeProxy = {
166
- [K in string as K extends NodeProxyMethods ? never : K]: any
167
- } & {
168
- [K in Swizzles]: NodeProxy<InferSwizzleType<K>>
169
- }
170
-
171
- // Internal NodeProxy implementation (renamed from original)
172
- type NodeProxyImpl<T extends Constants> = BaseNodeProxy<T> & ReadNodeProxy
173
-
174
- export type Void = NodeProxyImpl<'void'>
175
- export type Bool = NodeProxyImpl<'bool'>
176
- export type UInt = NodeProxyImpl<'uint'>
177
- export type Int = NodeProxyImpl<'int'>
178
- export type Float = NodeProxyImpl<'float'>
179
- export type BVec2 = NodeProxyImpl<'bvec2'>
180
- export type IVec2 = NodeProxyImpl<'ivec2'>
181
- export type UVec2 = NodeProxyImpl<'uvec2'>
182
- export type Vec2 = NodeProxyImpl<'vec2'>
183
- export type BVec3 = NodeProxyImpl<'bvec3'>
184
- export type IVec3 = NodeProxyImpl<'ivec3'>
185
- export type UVec3 = NodeProxyImpl<'uvec3'>
186
- export type Vec3 = NodeProxyImpl<'vec3'>
187
- export type BVec4 = NodeProxyImpl<'bvec4'>
188
- export type IVec4 = NodeProxyImpl<'ivec4'>
189
- export type UVec4 = NodeProxyImpl<'uvec4'>
190
- export type Vec4 = NodeProxyImpl<'vec4'>
191
- export type Color = NodeProxyImpl<'color'>
192
- export type Mat2 = NodeProxyImpl<'mat2'>
193
- export type Mat3 = NodeProxyImpl<'mat3'>
194
- export type Mat4 = NodeProxyImpl<'mat4'>
195
- export type Texture = NodeProxyImpl<'texture'>
196
- export type Sampler2D = NodeProxyImpl<'sampler2D'>
197
- export type Struct = NodeProxyImpl<'struct'>
198
- export type StructFields = Record<string, NodeProxy>
199
- export type StructNode<T extends StructFields = any> = Omit<Struct, keyof T> & {
200
- [K in keyof T]: T[K] extends NodeProxy<infer U> ? NodeProxy<U> : never
156
+ export type Void = XImpl<'void'>
157
+ export type Bool = XImpl<'bool'>
158
+ export type UInt = XImpl<'uint'>
159
+ export type Int = XImpl<'int'>
160
+ export type Float = XImpl<'float'>
161
+ export type BVec2 = XImpl<'bvec2'>
162
+ export type IVec2 = XImpl<'ivec2'>
163
+ export type UVec2 = XImpl<'uvec2'>
164
+ export type Vec2 = XImpl<'vec2'>
165
+ export type BVec3 = XImpl<'bvec3'>
166
+ export type IVec3 = XImpl<'ivec3'>
167
+ export type UVec3 = XImpl<'uvec3'>
168
+ export type Vec3 = XImpl<'vec3'>
169
+ export type BVec4 = XImpl<'bvec4'>
170
+ export type IVec4 = XImpl<'ivec4'>
171
+ export type UVec4 = XImpl<'uvec4'>
172
+ export type Vec4 = XImpl<'vec4'>
173
+ export type Color = XImpl<'color'>
174
+ export type Mat2 = XImpl<'mat2'>
175
+ export type Mat3 = XImpl<'mat3'>
176
+ export type Mat4 = XImpl<'mat4'>
177
+ export type Texture = XImpl<'texture'>
178
+ export type Sampler2D = XImpl<'sampler2D'>
179
+ export type StructBase = XImpl<'struct'>
180
+ export type Struct<T extends StructFields = any> = Omit<StructBase, keyof T> & {
181
+ [K in keyof T]: T[K] extends X<infer U> ? X<U> : never
201
182
  } & {
202
- toVar(id?: string): StructNode<T>
203
- }
204
-
205
- export interface StructFactory<T extends StructFields> {
206
- (initialValues?: StructFields, instanceId?: string): StructNode<T>
183
+ toVar(id?: string): Struct<T>
207
184
  }
208
185
 
209
186
  export interface ConstantsToType {
@@ -230,57 +207,94 @@ export interface ConstantsToType {
230
207
  mat4: Mat4
231
208
  texture: Texture
232
209
  sampler2D: Sampler2D
233
- struct: Struct
210
+ struct: StructBase
234
211
  }
235
212
 
236
- export type NodeProxy<T extends Constants = Constants> = T extends keyof ConstantsToType
237
- ? ConstantsToType[T]
238
- : BaseNodeProxy<T>
213
+ /**
214
+ * X and Y
215
+ */
216
+ type XImpl<T extends C> = _X<T> & {
217
+ [K in string as K extends Methods ? never : K]: any
218
+ } & {
219
+ [K in Swizzles]: X<InferSwizzleType<K>>
220
+ }
239
221
 
240
- export type X<T extends Constants = Constants> = number | string | boolean | undefined | NodeProxy<T>
222
+ type C = Constants
223
+
224
+ export type X<T extends C = C> = T extends keyof ConstantsToType ? ConstantsToType[T] : _X<T>
225
+ export type Y<T extends C = C> = number | number[] | string | boolean | undefined | X<T>
226
+
227
+ type Methods =
228
+ | Functions
229
+ | Operators
230
+ | Conversions
231
+ | Swizzles
232
+ // system property
233
+ | '__nodeType'
234
+ | 'type'
235
+ | 'props'
236
+ | 'isProxy'
237
+ | 'assign'
238
+ | 'toVar'
239
+ | 'toString'
240
+ | 'element'
241
241
 
242
- export interface BaseNodeProxy<T extends Constants> {
242
+ interface _X<T extends C> {
243
243
  // System properties
244
244
  readonly __nodeType?: T
245
- assign(x: any): NodeProxy<T>
246
- toVar(name?: string): NodeProxy<T>
245
+ assign(x: any): X<T>
246
+ fragment(c: NodeContext): string
247
+ toVar(name?: string): X<T>
247
248
  toString(c?: NodeContext): string
249
+ fragment(c?: NodeContext): string
250
+ compute(c?: NodeContext): string
251
+ vertex(c?: NodeContext): string
248
252
  type: NodeTypes
249
253
  props: NodeProps
250
254
  isProxy: true
251
255
  listeners: Set<(value: any) => void>
252
256
 
253
257
  // Element access for array/matrix types
254
- element<Index extends X>(index: Index): NodeProxy<InferArrayElement<T>>
258
+ element<Index extends X>(index: Index): X<InferArrayElement<T>>
255
259
 
256
260
  // Enhanced member access with type preservation
257
- member<K extends string>(
258
- key: K
259
- ): K extends keyof T ? (T[K] extends NodeProxy<infer U> ? NodeProxy<U> : never) : never
260
-
261
- // Operators methods
262
- add<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
263
- sub<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
264
- mul<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
265
- div<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
266
- mod<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
267
- equal<U extends Constants>(x: X<U>): Bool
268
- notEqual<U extends Constants>(x: X<U>): Bool
269
- lessThan<U extends Constants>(x: X<U>): Bool
270
- lessThanEqual<U extends Constants>(x: X<U>): Bool
271
- greaterThan<U extends Constants>(x: X<U>): Bool
272
- greaterThanEqual<U extends Constants>(x: X<U>): Bool
273
- and(x: X<'bool'>): Bool
274
- or(x: X<'bool'>): Bool
261
+ member<K extends string>(key: K): K extends keyof T ? (T[K] extends X<infer U> ? X<U> : never) : never
262
+
263
+ // Operators methods with unified type validation
264
+ add<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): X<InferOperator<T, U>>
265
+ sub<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): X<InferOperator<T, U>>
266
+ mul<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): X<InferOperator<T, U>>
267
+ div<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): X<InferOperator<T, U>>
268
+ mod<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): X<InferOperator<T, U>>
269
+ equal<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): Bool
270
+ notEqual<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): Bool
271
+ lessThan<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): Bool
272
+ lessThanEqual<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): Bool
273
+ greaterThan<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): Bool
274
+ greaterThanEqual<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): Bool
275
+ and(x: Bool): Bool
276
+ or(x: Bool): Bool
275
277
  not(): Bool
276
278
 
277
279
  // Bitwise operators
278
- bitAnd(x: X<T>): NodeProxy<T>
279
- bitOr(x: X<T>): NodeProxy<T>
280
- bitXor(x: X<T>): NodeProxy<T>
281
- bitNot(): NodeProxy<T>
282
- shiftLeft<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
283
- shiftRight<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
280
+ bitAnd(x: X<T>): X<T>
281
+ bitOr(x: X<T>): X<T>
282
+ bitXor(x: X<T>): X<T>
283
+ bitNot(): X<T>
284
+ shiftLeft<U extends C>(x: X<U>): X<InferOperator<T, U>>
285
+ shiftRight<U extends C>(x: X<U>): X<InferOperator<T, U>>
286
+
287
+ // Assignment operators
288
+ addAssign<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): X<T>
289
+ subAssign<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): X<T>
290
+ mulAssign<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): X<T>
291
+ divAssign<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): X<T>
292
+ modAssign<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): X<T>
293
+ bitAndAssign<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): X<T>
294
+ bitOrAssign<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): X<T>
295
+ bitXorAssign<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): X<T>
296
+ shiftLeftAssign<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): X<T>
297
+ shiftRightAssign<U extends C>(x: ValidateOperator<T, U> extends 0 ? never : number | X<U>): X<T>
284
298
 
285
299
  // Conversion methods
286
300
  toBool(): Bool
@@ -312,15 +326,26 @@ export interface BaseNodeProxy<T extends Constants> {
312
326
  // 0. Always return bool
313
327
  all(): Bool
314
328
  any(): Bool
315
- // 2. Always return float
316
- determinant(): Float
317
- distance<U extends Constants>(y: X<U>): Float
318
- dot<U extends Constants>(y: X<U>): Float
319
- length(): Float
329
+
330
+ // 2. WGSL-compliant return types with individual function constraints
331
+ determinant(): T extends 'mat2' | 'mat3' | 'mat4' ? Float : never
332
+ distance<U extends C>(
333
+ y: T extends 'vec2' | 'vec3' | 'vec4' ? (U extends T ? number | X<U> : never) : never
334
+ ): Float
335
+ dot<U extends C>(
336
+ y: T extends 'vec2' | 'vec3' | 'vec4' | 'ivec2' | 'ivec3' | 'ivec4'
337
+ ? U extends T
338
+ ? number | X<U>
339
+ : never
340
+ : never
341
+ ): T extends `ivec${string}` ? Int : Float
342
+ length(): T extends 'vec2' | 'vec3' | 'vec4' ? Float : never
320
343
  lengthSq(): Float
321
344
  luminance(): Float
322
- // 3. Always return vec3
323
- cross<U extends Constants>(y: X<U>): Vec3
345
+
346
+ // 3. Always return vec3 with vector constraint
347
+ cross<U extends C = 'vec3'>(y: T extends 'vec3' ? (U extends 'vec3' ? number | X<U> : never) : never): Vec3
348
+
324
349
  // 4. Always return vec4
325
350
  cubeTexture(...args: X[]): Vec4
326
351
  texture(...args: X[]): Vec4
@@ -328,59 +353,64 @@ export interface BaseNodeProxy<T extends Constants> {
328
353
  textureLod(...args: X[]): Vec4
329
354
 
330
355
  /**
331
- * 3.1. unified with:
332
- * 1.1. index.ts functions and
333
- * 2.1. const.ts FUNCTIONS
356
+ * 3.2. unified with:
357
+ * 1.2. index.ts functions and
358
+ * 2.2. const.ts FUNCTIONS
334
359
  */
335
- // 0. Component-wise functions
336
- abs(): NodeProxy<T>
337
- acos(): NodeProxy<T>
338
- acosh(): NodeProxy<T>
339
- asin(): NodeProxy<T>
340
- asinh(): NodeProxy<T>
341
- atan(): NodeProxy<T>
342
- atanh(): NodeProxy<T>
343
- ceil(): NodeProxy<T>
344
- cos(): NodeProxy<T>
345
- cosh(): NodeProxy<T>
346
- degrees(): NodeProxy<T>
347
- dFdx(): NodeProxy<T>
348
- dFdy(): NodeProxy<T>
349
- exp(): NodeProxy<T>
350
- exp2(): NodeProxy<T>
351
- floor(): NodeProxy<T>
352
- fract(): NodeProxy<T>
353
- fwidth(): NodeProxy<T>
354
- inverseSqrt(): NodeProxy<T>
355
- log(): NodeProxy<T>
356
- log2(): NodeProxy<T>
357
- negate(): NodeProxy<T>
358
- normalize(): NodeProxy<T>
359
- oneMinus(): NodeProxy<T>
360
- radians(): NodeProxy<T>
361
- reciprocal(): NodeProxy<T>
362
- round(): NodeProxy<T>
363
- saturate(): NodeProxy<T>
364
- sign(): NodeProxy<T>
365
- sin(): NodeProxy<T>
366
- sinh(): NodeProxy<T>
367
- sqrt(): NodeProxy<T>
368
- tan(): NodeProxy<T>
369
- tanh(): NodeProxy<T>
370
- trunc(): NodeProxy<T>
371
-
372
- // 1. Functions where first argument determines return type
373
- atan2<U extends Constants>(x: X<U>): NodeProxy<T>
374
- clamp<U extends Constants, V>(mix: X<U>, max: V): NodeProxy<InferOperator<T, U>>
375
- max<U extends Constants>(y: X<U>): NodeProxy<InferOperator<T, U>>
376
- min<U extends Constants>(y: X<U>): NodeProxy<InferOperator<T, U>>
377
- mix<U extends Constants, V>(y: X<U>, a: V): NodeProxy<InferOperator<T, U>>
378
- pow<U extends Constants>(y: X<U>): NodeProxy<T>
379
- reflect<U extends Constants>(N: X<U>): NodeProxy<T>
380
- refract<U extends Constants>(N: X<U>, eta: any): NodeProxy<T>
381
-
382
- // 2. Functions where not first argument determines return type
383
- smoothstep<U extends Constants, V>(edge0: X<U>, edge1: V): NodeProxy<InferOperator<T, U>>
384
- step<U extends Constants>(edge: X<U>): NodeProxy<InferOperator<T, U>>
360
+ // 0. Component-wise functions with type validation
361
+ abs(): X<T>
362
+ acos(): X<T>
363
+ acosh(): X<T>
364
+ asin(): X<T>
365
+ asinh(): X<T>
366
+ atan(): X<T>
367
+ atanh(): X<T>
368
+ ceil(): X<T>
369
+ cos(): X<T>
370
+ cosh(): X<T>
371
+ degrees(): X<T>
372
+ dFdx(): X<T>
373
+ dFdy(): X<T>
374
+ exp(): X<T>
375
+ exp2(): X<T>
376
+ floor(): X<T>
377
+ fract(): X<T>
378
+ fwidth(): X<T>
379
+ inverseSqrt(): X<T>
380
+ log(): X<T>
381
+ log2(): X<T>
382
+ negate(): X<T>
383
+ normalize(): T extends 'vec2' | 'vec3' | 'vec4' ? X<T> : never
384
+ oneMinus(): X<T>
385
+ radians(): X<T>
386
+ reciprocal(): X<T>
387
+ round(): X<T>
388
+ saturate(): X<T>
389
+ sign(): X<T>
390
+ sin(): X<T>
391
+ sinh(): X<T>
392
+ sqrt(): X<T>
393
+ tan(): X<T>
394
+ tanh(): X<T>
395
+ trunc(): X<T>
396
+
397
+ // 1. Functions where first argument determines return type with unified parameter types
398
+ atan2<U extends C>(x: number | X<U>): X<T>
399
+ clamp<U extends C>(min: number | X<U>, max: number | X<U>): X<InferOperator<T, U>>
400
+ max<U extends C>(y: number | X<U>): X<InferOperator<T, U>>
401
+ min<U extends C>(y: number | X<U>): X<InferOperator<T, U>>
402
+ mix<U extends C>(y: number | X<U>, a: number | Float | X<U>): X<InferOperator<T, U>>
403
+ pow<U extends C>(y: number | X<U>): X<T>
404
+ reflect<U extends C>(
405
+ N: T extends 'vec2' | 'vec3' | 'vec4' ? (U extends T ? number | X<U> : never) : never
406
+ ): X<T>
407
+ refract<U extends C>(
408
+ N: T extends 'vec2' | 'vec3' | 'vec4' ? (U extends T ? number | X<U> : never) : never,
409
+ eta: number | Float
410
+ ): T extends 'vec2' | 'vec3' | 'vec4' ? X<T> : never
411
+
412
+ // 2. Functions where not first argument determines return type with unified parameter types
413
+ smoothstep<U extends C>(edge0: number | X<U>, edge1: number | X<U>): X<InferOperator<T, U>>
414
+ step<U extends C>(edge: number | X<U>): X<InferOperator<T, U>>
385
415
  // @NOTE: mod is operator
386
416
  }
@@ -73,6 +73,16 @@ export const OPERATORS = {
73
73
  bitXor: '^',
74
74
  shiftLeft: '<<',
75
75
  shiftRight: '>>',
76
+ addAssign: '+=',
77
+ subAssign: '-=',
78
+ mulAssign: '*=',
79
+ divAssign: '/=',
80
+ modAssign: '%=',
81
+ bitAndAssign: '&=',
82
+ bitOrAssign: '|=',
83
+ bitXorAssign: '^=',
84
+ shiftLeftAssign: '<<=',
85
+ shiftRightAssign: '>>=',
76
86
  } as const
77
87
 
78
88
  export const OPERATOR_KEYS = Object.keys(OPERATORS) as (keyof typeof OPERATORS)[]
@@ -135,6 +145,28 @@ export const COMPARISON_OPERATORS = [
135
145
 
136
146
  export const LOGICAL_OPERATORS = ['and', 'or'] as const
137
147
 
148
+ // Operator type rules [L, R, Result] format (no duplicates, same-type handled by logic)
149
+ export const OPERATOR_TYPE_RULES = [
150
+ // Scalar broadcast operations (result follows vector type)
151
+ ['float', 'vec2', 'vec2'],
152
+ ['float', 'vec3', 'vec3'],
153
+ ['float', 'vec4', 'vec4'],
154
+ ['int', 'ivec2', 'ivec2'],
155
+ ['int', 'ivec3', 'ivec3'],
156
+ ['int', 'ivec4', 'ivec4'],
157
+ ['uint', 'uvec2', 'uvec2'],
158
+ ['uint', 'uvec3', 'uvec3'],
159
+ ['uint', 'uvec4', 'uvec4'],
160
+ // Matrix-vector operations (mat * vec → vec)
161
+ ['mat2', 'vec2', 'vec2'],
162
+ ['mat3', 'vec3', 'vec3'],
163
+ ['mat4', 'vec4', 'vec4'],
164
+ // Vector-matrix operations (vec * mat → vec)
165
+ ['vec2', 'mat2', 'vec2'],
166
+ ['vec3', 'mat3', 'vec3'],
167
+ ['vec4', 'mat4', 'vec4'],
168
+ ] as const
169
+
138
170
  export const WGSL_TO_GLSL_BUILTIN = {
139
171
  position: 'gl_FragCoord',
140
172
  vertex_index: 'gl_VertexID',
@@ -150,7 +182,7 @@ export const WGSL_TO_GLSL_BUILTIN = {
150
182
  /**
151
183
  * 2.1. unified with:
152
184
  * 1.1. index.ts functions and
153
- * 3.1. types.ts BaseNodeProxy
185
+ * 3.1. types.ts _N
154
186
  */
155
187
  // Function return type mapping for method chaining
156
188
  export const FUNCTION_RETURN_TYPES = {
@@ -176,7 +208,7 @@ export const FUNCTION_RETURN_TYPES = {
176
208
  /**
177
209
  * 2.2. unified with:
178
210
  * 1.2. index.ts functions and
179
- * 3.2. types.ts BaseNodeProxy
211
+ * 3.2. types.ts _N
180
212
  */
181
213
  // All shader functions (type inference now handled by inferFrom)
182
214
  export const FUNCTIONS = [
@@ -231,3 +263,31 @@ export const FUNCTIONS = [
231
263
  'step',
232
264
  // @NOTE: mod is operator
233
265
  ] as const
266
+
267
+ // Check if two types are the same (for same-type operations)
268
+ const isSameType = (L: string, R: string): boolean => L === R
269
+
270
+ // Check if combination exists in rules (handles bidirectional matching)
271
+ const isValidCombination = (L: string, R: string): boolean => {
272
+ return OPERATOR_TYPE_RULES.some(
273
+ ([left, right, _]) => (left === L && right === R) || (left === R && right === L)
274
+ )
275
+ }
276
+
277
+ // Type constraint validation for operators ([L, R, Result] format)
278
+ export const validateOperatorTypes = (L: string, R: string, op: string): boolean => {
279
+ if (COMPARISON_OPERATORS.includes(op as any) || LOGICAL_OPERATORS.includes(op as any)) return isSameType(L, R)
280
+ if (isSameType(L, R)) return true
281
+ return isValidCombination(L, R)
282
+ }
283
+
284
+ // Get result type for operator (used by inferOperator)
285
+ export const getOperatorResultType = (L: string, R: string, op: string): string => {
286
+ if (COMPARISON_OPERATORS.includes(op as any) || LOGICAL_OPERATORS.includes(op as any)) return 'bool'
287
+ // Same type operations return the same type
288
+ if (isSameType(L, R)) return L
289
+ const rule = OPERATOR_TYPE_RULES.find(
290
+ ([left, right, _]) => (left === L && right === R) || (left === R && right === L)
291
+ )
292
+ return rule ? rule[2] : L
293
+ }
@@ -16,13 +16,13 @@ import {
16
16
  parseUniformHead,
17
17
  parseVaryingHead,
18
18
  } from './parse'
19
- import { getBluiltin, getOperator, getConversions, safeEventCall, getEventFun, initNodeContext } from './utils'
19
+ import { getBluiltin, getConversions, getEventFun, getOperator, initNodeContext, safeEventCall } from './utils'
20
20
  import { is } from '../../utils/helpers'
21
- import type { Constants, NodeContext, X } from '../types'
21
+ import type { Constants as C, NodeContext, Y } from '../types'
22
22
 
23
23
  export * from './utils'
24
24
 
25
- export const code = <T extends Constants>(target: X<T>, c?: NodeContext | null): string => {
25
+ export const code = <T extends C>(target: Y<T>, c?: NodeContext | null): string => {
26
26
  if (!c) c = {}
27
27
  initNodeContext(c)
28
28
  if (is.arr(target)) return parseArray(target, c)
@@ -62,6 +62,7 @@ export const code = <T extends Constants>(target: X<T>, c?: NodeContext | null):
62
62
  if (type === 'conversion') return `${getConversions(x, c)}(${parseArray(children.slice(1), c)})`
63
63
  if (type === 'operator') {
64
64
  if (x === 'not' || x === 'bitNot') return `!${code(y, c)}`
65
+ if (x.endsWith('Assign')) return `${code(y, c)} ${getOperator(x)} ${code(z, c)};`
65
66
  return `(${code(y, c)} ${getOperator(x)} ${code(z, c)})`
66
67
  }
67
68
  if (type === 'function') {
@@ -77,6 +78,8 @@ export const code = <T extends Constants>(target: X<T>, c?: NodeContext | null):
77
78
  if (type === 'scope') return children.map((child: any) => code(child, c)).join('\n')
78
79
  if (type === 'assign') return `${code(x, c)} = ${code(y, c)};`
79
80
  if (type === 'return') return `return ${code(x, c)};`
81
+ if (type === 'break') return 'break;'
82
+ if (type === 'continue') return 'continue;'
80
83
  if (type === 'loop')
81
84
  return c.isWebGL
82
85
  ? `for (int ${id} = 0; ${id} < ${code(x, c)}; ${id} += 1) {\n${code(y, c)}\n}`