├── .gitignore ├── LICENSE ├── README.md ├── demo ├── animations │ ├── bundle.js │ ├── index.html │ └── index.js └── multiline │ ├── bundle.js │ ├── index.html │ └── index.js ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | package-lock.json 3 | .npmignore -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Bruno Imbrizi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | txt-shuffle 2 | =========== 3 | 4 | Customisable text shuffling animations. 5 | 6 | [![txt-shuffle-demo](https://user-images.githubusercontent.com/880280/229361502-c8c1bf0a-8da8-4d1d-ab3a-b3fde4cacae7.gif)](https://brunoimbrizi.github.io/txt-shuffle/demo/animations) 7 | 8 | 9 | ## Install 10 | ``` 11 | npm install txt-shuffle 12 | ``` 13 | 14 | ## Example 15 | ```js 16 | const { shuffle } = require('txt-shuffle'); 17 | 18 | shuffle({ text: 'Hello world', fps: 5, onUpdate: (output) => { 19 | console.log(output); 20 | } }); 21 | ``` 22 | Output: 23 | 24 | ``` 25 | kE}3 7 26 | Hep|> |dJ 27 | Hello UAo_ 28 | Hello worlz 29 | Hello world 30 | ``` 31 | 32 | ## Demo 33 | 34 | - [Demo: Animations](https://brunoimbrizi.github.io/txt-shuffle/demo/animations) 35 | - [Demo: Multiline (Canvas)](https://brunoimbrizi.github.io/txt-shuffle/demo/multiline) 36 | 37 | ## API 38 | 39 | #### `shuffle(options)` 40 | Starts a text shuffle animation in two tiers. 41 | First shuffling through random characters and then resolving into the target text. 42 | 43 | - `options` 44 | - `text` (default `''`) text string 45 | - `duration` (default `1`) duration of shuffle/resolve animation in seconds 46 | - `delay` (default `0`) delay to start shuffling 47 | - `delayResolve` (default `0.2`) delay to start resolving 48 | - `fps` (default `60`) framerate 49 | - `glyphs` (see below) glyphs to use in the shuffle animation 50 | - `animation` (default `show`) possible values: `show`, `hide`, `stay` 51 | - `direction` (default `right`) possible values: `left`, `right`, `random` 52 | - `onUpdate` callback function, returns the output string 53 | - `onComplete` callback function, returns the output string 54 | 55 | `glyphs` default 56 | ``` 57 | !#$&%()*+0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuüvwxyz{|}~ 58 | ``` 59 | 60 | ## License 61 | 62 | MIT, see [LICENSE](LICENSE) for details. 63 | -------------------------------------------------------------------------------- /demo/animations/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Demo : Animations 5 | 68 | 69 | 70 |
 
71 |
72 |

txt-shuffle

73 | 74 | shuffle : Two-tier animation. First shuffling through random characters and then resolving into the target text 75 | 76 |
77 | 78 | 79 | -------------------------------------------------------------------------------- /demo/animations/index.js: -------------------------------------------------------------------------------- 1 | const { shuffle, shuffleScroll, directions, animations } = require('../../index.js'); 2 | const Tweakpane = require('tweakpane'); 3 | 4 | const paramsA = { 5 | text : 'We chase misprinted lies', 6 | duration : 2, 7 | fps : 60, 8 | animation : animations.SHOW, 9 | direction : directions.RANDOM, 10 | nglyphs : '', 11 | }; 12 | 13 | const paramsB = { 14 | text : 'We face the path of time', 15 | fps : 60, 16 | stayFrames : 25, 17 | animation : animations.SHOW, 18 | nglyphs : '', 19 | }; 20 | 21 | let el; 22 | 23 | const setup = () => { 24 | el = document.querySelector('pre'); 25 | 26 | // init parameters panel 27 | createPane(); 28 | // play first animation 29 | playShuffle(); 30 | }; 31 | 32 | const onUpdate = (output) => { 33 | el.innerText = output; 34 | }; 35 | 36 | const playShuffle = () => { 37 | const { text, duration, fps, nglyphs, direction, animation } = paramsA; 38 | const glyphs = nglyphs.length ? nglyphs : undefined; 39 | 40 | shuffle({ text, duration, fps, glyphs, direction, animation, onUpdate }); 41 | }; 42 | 43 | const playShuffleScroll = () => { 44 | const { text, fps, nglyphs, stayFrames, animation } = paramsB; 45 | const glyphs = nglyphs.length ? nglyphs : undefined; 46 | 47 | shuffleScroll({ text, fps, glyphs, stayFrames, animation, onUpdate }); 48 | }; 49 | 50 | const createPane = () => { 51 | const pane = new Tweakpane.Pane(); 52 | let folder; 53 | 54 | folder = pane.addFolder({ title: 'SHUFFLE' }); 55 | folder.addInput(paramsA, 'text'); 56 | folder.addInput(paramsA, 'duration', { min: 0, max: 3, step: 0.1 }); 57 | folder.addInput(paramsA, 'fps', { min: 1, max: 60, step: 1 }); 58 | folder.addInput(paramsA, 'animation', { options: animations }); 59 | folder.addInput(paramsA, 'direction', { options: directions }); 60 | folder.addInput(paramsA, 'nglyphs', { label: 'glyphs'}); 61 | folder.addButton({ title: 'SHUFFLE', label: 'play' }).on('click', playShuffle); 62 | 63 | /* 64 | folder = pane.addFolder({ title: 'SHUFFLE SCROLL' }); 65 | folder.addInput(paramsB, 'text'); 66 | folder.addInput(paramsB, 'fps', { min: 1, max: 60, step: 1 }); 67 | folder.addInput(paramsB, 'animation', { options: animations }); 68 | folder.addInput(paramsB, 'stayFrames', { min: 1, max: 60, step: 1 }); 69 | folder.addInput(paramsB, 'nglyphs', { label: 'glyphs'}); 70 | folder.addButton({ title: 'SHUFFLE SCROLL', label: 'play' }).on('click', playShuffleScroll); 71 | */ 72 | }; 73 | 74 | setup(); 75 | -------------------------------------------------------------------------------- /demo/multiline/bundle.js: -------------------------------------------------------------------------------- 1 | !function(){"use strict";var _$defined_7=function(){for(var t=0;tn){var i=e;e=n,n=i}var s=n-e;return 0===s?n:t-s*Math.floor((t-e)/s)},EPSILON=Number.EPSILON;function clamp(t,e,n){return en?n:t:te?e:t}function lerp(t,e,n){return t*(1-n)+e*n}function inverseLerp(t,e,n){return Math.abs(t-e)=o;)t/=2,e/=2,n>>>=1;return(t+n)/e}}).resetGlobal=function(){Math.random=r},l(Math.random(),e)}).call(this)}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{});var _$simplexNoise_41={exports:{}};!function(){var t=.5*(Math.sqrt(3)-1),e=(3-Math.sqrt(3))/6,n=(Math.sqrt(5)-1)/4,i=(5-Math.sqrt(5))/20;function s(t){var e;e="function"==typeof t?t:t?function(){var t,e=0,n=0,i=0,s=1,o=(t=4022871197,function(e){e=e.toString();for(var n=0;n>>0,t=(i*=t)>>>0,t+=4294967296*(i-=t)}return 2.3283064365386963e-10*(t>>>0)});e=o(" "),n=o(" "),i=o(" ");for(var r=0;r_?(s=1,o=0):(s=0,o=1);var w=v-s+e,g=_-o+e,b=v-1+2*e,y=_-1+2*e,x=255&d,E=255&m,C=.5-v*v-_*_;if(C>=0){var P=3*r[x+a[E]];u=(C*=C)*C*(l[P]*v+l[P+1]*_)}var M=.5-w*w-g*g;if(M>=0){var V=3*r[x+s+a[E+o]];h=(M*=M)*M*(l[V]*w+l[V+1]*g)}var $=.5-b*b-y*y;if($>=0){var L=3*r[x+1+a[E+1]];c=($*=$)*$*(l[L]*b+l[L+1]*y)}return 70*(u+h+c)},noise3D:function(t,e,n){var i,s,o,r,a,l,u,h,c,p,d=this.permMod12,m=this.perm,f=this.grad3,v=(t+e+n)*(1/3),_=Math.floor(t+v),w=Math.floor(e+v),g=Math.floor(n+v),b=(_+w+g)*(1/6),y=t-(_-b),x=e-(w-b),E=n-(g-b);y>=x?x>=E?(a=1,l=0,u=0,h=1,c=1,p=0):y>=E?(a=1,l=0,u=0,h=1,c=0,p=1):(a=0,l=0,u=1,h=1,c=0,p=1):xS?F++:N++,D>I?F++:A++,D>T?F++:K++,S>I?N++:A++,S>T?N++:K++,I>T?A++:K++;var O=D-(c=F>=3?1:0)+i,j=S-(p=N>=3?1:0)+i,R=I-(d=A>=3?1:0)+i,U=T-(m=K>=3?1:0)+i,q=D-(f=F>=2?1:0)+2*i,H=S-(v=N>=2?1:0)+2*i,B=I-(_=A>=2?1:0)+2*i,z=T-(w=K>=2?1:0)+2*i,Y=D-(g=F>=1?1:0)+3*i,W=S-(b=N>=1?1:0)+3*i,G=I-(y=A>=1?1:0)+3*i,X=T-(x=K>=1?1:0)+3*i,J=D-1+4*i,Z=S-1+4*i,Q=I-1+4*i,tt=T-1+4*i,et=255&M,nt=255&V,it=255&$,st=255&L,ot=.6-D*D-S*S-I*I-T*T;if(ot<0)r=0;else{var rt=E[et+E[nt+E[it+E[st]]]]%32*4;r=(ot*=ot)*ot*(C[rt]*D+C[rt+1]*S+C[rt+2]*I+C[rt+3]*T)}var at=.6-O*O-j*j-R*R-U*U;if(at<0)a=0;else{var lt=E[et+c+E[nt+p+E[it+d+E[st+m]]]]%32*4;a=(at*=at)*at*(C[lt]*O+C[lt+1]*j+C[lt+2]*R+C[lt+3]*U)}var ut=.6-q*q-H*H-B*B-z*z;if(ut<0)l=0;else{var ht=E[et+f+E[nt+v+E[it+_+E[st+w]]]]%32*4;l=(ut*=ut)*ut*(C[ht]*q+C[ht+1]*H+C[ht+2]*B+C[ht+3]*z)}var ct=.6-Y*Y-W*W-G*G-X*X;if(ct<0)u=0;else{var pt=E[et+g+E[nt+b+E[it+y+E[st+x]]]]%32*4;u=(ct*=ct)*ct*(C[pt]*Y+C[pt+1]*W+C[pt+2]*G+C[pt+3]*X)}var dt=.6-J*J-Z*Z-Q*Q-tt*tt;if(dt<0)h=0;else{var mt=E[et+1+E[nt+1+E[it+1+E[st+1]]]]%32*4;h=(dt*=dt)*dt*(C[mt]*J+C[mt+1]*Z+C[mt+2]*Q+C[mt+3]*tt)}return 27*(r+a+l+u+h)}},s._buildPermutationTable=o,"undefined"!=typeof define&&define.amd&&define((function(){return s})),void 0!==_$simplexNoise_41.exports?_$simplexNoise_41.exports.SimplexNoise=s:"undefined"!=typeof window&&(window.SimplexNoise=s),_$simplexNoise_41.exports=s}(),_$simplexNoise_41=_$simplexNoise_41.exports;var _$random_6=function t(e){e=_$defined_7(e,null);var n,i,s,o=Math.random,r=null,a=!1;return l(e),{value:u,createRandom:function(e){return t(e)},setSeed:l,getSeed:function(){return n},getRandomSeed:function(){return String(Math.floor(1e6*Math.random()))},valueNonZero:function(){for(var t=0;0===t;)t=u();return t},permuteNoise:function(){s=h()},noise1D:function(t,e,n){if(!isFinite(t))throw new TypeError("x component for noise() must be finite");return e=_$defined_7(e,1),(n=_$defined_7(n,1))*s.noise2D(t*e,0)},noise2D:function(t,e,n,i){if(!isFinite(t))throw new TypeError("x component for noise() must be finite");if(!isFinite(e))throw new TypeError("y component for noise() must be finite");return n=_$defined_7(n,1),(i=_$defined_7(i,1))*s.noise2D(t*n,e*n)},noise3D:function(t,e,n,i,o){if(!isFinite(t))throw new TypeError("x component for noise() must be finite");if(!isFinite(e))throw new TypeError("y component for noise() must be finite");if(!isFinite(n))throw new TypeError("z component for noise() must be finite");return i=_$defined_7(i,1),(o=_$defined_7(o,1))*s.noise3D(t*i,e*i,n*i)},noise4D:function(t,e,n,i,o,r){if(!isFinite(t))throw new TypeError("x component for noise() must be finite");if(!isFinite(e))throw new TypeError("y component for noise() must be finite");if(!isFinite(n))throw new TypeError("z component for noise() must be finite");if(!isFinite(i))throw new TypeError("w component for noise() must be finite");return o=_$defined_7(o,1),(r=_$defined_7(r,1))*s.noise4D(t*o,e*o,n*o,i*o)},sign:function(){return c()?1:-1},boolean:c,chance:function(t){if("number"!=typeof(t=_$defined_7(t,.5)))throw new TypeError("expected n to be a number");return u()=1||0===o);var l=Math.sqrt(-2*Math.log(o)/o);return r=s*l,a=!0,t+e*(i*l)}};function l(t,e){"number"==typeof t||"string"==typeof t?i=_$seedRandom_40(n=t,e):(n=void 0,i=o),s=h(),r=null,a=!1}function u(){return i()}function h(){return new _$simplexNoise_41(i)}function c(){return u()>.5}function p(t,e){if(void 0===e&&(e=t,t=0),"number"!=typeof t||"number"!=typeof e)throw new TypeError("Expected all arguments to be numbers");return u()*(e-t)+t}function d(t,e){if(void 0===e&&(e=t,t=0),"number"!=typeof t||"number"!=typeof e)throw new TypeError("Expected all arguments to be numbers");return Math.floor(p(t,e))}function m(t,e){t=_$defined_7(t,1),e=e||[];var n=2*u()*Math.PI;return e[0]=t*Math.cos(n),e[1]=t*Math.sin(n),e}function f(t){return 0===(t=t||[]).length?-1:v(t.map((function(t){return t.weight})))}function v(t){if(0===(t=t||[]).length)return-1;var e,n=0;for(e=0;e 0");var i=u()*n;for(e=0;e?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstu\xfcvwxyz{|}~",animation:r=animations.SHOW,direction:a=directions.RIGHT,onUpdate:l=null,onComplete:u=null}={})=>{const h=o.split(""),c=t.split(""),p=1e3/s;let d,m,f,v,_,w,g,b,y,x=Date.now(),E=Date.now(),C=c.map((t,e)=>e);r==animations.HIDE&&(a==directions.LEFT?a=directions.RIGHT:a==directions.RIGHT&&(a=directions.LEFT)),a==directions.LEFT&&C.reverse(),a==directions.RANDOM&&(C=_$random_6.shuffle(C));const P=()=>{if(Date.now()-x=d&&r!=animations.STAY&&(f=" ")," "!=f&&w>=m&&(f=_$random_6.pick(h)),v=`${v}${f}`;(_=r==animations.HIDE?b<=0:b>=1)?v=r==animations.HIDE?"":t:requestAnimationFrame(P),l&&l(v),_&&u&&u(v)}};P()},shuffleScroll:({text:t="",delay:e=0,fps:n=60,glyphs:i=" '\"\u201c\u201d\u2018\u2019\xb9\xb2\xb3!#$&%()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu\xfcvwxyz{|}~\xbd\xbc\xa1\xab\xbb\xd7\u2591\u2592\u2593\u2502\u2524\u2561\u2562\u2556\u2555\u2563\u2551\u2557\u255d\u255c\u255b\u2510\u2514\u2534\u252c\u251c\u2500\u253c\u255e\u255f\u255a\u2554\u2569\u2566\u2560\u2550\u256c\u2567\u2568\u2564\u2565\u2559\u2558\u2552\u2553\u256b\u256a\u2518\u250c",animation:s=animations.SHOW,stayFrames:o=25,onUpdate:r=null,onComplete:a=null}={})=>{const l=i.split(""),u=t.split(""),h=1e3/n;u.map((t,e)=>e),l.map((t,e)=>e);let c=u.map(t=>0),p=u.map(t=>l.findIndex(e=>e==t));s==animations.HIDE&&(c=p.concat()),s==animations.STAY&&(c=p.map(t=>_$math_5.mod(t-_$random_6.rangeFloor(5,o),l.length)));let d,m,f,v,_,w,g=Date.now(),b=Date.now(),y=0;const x=()=>{if(Date.now()-g1e3*e&&y++,m="",v=0;for(let e=0;e0?e=t.length)?m=s==animations.HIDE?"":t:requestAnimationFrame(x),r&&r(m),f&&a&&a(m)}};x()}},_$js_3={};Object.defineProperty(_$js_3,"__esModule",{value:!0}),_$js_3.split=function(t,e,n,i,s,o){let r=`${e}_${n}_${i}px`,a=d.get(r);if(void 0!==a)return a;if(i<=0)return[];let l=[],u=e.split("\n"),h=b.get(n),c=void 0===h?e.length:i/h.size*1.5,m=s&&void 0!==h&&h.count>2e4;for(let d of u){let e=p(t,d.slice(0,Math.max(0,c)),n,m),s=Math.min(d.length,c);if(e<=i)l.push(d);else{for(;e>i;){let r=T(t,d,i,n,e,s,m,o),a=d.slice(0,Math.max(0,r));d=d.slice(a.length),l.push(a),e=p(t,d.slice(0,Math.max(0,c)),n,m),s=Math.min(d.length,c)}e>0&&l.push(d)}}return l=l.map((t,e)=>0===e?t.trimEnd():t.trim()),d.set(r,l),d.size>500&&d.delete(d.keys().next().value),l};var d=new Map,b=new Map,__z_3=new Map;function p(t,e,n,i){var s,o;let r=b.get(n);if(i&&void 0!==r&&r.count>2e4){let i=__z_3.get(n);if(void 0===i&&(i=function(t,e){var n;let i=new Map,s=0;for(let l of"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890,.-+=?"){let e=t.measureText(l).width;i.set(l,e),s+=e}let o=s/i.size,r=(e/o+3)/4,a=i.keys();for(let l of a)i.set(l,(null!=(n=i.get(l))?n:o)*r);return i}(t,r.size),__z_3.set(n,i)),r.count>5e5){let t=0;for(let n of e)t+=null!=(s=i.get(n))?s:r.size;return 1.01*t}let o=t.measureText(e);return function(t,e,n,i,s){var o,r,a;let l=0,u={};for(let c of t)l+=null!=(o=n.get(c))?o:s,u[c]=(null!=(r=u[c])?r:0)+1;let h=e-l;for(let c of Object.keys(u)){let t=u[c],e=null!=(a=n.get(c))?a:s,o=e+h*(e*t/l)*i/t;n.set(c,o)}}(e,o.width,i,Math.max(.05,1-r.count/2e5),r.size),b.set(n,{count:r.count+e.length,size:r.size}),o.width}let a=t.measureText(e),l=a.width/e.length;if((null!=(o=null==r?void 0:r.count)?o:0)>2e4)return a.width;if(void 0===r)b.set(n,{count:e.length,size:l});else{let t=l-r.size,i=e.length/(r.count+e.length),s=r.size+t*i;b.set(n,{count:r.count+e.length,size:s})}return a.width}function T(t,e,n,i,s,o,r,a){if(e.length<=1)return e.length;if(sn;){let n=void 0!==h?0:e.lastIndexOf(" ",l-1);n>0?l=n:l--,u=p(t,e.slice(0,Math.max(0,l)),i,r)}if(" "!==e[l]){let t=0;if(void 0===h)t=e.lastIndexOf(" ",l);else for(let e of h){if(e>l)break;t=e}t>0&&(l=t)}return l}var _$tweakpane_42={exports:{}},__global_42,factory;__global_42=void 0,factory=function(t){function e(t){return null==t}const n={alreadydisposed:()=>"View has been already disposed",invalidparams:t=>`Invalid parameters for '${t.name}'`,nomatchingcontroller:t=>`No matching controller for '${t.key}'`,nomatchingview:t=>`No matching view for '${JSON.stringify(t.params)}'`,notbindable:()=>"Value is not bindable",propertynotfound:t=>`Property '${t.name}' not found`,shouldneverhappen:()=>"This error should never happen"};class i{static alreadyDisposed(){return new i({type:"alreadydisposed"})}static notBindable(){return new i({type:"notbindable"})}static propertyNotFound(t){return new i({type:"propertynotfound",context:{name:t}})}static shouldNeverHappen(){return new i({type:"shouldneverhappen"})}constructor(t){var e;this.message=null!==(e=n[t.type](t.context))&&void 0!==e?e:"Unexpected error",this.name=this.constructor.name,this.stack=new Error(this.message).stack,this.type=t.type}}class s{constructor(){this.observers_={}}on(t,e){let n=this.observers_[t];return n||(n=this.observers_[t]=[]),n.push({handler:e}),this}off(t,e){const n=this.observers_[t];return n&&(this.observers_[t]=n.filter(t=>t.handler!==e)),this}emit(t,e){const n=this.observers_[t];n&&n.forEach(t=>{t.handler(e)})}}const o="tp";function r(t){return(e,n)=>[o,"-",t,"v",e?"_"+e:"",n?"-"+n:""].join("")}function a(t){return t.rawValue}function l(t,e){var n,i;t.emitter.on("change",(n=a,i=e,t=>i(n(t)))),e(t.rawValue)}function u(t,e,n){l(t.value(e),n)}function h(t,e){return n=>{!function(t,e,n){n?t.classList.add(e):t.classList.remove(e)}(t,e,n)}}r("btn");class c{constructor(t,e){var n;this.constraint_=null==e?void 0:e.constraint,this.equals_=null!==(n=null==e?void 0:e.equals)&&void 0!==n?n:(t,e)=>t===e,this.emitter=new s,this.rawValue_=t}get constraint(){return this.constraint_}get rawValue(){return this.rawValue_}set rawValue(t){this.setRawValue(t,{forceEmit:!1,last:!0})}setRawValue(t,e){const n=null!=e?e:{forceEmit:!1,last:!0},i=this.constraint_?this.constraint_.constrain(t):t,s=this.rawValue_;(!this.equals_(s,i)||n.forceEmit)&&(this.emitter.emit("beforechange",{sender:this}),this.rawValue_=i,this.emitter.emit("change",{options:n,previousRawValue:s,rawValue:i,sender:this}))}}class p{constructor(t){this.emitter=new s,this.value_=t}get rawValue(){return this.value_}set rawValue(t){this.setRawValue(t,{forceEmit:!1,last:!0})}setRawValue(t,e){const n=null!=e?e:{forceEmit:!1,last:!0},i=this.value_;(i!==t||n.forceEmit)&&(this.emitter.emit("beforechange",{sender:this}),this.value_=t,this.emitter.emit("change",{options:n,previousRawValue:i,rawValue:this.value_,sender:this}))}}function d(t,e){const n=null==e?void 0:e.constraint,i=null==e?void 0:e.equals;return n||i?new c(t,e):new p(t)}class m{constructor(t){this.emitter=new s,this.valMap_=t;for(const e in this.valMap_)this.valMap_[e].emitter.on("change",()=>{this.emitter.emit("change",{key:e,sender:this})})}static createCore(t){return Object.keys(t).reduce((e,n)=>Object.assign(e,{[n]:d(t[n])}),{})}static fromObject(t){const e=this.createCore(t);return new m(e)}get(t){return this.valMap_[t].rawValue}set(t,e){this.valMap_[t].rawValue=e}value(t){return this.valMap_[t]}}function f(t){return e=>n=>{if(!e&&void 0===n)return{succeeded:!1,value:void 0};if(e&&void 0===n)return{succeeded:!0,value:void 0};const i=t(n);return void 0!==i?{succeeded:!0,value:i}:{succeeded:!1,value:void 0}}}function v(t){return{custom:e=>f(e)(t),boolean:f(t=>"boolean"==typeof t?t:void 0)(t),number:f(t=>"number"==typeof t?t:void 0)(t),string:f(t=>"string"==typeof t?t:void 0)(t),function:f(t=>"function"==typeof t?t:void 0)(t),constant:e=>f(t=>t===e?e:void 0)(t),raw:f(t=>t)(t),object:e=>f(t=>{if(null!==(n=t)&&"object"==typeof n)return function(t,e){return Object.keys(e).reduce((n,i)=>{if(void 0===n)return;const s=(0,e[i])(t[i]);return s.succeeded?Object.assign(Object.assign({},n),{[i]:s.value}):void 0},{})}(t,e);var n})(t),array:e=>f(t=>{if(Array.isArray(t))return n=e,t.reduce((t,e)=>{if(void 0===t)return;const i=n(e);return i.succeeded&&void 0!==i.value?[...t,i.value]:void 0},[]);var n})(t)}}const _={optional:v(!0),required:v(!1)};function w(t,e){const n=_.required.object(e)(t);return n.succeeded?n.value:void 0}r("");r("");const g="http://www.w3.org/2000/svg";function b(t){t.offsetHeight}function y(t){return void 0!==t.ontouchstart}const x={check:'',dropdown:'',p2dpad:''};function E(t,e){const n=t.createElementNS(g,"svg");return n.innerHTML=x[e],n}function C(t){for(;t.children.length>0;)t.removeChild(t.children[0])}function P(t){return t.relatedTarget?t.relatedTarget:"explicitOriginalTarget"in t?t.explicitOriginalTarget:null}r("lbl");class M extends m{constructor(t){super(t)}static create(t){const e={completed:!0,expanded:t,expandedHeight:null,shouldFixHeight:!1,temporaryExpanded:null},n=m.createCore(e);return new M(n)}get styleExpanded(){var t;return null!==(t=this.get("temporaryExpanded"))&&void 0!==t?t:this.get("expanded")}get styleHeight(){if(!this.styleExpanded)return"0";const t=this.get("expandedHeight");return this.get("shouldFixHeight")&&!e(t)?t+"px":"auto"}bindExpandedClass(t,e){const n=()=>{this.styleExpanded?t.classList.add(e):t.classList.remove(e)};u(this,"expanded",n),u(this,"temporaryExpanded",n)}cleanUpTransition(){this.set("shouldFixHeight",!1),this.set("expandedHeight",null),this.set("completed",!0)}}function V(t,e){e.style.height=t.styleHeight}function $(t,n){t.value("expanded").emitter.on("beforechange",()=>{if(t.set("completed",!1),e(t.get("expandedHeight"))){const e=function(t,e){let n=0;return function(i,s){const o=i.style.transition;i.style.transition="none",t.set("expandedHeight",null),t.set("temporaryExpanded",!0),b(e),n=e.clientHeight,t.set("temporaryExpanded",null),b(e),i.style.transition=o}(e),n}(t,n);e>0&&t.set("expandedHeight",e)}t.set("shouldFixHeight",!0),b(n)}),t.emitter.on("change",()=>{V(t,n)}),V(t,n),n.addEventListener("transitionend",e=>{"height"===e.propertyName&&t.cleanUpTransition()})}r("cnt");r("spr");r("tbi");r("tab");class L{constructor(t){this.constraints=t}constrain(t){return this.constraints.reduce((t,e)=>e.constrain(t),t)}}function k(t,e){if(t instanceof e)return t;if(t instanceof L){const n=t.constraints.reduce((t,n)=>t||(n instanceof e?n:null),null);if(n)return n}return null}class D{constructor(t){this.values=m.fromObject({max:t.max,min:t.min})}constrain(t){const e=this.values.get("max"),n=this.values.get("min");return Math.min(Math.max(t,n),e)}}class S{constructor(t){this.values=m.fromObject({max:t.max,min:t.min})}get maxValue(){return this.values.get("max")}get minValue(){return this.values.get("min")}constrain(t){const n=this.values.get("max"),i=this.values.get("min");let s=t;return e(i)||(s=Math.max(s,i)),e(n)||(s=Math.min(s,n)),s}}class I{constructor(t,e=0){this.step=t,this.origin=e}constrain(t){const e=this.origin%this.step;return e+Math.round((t-e)/this.step)*this.step}}r("lst");const T=r("pop");class F{constructor(t,e){this.element=t.createElement("div"),this.element.classList.add(T()),e.viewProps.bindClassModifiers(this.element),l(e.shows,h(this.element,T(void 0,"v")))}}class N{constructor(t,e){this.shows=d(!1),this.viewProps=e.viewProps,this.view=new F(t,{shows:this.shows,viewProps:this.viewProps})}}const A=r("txt");class K{constructor(t,e){this.onChange_=this.onChange_.bind(this),this.element=t.createElement("div"),this.element.classList.add(A()),e.viewProps.bindClassModifiers(this.element),this.props_=e.props,this.props_.emitter.on("change",this.onChange_);const n=t.createElement("input");n.classList.add(A("i")),n.type="text",e.viewProps.bindDisabled(n),this.element.appendChild(n),this.inputElement=n,e.value.emitter.on("change",this.onChange_),this.value_=e.value,this.refresh()}refresh(){const t=this.props_.get("formatter");this.inputElement.value=t(this.value_.rawValue)}onChange_(){this.refresh()}}class O{constructor(t,e){this.onInputChange_=this.onInputChange_.bind(this),this.parser_=e.parser,this.props=e.props,this.value=e.value,this.viewProps=e.viewProps,this.view=new K(t,{props:e.props,value:this.value,viewProps:this.viewProps}),this.view.inputElement.addEventListener("change",this.onInputChange_)}onInputChange_(t){const n=t.currentTarget.value,i=this.parser_(n);e(i)||(this.value.rawValue=i),this.view.refresh()}}class j{constructor(t){this.text=t}evaluate(){return Number(this.text)}toString(){return this.text}}const R={"**":(t,e)=>Math.pow(t,e),"*":(t,e)=>t*e,"/":(t,e)=>t/e,"%":(t,e)=>t%e,"+":(t,e)=>t+e,"-":(t,e)=>t-e,"<<":(t,e)=>t<>":(t,e)=>t>>e,">>>":(t,e)=>t>>>e,"&":(t,e)=>t&e,"^":(t,e)=>t^e,"|":(t,e)=>t|e};class U{constructor(t,e,n){this.left=e,this.operator=t,this.right=n}evaluate(){const t=R[this.operator];if(!t)throw new Error("unexpected binary operator: '"+this.operator);return t(this.left.evaluate(),this.right.evaluate())}toString(){return["b(",this.left.toString(),this.operator,this.right.toString(),")"].join(" ")}}const q={"+":t=>t,"-":t=>-t,"~":t=>~t};class H{constructor(t,e){this.operator=t,this.expression=e}evaluate(){const t=q[this.operator];if(!t)throw new Error("unexpected unary operator: '"+this.operator);return t(this.expression.evaluate())}toString(){return["u(",this.operator,this.expression.toString(),")"].join(" ")}}function B(t){return(e,n)=>{for(let i=0;ie.startsWith(t,n))[0];return i?(n+=i.length,{cursor:n+=z(e,n).length,operator:i}):null}const tt=[["**"],["*","/","%"],["+","-"],["<<",">>>",">>"],["&"],["^"],["|"]].reduce((t,e)=>function(t,e){return(n,i)=>{const s=t(n,i);if(!s)return null;i=s.cursor;let o=s.evaluable;for(;;){const s=Q(e,n,i);if(!s)break;i=s.cursor;const r=t(n,i);if(!r)return null;i=r.cursor,o=new U(s.operator,o,r.evaluable)}return o?{cursor:i,evaluable:o}:null}}(t,e),(function t(e,n){const i=function(t,e){var n;return null!==(n=function(t,e){const n=Z(t,e);return e+=n.length,""===n?null:{evaluable:new j(n),cursor:e}}(t,e))&&void 0!==n?n:function(t,e){const n=t.substr(e,1);if(e+=n.length,"("!==n)return null;const i=et(t,e);if(!i)return null;e=i.cursor,e+=z(t,e).length;const s=t.substr(e,1);return e+=s.length,")"!==s?null:{evaluable:i.evaluable,cursor:e}}(t,e)}(e,n);if(i)return i;const s=e.substr(n,1);if(n+=s.length,"+"!==s&&"-"!==s&&"~"!==s)return null;const o=t(e,n);return o?{cursor:n=o.cursor,evaluable:new H(s,o.evaluable)}:null}));function et(t,e){return e+=z(t,e).length,tt(t,e)}function nt(t){var e;const n=function(t){const e=et(t,0);return e?e.cursor+z(t,e.cursor).length!==t.length?null:e.evaluable:null}(t);return null!==(e=null==n?void 0:n.evaluate())&&void 0!==e?e:null}function it(t){return e=>e.toFixed(Math.max(Math.min(t,20),0))}const st=it(0);function ot(t){return st(t)+"%"}function rt({primary:t,secondary:e,forward:n,backward:i}){let s=!1;function o(t){s||(s=!0,t(),s=!1)}t.emitter.on("change",i=>{o(()=>{e.setRawValue(n(t,e),i.options)})}),e.emitter.on("change",s=>{o(()=>{t.setRawValue(i(t,e),s.options)}),o(()=>{e.setRawValue(n(t,e),s.options)})}),o(()=>{e.setRawValue(n(t,e),{forceEmit:!1,last:!0})})}function at(t,e){const n=t*(e.altKey?.1:1)*(e.shiftKey?10:1);return e.upKey?+n:e.downKey?-n:0}function lt(t){return{altKey:t.altKey,downKey:"ArrowDown"===t.key,shiftKey:t.shiftKey,upKey:"ArrowUp"===t.key}}function ut(t){return{altKey:t.altKey,downKey:"ArrowLeft"===t.key,shiftKey:t.shiftKey,upKey:"ArrowRight"===t.key}}function ht(t){return function(t){return"ArrowUp"===t||"ArrowDown"===t}(t)||"ArrowLeft"===t||"ArrowRight"===t}function ct(t,e){var n,i;const s=e.ownerDocument.defaultView,o=e.getBoundingClientRect();return{x:t.pageX-((null!==(n=s&&s.scrollX)&&void 0!==n?n:0)+o.left),y:t.pageY-((null!==(i=s&&s.scrollY)&&void 0!==i?i:0)+o.top)}}class pt{constructor(t){this.lastTouch_=null,this.onDocumentMouseMove_=this.onDocumentMouseMove_.bind(this),this.onDocumentMouseUp_=this.onDocumentMouseUp_.bind(this),this.onMouseDown_=this.onMouseDown_.bind(this),this.onTouchEnd_=this.onTouchEnd_.bind(this),this.onTouchMove_=this.onTouchMove_.bind(this),this.onTouchStart_=this.onTouchStart_.bind(this),this.elem_=t,this.emitter=new s,t.addEventListener("touchstart",this.onTouchStart_,{passive:!1}),t.addEventListener("touchmove",this.onTouchMove_,{passive:!0}),t.addEventListener("touchend",this.onTouchEnd_),t.addEventListener("mousedown",this.onMouseDown_)}computePosition_(t){const e=this.elem_.getBoundingClientRect();return{bounds:{width:e.width,height:e.height},point:t?{x:t.x,y:t.y}:null}}onMouseDown_(t){var e;t.preventDefault(),null===(e=t.currentTarget)||void 0===e||e.focus();const n=this.elem_.ownerDocument;n.addEventListener("mousemove",this.onDocumentMouseMove_),n.addEventListener("mouseup",this.onDocumentMouseUp_),this.emitter.emit("down",{altKey:t.altKey,data:this.computePosition_(ct(t,this.elem_)),sender:this,shiftKey:t.shiftKey})}onDocumentMouseMove_(t){this.emitter.emit("move",{altKey:t.altKey,data:this.computePosition_(ct(t,this.elem_)),sender:this,shiftKey:t.shiftKey})}onDocumentMouseUp_(t){const e=this.elem_.ownerDocument;e.removeEventListener("mousemove",this.onDocumentMouseMove_),e.removeEventListener("mouseup",this.onDocumentMouseUp_),this.emitter.emit("up",{altKey:t.altKey,data:this.computePosition_(ct(t,this.elem_)),sender:this,shiftKey:t.shiftKey})}onTouchStart_(t){t.preventDefault();const e=t.targetTouches.item(0),n=this.elem_.getBoundingClientRect();this.emitter.emit("down",{altKey:t.altKey,data:this.computePosition_(e?{x:e.clientX-n.left,y:e.clientY-n.top}:void 0),sender:this,shiftKey:t.shiftKey}),this.lastTouch_=e}onTouchMove_(t){const e=t.targetTouches.item(0),n=this.elem_.getBoundingClientRect();this.emitter.emit("move",{altKey:t.altKey,data:this.computePosition_(e?{x:e.clientX-n.left,y:e.clientY-n.top}:void 0),sender:this,shiftKey:t.shiftKey}),this.lastTouch_=e}onTouchEnd_(t){var e;const n=null!==(e=t.targetTouches.item(0))&&void 0!==e?e:this.lastTouch_,i=this.elem_.getBoundingClientRect();this.emitter.emit("up",{altKey:t.altKey,data:this.computePosition_(n?{x:n.clientX-i.left,y:n.clientY-i.top}:void 0),sender:this,shiftKey:t.shiftKey})}}function dt(t,e,n,i,s){return i+(t-e)/(n-e)*(s-i)}function mt(t){return String(t.toFixed(10)).split(".")[1].replace(/0+$/,"").length}function ft(t,e,n){return Math.min(Math.max(t,e),n)}function vt(t,e){return(t%e+e)%e}const _t=r("txt");class wt{constructor(t,e){this.onChange_=this.onChange_.bind(this),this.props_=e.props,this.props_.emitter.on("change",this.onChange_),this.element=t.createElement("div"),this.element.classList.add(_t(),_t(void 0,"num")),e.arrayPosition&&this.element.classList.add(_t(void 0,e.arrayPosition)),e.viewProps.bindClassModifiers(this.element);const n=t.createElement("input");n.classList.add(_t("i")),n.type="text",e.viewProps.bindDisabled(n),this.element.appendChild(n),this.inputElement=n,this.onDraggingChange_=this.onDraggingChange_.bind(this),this.dragging_=e.dragging,this.dragging_.emitter.on("change",this.onDraggingChange_),this.element.classList.add(_t()),this.inputElement.classList.add(_t("i"));const i=t.createElement("div");i.classList.add(_t("k")),this.element.appendChild(i),this.knobElement=i;const s=t.createElementNS(g,"svg");s.classList.add(_t("g")),this.knobElement.appendChild(s);const o=t.createElementNS(g,"path");o.classList.add(_t("gb")),s.appendChild(o),this.guideBodyElem_=o;const a=t.createElementNS(g,"path");a.classList.add(_t("gh")),s.appendChild(a),this.guideHeadElem_=a;const l=t.createElement("div");l.classList.add(r("tt")()),this.knobElement.appendChild(l),this.tooltipElem_=l,e.value.emitter.on("change",this.onChange_),this.value=e.value,this.refresh()}onDraggingChange_(t){if(null===t.rawValue)return void this.element.classList.remove(_t(void 0,"drg"));this.element.classList.add(_t(void 0,"drg"));const e=t.rawValue/this.props_.get("draggingScale"),n=e+(e>0?-1:e<0?1:0),i=ft(-n,-4,4);this.guideHeadElem_.setAttributeNS(null,"d",[`M ${n+i},0 L${n},4 L${n+i},8`,`M ${e},-1 L${e},9`].join(" ")),this.guideBodyElem_.setAttributeNS(null,"d",`M 0,4 L${e},4`);const s=this.props_.get("formatter");this.tooltipElem_.textContent=s(this.value.rawValue),this.tooltipElem_.style.left=e+"px"}refresh(){const t=this.props_.get("formatter");this.inputElement.value=t(this.value.rawValue)}onChange_(){this.refresh()}}class gt{constructor(t,e){var n;this.originRawValue_=0,this.onInputChange_=this.onInputChange_.bind(this),this.onInputKeyDown_=this.onInputKeyDown_.bind(this),this.onInputKeyUp_=this.onInputKeyUp_.bind(this),this.onPointerDown_=this.onPointerDown_.bind(this),this.onPointerMove_=this.onPointerMove_.bind(this),this.onPointerUp_=this.onPointerUp_.bind(this),this.baseStep_=e.baseStep,this.parser_=e.parser,this.props=e.props,this.sliderProps_=null!==(n=e.sliderProps)&&void 0!==n?n:null,this.value=e.value,this.viewProps=e.viewProps,this.dragging_=d(null),this.view=new wt(t,{arrayPosition:e.arrayPosition,dragging:this.dragging_,props:this.props,value:this.value,viewProps:this.viewProps}),this.view.inputElement.addEventListener("change",this.onInputChange_),this.view.inputElement.addEventListener("keydown",this.onInputKeyDown_),this.view.inputElement.addEventListener("keyup",this.onInputKeyUp_);const i=new pt(this.view.knobElement);i.emitter.on("down",this.onPointerDown_),i.emitter.on("move",this.onPointerMove_),i.emitter.on("up",this.onPointerUp_)}constrainValue_(t){var e,n;const i=null===(e=this.sliderProps_)||void 0===e?void 0:e.get("minValue"),s=null===(n=this.sliderProps_)||void 0===n?void 0:n.get("maxValue");let o=t;return void 0!==i&&(o=Math.max(o,i)),void 0!==s&&(o=Math.min(o,s)),o}onInputChange_(t){const n=t.currentTarget.value,i=this.parser_(n);e(i)||(this.value.rawValue=this.constrainValue_(i)),this.view.refresh()}onInputKeyDown_(t){const e=at(this.baseStep_,lt(t));0!==e&&this.value.setRawValue(this.constrainValue_(this.value.rawValue+e),{forceEmit:!1,last:!1})}onInputKeyUp_(t){0!==at(this.baseStep_,lt(t))&&this.value.setRawValue(this.value.rawValue,{forceEmit:!0,last:!0})}onPointerDown_(){this.originRawValue_=this.value.rawValue,this.dragging_.rawValue=0}computeDraggingValue_(t){if(!t.point)return null;const e=t.point.x-t.bounds.width/2;return this.constrainValue_(this.originRawValue_+e*this.props.get("draggingScale"))}onPointerMove_(t){const e=this.computeDraggingValue_(t.data);null!==e&&(this.value.setRawValue(e,{forceEmit:!1,last:!1}),this.dragging_.rawValue=this.value.rawValue-this.originRawValue_)}onPointerUp_(t){const e=this.computeDraggingValue_(t.data);null!==e&&(this.value.setRawValue(e,{forceEmit:!0,last:!0}),this.dragging_.rawValue=null)}}r("sld");r("sldtxt");function bt(t,e){t.write(e)}function yt(t){if("inline"===t||"popup"===t)return t}function xt(t){const e=_;return e.required.object({max:e.optional.number,min:e.optional.number,step:e.optional.number})(t).value}function Et(t,e){const n=t&&k(t,I);return n?mt(n.step):Math.max(mt(e),2)}function Ct(t){const e=function(t){const e=t?k(t,I):null;return e?e.step:null}(t);return null!=e?e:1}function Pt(t,e){var n;const i=t&&k(t,I),s=Math.abs(null!==(n=null==i?void 0:i.step)&&void 0!==n?n:e);return 0===s?.1:Math.pow(10,Math.floor(Math.log10(s))-1)}r("ckb");const Mt=r("col");class Vt{constructor(t,e){this.element=t.createElement("div"),this.element.classList.add(Mt()),e.foldable.bindExpandedClass(this.element,Mt(void 0,"expanded")),u(e.foldable,"completed",h(this.element,Mt(void 0,"cpl")));const n=t.createElement("div");n.classList.add(Mt("h")),this.element.appendChild(n);const i=t.createElement("div");i.classList.add(Mt("s")),n.appendChild(i),this.swatchElement=i;const s=t.createElement("div");if(s.classList.add(Mt("t")),n.appendChild(s),this.textElement=s,"inline"===e.pickerLayout){const e=t.createElement("div");e.classList.add(Mt("p")),this.element.appendChild(e),this.pickerElement=e}else this.pickerElement=null}}function $t(t,e,n){const i=vt(t,360),s=ft(e/100,0,1),o=ft(n/100,0,1),r=o*s,a=r*(1-Math.abs(i/60%2-1)),l=o-r;let u,h,c;return[u,h,c]=i>=0&&i<60?[r,a,0]:i>=60&&i<120?[a,r,0]:i>=120&&i<180?[0,r,a]:i>=180&&i<240?[0,a,r]:i>=240&&i<300?[a,0,r]:[r,0,a],[255*(u+l),255*(h+l),255*(c+l)]}function Lt(t){return[t[0],t[1],t[2]]}function kt(t,e){return[t[0],t[1],t[2],e]}const Dt={hsl:{hsl:(t,e,n)=>[t,e,n],hsv:function(t,e,n){const i=n+e*(100-Math.abs(2*n-100))/200;return[t,0!==i?e*(100-Math.abs(2*n-100))/i:0,n+e*(100-Math.abs(2*n-100))/200]},rgb:function(t,e,n){const i=(t%360+360)%360,s=ft(e/100,0,1),o=ft(n/100,0,1),r=(1-Math.abs(2*o-1))*s,a=r*(1-Math.abs(i/60%2-1)),l=o-r/2;let u,h,c;return[u,h,c]=i>=0&&i<60?[r,a,0]:i>=60&&i<120?[a,r,0]:i>=120&&i<180?[0,r,a]:i>=180&&i<240?[0,a,r]:i>=240&&i<300?[a,0,r]:[r,0,a],[255*(u+l),255*(h+l),255*(c+l)]}},hsv:{hsl:function(t,e,n){const i=100-Math.abs(n*(200-e)/100-100);return[t,0!==i?e*n/i:0,n*(200-e)/200]},hsv:(t,e,n)=>[t,e,n],rgb:$t},rgb:{hsl:function(t,e,n){const i=ft(t/255,0,1),s=ft(e/255,0,1),o=ft(n/255,0,1),r=Math.max(i,s,o),a=Math.min(i,s,o),l=r-a;let u=0,h=0;const c=(a+r)/2;return 0!==l&&(h=l/(1-Math.abs(r+a-1)),u=(u=i===r?(s-o)/l:s===r?2+(o-i)/l:4+(i-s)/l)/6+(u<0?1:0)),[360*u,100*h,100*c]},hsv:function(t,e,n){const i=ft(t/255,0,1),s=ft(e/255,0,1),o=ft(n/255,0,1),r=Math.max(i,s,o),a=r-Math.min(i,s,o);let l;return[l=0===a?0:r===i?((s-o)/a%6+6)%6*60:r===s?60*((o-i)/a+2):60*((i-s)/a+4),100*(0===r?0:a/r),100*r]},rgb:(t,e,n)=>[t,e,n]}};function St(t,e){return["float"===e?1:"rgb"===t?255:360,"float"===e?1:"rgb"===t?255:100,"float"===e?1:"rgb"===t?255:100]}function It(t,e,n,i){const s=St(e,n),o=St(e,i);return t.map((t,e)=>t/s[e]*o[e])}function Tt(t,n){return"object"==typeof t&&!e(t)&&n in t&&"number"==typeof t[n]}class Ft{static black(t="int"){return new Ft([0,0,0],"rgb",t)}static fromObject(t,e="int"){const n="a"in t?[t.r,t.g,t.b,t.a]:[t.r,t.g,t.b];return new Ft(n,"rgb",e)}static toRgbaObject(t,e="int"){return t.toRgbaObject(e)}static isRgbColorObject(t){return Tt(t,"r")&&Tt(t,"g")&&Tt(t,"b")}static isRgbaColorObject(t){return this.isRgbColorObject(t)&&Tt(t,"a")}static isColorObject(t){return this.isRgbColorObject(t)}static equals(t,e){if(t.mode!==e.mode)return!1;const n=t.comps_,i=e.comps_;for(let s=0;st.inputElement)];return this.alphaViews_&&t.push(this.alphaViews_.palette.element,this.alphaViews_.text.inputElement),t}}function Kt(t){return"int"===t?"int":"float"===t?"float":void 0}function Ot(t){const e=_;return w(t,{alpha:e.optional.boolean,color:e.optional.object({alpha:e.optional.boolean,type:e.optional.custom(Kt)}),expanded:e.optional.boolean,picker:e.optional.custom(yt)})}function jt(t){return t?.1:1}function Rt(t){var e;return null===(e=t.color)||void 0===e?void 0:e.type}function Ut(t,e){const n=t.match(/^(.+)%$/);return n?Math.min(.01*parseFloat(n[1])*e,e):Math.min(parseFloat(t),e)}const qt={deg:t=>t,grad:t=>360*t/400,rad:t=>360*t/(2*Math.PI),turn:t=>360*t};function Ht(t){const e=t.match(/^([0-9.]+?)(deg|grad|rad|turn)$/);if(!e)return parseFloat(t);const n=parseFloat(e[1]),i=e[2];return qt[i](n)}function Bt(t){const e=t.match(/^rgb\(\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*\)$/);if(!e)return null;const n=[Ut(e[1],255),Ut(e[2],255),Ut(e[3],255)];return isNaN(n[0])||isNaN(n[1])||isNaN(n[2])?null:n}function zt(t){return e=>{const n=Bt(e);return n?new Ft(n,"rgb",t):null}}function Yt(t){const e=t.match(/^rgba\(\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*\)$/);if(!e)return null;const n=[Ut(e[1],255),Ut(e[2],255),Ut(e[3],255),Ut(e[4],1)];return isNaN(n[0])||isNaN(n[1])||isNaN(n[2])||isNaN(n[3])?null:n}function Wt(t){return e=>{const n=Yt(e);return n?new Ft(n,"rgb",t):null}}function Gt(t){const e=t.match(/^hsl\(\s*([0-9A-Fa-f.]+(?:deg|grad|rad|turn)?)\s*,\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*\)$/);if(!e)return null;const n=[Ht(e[1]),Ut(e[2],100),Ut(e[3],100)];return isNaN(n[0])||isNaN(n[1])||isNaN(n[2])?null:n}function Xt(t){return e=>{const n=Gt(e);return n?new Ft(n,"hsl",t):null}}function Jt(t){const e=t.match(/^hsla\(\s*([0-9A-Fa-f.]+(?:deg|grad|rad|turn)?)\s*,\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*,\s*([0-9A-Fa-f.]+%?)\s*\)$/);if(!e)return null;const n=[Ht(e[1]),Ut(e[2],100),Ut(e[3],100),Ut(e[4],1)];return isNaN(n[0])||isNaN(n[1])||isNaN(n[2])||isNaN(n[3])?null:n}function Zt(t){return e=>{const n=Jt(e);return n?new Ft(n,"hsl",t):null}}function Qt(t){const e=t.match(/^#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/);if(e)return[parseInt(e[1]+e[1],16),parseInt(e[2]+e[2],16),parseInt(e[3]+e[3],16)];const n=t.match(/^(?:#|0x)([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/);return n?[parseInt(n[1],16),parseInt(n[2],16),parseInt(n[3],16)]:null}function te(t){const e=t.match(/^#?([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/);if(e)return[parseInt(e[1]+e[1],16),parseInt(e[2]+e[2],16),parseInt(e[3]+e[3],16),dt(parseInt(e[4]+e[4],16),0,255,0,1)];const n=t.match(/^(?:#|0x)?([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/);return n?[parseInt(n[1],16),parseInt(n[2],16),parseInt(n[3],16),dt(parseInt(n[4],16),0,255,0,1)]:null}function ee(t){const e=t.match(/^\{\s*r\s*:\s*([0-9A-Fa-f.]+%?)\s*,\s*g\s*:\s*([0-9A-Fa-f.]+%?)\s*,\s*b\s*:\s*([0-9A-Fa-f.]+%?)\s*\}$/);if(!e)return null;const n=[parseFloat(e[1]),parseFloat(e[2]),parseFloat(e[3])];return isNaN(n[0])||isNaN(n[1])||isNaN(n[2])?null:n}function ne(t){return e=>{const n=ee(e);return n?new Ft(n,"rgb",t):null}}function ie(t){const e=t.match(/^\{\s*r\s*:\s*([0-9A-Fa-f.]+%?)\s*,\s*g\s*:\s*([0-9A-Fa-f.]+%?)\s*,\s*b\s*:\s*([0-9A-Fa-f.]+%?)\s*,\s*a\s*:\s*([0-9A-Fa-f.]+%?)\s*\}$/);if(!e)return null;const n=[parseFloat(e[1]),parseFloat(e[2]),parseFloat(e[3]),parseFloat(e[4])];return isNaN(n[0])||isNaN(n[1])||isNaN(n[2])||isNaN(n[3])?null:n}function se(t){return e=>{const n=ie(e);return n?new Ft(n,"rgb",t):null}}const oe=[{parser:Qt,result:{alpha:!1,mode:"rgb",notation:"hex"}},{parser:te,result:{alpha:!0,mode:"rgb",notation:"hex"}},{parser:Bt,result:{alpha:!1,mode:"rgb",notation:"func"}},{parser:Yt,result:{alpha:!0,mode:"rgb",notation:"func"}},{parser:Gt,result:{alpha:!1,mode:"hsl",notation:"func"}},{parser:Jt,result:{alpha:!0,mode:"hsl",notation:"func"}},{parser:ee,result:{alpha:!1,mode:"rgb",notation:"object"}},{parser:ie,result:{alpha:!0,mode:"rgb",notation:"object"}}];function re(t,e="int"){const n=function(t){return oe.reduce((e,{parser:n,result:i})=>e||(n(t)?i:null),null)}(t);return n?"hex"===n.notation&&"float"!==e?Object.assign(Object.assign({},n),{type:"int"}):"func"===n.notation?Object.assign(Object.assign({},n),{type:e}):null:null}const ae={int:[function(t){const e=Qt(t);return e?new Ft(e,"rgb","int"):null},function(t){const e=te(t);return e?new Ft(e,"rgb","int"):null},zt("int"),Wt("int"),Xt("int"),Zt("int"),ne("int"),se("int")],float:[zt("float"),Wt("float"),Xt("float"),Zt("float"),ne("float"),se("float")]};function le(t){const e=ae[t];return t=>e.reduce((e,n)=>e||n(t),null)}function ue(t){const e=ft(Math.floor(t),0,255).toString(16);return 1===e.length?"0"+e:e}function he(t,e="#"){return`${e}${Lt(t.getComponents("rgb")).map(ue).join("")}`}function ce(t,e="#"){const n=t.getComponents("rgb");return`${e}${[n[0],n[1],n[2],255*n[3]].map(ue).join("")}`}function pe(t,e){const n=it("float"===e?2:0);return`rgb(${Lt(t.getComponents("rgb",e)).map(t=>n(t)).join(", ")})`}function de(t){return e=>pe(e,t)}function me(t,e){const n=it(2),i=it("float"===e?2:0);return`rgba(${t.getComponents("rgb",e).map((t,e)=>(3===e?n:i)(t)).join(", ")})`}function fe(t){return e=>me(e,t)}function ve(t,e){const n=it("float"===e?2:0),i=["r","g","b"];return`{${Lt(t.getComponents("rgb",e)).map((t,e)=>`${i[e]}: ${n(t)}`).join(", ")}}`}function _e(t){return e=>ve(e,t)}function we(t,e){const n=it(2),i=it("float"===e?2:0),s=["r","g","b","a"];return`{${t.getComponents("rgb",e).map((t,e)=>`${s[e]}: ${(3===e?n:i)(t)}`).join(", ")}}`}function ge(t){return e=>we(e,t)}const be=[{format:{alpha:!1,mode:"rgb",notation:"hex",type:"int"},stringifier:he},{format:{alpha:!0,mode:"rgb",notation:"hex",type:"int"},stringifier:ce},{format:{alpha:!1,mode:"hsl",notation:"func",type:"int"},stringifier:function(t){const e=[it(0),ot,ot];return`hsl(${Lt(t.getComponents("hsl")).map((t,n)=>e[n](t)).join(", ")})`}},{format:{alpha:!0,mode:"hsl",notation:"func",type:"int"},stringifier:function(t){const e=[it(0),ot,ot,it(2)];return`hsla(${t.getComponents("hsl").map((t,n)=>e[n](t)).join(", ")})`}},...["int","float"].reduce((t,e)=>[...t,{format:{alpha:!1,mode:"rgb",notation:"func",type:e},stringifier:de(e)},{format:{alpha:!0,mode:"rgb",notation:"func",type:e},stringifier:fe(e)},{format:{alpha:!1,mode:"rgb",notation:"object",type:e},stringifier:_e(e)},{format:{alpha:!0,mode:"rgb",notation:"object",type:e},stringifier:ge(e)}],[])];function ye(t){return be.reduce((e,n)=>{return e||(i=n.format,s=t,i.alpha===s.alpha&&i.mode===s.mode&&i.notation===s.notation&&i.type===s.type?n.stringifier:null);var i,s},null)}const xe=r("apl");class Ee{constructor(t,e){this.onValueChange_=this.onValueChange_.bind(this),this.value=e.value,this.value.emitter.on("change",this.onValueChange_),this.element=t.createElement("div"),this.element.classList.add(xe()),e.viewProps.bindClassModifiers(this.element),e.viewProps.bindTabIndex(this.element);const n=t.createElement("div");n.classList.add(xe("b")),this.element.appendChild(n);const i=t.createElement("div");i.classList.add(xe("c")),n.appendChild(i),this.colorElem_=i;const s=t.createElement("div");s.classList.add(xe("m")),this.element.appendChild(s),this.markerElem_=s;const o=t.createElement("div");o.classList.add(xe("p")),this.markerElem_.appendChild(o),this.previewElem_=o,this.update_()}update_(){const t=this.value.rawValue,e=t.getComponents("rgb"),n=new Ft([e[0],e[1],e[2],0],"rgb"),i=new Ft([e[0],e[1],e[2],255],"rgb"),s=["to right",me(n),me(i)];this.colorElem_.style.background=`linear-gradient(${s.join(",")})`,this.previewElem_.style.backgroundColor=me(t);const o=dt(e[3],0,1,0,100);this.markerElem_.style.left=o+"%"}onValueChange_(){this.update_()}}class Ce{constructor(t,e){this.onKeyDown_=this.onKeyDown_.bind(this),this.onKeyUp_=this.onKeyUp_.bind(this),this.onPointerDown_=this.onPointerDown_.bind(this),this.onPointerMove_=this.onPointerMove_.bind(this),this.onPointerUp_=this.onPointerUp_.bind(this),this.value=e.value,this.viewProps=e.viewProps,this.view=new Ee(t,{value:this.value,viewProps:this.viewProps}),this.ptHandler_=new pt(this.view.element),this.ptHandler_.emitter.on("down",this.onPointerDown_),this.ptHandler_.emitter.on("move",this.onPointerMove_),this.ptHandler_.emitter.on("up",this.onPointerUp_),this.view.element.addEventListener("keydown",this.onKeyDown_),this.view.element.addEventListener("keyup",this.onKeyUp_)}handlePointerEvent_(t,e){if(!t.point)return;const n=t.point.x/t.bounds.width,i=this.value.rawValue,[s,o,r]=i.getComponents("hsv");this.value.setRawValue(new Ft([s,o,r,n],"hsv"),e)}onPointerDown_(t){this.handlePointerEvent_(t.data,{forceEmit:!1,last:!1})}onPointerMove_(t){this.handlePointerEvent_(t.data,{forceEmit:!1,last:!1})}onPointerUp_(t){this.handlePointerEvent_(t.data,{forceEmit:!0,last:!0})}onKeyDown_(t){const e=at(jt(!0),ut(t));if(0===e)return;const n=this.value.rawValue,[i,s,o,r]=n.getComponents("hsv");this.value.setRawValue(new Ft([i,s,o,r+e],"hsv"),{forceEmit:!1,last:!1})}onKeyUp_(t){0!==at(jt(!0),ut(t))&&this.value.setRawValue(this.value.rawValue,{forceEmit:!0,last:!0})}}const Pe=r("coltxt");class Me{constructor(t,e){this.element=t.createElement("div"),this.element.classList.add(Pe()),e.viewProps.bindClassModifiers(this.element);const n=t.createElement("div");n.classList.add(Pe("m")),this.modeElem_=function(t){const e=t.createElement("select");return e.appendChild([{text:"RGB",value:"rgb"},{text:"HSL",value:"hsl"},{text:"HSV",value:"hsv"}].reduce((e,n)=>{const i=t.createElement("option");return i.textContent=n.text,i.value=n.value,e.appendChild(i),e},t.createDocumentFragment())),e}(t),this.modeElem_.classList.add(Pe("ms")),n.appendChild(this.modeSelectElement),e.viewProps.bindDisabled(this.modeElem_);const i=t.createElement("div");i.classList.add(Pe("mm")),i.appendChild(E(t,"dropdown")),n.appendChild(i),this.element.appendChild(n);const s=t.createElement("div");s.classList.add(Pe("w")),this.element.appendChild(s),this.textsElem_=s,this.textViews_=e.textViews,this.applyTextViews_(),l(e.colorMode,t=>{this.modeElem_.value=t})}get modeSelectElement(){return this.modeElem_}get textViews(){return this.textViews_}set textViews(t){this.textViews_=t,this.applyTextViews_()}applyTextViews_(){C(this.textsElem_);const t=this.element.ownerDocument;this.textViews_.forEach(e=>{const n=t.createElement("div");n.classList.add(Pe("c")),n.appendChild(e.element),this.textsElem_.appendChild(n)})}}function Ve(t,e,n){const i=St(t,e)[n];return new D({min:0,max:i})}function $e(t,e,n){return new gt(t,{arrayPosition:0===n?"fst":2===n?"lst":"mid",baseStep:jt(!1),parser:e.parser,props:m.fromObject({draggingScale:"float"===e.colorType?.01:1,formatter:(i=e.colorType,it("float"===i?2:0))}),value:d(0,{constraint:Ve(e.colorMode,e.colorType,n)}),viewProps:e.viewProps});var i}class Le{constructor(t,e){this.onModeSelectChange_=this.onModeSelectChange_.bind(this),this.colorType_=e.colorType,this.parser_=e.parser,this.value=e.value,this.viewProps=e.viewProps,this.colorMode=d(this.value.rawValue.mode),this.ccs_=this.createComponentControllers_(t),this.view=new Me(t,{colorMode:this.colorMode,textViews:[this.ccs_[0].view,this.ccs_[1].view,this.ccs_[2].view],viewProps:this.viewProps}),this.view.modeSelectElement.addEventListener("change",this.onModeSelectChange_)}createComponentControllers_(t){const e={colorMode:this.colorMode.rawValue,colorType:this.colorType_,parser:this.parser_,viewProps:this.viewProps},n=[$e(t,e,0),$e(t,e,1),$e(t,e,2)];return n.forEach((t,e)=>{rt({primary:this.value,secondary:t.value,forward:t=>t.rawValue.getComponents(this.colorMode.rawValue,this.colorType_)[e],backward:(t,n)=>{const i=this.colorMode.rawValue,s=t.rawValue.getComponents(i,this.colorType_);return s[e]=n.rawValue,new Ft(kt(Lt(s),s[3]),i,this.colorType_)}})}),n}onModeSelectChange_(t){const e=t.currentTarget;this.colorMode.rawValue=e.value,this.ccs_=this.createComponentControllers_(this.view.element.ownerDocument),this.view.textViews=[this.ccs_[0].view,this.ccs_[1].view,this.ccs_[2].view]}}const ke=r("hpl");class De{constructor(t,e){this.onValueChange_=this.onValueChange_.bind(this),this.value=e.value,this.value.emitter.on("change",this.onValueChange_),this.element=t.createElement("div"),this.element.classList.add(ke()),e.viewProps.bindClassModifiers(this.element),e.viewProps.bindTabIndex(this.element);const n=t.createElement("div");n.classList.add(ke("c")),this.element.appendChild(n);const i=t.createElement("div");i.classList.add(ke("m")),this.element.appendChild(i),this.markerElem_=i,this.update_()}update_(){const t=this.value.rawValue,[e]=t.getComponents("hsv");this.markerElem_.style.backgroundColor=pe(new Ft([e,100,100],"hsv"));const n=dt(e,0,360,0,100);this.markerElem_.style.left=n+"%"}onValueChange_(){this.update_()}}class Se{constructor(t,e){this.onKeyDown_=this.onKeyDown_.bind(this),this.onKeyUp_=this.onKeyUp_.bind(this),this.onPointerDown_=this.onPointerDown_.bind(this),this.onPointerMove_=this.onPointerMove_.bind(this),this.onPointerUp_=this.onPointerUp_.bind(this),this.value=e.value,this.viewProps=e.viewProps,this.view=new De(t,{value:this.value,viewProps:this.viewProps}),this.ptHandler_=new pt(this.view.element),this.ptHandler_.emitter.on("down",this.onPointerDown_),this.ptHandler_.emitter.on("move",this.onPointerMove_),this.ptHandler_.emitter.on("up",this.onPointerUp_),this.view.element.addEventListener("keydown",this.onKeyDown_),this.view.element.addEventListener("keyup",this.onKeyUp_)}handlePointerEvent_(t,e){if(!t.point)return;const n=dt(ft(t.point.x,0,t.bounds.width),0,t.bounds.width,0,360),i=this.value.rawValue,[,s,o,r]=i.getComponents("hsv");this.value.setRawValue(new Ft([n,s,o,r],"hsv"),e)}onPointerDown_(t){this.handlePointerEvent_(t.data,{forceEmit:!1,last:!1})}onPointerMove_(t){this.handlePointerEvent_(t.data,{forceEmit:!1,last:!1})}onPointerUp_(t){this.handlePointerEvent_(t.data,{forceEmit:!0,last:!0})}onKeyDown_(t){const e=at(jt(!1),ut(t));if(0===e)return;const n=this.value.rawValue,[i,s,o,r]=n.getComponents("hsv");this.value.setRawValue(new Ft([i+e,s,o,r],"hsv"),{forceEmit:!1,last:!1})}onKeyUp_(t){0!==at(jt(!1),ut(t))&&this.value.setRawValue(this.value.rawValue,{forceEmit:!0,last:!0})}}const Ie=r("svp");class Te{constructor(t,e){this.onValueChange_=this.onValueChange_.bind(this),this.value=e.value,this.value.emitter.on("change",this.onValueChange_),this.element=t.createElement("div"),this.element.classList.add(Ie()),e.viewProps.bindClassModifiers(this.element),e.viewProps.bindTabIndex(this.element);const n=t.createElement("canvas");n.height=64,n.width=64,n.classList.add(Ie("c")),this.element.appendChild(n),this.canvasElement=n;const i=t.createElement("div");i.classList.add(Ie("m")),this.element.appendChild(i),this.markerElem_=i,this.update_()}update_(){const t=function(t){const e=t.ownerDocument.defaultView;return e&&"document"in e?t.getContext("2d",{willReadFrequently:!0}):null}(this.canvasElement);if(!t)return;const e=this.value.rawValue.getComponents("hsv"),n=this.canvasElement.width,i=this.canvasElement.height,s=t.getImageData(0,0,n,i),o=s.data;for(let l=0;lt.rawValue.getComponents()[3],backward:(t,e)=>{const n=t.rawValue.getComponents();return n[3]=e.rawValue,new Ft(n,t.rawValue.mode)}}),this.textC_=new Le(t,{colorType:e.colorType,parser:nt,value:this.value,viewProps:this.viewProps}),this.view=new At(t,{alphaViews:this.alphaIcs_?{palette:this.alphaIcs_.palette.view,text:this.alphaIcs_.text.view}:null,hPaletteView:this.hPaletteC_.view,supportsAlpha:e.supportsAlpha,svPaletteView:this.svPaletteC_.view,textView:this.textC_.view,viewProps:this.viewProps})}get textController(){return this.textC_}}const Ae=r("colsw");class Ke{constructor(t,e){this.onValueChange_=this.onValueChange_.bind(this),e.value.emitter.on("change",this.onValueChange_),this.value=e.value,this.element=t.createElement("div"),this.element.classList.add(Ae()),e.viewProps.bindClassModifiers(this.element);const n=t.createElement("div");n.classList.add(Ae("sw")),this.element.appendChild(n),this.swatchElem_=n;const i=t.createElement("button");i.classList.add(Ae("b")),e.viewProps.bindDisabled(i),this.element.appendChild(i),this.buttonElement=i,this.update_()}update_(){const t=this.value.rawValue;this.swatchElem_.style.backgroundColor=ce(t)}onValueChange_(){this.update_()}}class Oe{constructor(t,e){this.value=e.value,this.viewProps=e.viewProps,this.view=new Ke(t,{value:this.value,viewProps:this.viewProps})}}class je{constructor(t,e){this.onButtonBlur_=this.onButtonBlur_.bind(this),this.onButtonClick_=this.onButtonClick_.bind(this),this.onPopupChildBlur_=this.onPopupChildBlur_.bind(this),this.onPopupChildKeydown_=this.onPopupChildKeydown_.bind(this),this.value=e.value,this.viewProps=e.viewProps,this.foldable_=M.create(e.expanded),this.swatchC_=new Oe(t,{value:this.value,viewProps:this.viewProps});const n=this.swatchC_.view.buttonElement;n.addEventListener("blur",this.onButtonBlur_),n.addEventListener("click",this.onButtonClick_),this.textC_=new O(t,{parser:e.parser,props:m.fromObject({formatter:e.formatter}),value:this.value,viewProps:this.viewProps}),this.view=new Vt(t,{foldable:this.foldable_,pickerLayout:e.pickerLayout}),this.view.swatchElement.appendChild(this.swatchC_.view.element),this.view.textElement.appendChild(this.textC_.view.element),this.popC_="popup"===e.pickerLayout?new N(t,{viewProps:this.viewProps}):null;const i=new Ne(t,{colorType:e.colorType,supportsAlpha:e.supportsAlpha,value:this.value,viewProps:this.viewProps});i.view.allFocusableElements.forEach(t=>{t.addEventListener("blur",this.onPopupChildBlur_),t.addEventListener("keydown",this.onPopupChildKeydown_)}),this.pickerC_=i,this.popC_?(this.view.element.appendChild(this.popC_.view.element),this.popC_.view.element.appendChild(i.view.element),rt({primary:this.foldable_.value("expanded"),secondary:this.popC_.shows,forward:t=>t.rawValue,backward:(t,e)=>e.rawValue})):this.view.pickerElement&&(this.view.pickerElement.appendChild(this.pickerC_.view.element),$(this.foldable_,this.view.pickerElement))}get textController(){return this.textC_}onButtonBlur_(t){if(!this.popC_)return;const e=this.view.element,n=t.relatedTarget;n&&e.contains(n)||(this.popC_.shows.rawValue=!1)}onButtonClick_(){this.foldable_.set("expanded",!this.foldable_.get("expanded")),this.foldable_.get("expanded")&&this.pickerC_.view.allFocusableElements[0].focus()}onPopupChildBlur_(t){if(!this.popC_)return;const e=this.popC_.view.element,n=P(t);n&&e.contains(n)||n&&n===this.swatchC_.view.buttonElement&&!y(e.ownerDocument)||(this.popC_.shows.rawValue=!1)}onPopupChildKeydown_(t){this.popC_?"Escape"===t.key&&(this.popC_.shows.rawValue=!1):this.view.pickerElement&&"Escape"===t.key&&this.swatchC_.view.buttonElement.focus()}}function Re(t){return Lt(t.getComponents("rgb")).reduce((t,e)=>t<<8|255&Math.floor(e),0)}function Ue(t){return t.getComponents("rgb").reduce((t,e,n)=>t<<8|255&Math.floor(3===n?255*e:e),0)>>>0}function qe(t){return"number"!=typeof t?Ft.black():new Ft([(e=t)>>16&255,e>>8&255,255&e],"rgb");var e}function He(t){return"number"!=typeof t?Ft.black():new Ft([(e=t)>>24&255,e>>16&255,e>>8&255,dt(255&e,0,255,0,1)],"rgb");var e}function Be(t){var e;return!(!(null==t?void 0:t.alpha)&&!(null===(e=null==t?void 0:t.color)||void 0===e?void 0:e.alpha))}function ze(t){return t?t=>ce(t,"0x"):t=>he(t,"0x")}Ft.equals;function Ye(t,e){return n=>t?we(n,e):ve(n,e)}Ft.equals,Ft.equals;class We{constructor(t){this.components=t.components,this.asm_=t.assembly}constrain(t){const e=this.asm_.toComponents(t).map((t,e)=>{var n,i;return null!==(i=null===(n=this.components[e])||void 0===n?void 0:n.constrain(t))&&void 0!==i?i:t});return this.asm_.fromComponents(e)}}const Ge=r("pndtxt");class Xe{constructor(t,e){this.textViews=e.textViews,this.element=t.createElement("div"),this.element.classList.add(Ge()),this.textViews.forEach(e=>{const n=t.createElement("div");n.classList.add(Ge("a")),n.appendChild(e.element),this.element.appendChild(n)})}}class Je{constructor(t,e){this.value=e.value,this.viewProps=e.viewProps,this.acs_=e.axes.map((n,i)=>function(t,e,n){return new gt(t,{arrayPosition:0===n?"fst":n===e.axes.length-1?"lst":"mid",baseStep:e.axes[n].baseStep,parser:e.parser,props:e.axes[n].textProps,value:d(0,{constraint:e.axes[n].constraint}),viewProps:e.viewProps})}(t,e,i)),this.acs_.forEach((t,n)=>{rt({primary:this.value,secondary:t.value,forward:t=>e.assembly.toComponents(t.rawValue)[n],backward:(t,i)=>{const s=e.assembly.toComponents(t.rawValue);return s[n]=i.rawValue,e.assembly.fromComponents(s)}})}),this.view=new Xe(t,{textViews:this.acs_.map(t=>t.view)})}}function Ze(t,n){return"step"in t&&!e(t.step)?new I(t.step,n):null}function Qe(t){return e(t.max)||e(t.min)?e(t.max)&&e(t.min)?null:new S({max:t.max,min:t.min}):new D({max:t.max,min:t.min})}class tn{constructor(t=0,e=0){this.x=t,this.y=e}getComponents(){return[this.x,this.y]}static isObject(t){if(e(t))return!1;const n=t.x,i=t.y;return"number"==typeof n&&"number"==typeof i}static equals(t,e){return t.x===e.x&&t.y===e.y}toObject(){return{x:this.x,y:this.y}}}const en={toComponents:t=>t.getComponents(),fromComponents:t=>new tn(...t)},nn=r("p2d");class sn{constructor(t,e){this.element=t.createElement("div"),this.element.classList.add(nn()),e.viewProps.bindClassModifiers(this.element),l(e.expanded,h(this.element,nn(void 0,"expanded")));const n=t.createElement("div");n.classList.add(nn("h")),this.element.appendChild(n);const i=t.createElement("button");i.classList.add(nn("b")),i.appendChild(E(t,"p2dpad")),e.viewProps.bindDisabled(i),n.appendChild(i),this.buttonElement=i;const s=t.createElement("div");if(s.classList.add(nn("t")),n.appendChild(s),this.textElement=s,"inline"===e.pickerLayout){const e=t.createElement("div");e.classList.add(nn("p")),this.element.appendChild(e),this.pickerElement=e}else this.pickerElement=null}}const on=r("p2dp");class rn{constructor(t,e){this.onFoldableChange_=this.onFoldableChange_.bind(this),this.onValueChange_=this.onValueChange_.bind(this),this.invertsY_=e.invertsY,this.maxValue_=e.maxValue,this.element=t.createElement("div"),this.element.classList.add(on()),"popup"===e.layout&&this.element.classList.add(on(void 0,"p")),e.viewProps.bindClassModifiers(this.element);const n=t.createElement("div");n.classList.add(on("p")),e.viewProps.bindTabIndex(n),this.element.appendChild(n),this.padElement=n;const i=t.createElementNS(g,"svg");i.classList.add(on("g")),this.padElement.appendChild(i),this.svgElem_=i;const s=t.createElementNS(g,"line");s.classList.add(on("ax")),s.setAttributeNS(null,"x1","0"),s.setAttributeNS(null,"y1","50%"),s.setAttributeNS(null,"x2","100%"),s.setAttributeNS(null,"y2","50%"),this.svgElem_.appendChild(s);const o=t.createElementNS(g,"line");o.classList.add(on("ax")),o.setAttributeNS(null,"x1","50%"),o.setAttributeNS(null,"y1","0"),o.setAttributeNS(null,"x2","50%"),o.setAttributeNS(null,"y2","100%"),this.svgElem_.appendChild(o);const r=t.createElementNS(g,"line");r.classList.add(on("l")),r.setAttributeNS(null,"x1","50%"),r.setAttributeNS(null,"y1","50%"),this.svgElem_.appendChild(r),this.lineElem_=r;const a=t.createElement("div");a.classList.add(on("m")),this.padElement.appendChild(a),this.markerElem_=a,e.value.emitter.on("change",this.onValueChange_),this.value=e.value,this.update_()}get allFocusableElements(){return[this.padElement]}update_(){const[t,e]=this.value.rawValue.getComponents(),n=this.maxValue_,i=dt(t,-n,+n,0,100),s=dt(e,-n,+n,0,100),o=this.invertsY_?100-s:s;this.lineElem_.setAttributeNS(null,"x2",i+"%"),this.lineElem_.setAttributeNS(null,"y2",o+"%"),this.markerElem_.style.left=i+"%",this.markerElem_.style.top=o+"%"}onValueChange_(){this.update_()}onFoldableChange_(){this.update_()}}function an(t,e,n){return[at(e[0],ut(t)),at(e[1],lt(t))*(n?1:-1)]}class ln{constructor(t,e){this.onPadKeyDown_=this.onPadKeyDown_.bind(this),this.onPadKeyUp_=this.onPadKeyUp_.bind(this),this.onPointerDown_=this.onPointerDown_.bind(this),this.onPointerMove_=this.onPointerMove_.bind(this),this.onPointerUp_=this.onPointerUp_.bind(this),this.value=e.value,this.viewProps=e.viewProps,this.baseSteps_=e.baseSteps,this.maxValue_=e.maxValue,this.invertsY_=e.invertsY,this.view=new rn(t,{invertsY:this.invertsY_,layout:e.layout,maxValue:this.maxValue_,value:this.value,viewProps:this.viewProps}),this.ptHandler_=new pt(this.view.padElement),this.ptHandler_.emitter.on("down",this.onPointerDown_),this.ptHandler_.emitter.on("move",this.onPointerMove_),this.ptHandler_.emitter.on("up",this.onPointerUp_),this.view.padElement.addEventListener("keydown",this.onPadKeyDown_),this.view.padElement.addEventListener("keyup",this.onPadKeyUp_)}handlePointerEvent_(t,e){if(!t.point)return;const n=this.maxValue_,i=dt(t.point.x,0,t.bounds.width,-n,+n),s=dt(this.invertsY_?t.bounds.height-t.point.y:t.point.y,0,t.bounds.height,-n,+n);this.value.setRawValue(new tn(i,s),e)}onPointerDown_(t){this.handlePointerEvent_(t.data,{forceEmit:!1,last:!1})}onPointerMove_(t){this.handlePointerEvent_(t.data,{forceEmit:!1,last:!1})}onPointerUp_(t){this.handlePointerEvent_(t.data,{forceEmit:!0,last:!0})}onPadKeyDown_(t){ht(t.key)&&t.preventDefault();const[e,n]=an(t,this.baseSteps_,this.invertsY_);0===e&&0===n||this.value.setRawValue(new tn(this.value.rawValue.x+e,this.value.rawValue.y+n),{forceEmit:!1,last:!1})}onPadKeyUp_(t){const[e,n]=an(t,this.baseSteps_,this.invertsY_);0===e&&0===n||this.value.setRawValue(this.value.rawValue,{forceEmit:!0,last:!0})}}class un{constructor(t,e){var n,i;this.onPopupChildBlur_=this.onPopupChildBlur_.bind(this),this.onPopupChildKeydown_=this.onPopupChildKeydown_.bind(this),this.onPadButtonBlur_=this.onPadButtonBlur_.bind(this),this.onPadButtonClick_=this.onPadButtonClick_.bind(this),this.value=e.value,this.viewProps=e.viewProps,this.foldable_=M.create(e.expanded),this.popC_="popup"===e.pickerLayout?new N(t,{viewProps:this.viewProps}):null;const s=new ln(t,{baseSteps:[e.axes[0].baseStep,e.axes[1].baseStep],invertsY:e.invertsY,layout:e.pickerLayout,maxValue:e.maxValue,value:this.value,viewProps:this.viewProps});s.view.allFocusableElements.forEach(t=>{t.addEventListener("blur",this.onPopupChildBlur_),t.addEventListener("keydown",this.onPopupChildKeydown_)}),this.pickerC_=s,this.textC_=new Je(t,{assembly:en,axes:e.axes,parser:e.parser,value:this.value,viewProps:this.viewProps}),this.view=new sn(t,{expanded:this.foldable_.value("expanded"),pickerLayout:e.pickerLayout,viewProps:this.viewProps}),this.view.textElement.appendChild(this.textC_.view.element),null===(n=this.view.buttonElement)||void 0===n||n.addEventListener("blur",this.onPadButtonBlur_),null===(i=this.view.buttonElement)||void 0===i||i.addEventListener("click",this.onPadButtonClick_),this.popC_?(this.view.element.appendChild(this.popC_.view.element),this.popC_.view.element.appendChild(this.pickerC_.view.element),rt({primary:this.foldable_.value("expanded"),secondary:this.popC_.shows,forward:t=>t.rawValue,backward:(t,e)=>e.rawValue})):this.view.pickerElement&&(this.view.pickerElement.appendChild(this.pickerC_.view.element),$(this.foldable_,this.view.pickerElement))}onPadButtonBlur_(t){if(!this.popC_)return;const e=this.view.element,n=t.relatedTarget;n&&e.contains(n)||(this.popC_.shows.rawValue=!1)}onPadButtonClick_(){this.foldable_.set("expanded",!this.foldable_.get("expanded")),this.foldable_.get("expanded")&&this.pickerC_.view.allFocusableElements[0].focus()}onPopupChildBlur_(t){if(!this.popC_)return;const e=this.popC_.view.element,n=P(t);n&&e.contains(n)||n&&n===this.view.buttonElement&&!y(e.ownerDocument)||(this.popC_.shows.rawValue=!1)}onPopupChildKeydown_(t){this.popC_?"Escape"===t.key&&(this.popC_.shows.rawValue=!1):this.view.pickerElement&&"Escape"===t.key&&this.view.buttonElement.focus()}}class hn{constructor(t=0,e=0,n=0){this.x=t,this.y=e,this.z=n}getComponents(){return[this.x,this.y,this.z]}static isObject(t){if(e(t))return!1;const n=t.x,i=t.y,s=t.z;return"number"==typeof n&&"number"==typeof i&&"number"==typeof s}static equals(t,e){return t.x===e.x&&t.y===e.y&&t.z===e.z}toObject(){return{x:this.x,y:this.y,z:this.z}}}const cn={toComponents:t=>t.getComponents(),fromComponents:t=>new hn(...t)};function pn(t,e){return{baseStep:Ct(e),constraint:e,textProps:m.fromObject({draggingScale:Pt(e,t),formatter:it(Et(e,t))})}}hn.equals;class dn{constructor(t=0,e=0,n=0,i=0){this.x=t,this.y=e,this.z=n,this.w=i}getComponents(){return[this.x,this.y,this.z,this.w]}static isObject(t){if(e(t))return!1;const n=t.x,i=t.y,s=t.z,o=t.w;return"number"==typeof n&&"number"==typeof i&&"number"==typeof s&&"number"==typeof o}static equals(t,e){return t.x===e.x&&t.y===e.y&&t.z===e.z&&t.w===e.w}toObject(){return{x:this.x,y:this.y,z:this.z,w:this.w}}}const mn={toComponents:t=>t.getComponents(),fromComponents:t=>new dn(...t)};dn.equals,r("mll");r("sgl");r("grl");function fn(t,e){if(!t)return;const n=[],i=Ze(t,e);i&&n.push(i);const s=Qe(t);return s&&n.push(s),new L(n)}function vn(t,n){const[i,s]=t?function(t){const e=k(t,D);if(e)return[e.values.get("min"),e.values.get("max")];const n=k(t,S);return n?[n.minValue,n.maxValue]:[void 0,void 0]}(t):[];if(!e(i)||!e(s))return Math.max(Math.abs(null!=i?i:0),Math.abs(null!=s?s:0));const o=Ct(t);return Math.max(10*Math.abs(o),10*Math.abs(n))}function _n(t,e){const n=e instanceof We?e.components[0]:void 0,i=e instanceof We?e.components[1]:void 0,s=vn(n,t.x),o=vn(i,t.y);return Math.max(s,o)}function wn(t,e){return{baseStep:Ct(e),constraint:e,textProps:m.fromObject({draggingScale:Pt(e,t),formatter:it(Et(e,t))})}}function gn(t){if(!("y"in t))return!1;const e=t.y;return!!e&&"inverted"in e&&!!e.inverted}tn.equals;new class{constructor(t){const[e,n]=t.split("-"),i=e.split(".");this.major=parseInt(i[0],10),this.minor=parseInt(i[1],10),this.patch=parseInt(i[2],10),this.prerelease=null!=n?n:null}toString(){const t=[this.major,this.minor,this.patch].join(".");return null!==this.prerelease?[t,this.prerelease].join("-"):t}}("3.1.7");Object.defineProperty(t,"__esModule",{value:!0})},"object"==typeof _$tweakpane_42.exports?factory(_$tweakpane_42.exports):"function"==typeof define&&define.amd?define(["exports"],factory):factory((__global_42="undefined"!=typeof globalThis?globalThis:__global_42||self).Tweakpane={}),_$tweakpane_42=_$tweakpane_42.exports;var _$multiline_1={};const{shuffle:shuffle,shuffleScroll:shuffleScroll,directions:__directions_1,animations:__animations_1}=_$txtShuffle_2,{split:split}=_$js_3;let elPreset,canvas,context,lines=[],linesShuffle=[],idxPreset=-1,__text_1="We chase misprinted lies\nWe face the path of time\nAnd yet I fight, and yet I fight\nThis battle all alone\nNo one to cry to\nNo place to call home";const presets=[{fn:"shuffle",glyphs:"_"},{fn:"shuffle"},{fn:"shuffle",glyphs:"\u2582\u2584\u2586",fps:40},{fn:"shuffle",glyphs:"weruoaszxcvnm",direction:__directions_1.RANDOM}],setup=()=>{elPreset=document.querySelector(".preset"),canvas=document.querySelector("canvas"),(context=canvas.getContext("2d")).font="48px monospace",window.addEventListener("resize",resize),canvas.addEventListener("click",onCanvasClick),resize(),animate(),onCanvasClick()},draw=()=>{context.fillStyle="#eee",context.fillRect(0,0,canvas.width,canvas.height),context.fillStyle="black",context.font="48px monospace",context.textBaseline="top";let t=200;linesShuffle.forEach(e=>{context.fillText(e,20,t),t+=60})},playShuffle=()=>{const preset=presets[idxPreset],fn=eval(preset.fn);lines.forEach((t,e)=>{fn({text:t,delay:.2*e,fps:preset.fps,glyphs:preset.glyphs,direction:preset.direction,onUpdate:t=>{linesShuffle[e]=t}})})},animate=()=>{requestAnimationFrame(animate),draw()},resize=()=>{canvas.width=window.innerWidth,canvas.height=window.innerHeight,lines=split(context,__text_1,context.font,canvas.width)},onCanvasClick=()=>{idxPreset++;let t="Example "+(idxPreset%=presets.length);const e=presets[idxPreset];for(const n in e)t=`${t} ${n}: ${e[n]}`;elPreset.innerText=t,playShuffle()};setup()}(); -------------------------------------------------------------------------------- /demo/multiline/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Demo : Multiline 5 | 67 | 68 | 69 | 70 |
71 |

txt-shuffle

72 | Click to play next example 73 | 74 |
75 | 76 | 77 | -------------------------------------------------------------------------------- /demo/multiline/index.js: -------------------------------------------------------------------------------- 1 | const { shuffle, shuffleScroll, directions, animations } = require('../../index.js'); 2 | const { split } = require('canvas-hypertxt'); 3 | const Tweakpane = require('tweakpane'); 4 | 5 | let elPreset; 6 | let canvas, context; 7 | let lines = []; 8 | let linesShuffle = []; 9 | let idxPreset = -1; 10 | 11 | // Alice In Chains - Nutshell 12 | let text = `We chase misprinted lies 13 | We face the path of time 14 | And yet I fight, and yet I fight 15 | This battle all alone 16 | No one to cry to 17 | No place to call home`; 18 | 19 | // a list of different parameters to demo 20 | const presets = [ 21 | { fn: 'shuffle', glyphs: '_' }, 22 | { fn: 'shuffle' }, 23 | { fn: 'shuffle', glyphs: '▂▄▆', fps: 40 }, 24 | { fn: 'shuffle', glyphs: 'weruoaszxcvnm', direction: directions.RANDOM }, 25 | // { fn: 'shuffleScroll', fps: 40 }, 26 | ]; 27 | 28 | const setup = () => { 29 | elPreset = document.querySelector('.preset'); 30 | 31 | canvas = document.querySelector('canvas'); 32 | context = canvas.getContext('2d'); 33 | context.font = '48px monospace'; 34 | 35 | window.addEventListener('resize', resize); 36 | canvas.addEventListener('click', onCanvasClick); 37 | 38 | resize(); 39 | animate(); 40 | 41 | // play first animation 42 | onCanvasClick(); 43 | }; 44 | 45 | const draw = () => { 46 | context.fillStyle = '#eee'; 47 | context.fillRect(0, 0, canvas.width, canvas.height); 48 | 49 | context.fillStyle = 'black'; 50 | context.font = '48px monospace'; 51 | context.textBaseline = 'top'; 52 | 53 | let x = 20; 54 | let y = 200; 55 | 56 | linesShuffle.forEach(line => { 57 | context.fillText(line, x, y); 58 | y += 60; 59 | }); 60 | }; 61 | 62 | const playShuffle = () => { 63 | const preset = presets[idxPreset]; 64 | const fn = eval(preset.fn); 65 | 66 | lines.forEach((line, i) => { 67 | fn({ 68 | text : line, 69 | delay : i * 0.2, 70 | fps : preset.fps, 71 | glyphs : preset.glyphs, 72 | direction : preset.direction, 73 | onUpdate : (output) => { linesShuffle[i] = output; } 74 | }); 75 | }); 76 | }; 77 | 78 | const animate = () => { 79 | requestAnimationFrame(animate); 80 | draw(); 81 | }; 82 | 83 | const resize = () => { 84 | canvas.width = window.innerWidth; 85 | canvas.height = window.innerHeight; 86 | 87 | // split text into lines again after resizing the canvas 88 | lines = split(context, text, context.font, canvas.width); 89 | }; 90 | 91 | const onCanvasClick = () => { 92 | idxPreset++; 93 | idxPreset %= presets.length; 94 | 95 | // update ui 96 | let str = `Example ${idxPreset}`; 97 | const preset = presets[idxPreset]; 98 | for (const key in preset) { 99 | str = `${str} ${key}: ${preset[key]}`; 100 | } 101 | elPreset.innerText = str; 102 | 103 | playShuffle(); 104 | }; 105 | 106 | setup(); 107 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const math = require('canvas-sketch-util/math'); 2 | const random = require('canvas-sketch-util/random'); 3 | const eases = require('eases'); 4 | 5 | const directions = { 6 | RIGHT : 'right', 7 | LEFT : 'left', 8 | RANDOM : 'random', 9 | }; 10 | 11 | const animations = { 12 | SHOW : 'show', 13 | HIDE : 'hide', 14 | STAY : 'stay', 15 | }; 16 | 17 | /** 18 | * Starts a text shuffle animation in two tiers. 19 | * First shuffling through random characters and then resolving into the target text. 20 | * 21 | * text - target text string 22 | * duration - duration of shuffle/resolve animation in seconds 23 | * delay - delay to start shuffling 24 | * delayResolve - delay to start resolving 25 | * fps - framerate 26 | * glyphs - glyphs to use in the shuffle animation 27 | * animation - possible values: `show`, `hide`, `stay` 28 | * direction - possible values: `left`, `right`, `random` 29 | * onUpdate - callback function, returns the output string 30 | * onComplete - callback function, returns the output string 31 | */ 32 | const shuffle = ({ 33 | text = '', 34 | duration = 1, 35 | delay = 0, 36 | delayResolve = 0.2, 37 | fps = 60, 38 | glyphs = ' !#$&%()*+0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuüvwxyz{|}~', 39 | animation = animations.SHOW, 40 | direction = directions.RIGHT, 41 | onUpdate = null, 42 | onComplete = null, 43 | } = {}) => { 44 | const _glyphs = glyphs.split(''); 45 | const _text = text.split(''); 46 | const _delta = 1000 / fps; 47 | 48 | let _now = Date.now(); 49 | let _start = Date.now(); 50 | 51 | // text indices 52 | let _tindices = _text.map((t, i) => i); 53 | 54 | // flip direction when hiding 55 | if (animation == animations.HIDE) { 56 | if (direction == directions.LEFT) direction = directions.RIGHT; 57 | else if (direction == directions.RIGHT) direction = directions.LEFT; 58 | } 59 | 60 | // reverse text indices 61 | if (direction == directions.LEFT) _tindices.reverse(); 62 | // randomise text indices 63 | if (direction == directions.RANDOM) _tindices = random.shuffle(_tindices); 64 | 65 | let uLen, vLen; 66 | let glyph, output, complete; 67 | let tidx; 68 | let t, u, v; 69 | 70 | const _onUpdate = () => { 71 | if (Date.now() - _now < _delta) { 72 | requestAnimationFrame(_onUpdate); 73 | return; 74 | } 75 | 76 | _now = Date.now(); 77 | output = ''; 78 | 79 | // t = linear time 80 | t = (_now - _start) * 0.001 / duration; 81 | if (animation == animations.HIDE) t = 1 - t; 82 | 83 | // u = shuffle curve 84 | // u starts at delay 85 | u = math.clamp01(t - delay); 86 | u = eases.quartOut(u); 87 | 88 | // v = resolve curve 89 | // v starts at u + it's own delay 90 | v = math.clamp01(t - delay - delayResolve); 91 | // v duration is deducted from it's delay (increase speed) 92 | v = v * (1 / (1 - delayResolve)); 93 | v = eases.quadInOut(v); 94 | 95 | uLen = Math.round(u * text.length); 96 | vLen = Math.round(v * text.length); 97 | 98 | for (let i = 0; i < text.length; i++) { 99 | tidx = _tindices[i]; 100 | glyph = _text[i]; 101 | 102 | if (tidx >= uLen && animation != animations.STAY) glyph = ' '; 103 | if (glyph != ' ' && tidx >= vLen) glyph = random.pick(_glyphs); 104 | 105 | output = `${output}${glyph}`; 106 | } 107 | 108 | // loop until u reaches 0 109 | if (animation == animations.HIDE) complete = u <= 0; 110 | // loop until u reaches 1 111 | else complete = u >= 1; 112 | 113 | if (!complete) requestAnimationFrame(_onUpdate); 114 | else output = animation == animations.HIDE ? '' : text; 115 | 116 | if (onUpdate) onUpdate(output); 117 | if (complete && onComplete) onComplete(output); 118 | }; 119 | 120 | _onUpdate(); 121 | } 122 | 123 | /** 124 | * Starts a text shuffle animation inspired by https://lcd.ertdfgcvb.xyz/ 125 | * It goes through every character in `glyphs` until it finds a match in the target text. 126 | * 127 | * text - target text string 128 | * delay - delay to start shuffling 129 | * fps - framerate 130 | * glyphs - glyphs to use in the shuffle animation 131 | * animation - possible values: `show`, `hide`, `stay` 132 | * stayFrames - max number of frames in the `stay` animation 133 | * onUpdate - callback function, returns the output string 134 | * onComplete - callback function, returns the output string 135 | */ 136 | 137 | const shuffleScroll = ({ 138 | text = '', 139 | delay = 0, 140 | fps = 60, 141 | glyphs = ' \'"“”‘’¹²³!#$&%()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuüvwxyz{|}~½¼¡«»×░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌', 142 | animation = animations.SHOW, 143 | stayFrames = 25, 144 | onUpdate = null, 145 | onComplete = null, 146 | } = {}) => { 147 | const _glyphs = glyphs.split(''); 148 | const _text = text.split(''); 149 | const _delta = 1000 / fps; 150 | 151 | // text indices 152 | let _tindices = _text.map((t, i) => i); 153 | // glyph indices 154 | let _gindices = _glyphs.map((t, i) => i); 155 | // shuffle indices 156 | let _sindices = _text.map(t => 0); 157 | // resolve indices (glyph index for each char in text) 158 | let _rindices = _text.map(t => _glyphs.findIndex(g => g == t)); 159 | 160 | // when hiding, start shuffling from resolve indices 161 | if (animation == animations.HIDE) _sindices = _rindices.concat(); 162 | // on stay, increase shuffle indices by a random value 163 | if (animation == animations.STAY) _sindices = _rindices.map(r => math.mod(r - random.rangeFloor(5, stayFrames), _glyphs.length)); 164 | 165 | let _now = Date.now(); 166 | let _start = Date.now(); 167 | let _frame = 0; 168 | 169 | let glyph, output, complete, resolved; 170 | let tidx, sidx, ridx; 171 | 172 | const _onUpdate = () => { 173 | if (Date.now() - _now < _delta) { 174 | requestAnimationFrame(_onUpdate); 175 | return; 176 | } 177 | 178 | _now = Date.now(); 179 | if (_now - _start > delay * 1000) _frame++; 180 | 181 | output = ''; 182 | resolved = 0; 183 | 184 | for (let i = 0; i < text.length; i++) { 185 | sidx = _sindices[i]; 186 | ridx = _rindices[i]; 187 | 188 | // increase shuffle index left to right 189 | if (animation == animations.SHOW) { 190 | if (sidx != ridx) { 191 | if (i < _frame) sidx++; 192 | } 193 | else resolved++; 194 | } 195 | // decrease shuffle index left to right 196 | if (animation == animations.HIDE) { 197 | if (sidx > 0) { 198 | if (i < _frame) sidx--; 199 | } 200 | else resolved++; 201 | } 202 | // increase all shuffle indices 203 | if (animation == animations.STAY) { 204 | if (sidx != ridx) sidx++; 205 | else resolved++; 206 | } 207 | 208 | // get corresponding glyph 209 | glyph = _glyphs[sidx % _glyphs.length]; 210 | // update shuffle indices array 211 | _sindices[i] = sidx % _glyphs.length; 212 | 213 | output = `${output}${glyph}`; 214 | } 215 | 216 | // keep looping until all glyphs are resolved 217 | complete = resolved >= text.length; 218 | 219 | if (!complete) requestAnimationFrame(_onUpdate); 220 | else output = animation == animations.HIDE ? '' : text; 221 | 222 | if (onUpdate) onUpdate(output); 223 | if (complete && onComplete) onComplete(output); 224 | }; 225 | 226 | _onUpdate(); 227 | } 228 | 229 | 230 | module.exports = { 231 | animations, 232 | directions, 233 | shuffle, 234 | shuffleScroll, 235 | }; 236 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "txt-shuffle", 3 | "version": "1.0.3", 4 | "description": "Customisable text shuffling animations.", 5 | "main": "index.js", 6 | "license": "MIT", 7 | "author": { 8 | "name": "Bruno Imbrizi", 9 | "url": "https://github.com/brunoimbrizi" 10 | }, 11 | "dependencies": { 12 | "canvas-sketch-util": "^1.10.0", 13 | "eases": "^1.0.8" 14 | }, 15 | "devDependencies": { 16 | "@babel/core": "^7.12.10", 17 | "babelify": "^10.0.0", 18 | "browserify": "^17.0.0", 19 | "canvas-hypertxt": "^1.0.1", 20 | "esmify": "^2.1.1", 21 | "tinyify": "^3.1.0", 22 | "tweakpane": "^3.1.2" 23 | }, 24 | "scripts": { 25 | "demo:animations": "budo demo/animations/:bundle.js --live --dir demo/animations/", 26 | "demo:multiline": "budo demo/multiline/:bundle.js --live --dir demo/multiline/ -- -p esmify", 27 | "build:animations": "browserify demo/animations/index.js -t babelify -p tinyify -o demo/animations/bundle.js", 28 | "build:multiline": "browserify demo/multiline/index.js -p esmify -p tinyify -o demo/multiline/bundle.js" 29 | }, 30 | "keywords": [ 31 | "text", 32 | "shuffle", 33 | "scramble", 34 | "flicker" 35 | ], 36 | "repository": { 37 | "type": "git", 38 | "url": "git://github.com/brunoimbrizi/txt-shuffle.git" 39 | }, 40 | "homepage": "https://github.com/brunoimbrizi/txt-shuffle", 41 | "bugs": { 42 | "url": "https://github.com/brunoimbrizi/txt-shuffle/issues" 43 | } 44 | } 45 | --------------------------------------------------------------------------------