textmode.synth.js 1.0.0-beta.5 → 1.0.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/README.md CHANGED
@@ -7,7 +7,7 @@ Create procedural ASCII/text animations with a `hydra`-inspired, chainable visua
7
7
  > [!NOTE]
8
8
  > This project is work-in-progress and not yet ready for production use.
9
9
  >
10
- > `textmode.synth.js` becomes usable once `textmode.js` v0.9.0 is released.
10
+ > `textmode.synth.js` becomes usable once `textmode.js` v0.8.5 is released.
11
11
 
12
12
  ## Features
13
13
 
@@ -25,6 +25,9 @@ To go along with the release of this library, we've created a **live coding envi
25
25
 
26
26
  It features IntelliSense & auto-completion, documentation on hover, curated examples to explore, and a lot more. The whole `textmode.js` ecosystem is available at your fingertips.
27
27
 
28
+ ## Prerequisites
29
+
30
+ - **textmode.js v0.8.5+** - This library depends on the core `textmode.js` package v0.8.5 or higher.
28
31
 
29
32
  ## Installation
30
33
 
@@ -255,16 +255,16 @@ const P = new G(), q = { name: "osc", type: "src", inputs: [{ name: "frequency",
255
255
  return (_c0 - _c1) * amount + _c0 * (1.0 - amount);
256
256
  `, description: "Subtract another source" }, Ie = { name: "mult", type: "combine", inputs: [{ name: "amount", type: "float", default: 1 }], glsl: `
257
257
  return _c0 * (1.0 - amount) + (_c0 * _c1) * amount;
258
- `, description: "Multiply with another source" }, Ae = { name: "blend", type: "combine", inputs: [{ name: "amount", type: "float", default: 0.5 }], glsl: `
258
+ `, description: "Multiply with another source" }, Re = { name: "blend", type: "combine", inputs: [{ name: "amount", type: "float", default: 0.5 }], glsl: `
259
259
  return _c0 * (1.0 - amount) + _c1 * amount;
260
- `, description: "Blend with another source" }, Re = { name: "diff", type: "combine", inputs: [], glsl: `
260
+ `, description: "Blend with another source" }, Ae = { name: "diff", type: "combine", inputs: [], glsl: `
261
261
  return vec4(abs(_c0.rgb - _c1.rgb), max(_c0.a, _c1.a));
262
262
  `, description: "Difference with another source" }, ze = { name: "layer", type: "combine", inputs: [], glsl: `
263
263
  return vec4(mix(_c0.rgb, _c1.rgb, _c1.a), clamp(_c0.a + _c1.a, 0.0, 1.0));
264
264
  `, description: "Layer another source on top" }, Oe = { name: "mask", type: "combine", inputs: [], glsl: `
265
265
  float a = _luminance(_c1.rgb);
266
266
  return vec4(_c0.rgb * a, a * _c0.a);
267
- `, description: "Mask with another source" }, Ue = [Le, Pe, Ie, Ae, Re, ze, Oe], Ve = { name: "modulate", type: "combineCoord", inputs: [{ name: "amount", type: "float", default: 0.1 }], glsl: `
267
+ `, description: "Mask with another source" }, Ue = [Le, Pe, Ie, Re, Ae, ze, Oe], Ve = { name: "modulate", type: "combineCoord", inputs: [{ name: "amount", type: "float", default: 0.1 }], glsl: `
268
268
  return _st + _c0.xy * amount;
269
269
  `, description: "Modulate coordinates with another source" }, Ee = { name: "modulateScale", type: "combineCoord", inputs: [{ name: "multiple", type: "float", default: 1 }, { name: "offset", type: "float", default: 1 }], glsl: `
270
270
  vec2 xy = _st - vec2(0.5);
@@ -787,7 +787,7 @@ function lt(t, e, r) {
787
787
  int charIdx = int(lum * 255.0);
788
788
  vec4 charOutput = vec4(float(charIdx % 256) / 255.0, float(charIdx / 256) / 255.0, 0.0, 0.0);`;
789
789
  }
790
- function A(t) {
790
+ function R(t) {
791
791
  return new it().compile(t);
792
792
  }
793
793
  class it {
@@ -833,9 +833,9 @@ class it {
833
833
  g.name === "src" && this._trackSrcUsage(C);
834
834
  const u = this._codeGenerator.getContextAwareGlslFunction(_, g.name, this._currentTarget, C, (L) => this._externalLayerManager.getPrefix(L));
835
835
  this._glslFunctions.add(u);
836
- const Y = this._processArguments(g.userArgs, _.inputs, `${r}_${c}_${g.name}`), R = e.nestedSources.get(c);
836
+ const Y = this._processArguments(g.userArgs, _.inputs, `${r}_${c}_${g.name}`), A = e.nestedSources.get(c);
837
837
  let z;
838
- R && (_.type === "combine" || _.type === "combineCoord") && (z = this._compileChain(R, `${r}_nested_${c}`, a, s, o).colorVar);
838
+ A && (_.type === "combine" || _.type === "combineCoord") && (z = this._compileChain(A, `${r}_nested_${c}`, a, s, o).colorVar);
839
839
  const M = this._codeGenerator.generateTransformCode(this._mainCode, _, this._varCounter++, s, y, i, m, h, Y, this._currentTarget, z, C, (L) => this._externalLayerManager.getPrefix(L));
840
840
  y = M.colorVar, M.charVar && (i = M.charVar), M.flagsVar && (m = M.flagsVar), M.rotationVar && (h = M.rotationVar);
841
841
  };
@@ -898,7 +898,7 @@ function ft(t) {
898
898
  t.extendLayer("synth", function(e) {
899
899
  const r = this.grid !== void 0 && this.drawFramebuffer !== void 0;
900
900
  let a = this.getPluginState(b);
901
- a ? (a.source = e, a.needsCompile = !0, a.characterResolver.invalidate(), r && (a.compiled = A(e))) : a = V({ source: e, compiled: r ? A(e) : void 0, needsCompile: !0 }), this.setPluginState(b, a);
901
+ a ? (a.source = e, a.needsCompile = !0, a.characterResolver.invalidate(), r && (a.compiled = R(e))) : a = V({ source: e, compiled: r ? R(e) : void 0, needsCompile: !0 }), this.setPluginState(b, a);
902
902
  });
903
903
  }
904
904
  function pt(t) {
@@ -986,7 +986,7 @@ async function vt(t, e) {
986
986
  const r = t.getPluginState(b);
987
987
  if (!r) return;
988
988
  const a = t.grid, n = t.drawFramebuffer;
989
- if (!a || !n || (r.compiled || (r.compiled = A(r.source), r.externalLayerMap = w(r.source), r.needsCompile = !0), r.needsCompile && r.compiled && (r.shader?.dispose && r.shader.dispose(), r.externalLayerMap = w(r.source), r.shader = await e.createFilterShader(r.compiled.fragmentSource), r.needsCompile = !1), !r.shader || !r.compiled)) return;
989
+ if (!a || !n || (r.compiled || (r.compiled = R(r.source), r.externalLayerMap = w(r.source), r.needsCompile = !0), r.needsCompile && r.compiled && (r.shader?.dispose && r.shader.dispose(), r.externalLayerMap = w(r.source), r.shader = await e.createFilterShader(r.compiled.fragmentSource), r.needsCompile = !1), !r.shader || !r.compiled)) return;
990
990
  const o = r.compiled.usesCharColorFeedback, l = r.compiled.usesCharFeedback, s = r.compiled.usesCellColorFeedback, i = o || l || s;
991
991
  i && !r.pingPongBuffers && (r.pingPongBuffers = [e.createFramebuffer({ width: a.cols, height: a.rows, attachments: 3 }), e.createFramebuffer({ width: a.cols, height: a.rows, attachments: 3 })], r.pingPongIndex = 0);
992
992
  const m = { time: e.secs, frameCount: e.frameCount, width: a.width, height: a.height, cols: a.cols, rows: a.rows, bpm: r.bpm ?? ht() }, h = /* @__PURE__ */ new Map();
@@ -995,7 +995,7 @@ async function vt(t, e) {
995
995
  h.set(d, f);
996
996
  }
997
997
  const y = (d) => {
998
- e.setUniform("time", e.secs), e.setUniform("resolution", [m.cols, m.rows]);
998
+ e.setUniform("time", e.frameCount / e.targetFrameRate()), e.setUniform("resolution", [m.cols, m.rows]);
999
999
  for (const [p, f] of h) e.setUniform(p, f);
1000
1000
  for (const [p, f] of r.compiled.uniforms) f.isDynamic || typeof f.value == "function" || e.setUniform(p, f.value);
1001
1001
  if (r.compiled.charMapping) {
@@ -1072,7 +1072,7 @@ const It = (t) => {
1072
1072
  const r = new S(), a = t.id ?? `layer_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
1073
1073
  return r.addExternalLayerRef({ layerId: a, layer: t }), r;
1074
1074
  };
1075
- function At(t, e, r) {
1075
+ function Rt(t, e, r) {
1076
1076
  return $.voronoi(t, e, r);
1077
1077
  }
1078
1078
  export {
@@ -1089,5 +1089,5 @@ export {
1089
1089
  Lt as shape,
1090
1090
  Pt as solid,
1091
1091
  It as src,
1092
- At as voronoi
1092
+ Rt as voronoi
1093
1093
  };
@@ -376,4 +376,4 @@ ${$}
376
376
  o_primaryColor = ${_};
377
377
  o_secondaryColor = ${p};
378
378
  }
379
- `})({uniforms:this._uniformManager.getUniforms(),glslFunctions:this._glslFunctions,mainCode:this._mainCode,charOutputCode:s,primaryColorVar:n,cellColorVar:o,charMapping:t.charMapping,usesFeedback:c.usesCharColorFeedback,usesCharFeedback:c.usesCharFeedback,usesCellColorFeedback:c.usesCellColorFeedback,usesCharSource:this._usesCharSource,externalLayers:this._externalLayerManager.getExternalLayers()}),uniforms:this._uniformManager.getUniforms(),dynamicUpdaters:this._uniformManager.getDynamicUpdaters(),charMapping:t.charMapping,usesCharColorFeedback:c.usesCharColorFeedback,usesCharFeedback:c.usesCharFeedback,usesCellColorFeedback:c.usesCellColorFeedback,usesCharSource:this._usesCharSource,externalLayers:this._externalLayerManager.getExternalLayers()}}_reset(){this._varCounter=0,this._uniformManager.clear(),this._feedbackTracker.reset(),this._externalLayerManager.reset(),this._glslFunctions.clear(),this._mainCode.length=0,this._currentTarget="main",this._usesCharSource=!1}_compileCharSource(t){this._usesCharSource=!0;const r=this._compileChain(t.charSource,"charSrc","vec4(1.0, 1.0, 1.0, 1.0)","v_uv","char"),a="charFromSource_"+this._varCounter++;return this._mainCode.push(" // Convert charSource color to character index"),this._mainCode.push(` float charLum_${a} = _luminance(${r.colorVar}.rgb);`),this._mainCode.push(` int charIdx_${a} = int(charLum_${a} * u_charSourceCount);`),this._mainCode.push(` vec4 ${a} = vec4(float(charIdx_${a} % 256) / 255.0, float(charIdx_${a} / 256) / 255.0, 0.0, 0.0);`),a}_compileChain(t,r,a,n="v_uv",o="main"){const s=this._currentTarget;this._currentTarget=o;const c=`${r}_st`;let l,f,h,y=`${r}_c`;this._mainCode.push(` vec2 ${c} = ${n};`),this._mainCode.push(` vec4 ${y} = ${a};`);const v=t.transforms,C=v.map(i=>this._getProcessedTransform(i.name)),_=this._identifyCoordTransforms(C),p=i=>{const u=v[i],m=C[i];if(!m)return void console.warn(`[SynthCompiler] Unknown transform: ${u.name}`);const b=t.externalLayerRefs.get(i);u.name==="src"&&this._trackSrcUsage(b);const d=this._codeGenerator.getContextAwareGlslFunction(m,u.name,this._currentTarget,b,k=>this._externalLayerManager.getPrefix(k));this._glslFunctions.add(d);const M=this._processArguments(u.userArgs,m.inputs,`${r}_${i}_${u.name}`),B=t.nestedSources.get(i);let z;B&&(m.type==="combine"||m.type==="combineCoord")&&(z=this._compileChain(B,`${r}_nested_${i}`,a,c,o).colorVar);const $=this._codeGenerator.generateTransformCode(this._mainCode,m,this._varCounter++,c,y,l,f,h,M,this._currentTarget,z,b,k=>this._externalLayerManager.getPrefix(k));y=$.colorVar,$.charVar&&(l=$.charVar),$.flagsVar&&(f=$.flagsVar),$.rotationVar&&(h=$.rotationVar)};for(let i=_.length-1;i>=0;i--)p(_[i]);for(let i=0;i<v.length;i++){const u=C[i];(!u||u.type!=="coord"&&u.type!=="combineCoord")&&p(i)}return this._currentTarget=s,{coordVar:c,colorVar:y,charVar:l,flagsVar:f,rotationVar:h}}_identifyCoordTransforms(t){const r=[];for(let a=0;a<t.length;a++){const n=t[a];n&&(n.type!=="coord"&&n.type!=="combineCoord"||r.push(a))}return r}_trackSrcUsage(t){t?this._externalLayerManager.trackUsage(t,this._currentTarget):this._feedbackTracker.trackUsage(this._currentTarget)}_getProcessedTransform(t){return A.getProcessed(t)}_processArguments(t,r,a){const n=[];for(let o=0;o<r.length;o++){const s=r[o],c=t[o]??s.default,l=this._uniformManager.processArgument(c,s,a);n.push(l.glslValue)}return n}}class ee{_resolvedIndices;_lastFontCharacterCount=0;_lastChars="";resolve(t,r){const a=r.characters.length;if(this._resolvedIndices&&this._lastFontCharacterCount===a&&this._lastChars===t)return this._resolvedIndices;const n=Array.from(t),o=new Int32Array(n.length),s=r.characterMap,c=r.characters;for(let l=0;l<n.length;l++){const f=n[l],h=s.get(f);if(h!==void 0)o[l]=c.indexOf(h);else{const y=s.get(" ");o[l]=y!==void 0?c.indexOf(y):0}}return this._resolvedIndices=o,this._lastFontCharacterCount=a,this._lastChars=t,o}invalidate(){this._resolvedIndices=void 0,this._lastFontCharacterCount=0,this._lastChars=""}}function E(e={}){return{source:e.source??new S,compiled:e.compiled,shader:e.shader,characterResolver:e.characterResolver??new ee,needsCompile:e.needsCompile??!1,pingPongBuffers:e.pingPongBuffers,pingPongIndex:e.pingPongIndex??0,externalLayerMap:e.externalLayerMap,bpm:e.bpm}}let D=60;function te(e){e.bpm=function(t){return(function(r){D=r})(t),t}}function I(e){const t=new Map;for(const[,r]of e.externalLayerRefs)t.set(r.layerId,r.layer);for(const[,r]of e.nestedSources){const a=I(r);for(const[n,o]of a)t.set(n,o)}if(e.charSource){const r=I(e.charSource);for(const[a,n]of r)t.set(a,n)}if(e.colorSource){const r=I(e.colorSource);for(const[a,n]of r)t.set(a,n)}if(e.cellColorSource){const r=I(e.cellColorSource);for(const[a,n]of r)t.set(a,n)}return t}let O=null;function q(e,t,r){const a=r??O;if(a)try{a(e,t)}catch{}}function ne(e,t,r,a={}){let n;try{n=e()}catch(o){return q(o,t,a.onError),r}return(function(o){return o==null?!1:typeof o=="number"?Number.isFinite(o):Array.isArray(o)?o.length>0&&o.every(s=>typeof s=="number"&&Number.isFinite(s)):!1})(n)?n:(q(new Error(`[textmode.synth.js] Invalid dynamic parameter value for "${t}": ${N(n)}`),t,a.onError),r)}function N(e){if(e===void 0)return"undefined";if(e===null)return"null";if(typeof e=="number"){if(Number.isNaN(e))return"NaN";if(!Number.isFinite(e))return e>0?"Infinity":"-Infinity"}if(Array.isArray(e)){const t=e.findIndex(r=>typeof r!="number"||!Number.isFinite(r));if(t>=0)return`array with invalid element at index ${t}: ${N(e[t])}`}return String(e)}function re(e){const t=e.getPluginState(w);t&&(t.shader?.dispose&&t.shader.dispose(),t.pingPongBuffers&&(t.pingPongBuffers[0].dispose?.(),t.pingPongBuffers[1].dispose?.()))}const ae={name:w,version:"1.0.0",install(e,t){te(e),(function(r){r.extendLayer("synth",function(a){const n=this.grid!==void 0&&this.drawFramebuffer!==void 0;let o=this.getPluginState(w);o?(o.source=a,o.needsCompile=!0,o.characterResolver.invalidate(),n&&(o.compiled=X(a))):o=E({source:a,compiled:n?X(a):void 0,needsCompile:!0}),this.setPluginState(w,o)})})(t),(function(r){r.extendLayer("bpm",function(a){let n=this.getPluginState(w);n?n.bpm=a:n=E({bpm:a}),this.setPluginState(w,n)})})(t),(function(r){r.extendLayer("clearSynth",function(){const a=this.getPluginState(w);a&&(a.shader?.dispose&&a.shader.dispose(),a.pingPongBuffers&&(a.pingPongBuffers[0].dispose?.(),a.pingPongBuffers[1].dispose?.()),this.setPluginState(w,void 0))})})(t),t.registerLayerPreRenderHook(r=>(async function(a,n){const o=a.getPluginState(w);if(!o)return;const s=a.grid,c=a.drawFramebuffer;if(!s||!c||(o.compiled||(o.compiled=X(o.source),o.externalLayerMap=I(o.source),o.needsCompile=!0),o.needsCompile&&o.compiled&&(o.shader?.dispose&&o.shader.dispose(),o.externalLayerMap=I(o.source),o.shader=await n.createFilterShader(o.compiled.fragmentSource),o.needsCompile=!1),!o.shader||!o.compiled))return;const l=o.compiled.usesCharColorFeedback,f=o.compiled.usesCharFeedback,h=o.compiled.usesCellColorFeedback,y=l||f||h;y&&!o.pingPongBuffers&&(o.pingPongBuffers=[n.createFramebuffer({width:s.cols,height:s.rows,attachments:3}),n.createFramebuffer({width:s.cols,height:s.rows,attachments:3})],o.pingPongIndex=0);const v={time:n.secs,frameCount:n.frameCount,width:s.width,height:s.height,cols:s.cols,rows:s.rows,bpm:o.bpm??D},C=new Map;for(const[p,i]of o.compiled.dynamicUpdaters){const u=o.compiled.uniforms.get(p),m=ne(()=>i(v),p,u?.value??0,{onError:o.onDynamicError});C.set(p,m)}const _=p=>{n.setUniform("time",n.secs),n.setUniform("resolution",[v.cols,v.rows]);for(const[u,m]of C)n.setUniform(u,m);for(const[u,m]of o.compiled.uniforms)m.isDynamic||typeof m.value=="function"||n.setUniform(u,m.value);if(o.compiled.charMapping){const u=o.characterResolver.resolve(o.compiled.charMapping.chars,a.font);n.setUniform("u_charMap",u),n.setUniform("u_charMapSize",u.length)}if(o.compiled.usesCharSource){const u=o.compiled.charMapping?o.compiled.charMapping.chars.length:a.font.characters.length;n.setUniform("u_charSourceCount",u)}p&&(l&&n.setUniform("prevCharColorBuffer",p.textures[1]),f&&n.setUniform("prevCharBuffer",p.textures[0]),h&&n.setUniform("prevCellColorBuffer",p.textures[2]));const i=o.compiled.externalLayers;if(i&&i.size>0&&o.externalLayerMap)for(const[u,m]of i){const b=o.externalLayerMap.get(u);if(!b){console.warn(`[textmode.synth.js] External layer not found: ${u}`);continue}const d=b.getPluginState(w);let M;d?.pingPongBuffers?M=d.pingPongBuffers[d.pingPongIndex].textures:b.drawFramebuffer&&(M=b.drawFramebuffer.textures),M&&(m.usesChar&&n.setUniform(`${m.uniformPrefix}_char`,M[0]),m.usesCharColor&&n.setUniform(`${m.uniformPrefix}_primary`,M[1]),m.usesCellColor&&n.setUniform(`${m.uniformPrefix}_cell`,M[2]))}};if(y&&o.pingPongBuffers){const p=o.pingPongBuffers[o.pingPongIndex],i=o.pingPongBuffers[1-o.pingPongIndex];i.begin(),n.clear(),n.shader(o.shader),_(p),n.rect(s.cols,s.rows),i.end(),c.begin(),n.clear(),n.shader(o.shader),_(p),n.rect(s.cols,s.rows),c.end(),o.pingPongIndex=1-o.pingPongIndex}else c.begin(),n.clear(),n.shader(o.shader),_(null),n.rect(s.cols,s.rows),c.end()})(r,e)),t.registerLayerDisposedHook(re)},uninstall(e,t){const r=[t.layerManager.base,...t.layerManager.all];for(const a of r){const n=a.getPluginState(w);n&&(n.shader?.dispose&&n.shader.dispose(),n.pingPongBuffers&&(n.pingPongBuffers[0].dispose?.(),n.pingPongBuffers[1].dispose?.()))}delete e.bpm,t.removeLayerExtension("synth"),t.removeLayerExtension("bpm"),t.removeLayerExtension("clearSynth")}};g.SynthPlugin=ae,g.SynthSource=S,g.cellColor=e=>{const t=new S;return t._colorSource=e,t},g.char=(e,t)=>{const r=new S;return r._charSource=e,r._charCount=t,r},g.charColor=e=>{const t=new S;return t._colorSource=e,t},g.gradient=function(e){return P.gradient(e)},g.noise=function(e,t){return P.noise(e,t)},g.osc=function(e,t,r){return P.osc(e,t,r)},g.paint=e=>{const t=new S;return t._colorSource=e,t._cellColorSource=e,t},g.setGlobalErrorCallback=function(e){O=e},g.shape=function(e,t,r){return P.shape(e,t,r)},g.solid=function(e,t,r,a){return P.solid(e,t,r,a)},g.src=e=>{const t=P.src;if(!e)return t();const r=new S,a=e.id??`layer_${Date.now()}_${Math.random().toString(36).slice(2,9)}`;return r.addExternalLayerRef({layerId:a,layer:e}),r},g.voronoi=function(e,t,r){return P.voronoi(e,t,r)},Object.defineProperty(g,Symbol.toStringTag,{value:"Module"})});
379
+ `})({uniforms:this._uniformManager.getUniforms(),glslFunctions:this._glslFunctions,mainCode:this._mainCode,charOutputCode:s,primaryColorVar:n,cellColorVar:o,charMapping:t.charMapping,usesFeedback:c.usesCharColorFeedback,usesCharFeedback:c.usesCharFeedback,usesCellColorFeedback:c.usesCellColorFeedback,usesCharSource:this._usesCharSource,externalLayers:this._externalLayerManager.getExternalLayers()}),uniforms:this._uniformManager.getUniforms(),dynamicUpdaters:this._uniformManager.getDynamicUpdaters(),charMapping:t.charMapping,usesCharColorFeedback:c.usesCharColorFeedback,usesCharFeedback:c.usesCharFeedback,usesCellColorFeedback:c.usesCellColorFeedback,usesCharSource:this._usesCharSource,externalLayers:this._externalLayerManager.getExternalLayers()}}_reset(){this._varCounter=0,this._uniformManager.clear(),this._feedbackTracker.reset(),this._externalLayerManager.reset(),this._glslFunctions.clear(),this._mainCode.length=0,this._currentTarget="main",this._usesCharSource=!1}_compileCharSource(t){this._usesCharSource=!0;const r=this._compileChain(t.charSource,"charSrc","vec4(1.0, 1.0, 1.0, 1.0)","v_uv","char"),a="charFromSource_"+this._varCounter++;return this._mainCode.push(" // Convert charSource color to character index"),this._mainCode.push(` float charLum_${a} = _luminance(${r.colorVar}.rgb);`),this._mainCode.push(` int charIdx_${a} = int(charLum_${a} * u_charSourceCount);`),this._mainCode.push(` vec4 ${a} = vec4(float(charIdx_${a} % 256) / 255.0, float(charIdx_${a} / 256) / 255.0, 0.0, 0.0);`),a}_compileChain(t,r,a,n="v_uv",o="main"){const s=this._currentTarget;this._currentTarget=o;const c=`${r}_st`;let l,f,h,y=`${r}_c`;this._mainCode.push(` vec2 ${c} = ${n};`),this._mainCode.push(` vec4 ${y} = ${a};`);const v=t.transforms,C=v.map(i=>this._getProcessedTransform(i.name)),_=this._identifyCoordTransforms(C),p=i=>{const u=v[i],m=C[i];if(!m)return void console.warn(`[SynthCompiler] Unknown transform: ${u.name}`);const b=t.externalLayerRefs.get(i);u.name==="src"&&this._trackSrcUsage(b);const d=this._codeGenerator.getContextAwareGlslFunction(m,u.name,this._currentTarget,b,k=>this._externalLayerManager.getPrefix(k));this._glslFunctions.add(d);const M=this._processArguments(u.userArgs,m.inputs,`${r}_${i}_${u.name}`),B=t.nestedSources.get(i);let z;B&&(m.type==="combine"||m.type==="combineCoord")&&(z=this._compileChain(B,`${r}_nested_${i}`,a,c,o).colorVar);const $=this._codeGenerator.generateTransformCode(this._mainCode,m,this._varCounter++,c,y,l,f,h,M,this._currentTarget,z,b,k=>this._externalLayerManager.getPrefix(k));y=$.colorVar,$.charVar&&(l=$.charVar),$.flagsVar&&(f=$.flagsVar),$.rotationVar&&(h=$.rotationVar)};for(let i=_.length-1;i>=0;i--)p(_[i]);for(let i=0;i<v.length;i++){const u=C[i];(!u||u.type!=="coord"&&u.type!=="combineCoord")&&p(i)}return this._currentTarget=s,{coordVar:c,colorVar:y,charVar:l,flagsVar:f,rotationVar:h}}_identifyCoordTransforms(t){const r=[];for(let a=0;a<t.length;a++){const n=t[a];n&&(n.type!=="coord"&&n.type!=="combineCoord"||r.push(a))}return r}_trackSrcUsage(t){t?this._externalLayerManager.trackUsage(t,this._currentTarget):this._feedbackTracker.trackUsage(this._currentTarget)}_getProcessedTransform(t){return A.getProcessed(t)}_processArguments(t,r,a){const n=[];for(let o=0;o<r.length;o++){const s=r[o],c=t[o]??s.default,l=this._uniformManager.processArgument(c,s,a);n.push(l.glslValue)}return n}}class ee{_resolvedIndices;_lastFontCharacterCount=0;_lastChars="";resolve(t,r){const a=r.characters.length;if(this._resolvedIndices&&this._lastFontCharacterCount===a&&this._lastChars===t)return this._resolvedIndices;const n=Array.from(t),o=new Int32Array(n.length),s=r.characterMap,c=r.characters;for(let l=0;l<n.length;l++){const f=n[l],h=s.get(f);if(h!==void 0)o[l]=c.indexOf(h);else{const y=s.get(" ");o[l]=y!==void 0?c.indexOf(y):0}}return this._resolvedIndices=o,this._lastFontCharacterCount=a,this._lastChars=t,o}invalidate(){this._resolvedIndices=void 0,this._lastFontCharacterCount=0,this._lastChars=""}}function E(e={}){return{source:e.source??new S,compiled:e.compiled,shader:e.shader,characterResolver:e.characterResolver??new ee,needsCompile:e.needsCompile??!1,pingPongBuffers:e.pingPongBuffers,pingPongIndex:e.pingPongIndex??0,externalLayerMap:e.externalLayerMap,bpm:e.bpm}}let D=60;function te(e){e.bpm=function(t){return(function(r){D=r})(t),t}}function I(e){const t=new Map;for(const[,r]of e.externalLayerRefs)t.set(r.layerId,r.layer);for(const[,r]of e.nestedSources){const a=I(r);for(const[n,o]of a)t.set(n,o)}if(e.charSource){const r=I(e.charSource);for(const[a,n]of r)t.set(a,n)}if(e.colorSource){const r=I(e.colorSource);for(const[a,n]of r)t.set(a,n)}if(e.cellColorSource){const r=I(e.cellColorSource);for(const[a,n]of r)t.set(a,n)}return t}let O=null;function q(e,t,r){const a=r??O;if(a)try{a(e,t)}catch{}}function ne(e,t,r,a={}){let n;try{n=e()}catch(o){return q(o,t,a.onError),r}return(function(o){return o==null?!1:typeof o=="number"?Number.isFinite(o):Array.isArray(o)?o.length>0&&o.every(s=>typeof s=="number"&&Number.isFinite(s)):!1})(n)?n:(q(new Error(`[textmode.synth.js] Invalid dynamic parameter value for "${t}": ${N(n)}`),t,a.onError),r)}function N(e){if(e===void 0)return"undefined";if(e===null)return"null";if(typeof e=="number"){if(Number.isNaN(e))return"NaN";if(!Number.isFinite(e))return e>0?"Infinity":"-Infinity"}if(Array.isArray(e)){const t=e.findIndex(r=>typeof r!="number"||!Number.isFinite(r));if(t>=0)return`array with invalid element at index ${t}: ${N(e[t])}`}return String(e)}function re(e){const t=e.getPluginState(w);t&&(t.shader?.dispose&&t.shader.dispose(),t.pingPongBuffers&&(t.pingPongBuffers[0].dispose?.(),t.pingPongBuffers[1].dispose?.()))}const ae={name:w,version:"1.0.0",install(e,t){te(e),(function(r){r.extendLayer("synth",function(a){const n=this.grid!==void 0&&this.drawFramebuffer!==void 0;let o=this.getPluginState(w);o?(o.source=a,o.needsCompile=!0,o.characterResolver.invalidate(),n&&(o.compiled=X(a))):o=E({source:a,compiled:n?X(a):void 0,needsCompile:!0}),this.setPluginState(w,o)})})(t),(function(r){r.extendLayer("bpm",function(a){let n=this.getPluginState(w);n?n.bpm=a:n=E({bpm:a}),this.setPluginState(w,n)})})(t),(function(r){r.extendLayer("clearSynth",function(){const a=this.getPluginState(w);a&&(a.shader?.dispose&&a.shader.dispose(),a.pingPongBuffers&&(a.pingPongBuffers[0].dispose?.(),a.pingPongBuffers[1].dispose?.()),this.setPluginState(w,void 0))})})(t),t.registerLayerPreRenderHook(r=>(async function(a,n){const o=a.getPluginState(w);if(!o)return;const s=a.grid,c=a.drawFramebuffer;if(!s||!c||(o.compiled||(o.compiled=X(o.source),o.externalLayerMap=I(o.source),o.needsCompile=!0),o.needsCompile&&o.compiled&&(o.shader?.dispose&&o.shader.dispose(),o.externalLayerMap=I(o.source),o.shader=await n.createFilterShader(o.compiled.fragmentSource),o.needsCompile=!1),!o.shader||!o.compiled))return;const l=o.compiled.usesCharColorFeedback,f=o.compiled.usesCharFeedback,h=o.compiled.usesCellColorFeedback,y=l||f||h;y&&!o.pingPongBuffers&&(o.pingPongBuffers=[n.createFramebuffer({width:s.cols,height:s.rows,attachments:3}),n.createFramebuffer({width:s.cols,height:s.rows,attachments:3})],o.pingPongIndex=0);const v={time:n.secs,frameCount:n.frameCount,width:s.width,height:s.height,cols:s.cols,rows:s.rows,bpm:o.bpm??D},C=new Map;for(const[p,i]of o.compiled.dynamicUpdaters){const u=o.compiled.uniforms.get(p),m=ne(()=>i(v),p,u?.value??0,{onError:o.onDynamicError});C.set(p,m)}const _=p=>{n.setUniform("time",n.frameCount/n.targetFrameRate()),n.setUniform("resolution",[v.cols,v.rows]);for(const[u,m]of C)n.setUniform(u,m);for(const[u,m]of o.compiled.uniforms)m.isDynamic||typeof m.value=="function"||n.setUniform(u,m.value);if(o.compiled.charMapping){const u=o.characterResolver.resolve(o.compiled.charMapping.chars,a.font);n.setUniform("u_charMap",u),n.setUniform("u_charMapSize",u.length)}if(o.compiled.usesCharSource){const u=o.compiled.charMapping?o.compiled.charMapping.chars.length:a.font.characters.length;n.setUniform("u_charSourceCount",u)}p&&(l&&n.setUniform("prevCharColorBuffer",p.textures[1]),f&&n.setUniform("prevCharBuffer",p.textures[0]),h&&n.setUniform("prevCellColorBuffer",p.textures[2]));const i=o.compiled.externalLayers;if(i&&i.size>0&&o.externalLayerMap)for(const[u,m]of i){const b=o.externalLayerMap.get(u);if(!b){console.warn(`[textmode.synth.js] External layer not found: ${u}`);continue}const d=b.getPluginState(w);let M;d?.pingPongBuffers?M=d.pingPongBuffers[d.pingPongIndex].textures:b.drawFramebuffer&&(M=b.drawFramebuffer.textures),M&&(m.usesChar&&n.setUniform(`${m.uniformPrefix}_char`,M[0]),m.usesCharColor&&n.setUniform(`${m.uniformPrefix}_primary`,M[1]),m.usesCellColor&&n.setUniform(`${m.uniformPrefix}_cell`,M[2]))}};if(y&&o.pingPongBuffers){const p=o.pingPongBuffers[o.pingPongIndex],i=o.pingPongBuffers[1-o.pingPongIndex];i.begin(),n.clear(),n.shader(o.shader),_(p),n.rect(s.cols,s.rows),i.end(),c.begin(),n.clear(),n.shader(o.shader),_(p),n.rect(s.cols,s.rows),c.end(),o.pingPongIndex=1-o.pingPongIndex}else c.begin(),n.clear(),n.shader(o.shader),_(null),n.rect(s.cols,s.rows),c.end()})(r,e)),t.registerLayerDisposedHook(re)},uninstall(e,t){const r=[t.layerManager.base,...t.layerManager.all];for(const a of r){const n=a.getPluginState(w);n&&(n.shader?.dispose&&n.shader.dispose(),n.pingPongBuffers&&(n.pingPongBuffers[0].dispose?.(),n.pingPongBuffers[1].dispose?.()))}delete e.bpm,t.removeLayerExtension("synth"),t.removeLayerExtension("bpm"),t.removeLayerExtension("clearSynth")}};g.SynthPlugin=ae,g.SynthSource=S,g.cellColor=e=>{const t=new S;return t._colorSource=e,t},g.char=(e,t)=>{const r=new S;return r._charSource=e,r._charCount=t,r},g.charColor=e=>{const t=new S;return t._colorSource=e,t},g.gradient=function(e){return P.gradient(e)},g.noise=function(e,t){return P.noise(e,t)},g.osc=function(e,t,r){return P.osc(e,t,r)},g.paint=e=>{const t=new S;return t._colorSource=e,t._cellColorSource=e,t},g.setGlobalErrorCallback=function(e){O=e},g.shape=function(e,t,r){return P.shape(e,t,r)},g.solid=function(e,t,r,a){return P.solid(e,t,r,a)},g.src=e=>{const t=P.src;if(!e)return t();const r=new S,a=e.id??`layer_${Date.now()}_${Math.random().toString(36).slice(2,9)}`;return r.addExternalLayerRef({layerId:a,layer:e}),r},g.voronoi=function(e,t,r){return P.voronoi(e,t,r)},Object.defineProperty(g,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "textmode.synth.js",
3
- "version": "1.0.0-beta.5",
3
+ "version": "1.0.0",
4
4
  "description": "Synth engine for textmode.js",
5
5
  "type": "module",
6
6
  "types": "./dist/types/index.d.ts",
@@ -22,21 +22,20 @@
22
22
  "format": "prettier --write \"src/**/*.ts\"",
23
23
  "format:check": "prettier --check \"src/**/*.ts\""
24
24
  },
25
+ "dependencies": {
26
+ "textmode.js": "^0.8.5"
27
+ },
25
28
  "devDependencies": {
26
29
  "@rollup/plugin-terser": "^0.4.4",
27
30
  "@types/node": "^24.5.2",
28
31
  "prettier": "^3.7.4",
29
32
  "terser": "^5.44.0",
30
- "textmode.js": "^0.9.0-beta.2",
31
33
  "typedoc": "^0.28.13",
32
34
  "typedoc-plugin-markdown": "^4.7.0",
33
35
  "typedoc-vitepress-theme": "^1.1.2",
34
36
  "typescript": "~5.8.3",
35
37
  "vite": "^7.1.7"
36
38
  },
37
- "peerDependencies": {
38
- "textmode.js": "^0.9.0-beta.2"
39
- },
40
39
  "repository": {
41
40
  "type": "git",
42
41
  "url": "git+https://github.com/humanbydefinition/textmode.synth.js.git"