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 +4 -1
- package/dist/textmode.synth.esm.js +11 -11
- package/dist/textmode.synth.umd.js +1 -1
- package/package.json +4 -5
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.
|
|
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" },
|
|
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" },
|
|
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,
|
|
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
|
|
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}`),
|
|
836
|
+
const Y = this._processArguments(g.userArgs, _.inputs, `${r}_${c}_${g.name}`), A = e.nestedSources.get(c);
|
|
837
837
|
let z;
|
|
838
|
-
|
|
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 =
|
|
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 =
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
|
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"
|