@triforge/shader-core 0.4.0 → 0.4.2

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/dist/bundle.js CHANGED
@@ -300,6 +300,12 @@ var CompileContext = class _CompileContext {
300
300
  this.order = [];
301
301
  this.emittedDefs = /* @__PURE__ */ new Set();
302
302
  this.defs = [];
303
+ /**
304
+ * `#extension` pragmas collected from any node's compileDefs() output.
305
+ * GLSL requires these before any other non-preprocessor token in the
306
+ * shader — see _extractExtensions / buildFragmentShader.
307
+ */
308
+ this._extensions = /* @__PURE__ */ new Set();
303
309
  this.calls = [];
304
310
  this.graphPath = [];
305
311
  this._uniforms = {};
@@ -421,16 +427,32 @@ var CompileContext = class _CompileContext {
421
427
  const fn = node.glslFunction ?? NodeClass.glslFunction;
422
428
  const defsSource = node.compileDefs();
423
429
  if (isInstanceSpecific) {
424
- if (defsSource.trim()) this.defs.push(defsSource);
430
+ if (defsSource.trim()) this.defs.push(this._extractExtensions(defsSource));
425
431
  } else {
426
432
  const key = node.nodeType;
427
433
  if (!this.emittedDefs.has(key)) {
428
434
  this.emittedDefs.add(key);
429
435
  const source = fn ?? defsSource;
430
- if (source.trim()) this.defs.push(source);
436
+ if (source.trim()) this.defs.push(this._extractExtensions(source));
431
437
  }
432
438
  }
433
439
  }
440
+ /**
441
+ * Strips `#extension` lines out of a node's compileDefs() output and
442
+ * collects them (deduplicated) to be hoisted to the very top of the
443
+ * fragment shader by buildFragmentShader(). WebGL2/ESSL3 requires
444
+ * `#extension` directives to appear before any non-preprocessor token —
445
+ * leaving them in place mid-file (after other nodes' defs/uniforms) throws
446
+ * "extension directive must occur before any non-preprocessor tokens".
447
+ * A node just writes `#extension NAME : enable` anywhere in compileDefs()
448
+ * and gets correct placement automatically — no per-node opt-in needed.
449
+ */
450
+ _extractExtensions(source) {
451
+ return source.replace(/^[ \t]*#extension[^\n]*$/gm, (line) => {
452
+ this._extensions.add(line.trim());
453
+ return "";
454
+ });
455
+ }
434
456
  // ── Validation ────────────────────────────────────────────────────
435
457
  validate(root) {
436
458
  if (ShaderConfig.errorLevel === "off") return;
@@ -495,11 +517,13 @@ ${customAssigns}
495
517
  return Object.entries(this._uniforms).map(([name, { value }]) => Array.isArray(value) ? `uniform vec3 ${name};` : `uniform float ${name};`).join("\n");
496
518
  }
