glre 0.37.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 +31 -40
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.ts +170 -1791
  9. package/dist/index.js +31 -40
  10. package/dist/index.js.map +1 -1
  11. package/dist/native.cjs +1 -45
  12. package/dist/native.cjs.map +1 -1
  13. package/dist/native.d.ts +511 -11
  14. package/dist/native.js +1 -45
  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 -45
  22. package/dist/react.cjs.map +1 -1
  23. package/dist/react.d.ts +506 -4
  24. package/dist/react.js +1 -45
  25. package/dist/react.js.map +1 -1
  26. package/dist/solid.cjs +1 -45
  27. package/dist/solid.cjs.map +1 -1
  28. package/dist/solid.d.ts +506 -4
  29. package/dist/solid.js +1 -45
  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 +65 -50
  38. package/src/node/types.ts +222 -164
  39. package/src/node/utils/const.ts +64 -3
  40. package/src/node/utils/index.ts +8 -5
  41. package/src/node/utils/infer.ts +23 -35
  42. package/src/node/utils/parse.ts +15 -18
  43. package/src/node/utils/utils.ts +13 -12
  44. package/src/types.ts +5 -7
  45. package/src/utils/pipeline.ts +3 -3
  46. package/src/utils/program.ts +7 -2
  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 -64
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'
@@ -6,17 +6,31 @@ export type Conversions = (typeof CONVERSIONS)[number]
6
6
  export type Functions = (typeof FUNCTIONS)[number]
7
7
  export type Operators = (typeof OPERATOR_KEYS)[number]
8
8
 
9
+ /**
10
+ * scope
11
+ */
9
12
  export interface FnLayout {
10
13
  name: string
11
- type: Constants | 'auto'
14
+ type: C | 'auto'
12
15
  inputs?: Array<{
13
16
  name: string
14
- type: Constants
17
+ type: C
15
18
  }>
16
19
  }
17
20
 
21
+ export interface FnType<T extends X | Struct | void, Args extends any[]> {
22
+ (...args: Args): T extends void ? Void : T
23
+ setLayout(layout: FnLayout): FnType<T, Args>
24
+ }
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
+
18
32
  /**
19
- * Node
33
+ * node
20
34
  */
21
35
  export type NodeTypes =
22
36
  // headers
@@ -47,8 +61,10 @@ export type NodeTypes =
47
61
  | 'switch'
48
62
  | 'declare'
49
63
  | 'return'
64
+ | 'break'
65
+ | 'continue'
50
66
 
