glre 0.36.0 → 0.38.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glre",
3
- "version": "0.36.0",
3
+ "version": "0.38.0",
4
4
  "author": "tseijp",
5
5
  "license": "MIT",
6
6
  "private": false,
package/src/index.ts CHANGED
@@ -51,6 +51,7 @@ export const createGL = (props?: Partial<GL>) => {
51
51
  size: [0, 0],
52
52
  mouse: [0, 0],
53
53
  count: 6,
54
+ particles: 1024,
54
55
  webgl: {},
55
56
  webgpu: {},
56
57
  loading: 0,
@@ -58,6 +59,7 @@ export const createGL = (props?: Partial<GL>) => {
58
59
  gl.isError = true
59
60
  gl.isLoop = false
60
61
  gl.clean()
62
+ console.warn('GLRE Error:', ...arguments)
61
63
  },
62
64
  }) as EventState<GL>
63
65
 
package/src/node/core.ts CHANGED
@@ -43,7 +43,7 @@ const generateStruct = (id: string, map: Map<string, string>) => {
43
43
  export const fragment = (x: X, c: NodeContext) => {
44
44
  if (is.str(x)) return x.trim()
45
45
  c.code?.headers?.clear()
46
- c.isFrag = true // for varying inputs or outputs
46
+ c.label = 'frag' // for varying inputs or outputs
47
47
  const [head, body] = generateHead(x, c)
48
48
  const ret = []
49
49
  if (c.isWebGL) {
@@ -66,7 +66,7 @@ export const fragment = (x: X, c: NodeContext) => {
66
66
  export const vertex = (x: X, c: NodeContext) => {
67
67
  if (is.str(x)) return x.trim()
68
68
  c.code?.headers?.clear()
69
- c.isFrag = false // for varying inputs or outputs
69
+ c.label = 'vert' // for varying inputs or outputs
70
70
  const [head, body] = generateHead(x, c)
71
71
  const ret = []
72
72
  if (c.isWebGL) {
@@ -94,7 +94,28 @@ export const vertex = (x: X, c: NodeContext) => {
94
94
  return main
95
95
  }
96
96
 
97
- export const compute = (x: X, _c: NodeContext) => {
97
+ export const compute = (x: X, c: NodeContext) => {
98
98
  if (is.str(x)) return x.trim()
99
- return ''
99
+ c.code?.headers?.clear()
100
+ c.label = 'compute'
101
+ const [head, body] = generateHead(x, c)
102
+ const ret = []
103
+ if (c.isWebGL) {
104
+ ret.push('#version 300 es')
105
+ ret.push('precision mediump float;')
106
+ ret.push(head)
107
+ ret.push('void main() {')
108
+ ret.push(` ${body};`)
109
+ ret.push('}')
110
+ } else {
111
+ if (c.code?.computeInputs?.size) ret.push(generateStruct('In', c.code.computeInputs))
112
+ ret.push(head)
113
+ ret.push('@compute @workgroup_size(32)')
114
+ ret.push(`fn main(${c.code?.computeInputs?.size ? 'in: In' : ''}) {`)
115
+ ret.push(` ${body};`)
116
+ ret.push('}')
117
+ }
118
+ const main = ret.filter(Boolean).join('\n').trim()
119
+ // console.log(`↓↓↓generated↓↓↓\n${main}`)
120
+ return main
100
121
  }
package/src/node/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { hex2rgb } from './utils'
2
2
  import { builtin as b, conversion as c, function_ as f, uniform as u } from './node'
3
3
  import { is } from '../utils/helpers'
4
- import type { Constants as C, X, Vec2, Float, NodeProxy } from './types'
4
+ import type { Constants as C, X, NodeProxy } from './types'
5
5
  export * from './core'
6
6
  export * from './node'
7
7
  export * from './scope'
@@ -16,6 +16,7 @@ export const fragDepth = b<'float'>('frag_depth')
16
16
  export const sampleIndex = b<'uint'>('sample_index')
17
17
  export const sampleMask = b<'uint'>('sample_mask')
18
18
  export const pointCoord = b<'vec2'>('point_coord')
19
+ export const id = b<'vec3'>('global_invocation_id')
19
20
 
20
21
  // TSL Compatible Builtin Variables
21
22
  export const positionLocal = b<'vec3'>('position')
@@ -55,92 +56,88 @@ export const color = (r?: X, g?: X, b?: X) => {
55
56
  }
56
57
 
57
58
  // Default uniforms with proper typing
58
- export const iResolution: Vec2 = u(vec2(), 'iResolution')
59
- export const iMouse: Vec2 = u(vec2(), 'iMouse')
60
- export const iTime: Float = u(float(), 'iTime')
59
+ export const iResolution = u(vec2(), 'iResolution')
60
+ export const iMouse = u(vec2(), 'iMouse')
61
+ export const iTime = u(float(), 'iTime')
61
62
  export const uv = position.xy.div(iResolution)
62
63
 
63
- // Texture Functions - always return vec4
64
- export const texture = (x: X, y: X, z?: X) => f<'vec4'>('texture', x, y, z)
65
- export const cubeTexture = (x: X, y: X, z?: X) => f<'vec4'>('cubeTexture', x, y, z)
66
- export const textureSize = (x: X, y?: X) => f<'vec4'>('textureSize', x, y)
64
+ /**
65
+ * 1.1. unified with:
66
+ * 2.1. const.ts BUILTIN_VARIABLES and
67
+ * 3.1. types.ts BaseNodeProxy
68
+ */
69
+ // 0. Always return bool
70
+ export const all = <T extends C>(x: X<T>) => f<'bool'>('all', x)
71
+ export const any = <T extends C>(x: X<T>) => f<'bool'>('any', x)
67
72
 
68
- // Functions that always return float regardless of input
73
+ // 2. Always return float
69
74
  export const length = (x: X) => f<'float'>('length', x)
70
75
  export const lengthSq = (x: X) => f<'float'>('lengthSq', x)
71
76
  export const distance = (x: X, y: X) => f<'float'>('distance', x, y)
72
77
  export const dot = (x: X, y: X) => f<'float'>('dot', x, y)
73
78
 
74
- // Functions that always return bool
75
- export const all = <T extends C>(x: X<T>) => f<'bool'>('all', x)
76
- export const any = <T extends C>(x: X<T>) => f<'bool'>('any', x)
77
-
78
- // Functions that always return vec3 (cross product only works with vec3)
79
+ // 3. Always return vec3
79
80
  export const cross = (x: X<'vec3'>, y: X<'vec3'>) => f<'vec3'>('cross', x, y)
80
81
 
81
- // Component-wise functions - preserve input type (T -> T)
82
+ // 4. Always return vec4
83
+ export const cubeTexture = (x: X, y: X, z?: X) => f<'vec4'>('cubeTexture', x, y, z)
84
+ export const texture = (x: X, y: X, z?: X) => f<'vec4'>('texture', x, y, z)
85
+ export const texelFetch = (x: X, y: X, z?: X) => f<'vec4'>('texelFetch', x, y, z)
86
+ export const textureLod = (x: X, y: X, z?: X) => f<'vec4'>('textureLod', x, y, z)
87
+
88
+ /**
89
+ * 1.2. unified with:
90
+ * 2.2. const.ts FUNCTIONS and
91
+ * 3.2. types.ts BaseNodeProxy
92
+ */
93
+ // 0. Component-wise functions
82
94
  export const abs = <T extends C>(x: X<T>) => f<T>('abs', x)
83
- export const sign = <T extends C>(x: X<T>) => f<T>('sign', x)
84
- export const floor = <T extends C>(x: X<T>) => f<T>('floor', x)
85
- export const ceil = <T extends C>(x: X<T>) => f<T>('ceil', x)
86
- export const round = <T extends C>(x: X<T>) => f<T>('round', x)
87
- export const fract = <T extends C>(x: X<T>) => f<T>('fract', x)
88
- export const trunc = <T extends C>(x: X<T>) => f<T>('trunc', x)
89
- export const sin = <T extends C>(x: X<T>) => f<T>('sin', x)
90
- export const cos = <T extends C>(x: X<T>) => f<T>('cos', x)
91
- export const tan = <T extends C>(x: X<T>) => f<T>('tan', x)
92
- export const asin = <T extends C>(x: X<T>) => f<T>('asin', x)
93
95
  export const acos = <T extends C>(x: X<T>) => f<T>('acos', x)
94
- export const atan = <T extends C>(x: X<T>) => f<T>('atan', x)
95
- export const sinh = <T extends C>(x: X<T>) => f<T>('sinh', x)
96
- export const cosh = <T extends C>(x: X<T>) => f<T>('cosh', x)
97
- export const tanh = <T extends C>(x: X<T>) => f<T>('tanh', x)
98
- export const asinh = <T extends C>(x: X<T>) => f<T>('asinh', x)
99
96
  export const acosh = <T extends C>(x: X<T>) => f<T>('acosh', x)
97
+ export const asin = <T extends C>(x: X<T>) => f<T>('asin', x)
98
+ export const asinh = <T extends C>(x: X<T>) => f<T>('asinh', x)
99
+ export const atan = <T extends C>(x: X<T>) => f<T>('atan', x)
100
100
  export const atanh = <T extends C>(x: X<T>) => f<T>('atanh', x)
101
+ export const ceil = <T extends C>(x: X<T>) => f<T>('ceil', x)
102
+ export const cos = <T extends C>(x: X<T>) => f<T>('cos', x)
103
+ export const cosh = <T extends C>(x: X<T>) => f<T>('cosh', x)
104
+ export const dFdx = <T extends C>(x: X<T>) => f<T>('dFdx', x)
105
+ export const dFdy = <T extends C>(x: X<T>) => f<T>('dFdy', x)
106
+ export const degrees = <T extends C>(x: X<T>) => f<T>('degrees', x)
101
107
  export const exp = <T extends C>(x: X<T>) => f<T>('exp', x)
102
108
  export const exp2 = <T extends C>(x: X<T>) => f<T>('exp2', x)
109
+ export const floor = <T extends C>(x: X<T>) => f<T>('floor', x)
110
+ export const fract = <T extends C>(x: X<T>) => f<T>('fract', x)
111
+ export const fwidth = <T extends C>(x: X<T>) => f<T>('fwidth', x)
112
+ export const inverseSqrt = <T extends C>(x: X<T>) => f<T>('inverseSqrt', x)
103
113
  export const log = <T extends C>(x: X<T>) => f<T>('log', x)
104
114
  export const log2 = <T extends C>(x: X<T>) => f<T>('log2', x)
105
- export const sqrt = <T extends C>(x: X<T>) => f<T>('sqrt', x)
106
- export const inverseSqrt = <T extends C>(x: X<T>) => f<T>('inverseSqrt', x)
115
+ export const negate = <T extends C>(x: X<T>) => f<T>('negate', x)
107
116
  export const normalize = <T extends C>(x: X<T>) => f<T>('normalize', x)
108
117
  export const oneMinus = <T extends C>(x: X<T>) => f<T>('oneMinus', x)
109
- export const saturate = <T extends C>(x: X<T>) => f<T>('saturate', x)
110
- export const negate = <T extends C>(x: X<T>) => f<T>('negate', x)
111
- export const reciprocal = <T extends C>(x: X<T>) => f<T>('reciprocal', x)
112
- export const dFdx = <T extends C>(x: X<T>) => f<T>('dFdx', x)
113
- export const dFdy = <T extends C>(x: X<T>) => f<T>('dFdy', x)
114
- export const fwidth = <T extends C>(x: X<T>) => f<T>('fwidth', x)
115
- export const degrees = <T extends C>(x: X<T>) => f<T>('degrees', x)
116
118
  export const radians = <T extends C>(x: X<T>) => f<T>('radians', x)
119
+ export const reciprocal = <T extends C>(x: X<T>) => f<T>('reciprocal', x)
120
+ export const round = <T extends C>(x: X<T>) => f<T>('round', x)
121
+ export const saturate = <T extends C>(x: X<T>) => f<T>('saturate', x)
122
+ export const sign = <T extends C>(x: X<T>) => f<T>('sign', x)
123
+ export const sin = <T extends C>(x: X<T>) => f<T>('sin', x)
124
+ export const sinh = <T extends C>(x: X<T>) => f<T>('sinh', x)
125
+ export const sqrt = <T extends C>(x: X<T>) => f<T>('sqrt', x)
126
+ export const tan = <T extends C>(x: X<T>) => f<T>('tan', x)
127
+ export const tanh = <T extends C>(x: X<T>) => f<T>('tanh', x)
128
+ export const trunc = <T extends C>(x: X<T>) => f<T>('trunc', x)
117
129
 
118
- // Functions where first argument determines return type
119
- export const reflect = <T extends C>(I: X<T>, N: X) => f<T>('reflect', I, N)
120
- export const refract = <T extends C>(I: X<T>, N: X, eta: X) => f<T>('refract', I, N, eta)
121
-
122
- // Functions with highest priority type among arguments (using first arg for simplicity)
123
- export const min = <T extends C>(x: X<T>, y: X) => f<T>('min', x, y)
130
+ // 1. Functions where first argument determines return type
131
+ export const atan2 = <T extends C>(x: X<T>, y: X) => f<T>('atan2', x, y)
132
+ export const clamp = <T extends C>(x: X<T>, y: X, z: X) => f<T>('clamp', x, y, z)
124
133
  export const max = <T extends C>(x: X<T>, y: X) => f<T>('max', x, y)
134
+ export const min = <T extends C>(x: X<T>, y: X) => f<T>('min', x, y)
125
135
  export const mix = <T extends C>(x: X<T>, y: X, a: X) => f<T>('mix', x, y, a)
126
- export const clamp = <T extends C>(x: X<T>, minVal: X, maxVal: X) => f<T>('clamp', x, minVal, maxVal)
127
- export const step = <T extends C>(edge: X, x: X<T>) => f<T>('step', edge, x)
128
- export const smoothstep = <T extends C>(e0: X, e1: X, x: X<T>) => f<T>('smoothstep', e0, e1, x)
129
-
130
- // Two-argument functions with highest priority type
131
- export const atan2 = <T extends C>(x: X<T>, y: X) => f<T>('atan2', x, y)
132
136
  export const pow = <T extends C>(x: X<T>, y: X) => f<T>('pow', x, y)
137
+ export const reflect = <T extends C>(I: X<T>, N: X) => f<T>('reflect', I, N)
138
+ export const refract = <T extends C>(I: X<T>, N: X, eta: X) => f<T>('refract', I, N, eta)
133
139
 
134
- // Component-wise power functions
135
- export const pow2 = <T extends C>(x: X<T>) => f<T>('pow2', x)
136
- export const pow3 = <T extends C>(x: X<T>) => f<T>('pow3', x)
137
- export const pow4 = <T extends C>(x: X<T>) => f<T>('pow4', x)
138
-
139
- // Utility functions
140
- export const bitcast = <T extends C>(x: X<T>, y: X) => f<T>('bitcast', x, y)
141
- export const cbrt = <T extends C>(x: X<T>) => f<T>('cbrt', x)
142
- export const difference = <T extends C>(x: X<T>, y: X) => f<T>('difference', x, y)
143
- export const equals = (x: X, y: X) => f<'bool'>('equals', x, y)
144
- export const faceforward = <T extends C>(N: X<T>, I: X, Nref: X) => f<T>('faceforward', N, I, Nref)
145
- export const transformDirection = <T extends C>(dir: X<T>, matrix: X) => f<T>('transformDirection', dir, matrix)
146
- export const mod = <T extends C>(x: NodeProxy<T>, y: X<T>) => x.sub(x.div(y).floor().mul(y))
140
+ // 2. Functions where not first argument determines return type
141
+ export const smoothstep = <T extends C>(e0: X, e1: X, x: X<T>) => f<T>('smoothstep', e0, e1, x)
142
+ export const step = <T extends C>(edge: X, x: X<T>) => f<T>('step', edge, x)
143
+ export const mod = <T extends C>(x: NodeProxy<T>, y: X<T>) => x.sub(x.div(y).toFloat().floor().mul(y))
package/src/node/node.ts CHANGED
@@ -4,7 +4,7 @@ import { is } from '../utils/helpers'
4
4
  import type { Functions, NodeProps, NodeProxy, NodeTypes, Operators, X, Constants as C } from './types'
5
5
 
6
6
  const toPrimitive = (x: X, hint: string) => {
7
- if (hint === 'string') return code(x)
7
+ if (hint === 'string') return code(x, null)
8
8
  }
9
9
 
10
10
  export const node = <T extends C>(type: NodeTypes, props?: NodeProps | null, ...args: X[]) => {
@@ -14,8 +14,8 @@ export const node = <T extends C>(type: NodeTypes, props?: NodeProps | null, ...
14
14
  const get = (_: unknown, y: string | Symbol) => {
15
15
  if (y === 'type') return type
16
16
  if (y === 'props') return props
17
- if (y === 'toVar') return toVar.bind(null, x)
18
- if (y === 'assign') return assign.bind(null, x)
17
+ if (y === '__nodeType') return undefined // Will be inferred by TypeScript
18
+ if (y === 'toVar') return toVar.bind(null, x as any)
19
19
  if (y === 'isProxy') return true
20
20
  if (y === 'toString') return code.bind(null, x)
21
21
  if (y === Symbol.toPrimitive) return toPrimitive.bind(null, x)
@@ -26,8 +26,9 @@ export const node = <T extends C>(type: NodeTypes, props?: NodeProps | null, ...
26
26
  if (y === 'variable') return (id = getId()) => variable(id)
27
27
  if (y === 'builtin') return (id = getId()) => builtin(id)
28
28
  if (y === 'vertexStage') return (id = getId()) => vertexStage(x, id)
29
- if (y === 'element') return (z: X) => element(x, z)
29
+ if (y === 'element') return (z: X) => (type === 'storage' ? gather(x, z) : element(x, z))
30
30
  if (y === 'member') return (z: X) => member(x, z)
31
+ if (y === 'assign') return assign.bind(null, x, x.type === 'gather')
31
32
  if (isOperator(y)) return (...z: X[]) => operator(y, x, ...z)
32
33
  if (isFunction(y)) return (...z: X[]) => function_(y, x, ...z)
33
34
  if (isConversion(y)) return () => conversion(getConstant(y), x)
@@ -43,9 +44,10 @@ export const node = <T extends C>(type: NodeTypes, props?: NodeProps | null, ...
43
44
  }
44
45
 
45
46
  // headers with proper type inference
46
- export const attribute = <T extends C>(x: X, id = getId()) => node<T>('attribute', { id }, x)
47
+ export const attribute = <T extends C>(x: X<T>, id = getId()) => node<T>('attribute', { id }, x)
47
48
  export const constant = <T extends C>(x: X<T>, id = getId()) => node<T>('constant', { id }, x)
48
49
  export const uniform = <T extends C>(x: X<T>, id = getId()) => node<T>('uniform', { id }, x)
50
+ export const storage = <T extends C>(x: X<T>, id = getId()) => node<T>('storage', { id }, x)
49
51
  export const variable = <T extends C>(id = getId()) => node<T>('variable', { id })
50
52
  export const builtin = <T extends C>(id = getId()) => node<T>('builtin', { id })
51
53
  export const vertexStage = <T extends C>(x: X<T>, id = getId()) => {
@@ -55,6 +57,8 @@ export const vertexStage = <T extends C>(x: X<T>, id = getId()) => {
55
57
  // Node shorthands with proper typing
56
58
  export const member = <T extends C>(x: X, index: X) => node<T>('member', null, x, index)
57
59
  export const element = <T extends C>(x: X, index: X) => node<T>('element', null, x, index)
60
+ export const gather = <T extends C>(x: X, index: X) => node<T>('gather', null, x, index)
61
+ export const scatter = <T extends C>(x: X, index: X) => node<T>('scatter', null, x, index)
58
62
  export const select = <T extends C>(x: X<T>, y: X<T>, z: X) => node<T>('ternary', null, x, y, z) // z ? x : y @TODO REMOVE
59
63
  export const operator = <T extends C>(key: Operators, ...x: X[]) => node<T>('operator', null, key, ...x)
60
64
  export const function_ = <T extends C>(key: Functions, ...x: X[]) => node<T>('function', null, key, ...x)
package/src/node/scope.ts CHANGED
@@ -1,6 +1,17 @@
1
1
  import { getId } from './utils'
2
2
  import { conversion, node } from './node'
3
- import type { FnLayout, NodeProps, NodeProxy, X, Constants, Int } from './types'
3
+ import type {
4
+ FnLayout,
5
+ FnType,
6
+ NodeProps,
7
+ NodeProxy,
8
+ X,
9
+ Constants,
10
+ Int,
11
+ StructFactory,
12
+ StructNode,
13
+ StructFields,
14
+ } from './types'
4
15
 
5
16
  let scope: NodeProxy | null = null
6
17
  let define: NodeProxy | null = null
@@ -15,16 +26,17 @@ const addToScope = (x: NodeProxy) => {
15
26
  props.inferFrom.push(x)
16
27
  }
17
28
 
18
- export const toVar = <T extends Constants>(x: X<T>, id?: string): NodeProxy<T> => {
29
+ export function toVar<T extends StructFields>(x: StructNode<T>, id?: string): StructNode<T>
30
+ export function toVar<T extends Constants>(x: NodeProxy<T>, id?: string): NodeProxy<T> {
19
31
  if (!id) id = getId()
20
32
  const y = node<T>('variable', { id, inferFrom: [x] })
21
- const z = node('declare', null, x, y)
33
+ const z = node<T>('declare', null, x as NodeProxy, y)
22
34
  addToScope(z)
23
35
  return y
24
36
  }
25
37
 
26
- export const assign = <T extends Constants>(x: X<T>, y: X<T>): X<T> => {
27
- const z = node('assign', null, x, y)
38
+ export const assign = <T extends Constants>(x: NodeProxy<T>, isScatter = false, y: X<T>): X<T> => {
39
+ const z = node(isScatter ? 'scatter' : 'assign', null, x, y)
28
40
  addToScope(z)
29
41
  return x
30
42
  }
@@ -35,12 +47,12 @@ export const Return = <T extends Constants>(x: X<T>): NodeProxy<T> => {
35
47
  return y
36
48
  }
37
49
 
38
- export const struct = <T extends Record<string, NodeProxy>>(fields: T, id = getId()) => {
39
- return (initialValues: T = {} as T, instanceId = getId()) => {
50
+ export const struct = <T extends StructFields>(fields: T, id = getId()): StructFactory<T> => {
51
+ return (initialValues: StructFields = {}, instanceId = getId()) => {
40
52
  const x = node('variable', { id: instanceId, inferFrom: [id] })
41
53
  const y = node('struct', { id, fields, initialValues }, x)
42
54
  addToScope(y)
43
- return x
55
+ return x as StructNode<T>
44
56
  }
45
57
  }
46
58
 
@@ -103,32 +115,33 @@ export const Switch = (x: NodeProxy) => {
103
115
  return ret()
104
116
  }
105
117
 
106
- export const Fn = <ReturnType extends Constants, Args extends Constants[]>(
107
- fun: (paramVars: NodeProxy[]) => NodeProxy<ReturnType> | void,
118
+ export function Fn<T extends NodeProxy | StructNode | void, Args extends any[]>(
119
+ fun: (args: Args) => T,
108
120
  defaultId = getId()
109
- ) => {
121
+ ) {
110
122
  let layout: FnLayout
111
- const ret = (...args: X<Args[number]>[]): NodeProxy<ReturnType> => {
123
+ const ret = (...args: any[]) => {
112
124
  const id = layout?.name || defaultId
113
125
  const x = node('scope')
114
126
  const paramVars: NodeProxy[] = []
115
127
  const paramDefs: NodeProps[] = []
116
- if (layout?.inputs)
128
+ if (layout?.inputs) {
117
129
  for (const input of layout.inputs) {
118
130
  paramDefs.push({ id: input.name, inferFrom: [conversion(input.type)] })
119
131
  }
120
- else
132
+ } else {
121
133
  for (let i = 0; i < args.length; i++) {
122
134
  paramDefs.push({ id: `p${i}`, inferFrom: [args[i]] })
123
135
  }
136
+ }
124
137
  for (const props of paramDefs) paramVars.push(node('variable', props))
125
- const y = node<ReturnType>('define', { id, layout }, x, ...args)
126
- scoped(x, () => fun(paramVars), y)
138
+ const y = node('define', { id, layout }, x, ...args)
139
+ scoped(x, () => fun(paramVars as Args) as any, y)
127
140
  return y
128
141
  }
129
142
  ret.setLayout = (_layout: FnLayout) => {
130
143
  layout = _layout
131
144
  return ret
132
145
  }
133
- return ret
146
+ return ret as unknown as Args extends readonly unknown[] ? FnType<T, Args> : never
134
147
  }