497
519
  buildFragmentShader() {
520
+ const extensionsBlock = [...this._extensions].join("\n");
498
521
  const uniformsBlock = this.buildUniformDeclarations();
499
522
  const customVaryings = [...this._vertexInjections.entries()].map(([vName, { attrType }]) => `varying ${attrType} ${vName};`).join("\n");
500
523
  const defsBlock = this.defs.join("\n\n");
501
524
  const callsBlock = this.calls.map((c) => ` ${c}`).join("\n");
502
525
  return `
526
+ ${extensionsBlock}
503
527
  precision mediump float;
504
528
 
505
529
  varying vec2 vUv;
@@ -2843,13 +2867,7 @@ vec3 _st_bump(float height, float strength, float distance, vec3 N) {
2843
2867
  }
2844
2868
  compileDefs() {
2845
2869
  if (this._method === "uv-offset") {
2846
- return [
2847
- "#ifndef _ST_BUMP_TEXLOD_EXT",
2848
- "#define _ST_BUMP_TEXLOD_EXT",
2849
- "#extension GL_EXT_shader_texture_lod : enable",
2850
- "#endif",
2851
- `uniform sampler2D ${this._uniformName};`
2852
- ].join("\n");
2870
+ return `uniform sampler2D ${this._uniformName};`;
2853
2871
  }
2854
2872
  return _Bump.derivativeGlslFunction;
2855
2873
  }
@@ -27,6 +27,12 @@ export declare class CompileContext {
27
27
  private order;
28
28
  private emittedDefs;
29
29
  private defs;
30
+ /**
31
+ * `#extension` pragmas collected from any node's compileDefs() output.
32
+ * GLSL requires these before any other non-preprocessor token in the
33
+ * shader — see _extractExtensions / buildFragmentShader.
34
+ */
35
+ private _extensions;
30
36
  private calls;
31
37
  private graphPath;
32
38
  private _uniforms;
@@ -48,6 +54,17 @@ export declare class CompileContext {
48
54
  private visit;
49
55
  private emit;
50
56
  private emitDefs;
57
+ /**
58
+ * Strips `#extension` lines out of a node's compileDefs() output and
59
+ * collects them (deduplicated) to be hoisted to the very top of the
60
+ * fragment shader by buildFragmentShader(). WebGL2/ESSL3 requires
61
+ * `#extension` directives to appear before any non-preprocessor token —
62
+ * leaving them in place mid-file (after other nodes' defs/uniforms) throws
63
+ * "extension directive must occur before any non-preprocessor tokens".
64
+ * A node just writes `#extension NAME : enable` anywhere in compileDefs()
65
+ * and gets correct placement automatically — no per-node opt-in needed.
66
+ */
67
+ private _extractExtensions;
51
68
  private validate;
52
69
  private validateNode;
53
70
  private typesCompatible;
@@ -1 +1 @@
1
- {"version":3,"file":"CompileContext.d.ts","sourceRoot":"","sources":["../../src/core/CompileContext.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEjD,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAO,MAAM,CAAA;IACzB,cAAc,EAAK,MAAM,CAAA;IACzB,QAAQ,EAAW,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IACrD,KAAK,EAAc,UAAU,EAAE,CAAA;IAC/B,gHAAgH;IAChH,iBAAiB,EAAE,OAAO,CAAA;CAC3B;AAED;;;;;;;;;GASG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAqD;IACpE,OAAO,CAAC,QAAQ,CAAoD;IACpE,OAAO,CAAC,KAAK,CAAgD;IAC7D,OAAO,CAAC,WAAW,CAAiD;IACpE,OAAO,CAAC,IAAI,CAAiD;IAC7D,OAAO,CAAC,KAAK,CAAgD;IAC7D,OAAO,CAAC,SAAS,CAA4C;IAC7D,OAAO,CAAC,SAAS,CAAuD;IACxE,0FAA0F;IAC1F,OAAO,CAAC,iBAAiB,CAAiE;IAI1F,OAAO,CAAC,UAAU,EAAE,UAAU,GAAG,gBAAgB;IAejD;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM;IAKvD;;;;;OAKG;IACH,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,MAAM;IAgDlD,OAAO,CAAC,KAAK;IA8Bb,OAAO,CAAC,IAAI;IAyBZ,OAAO,CAAC,QAAQ;IA0BhB,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,YAAY;IAsCpB,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,iBAAiB;IAuBzB,OAAO,CAAC,wBAAwB;IAMhC,OAAO,CAAC,mBAAmB;IA2B3B,OAAO,CAAC,SAAS;IAwBjB,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAS3D,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAQrC,OAAO,CAAC,SAAS;CAGlB"}
1
+ {"version":3,"file":"CompileContext.d.ts","sourceRoot":"","sources":["../../src/core/CompileContext.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEjD,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAO,MAAM,CAAA;IACzB,cAAc,EAAK,MAAM,CAAA;IACzB,QAAQ,EAAW,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IACrD,KAAK,EAAc,UAAU,EAAE,CAAA;IAC/B,gHAAgH;IAChH,iBAAiB,EAAE,OAAO,CAAA;CAC3B;AAED;;;;;;;;;GASG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAqD;IACpE,OAAO,CAAC,QAAQ,CAAoD;IACpE,OAAO,CAAC,KAAK,CAAgD;IAC7D,OAAO,CAAC,WAAW,CAAiD;IACpE,OAAO,CAAC,IAAI,CAAiD;IAC7D;;;;OAIG;IACH,OAAO,CAAC,WAAW,CAAiD;IACpE,OAAO,CAAC,KAAK,CAAgD;IAC7D,OAAO,CAAC,SAAS,CAA4C;IAC7D,OAAO,CAAC,SAAS,CAAuD;IACxE,0FAA0F;IAC1F,OAAO,CAAC,iBAAiB,CAAiE;IAI1F,OAAO,CAAC,UAAU,EAAE,UAAU,GAAG,gBAAgB;IAejD;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM;IAKvD;;;;;OAKG;IACH,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,MAAM;IAgDlD,OAAO,CAAC,KAAK;IA8Bb,OAAO,CAAC,IAAI;IAyBZ,OAAO,CAAC,QAAQ;IAwBhB;;;;;;;;;OASG;IACH,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,QAAQ;IAKhB,OAAO,CAAC,YAAY;IAsCpB,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,iBAAiB;IAuBzB,OAAO,CAAC,wBAAwB;IAMhC,OAAO,CAAC,mBAAmB;IA6B3B,OAAO,CAAC,SAAS;IAwBjB,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IAS3D,MAAM,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAQrC,OAAO,CAAC,SAAS;CAGlB"}
@@ -18,6 +18,12 @@ export class CompileContext {
18
18
  this.order = [];
19
19
  this.emittedDefs = new Set();
20
20
  this.defs = [];
21
+ /**
22
+ * `#extension` pragmas collected from any node's compileDefs() output.
23
+ * GLSL requires these before any other non-preprocessor token in the
24
+ * shader — see _extractExtensions / buildFragmentShader.
25
+ */
26
+ this._extensions = new Set();
21
27
  this.calls = [];
22
28
  this.graphPath = [];
23
29
  this._uniforms = {};
@@ -159,7 +165,7 @@ export class CompileContext {
159
165
  if (isInstanceSpecific) {
160
166
  // Each instance emits its own uniquely named function — no dedup
161
167
  if (defsSource.trim())
162
- this.defs.push(defsSource);
168
+ this.defs.push(this._extractExtensions(defsSource));
163
169
  }
164
170
  else {
165
171
  // Shared function — emit once per node type
@@ -168,10 +174,26 @@ export class CompileContext {
168
174
  this.emittedDefs.add(key);
169
175
  const source = fn ?? defsSource;
170
176
  if (source.trim())
171
- this.defs.push(source);
177
+ this.defs.push(this._extractExtensions(source));
172
178
  }
173
179
  }
174
180
  }
181
+ /**
182
+ * Strips `#extension` lines out of a node's compileDefs() output and
183
+ * collects them (deduplicated) to be hoisted to the very top of the
184
+ * fragment shader by buildFragmentShader(). WebGL2/ESSL3 requires
185
+ * `#extension` directives to appear before any non-preprocessor token —
186
+ * leaving them in place mid-file (after other nodes' defs/uniforms) throws
187
+ * "extension directive must occur before any non-preprocessor tokens".
188
+ * A node just writes `#extension NAME : enable` anywhere in compileDefs()
189
+ * and gets correct placement automatically — no per-node opt-in needed.
190
+ */
191
+ _extractExtensions(source) {
192
+ return source.replace(/^[ \t]*#extension[^\n]*$/gm, (line) => {
193
+ this._extensions.add(line.trim());
194
+ return '';
195
+ });
196
+ }
175
197
  // ── Validation ────────────────────────────────────────────────────
176
198
  validate(root) {
177
199
  if (ShaderConfig.errorLevel === 'off')
@@ -255,6 +277,7 @@ ${customAssigns}
255
277
  .join('\n');
256
278
  }
257
279
  buildFragmentShader() {
280
+ const extensionsBlock = [...this._extensions].join('\n');
258
281
  const uniformsBlock = this.buildUniformDeclarations();
259
282
  const customVaryings = [...this._vertexInjections.entries()]
260
283
  .map(([vName, { attrType }]) => `varying ${attrType} ${vName};`)
@@ -262,6 +285,7 @@ ${customAssigns}
262
285
  const defsBlock = this.defs.join('\n\n');
263
286
  const callsBlock = this.calls.map(c => ` ${c}`).join('\n');
264
287
  return `
288
+ ${extensionsBlock}
265
289
  precision mediump float;
266
290
 
267
291
  varying vec2 vUv;
@@ -1 +1 @@
1
- {"version":3,"file":"Bump.d.ts","sourceRoot":"","sources":["../../../src/nodes/process/Bump.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAIvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAE9D,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,YAAY,GAAG,MAAM,CAAA;IAChC,QAAQ,CAAC,EAAE,YAAY,GAAG,MAAM,CAAA;IAChC,MAAM,CAAC,EAAI,YAAY,CAAA;IACvB,MAAM,CAAC,EAAI,YAAY,CAAA;IACvB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAO,YAAY,GAAG,WAAW,CAAA;IACxC,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,kFAAkF;IAClF,MAAM,CAAC,EAAO,YAAY,CAAA;IAC1B,oFAAoF;IACpF,SAAS,CAAC,EAAI,YAAY,GAAG,MAAM,CAAA;IACnC,mEAAmE;IACnE,GAAG,CAAC,EAAU,YAAY,GAAG,MAAM,CAAA;CACpC;AAED;;;;;;;;GAQG;AACH,qBAAa,IAAK,SAAQ,WAAW;IACnC,IAAI,QAAQ,WAAoB;IAKhC,MAAM,CAAC,mBAAmB,UAAO;IAEjC,IAAI,QAAQ,IAAI,YAAY,CAE3B;IAED,MAAM,CAAC,sBAAsB,SA8BxB;IAEL,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;IACzD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2E;IACnG,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmE;gBAEhF,MAAM,GAAE,UAAe;IA+BnC,eAAe;IACf,gBAAgB;IAEhB,WAAW,IAAI,MAAM;IAarB,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM;CAkDzC"}
1
+ {"version":3,"file":"Bump.d.ts","sourceRoot":"","sources":["../../../src/nodes/process/Bump.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA;AAIvD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAClE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAE9D,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,YAAY,GAAG,MAAM,CAAA;IAChC,QAAQ,CAAC,EAAE,YAAY,GAAG,MAAM,CAAA;IAChC,MAAM,CAAC,EAAI,YAAY,CAAA;IACvB,MAAM,CAAC,EAAI,YAAY,CAAA;IACvB;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAO,YAAY,GAAG,WAAW,CAAA;IACxC,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,kFAAkF;IAClF,MAAM,CAAC,EAAO,YAAY,CAAA;IAC1B,oFAAoF;IACpF,SAAS,CAAC,EAAI,YAAY,GAAG,MAAM,CAAA;IACnC,mEAAmE;IACnE,GAAG,CAAC,EAAU,YAAY,GAAG,MAAM,CAAA;CACpC;AAED;;;;;;;;GAQG;AACH,qBAAa,IAAK,SAAQ,WAAW;IACnC,IAAI,QAAQ,WAAoB;IAKhC,MAAM,CAAC,mBAAmB,UAAO;IAEjC,IAAI,QAAQ,IAAI,YAAY,CAE3B;IAED,MAAM,CAAC,sBAAsB,SA8BxB;IAEL,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;IACzD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2E;IACnG,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmE;gBAEhF,MAAM,GAAE,UAAe;IA+BnC,eAAe;IACf,gBAAgB;IAEhB,WAAW,IAAI,MAAM;IAWrB,WAAW,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM;CAkDzC"}
@@ -50,13 +50,11 @@ export class Bump extends ProcessNode {
50
50
  getOutputSockets() { return this._outputs; }
51
51
  compileDefs() {
52
52
  if (this._method === 'uv-offset') {
53
- return [
54
- '#ifndef _ST_BUMP_TEXLOD_EXT',
55
- '#define _ST_BUMP_TEXLOD_EXT',
56
- '#extension GL_EXT_shader_texture_lod : enable',
57
- '#endif',
58
- `uniform sampler2D ${this._uniformName};`,
59
- ].join('\n');
53
+ // No #extension needed: three.js's WebGL2/ESSL3 prefix already
54
+ // #defines texture2DLodEXT to the core textureLod() built-in, and that
55
+ // prefix is injected ahead of anything CompileContext could hoist this
56
+ // extension above — emitting it here breaks ESSL3's ordering rule.
57
+ return `uniform sampler2D ${this._uniformName};`;
60
58
  }
61
59
  return Bump.derivativeGlslFunction;
62
60
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@triforge/shader-core",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "GLSL shader library for Three.js with Blender workflow",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",