51
- export interface NodeProps<T extends Record<string, NodeProxy> = {}> {
67
+ export interface NodeProps {
52
68
  id?: string
53
69
  args?: any[]
54
70
  type?: string
@@ -56,8 +72,8 @@ export interface NodeProps<T extends Record<string, NodeProxy> = {}> {
56
72
  inferFrom?: any[]
57
73
  layout?: FnLayout
58
74
  // for struct
59
- fields?: T
60
- initialValues?: T
75
+ fields?: StructFields
76
+ initialValues?: StructFields
61
77
  }
62
78
 
63
79
  export interface NodeContext {
@@ -65,7 +81,7 @@ export interface NodeContext {
65
81
  label?: 'vert' | 'frag' | 'compute'
66
82
  isWebGL?: boolean
67
83
  units?: any // @TODO FIX
68
- infers?: WeakMap<NodeProxy, Constants>
84
+ infers?: WeakMap<X, C>
69
85
  onMount?: (name: string) => void
70
86
  code?: {
71
87
  headers: Map<string, string>
@@ -75,29 +91,24 @@ export interface NodeContext {
75
91
  vertVaryings: Map<string, string>
76
92
  computeInputs: Map<string, string>
77
93
  dependencies: Map<string, Set<string>>
94
+ structStructFields: Map<string, StructFields>
78
95
  }
79
96
  }
80
97
 
81
98
  /**
82
99
  * infer
83
100
  */
84
- type _StringLength<S extends string> = S extends `${infer _}${infer Rest}`
85
- ? Rest extends ''
86
- ? 1
87
- : Rest extends `${infer _}${infer Rest2}`
88
- ? Rest2 extends ''
89
- ? 2
90
- : Rest2 extends `${infer _}${infer Rest3}`
91
- ? Rest3 extends ''
92
- ? 3
93
- : 4
94
- : never
95
- : never
96
- : 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
97
108
 
98
109
  // Unified logic with infer.ts inferOperator function
99
110
  // prettier-ignore
100
- type InferOperator<L extends Constants, R extends Constants> =
111
+ type InferOperator<L extends C, R extends C> =
101
112
  L extends R ? L :
102
113
  // broadcast
103
114
  L extends 'float' | 'int' ? R :
@@ -113,19 +124,23 @@ type InferOperator<L extends Constants, R extends Constants> =
113
124
 
114
125
  // Unified logic with infer.ts inferArrayElement function
115
126
  // prettier-ignore
116
- type InferArrayElement<T extends Constants> =
127
+ type InferArrayElement<T extends C> =
117
128
  T extends 'mat4' ? 'vec4' :
118
129
  T extends 'mat3' ? 'vec3' :
119
130
  T extends 'mat2' ? 'vec2' :
120
131
  'float'
121
132
 
122
- type InferSwizzleType<S extends string> = _StringLength<S> extends 4
123
- ? 'vec4'
124
- : _StringLength<S> extends 3
125
- ? 'vec3'
126
- : _StringLength<S> extends 2
127
- ? 'vec2'
128
- : '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'
129
144
 
130
145
  /**
131
146
  * Swizzles
@@ -138,54 +153,38 @@ export type Swizzles =
138
153
  | _Swizzles<'p' | 'q'>
139
154
  | _Swizzles<'s' | 't'>
140
155
 
141
- type NodeProxyMethods =
142
- | Functions
143
- | Operators
144
- | Conversions
145
- | Swizzles
146
- // system property
147
- | 'type'
148
- | 'props'
149
- | 'isProxy'
150
- | 'assign'
151
- | 'toVar'
152
- | 'toString'
153
- | 'element'
154
-
155
- type ReadNodeProxy = {
156
- [K in string as K extends NodeProxyMethods ? never : K]: any
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
157
182
  } & {
158
- [K in Swizzles]: NodeProxy<InferSwizzleType<K>>
183
+ toVar(id?: string): Struct<T>
159
184
  }
160
185
 
161
- // Internal NodeProxy implementation (renamed from original)
162
- type NodeProxyImpl<T extends Constants = string> = BaseNodeProxy<T> & ReadNodeProxy
163
-
164
- export type Bool = NodeProxyImpl<'bool'>
165
- export type UInt = NodeProxyImpl<'uint'>
166
- export type Int = NodeProxyImpl<'int'>
167
- export type Float = NodeProxyImpl<'float'>
168
- export type BVec2 = NodeProxyImpl<'bvec2'>
169
- export type IVec2 = NodeProxyImpl<'ivec2'>
170
- export type UVec2 = NodeProxyImpl<'uvec2'>
171
- export type Vec2 = NodeProxyImpl<'vec2'>
172
- export type BVec3 = NodeProxyImpl<'bvec3'>
173
- export type IVec3 = NodeProxyImpl<'ivec3'>
174
- export type UVec3 = NodeProxyImpl<'uvec3'>
175
- export type Vec3 = NodeProxyImpl<'vec3'>
176
- export type BVec4 = NodeProxyImpl<'bvec4'>
177
- export type IVec4 = NodeProxyImpl<'ivec4'>
178
- export type UVec4 = NodeProxyImpl<'uvec4'>
179
- export type Vec4 = NodeProxyImpl<'vec4'>
180
- export type Color = NodeProxyImpl<'color'>
181
- export type Mat2 = NodeProxyImpl<'mat2'>
182
- export type Mat3 = NodeProxyImpl<'mat3'>
183
- export type Mat4 = NodeProxyImpl<'mat4'>
184
- export type Texture = NodeProxyImpl<'texture'>
185
- export type Sampler2D = NodeProxyImpl<'sampler2D'>
186
- export type Struct = NodeProxyImpl<'struct'>
187
-
188
186
  export interface ConstantsToType {
187
+ void: Void
189
188
  bool: Bool
190
189
  uint: UInt
191
190
  int: Int
@@ -208,51 +207,94 @@ export interface ConstantsToType {
208
207
  mat4: Mat4
209
208
  texture: Texture
210
209
  sampler2D: Sampler2D
211
- struct: Struct
210
+ struct: StructBase
211
+ }
212
+
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>>
212
220
  }
213
221
 
214
- export type NodeProxy<T extends Constants = string> = T extends keyof ConstantsToType
215
- ? ConstantsToType[T]
216
- : NodeProxyImpl<T>
222
+ type C = Constants
217
223
 
218
- export type X<T extends Constants = string> = number | string | boolean | undefined | NodeProxy<T> | X[]
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>
219
226
 
220
- export interface BaseNodeProxy<T extends Constants> {
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
+
242
+ interface _X<T extends C> {
221
243
  // System properties
222
- assign(x: any): NodeProxy<T>
223
- toVar(name?: string): NodeProxy<T>
244
+ readonly __nodeType?: T
245
+ assign(x: any): X<T>
246
+ fragment(c: NodeContext): string
247
+ toVar(name?: string): X<T>
224
248
  toString(c?: NodeContext): string
249
+ fragment(c?: NodeContext): string
250
+ compute(c?: NodeContext): string
251
+ vertex(c?: NodeContext): string
225
252
  type: NodeTypes
226
253
  props: NodeProps
227
254
  isProxy: true
228
255
  listeners: Set<(value: any) => void>
229
256
 
230
257
  // Element access for array/matrix types
231
- element<Index extends X>(index: Index): NodeProxy<InferArrayElement<T>>
232
-
233
- // Operators methods
234
- add<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
235
- sub<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
236
- mul<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
237
- div<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
238
- mod<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
239
- equal<U extends Constants>(x: X<U>): Bool
240
- notEqual<U extends Constants>(x: X<U>): Bool
241
- lessThan<U extends Constants>(x: X<U>): Bool
242
- lessThanEqual<U extends Constants>(x: X<U>): Bool
243
- greaterThan<U extends Constants>(x: X<U>): Bool
244
- greaterThanEqual<U extends Constants>(x: X<U>): Bool
245
- and(x: X<'bool'>): Bool
246
- or(x: X<'bool'>): Bool
258
+ element<Index extends X>(index: Index): X<InferArrayElement<T>>
259
+
260
+ // Enhanced member access with type preservation
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
247
277
  not(): Bool
248
278
 
249
279
  // Bitwise operators
250
- bitAnd(x: X<T>): NodeProxy<T>
251
- bitOr(x: X<T>): NodeProxy<T>
252
- bitXor(x: X<T>): NodeProxy<T>
253
- bitNot(): NodeProxy<T>
254
- shiftLeft<U extends Constants>(x: X<U>): NodeProxy<InferOperator<T, U>>
255
- 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>
256
298
 
257
299
  // Conversion methods
258
300
  toBool(): Bool
@@ -284,15 +326,26 @@ export interface BaseNodeProxy<T extends Constants> {
284
326
  // 0. Always return bool
285
327
  all(): Bool
286
328
  any(): Bool
287
- // 2. Always return float
288
- determinant(): Float
289
- distance<U extends Constants>(y: X<U>): Float
290
- dot<U extends Constants>(y: X<U>): Float
291
- 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
292
343
  lengthSq(): Float
293
344
  luminance(): Float
294
- // 3. Always return vec3
295
- 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
+
296
349
  // 4. Always return vec4
297
350
  cubeTexture(...args: X[]): Vec4
298
351
  texture(...args: X[]): Vec4
@@ -300,59 +353,64 @@ export interface BaseNodeProxy<T extends Constants> {
300
353
  textureLod(...args: X[]): Vec4
301
354
 
302
355
  /**
303
- * 3.1. unified with:
304
- * 1.1. index.ts functions and
305
- * 2.1. const.ts FUNCTIONS
356
+ * 3.2. unified with:
357
+ * 1.2. index.ts functions and
358
+ * 2.2. const.ts FUNCTIONS
306
359
  */
307
- // 0. Component-wise functions
308
- abs(): NodeProxy
309
- acos(): NodeProxy
310
- acosh(): NodeProxy
311
- asin(): NodeProxy
312
- asinh(): NodeProxy
313
- atan(): NodeProxy
314
- atanh(): NodeProxy
315
- ceil(): NodeProxy
316
- cos(): NodeProxy
317
- cosh(): NodeProxy
318
- degrees(): NodeProxy
319
- dFdx(): NodeProxy
320
- dFdy(): NodeProxy
321
- exp(): NodeProxy
322
- exp2(): NodeProxy
323
- floor(): NodeProxy
324
- fract(): NodeProxy
325
- fwidth(): NodeProxy
326
- inverseSqrt(): NodeProxy
327
- log(): NodeProxy
328
- log2(): NodeProxy
329
- negate(): NodeProxy
330
- normalize(): NodeProxy
331
- oneMinus(): NodeProxy
332
- radians(): NodeProxy
333
- reciprocal(): NodeProxy
334
- round(): NodeProxy
335
- saturate(): NodeProxy
336
- sign(): NodeProxy
337
- sin(): NodeProxy
338
- sinh(): NodeProxy
339
- sqrt(): NodeProxy
340
- tan(): NodeProxy
341
- tanh(): NodeProxy
342
- trunc(): NodeProxy
343
-
344
- // 1. Functions where first argument determines return type
345
- atan2<U extends Constants>(x: X<U>): NodeProxy<T>
346
- clamp<U extends Constants, V>(mix: X<U>, max: V): NodeProxy<InferOperator<T, U>>
347
- max<U extends Constants>(y: X<U>): NodeProxy<InferOperator<T, U>>
348
- min<U extends Constants>(y: X<U>): NodeProxy<InferOperator<T, U>>
349
- mix<U extends Constants, V>(y: X<U>, a: V): NodeProxy<InferOperator<T, U>>
350
- pow<U extends Constants>(y: X<U>): NodeProxy<T>
351
- reflect<U extends Constants>(N: X<U>): NodeProxy<T>
352
- refract<U extends Constants>(N: X<U>, eta: any): NodeProxy<T>
353
-
354
- // 2. Functions where not first argument determines return type
355
- smoothstep<U extends Constants, V>(edge0: X<U>, edge1: V): NodeProxy<InferOperator<T, U>>
356
- 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>>
357
415
  // @NOTE: mod is operator
358
416
  }
@@ -51,9 +51,10 @@ export const TYPE_MAPPING = {
51
51
  struct: 'struct',
52
52
  } as const
53
53
 
54
- export const CONSTANTS = Object.keys(TYPE_MAPPING) as unknown as keyof typeof TYPE_MAPPING
54
+ export const CONSTANTS = Object.keys(TYPE_MAPPING) as (keyof typeof TYPE_MAPPING)[]
55
55
 
56
56
  export const OPERATORS = {
57
+ not: '', // IGNORED
57
58
  add: '+',
58
59
  sub: '-',
59
60
  mul: '*',
@@ -72,6 +73,16 @@ export const OPERATORS = {
72
73
  bitXor: '^',
73
74
  shiftLeft: '<<',
74
75
  shiftRight: '>>',
76
+ addAssign: '+=',
77
+ subAssign: '-=',
78
+ mulAssign: '*=',
79
+ divAssign: '/=',
80
+ modAssign: '%=',
81
+ bitAndAssign: '&=',
82
+ bitOrAssign: '|=',
83
+ bitXorAssign: '^=',
84
+ shiftLeftAssign: '<<=',
85
+ shiftRightAssign: '>>=',
75
86
  } as const
76
87
 
77
88
  export const OPERATOR_KEYS = Object.keys(OPERATORS) as (keyof typeof OPERATORS)[]
@@ -134,6 +145,28 @@ export const COMPARISON_OPERATORS = [
134
145
 
135
146
  export const LOGICAL_OPERATORS = ['and', 'or'] as const
136
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
+
137
170
  export const WGSL_TO_GLSL_BUILTIN = {
138
171
  position: 'gl_FragCoord',
139
172
  vertex_index: 'gl_VertexID',
@@ -149,7 +182,7 @@ export const WGSL_TO_GLSL_BUILTIN = {
149
182
  /**
150
183
  * 2.1. unified with:
151
184
  * 1.1. index.ts functions and
152
- * 3.1. types.ts BaseNodeProxy
185
+ * 3.1. types.ts _N
153
186
  */
154
187
  // Function return type mapping for method chaining
155
188
  export const FUNCTION_RETURN_TYPES = {
@@ -175,7 +208,7 @@ export const FUNCTION_RETURN_TYPES = {
175
208
  /**
176
209
  * 2.2. unified with:
177
210
  * 1.2. index.ts functions and
178
- * 3.2. types.ts BaseNodeProxy
211
+ * 3.2. types.ts _N
179
212
  */
180
213
  // All shader functions (type inference now handled by inferFrom)
181
214
  export const FUNCTIONS = [
@@ -230,3 +263,31 @@ export const FUNCTIONS = [
230
263
  'step',
231
264
  // @NOTE: mod is operator
232
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}`
@@ -85,12 +88,12 @@ export const code = <T extends Constants>(target: X<T>, c?: NodeContext | null):
85
88
  if (type === 'switch') return parseSwitch(c, x, children)
86
89
  if (type === 'declare') return parseDeclare(c, x, y)
87
90
  if (type === 'define') {
88
- if (!c.code?.headers.has(id)) c.code?.headers.set(id, parseDefine(c, props, infer(target, c)))
91
+ if (!c.code?.headers.has(id)) c.code?.headers.set(id, parseDefine(c, props, target))
89
92
  return `${id}(${parseArray(children.slice(1), c)})`
90
93
  }
91
94
  if (type === 'struct') {
92
95
  if (!c.code?.headers.has(id)) c.code?.headers.set(id, parseStructHead(c, id, fields))
93
- return parseStruct(c, id, x.props.id, fields, initialValues)
96
+ return parseStruct(c, id, x.props.id, initialValues)
94
97
  }
95
98
  /**
96
99
  * headers