@sarmal/core 0.5.0 → 0.7.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/dist/auto-init.cjs +174 -40
- package/dist/auto-init.cjs.map +1 -1
- package/dist/auto-init.js +174 -40
- package/dist/auto-init.js.map +1 -1
- package/dist/index.cjs +278 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -12
- package/dist/index.d.ts +52 -12
- package/dist/index.js +278 -41
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/engine.ts","../src/renderer.ts","../src/renderer-svg.ts","../src/curves.ts","../src/index.ts"],"names":["options","TRAIL_FADE_CURVE","TRAIL_MAX_OPACITY","TRAIL_MIN_WIDTH","TRAIL_MAX_WIDTH","DEFAULT_SKELETON_OPACITY","FIT_PADDING","skeleton","TWO_PI"],"mappings":";;;AAEA,IAAM,MAAA,GAAS,KAAK,EAAA,GAAK,CAAA;AACzB,IAAM,sBAAA,GAAyB,EAAA;AAS/B,IAAM,iBAAN,MAAqB;AAAA,EAOnB,YAAY,QAAA,EAAkB;AAH9B,IAAA,IAAA,CAAQ,IAAA,GAAe,CAAA;AACvB,IAAA,IAAA,CAAQ,KAAA,GAAgB,CAAA;AAGtB,IAAA,IAAA,CAAK,QAAA,GAAW,QAAA;AAChB,IAAA,IAAA,CAAK,IAAA,GAAO,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,QAAA,EAAS,EAAG,OAAO,EAAE,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,GAAE,CAAE,CAAA;AACnE,IAAA,IAAA,CAAK,MAAA,GAAS,KAAA,CAAM,IAAA,CAAK,EAAE,MAAA,EAAQ,QAAA,EAAS,EAAG,OAAO,EAAE,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,GAAE,CAAE,CAAA;AAAA,EACvE;AAAA;AAAA,EAGA,IAAA,CAAK,GAAW,CAAA,EAAiB;AAC/B,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,IAAA,CAAK,IAAI,CAAA;AAEhC,IAAA,IAAA,CAAK,CAAA,GAAI,CAAA;AACT,IAAA,IAAA,CAAK,CAAA,GAAI,CAAA;AACT,IAAA,IAAA,CAAK,IAAA,GAAA,CAAQ,IAAA,CAAK,IAAA,GAAO,CAAA,IAAK,IAAA,CAAK,QAAA;AAEnC,IAAA,IAAI,IAAA,CAAK,KAAA,GAAQ,IAAA,CAAK,QAAA,EAAU;AAC9B,MAAA,IAAA,CAAK,KAAA,EAAA;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAA,GAAwB;AACtB,IAAA,MAAM,QAAQ,IAAA,CAAK,KAAA,GAAQ,IAAA,CAAK,QAAA,GAAW,IAAI,IAAA,CAAK,IAAA;AAEpD,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,OAAO,CAAA,EAAA,EAAK;AACnC,MAAA,MAAM,MAAM,IAAA,CAAK,IAAA,CAAA,CAAM,KAAA,GAAQ,CAAA,IAAK,KAAK,QAAQ,CAAA;AACjD,MAAA,MAAM,GAAA,GAAM,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA;AACzB,MAAA,GAAA,CAAI,IAAI,GAAA,CAAI,CAAA;AACZ,MAAA,GAAA,CAAI,IAAI,GAAA,CAAI,CAAA;AAAA,IACd;AAEA,IAAA,OAAO,IAAA,CAAK,MAAA;AAAA,EACd;AAAA,EAEA,KAAA,GAAc;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,CAAA;AACZ,IAAA,IAAA,CAAK,KAAA,GAAQ,CAAA;AAAA,EACf;AAAA,EAEA,IAAI,MAAA,GAAS;AACX,IAAA,OAAO,IAAA,CAAK,KAAA;AAAA,EACd;AACF,CAAA;AAcO,SAAS,YAAA,CAAa,QAAA,EAAoB,WAAA,GAAsB,GAAA,EAAa;AAClF,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,MAAM,QAAA,CAAS,IAAA;AAAA,IACf,IAAI,QAAA,CAAS,EAAA;AAAA,IACb,MAAA,EAAQ,SAAS,MAAA,IAAU,MAAA;AAAA,IAC3B,KAAA,EAAO,SAAS,KAAA,IAAS,CAAA;AAAA,IACzB,UAAU,QAAA,CAAS,QAAA;AAAA,IACnB,YAAY,QAAA,CAAS;AAAA,GACvB;AACA,EAAA,MAAM,KAAA,GAAQ,IAAI,cAAA,CAAe,WAAW,CAAA;AAC5C,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,IAAI,UAAA,GAAa,CAAA;AAEjB,EAAA,OAAO;AAAA,IACL,KAAK,SAAA,EAAiC;AACpC,MAAA,CAAA,GAAA,CAAK,CAAA,GAAI,KAAA,CAAM,KAAA,GAAQ,SAAA,IAAa,KAAA,CAAM,MAAA;AAC1C,MAAA,UAAA,IAAc,SAAA;AACd,MAAA,MAAM,QAAQ,KAAA,CAAM,EAAA,CAAG,CAAA,EAAG,UAAA,EAAY,EAAE,CAAA;AACxC,MAAA,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,KAAA,CAAM,CAAC,CAAA;AAC3B,MAAA,OAAO,MAAM,OAAA,EAAQ;AAAA,IACvB,CAAA;AAAA,IAEA,IAAI,UAAA,GAAa;AACf,MAAA,OAAO,KAAA,CAAM,MAAA;AAAA,IACf,CAAA;AAAA,IAEA,IAAI,cAAA,GAAiB;AACnB,MAAA,OAAO,MAAM,QAAA,KAAa,MAAA;AAAA,IAC5B,CAAA;AAAA,IAEA,KAAA,GAAQ;AACN,MAAA,CAAA,GAAI,CAAA;AACJ,MAAA,UAAA,GAAa,CAAA;AACb,MAAA,KAAA,CAAM,KAAA,EAAM;AAAA,IACd,CAAA;AAAA,IAEA,KAAK,IAAA,EAAc,EAAE,aAAa,KAAA,EAAM,GAAiB,EAAC,EAAG;AAC3D,MAAA,CAAA,GAAA,CAAM,IAAA,GAAO,KAAA,CAAM,MAAA,GAAU,KAAA,CAAM,UAAU,KAAA,CAAM,MAAA;AACnD,MAAA,IAAI,UAAA,EAAY;AACd,QAAA,KAAA,CAAM,KAAA,EAAM;AAAA,MACd;AAAA,IACF,CAAA;AAAA,IAEA,aAAA,CACE,OAAA,EACA,EAAE,IAAA,GAAO,KAAA,EAAO,IAAA,GAAO,KAAA,CAAM,MAAA,GAAS,WAAA,EAAY,GAA0B,EAAC,EAC7E;AACA,MAAA,MAAM,OAAA,GAAU,MAAM,KAAA,GAAQ,IAAA;AAC9B,MAAA,MAAM,UAAW,OAAA,GAAU,KAAA,CAAM,MAAA,GAAU,KAAA,CAAM,UAAU,KAAA,CAAM,MAAA;AACjE,MAAA,MAAM,UAAA,GAAa,SAAS,KAAA,CAAM,KAAA;AAElC,MAAA,CAAA,GAAI,MAAA;AACJ,MAAA,UAAA,GAAa,UAAA;AACb,MAAA,KAAA,CAAM,KAAA,EAAM;AAEZ,MAAA,MAAM,eAAA,GAAkB,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,OAAO,CAAA,GAAI,CAAA;AACvD,MAAA,MAAM,QAAQ,IAAA,GAAO,WAAA,GAAc,IAAA,CAAK,GAAA,CAAI,aAAa,eAAe,CAAA;AAExE,MAAA,KAAA,IAAS,CAAA,GAAI,KAAA,GAAQ,CAAA,EAAG,CAAA,IAAK,GAAG,CAAA,EAAA,EAAK;AACnC,QAAA,MAAM,OAAA,GAAU,SAAS,CAAA,GAAI,OAAA;AAC7B,QAAA,MAAM,QAAA,GAAW,OAAA,GAAU,CAAA,GAAI,OAAA,GAAU,MAAM,MAAA,GAAS,OAAA;AACxD,QAAA,MAAM,IAAA,GAAO,aAAa,CAAA,GAAI,IAAA;AAC9B,QAAA,MAAM,QAAQ,KAAA,CAAM,EAAA,CAAG,QAAA,EAAU,IAAA,EAAM,EAAE,CAAA;AAEzC,QAAA,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,KAAA,CAAM,CAAC,CAAA;AAAA,MAC7B;AAAA,IACF,CAAA;AAAA,IAEA,iBAAA,GAAkC;AAChC,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,SAAS,sBAAsB,CAAA;AAE7D,MAAA,MAAM,MAAA,GAAuB,IAAI,KAAA,CAAM,KAAK,CAAA;AAE5C,MAAA,IAAI,MAAM,UAAA,EAAY;AACpB,QAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC9B,UAAA,MAAM,OAAA,GAAW,CAAA,IAAK,KAAA,GAAQ,CAAA,CAAA,GAAM,KAAA,CAAM,MAAA;AAC1C,UAAA,MAAA,CAAO,CAAC,CAAA,GAAI,KAAA,CAAM,UAAA,CAAW,OAAO,CAAA;AAAA,QACtC;AAAA,MACF,CAAA,MAAA,IAAW,KAAA,CAAM,QAAA,KAAa,MAAA,EAAQ;AACpC,QAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC9B,UAAA,MAAM,OAAA,GAAW,CAAA,IAAK,KAAA,GAAQ,CAAA,CAAA,GAAM,KAAA,CAAM,MAAA;AAC1C,UAAA,MAAA,CAAO,CAAC,CAAA,GAAI,KAAA,CAAM,GAAG,OAAA,EAAS,UAAA,EAAY,EAAE,CAAA;AAAA,QAC9C;AAAA,MACF,CAAA,MAAO;AACL,QAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,EAAO,CAAA,EAAA,EAAK;AAC9B,UAAA,MAAM,OAAA,GAAW,CAAA,IAAK,KAAA,GAAQ,CAAA,CAAA,GAAM,KAAA,CAAM,MAAA;AAC1C,UAAA,MAAA,CAAO,CAAC,CAAA,GAAI,KAAA,CAAM,GAAG,OAAA,EAAS,CAAA,EAAG,EAAE,CAAA;AAAA,QACrC;AAAA,MACF;AAEA,MAAA,OAAO,MAAA;AAAA,IACT;AAAA,GACF;AACF;;;ACzKA,IAAM,mBAAA,GAAsB,CAAA;AAG5B,IAAM,iBAAA,GAAoB,EAAA;AAC1B,IAAM,sBAAA,GAAyB,SAAA;AAC/B,IAAM,wBAAA,GAA2B,IAAA;AAGjC,IAAM,WAAA,GAAc,GAAA;AASpB,IAAM,gBAAA,GAAmB,EAAA;AAEzB,IAAM,gBAAA,GAAmB,GAAA;AACzB,IAAM,iBAAA,GAAoB,IAAA;AAE1B,IAAM,eAAA,GAAkB,GAAA;AAExB,IAAM,eAAA,GAAkB,GAAA;AAExB,IAAM,eAAA,GAAkB,GAAA;AAExB,IAAM,oBAAA,GAAuB,IAAA;AAGtB,SAAS,mBAAmB,GAAA,EAAqB;AACtD,EAAA,MAAM,IAAI,QAAA,CAAS,GAAA,CAAI,KAAA,CAAM,CAAC,GAAG,EAAE,CAAA;AACnC,EAAA,OAAO,CAAA,EAAG,KAAK,EAAE,CAAA,CAAA,EAAK,KAAK,CAAA,GAAK,GAAG,CAAA,CAAA,EAAI,CAAA,GAAI,GAAG,CAAA,CAAA;AAChD;AAMO,SAAS,eAAe,OAAA,EAA0C;AACvE,EAAA,MAAM,SAAS,OAAA,CAAQ,MAAA;AACvB,EAAA,IAAI,CAAC,MAAA,CAAO,UAAA,CAAW,IAAI,CAAA,EAAG;AAC5B,IAAA,MAAM,IAAI,MAAM,sCAAsC,CAAA;AAAA,EACxD;AACA,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,UAAA,CAAW,IAAI,CAAA;AAElC,EAAA,MAAM,SAAS,OAAA,CAAQ,MAAA;AACvB,EAAA,MAAM,IAAA,GAAO;AAAA,IACX,aAAA,EAAe,QAAQ,aAAA,IAAiB,sBAAA;AAAA,IACxC,UAAA,EAAY,QAAQ,UAAA,IAAc,SAAA;AAAA,IAClC,SAAA,EAAW,QAAQ,SAAA,IAAa,SAAA;AAAA,IAChC,UAAA,EAAY,QAAQ,UAAA,IAAc,mBAAA;AAAA,IAClC,QAAA,EAAU,QAAQ,QAAA,IAAY;AAAA,GAChC;AAEA,EAAA,MAAM,QAAA,GAAW,kBAAA,CAAmB,IAAA,CAAK,UAAU,CAAA;AACnD,EAAA,MAAM,iBAAiB,CAAA,KAAA,EAAQ,kBAAA,CAAmB,KAAK,SAAS,CAAC,IAAI,oBAAoB,CAAA,CAAA,CAAA;AAEzF,EAAA,IAAI,WAAyB,EAAC;AAC9B,EAAA,IAAI,cAAA,GAAyC,IAAA;AAC7C,EAAA,IAAI,QAAsB,EAAC;AAC3B,EAAA,IAAI,UAAA,GAAa,CAAA;AACjB,EAAA,IAAI,IAAA,GAAqB,IAAA;AACzB,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,IAAI,WAAA,GAA6B,IAAA;AACjC,EAAA,IAAI,QAAA,GAAW,CAAA;AAWf,EAAA,SAAS,mBAAA,GAAsB;AAC7B,IAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AACzB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,GAAQ,SAAS,CAAC,CAAA;AACxB,IAAA,IAAI,IAAA,GAAO,KAAA,CAAM,CAAA,EACf,IAAA,GAAO,KAAA,CAAM,GACb,IAAA,GAAO,KAAA,CAAM,CAAA,EACb,IAAA,GAAO,KAAA,CAAM,CAAA;AACf,IAAA,KAAA,MAAW,KAAK,QAAA,EAAU;AACxB,MAAA,IAAI,CAAA,CAAE,IAAI,IAAA,EAAM;AACd,QAAA,IAAA,GAAO,CAAA,CAAE,CAAA;AAAA,MACX;AAEA,MAAA,IAAI,CAAA,CAAE,IAAI,IAAA,EAAM;AACd,QAAA,IAAA,GAAO,CAAA,CAAE,CAAA;AAAA,MACX;AAEA,MAAA,IAAI,CAAA,CAAE,IAAI,IAAA,EAAM;AACd,QAAA,IAAA,GAAO,CAAA,CAAE,CAAA;AAAA,MACX;AAEA,MAAA,IAAI,CAAA,CAAE,IAAI,IAAA,EAAM;AACd,QAAA,IAAA,GAAO,CAAA,CAAE,CAAA;AAAA,MACX;AAAA,IACF;AAEA,IAAA,MAAM,QAAQ,IAAA,GAAO,IAAA;AACrB,IAAA,MAAM,SAAS,IAAA,GAAO,IAAA;AACtB,IAAA,MAAM,cAAc,MAAA,CAAO,KAAA;AAC3B,IAAA,MAAM,eAAe,MAAA,CAAO,MAAA;AAE5B,IAAA,MAAM,MAAA,GAAS,WAAA,IAAe,KAAA,IAAS,CAAA,GAAI,WAAA,GAAc,CAAA,CAAA,CAAA;AACzD,IAAA,MAAM,MAAA,GAAS,YAAA,IAAgB,MAAA,IAAU,CAAA,GAAI,WAAA,GAAc,CAAA,CAAA,CAAA;AAC3D,IAAA,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,MAAA,EAAQ,MAAM,CAAA;AAE/B,IAAA,MAAM,cAAc,KAAA,GAAQ,KAAA;AAC5B,IAAA,MAAM,eAAe,MAAA,GAAS,KAAA;AAC9B,IAAA,OAAA,GAAA,CAAW,WAAA,GAAc,WAAA,IAAe,CAAA,GAAI,IAAA,GAAO,KAAA;AACnD,IAAA,OAAA,GAAA,CAAW,YAAA,GAAe,YAAA,IAAgB,CAAA,GAAI,IAAA,GAAO,KAAA;AAAA,EACvD;AAMA,EAAA,SAAS,mBAAA,GAAsB;AAC7B,IAAA,IAAI,QAAA,CAAS,SAAS,CAAA,EAAG;AAEzB,IAAA,cAAA,GAAiB,IAAI,eAAA,CAAgB,MAAA,CAAO,KAAA,EAAO,OAAO,MAAM,CAAA;AAChE,IAAA,MAAM,WAAA,GAAc,cAAA,CAAe,UAAA,CAAW,IAAI,CAAA;AAElD,IAAA,WAAA,CAAY,cAAc,CAAA,KAAA,EAAQ,kBAAA,CAAmB,KAAK,aAAa,CAAC,IAAI,wBAAwB,CAAA,CAAA,CAAA;AACpG,IAAA,WAAA,CAAY,SAAA,GAAY,GAAA;AACxB,IAAA,WAAA,CAAY,SAAA,EAAU;AAEtB,IAAA,MAAM,KAAA,GAAQ,SAAS,CAAC,CAAA;AACxB,IAAA,WAAA,CAAY,MAAA,CAAO,MAAM,CAAA,GAAI,KAAA,GAAQ,SAAS,KAAA,CAAM,CAAA,GAAI,QAAQ,OAAO,CAAA;AAEvE,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,QAAA,CAAS,QAAQ,CAAA,EAAA,EAAK;AACxC,MAAA,MAAM,CAAA,GAAI,SAAS,CAAC,CAAA;AACpB,MAAA,WAAA,CAAY,MAAA,CAAO,EAAE,CAAA,GAAI,KAAA,GAAQ,SAAS,CAAA,CAAE,CAAA,GAAI,QAAQ,OAAO,CAAA;AAAA,IACjE;AAEA,IAAA,WAAA,CAAY,MAAA,EAAO;AAAA,EACrB;AAEA,EAAA,SAAS,YAAA,GAAe;AACtB,IAAA,IAAI,IAAA,CAAK,kBAAkB,aAAA,EAAe;AACxC,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,OAAO,cAAA,EAAgB;AAGzB,MAAA,IAAI,QAAA,CAAS,SAAS,CAAA,EAAG;AACvB,QAAA;AAAA,MACF;AAEA,MAAA,GAAA,CAAI,cAAc,CAAA,KAAA,EAAQ,kBAAA,CAAmB,KAAK,aAAa,CAAC,IAAI,wBAAwB,CAAA,CAAA,CAAA;AAC5F,MAAA,GAAA,CAAI,SAAA,GAAY,GAAA;AAChB,MAAA,GAAA,CAAI,SAAA,EAAU;AAEd,MAAA,MAAM,KAAA,GAAQ,SAAS,CAAC,CAAA;AACxB,MAAA,GAAA,CAAI,MAAA,CAAO,MAAM,CAAA,GAAI,KAAA,GAAQ,SAAS,KAAA,CAAM,CAAA,GAAI,QAAQ,OAAO,CAAA;AAE/D,MAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,QAAA,CAAS,QAAQ,CAAA,EAAA,EAAK;AACxC,QAAA,MAAM,CAAA,GAAI,SAAS,CAAC,CAAA;AACpB,QAAA,GAAA,CAAI,MAAA,CAAO,EAAE,CAAA,GAAI,KAAA,GAAQ,SAAS,CAAA,CAAE,CAAA,GAAI,QAAQ,OAAO,CAAA;AAAA,MACzD;AAEA,MAAA,GAAA,CAAI,MAAA,EAAO;AAAA,IACb,WAAW,cAAA,EAAgB;AACzB,MAAA,GAAA,CAAI,SAAA,CAAU,cAAA,EAAgB,CAAA,EAAG,CAAC,CAAA;AAAA,IACpC;AAAA,EACF;AAEA,EAAA,SAAS,SAAA,GAAY;AACnB,IAAA,IAAI,aAAa,CAAA,EAAG;AAClB,MAAA;AAAA,IACF;AAGA,IAAA,GAAA,CAAI,QAAA,GAAW,OAAA;AACf,IAAA,GAAA,CAAI,OAAA,GAAU,OAAA;AAEd,IAAA,KAAA,IAAS,aAAa,CAAA,EAAG,UAAA,GAAa,UAAA,GAAa,CAAA,EAAG,cAAc,gBAAA,EAAkB;AACpF,MAAA,MAAM,OAAO,IAAA,CAAK,GAAA,CAAI,UAAA,GAAa,gBAAA,EAAkB,aAAa,CAAC,CAAA;AAEnE,MAAA,MAAM,QAAA,GAAA,CAAY,UAAA,GAAa,IAAA,IAAQ,CAAA,IAAK,UAAA,GAAa,CAAA,CAAA;AACzD,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,QAAA,EAAU,gBAAgB,CAAA,GAAI,iBAAA;AACrD,MAAA,MAAM,SAAA,GAAY,eAAA,GAAkB,QAAA,IAAY,eAAA,GAAkB,eAAA,CAAA;AAElE,MAAA,GAAA,CAAI,SAAA,EAAU;AACd,MAAA,KAAA,IAAS,CAAA,GAAI,UAAA,EAAY,CAAA,IAAK,IAAA,EAAM,CAAA,EAAA,EAAK;AACvC,QAAA,MAAM,KAAA,GAAQ,MAAM,CAAC,CAAA;AAErB,QAAA,IAAI,MAAM,UAAA,EAAY;AACpB,UAAA,GAAA,CAAI,MAAA,CAAO,MAAM,CAAA,GAAI,KAAA,GAAQ,SAAS,KAAA,CAAM,CAAA,GAAI,QAAQ,OAAO,CAAA;AAAA,QACjE,CAAA,MAAO;AACL,UAAA,GAAA,CAAI,MAAA,CAAO,MAAM,CAAA,GAAI,KAAA,GAAQ,SAAS,KAAA,CAAM,CAAA,GAAI,QAAQ,OAAO,CAAA;AAAA,QACjE;AAAA,MACF;AAOA,MAAA,GAAA,CAAI,WAAA,GAAc,CAAA,KAAA,EAAQ,QAAQ,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA,CAAA;AAC3C,MAAA,GAAA,CAAI,SAAA,GAAY,SAAA;AAChB,MAAA,GAAA,CAAI,MAAA,EAAO;AAAA,IACb;AAAA,EACF;AAEA,EAAA,SAAS,QAAA,GAAW;AAClB,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,CAAA,GAAI,KAAA,GAAQ,OAAA;AAC3B,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,CAAA,GAAI,KAAA,GAAQ,OAAA;AAE3B,IAAA,MAAM,QAAA,GAAW,IAAI,oBAAA,CAAqB,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,IAAA,CAAK,QAAQ,CAAA;AACtE,IAAA,QAAA,CAAS,YAAA,CAAa,CAAA,EAAG,IAAA,CAAK,SAAS,CAAA;AACvC,IAAA,QAAA,CAAS,YAAA,CAAa,iBAAiB,cAAc,CAAA;AACrD,IAAA,QAAA,CAAS,YAAA,CAAa,GAAG,aAAa,CAAA;AAEtC,IAAA,GAAA,CAAI,SAAA,GAAY,QAAA;AAChB,IAAA,GAAA,CAAI,SAAA,EAAU;AACd,IAAA,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA,EAAG,IAAA,CAAK,UAAU,CAAA,EAAG,IAAA,CAAK,KAAK,CAAC,CAAA;AAC3C,IAAA,GAAA,CAAI,IAAA,EAAK;AAET,IAAA,GAAA,CAAI,YAAY,IAAA,CAAK,SAAA;AACrB,IAAA,GAAA,CAAI,SAAA,EAAU;AACd,IAAA,GAAA,CAAI,GAAA,CAAI,GAAG,CAAA,EAAG,IAAA,CAAK,YAAY,CAAA,EAAG,IAAA,CAAK,KAAK,CAAC,CAAA;AAC7C,IAAA,GAAA,CAAI,IAAA,EAAK;AAAA,EACX;AAEA,EAAA,SAAS,MAAA,GAAS;AAChB,IAAA,MAAM,GAAA,GAAM,YAAY,GAAA,EAAI;AAC5B,IAAA,MAAM,YAAY,IAAA,CAAK,GAAA,CAAA,CAAK,MAAM,QAAA,IAAY,GAAA,EAAM,IAAI,EAAE,CAAA;AAC1D,IAAA,QAAA,GAAW,GAAA;AAEX,IAAA,KAAA,GAAQ,MAAA,CAAO,KAAK,SAAS,CAAA;AAC7B,IAAA,UAAA,GAAa,MAAA,CAAO,UAAA;AACpB,IAAA,IAAA,GAAO,UAAA,GAAa,CAAA,GAAI,KAAA,CAAM,UAAA,GAAa,CAAC,CAAA,GAAK,IAAA;AAEjD,IAAA,GAAA,CAAI,UAAU,CAAA,EAAG,CAAA,EAAG,MAAA,CAAO,KAAA,EAAO,OAAO,MAAM,CAAA;AAE/C,IAAA,IAAI,OAAO,cAAA,EAAgB;AAEzB,MAAA,QAAA,GAAW,OAAO,iBAAA,EAAkB;AACpC,MAAA,mBAAA,EAAoB;AAAA,IACtB;AAEA,IAAA,YAAA,EAAa;AACb,IAAA,SAAA,EAAU;AACV,IAAA,QAAA,EAAS;AAET,IAAA,WAAA,GAAc,sBAAsB,MAAM,CAAA;AAAA,EAC5C;AAGA,EAAA,QAAA,GAAW,OAAO,iBAAA,EAAkB;AACpC,EAAA,mBAAA,EAAoB;AAEpB,EAAA,IAAI,CAAC,OAAO,cAAA,EAAgB;AAC1B,IAAA,mBAAA,EAAoB;AAAA,EACtB;AAEA,EAAA,OAAO;AAAA,IACL,KAAA,GAAQ;AACN,MAAA,IAAI,gBAAgB,IAAA,EAAM;AACxB,QAAA;AAAA,MACF;AAEA,MAAA,QAAA,GAAW,YAAY,GAAA,EAAI;AAC3B,MAAA,MAAA,EAAO;AAAA,IACT,CAAA;AAAA,IAEA,IAAA,GAAO;AACL,MAAA,IAAI,gBAAgB,IAAA,EAAM;AACxB,QAAA;AAAA,MACF;AAEA,MAAA,oBAAA,CAAqB,WAAW,CAAA;AAChC,MAAA,WAAA,GAAc,IAAA;AAAA,IAChB,CAAA;AAAA,IAEA,KAAA,GAAQ;AACN,MAAA,MAAA,CAAO,KAAA,EAAM;AACb,MAAA,KAAA,GAAQ,EAAC;AACT,MAAA,IAAA,GAAO,IAAA;AAAA,IACT,CAAA;AAAA,IAEA,OAAA,GAAU;AACR,MAAA,IAAI,gBAAgB,IAAA,EAAM;AACxB,QAAA,oBAAA,CAAqB,WAAW,CAAA;AAChC,QAAA,WAAA,GAAc,IAAA;AAAA,MAChB;AAAA,IACF,CAAA;AAAA,IAEA,IAAA,CAAK,GAAGA,QAAAA,EAAS;AACf,MAAA,MAAA,CAAO,IAAA,CAAK,GAAGA,QAAO,CAAA;AAAA,IACxB,CAAA;AAAA,IAEA,cAAc,CAAA,EAAG;AACf,MAAA,MAAA,CAAO,cAAc,CAAC,CAAA;AAAA,IACxB;AAAA,GACF;AACF;;;ACtTA,IAAM,iBAAA,GAAoB,EAAA;AAE1B,IAAMC,iBAAAA,GAAmB,GAAA;AACzB,IAAMC,kBAAAA,GAAoB,IAAA;AAE1B,IAAMC,gBAAAA,GAAkB,GAAA;AAExB,IAAMC,gBAAAA,GAAkB,GAAA;AACxB,IAAMC,yBAAAA,GAA2B,IAAA;AACjC,IAAM,uBAAA,GAA0B,GAAA;AAChC,IAAM,4BAAA,GAA+B,IAAA;AAErC,IAAMC,YAAAA,GAAc,GAAA;AAEpB,IAAI,aAAA,GAAgB,CAAA;AAyBpB,SAAS,GAAG,GAAA,EAAyB;AACnC,EAAA,OAAO,QAAA,CAAS,eAAA,CAAgB,4BAAA,EAA8B,GAAG,CAAA;AACnE;AAMO,SAAS,kBAAkB,OAAA,EAA6C;AAC7E,EAAA,MAAM,EAAE,SAAA,EAAW,MAAA,EAAO,GAAI,OAAA;AAC9B,EAAA,MAAM,IAAA,GAAO;AAAA,IACX,aAAA,EAAe,QAAQ,aAAA,IAAiB,SAAA;AAAA,IACxC,UAAA,EAAY,QAAQ,UAAA,IAAc,SAAA;AAAA,IAClC,SAAA,EAAW,QAAQ,SAAA,IAAa,SAAA;AAAA,IAChC,UAAA,EAAY,QAAQ,UAAA,IAAc,CAAA;AAAA,IAClC,QAAA,EAAU,QAAQ,QAAA,IAAY,EAAA;AAAA,IAC9B,SAAA,EAAW,QAAQ,SAAA,IAAa;AAAA,GAClC;AAGA,EAAA,MAAM,MAAM,EAAE,aAAA;AACd,EAAA,MAAM,UAAA,GAAa,eAAe,GAAG,CAAA,CAAA;AAErC,EAAA,MAAM,IAAA,GAAO,UAAU,qBAAA,EAAsB;AAC7C,EAAA,MAAM,KAAA,GAAQ,KAAK,KAAA,IAAS,GAAA;AAC5B,EAAA,MAAM,MAAA,GAAS,KAAK,MAAA,IAAU,GAAA;AAE9B,EAAA,MAAM,GAAA,GAAM,GAAG,KAAK,CAAA;AACpB,EAAA,GAAA,CAAI,YAAA,CAAa,OAAA,EAAS,MAAA,CAAO,KAAK,CAAC,CAAA;AACvC,EAAA,GAAA,CAAI,YAAA,CAAa,QAAA,EAAU,MAAA,CAAO,MAAM,CAAC,CAAA;AACzC,EAAA,GAAA,CAAI,aAAa,SAAA,EAAW,CAAA,IAAA,EAAO,KAAK,CAAA,CAAA,EAAI,MAAM,CAAA,CAAE,CAAA;AACpD,EAAA,GAAA,CAAI,YAAA,CAAa,QAAQ,KAAK,CAAA;AAC9B,EAAA,GAAA,CAAI,YAAA,CAAa,YAAA,EAAc,IAAA,CAAK,SAAS,CAAA;AAE7C,EAAA,MAAM,OAAA,GAAU,GAAG,OAAO,CAAA;AAC1B,EAAA,OAAA,CAAQ,cAAc,IAAA,CAAK,SAAA;AAC3B,EAAA,GAAA,CAAI,YAAY,OAAO,CAAA;AAEvB,EAAA,MAAM,IAAA,GAAO,GAAG,MAAM,CAAA;AACtB,EAAA,MAAM,QAAA,GAAW,GAAG,gBAAgB,CAAA;AACpC,EAAA,QAAA,CAAS,EAAA,GAAK,UAAA;AACd,EAAA,QAAA,CAAS,YAAA,CAAa,MAAM,KAAK,CAAA;AACjC,EAAA,QAAA,CAAS,YAAA,CAAa,MAAM,KAAK,CAAA;AACjC,EAAA,QAAA,CAAS,YAAA,CAAa,KAAK,KAAK,CAAA;AAChC,EAAA,MAAM,KAAA,GAAQ,GAAG,MAAM,CAAA;AACvB,EAAA,KAAA,CAAM,YAAA,CAAa,UAAU,IAAI,CAAA;AACjC,EAAA,KAAA,CAAM,YAAA,CAAa,YAAA,EAAc,IAAA,CAAK,SAAS,CAAA;AAC/C,EAAA,KAAA,CAAM,YAAA,CAAa,gBAAgB,GAAG,CAAA;AACtC,EAAA,MAAM,OAAA,GAAU,GAAG,MAAM,CAAA;AACzB,EAAA,OAAA,CAAQ,YAAA,CAAa,QAAA,EAAU,CAAA,EAAG,uBAAA,GAA0B,GAAG,CAAA,CAAA,CAAG,CAAA;AAClE,EAAA,OAAA,CAAQ,YAAA,CAAa,YAAA,EAAc,IAAA,CAAK,SAAS,CAAA;AACjD,EAAA,OAAA,CAAQ,YAAA,CAAa,cAAA,EAAgB,MAAA,CAAO,4BAA4B,CAAC,CAAA;AACzE,EAAA,MAAM,KAAA,GAAQ,GAAG,MAAM,CAAA;AACvB,EAAA,KAAA,CAAM,YAAA,CAAa,UAAU,MAAM,CAAA;AACnC,EAAA,KAAA,CAAM,YAAA,CAAa,YAAA,EAAc,IAAA,CAAK,SAAS,CAAA;AAC/C,EAAA,KAAA,CAAM,YAAA,CAAa,gBAAgB,GAAG,CAAA;AACtC,EAAA,QAAA,CAAS,MAAA,CAAO,KAAA,EAAO,OAAA,EAAS,KAAK,CAAA;AACrC,EAAA,IAAA,CAAK,YAAY,QAAQ,CAAA;AACzB,EAAA,GAAA,CAAI,YAAY,IAAI,CAAA;AAEpB,EAAA,MAAM,YAAA,GAAe,GAAG,MAAM,CAAA;AAC9B,EAAA,YAAA,CAAa,YAAA,CAAa,QAAQ,MAAM,CAAA;AACxC,EAAA,YAAA,CAAa,YAAA,CAAa,QAAA,EAAU,IAAA,CAAK,aAAa,CAAA;AACtD,EAAA,YAAA,CAAa,YAAA,CAAa,gBAAA,EAAkB,MAAA,CAAOD,yBAAwB,CAAC,CAAA;AAC5E,EAAA,YAAA,CAAa,YAAA,CAAa,gBAAgB,KAAK,CAAA;AAC/C,EAAA,GAAA,CAAI,YAAY,YAAY,CAAA;AAE5B,EAAA,MAAM,aAA+B,EAAC;AACtC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,iBAAA,EAAmB,CAAA,EAAA,EAAK;AAC1C,IAAA,MAAM,IAAA,GAAO,GAAG,MAAM,CAAA;AACtB,IAAA,IAAA,CAAK,YAAA,CAAa,QAAQ,MAAM,CAAA;AAChC,IAAA,IAAA,CAAK,YAAA,CAAa,QAAA,EAAU,IAAA,CAAK,UAAU,CAAA;AAC3C,IAAA,IAAA,CAAK,YAAA,CAAa,kBAAkB,OAAO,CAAA;AAC3C,IAAA,IAAA,CAAK,YAAA,CAAa,mBAAmB,OAAO,CAAA;AAC5C,IAAA,GAAA,CAAI,YAAY,IAAI,CAAA;AACpB,IAAA,UAAA,CAAW,KAAK,IAAI,CAAA;AAAA,EACtB;AAEA,EAAA,MAAM,UAAA,GAAa,GAAG,QAAQ,CAAA;AAC9B,EAAA,UAAA,CAAW,YAAA,CAAa,MAAA,EAAQ,CAAA,KAAA,EAAQ,UAAU,CAAA,CAAA,CAAG,CAAA;AACrD,EAAA,UAAA,CAAW,YAAA,CAAa,GAAA,EAAK,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAC,CAAA;AAClD,EAAA,GAAA,CAAI,YAAY,UAAU,CAAA;AAE1B,EAAA,MAAM,UAAA,GAAa,GAAG,QAAQ,CAAA;AAC9B,EAAA,UAAA,CAAW,YAAA,CAAa,MAAA,EAAQ,IAAA,CAAK,SAAS,CAAA;AAC9C,EAAA,UAAA,CAAW,YAAA,CAAa,GAAA,EAAK,MAAA,CAAO,IAAA,CAAK,UAAU,CAAC,CAAA;AACpD,EAAA,GAAA,CAAI,YAAY,UAAU,CAAA;AAE1B,EAAA,SAAA,CAAU,YAAY,GAAG,CAAA;AAEzB,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,IAAI,OAAA,GAAU,CAAA;AAEd,EAAA,SAAS,oBAAoBE,SAAAA,EAAmB;AAC9C,IAAA,IAAIA,SAAAA,CAAS,WAAW,CAAA,EAAG;AACzB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,KAAA,GAAQA,UAAS,CAAC,CAAA;AACxB,IAAA,IAAI,IAAA,GAAO,KAAA,CAAM,CAAA,EACf,IAAA,GAAO,KAAA,CAAM,GACb,IAAA,GAAO,KAAA,CAAM,CAAA,EACb,IAAA,GAAO,KAAA,CAAM,CAAA;AAEf,IAAA,KAAA,MAAW,KAAKA,SAAAA,EAAU;AACxB,MAAA,IAAI,CAAA,CAAE,IAAI,IAAA,EAAM;AACd,QAAA,IAAA,GAAO,CAAA,CAAE,CAAA;AAAA,MACX;AAEA,MAAA,IAAI,CAAA,CAAE,IAAI,IAAA,EAAM;AACd,QAAA,IAAA,GAAO,CAAA,CAAE,CAAA;AAAA,MACX;AAEA,MAAA,IAAI,CAAA,CAAE,IAAI,IAAA,EAAM;AACd,QAAA,IAAA,GAAO,CAAA,CAAE,CAAA;AAAA,MACX;AAEA,MAAA,IAAI,CAAA,CAAE,IAAI,IAAA,EAAM;AACd,QAAA,IAAA,GAAO,CAAA,CAAE,CAAA;AAAA,MACX;AAAA,IACF;AAEA,IAAA,MAAM,IAAI,IAAA,GAAO,IAAA;AACjB,IAAA,MAAM,IAAI,IAAA,GAAO,IAAA;AACjB,IAAA,MAAM,MAAA,GAAS,KAAA,IAAS,CAAA,IAAK,CAAA,GAAID,YAAAA,GAAc,CAAA,CAAA,CAAA;AAC/C,IAAA,MAAM,MAAA,GAAS,MAAA,IAAU,CAAA,IAAK,CAAA,GAAIA,YAAAA,GAAc,CAAA,CAAA,CAAA;AAEhD,IAAA,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,MAAA,EAAQ,MAAM,CAAA;AAC/B,IAAA,OAAA,GAAA,CAAW,KAAA,GAAQ,CAAA,GAAI,KAAA,IAAS,CAAA,GAAI,IAAA,GAAO,KAAA;AAC3C,IAAA,OAAA,GAAA,CAAW,MAAA,GAAS,CAAA,GAAI,KAAA,IAAS,CAAA,GAAI,IAAA,GAAO,KAAA;AAAA,EAC9C;AAGA,EAAA,SAAS,GAAG,CAAA,EAAU;AACpB,IAAA,OAAA,CAAQ,CAAA,CAAE,CAAA,GAAI,KAAA,GAAQ,OAAA,EAAS,QAAQ,CAAC,CAAA;AAAA,EAC1C;AACA,EAAA,SAAS,GAAG,CAAA,EAAU;AACpB,IAAA,OAAA,CAAQ,CAAA,CAAE,CAAA,GAAI,KAAA,GAAQ,OAAA,EAAS,QAAQ,CAAC,CAAA;AAAA,EAC1C;AAEA,EAAA,SAAS,eAAeC,SAAAA,EAAmB;AACzC,IAAA,IAAIA,SAAAA,CAAS,SAAS,CAAA,EAAG;AACvB,MAAA,YAAA,CAAa,YAAA,CAAa,KAAK,EAAE,CAAA;AACjC,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,CAAA,GAAI,CAAA,CAAA,EAAI,EAAA,CAAGA,SAAAA,CAAS,CAAC,CAAE,CAAC,CAAA,CAAA,EAAI,EAAA,CAAGA,SAAAA,CAAS,CAAC,CAAE,CAAC,CAAA,CAAA;AAEhD,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAIA,SAAAA,CAAS,QAAQ,CAAA,EAAA,EAAK;AACxC,MAAA,CAAA,IAAK,CAAA,EAAA,EAAK,EAAA,CAAGA,SAAAA,CAAS,CAAC,CAAE,CAAC,CAAA,CAAA,EAAI,EAAA,CAAGA,SAAAA,CAAS,CAAC,CAAE,CAAC,CAAA,CAAA;AAAA,IAChD;AACA,IAAA,CAAA,IAAK,IAAA;AAEL,IAAA,YAAA,CAAa,YAAA,CAAa,KAAK,CAAC,CAAA;AAAA,EAClC;AAEA,EAAA,MAAM,QAAA,GAAW,OAAO,iBAAA,EAAkB;AAC1C,EAAA,mBAAA,CAAoB,QAAQ,CAAA;AAE5B,EAAA,IAAI,CAAC,OAAO,cAAA,EAAgB;AAC1B,IAAA,cAAA,CAAe,QAAQ,CAAA;AAAA,EACzB;AAEA,EAAA,SAAS,WAAA,CAAY,OAAgB,UAAA,EAAoB;AACvD,IAAA,IAAI,aAAa,CAAA,EAAG;AAClB,MAAA,KAAA,MAAW,KAAK,UAAA,EAAY;AAC1B,QAAA,CAAA,CAAE,YAAA,CAAa,KAAK,EAAE,CAAA;AAAA,MACxB;AAEA,MAAA;AAAA,IACF;AACA,IAAA,MAAM,SAAA,GAAY,IAAA,CAAK,IAAA,CAAK,UAAA,GAAa,iBAAiB,CAAA;AAE1D,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,iBAAA,EAAmB,CAAA,EAAA,EAAK;AAC1C,MAAA,MAAM,QAAQ,CAAA,GAAI,SAAA;AAClB,MAAA,MAAM,MAAM,IAAA,CAAK,GAAA,CAAI,KAAA,GAAQ,SAAA,EAAW,aAAa,CAAC,CAAA;AACtD,MAAA,IAAI,KAAA,IAAS,aAAa,CAAA,EAAG;AAC3B,QAAA,UAAA,CAAW,CAAC,CAAA,CAAG,YAAA,CAAa,GAAA,EAAK,EAAE,CAAA;AACnC,QAAA;AAAA,MACF;AACA,MAAA,MAAM,QAAA,GAAA,CAAY,KAAA,GAAQ,GAAA,IAAO,CAAA,IAAK,UAAA,GAAa,CAAA,CAAA;AACnD,MAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,CAAI,QAAA,EAAUN,iBAAgB,CAAA,GAAIC,kBAAAA;AACvD,MAAA,MAAM,WAAA,GAAcC,gBAAAA,GAAkB,QAAA,IAAYC,gBAAAA,GAAkBD,gBAAAA,CAAAA;AAEpE,MAAA,IAAI,CAAA,GAAI,CAAA,CAAA,EAAI,EAAA,CAAG,KAAA,CAAM,KAAK,CAAE,CAAC,CAAA,CAAA,EAAI,EAAA,CAAG,KAAA,CAAM,KAAK,CAAE,CAAC,CAAA,CAAA;AAClD,MAAA,KAAA,IAAS,CAAA,GAAI,KAAA,GAAQ,CAAA,EAAG,CAAA,IAAK,KAAK,CAAA,EAAA,EAAK;AACrC,QAAA,CAAA,IAAK,CAAA,EAAA,EAAK,EAAA,CAAG,KAAA,CAAM,CAAC,CAAE,CAAC,CAAA,CAAA,EAAI,EAAA,CAAG,KAAA,CAAM,CAAC,CAAE,CAAC,CAAA,CAAA;AAAA,MAC1C;AAEA,MAAA,UAAA,CAAW,CAAC,CAAA,CAAG,YAAA,CAAa,GAAA,EAAK,CAAC,CAAA;AAClC,MAAA,UAAA,CAAW,CAAC,CAAA,CAAG,YAAA,CAAa,kBAAkB,OAAA,CAAQ,OAAA,CAAQ,CAAC,CAAC,CAAA;AAChE,MAAA,UAAA,CAAW,CAAC,CAAA,CAAG,YAAA,CAAa,gBAAgB,WAAA,CAAY,OAAA,CAAQ,CAAC,CAAC,CAAA;AAAA,IACpE;AAAA,EACF;AAEA,EAAA,SAAS,UAAA,CAAW,OAAgB,UAAA,EAAoB;AACtD,IAAA,IAAI,eAAe,CAAA,EAAG;AACpB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,UAAA,GAAa,CAAC,CAAA;AACjC,IAAA,MAAM,CAAA,GAAI,GAAG,IAAI,CAAA;AACjB,IAAA,MAAM,CAAA,GAAI,GAAG,IAAI,CAAA;AAEjB,IAAA,UAAA,CAAW,YAAA,CAAa,MAAM,CAAC,CAAA;AAC/B,IAAA,UAAA,CAAW,YAAA,CAAa,MAAM,CAAC,CAAA;AAC/B,IAAA,UAAA,CAAW,YAAA,CAAa,MAAM,CAAC,CAAA;AAC/B,IAAA,UAAA,CAAW,YAAA,CAAa,MAAM,CAAC,CAAA;AAAA,EACjC;AAEA,EAAA,IAAI,WAAA,GAA6B,IAAA;AACjC,EAAA,IAAI,QAAA,GAAW,CAAA;AACf,EAAA,MAAM,uBACJ,OAAO,MAAA,KAAW,eAAe,MAAA,CAAO,UAAA,CAAW,kCAAkC,CAAA,CAAE,OAAA;AAEzF,EAAA,SAAS,WAAA,GAAc;AACrB,IAAA,MAAM,GAAA,GAAM,YAAY,GAAA,EAAI;AAC5B,IAAA,MAAM,KAAK,IAAA,CAAK,GAAA,CAAA,CAAK,MAAM,QAAA,IAAY,GAAA,EAAM,IAAI,EAAE,CAAA;AACnD,IAAA,QAAA,GAAW,GAAA;AAEX,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,IAAA,CAAK,EAAE,CAAA;AAC5B,IAAA,MAAM,aAAa,MAAA,CAAO,UAAA;AAE1B,IAAA,IAAI,OAAO,cAAA,EAAgB;AACzB,MAAA,MAAM,YAAA,GAAe,OAAO,iBAAA,EAAkB;AAE9C,MAAA,mBAAA,CAAoB,YAAY,CAAA;AAChC,MAAA,cAAA,CAAe,YAAY,CAAA;AAAA,IAC7B;AAEA,IAAA,WAAA,CAAY,OAAO,UAAU,CAAA;AAC7B,IAAA,UAAA,CAAW,OAAO,UAAU,CAAA;AAE5B,IAAA,IAAI,CAAC,oBAAA,EAAsB;AACzB,MAAA,WAAA,GAAc,sBAAsB,WAAW,CAAA;AAAA,IACjD;AAAA,EACF;AAEA,EAAA,OAAO;AAAA,IACL,KAAA,GAAQ;AACN,MAAA,IAAI,gBAAgB,IAAA,EAAM;AACxB,QAAA;AAAA,MACF;AACA,MAAA,QAAA,GAAW,YAAY,GAAA,EAAI;AAC3B,MAAA,WAAA,EAAY;AAAA,IACd,CAAA;AAAA,IAEA,IAAA,GAAO;AACL,MAAA,IAAI,gBAAgB,IAAA,EAAM;AACxB,QAAA;AAAA,MACF;AACA,MAAA,oBAAA,CAAqB,WAAW,CAAA;AAChC,MAAA,WAAA,GAAc,IAAA;AAAA,IAChB,CAAA;AAAA,IAEA,KAAA,GAAQ;AACN,MAAA,MAAA,CAAO,KAAA,EAAM;AAAA,IACf,CAAA;AAAA,IAEA,OAAA,GAAU;AACR,MAAA,IAAI,gBAAgB,IAAA,EAAM;AACxB,QAAA,oBAAA,CAAqB,WAAW,CAAA;AAChC,QAAA,WAAA,GAAc,IAAA;AAAA,MAChB;AACA,MAAA,GAAA,CAAI,MAAA,EAAO;AAAA,IACb,CAAA;AAAA,IAEA,IAAA,CAAK,GAAGH,QAAAA,EAAS;AACf,MAAA,MAAA,CAAO,IAAA,CAAK,GAAGA,QAAO,CAAA;AAAA,IACxB,CAAA;AAAA,IAEA,cAAc,CAAA,EAAG;AACf,MAAA,MAAA,CAAO,cAAc,CAAC,CAAA;AAAA,IACxB;AAAA,GACF;AACF;AAaO,SAAS,eAAA,CACd,SAAA,EACA,QAAA,EACA,OAAA,EACgB;AAChB,EAAA,MAAM,EAAE,WAAA,EAAa,GAAG,YAAA,EAAa,GAAI,WAAW,EAAC;AACrD,EAAA,MAAM,MAAA,GAAS,YAAA,CAAa,QAAA,EAAU,WAAW,CAAA;AACjD,EAAA,OAAO,kBAAkB,EAAE,SAAA,EAAW,MAAA,EAAQ,GAAG,cAAc,CAAA;AACjE;;;ACjVA,IAAMQ,OAAAA,GAAS,KAAK,EAAA,GAAK,CAAA;AASzB,SAAS,QAAA,CAAS,CAAA,EAAW,KAAA,EAAe,OAAA,EAAwC;AAClF,EAAA,MAAM,CAAA,GAAI,IAAA,EACR,CAAA,GAAI,IAAA,EACJ,EAAA,GAAK,KAAA;AACP,EAAA,MAAM,CAAA,GAAI,KAAK,GAAA,CAAI,CAAC,GAClB,CAAA,GAAI,IAAA,CAAK,IAAI,CAAC,CAAA;AAChB,EAAA,MAAM,KAAA,GAAQ,IAAI,CAAA,GAAI,CAAA;AACtB,EAAA,OAAO;AAAA,IACL,CAAA,EAAI,CAAA,IAAK,CAAA,GAAI,CAAA,GAAI,KAAM,KAAA,GAAQ,EAAA;AAAA,IAC/B,CAAA,EAAI,CAAA,GAAI,CAAA,IAAK,CAAA,GAAI,IAAI,CAAA,CAAA,GAAM;AAAA,GAC7B;AACF;AAEA,SAAS,YAAA,CAAa,CAAA,EAAW,KAAA,EAAe,OAAA,EAAwC;AACtF,EAAA,MAAM,IAAI,CAAA,GAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,IAAI,GAAG,CAAA;AACvC,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAC,IAAI,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAC,CAAA;AAAA,IACvC,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAC,IAAI,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAC;AAAA,GACzC;AACF;AAEA,SAAS,qBAAqB,CAAA,EAAkB;AAE9C,EAAA,MAAM,CAAA,GAAI,KAAA;AACV,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAC,IAAI,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAC,CAAA;AAAA,IACvC,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAC,IAAI,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAC;AAAA,GACzC;AACF;AAEA,SAAS,OAAA,CAAQ,CAAA,EAAW,KAAA,EAAe,OAAA,EAAwC;AACjF,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA;AACpB,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA;AACpB,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,IAAI,CAAA,GAAI,CAAA;AAAA,IACX,CAAA,EAAG,IAAI,CAAA,GAAI;AAAA,GACb;AACF;AAEA,SAAS,OAAA,CAAQ,CAAA,EAAW,KAAA,EAAe,OAAA,EAAwC;AACjF,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,IAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAC,CAAA;AAAA,IACnC,CAAA,EAAG,IAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAC;AAAA,GACrC;AACF;AAEA,SAAS,KAAA,CAAM,CAAA,EAAW,KAAA,EAAe,OAAA,EAAwC;AAC/E,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAC,CAAA;AACxB,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA;AAAA,IACjB,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAC;AAAA,GACnB;AACF;AAEA,SAAS,KAAA,CAAM,CAAA,EAAW,KAAA,EAAe,OAAA,EAAwC;AAC/E,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAC,CAAA;AACxB,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA;AAAA,IACjB,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAC;AAAA,GACnB;AACF;AAEA,SAAS,WAAA,CAAY,CAAA,EAAW,IAAA,EAAc,OAAA,EAAwC;AACpF,EAAA,MAAM,MAAM,IAAA,GAAO,IAAA;AACnB,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,IAAI,GAAG,CAAA;AAAA,IACvB,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAC;AAAA,GACnB;AACF;AAEA,SAAS,WAAA,CAAY,CAAA,EAAW,IAAA,EAAc,OAAA,EAAwC;AACpF,EAAA,MAAM,MAAM,IAAA,GAAO,IAAA;AACnB,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,IAAI,GAAG,CAAA;AAAA,IACvB,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAC;AAAA,GACnB;AACF;AAEA,SAAS,WAAA,CAAY,CAAA,EAAW,KAAA,EAAe,OAAA,EAAwC;AACrF,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,IAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAC,CAAA;AAAA,IACnC,CAAA,EAAG,IAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAC;AAAA,GACrC;AACF;AAEA,SAAS,IAAA,CAAK,CAAA,EAAW,IAAA,EAAc,OAAA,EAAwC;AAC7E,EAAA,MAAM,IAAI,IAAA,GAAO,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,OAAO,IAAI,CAAA;AAC5C,EAAA,MAAM,CAAA,GAAI,KAAK,GAAA,CAAI,CAAC,GAClB,CAAA,GAAI,IAAA,CAAK,IAAI,CAAC,CAAA;AAChB,EAAA,OAAO;AAAA,IACL,CAAA,EAAG,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,EAAG,CAAC,CAAA;AAAA,IACzC,CAAA,EAAG,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,EAAG,CAAC;AAAA,GAC3C;AACF;AACO,IAAM,MAAA,GAAmC;AAAA,EAC9C,QAAA,EAAU;AAAA,IACR,IAAA,EAAM,YAAA;AAAA,IACN,EAAA,EAAI,QAAA;AAAA,IACJ,MAAA,EAAQA,OAAAA;AAAA,IACR,KAAA,EAAO;AAAA,GACT;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,IAAA,EAAM,aAAA;AAAA,IACN,EAAA,EAAI,YAAA;AAAA,IACJ,MAAA,EAAQA,OAAAA;AAAA,IACR,KAAA,EAAO,GAAA;AAAA,IACP,UAAA,EAAY;AAAA,GACd;AAAA,EACA,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,SAAA;AAAA,IACN,EAAA,EAAI,OAAA;AAAA,IACJ,MAAA,EAAQA,OAAAA;AAAA,IACR,KAAA,EAAO;AAAA,GACT;AAAA,EACA,OAAA,EAAS;AAAA,IACP,IAAA,EAAM,SAAA;AAAA,IACN,EAAA,EAAI,OAAA;AAAA,IACJ,MAAA,EAAQA,OAAAA;AAAA,IACR,KAAA,EAAO;AAAA,GACT;AAAA,EACA,KAAA,EAAO;AAAA,IACL,IAAA,EAAM,YAAA;AAAA,IACN,EAAA,EAAI,KAAA;AAAA,IACJ,MAAA,EAAQA,OAAAA;AAAA,IACR,KAAA,EAAO;AAAA,GACT;AAAA,EACA,KAAA,EAAO;AAAA,IACL,IAAA,EAAM,YAAA;AAAA,IACN,EAAA,EAAI,KAAA;AAAA,IACJ,MAAA,EAAQA,OAAAA;AAAA,IACR,KAAA,EAAO;AAAA,GACT;AAAA,EACA,WAAA,EAAa;AAAA,IACX,IAAA,EAAM,eAAA;AAAA,IACN,EAAA,EAAI,WAAA;AAAA,IACJ,MAAA,EAAQA,OAAAA;AAAA,IACR,KAAA,EAAO,CAAA;AAAA,IACP,QAAA,EAAU;AAAA,GACZ;AAAA,EACA,WAAA,EAAa;AAAA,IACX,IAAA,EAAM,eAAA;AAAA,IACN,EAAA,EAAI,WAAA;AAAA,IACJ,MAAA,EAAQA,OAAAA;AAAA,IACR,KAAA,EAAO,GAAA;AAAA,IACP,QAAA,EAAU;AAAA,GACZ;AAAA,EACA,WAAA,EAAa;AAAA,IACX,IAAA,EAAM,kBAAA;AAAA,IACN,EAAA,EAAI,WAAA;AAAA,IACJ,MAAA,EAAQA,OAAAA;AAAA,IACR,KAAA,EAAO;AAAA,GACT;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,IAAA,EAAM,eAAA;AAAA,IACN,EAAA,EAAI,IAAA;AAAA,IACJ,MAAA,EAAQA,OAAAA;AAAA,IACR,KAAA,EAAO,CAAA;AAAA,IACP,QAAA,EAAU;AAAA;AAEd;;;AC3IO,SAAS,YAAA,CACd,MAAA,EACA,QAAA,EACA,OAAA,EACgB;AAChB,EAAA,MAAM,EAAE,WAAA,EAAa,GAAG,YAAA,EAAa,GAAI,WAAW,EAAC;AACrD,EAAA,MAAM,MAAA,GAAS,YAAA,CAAa,QAAA,EAAU,WAAW,CAAA;AAEjD,EAAA,OAAO,eAAe,EAAE,MAAA,EAAQ,MAAA,EAAQ,GAAG,cAAc,CAAA;AAC3D","file":"index.cjs","sourcesContent":["import type { CurveDef, Engine, Point, SeekOptions, SeekWithTrailOptions } from \"./types\";\n\nconst TWO_PI = Math.PI * 2;\nconst POINTS_PER_PERIOD_UNIT = 50;\n\n/**\n * A fixed-size list of points with first in, last out method\n * The oldest entry is automatically discarded when the list is at capacity\n *\n * Note: `result.length` is *never* changed,\n * so callers use the separate `count` getter to know valid size\n */\nclass CircularBuffer {\n private data: Array<Point>;\n private result: Array<Point>;\n private capacity: number;\n private head: number = 0;\n private count: number = 0;\n\n constructor(capacity: number) {\n this.capacity = capacity;\n this.data = Array.from({ length: capacity }, () => ({ x: 0, y: 0 }));\n this.result = Array.from({ length: capacity }, () => ({ x: 0, y: 0 }));\n }\n\n /** Mutates in-place */\n push(x: number, y: number): void {\n const slot = this.data[this.head]!;\n\n slot.x = x;\n slot.y = y;\n this.head = (this.head + 1) % this.capacity;\n\n if (this.count < this.capacity) {\n this.count++;\n }\n }\n\n /**\n * Copies ordered points into the pre-allocated result buffer and returns it\n * Note: The *same* array reference is returned every call,\n * so `result.length` is also always `capacity`\n */\n toArray(): Array<Point> {\n const start = this.count < this.capacity ? 0 : this.head;\n\n for (let i = 0; i < this.count; i++) {\n const src = this.data[(start + i) % this.capacity]!;\n const dst = this.result[i]!;\n dst.x = src.x;\n dst.y = src.y;\n }\n\n return this.result;\n }\n\n clear(): void {\n this.head = 0;\n this.count = 0;\n }\n\n get length() {\n return this.count;\n }\n}\n\n/**\n * Creates the core simulation engine for a sarmal\n *\n * it runs a clock (time `t`), asks the curve for the current Point position at that time,\n * and remembers the last N positions so the renderer can draw the trail\n *\n * The engine is only responsible for math coordinates,\n * so it is not responsible for drawing or colors\n *\n * @param curveDef A curve definition\n * @param trailLength default: `120`\n */\nexport function createEngine(curveDef: CurveDef, trailLength: number = 120): Engine {\n const curve = {\n name: curveDef.name,\n fn: curveDef.fn,\n period: curveDef.period ?? TWO_PI,\n speed: curveDef.speed ?? 1,\n skeleton: curveDef.skeleton,\n skeletonFn: curveDef.skeletonFn,\n };\n const trail = new CircularBuffer(trailLength);\n let t = 0;\n let actualTime = 0;\n\n return {\n tick(deltaTime: number): Array<Point> {\n t = (t + curve.speed * deltaTime) % curve.period;\n actualTime += deltaTime;\n const point = curve.fn(t, actualTime, {});\n trail.push(point.x, point.y);\n return trail.toArray();\n },\n\n get trailCount() {\n return trail.length;\n },\n\n get isLiveSkeleton() {\n return curve.skeleton === \"live\";\n },\n\n reset() {\n t = 0;\n actualTime = 0;\n trail.clear();\n },\n\n seek(newT: number, { clearTrail = false }: SeekOptions = {}) {\n t = ((newT % curve.period) + curve.period) % curve.period;\n if (clearTrail) {\n trail.clear();\n }\n },\n\n seekWithTrail(\n targetT: number,\n { wrap = false, step = curve.period / trailLength }: SeekWithTrailOptions = {},\n ) {\n const advance = curve.speed * step;\n const target = ((targetT % curve.period) + curve.period) % curve.period;\n const targetTime = target / curve.speed;\n\n t = target;\n actualTime = targetTime;\n trail.clear();\n\n const pointsFromStart = Math.floor(target / advance) + 1;\n const count = wrap ? trailLength : Math.min(trailLength, pointsFromStart);\n\n for (let i = count - 1; i >= 0; i--) {\n const sampleT = target - i * advance;\n const wrappedT = sampleT < 0 ? sampleT + curve.period : sampleT;\n const time = targetTime - i * step;\n const point = curve.fn(wrappedT, time, {});\n\n trail.push(point.x, point.y);\n }\n },\n\n getSarmalSkeleton(): Array<Point> {\n const steps = Math.ceil(curve.period * POINTS_PER_PERIOD_UNIT);\n // oxlint-disable-next-line unicorn/no-new-array -- array is pre-allocated, filled immediately below\n const points: Array<Point> = new Array(steps);\n\n if (curve.skeletonFn) {\n for (let i = 0; i < steps; i++) {\n const sampleT = (i / (steps - 1)) * curve.period;\n points[i] = curve.skeletonFn(sampleT);\n }\n } else if (curve.skeleton === \"live\") {\n for (let i = 0; i < steps; i++) {\n const sampleT = (i / (steps - 1)) * curve.period;\n points[i] = curve.fn(sampleT, actualTime, {});\n }\n } else {\n for (let i = 0; i < steps; i++) {\n const sampleT = (i / (steps - 1)) * curve.period;\n points[i] = curve.fn(sampleT, 0, {});\n }\n }\n\n return points;\n },\n };\n}\n","import type { Point, RendererOptions, SarmalInstance } from \"./types\";\n\nconst DEFAULT_HEAD_RADIUS = 4;\n// TODO: Re-evaluate glow implementation. Current approach looks TERRIBLE!\n// Consider: remove glow entirely, replace with a sharper bloom, or make it opt-in only (default 0).\nconst DEFAULT_GLOW_SIZE = 20;\nconst DEFAULT_SKELETON_COLOR = \"#ffffff\";\nconst DEFAULT_SKELETON_OPACITY = 0.15;\n\n/** Fraction of the bounding box added as padding when fitting the curve to the canvas */\nconst FIT_PADDING = 0.1;\n\n/**\n * The trail is drawn in batches of points\n * Each batch has lower opacity than the one that comes before it\n * (0 = oldest/tail, 1 = newest/head)\n *\n * ! Performance note: Larger batch size = fewer GPU stroke calls per frame\n */\nconst TRAIL_BATCH_SIZE = 20;\n/** Higher values = sharper fade near the tail, more of the trail appears faint */\nconst TRAIL_FADE_CURVE = 1.5;\nconst TRAIL_MAX_OPACITY = 0.88;\n/** Line width of tail */\nconst TRAIL_MIN_WIDTH = 0.5;\n/** Line width of head */\nconst TRAIL_MAX_WIDTH = 2.5;\n\nconst GLOW_INNER_EDGE = 0.4;\n/** Opacity at the inner edge of the glow falloff */\nconst GLOW_FALLOFF_OPACITY = 0.53;\n\n/** Parses a hex color into its \"r,g,b\" string for use in rgba() — called once at init */\nexport function hexToRgbComponents(hex: string): string {\n const n = parseInt(hex.slice(1), 16);\n return `${n >> 16},${(n >> 8) & 255},${n & 255}`;\n}\n\n/**\n * Creates a Canvas 2D renderer for sarmal animations\n * Renders the skeleton, the trail, and the glowing dot\n */\nexport function createRenderer(options: RendererOptions): SarmalInstance {\n const canvas = options.canvas;\n if (!canvas.getContext(\"2d\")) {\n throw new Error(\"Could not get 2d context from canvas\");\n }\n const ctx = canvas.getContext(\"2d\")!;\n\n const engine = options.engine;\n const opts = {\n skeletonColor: options.skeletonColor ?? DEFAULT_SKELETON_COLOR,\n trailColor: options.trailColor ?? \"#ffffff\",\n headColor: options.headColor ?? \"#ffffff\",\n headRadius: options.headRadius ?? DEFAULT_HEAD_RADIUS,\n glowSize: options.glowSize ?? DEFAULT_GLOW_SIZE,\n };\n\n const trailRgb = hexToRgbComponents(opts.trailColor);\n const headRgbFalloff = `rgba(${hexToRgbComponents(opts.headColor)},${GLOW_FALLOFF_OPACITY})`;\n\n let skeleton: Array<Point> = [];\n let skeletonCanvas: OffscreenCanvas | null = null;\n let trail: Array<Point> = [];\n let trailCount = 0;\n let head: Point | null = null;\n let scale = 1;\n let offsetX = 0;\n let offsetY = 0;\n let animationId: number | null = null;\n let lastTime = 0;\n\n /**\n * Computes how to map engine coordinates to canvas pixels\n *\n * Steps are roughly: curve fn -> coordinate point -> (scale + offset) -> pixel\n *\n * 1. Find the bounding box of the skeleton (min/max x/y in coordinates)\n * 2. Compute a scale factor within the bounds into the canvas with padding\n * 3. Compute offsets to center the curve in the canvas\n */\n function calculateBoundaries() {\n if (skeleton.length === 0) {\n return;\n }\n\n const first = skeleton[0]!;\n let minX = first.x,\n maxX = first.x,\n minY = first.y,\n maxY = first.y;\n for (const p of skeleton) {\n if (p.x < minX) {\n minX = p.x;\n }\n\n if (p.x > maxX) {\n maxX = p.x;\n }\n\n if (p.y < minY) {\n minY = p.y;\n }\n\n if (p.y > maxY) {\n maxY = p.y;\n }\n }\n\n const width = maxX - minX;\n const height = maxY - minY;\n const canvasWidth = canvas.width;\n const canvasHeight = canvas.height;\n\n const scaleX = canvasWidth / (width * (1 + FIT_PADDING * 2));\n const scaleY = canvasHeight / (height * (1 + FIT_PADDING * 2));\n scale = Math.min(scaleX, scaleY);\n\n const boundsWidth = width * scale;\n const boundsHeight = height * scale;\n offsetX = (canvasWidth - boundsWidth) / 2 - minX * scale;\n offsetY = (canvasHeight - boundsHeight) / 2 - minY * scale;\n }\n\n /**\n * Draws the skeleton once into an OffscreenCanvas so that every frame\n * only needs a single ctx.drawImage() instead of rebuilding the full path.\n */\n function buildSkeletonCanvas() {\n if (skeleton.length < 2) return;\n\n skeletonCanvas = new OffscreenCanvas(canvas.width, canvas.height);\n const skeletonCtx = skeletonCanvas.getContext(\"2d\")!;\n\n skeletonCtx.strokeStyle = `rgba(${hexToRgbComponents(opts.skeletonColor)},${DEFAULT_SKELETON_OPACITY})`;\n skeletonCtx.lineWidth = 1.5;\n skeletonCtx.beginPath();\n\n const first = skeleton[0]!;\n skeletonCtx.moveTo(first.x * scale + offsetX, first.y * scale + offsetY);\n\n for (let i = 1; i < skeleton.length; i++) {\n const p = skeleton[i]!;\n skeletonCtx.lineTo(p.x * scale + offsetX, p.y * scale + offsetY);\n }\n\n skeletonCtx.stroke();\n }\n\n function drawSkeleton() {\n if (opts.skeletonColor === \"transparent\") {\n return;\n }\n\n if (engine.isLiveSkeleton) {\n // Live skeletons change each frame\n // ! `skeleton` is already updated for this frame in `render()` before `drawSkeleton()` is called\n if (skeleton.length < 2) {\n return;\n }\n\n ctx.strokeStyle = `rgba(${hexToRgbComponents(opts.skeletonColor)},${DEFAULT_SKELETON_OPACITY})`;\n ctx.lineWidth = 1.5;\n ctx.beginPath();\n\n const first = skeleton[0]!;\n ctx.moveTo(first.x * scale + offsetX, first.y * scale + offsetY);\n\n for (let i = 1; i < skeleton.length; i++) {\n const p = skeleton[i]!;\n ctx.lineTo(p.x * scale + offsetX, p.y * scale + offsetY);\n }\n\n ctx.stroke();\n } else if (skeletonCanvas) {\n ctx.drawImage(skeletonCanvas, 0, 0);\n }\n }\n\n function drawTrail() {\n if (trailCount < 2) {\n return;\n }\n\n // Set constant state once outside the batch loop\n ctx.lineJoin = \"round\";\n ctx.lineCap = \"round\";\n\n for (let batchIndex = 0; batchIndex < trailCount - 1; batchIndex += TRAIL_BATCH_SIZE) {\n const bEnd = Math.min(batchIndex + TRAIL_BATCH_SIZE, trailCount - 1);\n /** Normalized position of this batch along the trail (0 = tail, 1 = head) */\n const progress = (batchIndex + bEnd) / 2 / (trailCount - 1);\n const alpha = Math.pow(progress, TRAIL_FADE_CURVE) * TRAIL_MAX_OPACITY;\n const lineWidth = TRAIL_MIN_WIDTH + progress * (TRAIL_MAX_WIDTH - TRAIL_MIN_WIDTH);\n\n ctx.beginPath();\n for (let i = batchIndex; i <= bEnd; i++) {\n const point = trail[i]!;\n\n if (i === batchIndex) {\n ctx.moveTo(point.x * scale + offsetX, point.y * scale + offsetY);\n } else {\n ctx.lineTo(point.x * scale + offsetX, point.y * scale + offsetY);\n }\n }\n\n // ! AI Note\n // FIXME: still allocates a new string every batch every frame (~20x/frame).\n // `trailRgb` avoids re-parsing the hex, but alpha is a continuous float so the full\n // rgba string can't be pre-computed. Fix: discretize alpha into N buckets at init\n // and do a lookup (e.g. trailColors[Math.round(progress * N)]) instead of a template literal.\n ctx.strokeStyle = `rgba(${trailRgb},${alpha})`;\n ctx.lineWidth = lineWidth;\n ctx.stroke();\n }\n }\n\n function drawHead() {\n if (!head) {\n return;\n }\n\n const x = head.x * scale + offsetX;\n const y = head.y * scale + offsetY;\n\n const gradient = ctx.createRadialGradient(x, y, 0, x, y, opts.glowSize);\n gradient.addColorStop(0, opts.headColor);\n gradient.addColorStop(GLOW_INNER_EDGE, headRgbFalloff);\n gradient.addColorStop(1, \"transparent\");\n\n ctx.fillStyle = gradient;\n ctx.beginPath();\n ctx.arc(x, y, opts.glowSize, 0, Math.PI * 2);\n ctx.fill();\n\n ctx.fillStyle = opts.headColor;\n ctx.beginPath();\n ctx.arc(x, y, opts.headRadius, 0, Math.PI * 2);\n ctx.fill();\n }\n\n function render() {\n const now = performance.now();\n const deltaTime = Math.min((now - lastTime) / 1000, 1 / 30);\n lastTime = now;\n\n trail = engine.tick(deltaTime);\n trailCount = engine.trailCount;\n head = trailCount > 0 ? trail[trailCount - 1]! : null;\n\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n\n if (engine.isLiveSkeleton) {\n // ! \"live\" skeletons change shape, so we need to recalculate boundaries each frame\n skeleton = engine.getSarmalSkeleton();\n calculateBoundaries();\n }\n\n drawSkeleton();\n drawTrail();\n drawHead();\n\n animationId = requestAnimationFrame(render);\n }\n\n // Initialize skeleton and offscreen canvas on creation\n skeleton = engine.getSarmalSkeleton();\n calculateBoundaries();\n\n if (!engine.isLiveSkeleton) {\n buildSkeletonCanvas();\n }\n\n return {\n start() {\n if (animationId !== null) {\n return;\n }\n\n lastTime = performance.now();\n render();\n },\n\n stop() {\n if (animationId === null) {\n return;\n }\n\n cancelAnimationFrame(animationId);\n animationId = null;\n },\n\n reset() {\n engine.reset();\n trail = [];\n head = null;\n },\n\n destroy() {\n if (animationId !== null) {\n cancelAnimationFrame(animationId);\n animationId = null;\n }\n },\n\n seek(t, options) {\n engine.seek(t, options);\n },\n\n seekWithTrail(t) {\n engine.seekWithTrail(t);\n },\n };\n}\n","import type { CurveDef, Engine, Point, SarmalInstance } from \"./types\";\nimport { createEngine } from \"./engine\";\n\nconst TRAIL_BATCH_COUNT = 12;\n/** Higher values = sharper fade near the tail */\nconst TRAIL_FADE_CURVE = 1.5;\nconst TRAIL_MAX_OPACITY = 0.88;\n/** Stroke width at the tail */\nconst TRAIL_MIN_WIDTH = 0.5;\n/** Stroke width at the head */\nconst TRAIL_MAX_WIDTH = 2.5;\nconst DEFAULT_SKELETON_OPACITY = 0.15;\nconst DEFAULT_GLOW_INNER_STOP = 0.4;\nconst DEFAULT_GLOW_FALLOFF_OPACITY = 0.53;\n/** Fraction of the bounding box added as padding when auto-fitting the curve */\nconst FIT_PADDING = 0.1;\n\nlet instanceCount = 0;\n\nexport interface SVGRendererOptions {\n /** Container element that will contain the SVG */\n container: Element;\n engine: Engine;\n /** @default '#ffffff' */\n skeletonColor?: string;\n /** @default '#ffffff' */\n trailColor?: string;\n /** @default '#ffffff' */\n headColor?: string;\n /** @default 4 */\n headRadius?: number;\n /** @default 20 */\n glowSize?: number;\n /** @default 'Loading' */\n ariaLabel?: string;\n}\n\nexport interface SVGSarmalOptions extends Omit<SVGRendererOptions, \"container\" | \"engine\"> {\n /** @default 120 */\n trailLength?: number;\n}\n\nfunction el(tag: string): SVGElement {\n return document.createElementNS(\"http://www.w3.org/2000/svg\", tag);\n}\n\n/**\n * Creates a live SVG renderer for sarmal animations\n * The SVG is appended into `container` and updated each frame via **requestAnimationFrame**\n */\nexport function createSVGRenderer(options: SVGRendererOptions): SarmalInstance {\n const { container, engine } = options;\n const opts = {\n skeletonColor: options.skeletonColor ?? \"#ffffff\",\n trailColor: options.trailColor ?? \"#ffffff\",\n headColor: options.headColor ?? \"#ffffff\",\n headRadius: options.headRadius ?? 4,\n glowSize: options.glowSize ?? 20,\n ariaLabel: options.ariaLabel ?? \"Loading\",\n };\n\n // Unique per-instance ID prevents ID collisions of multiple instances\n const uid = ++instanceCount;\n const gradientId = `sarmal-glow-${uid}`;\n\n const rect = container.getBoundingClientRect();\n const width = rect.width || 200;\n const height = rect.height || 200;\n\n const svg = el(\"svg\") as SVGSVGElement;\n svg.setAttribute(\"width\", String(width));\n svg.setAttribute(\"height\", String(height));\n svg.setAttribute(\"viewBox\", `0 0 ${width} ${height}`);\n svg.setAttribute(\"role\", \"img\");\n svg.setAttribute(\"aria-label\", opts.ariaLabel);\n\n const titleEl = el(\"title\");\n titleEl.textContent = opts.ariaLabel;\n svg.appendChild(titleEl);\n\n const defs = el(\"defs\");\n const gradient = el(\"radialGradient\") as SVGRadialGradientElement;\n gradient.id = gradientId;\n gradient.setAttribute(\"cx\", \"50%\");\n gradient.setAttribute(\"cy\", \"50%\");\n gradient.setAttribute(\"r\", \"50%\");\n const stop0 = el(\"stop\");\n stop0.setAttribute(\"offset\", \"0%\");\n stop0.setAttribute(\"stop-color\", opts.headColor);\n stop0.setAttribute(\"stop-opacity\", \"1\");\n const stopMid = el(\"stop\");\n stopMid.setAttribute(\"offset\", `${DEFAULT_GLOW_INNER_STOP * 100}%`);\n stopMid.setAttribute(\"stop-color\", opts.headColor);\n stopMid.setAttribute(\"stop-opacity\", String(DEFAULT_GLOW_FALLOFF_OPACITY));\n const stop1 = el(\"stop\");\n stop1.setAttribute(\"offset\", \"100%\");\n stop1.setAttribute(\"stop-color\", opts.headColor);\n stop1.setAttribute(\"stop-opacity\", \"0\");\n gradient.append(stop0, stopMid, stop1);\n defs.appendChild(gradient);\n svg.appendChild(defs);\n\n const skeletonPath = el(\"path\") as SVGPathElement;\n skeletonPath.setAttribute(\"fill\", \"none\");\n skeletonPath.setAttribute(\"stroke\", opts.skeletonColor);\n skeletonPath.setAttribute(\"stroke-opacity\", String(DEFAULT_SKELETON_OPACITY));\n skeletonPath.setAttribute(\"stroke-width\", \"1.5\");\n svg.appendChild(skeletonPath);\n\n const trailPaths: SVGPathElement[] = [];\n for (let i = 0; i < TRAIL_BATCH_COUNT; i++) {\n const path = el(\"path\") as SVGPathElement;\n path.setAttribute(\"fill\", \"none\");\n path.setAttribute(\"stroke\", opts.trailColor);\n path.setAttribute(\"stroke-linecap\", \"round\");\n path.setAttribute(\"stroke-linejoin\", \"round\");\n svg.appendChild(path);\n trailPaths.push(path);\n }\n\n const glowCircle = el(\"circle\") as SVGCircleElement;\n glowCircle.setAttribute(\"fill\", `url(#${gradientId})`);\n glowCircle.setAttribute(\"r\", String(opts.glowSize));\n svg.appendChild(glowCircle);\n\n const headCircle = el(\"circle\") as SVGCircleElement;\n headCircle.setAttribute(\"fill\", opts.headColor);\n headCircle.setAttribute(\"r\", String(opts.headRadius));\n svg.appendChild(headCircle);\n\n container.appendChild(svg);\n\n let scale = 1;\n let offsetX = 0;\n let offsetY = 0;\n\n function calculateBoundaries(skeleton: Point[]) {\n if (skeleton.length === 0) {\n return;\n }\n\n const first = skeleton[0]!;\n let minX = first.x,\n maxX = first.x,\n minY = first.y,\n maxY = first.y;\n\n for (const p of skeleton) {\n if (p.x < minX) {\n minX = p.x;\n }\n\n if (p.x > maxX) {\n maxX = p.x;\n }\n\n if (p.y < minY) {\n minY = p.y;\n }\n\n if (p.y > maxY) {\n maxY = p.y;\n }\n }\n\n const w = maxX - minX;\n const h = maxY - minY;\n const scaleX = width / (w * (1 + FIT_PADDING * 2));\n const scaleY = height / (h * (1 + FIT_PADDING * 2));\n\n scale = Math.min(scaleX, scaleY);\n offsetX = (width - w * scale) / 2 - minX * scale;\n offsetY = (height - h * scale) / 2 - minY * scale;\n }\n\n // TODO: might avoid code repetition\n function px(p: Point) {\n return (p.x * scale + offsetX).toFixed(2);\n }\n function py(p: Point) {\n return (p.y * scale + offsetY).toFixed(2);\n }\n\n function updateSkeleton(skeleton: Point[]) {\n if (skeleton.length < 2) {\n skeletonPath.setAttribute(\"d\", \"\");\n return;\n }\n\n let d = `M${px(skeleton[0]!)} ${py(skeleton[0]!)}`;\n\n for (let i = 1; i < skeleton.length; i++) {\n d += ` L${px(skeleton[i]!)} ${py(skeleton[i]!)}`;\n }\n d += \" Z\";\n\n skeletonPath.setAttribute(\"d\", d);\n }\n\n const skeleton = engine.getSarmalSkeleton();\n calculateBoundaries(skeleton);\n\n if (!engine.isLiveSkeleton) {\n updateSkeleton(skeleton);\n }\n\n function updateTrail(trail: Point[], trailCount: number) {\n if (trailCount < 2) {\n for (const p of trailPaths) {\n p.setAttribute(\"d\", \"\");\n }\n\n return;\n }\n const batchSize = Math.ceil(trailCount / TRAIL_BATCH_COUNT);\n\n for (let b = 0; b < TRAIL_BATCH_COUNT; b++) {\n const start = b * batchSize;\n const end = Math.min(start + batchSize, trailCount - 1);\n if (start >= trailCount - 1) {\n trailPaths[b]!.setAttribute(\"d\", \"\");\n continue;\n }\n const progress = (start + end) / 2 / (trailCount - 1);\n const opacity = Math.pow(progress, TRAIL_FADE_CURVE) * TRAIL_MAX_OPACITY;\n const strokeWidth = TRAIL_MIN_WIDTH + progress * (TRAIL_MAX_WIDTH - TRAIL_MIN_WIDTH);\n\n let d = `M${px(trail[start]!)} ${py(trail[start]!)}`;\n for (let i = start + 1; i <= end; i++) {\n d += ` L${px(trail[i]!)} ${py(trail[i]!)}`;\n }\n\n trailPaths[b]!.setAttribute(\"d\", d);\n trailPaths[b]!.setAttribute(\"stroke-opacity\", opacity.toFixed(3));\n trailPaths[b]!.setAttribute(\"stroke-width\", strokeWidth.toFixed(2));\n }\n }\n\n function updateHead(trail: Point[], trailCount: number) {\n if (trailCount === 0) {\n return;\n }\n\n const head = trail[trailCount - 1]!;\n const x = px(head);\n const y = py(head);\n\n glowCircle.setAttribute(\"cx\", x);\n glowCircle.setAttribute(\"cy\", y);\n headCircle.setAttribute(\"cx\", x);\n headCircle.setAttribute(\"cy\", y);\n }\n\n let animationId: number | null = null;\n let lastTime = 0;\n const prefersReducedMotion =\n typeof window !== \"undefined\" && window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n\n function renderFrame() {\n const now = performance.now();\n const dt = Math.min((now - lastTime) / 1000, 1 / 30);\n lastTime = now;\n\n const trail = engine.tick(dt);\n const trailCount = engine.trailCount;\n\n if (engine.isLiveSkeleton) {\n const liveSkeleton = engine.getSarmalSkeleton();\n\n calculateBoundaries(liveSkeleton);\n updateSkeleton(liveSkeleton);\n }\n\n updateTrail(trail, trailCount);\n updateHead(trail, trailCount);\n\n if (!prefersReducedMotion) {\n animationId = requestAnimationFrame(renderFrame);\n }\n }\n\n return {\n start() {\n if (animationId !== null) {\n return;\n }\n lastTime = performance.now();\n renderFrame();\n },\n\n stop() {\n if (animationId === null) {\n return;\n }\n cancelAnimationFrame(animationId);\n animationId = null;\n },\n\n reset() {\n engine.reset();\n },\n\n destroy() {\n if (animationId !== null) {\n cancelAnimationFrame(animationId);\n animationId = null;\n }\n svg.remove();\n },\n\n seek(t, options) {\n engine.seek(t, options);\n },\n\n seekWithTrail(t) {\n engine.seekWithTrail(t);\n },\n };\n}\n\n/**\n * Creates a sarmal animation inside a container element using an SVG renderer\n * The SVG is appended to the container and animated via requestAnimationFrame\n *\n * @example\n * ```ts\n * import { createSarmalSVG, curves } from '@sarmal/core'\n * const sarmal = createSarmalSVG(document.getElementById('spinner'), curves.epitrochoid7)\n * sarmal.start()\n * ```\n */\nexport function createSarmalSVG(\n container: Element,\n curveDef: CurveDef,\n options?: SVGSarmalOptions,\n): SarmalInstance {\n const { trailLength, ...rendererOpts } = options ?? {};\n const engine = createEngine(curveDef, trailLength);\n return createSVGRenderer({ container, engine, ...rendererOpts });\n}\n","import type { CurveDef, Point } from \"./types\";\n\nconst TWO_PI = Math.PI * 2;\n\n/**\n * Artemis II free-return lunar trajectory\n * @see https://www.nasa.gov/wp-content/uploads/2025/09/artemis-ii-map-508.pdf\n * a = x-axis asymmetry (widens one lobe),\n * b = y-axis asymmetry,\n * ox = horizontal offset to visually center the shape\n */\nfunction artemis2(t: number, _time: number, _params: Record<string, number>): Point {\n const a = 0.35,\n b = 0.15,\n ox = 0.175;\n const s = Math.sin(t),\n c = Math.cos(t);\n const denom = 1 + s * s;\n return {\n x: (c * (1 + a * c)) / denom - ox,\n y: (s * c * (1 + b * c)) / denom,\n };\n}\n\nfunction epitrochoid7(t: number, _time: number, _params: Record<string, number>): Point {\n const d = 1.0 + 0.55 * Math.sin(t * 0.5);\n return {\n x: 7 * Math.cos(t) - d * Math.cos(7 * t),\n y: 7 * Math.sin(t) - d * Math.sin(7 * t),\n };\n}\n\nfunction epitrochoid7Skeleton(t: number): Point {\n // average of the oscillating range for a stable base shape\n const d = 1.275;\n return {\n x: 7 * Math.cos(t) - d * Math.cos(7 * t),\n y: 7 * Math.sin(t) - d * Math.sin(7 * t),\n };\n}\n\nfunction astroid(t: number, _time: number, _params: Record<string, number>): Point {\n const c = Math.cos(t);\n const s = Math.sin(t);\n return {\n x: c * c * c,\n y: s * s * s,\n };\n}\n\nfunction deltoid(t: number, _time: number, _params: Record<string, number>): Point {\n return {\n x: 2 * Math.cos(t) + Math.cos(2 * t),\n y: 2 * Math.sin(t) - Math.sin(2 * t),\n };\n}\n\nfunction rose5(t: number, _time: number, _params: Record<string, number>): Point {\n const r = Math.cos(5 * t);\n return {\n x: r * Math.cos(t),\n y: r * Math.sin(t),\n };\n}\n\nfunction rose3(t: number, _time: number, _params: Record<string, number>): Point {\n const r = Math.cos(3 * t);\n return {\n x: r * Math.cos(t),\n y: r * Math.sin(t),\n };\n}\n\nfunction lissajous32(t: number, time: number, _params: Record<string, number>): Point {\n const phi = time * 0.45;\n return {\n x: Math.sin(3 * t + phi),\n y: Math.sin(2 * t),\n };\n}\n\nfunction lissajous43(t: number, time: number, _params: Record<string, number>): Point {\n const phi = time * 0.38;\n return {\n x: Math.sin(4 * t + phi),\n y: Math.sin(3 * t),\n };\n}\n\nfunction epicycloid3(t: number, _time: number, _params: Record<string, number>): Point {\n return {\n x: 4 * Math.cos(t) - Math.cos(4 * t),\n y: 4 * Math.sin(t) - Math.sin(4 * t),\n };\n}\n\nfunction lame(t: number, time: number, _params: Record<string, number>): Point {\n const p = 1.75 + 1.25 * Math.sin(time * 0.48);\n const c = Math.cos(t),\n s = Math.sin(t);\n return {\n x: Math.sign(c) * Math.pow(Math.abs(c), p),\n y: Math.sign(s) * Math.pow(Math.abs(s), p),\n };\n}\nexport const curves: Record<string, CurveDef> = {\n artemis2: {\n name: \"Artemis II\",\n fn: artemis2,\n period: TWO_PI,\n speed: 0.7,\n },\n epitrochoid7: {\n name: \"Epitrochoid\",\n fn: epitrochoid7,\n period: TWO_PI,\n speed: 1.4,\n skeletonFn: epitrochoid7Skeleton,\n },\n astroid: {\n name: \"Astroid\",\n fn: astroid,\n period: TWO_PI,\n speed: 1.1,\n },\n deltoid: {\n name: \"Deltoid\",\n fn: deltoid,\n period: TWO_PI,\n speed: 0.9,\n },\n rose5: {\n name: \"Rose (n=5)\",\n fn: rose5,\n period: TWO_PI,\n speed: 1.0,\n },\n rose3: {\n name: \"Rose (n=3)\",\n fn: rose3,\n period: TWO_PI,\n speed: 1.15,\n },\n lissajous32: {\n name: \"Lissajous 3:2\",\n fn: lissajous32,\n period: TWO_PI,\n speed: 2.0,\n skeleton: \"live\",\n },\n lissajous43: {\n name: \"Lissajous 4:3\",\n fn: lissajous43,\n period: TWO_PI,\n speed: 1.8,\n skeleton: \"live\",\n },\n epicycloid3: {\n name: \"Epicycloid (n=3)\",\n fn: epicycloid3,\n period: TWO_PI,\n speed: 0.75,\n },\n lame: {\n name: \"Lamé Curve\",\n fn: lame,\n period: TWO_PI,\n speed: 1.0,\n skeleton: \"live\",\n },\n};\n","export type { SVGRendererOptions, SVGSarmalOptions } from \"./renderer-svg\";\nexport type {\n Point,\n CurveDef,\n Engine,\n SarmalInstance,\n SeekOptions,\n SeekWithTrailOptions,\n RendererOptions,\n SarmalOptions,\n} from \"./types\";\n\nexport { createEngine } from \"./engine\";\nexport { createRenderer } from \"./renderer\";\nexport { createSVGRenderer, createSarmalSVG } from \"./renderer-svg\";\nexport { curves } from \"./curves\";\n\nimport type { CurveDef, SarmalInstance, SarmalOptions } from \"./types\";\nimport { createEngine } from \"./engine\";\nimport { createRenderer } from \"./renderer\";\n\n/**\n * Creates a sarmal animation on a canvas element\n *\n * @example\n * ```ts\n * import { createSarmal, curves } from '@sarmal/core'\n * const sarmal = createSarmal(canvas, curves.artemis2)\n * sarmal.start()\n * ```\n */\nexport function createSarmal(\n canvas: HTMLCanvasElement,\n curveDef: CurveDef,\n options?: SarmalOptions,\n): SarmalInstance {\n const { trailLength, ...rendererOpts } = options ?? {};\n const engine = createEngine(curveDef, trailLength);\n\n return createRenderer({ canvas, engine, ...rendererOpts });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/engine.ts","../src/renderer.ts","../src/renderer-svg.ts","../src/curves.ts","../src/index.ts"],"names":["options","DEFAULT_MORPH_DURATION_MS","TRAIL_FADE_CURVE","TRAIL_MAX_OPACITY","TRAIL_MIN_WIDTH","TRAIL_MAX_WIDTH","DEFAULT_SKELETON_OPACITY","FIT_PADDING","skeleton","scale","offsetX","offsetY","px","py","TWO_PI"],"mappings":"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","file":"index.cjs","sourcesContent":["import type {\n CurveDef,\n Engine,\n MorpStrategy,\n Point,\n SeekOptions,\n SeekWithTrailOptions,\n} from \"./types\";\n\nconst TWO_PI = Math.PI * 2;\nconst POINTS_PER_PERIOD_UNIT = 50;\n\n/**\n * A fixed-size list of points with first in, last out method\n * The oldest entry is automatically discarded when the list is at capacity\n *\n * Note: `result.length` is *never* changed,\n * so callers use the separate `count` getter to know valid size\n */\nclass CircularBuffer {\n private data: Array<Point>;\n private result: Array<Point>;\n private capacity: number;\n private head: number = 0;\n private count: number = 0;\n\n constructor(capacity: number) {\n this.capacity = capacity;\n this.data = Array.from({ length: capacity }, () => ({ x: 0, y: 0 }));\n this.result = Array.from({ length: capacity }, () => ({ x: 0, y: 0 }));\n }\n\n /** Mutates in-place */\n push(x: number, y: number): void {\n const slot = this.data[this.head]!;\n\n slot.x = x;\n slot.y = y;\n this.head = (this.head + 1) % this.capacity;\n\n if (this.count < this.capacity) {\n this.count++;\n }\n }\n\n /**\n * Copies ordered points into the pre-allocated result buffer and returns it\n * Note: The *same* array reference is returned every call,\n * so `result.length` is also always `capacity`\n */\n toArray(): Array<Point> {\n const start = this.count < this.capacity ? 0 : this.head;\n\n for (let i = 0; i < this.count; i++) {\n const src = this.data[(start + i) % this.capacity]!;\n const dst = this.result[i]!;\n dst.x = src.x;\n dst.y = src.y;\n }\n\n return this.result;\n }\n\n clear(): void {\n this.head = 0;\n this.count = 0;\n }\n\n get length() {\n return this.count;\n }\n}\n\n/**\n * Creates the core simulation engine for a sarmal\n *\n * it runs a clock (time `t`), asks the curve for the current Point position at that time,\n * and remembers the last N positions so the renderer can draw the trail\n *\n * The engine is only responsible for math coordinates,\n * so it is not responsible for drawing or colors\n *\n * @param curveDef A curve definition\n * @param trailLength default: `120`\n */\n/** Normalised resolution of a CurveDef, with required fields filled in */\ntype ResolvedCurve = {\n name: string;\n fn: CurveDef[\"fn\"];\n period: number;\n speed: number;\n skeleton?: CurveDef[\"skeleton\"];\n skeletonFn?: CurveDef[\"skeletonFn\"];\n};\n\nfunction resolveCurve(curveDef: CurveDef): ResolvedCurve {\n return {\n name: curveDef.name,\n fn: curveDef.fn,\n period: curveDef.period ?? TWO_PI,\n speed: curveDef.speed ?? 1,\n skeleton: curveDef.skeleton,\n skeletonFn: curveDef.skeletonFn,\n };\n}\n\nexport function createEngine(curveDef: CurveDef, trailLength: number = 120): Engine {\n let curve = resolveCurve(curveDef);\n const trail = new CircularBuffer(trailLength);\n let t = 0;\n let actualTime = 0;\n\n // Morph state which is `null` when not morphing\n let morphCurveB: ResolvedCurve | null = null;\n let _morphAlpha: number | null = null;\n let _morphStrategy: MorpStrategy = \"normalized\";\n\n /** Samples a resolved curve's skeleton at position `sampleT` */\n function sampleSkeleton(c: ResolvedCurve, sampleT: number): Point {\n if (c.skeletonFn) {\n return c.skeletonFn(sampleT);\n }\n if (c.skeleton === \"live\") {\n return c.fn(sampleT, actualTime, {});\n }\n return c.fn(sampleT, 0, {});\n }\n\n return {\n tick(deltaTime: number): Array<Point> {\n t = (t + curve.speed * deltaTime) % curve.period;\n actualTime += deltaTime;\n\n if (morphCurveB !== null && _morphAlpha !== null) {\n const a = curve.fn(t, actualTime, {});\n const tB = _morphStrategy === \"normalized\" ? (t / curve.period) * morphCurveB.period : t;\n const b = morphCurveB.fn(tB, actualTime, {});\n trail.push(a.x + (b.x - a.x) * _morphAlpha, a.y + (b.y - a.y) * _morphAlpha);\n } else {\n const point = curve.fn(t, actualTime, {});\n trail.push(point.x, point.y);\n }\n\n return trail.toArray();\n },\n\n get trailCount() {\n return trail.length;\n },\n\n get isLiveSkeleton() {\n return curve.skeleton === \"live\";\n },\n\n get morphAlpha() {\n return _morphAlpha;\n },\n\n reset() {\n t = 0;\n actualTime = 0;\n trail.clear();\n },\n\n seek(newT: number, { clearTrail = false }: SeekOptions = {}) {\n t = ((newT % curve.period) + curve.period) % curve.period;\n if (clearTrail) {\n trail.clear();\n }\n },\n\n seekWithTrail(\n targetT: number,\n { wrap = false, step = curve.period / trailLength }: SeekWithTrailOptions = {},\n ) {\n const advance = curve.speed * step;\n const target = ((targetT % curve.period) + curve.period) % curve.period;\n const targetTime = target / curve.speed;\n\n t = target;\n actualTime = targetTime;\n trail.clear();\n\n const pointsFromStart = Math.floor(target / advance) + 1;\n const count = wrap ? trailLength : Math.min(trailLength, pointsFromStart);\n\n for (let i = count - 1; i >= 0; i--) {\n const sampleT = target - i * advance;\n const wrappedT = sampleT < 0 ? sampleT + curve.period : sampleT;\n const time = targetTime - i * step;\n const point = curve.fn(wrappedT, time, {});\n\n trail.push(point.x, point.y);\n }\n },\n\n startMorph(target: CurveDef, strategy: MorpStrategy = \"normalized\") {\n const resolvedTarget = resolveCurve(target);\n\n if (morphCurveB !== null && _morphAlpha !== null) {\n const frozenAlpha = _morphAlpha;\n const frozenA = curve;\n const frozenB = morphCurveB;\n const frozenStrategy = _morphStrategy;\n\n curve = {\n ...frozenB,\n fn: (sampleT: number, time: number, params: Record<string, number>) => {\n const a = frozenA.fn(sampleT, time, params);\n const tB =\n frozenStrategy === \"normalized\"\n ? (sampleT / frozenA.period) * frozenB.period\n : sampleT;\n const b = frozenB.fn(tB, time, params);\n return {\n x: a.x + (b.x - a.x) * frozenAlpha,\n y: a.y + (b.y - a.y) * frozenAlpha,\n };\n },\n };\n }\n\n _morphStrategy = strategy;\n morphCurveB = resolvedTarget;\n _morphAlpha = 0;\n },\n\n setMorphAlpha(alpha: number) {\n _morphAlpha = alpha;\n },\n\n completeMorph() {\n if (morphCurveB !== null) {\n // Normalized strategy drives `curveB` at `tB` = `(t / periodA) * periodB`\n // Remap `t` so the trail continues from the same position on `curveB`,\n // not from a raw `t` value that belongs to `curveA`'s smaller range.\n if (_morphStrategy === \"normalized\" && curve.period !== morphCurveB.period) {\n t = (t / curve.period) * morphCurveB.period;\n }\n curve = morphCurveB;\n }\n morphCurveB = null;\n _morphAlpha = null;\n },\n\n getSarmalSkeleton(): Array<Point> {\n const steps = Math.ceil(curve.period * POINTS_PER_PERIOD_UNIT);\n // oxlint-disable-next-line unicorn/no-new-array -- array is pre-allocated, filled immediately below\n const points: Array<Point> = new Array(steps);\n\n if (morphCurveB !== null && _morphAlpha !== null) {\n for (let i = 0; i < steps; i++) {\n const sampleT = (i / (steps - 1)) * curve.period;\n const a = sampleSkeleton(curve, sampleT);\n const tB =\n _morphStrategy === \"normalized\"\n ? (sampleT / curve.period) * morphCurveB.period\n : sampleT;\n const b = sampleSkeleton(morphCurveB, tB);\n\n points[i] = {\n x: a.x + (b.x - a.x) * _morphAlpha,\n y: a.y + (b.y - a.y) * _morphAlpha,\n };\n }\n return points;\n }\n\n for (let i = 0; i < steps; i++) {\n const sampleT = (i / (steps - 1)) * curve.period;\n points[i] = sampleSkeleton(curve, sampleT);\n }\n\n return points;\n },\n };\n}\n","import type { CurveDef, MorphOptions, Point, RendererOptions, SarmalInstance } from \"./types\";\n\nconst DEFAULT_MORPH_DURATION_MS = 300;\nconst DEFAULT_HEAD_RADIUS = 4;\n// TODO: Re-evaluate glow implementation. Current approach looks TERRIBLE!\n// Consider: remove glow entirely, replace with a sharper bloom, or make it opt-in only (default 0).\nconst DEFAULT_GLOW_SIZE = 20;\nconst DEFAULT_SKELETON_COLOR = \"#ffffff\";\nconst DEFAULT_SKELETON_OPACITY = 0.15;\n\n/** Fraction of the bounding box added as padding when fitting the curve to the canvas */\nconst FIT_PADDING = 0.1;\n\n/**\n * The trail is drawn in batches of points\n * Each batch has lower opacity than the one that comes before it\n * (0 = oldest/tail, 1 = newest/head)\n *\n * ! Performance note: Larger batch size = fewer GPU stroke calls per frame\n */\nconst TRAIL_BATCH_SIZE = 20;\n/** Higher values = sharper fade near the tail, more of the trail appears faint */\nconst TRAIL_FADE_CURVE = 1.5;\nconst TRAIL_MAX_OPACITY = 0.88;\n/** Line width of tail */\nconst TRAIL_MIN_WIDTH = 0.5;\n/** Line width of head */\nconst TRAIL_MAX_WIDTH = 2.5;\n\nconst GLOW_INNER_EDGE = 0.4;\n/** Opacity at the inner edge of the glow falloff */\nconst GLOW_FALLOFF_OPACITY = 0.53;\n\n/** Parses a hex color into its \"r,g,b\" string for use in rgba() — called once at init */\nexport function hexToRgbComponents(hex: string): string {\n const n = parseInt(hex.slice(1), 16);\n return `${n >> 16},${(n >> 8) & 255},${n & 255}`;\n}\n\n/**\n * Creates a Canvas 2D renderer for sarmal animations\n * Renders the skeleton, the trail, and the glowing dot\n */\nexport function createRenderer(options: RendererOptions): SarmalInstance {\n const canvas = options.canvas;\n if (!canvas.getContext(\"2d\")) {\n throw new Error(\"Could not get 2d context from canvas\");\n }\n const ctx = canvas.getContext(\"2d\")!;\n\n const engine = options.engine;\n const opts = {\n skeletonColor: options.skeletonColor ?? DEFAULT_SKELETON_COLOR,\n trailColor: options.trailColor ?? \"#ffffff\",\n headColor: options.headColor ?? \"#ffffff\",\n headRadius: options.headRadius ?? DEFAULT_HEAD_RADIUS,\n glowSize: options.glowSize ?? DEFAULT_GLOW_SIZE,\n };\n\n const trailRgb = hexToRgbComponents(opts.trailColor);\n const headRgbFalloff = `rgba(${hexToRgbComponents(opts.headColor)},${GLOW_FALLOFF_OPACITY})`;\n\n let skeleton: Array<Point> = [];\n let skeletonCanvas: OffscreenCanvas | null = null;\n let trail: Array<Point> = [];\n let trailCount = 0;\n let head: Point | null = null;\n let scale = 1;\n let offsetX = 0;\n let offsetY = 0;\n let animationId: number | null = null;\n let lastTime = 0;\n\n let morphResolve: (() => void) | null = null;\n let morphDurationMs = DEFAULT_MORPH_DURATION_MS;\n let morphAlpha = 0;\n let morphBoundsA: { scale: number; offsetX: number; offsetY: number } | null = null;\n let morphBoundsB: { scale: number; offsetX: number; offsetY: number } | null = null;\n\n /**\n * Computes how to map engine coordinates to canvas pixels.\n * Returns the transform values without mutating renderer state.\n *\n * Steps are roughly: curve fn -> coordinate point -> (scale + offset) -> pixel\n *\n * 1. Find the bounding box of the skeleton (min/max x/y in coordinates)\n * 2. Compute a scale factor within the bounds into the canvas with padding\n * 3. Compute offsets to center the curve in the canvas\n */\n function computeBoundaries(\n pts: Array<Point>,\n ): { scale: number; offsetX: number; offsetY: number } | null {\n if (pts.length === 0) return null;\n\n const first = pts[0]!;\n let minX = first.x,\n maxX = first.x,\n minY = first.y,\n maxY = first.y;\n for (const p of pts) {\n if (p.x < minX) minX = p.x;\n if (p.x > maxX) maxX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.y > maxY) maxY = p.y;\n }\n\n const width = maxX - minX;\n const height = maxY - minY;\n const canvasWidth = canvas.width;\n const canvasHeight = canvas.height;\n\n const scaleX = canvasWidth / (width * (1 + FIT_PADDING * 2));\n const scaleY = canvasHeight / (height * (1 + FIT_PADDING * 2));\n const s = Math.min(scaleX, scaleY);\n const boundsWidth = width * s;\n const boundsHeight = height * s;\n return {\n scale: s,\n offsetX: (canvasWidth - boundsWidth) / 2 - minX * s,\n offsetY: (canvasHeight - boundsHeight) / 2 - minY * s,\n };\n }\n\n function calculateBoundaries() {\n const b = computeBoundaries(skeleton);\n if (b) {\n scale = b.scale;\n offsetX = b.offsetX;\n offsetY = b.offsetY;\n }\n }\n\n /**\n * Draws the skeleton once into an OffscreenCanvas so that every frame\n * only needs a single ctx.drawImage() instead of rebuilding the full path.\n */\n function buildSkeletonCanvas() {\n if (skeleton.length < 2) return;\n\n skeletonCanvas = new OffscreenCanvas(canvas.width, canvas.height);\n const skeletonCtx = skeletonCanvas.getContext(\"2d\")!;\n\n skeletonCtx.strokeStyle = `rgba(${hexToRgbComponents(opts.skeletonColor)},${DEFAULT_SKELETON_OPACITY})`;\n skeletonCtx.lineWidth = 1.5;\n skeletonCtx.beginPath();\n\n const first = skeleton[0]!;\n skeletonCtx.moveTo(first.x * scale + offsetX, first.y * scale + offsetY);\n\n for (let i = 1; i < skeleton.length; i++) {\n const p = skeleton[i]!;\n skeletonCtx.lineTo(p.x * scale + offsetX, p.y * scale + offsetY);\n }\n\n skeletonCtx.stroke();\n }\n\n function drawSkeletonPath(pts: Array<Point>, opacity: number) {\n if (pts.length < 2) return;\n ctx.strokeStyle = `rgba(${hexToRgbComponents(opts.skeletonColor)},${opacity})`;\n ctx.lineWidth = 1.5;\n ctx.beginPath();\n ctx.moveTo(pts[0]!.x * scale + offsetX, pts[0]!.y * scale + offsetY);\n for (let i = 1; i < pts.length; i++) {\n ctx.lineTo(pts[i]!.x * scale + offsetX, pts[i]!.y * scale + offsetY);\n }\n ctx.stroke();\n }\n\n function drawSkeleton() {\n if (opts.skeletonColor === \"transparent\") {\n return;\n }\n\n if (engine.morphAlpha !== null) {\n // Draw the live lerped skeleton every frame so it always matches the current\n // scale/offset and correctly tracks live curves that change with actualTime\n drawSkeletonPath(engine.getSarmalSkeleton(), DEFAULT_SKELETON_OPACITY);\n return;\n }\n\n if (engine.isLiveSkeleton) {\n if (skeleton.length < 2) {\n return;\n }\n\n ctx.strokeStyle = `rgba(${hexToRgbComponents(opts.skeletonColor)},${DEFAULT_SKELETON_OPACITY})`;\n ctx.lineWidth = 1.5;\n ctx.beginPath();\n\n const first = skeleton[0]!;\n ctx.moveTo(first.x * scale + offsetX, first.y * scale + offsetY);\n\n for (let i = 1; i < skeleton.length; i++) {\n const p = skeleton[i]!;\n ctx.lineTo(p.x * scale + offsetX, p.y * scale + offsetY);\n }\n\n ctx.stroke();\n } else if (skeletonCanvas) {\n ctx.drawImage(skeletonCanvas, 0, 0);\n }\n }\n\n function drawTrail() {\n if (trailCount < 2) {\n return;\n }\n\n // Set constant state once outside the batch loop\n ctx.lineJoin = \"round\";\n ctx.lineCap = \"round\";\n\n for (let batchIndex = 0; batchIndex < trailCount - 1; batchIndex += TRAIL_BATCH_SIZE) {\n const bEnd = Math.min(batchIndex + TRAIL_BATCH_SIZE, trailCount - 1);\n /** Normalized position of this batch along the trail (0 = tail, 1 = head) */\n const progress = (batchIndex + bEnd) / 2 / (trailCount - 1);\n const alpha = Math.pow(progress, TRAIL_FADE_CURVE) * TRAIL_MAX_OPACITY;\n const lineWidth = TRAIL_MIN_WIDTH + progress * (TRAIL_MAX_WIDTH - TRAIL_MIN_WIDTH);\n\n ctx.beginPath();\n for (let i = batchIndex; i <= bEnd; i++) {\n const point = trail[i]!;\n\n if (i === batchIndex) {\n ctx.moveTo(point.x * scale + offsetX, point.y * scale + offsetY);\n } else {\n ctx.lineTo(point.x * scale + offsetX, point.y * scale + offsetY);\n }\n }\n\n // ! AI Note\n // FIXME: still allocates a new string every batch every frame (~20x/frame).\n // `trailRgb` avoids re-parsing the hex, but alpha is a continuous float so the full\n // rgba string can't be pre-computed. Fix: discretize alpha into N buckets at init\n // and do a lookup (e.g. trailColors[Math.round(progress * N)]) instead of a template literal.\n ctx.strokeStyle = `rgba(${trailRgb},${alpha})`;\n ctx.lineWidth = lineWidth;\n ctx.stroke();\n }\n }\n\n function drawHead() {\n if (!head) {\n return;\n }\n\n const x = head.x * scale + offsetX;\n const y = head.y * scale + offsetY;\n\n const gradient = ctx.createRadialGradient(x, y, 0, x, y, opts.glowSize);\n gradient.addColorStop(0, opts.headColor);\n gradient.addColorStop(GLOW_INNER_EDGE, headRgbFalloff);\n gradient.addColorStop(1, \"transparent\");\n\n ctx.fillStyle = gradient;\n ctx.beginPath();\n ctx.arc(x, y, opts.glowSize, 0, Math.PI * 2);\n ctx.fill();\n\n ctx.fillStyle = opts.headColor;\n ctx.beginPath();\n ctx.arc(x, y, opts.headRadius, 0, Math.PI * 2);\n ctx.fill();\n }\n\n function render() {\n const now = performance.now();\n const deltaTime = Math.min((now - lastTime) / 1000, 1 / 30);\n lastTime = now;\n\n if (engine.morphAlpha !== null) {\n morphAlpha = Math.min(1, morphAlpha + deltaTime / (morphDurationMs / 1000));\n engine.setMorphAlpha(morphAlpha);\n\n // Lerp the coordinate transform smoothly from curveA's space to curveB's space\n if (morphBoundsA && morphBoundsB) {\n const a = morphBoundsA;\n const b = morphBoundsB;\n scale = a.scale + (b.scale - a.scale) * morphAlpha;\n offsetX = a.offsetX + (b.offsetX - a.offsetX) * morphAlpha;\n offsetY = a.offsetY + (b.offsetY - a.offsetY) * morphAlpha;\n }\n\n if (morphAlpha >= 1) {\n engine.completeMorph();\n morphResolve?.();\n morphResolve = null;\n morphAlpha = 0;\n morphBoundsA = null;\n morphBoundsB = null;\n // Coordinate space is already at curveB (morphAlpha was 1); rebuild skeleton cache\n skeleton = engine.getSarmalSkeleton();\n if (!engine.isLiveSkeleton) {\n buildSkeletonCanvas();\n }\n }\n }\n\n trail = engine.tick(deltaTime);\n trailCount = engine.trailCount;\n head = trailCount > 0 ? trail[trailCount - 1]! : null;\n\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n\n if (engine.isLiveSkeleton && engine.morphAlpha === null) {\n skeleton = engine.getSarmalSkeleton();\n calculateBoundaries();\n }\n\n drawSkeleton();\n drawTrail();\n drawHead();\n\n animationId = requestAnimationFrame(render);\n }\n\n // Initialize skeleton and offscreen canvas on creation\n skeleton = engine.getSarmalSkeleton();\n calculateBoundaries();\n\n if (!engine.isLiveSkeleton) {\n buildSkeletonCanvas();\n }\n\n return {\n start() {\n if (animationId !== null) {\n return;\n }\n\n lastTime = performance.now();\n render();\n },\n\n stop() {\n if (animationId === null) {\n return;\n }\n\n cancelAnimationFrame(animationId);\n animationId = null;\n },\n\n reset() {\n engine.reset();\n trail = [];\n head = null;\n },\n\n destroy() {\n if (animationId !== null) {\n cancelAnimationFrame(animationId);\n animationId = null;\n }\n },\n\n seek(t, options) {\n engine.seek(t, options);\n },\n\n seekWithTrail(t) {\n engine.seekWithTrail(t);\n },\n\n morphTo(target: CurveDef, options?: MorphOptions): Promise<void> {\n // On interrupt: snapshot the current visual state so the new morph starts from\n // exactly where things look right now — no jump at the handoff point\n // On interrupt: snapshot current visual state as the starting bounds for the new morph\n const interruptBounds = morphResolve !== null ? { scale, offsetX, offsetY } : null;\n\n if (morphResolve !== null) {\n engine.completeMorph();\n morphResolve();\n morphResolve = null;\n morphAlpha = 0;\n morphBoundsA = null;\n morphBoundsB = null;\n }\n\n morphDurationMs = options?.duration ?? DEFAULT_MORPH_DURATION_MS;\n morphAlpha = 0;\n\n // Compute `curveA`'s bounds from the current skeleton (or use the interrupted visual state)\n morphBoundsA = interruptBounds ??\n computeBoundaries(engine.getSarmalSkeleton()) ?? { scale, offsetX, offsetY };\n\n engine.startMorph(target, options?.morphStrategy);\n\n // Compute `curveB`'s bounds for the boundary lerp\n const period = target.period ?? Math.PI * 2;\n const samples = Math.max(50, Math.round(period * 20));\n const skeletonFn = target.skeletonFn ?? ((t: number) => target.fn(t, 0, {}));\n const skeletonB = Array.from({ length: samples + 1 }, (_, i) =>\n skeletonFn((i / samples) * period),\n );\n morphBoundsB = computeBoundaries(skeletonB) ?? { scale, offsetX, offsetY };\n\n return new Promise<void>((resolve) => {\n morphResolve = resolve;\n });\n },\n };\n}\n","import type { CurveDef, Engine, MorphOptions, Point, SarmalInstance } from \"./types\";\nimport { createEngine } from \"./engine\";\n\nconst DEFAULT_MORPH_DURATION_MS = 300;\nconst TRAIL_BATCH_COUNT = 12;\n/** Higher values = sharper fade near the tail */\nconst TRAIL_FADE_CURVE = 1.5;\nconst TRAIL_MAX_OPACITY = 0.88;\n/** Stroke width at the tail */\nconst TRAIL_MIN_WIDTH = 0.5;\n/** Stroke width at the head */\nconst TRAIL_MAX_WIDTH = 2.5;\nconst DEFAULT_SKELETON_OPACITY = 0.15;\nconst DEFAULT_GLOW_INNER_STOP = 0.4;\nconst DEFAULT_GLOW_FALLOFF_OPACITY = 0.53;\n/** Fraction of the bounding box added as padding when auto-fitting the curve */\nconst FIT_PADDING = 0.1;\n\nlet instanceCount = 0;\n\nexport interface SVGRendererOptions {\n /** Container element that will contain the SVG */\n container: Element;\n engine: Engine;\n /** @default '#ffffff' */\n skeletonColor?: string;\n /** @default '#ffffff' */\n trailColor?: string;\n /** @default '#ffffff' */\n headColor?: string;\n /** @default 4 */\n headRadius?: number;\n /** @default 20 */\n glowSize?: number;\n /** @default 'Loading' */\n ariaLabel?: string;\n}\n\nexport interface SVGSarmalOptions extends Omit<SVGRendererOptions, \"container\" | \"engine\"> {\n /** @default 120 */\n trailLength?: number;\n}\n\nfunction el(tag: string): SVGElement {\n return document.createElementNS(\"http://www.w3.org/2000/svg\", tag);\n}\n\n/**\n * Creates a live SVG renderer for sarmal animations\n * The SVG is appended into `container` and updated each frame via **requestAnimationFrame**\n */\nexport function createSVGRenderer(options: SVGRendererOptions): SarmalInstance {\n const { container, engine } = options;\n const opts = {\n skeletonColor: options.skeletonColor ?? \"#ffffff\",\n trailColor: options.trailColor ?? \"#ffffff\",\n headColor: options.headColor ?? \"#ffffff\",\n headRadius: options.headRadius ?? 4,\n glowSize: options.glowSize ?? 20,\n ariaLabel: options.ariaLabel ?? \"Loading\",\n };\n\n // Unique per-instance ID prevents ID collisions of multiple instances\n const uid = ++instanceCount;\n const gradientId = `sarmal-glow-${uid}`;\n\n const rect = container.getBoundingClientRect();\n const width = rect.width || 200;\n const height = rect.height || 200;\n\n const svg = el(\"svg\") as SVGSVGElement;\n svg.setAttribute(\"width\", String(width));\n svg.setAttribute(\"height\", String(height));\n svg.setAttribute(\"viewBox\", `0 0 ${width} ${height}`);\n svg.setAttribute(\"role\", \"img\");\n svg.setAttribute(\"aria-label\", opts.ariaLabel);\n\n const titleEl = el(\"title\");\n titleEl.textContent = opts.ariaLabel;\n svg.appendChild(titleEl);\n\n const defs = el(\"defs\");\n const gradient = el(\"radialGradient\") as SVGRadialGradientElement;\n gradient.id = gradientId;\n gradient.setAttribute(\"cx\", \"50%\");\n gradient.setAttribute(\"cy\", \"50%\");\n gradient.setAttribute(\"r\", \"50%\");\n const stop0 = el(\"stop\");\n stop0.setAttribute(\"offset\", \"0%\");\n stop0.setAttribute(\"stop-color\", opts.headColor);\n stop0.setAttribute(\"stop-opacity\", \"1\");\n const stopMid = el(\"stop\");\n stopMid.setAttribute(\"offset\", `${DEFAULT_GLOW_INNER_STOP * 100}%`);\n stopMid.setAttribute(\"stop-color\", opts.headColor);\n stopMid.setAttribute(\"stop-opacity\", String(DEFAULT_GLOW_FALLOFF_OPACITY));\n const stop1 = el(\"stop\");\n stop1.setAttribute(\"offset\", \"100%\");\n stop1.setAttribute(\"stop-color\", opts.headColor);\n stop1.setAttribute(\"stop-opacity\", \"0\");\n gradient.append(stop0, stopMid, stop1);\n defs.appendChild(gradient);\n svg.appendChild(defs);\n\n const skeletonPath = el(\"path\") as SVGPathElement;\n skeletonPath.setAttribute(\"fill\", \"none\");\n skeletonPath.setAttribute(\"stroke\", opts.skeletonColor);\n skeletonPath.setAttribute(\"stroke-opacity\", String(DEFAULT_SKELETON_OPACITY));\n skeletonPath.setAttribute(\"stroke-width\", \"1.5\");\n svg.appendChild(skeletonPath);\n\n const skeletonPathA = el(\"path\") as SVGPathElement;\n skeletonPathA.setAttribute(\"fill\", \"none\");\n skeletonPathA.setAttribute(\"stroke\", opts.skeletonColor);\n skeletonPathA.setAttribute(\"stroke-width\", \"1.5\");\n skeletonPathA.setAttribute(\"visibility\", \"hidden\");\n svg.appendChild(skeletonPathA);\n\n const skeletonPathB = el(\"path\") as SVGPathElement;\n skeletonPathB.setAttribute(\"fill\", \"none\");\n skeletonPathB.setAttribute(\"stroke\", opts.skeletonColor);\n skeletonPathB.setAttribute(\"stroke-width\", \"1.5\");\n skeletonPathB.setAttribute(\"visibility\", \"hidden\");\n svg.appendChild(skeletonPathB);\n\n let morphPathABuilt = \"\";\n let morphPathBBuilt = \"\";\n\n const trailPaths: SVGPathElement[] = [];\n for (let i = 0; i < TRAIL_BATCH_COUNT; i++) {\n const path = el(\"path\") as SVGPathElement;\n path.setAttribute(\"fill\", \"none\");\n path.setAttribute(\"stroke\", opts.trailColor);\n path.setAttribute(\"stroke-linecap\", \"round\");\n path.setAttribute(\"stroke-linejoin\", \"round\");\n svg.appendChild(path);\n trailPaths.push(path);\n }\n\n const glowCircle = el(\"circle\") as SVGCircleElement;\n glowCircle.setAttribute(\"fill\", `url(#${gradientId})`);\n glowCircle.setAttribute(\"r\", String(opts.glowSize));\n svg.appendChild(glowCircle);\n\n const headCircle = el(\"circle\") as SVGCircleElement;\n headCircle.setAttribute(\"fill\", opts.headColor);\n headCircle.setAttribute(\"r\", String(opts.headRadius));\n svg.appendChild(headCircle);\n\n container.appendChild(svg);\n\n let scale = 1;\n let offsetX = 0;\n let offsetY = 0;\n\n function calculateBoundaries(skeleton: Point[]) {\n if (skeleton.length === 0) {\n return;\n }\n\n const first = skeleton[0]!;\n let minX = first.x,\n maxX = first.x,\n minY = first.y,\n maxY = first.y;\n\n for (const p of skeleton) {\n if (p.x < minX) {\n minX = p.x;\n }\n\n if (p.x > maxX) {\n maxX = p.x;\n }\n\n if (p.y < minY) {\n minY = p.y;\n }\n\n if (p.y > maxY) {\n maxY = p.y;\n }\n }\n\n const w = maxX - minX;\n const h = maxY - minY;\n const scaleX = width / (w * (1 + FIT_PADDING * 2));\n const scaleY = height / (h * (1 + FIT_PADDING * 2));\n\n scale = Math.min(scaleX, scaleY);\n offsetX = (width - w * scale) / 2 - minX * scale;\n offsetY = (height - h * scale) / 2 - minY * scale;\n }\n\n // TODO: might avoid code repetition\n function px(p: Point) {\n return (p.x * scale + offsetX).toFixed(2);\n }\n function py(p: Point) {\n return (p.y * scale + offsetY).toFixed(2);\n }\n\n function updateSkeleton(skeleton: Point[]) {\n if (skeleton.length < 2) {\n skeletonPath.setAttribute(\"d\", \"\");\n return;\n }\n\n let d = `M${px(skeleton[0]!)} ${py(skeleton[0]!)}`;\n\n for (let i = 1; i < skeleton.length; i++) {\n d += ` L${px(skeleton[i]!)} ${py(skeleton[i]!)}`;\n }\n d += \" Z\";\n\n skeletonPath.setAttribute(\"d\", d);\n }\n\n const skeleton = engine.getSarmalSkeleton();\n calculateBoundaries(skeleton);\n\n if (!engine.isLiveSkeleton) {\n updateSkeleton(skeleton);\n }\n\n function updateTrail(trail: Point[], trailCount: number) {\n if (trailCount < 2) {\n for (const p of trailPaths) {\n p.setAttribute(\"d\", \"\");\n }\n\n return;\n }\n const batchSize = Math.ceil(trailCount / TRAIL_BATCH_COUNT);\n\n for (let b = 0; b < TRAIL_BATCH_COUNT; b++) {\n const start = b * batchSize;\n const end = Math.min(start + batchSize, trailCount - 1);\n if (start >= trailCount - 1) {\n trailPaths[b]!.setAttribute(\"d\", \"\");\n continue;\n }\n const progress = (start + end) / 2 / (trailCount - 1);\n const opacity = Math.pow(progress, TRAIL_FADE_CURVE) * TRAIL_MAX_OPACITY;\n const strokeWidth = TRAIL_MIN_WIDTH + progress * (TRAIL_MAX_WIDTH - TRAIL_MIN_WIDTH);\n\n let d = `M${px(trail[start]!)} ${py(trail[start]!)}`;\n for (let i = start + 1; i <= end; i++) {\n d += ` L${px(trail[i]!)} ${py(trail[i]!)}`;\n }\n\n trailPaths[b]!.setAttribute(\"d\", d);\n trailPaths[b]!.setAttribute(\"stroke-opacity\", opacity.toFixed(3));\n trailPaths[b]!.setAttribute(\"stroke-width\", strokeWidth.toFixed(2));\n }\n }\n\n function updateHead(trail: Point[], trailCount: number) {\n if (trailCount === 0) {\n return;\n }\n\n const head = trail[trailCount - 1]!;\n const x = px(head);\n const y = py(head);\n\n glowCircle.setAttribute(\"cx\", x);\n glowCircle.setAttribute(\"cy\", y);\n headCircle.setAttribute(\"cx\", x);\n headCircle.setAttribute(\"cy\", y);\n }\n\n let animationId: number | null = null;\n let lastTime = 0;\n const prefersReducedMotion =\n typeof window !== \"undefined\" && window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n\n let morphResolve: (() => void) | null = null;\n let morphDurationMs = DEFAULT_MORPH_DURATION_MS;\n let morphTarget: CurveDef | null = null;\n let morphAlpha = 0;\n\n function buildSkeletonPath(\n target: CurveDef,\n scale: number,\n offsetX: number,\n offsetY: number,\n ): string {\n const period = target.period ?? Math.PI * 2;\n const samples = Math.max(50, Math.round(period * 20));\n const points: Point[] = [];\n\n for (let i = 0; i <= samples; i++) {\n const t = (i / samples) * period;\n const p = target.fn(t, 0, {});\n points.push(p);\n }\n\n if (points.length < 2) {\n return \"\";\n }\n\n const px = (p: Point) => (p.x * scale + offsetX).toFixed(2);\n const py = (p: Point) => (p.y * scale + offsetY).toFixed(2);\n let d = `M${px(points[0]!)} ${py(points[0]!)}`;\n\n for (let i = 1; i < points.length; i++) {\n d += ` L${px(points[i]!)} ${py(points[i]!)}`;\n }\n d += \" Z\";\n\n return d;\n }\n\n function renderFrame() {\n const now = performance.now();\n const dt = Math.min((now - lastTime) / 1000, 1 / 30);\n lastTime = now;\n\n if (engine.morphAlpha !== null) {\n morphAlpha = Math.min(1, morphAlpha + dt / (morphDurationMs / 1000));\n engine.setMorphAlpha(morphAlpha);\n\n if (morphPathABuilt) {\n skeletonPathA.setAttribute(\"d\", morphPathABuilt);\n skeletonPathA.setAttribute(\"visibility\", \"visible\");\n skeletonPathA.setAttribute(\n \"stroke-opacity\",\n String((1 - morphAlpha) * DEFAULT_SKELETON_OPACITY),\n );\n }\n\n if (morphPathBBuilt) {\n skeletonPathB.setAttribute(\"d\", morphPathBBuilt);\n skeletonPathB.setAttribute(\"visibility\", \"visible\");\n skeletonPathB.setAttribute(\"stroke-opacity\", String(morphAlpha * DEFAULT_SKELETON_OPACITY));\n }\n\n if (morphAlpha >= 1) {\n engine.completeMorph();\n morphResolve?.();\n morphResolve = null;\n morphTarget = null;\n morphAlpha = 0;\n morphPathABuilt = \"\";\n morphPathBBuilt = \"\";\n skeletonPathA.setAttribute(\"visibility\", \"hidden\");\n skeletonPathB.setAttribute(\"visibility\", \"hidden\");\n // Snap coordinate space to `curveB` and update skeleton path\n const newSkeleton = engine.getSarmalSkeleton();\n calculateBoundaries(newSkeleton);\n updateSkeleton(newSkeleton);\n }\n }\n\n const trail = engine.tick(dt);\n const trailCount = engine.trailCount;\n\n if (engine.isLiveSkeleton && engine.morphAlpha === null) {\n const liveSkeleton = engine.getSarmalSkeleton();\n calculateBoundaries(liveSkeleton);\n updateSkeleton(liveSkeleton);\n }\n\n updateTrail(trail, trailCount);\n updateHead(trail, trailCount);\n\n if (!prefersReducedMotion) {\n animationId = requestAnimationFrame(renderFrame);\n }\n }\n\n return {\n start() {\n if (animationId !== null) {\n return;\n }\n lastTime = performance.now();\n renderFrame();\n },\n\n stop() {\n if (animationId === null) {\n return;\n }\n cancelAnimationFrame(animationId);\n animationId = null;\n },\n\n reset() {\n engine.reset();\n },\n\n destroy() {\n if (animationId !== null) {\n cancelAnimationFrame(animationId);\n animationId = null;\n }\n svg.remove();\n },\n\n seek(t, options) {\n engine.seek(t, options);\n },\n\n seekWithTrail(t) {\n engine.seekWithTrail(t);\n },\n\n morphTo(target: CurveDef, options?: MorphOptions): Promise<void> {\n if (morphResolve !== null) {\n engine.completeMorph();\n morphResolve();\n morphResolve = null;\n morphAlpha = 0;\n skeletonPathA.setAttribute(\"visibility\", \"hidden\");\n skeletonPathB.setAttribute(\"visibility\", \"hidden\");\n }\n\n morphDurationMs = options?.duration ?? DEFAULT_MORPH_DURATION_MS;\n morphTarget = target;\n morphAlpha = 0;\n\n const currentSkeleton = engine.getSarmalSkeleton();\n if (currentSkeleton.length >= 2) {\n const px = (p: Point) => (p.x * scale + offsetX).toFixed(2);\n const py = (p: Point) => (p.y * scale + offsetY).toFixed(2);\n morphPathABuilt = `M${px(currentSkeleton[0]!)} ${py(currentSkeleton[0]!)}`;\n for (let i = 1; i < currentSkeleton.length; i++) {\n morphPathABuilt += ` L${px(currentSkeleton[i]!)} ${py(currentSkeleton[i]!)}`;\n }\n morphPathABuilt += \" Z\";\n } else {\n morphPathABuilt = \"\";\n }\n\n engine.startMorph(target, options?.morphStrategy);\n\n if (morphTarget) {\n morphPathBBuilt = buildSkeletonPath(morphTarget, scale, offsetX, offsetY);\n }\n\n return new Promise<void>((resolve) => {\n morphResolve = resolve;\n });\n },\n };\n}\n\n/**\n * Creates a sarmal animation inside a container element using an SVG renderer\n * The SVG is appended to the container and animated via requestAnimationFrame\n *\n * @example\n * ```ts\n * import { createSarmalSVG, curves } from '@sarmal/core'\n * const sarmal = createSarmalSVG(document.getElementById('spinner'), curves.epitrochoid7)\n * sarmal.start()\n * ```\n */\nexport function createSarmalSVG(\n container: Element,\n curveDef: CurveDef,\n options?: SVGSarmalOptions,\n): SarmalInstance {\n const { trailLength, ...rendererOpts } = options ?? {};\n const engine = createEngine(curveDef, trailLength);\n return createSVGRenderer({ container, engine, ...rendererOpts });\n}\n","import type { CurveDef, Point } from \"./types\";\n\nconst TWO_PI = Math.PI * 2;\n\n/**\n * Artemis II free-return lunar trajectory\n * @see https://www.nasa.gov/wp-content/uploads/2025/09/artemis-ii-map-508.pdf\n * a = x-axis asymmetry (widens one lobe),\n * b = y-axis asymmetry,\n * ox = horizontal offset to visually center the shape\n */\nfunction artemis2(t: number, _time: number, _params: Record<string, number>): Point {\n const a = 0.35,\n b = 0.15,\n ox = 0.175;\n const s = Math.sin(t),\n c = Math.cos(t);\n const denom = 1 + s * s;\n return {\n x: (c * (1 + a * c)) / denom - ox,\n y: (s * c * (1 + b * c)) / denom,\n };\n}\n\nfunction epitrochoid7(t: number, _time: number, _params: Record<string, number>): Point {\n const d = 1.0 + 0.55 * Math.sin(t * 0.5);\n return {\n x: 7 * Math.cos(t) - d * Math.cos(7 * t),\n y: 7 * Math.sin(t) - d * Math.sin(7 * t),\n };\n}\n\nfunction epitrochoid7Skeleton(t: number): Point {\n // average of the oscillating range for a stable base shape\n const d = 1.275;\n return {\n x: 7 * Math.cos(t) - d * Math.cos(7 * t),\n y: 7 * Math.sin(t) - d * Math.sin(7 * t),\n };\n}\n\nfunction astroid(t: number, _time: number, _params: Record<string, number>): Point {\n const c = Math.cos(t);\n const s = Math.sin(t);\n return {\n x: c * c * c,\n y: s * s * s,\n };\n}\n\nfunction deltoid(t: number, _time: number, _params: Record<string, number>): Point {\n return {\n x: 2 * Math.cos(t) + Math.cos(2 * t),\n y: 2 * Math.sin(t) - Math.sin(2 * t),\n };\n}\n\nfunction rose5(t: number, _time: number, _params: Record<string, number>): Point {\n const r = Math.cos(5 * t);\n return {\n x: r * Math.cos(t),\n y: r * Math.sin(t),\n };\n}\n\nfunction rose3(t: number, _time: number, _params: Record<string, number>): Point {\n const r = Math.cos(3 * t);\n return {\n x: r * Math.cos(t),\n y: r * Math.sin(t),\n };\n}\n\nfunction lissajous32(t: number, time: number, _params: Record<string, number>): Point {\n const phi = time * 0.45;\n return {\n x: Math.sin(3 * t + phi),\n y: Math.sin(2 * t),\n };\n}\n\nfunction lissajous43(t: number, time: number, _params: Record<string, number>): Point {\n const phi = time * 0.38;\n return {\n x: Math.sin(4 * t + phi),\n y: Math.sin(3 * t),\n };\n}\n\nfunction epicycloid3(t: number, _time: number, _params: Record<string, number>): Point {\n return {\n x: 4 * Math.cos(t) - Math.cos(4 * t),\n y: 4 * Math.sin(t) - Math.sin(4 * t),\n };\n}\n\nfunction lame(t: number, time: number, _params: Record<string, number>): Point {\n const p = 1.75 + 1.25 * Math.sin(time * 0.48);\n const c = Math.cos(t),\n s = Math.sin(t);\n return {\n x: Math.sign(c) * Math.pow(Math.abs(c), p),\n y: Math.sign(s) * Math.pow(Math.abs(s), p),\n };\n}\nexport const curves: Record<string, CurveDef> = {\n artemis2: {\n name: \"Artemis II\",\n fn: artemis2,\n period: TWO_PI,\n speed: 0.7,\n },\n epitrochoid7: {\n name: \"Epitrochoid\",\n fn: epitrochoid7,\n period: TWO_PI,\n speed: 1.4,\n skeletonFn: epitrochoid7Skeleton,\n },\n astroid: {\n name: \"Astroid\",\n fn: astroid,\n period: TWO_PI,\n speed: 1.1,\n },\n deltoid: {\n name: \"Deltoid\",\n fn: deltoid,\n period: TWO_PI,\n speed: 0.9,\n },\n rose5: {\n name: \"Rose (n=5)\",\n fn: rose5,\n period: TWO_PI,\n speed: 1.0,\n },\n rose3: {\n name: \"Rose (n=3)\",\n fn: rose3,\n period: TWO_PI,\n speed: 1.15,\n },\n lissajous32: {\n name: \"Lissajous 3:2\",\n fn: lissajous32,\n period: TWO_PI,\n speed: 2.0,\n skeleton: \"live\",\n },\n lissajous43: {\n name: \"Lissajous 4:3\",\n fn: lissajous43,\n period: TWO_PI,\n speed: 1.8,\n skeleton: \"live\",\n },\n epicycloid3: {\n name: \"Epicycloid (n=3)\",\n fn: epicycloid3,\n period: TWO_PI,\n speed: 0.75,\n },\n lame: {\n name: \"Lamé Curve\",\n fn: lame,\n period: TWO_PI,\n speed: 1.0,\n skeleton: \"live\",\n },\n};\n","export type { SVGRendererOptions, SVGSarmalOptions } from \"./renderer-svg\";\nexport type {\n Point,\n CurveDef,\n Engine,\n SarmalInstance,\n SeekOptions,\n SeekWithTrailOptions,\n RendererOptions,\n SarmalOptions,\n} from \"./types\";\n\nexport { createEngine } from \"./engine\";\nexport { createRenderer } from \"./renderer\";\nexport { createSVGRenderer, createSarmalSVG } from \"./renderer-svg\";\nexport { curves } from \"./curves\";\n\nimport type { CurveDef, SarmalInstance, SarmalOptions } from \"./types\";\nimport { createEngine } from \"./engine\";\nimport { createRenderer } from \"./renderer\";\n\n/**\n * Creates a sarmal animation on a canvas element\n *\n * @example\n * ```ts\n * import { createSarmal, curves } from '@sarmal/core'\n * const sarmal = createSarmal(canvas, curves.artemis2)\n * sarmal.start()\n * ```\n */\nexport function createSarmal(\n canvas: HTMLCanvasElement,\n curveDef: CurveDef,\n options?: SarmalOptions,\n): SarmalInstance {\n const { trailLength, ...rendererOpts } = options ?? {};\n const engine = createEngine(curveDef, trailLength);\n\n return createRenderer({ canvas, engine, ...rendererOpts });\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -55,6 +55,21 @@ type SeekWithTrailOptions = {
|
|
|
55
55
|
*/
|
|
56
56
|
step?: number;
|
|
57
57
|
};
|
|
58
|
+
type MorpStrategy = "raw" | "normalized";
|
|
59
|
+
type MorphOptions = {
|
|
60
|
+
/**
|
|
61
|
+
* Duration of the morph transition in milliseconds
|
|
62
|
+
* @default 300
|
|
63
|
+
*/
|
|
64
|
+
duration?: number;
|
|
65
|
+
/**
|
|
66
|
+
* Strategy for lerping between curves with different periods:
|
|
67
|
+
* - 'normalized': maps `t` proportionally into each curve's period (smooth for all period ratios)
|
|
68
|
+
* - 'raw': uses the same `t` for both curves (can produce incoherent results for mismatched periods)
|
|
69
|
+
* @default 'normalized'
|
|
70
|
+
*/
|
|
71
|
+
morphStrategy?: MorpStrategy;
|
|
72
|
+
};
|
|
58
73
|
interface Engine {
|
|
59
74
|
/**
|
|
60
75
|
* Advances the Sarmal simulation by the given delta time (dt) in seconds.
|
|
@@ -100,6 +115,34 @@ interface Engine {
|
|
|
100
115
|
* @param t The time value to seek to (will be wrapped into [0, period))
|
|
101
116
|
*/
|
|
102
117
|
seekWithTrail(t: number, options?: SeekWithTrailOptions): void;
|
|
118
|
+
/**
|
|
119
|
+
* Begins a smooth transition from the current curve to `target`
|
|
120
|
+
* Saves the current curve as `curveA`, registers `target` as `curveB`, and resets `morphAlpha` to `0`
|
|
121
|
+
*
|
|
122
|
+
* If called while a morph is already in progress,
|
|
123
|
+
* the interpolated state is frozen and becomes the new `curveA`
|
|
124
|
+
* @param target The curve to transition to
|
|
125
|
+
* @param strategy 'normalized' maps t proportionally into each curve's period (default), 'raw' uses the same t
|
|
126
|
+
*/
|
|
127
|
+
startMorph(target: CurveDef, strategy?: MorpStrategy): void;
|
|
128
|
+
/**
|
|
129
|
+
* Sets the interpolation amount between `curveA` and `curveB`.
|
|
130
|
+
* 0 = full curveA
|
|
131
|
+
* 1 = full curveB
|
|
132
|
+
* Called by the renderer each frame as `actualTime` advances
|
|
133
|
+
* @param alpha A value in [0, 1]
|
|
134
|
+
*/
|
|
135
|
+
setMorphAlpha(alpha: number): void;
|
|
136
|
+
/**
|
|
137
|
+
* Finalises the morph: `curveB` becomes the new active curve and `morphAlpha` is reset to `null`
|
|
138
|
+
* ! Called by the renderer when alpha reaches `1`
|
|
139
|
+
*/
|
|
140
|
+
completeMorph(): void;
|
|
141
|
+
/**
|
|
142
|
+
* Current interpolation progress between `curveA` and `curveB`
|
|
143
|
+
* `null` when no morph is in progress
|
|
144
|
+
*/
|
|
145
|
+
readonly morphAlpha: number | null;
|
|
103
146
|
}
|
|
104
147
|
interface SarmalInstance {
|
|
105
148
|
start(): void;
|
|
@@ -119,6 +162,15 @@ interface SarmalInstance {
|
|
|
119
162
|
* @param t The time value to seek to (will be wrapped into [0, period))
|
|
120
163
|
*/
|
|
121
164
|
seekWithTrail(t: number, options?: SeekWithTrailOptions): void;
|
|
165
|
+
/**
|
|
166
|
+
* Smoothly transitions from the current curve to `target`.
|
|
167
|
+
* The trail naturally reflects the new curve as new points are added.
|
|
168
|
+
* @param target The curve to transition to
|
|
169
|
+
* @param options.duration How long the morph takes in milliseconds (default: 300)
|
|
170
|
+
* @param options.morphStrategy 'normalized' uses proportional t mapping (default), 'raw' uses same t
|
|
171
|
+
* @returns Promise that resolves when the morph is complete
|
|
172
|
+
*/
|
|
173
|
+
morphTo(target: CurveDef, options?: MorphOptions): Promise<void>;
|
|
122
174
|
}
|
|
123
175
|
interface RendererOptions {
|
|
124
176
|
/** Target canvas element that will contain the Sarmal */
|
|
@@ -185,18 +237,6 @@ declare function createSVGRenderer(options: SVGRendererOptions): SarmalInstance;
|
|
|
185
237
|
*/
|
|
186
238
|
declare function createSarmalSVG(container: Element, curveDef: CurveDef, options?: SVGSarmalOptions): SarmalInstance;
|
|
187
239
|
|
|
188
|
-
/**
|
|
189
|
-
* Creates the core simulation engine for a sarmal
|
|
190
|
-
*
|
|
191
|
-
* it runs a clock (time `t`), asks the curve for the current Point position at that time,
|
|
192
|
-
* and remembers the last N positions so the renderer can draw the trail
|
|
193
|
-
*
|
|
194
|
-
* The engine is only responsible for math coordinates,
|
|
195
|
-
* so it is not responsible for drawing or colors
|
|
196
|
-
*
|
|
197
|
-
* @param curveDef A curve definition
|
|
198
|
-
* @param trailLength default: `120`
|
|
199
|
-
*/
|
|
200
240
|
declare function createEngine(curveDef: CurveDef, trailLength?: number): Engine;
|
|
201
241
|
|
|
202
242
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -55,6 +55,21 @@ type SeekWithTrailOptions = {
|
|
|
55
55
|
*/
|
|
56
56
|
step?: number;
|
|
57
57
|
};
|
|
58
|
+
type MorpStrategy = "raw" | "normalized";
|
|
59
|
+
type MorphOptions = {
|
|
60
|
+
/**
|
|
61
|
+
* Duration of the morph transition in milliseconds
|
|
62
|
+
* @default 300
|
|
63
|
+
*/
|
|
64
|
+
duration?: number;
|
|
65
|
+
/**
|
|
66
|
+
* Strategy for lerping between curves with different periods:
|
|
67
|
+
* - 'normalized': maps `t` proportionally into each curve's period (smooth for all period ratios)
|
|
68
|
+
* - 'raw': uses the same `t` for both curves (can produce incoherent results for mismatched periods)
|
|
69
|
+
* @default 'normalized'
|
|
70
|
+
*/
|
|
71
|
+
morphStrategy?: MorpStrategy;
|
|
72
|
+
};
|
|
58
73
|
interface Engine {
|
|
59
74
|
/**
|
|
60
75
|
* Advances the Sarmal simulation by the given delta time (dt) in seconds.
|
|
@@ -100,6 +115,34 @@ interface Engine {
|
|
|
100
115
|
* @param t The time value to seek to (will be wrapped into [0, period))
|
|
101
116
|
*/
|
|
102
117
|
seekWithTrail(t: number, options?: SeekWithTrailOptions): void;
|
|
118
|
+
/**
|
|
119
|
+
* Begins a smooth transition from the current curve to `target`
|
|
120
|
+
* Saves the current curve as `curveA`, registers `target` as `curveB`, and resets `morphAlpha` to `0`
|
|
121
|
+
*
|
|
122
|
+
* If called while a morph is already in progress,
|
|
123
|
+
* the interpolated state is frozen and becomes the new `curveA`
|
|
124
|
+
* @param target The curve to transition to
|
|
125
|
+
* @param strategy 'normalized' maps t proportionally into each curve's period (default), 'raw' uses the same t
|
|
126
|
+
*/
|
|
127
|
+
startMorph(target: CurveDef, strategy?: MorpStrategy): void;
|
|
128
|
+
/**
|
|
129
|
+
* Sets the interpolation amount between `curveA` and `curveB`.
|
|
130
|
+
* 0 = full curveA
|
|
131
|
+
* 1 = full curveB
|
|
132
|
+
* Called by the renderer each frame as `actualTime` advances
|
|
133
|
+
* @param alpha A value in [0, 1]
|
|
134
|
+
*/
|
|
135
|
+
setMorphAlpha(alpha: number): void;
|
|
136
|
+
/**
|
|
137
|
+
* Finalises the morph: `curveB` becomes the new active curve and `morphAlpha` is reset to `null`
|
|
138
|
+
* ! Called by the renderer when alpha reaches `1`
|
|
139
|
+
*/
|
|
140
|
+
completeMorph(): void;
|
|
141
|
+
/**
|
|
142
|
+
* Current interpolation progress between `curveA` and `curveB`
|
|
143
|
+
* `null` when no morph is in progress
|
|
144
|
+
*/
|
|
145
|
+
readonly morphAlpha: number | null;
|
|
103
146
|
}
|
|
104
147
|
interface SarmalInstance {
|
|
105
148
|
start(): void;
|
|
@@ -119,6 +162,15 @@ interface SarmalInstance {
|
|
|
119
162
|
* @param t The time value to seek to (will be wrapped into [0, period))
|
|
120
163
|
*/
|
|
121
164
|
seekWithTrail(t: number, options?: SeekWithTrailOptions): void;
|
|
165
|
+
/**
|
|
166
|
+
* Smoothly transitions from the current curve to `target`.
|
|
167
|
+
* The trail naturally reflects the new curve as new points are added.
|
|
168
|
+
* @param target The curve to transition to
|
|
169
|
+
* @param options.duration How long the morph takes in milliseconds (default: 300)
|
|
170
|
+
* @param options.morphStrategy 'normalized' uses proportional t mapping (default), 'raw' uses same t
|
|
171
|
+
* @returns Promise that resolves when the morph is complete
|
|
172
|
+
*/
|
|
173
|
+
morphTo(target: CurveDef, options?: MorphOptions): Promise<void>;
|
|
122
174
|
}
|
|
123
175
|
interface RendererOptions {
|
|
124
176
|
/** Target canvas element that will contain the Sarmal */
|
|
@@ -185,18 +237,6 @@ declare function createSVGRenderer(options: SVGRendererOptions): SarmalInstance;
|
|
|
185
237
|
*/
|
|
186
238
|
declare function createSarmalSVG(container: Element, curveDef: CurveDef, options?: SVGSarmalOptions): SarmalInstance;
|
|
187
239
|
|
|
188
|
-
/**
|
|
189
|
-
* Creates the core simulation engine for a sarmal
|
|
190
|
-
*
|
|
191
|
-
* it runs a clock (time `t`), asks the curve for the current Point position at that time,
|
|
192
|
-
* and remembers the last N positions so the renderer can draw the trail
|
|
193
|
-
*
|
|
194
|
-
* The engine is only responsible for math coordinates,
|
|
195
|
-
* so it is not responsible for drawing or colors
|
|
196
|
-
*
|
|
197
|
-
* @param curveDef A curve definition
|
|
198
|
-
* @param trailLength default: `120`
|
|
199
|
-
*/
|
|
200
240
|
declare function createEngine(curveDef: CurveDef, trailLength?: number): Engine;
|
|
201
241
|
|
|
202
242
|
/**
|