Full Code of cmiscm/leonsans for AI

master f8c03c92d805 cached
48 files
309.1 KB
104.1k tokens
362 symbols
1 requests
Download .txt
Showing preview only (324K chars total). Download the full file or copy to clipboard to get everything.
Repository: cmiscm/leonsans
Branch: master
Commit: f8c03c92d805
Files: 48
Total size: 309.1 KB

Directory structure:
gitextract_04kbmd_5/

├── .gitignore
├── LICENSE
├── README.md
├── dist/
│   └── leon.js
├── examples/
│   ├── all.html
│   ├── canvas-basic.html
│   ├── color-pattern.html
│   ├── colorful.html
│   ├── gradient.html
│   ├── grid.html
│   ├── index.html
│   ├── js/
│   │   └── util.js
│   ├── mask-tiling-pixi.html
│   ├── metaball-pixi.html
│   ├── morphing-pixi.html
│   ├── pattern.html
│   ├── plants-pixi.html
│   ├── wave.html
│   └── webgl-basic-pixi.html
└── src/
    ├── core/
    │   ├── align.js
    │   ├── dispatcher.js
    │   ├── group.js
    │   ├── guide.js
    │   ├── length.js
    │   ├── model.js
    │   ├── paths.js
    │   ├── point.js
    │   ├── util.js
    │   └── vector.js
    ├── draw/
    │   ├── canvas/
    │   │   ├── color.js
    │   │   ├── colorful.js
    │   │   ├── grids.js
    │   │   ├── lines.js
    │   │   ├── pattern.js
    │   │   ├── points.js
    │   │   └── wave.js
    │   └── pixi/
    │       ├── color.js
    │       └── lines.js
    ├── font/
    │   ├── index.js
    │   ├── latin.js
    │   ├── latinutil.js
    │   ├── lower.js
    │   ├── number.js
    │   ├── special.js
    │   ├── upper.js
    │   └── util.js
    ├── index.js
    └── leonsans.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================

examples/.DS_Store
examples/data/.DS_Store


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2019 Jongmin Kim

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# Leon Sans
Leon Sans is a geometric sans-serif typeface made with code in 2019 by Jongmin Kim. It allows to change font weight dynamically and to create custom animations, effects or shapes in the Canvas element of HTML5. He designed the font to celebrate his newborn baby Leon.

There are live examples at https://leon-kim.com/examples/

And website at https://leon-kim.com/

[![Video Label](https://raw.githubusercontent.com/cmiscm/leonsans/gh-pages/leon-youtube.jpg)](https://youtu.be/sb7v-d-R11E?hl=en&fs=1&cc_load_policy=1)

![uppercase](https://raw.githubusercontent.com/cmiscm/leonsans/gh-pages/screenshot/upper.gif)

![lowercase](https://raw.githubusercontent.com/cmiscm/leonsans/gh-pages/screenshot/lower.gif)

![number](https://raw.githubusercontent.com/cmiscm/leonsans/gh-pages/screenshot/number-special.gif)

![latin upper](https://raw.githubusercontent.com/cmiscm/leonsans/gh-pages/screenshot/latin-upper.gif)

![latin lower](https://raw.githubusercontent.com/cmiscm/leonsans/gh-pages/screenshot/latin-lower.gif)


## What is special?
The font is made with code, it has coordinate values of the drawing points for each glyph. With the coordinate values, you can create custom shapes, effects or animations.

![Drawing animation](https://raw.githubusercontent.com/cmiscm/leonsans/gh-pages/screenshot/drawing.gif)
- [Drawing animation](https://leon-kim.com/examples/#canvas-basic)

![Weight change](https://raw.githubusercontent.com/cmiscm/leonsans/gh-pages/screenshot/weight.gif)
- [Weight change](https://leon-kim.com/examples/#canvas-basic)

![Wave](https://raw.githubusercontent.com/cmiscm/leonsans/gh-pages/screenshot/wave.gif)
- [Wave](https://leon-kim.com/examples/#wave)

![Metaball](https://raw.githubusercontent.com/cmiscm/leonsans/gh-pages/screenshot/metaball.gif)
- [Metaball](https://leon-kim.com/examples/#metaball-pixi)

![Plant](https://raw.githubusercontent.com/cmiscm/leonsans/gh-pages/screenshot/plant.gif)
- [Plant](https://leon-kim.com/examples/#plants-pixi)

![Colorful](https://raw.githubusercontent.com/cmiscm/leonsans/gh-pages/screenshot/colorful.gif)
- [Colorful](https://leon-kim.com/examples/#colorful)

![Color pattern](https://raw.githubusercontent.com/cmiscm/leonsans/gh-pages/screenshot/colorpattern.gif)
- [Color pattern](https://leon-kim.com/examples/#color-pattern)


## Usage
Download the minified js file in dist folder and include it in your html.
```html
<script src="js/leon.js"></script>
```

Generate LeonSans and draw it in the Canvas element of HTML5.
```javascript

let leon, canvas, ctx;

const sw = 800;
const sh = 600;
const pixelRatio = 2;

function init() {
    canvas = document.createElement('canvas');
    document.body.appendChild(canvas);
    ctx = canvas.getContext("2d");

    canvas.width = sw * pixelRatio;
    canvas.height = sh * pixelRatio;
    canvas.style.width = sw + 'px';
    canvas.style.height = sh + 'px';
    ctx.scale(pixelRatio, pixelRatio);

    leon = new LeonSans({
        text: 'The quick brown\nfox jumps over\nthe lazy dog',
        color: ['#000000'],
        size: 80,
        weight: 200
    });

    requestAnimationFrame(animate);
}

function animate(t) {
    requestAnimationFrame(animate);

    ctx.clearRect(0, 0, sw, sh);

    const x = (sw - leon.rect.w) / 2;
    const y = (sh - leon.rect.h) / 2;
    leon.position(x, y);

    leon.draw(ctx);
}

window.onload = () => {
    init();
};
```

For the drawing animation, include TweenMax (JS animation library) in your html.
```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
```

And update all the drawing values from 0 to 1
```javascript
let i, total = leon.drawing.length;
for (i = 0; i < total; i++) {
    TweenMax.fromTo(leon.drawing[i], 1.6, {
        value: 0
    }, {
        delay: i * 0.05,
        value: 1,
        ease: Power4.easeOut
    });
}
```



### Option list

| Name                 | Type     | Description                                                                                                                                                                                                     |
| -------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `text`               | string   | The text that needs to be shown.                                                    |
| `size`               | integer   | The size of the text.                                                              |
| `weight`              | number   | The weight of the font: `1 - 900`. [Default: `1`] |
| `color`           | array  | The colors of each characters. [Default: `['#000000']`]                                                                                                                                                                 |
| `colorful`              | array  | The colors for colorful effect. [Default: `['#c5d73f', '#9d529c', '#49a9db', '#fec330', '#5eb96e', '#fc5356', '#f38f31']`]                            |
| `tracking`            | integer | The spacing between the characters of a block of text.  [Default: `0`]                                                                                                                                                            |
| `leading` | integer | The distance between each line of text.  [Default: `0`]           |
| `align` | string | How the text content of the element is horizontally aligned: `left, center, right`. [Default: `left`]   |
| `pathGap`            | number  | The gap between each coordinate of the points on a line of each character: `0 - 1`. [Default: `0.5`]                                                                                  |
| `amplitude`        | number  | The amplitude of the wave effect: `0 - 1`. [Default: `0.5`]  |
| `maxWidth`       | number  | The width of the text sentence.  |
| `breakWord`        | boolean  | Words break when reaching the end of a line. [Default: `false`]     |
| `fps`        | number  | The FPS for the wave effect. [Default: `30`]     |
| `isPath`        | boolean  | `true` to get the coordinate values of the points on a line of each character. [Default: `false`]     |
| `isWave`        | boolean  | `true` for the wave effect. [Default: `false`]     |


### Properties

| Name                 | Type     | Description                                                                                                                                                                                                     |
| -------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `lineWidth`               | number   | The thickness of lines of the character.                                                    |
| `scale`               | number   | The scale of the character. `scale` is `1` when the font size is `500`.    |
| `drawing`              | array   | The drawing object values for each character. `0` is the beginning of the animation, `1` is the end of the animation state. |
| `data`           | array  | An object of the raw data for the text.                       |
| `paths`              | array  | The coordinate values of the points on a line of each character.        |
| `drawingPaths`            | array | The coordinate values of the points on a line of each character to draw the drawing animation in WebGL. It has 1px distance of each path.  |
| `wavePaths` | array | The coordinate values of the points on a line for the wave effect.    |
| `rect` | Object | The size of the text and its position: `{x: x position, y: y position, w: width, h: height}`.|


### Methods

| Name                         | Description                                                                                                                                                                                                                                                              |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `on()`      | Add `update` event. |
| `off()`                     | Remove `update` event.  |
| `position(x, y)`                    | Set the position of the text.  |
| `updateDrawingPaths()`     | Update paths for drawing in WebGL (PIXI.js). It's very expensive, only call when it needs.  |
| `drawPixi(graphics)` | Draw text in WebGL with PIXI.js. |
| `draw(ctx)`                | Draw text in the Canvas element. |
| `drawColorful(ctx)`                | Draw the colorful effect. |
| `wave(ctx, t)`                | Draw the wave effect. |
| `pattern(ctx, w, h)`                | Draw rectangle shapes at each path point |
| `grid(ctx)`                | Draw grid for each type. |
| `point(ctx)`                | Draw circles at each drawing point and lines for each type. |
| `box(ctx)`                | Draw outline box for the text. |
| `reset()`                  | Reset all the values.  |
| `dispose()`                  | Dispose.  |



================================================
FILE: dist/leon.js
================================================
/*!
 * VERSION: 1.6.5
 * DATE: 2020-09-20
 * https://leon-sans.com
 *
 * @license Copyright (c) 2019-2020, Jongmin Kim. All rights reserved.
 **/
var LeonSans=function(t){var r={};function i(e){if(r[e])return r[e].exports;var a=r[e]={i:e,l:!1,exports:{}};return t[e].call(a.exports,a,a.exports,i),a.l=!0,a.exports}return i.m=t,i.c=r,i.d=function(t,r,e){i.o(t,r)||Object.defineProperty(t,r,{enumerable:!0,get:e})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,r){if(1&r&&(t=i(t)),8&r)return t;if(4&r&&"object"==typeof t&&t&&t.__esModule)return t;var e=Object.create(null);if(i.r(e),Object.defineProperty(e,"default",{enumerable:!0,value:t}),2&r&&"string"!=typeof t)for(var a in t)i.d(e,a,function(r){return t[r]}.bind(null,a));return e},i.n=function(t){var r=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(r,"a",r),r},i.o=function(t,r){return Object.prototype.hasOwnProperty.call(t,r)},i.p="",i(i.s=0)}([function(t,r,i){var e=i(1).default;t.exports=e},function(t,r,i){"use strict";i.r(r),i.d(r,"default",(function(){return Zt}));var e=1,a=2*Math.PI;function s(t,r){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0,e=arguments.length>3&&void 0!==arguments[3]?arguments[3]:0,a=.49*t.rect.w*r,s=.49*(t.rect.h+220)*r;return{x:i,y:e,w:a,h:s}}function n(t,r,i){return{x:t/2,y:(r-130*.49*i)/2}}function l(t,r,i){return{r:r,cr:i,fr1:1,fr2:.78,gx1:t.ratio.x1,gx2:t.ratio.x2,gy1:t.ratio.y1,gy2:t.ratio.y2}}function f(t,r,i,e,a){var s=(e-a)/(r-i)*(t-i)+a;return s<a?s=a:s>e&&(s=e),s}function o(t){var r,i,e,a,s,n,l,o,h,y,d,c=t.typo.p.length,p=[];for(r=0;r<c;r++)for(a=(s=t.typo.p[r]).cv.length,i=0;i<a;i++){if(l=(n=s.cv[i]).addRect(t.rect),o=s.d,y=(h=t.pointsLength.lengths[r])/t.pointsLength.max,d=0,r>0)for(e=0;e<r;e++)d+=t.pointsLength.lengths[e]/t.pointsLength.max;y+=d,p.push({pos:l,drawing:t.drawing,direction:o,lengths:h,maxDrawing:y,minDrawing:d,closePath:n.ratio.c,stroke:(t,r)=>{var i=f(r.drawing.value,r.maxDrawing,r.minDrawing,1,0);if(i>0&&"a"!=r.pos.type){var e=r.lengths*i;t.setLineDash([r.lengths]),t.lineDashOffset=r.direction*(e+r.lengths),t.stroke()}}})}return p}function h(t,r){var i,e,a=t.length,s=[];for(i=0;i<a;i++)e=t[i].addRect(r.rect),s.push(e);return s}function y(t,r){var i,e,s,n=r.lines.length;for(i=0;i<n;i++)"a"==(s=(e=r.lines[i]).pos).type?(t.beginPath(),t.arc(s.x,s.y,s.radius*e.drawing.value,0,a),t.fill(),t.closePath()):"m"==s.type?(t.beginPath(),t.moveTo(s.x,s.y)):"l"==s.type?(t.lineTo(s.x,s.y),e.stroke(t,e)):"b"==s.type&&(t.bezierCurveTo(s.x,s.y,s.x2,s.y2,s.x3,s.y3),e.stroke(t,e))}function d(t,r){t.save(),t.lineWidth=1;var i,e=r.lines.length;for(i=0;i<e;i++)p(t,r.lines[i]);for(t.restore(),t.save(),t.lineWidth=1,e=r.typo.p.length,i=0;i<e;i++)c(t,r.typo.p[i],r);t.restore()}function c(t,r,i){var e,s,n,l=r.v.length;for(e=0;e<l;e++)n=(s=r.cv[e]).addRect(i.rect),"b"==s.type?(t.fillStyle="#ff2a00",t.beginPath(),t.arc(n.x3+(n.x3-n.x2),n.y3+(n.y3-n.y2),1.5,0,a),t.fill(),t.beginPath(),t.arc(n.x2,n.y2,1.5,0,a),t.fill(),t.beginPath(),t.moveTo(n.x2,n.y2),t.lineTo(n.x3,n.y3),t.lineTo(n.x3+(n.x3-n.x2),n.y3+(n.y3-n.y2)),t.stroke(),t.beginPath(),t.fillStyle="#ffffff",t.arc(n.x3,n.y3,2.5,0,a),t.fill(),t.stroke()):(t.beginPath(),t.fillStyle="#ffffff",t.strokeStyle="#ff2a00",t.arc(n.x,n.y,2.5,0,a),t.fill(),t.stroke())}function p(t,r){var i=r.pos;"a"!=i.type&&("m"==i.type?(t.strokeStyle="#ff2a00",t.beginPath(),t.moveTo(i.x,i.y)):"l"==i.type?t.lineTo(i.x,i.y):"b"==i.type&&t.bezierCurveTo(i.x,i.y,i.x2,i.y2,i.x3,i.y3),t.stroke())}function v(t,r){t.save(),t.beginPath(),t.lineWidth=1,t.strokeStyle="#aaaaaa";var i,e,a=r.guide.length;for(i=0;i<a;i++)e=r.rect.y+r.grid[i],t.moveTo(r.rect.x,e),t.lineTo(r.rect.x+r.rect.w,e);t.stroke(),t.lineWidth=1,t.beginPath(),t.strokeStyle="#aaaaaa",t.rect(r.rect.x,r.rect.y,r.rect.w,r.rect.h),t.stroke(),t.restore()}var x,u=Math.cos,g=Math.sin;function b(t,r,i,e,s,n){var l,f,o,h,y,d=r.wavePaths.length,c=function(t,r){return 120*t*r}(e,i),p=[];for(t.beginPath(),l=0;l<d;l++){if(f=r.wavePaths[l],n){var v=Math.random()*c-c/2,x=Math.random()*c-c/2;f.rx=f.x+v*u(f.rotation),f.ry=f.y+v*g(f.rotation),f.sx=f.x+v,f.sy=f.y+x}"a"==f.type?p.push(f):1==f.start?t.moveTo(f.x,f.y):f.fix?t.lineTo(f.x,f.y):s<110?(o=r.wavePaths[l-1])&&(h=o.x+.5*(f.x-o.x),y=o.y+.5*(f.y-o.y),t.quadraticCurveTo(h,y,f.rx,f.ry)):t.lineTo(f.rx,f.ry)}for(t.stroke(),l=0;l<p.length;l++)f=p[l],t.beginPath(),t.arc(f.x,f.y,f.radius,0,a),t.fill()}function S(t,r,i,e){var s,n,l=Math.round(r.paths.length*r.drawing.value),f=i/2,o=i/3,h=e/2;for(s=0;s<l;s++)1==(n=r.paths[s]).num?t.fillStyle="#ff00c5":t.fillStyle="#ff95f8","a"==n.type?(t.beginPath(),t.arc(n.x,n.y,o,0,a),t.fill()):(t.beginPath(),t.save(),t.translate(n.x,n.y),t.rotate(n.rotation),t.fillRect(-f,-h,i,e),t.restore())}function m(t,r,i,e){var a=e.length,s=(r+a*(Math.abs(r/10|0)+1))%a;if(Array.isArray(e[s])){var n,l=1/((a=e[s].length)+1),f=t.createLinearGradient(i.rect.x,i.rect.y,i.rect.x,i.rect.y+i.rect.h);for(f.addColorStop(l,e[s][0]),n=0;n<a;n++)f.addColorStop(l*(n+1),e[s][n]);f.addColorStop(l*(a+1),e[s][a-1]),t.strokeStyle=f,t.fillStyle=f}else t.strokeStyle=e[s],t.fillStyle=e[s]}function O(t,r){var i,e,a=t.typo.p.length,s=[],n=[],l=0;for(e=0;e<a;e++)l+=(i=J(t,t.typo.p[e].v,r)).l,s.push(i.v),n.push(i.l);return{max:l,lines:s,lengths:n}}function J(t,r,i){var e,a,s,n,l,f,o=r.length,h=[],y=0;for(e=0;e<o;e++)s={},l=(a=r[e]).convert(t,i),0==e||"a"==a.type?(s.x1=l.x,s.y1=l.y,s.distance=0,s.radius=l.radius):(n=f.convert(t,i),"b"==f.type?(s.x1=n.x3,s.y1=n.y3):(s.x1=n.x,s.y1=n.y),s.x2=l.x,s.y2=l.y,"b"==a.type?(s.x3=l.x2,s.y3=l.y2,s.x4=l.x3,s.y4=l.y3,s.distance=N(s.x1,s.y1,s.x2,s.y2,s.x3,s.y3,s.x4,s.y4)):s.distance=w(s.x1,s.y1,s.x2,s.y2)),s.type=a.type,s.rotation=a.ratio.r,s.pat=a.ratio.p,s.fix=a.ratio.f,s.vt=a.ratio.v,h.push(s),y+=s.distance,f=a;return{v:h,l:y}}function N(t,r,i,e,a,s,n,l,f){var o,h,y,d,c=f||40,p=0,v=t,x=r;for(y=1;y<c;y++)o=(d=_(y/c,t,r,i,e,a,s,n,l)).x-v,h=d.y-x,p+=Math.sqrt(o*o+h*h),v=d.x,x=d.y;return o=n-v,h=l-x,p+=Math.sqrt(o*o+h*h)}function _(t,r,i,e,a,s,n,l,f){return r+=(e-r)*t,i+=(a-i)*t,{x:(r+=((e+=(s-e)*t)-r)*t)+((e+=((s+=(l-s)*t)-e)*t)-r)*t,y:(i+=((a+=(n-a)*t)-i)*t)+((a+=((n+=(f-n)*t)-a)*t)-i)*t}}function w(t,r,i,e){var a=i-t,s=e-r;return Math.sqrt(a*a+s*s)}var P,W=-1;function k(t){var r=function(){++W==P&&(W=0);return x[W]}();t.fillStyle=r,t.strokeStyle=r}function D(t,r,i,e,a,s){var n=i/e,l=f(a.drawing.value,s+n,s,1,0);if(1==r.direction&&(l=f(1-a.drawing.value,s,s+n,1,0)),l>0){var o=i*l;t.setLineDash([i]),t.lineDashOffset=r.direction*(o+i),t.stroke()}return n}function T(t,r,i,e){var a,s;if(1==r.drawing.value)for(a=r.lines.length,s=0;s<a;s++)I(t,r.lines[s],i,e);else for(a=r.drawingPaths.length*r.drawing.value,s=0;s<a;s++)R(t,r.drawingPaths[s],i,e,r.drawing.value)}function I(t,r,i,e){var a=r.pos;"a"==a.type?(t.lineStyle(0,e,0),t.beginFill(e),t.drawCircle(a.x,a.y,a.radius),t.endFill()):"m"==a.type?(t.lineStyle(i,e,1),t.moveTo(a.x,a.y)):"l"==a.type?t.lineTo(a.x,a.y):"b"==a.type&&t.bezierCurveTo(a.x,a.y,a.x2,a.y2,a.x3,a.y3),r.closePath&&t.closePath()}function R(t,r,i,e,a){"a"==r.type?(t.lineStyle(0,e,0),t.beginFill(e),t.drawCircle(r.x,r.y,r.radius*a),t.endFill()):1==r.start?(t.lineStyle(i,e,1),t.moveTo(r.x,r.y)):t.lineTo(r.x,r.y,1)}function F(t,r,i){var e=i.length,a=(t+e*(Math.abs(t/10|0)+1))%e;if(!Array.isArray(i[a]))return i[a]}function M(t,r){var i,e,a,s=[];for(i=0;i<6;i++)e=10*i+20,a=10*i+90,s[i]={x1:.49*e*r,x2:.49*(t.rect.w-2*e)*r,y1:.49*a*r,y2:.49*(t.rect.h-a)*r-10*i*.49*r};return s}function G(t,r){var i,e=[],a=[98,340,815];for(i=0;i<3;i++)e[i]=.49*a[i]*r;return e}function z(t){Object.assign(this,t)}function L(t){this.type=t[0],this.x=t[1]||0,this.y=t[2]||0,"b"==this.type?(this.x2=t[3]||0,this.y2=t[4]||0,this.x3=t[5]||0,this.y3=t[6]||0,null==t[7]?this.ratio={x:1,y:1,r:0,p:0,f:0,c:0,v:0}:(this.ratio={},this.ratio.x=null==t[7].x?1:t[7].x,this.ratio.y=null==t[7].y?1:t[7].y,this.ratio.r=t[7].r||0,this.ratio.p=t[7].p||0,this.ratio.f=t[7].f||0,this.ratio.c=t[7].c||0,this.ratio.v=t[7].v||0)):null==t[3]?this.ratio={x:1,y:1,r:0,p:0,f:0,c:0,v:0}:(this.ratio={},this.ratio.x=null==t[3].x?1:t[3].x,this.ratio.y=null==t[3].y?1:t[3].y,this.ratio.r=t[3].r||0,this.ratio.p=t[3].p||0,this.ratio.f=t[3].f||0,this.ratio.c=t[3].c||0,this.ratio.v=t[3].v||0)}function j(t,r,i,e){var a=r.range.r*i.x,s=(r.range.gx2-r.range.gx1)*a+r.range.gx1,n=(r.range.fr2-r.range.fr1)*a+r.range.fr1;return r.center.x+(t-s)*e.scale*n}function C(t,r,i,e){var a=r.range.r*i.y,s=(r.range.gy2-r.range.gy1)*a+r.range.gy1,n=(r.range.fr2-r.range.fr1)*a+r.range.fr1;return r.center.y+(t-s)*e.scale*n}Object.assign(z.prototype,{addRect:function(t){var r=new z(this);return r.x=this.x+t.x,r.y=this.y+t.y,r.x2=this.x2+t.x,r.y2=this.y2+t.y,r.x3=this.x3+t.x,r.y3=this.y3+t.y,r.rx=this.rx+t.x,r.ry=this.ry+t.y,r.sx=this.sx+t.x,r.sy=this.sy+t.y,r.radius<.5&&(r.radius=.5),r}}),Object.assign(L.prototype,{convert:function(t,r){var i=j(this.x,t,this.ratio,r),e=C(this.y,t,this.ratio,r),a=j(this.x2,t,this.ratio,r),s=C(this.y2,t,this.ratio,r),n=j(this.x3,t,this.ratio,r),l=C(this.y3,t,this.ratio,r),f=function(t,r,i){var e=0;"a"==t&&(e=r.range.cr*i.scale*i.fontRatio);return e}(this.type,t,r),o=new z(this);return o.x=i,o.y=e,o.x2=a,o.y2=s,o.x3=n,o.y3=l,o.radius=f,o}});var A=null;function q(t,r,i,e){var a,s,n,l,f,o=r.pointsLength.lines,h=t.scale,y=o.length,d=[],c=[],p=[];for(a=0;a<y;a++)l=o[a],A=null,d.push(X(l,i,h));for(y=d.length,a=0;a<y;a++){for(s=(f=d[a]).length,p=[],n=0;n<s;n++)(l=f[n]).rotation!=V&&(e&&l.pat||p.push(l));1==r.typo.p[a].d&&p.reverse(),p.length>0&&(p[0].start=1,Array.prototype.push.apply(c,p))}return c}function X(t,r,i){var e,a,s,n,l,o,h,y=t.length,d=[],c=1,p=1;for(r>-1&&(p=f(r,1,0,80,10)*i),e=0;e<y;e++)if("a"==(n=t[e]).type)d.push(new z({x:n.x1,y:n.y1,rotation:0,type:"a",pat:n.pat,fix:n.fix,radius:n.radius}));else if(0==n.distance)null!=(h=E(l=new z({x:n.x1,y:n.y1,rotation:n.rotation,type:n.type,pat:n.pat,fix:n.fix}),A,n,1))&&(c&&(h.type="m",c=0),d.push(h)),A=new z(l);else for((s=Math.ceil(n.distance/p))<3&&(s=3),n.vt&&(s=2),a=1;a<s;a++)o=a/(s-1),l="b"==n.type?B(n,o):new z({x:n.x1+(n.x2-n.x1)*o,y:n.y1+(n.y2-n.y1)*o,type:n.type}),0!=n.rotation&&1==o&&(l.rotation=n.rotation),n.pat&&1==o&&(l.pat=n.pat),n.fix&&1==o&&(l.fix=n.fix),s>0&&null!=(h=E(l,A,n,o))&&(c&&(h.type="m",c=0),d.push(h)),A=new z(l);return d}function E(t,r,i,e){if(t.type=i.type,t.distance=i.distance,t.num=e,r&&null==t.rotation){var a=t.x-r.x,s=t.y-r.y,n=Math.atan2(a,s);t.rotation=-n}else t.rotation=t.rotation;return t.rotation==V?null:t}function B(t,r){var i=H(t.x1,t.x2,t.x3,t.x4,r),e=H(t.y1,t.y2,t.y3,t.y4,r),a=K(t.x1,t.x2,t.x3,t.x4,r),s=K(t.y1,t.y2,t.y3,t.y4,r);return new z({x:i,y:e,rotation:-Math.atan2(a,s)})}function H(t,r,i,e,a){var s=a*a;return t+(3*-t+a*(3*t-t*a))*a+(3*r+a*(-6*r+3*r*a))*a+(3*i-3*i*a)*s+e*(s*a)}function K(t,r,i,e,a){return 3*a*a*(3*r-t-3*i+e)+6*a*(t-2*r+i)+3*(-t+r)}var Q=Math.PI/180*180,U=Math.PI/180*90,V=-100;function Y(t,r,i,e,a,s,n,l){var f,o=[],h=l.length;for(f=0;f<h;f++)o.push({d:l[f].d,v:Z(l[f].v,r,i)});return{rect:{w:t,h:824,fw:r,fh:i},ratio:{x1:e,x2:a,y1:s,y2:n},p:o,clone:()=>{for(var l=[],f=0;f<o.length;f++)l[f]={d:o[f].d,v:o[f].v};return{rect:{w:t,h:824,fw:r,fh:i},ratio:{x1:e,x2:a,y1:s,y2:n},p:l}}}}function Z(t,r,i){var e,a,s=t.length,n=r/2,l=i/2,f=[];for(a=0;a<s;a++)(e=t[a])[1]-=n,e[2]-=l,"b"==e[0]&&(e[3]-=n,e[4]-=l,e[5]-=n,e[6]-=l),f.push(new L(e));return f}function $(t,r,i,e){var a=t-i,s=r-e;return-Math.atan2(a,s)}function tt(t,r,i,e,a,s,n,l,f){var o=K(t,i,a,n,f),h=K(r,e,s,l,f);return-Math.atan2(o,h)}var rt=[{d:-1,v:[["m",0,352,{x:.55,y:.3,r:$(0,352,143.5,0)}],["l",143.5,0,{r:$(0,352,143.5,0),f:1}],["l",146.5,0,{r:$(290,352,146.5,0),f:1,v:1}],["l",290,352,{x:.55,y:.3,f:1}]]},{d:-1,v:[["m",47,237,{r:U,p:1}],["l",243,237,{r:U,p:1,f:1}]]}],it=[{d:1,v:[["m",293.1,320.1,{r:tt(293.1,320.1,262.2,345,222.8,360,180,360,0),f:1}],["b",262.2,345,222.8,360,180,360],["b",80.6,360,0,279.4,0,180],["b",0,80.6,80.6,0,180,0],["b",222.8,0,262.2,15,293.1,39.9]]}],et=[{d:-1,v:[["m",95,352,{r:U,f:1}],["b",191.6,352,270,271.6,270,175,{r:Q}],["b",270,78.4,191.6,0,95,0,{r:U}],["l",0,0,{r:Q,f:1}],["l",0,352,{r:Q,f:1}],["l",95,352,{r:U,f:1}]]}],at=[{d:-1,v:[["m",192,0,{x:0,r:U}],["l",0,0,{r:Q,f:1,x:.5}],["l",0,352,{f:1,x:.5}],["l",192,352,{x:0,r:U,f:1}]]},{d:-1,v:[["m",0,164,{r:U,p:1,x:.5}],["l",180,164,{x:0,r:U,f:1}]]}],st=[{d:1,v:[["m",202,180,{r:U,f:1}],["l",352,180,{f:1}],["b",352,279.4,279.4,360,180,360,{r:U}],["b",80.6,360,0,279.4,0,180,{r:Q}],["b",0,80.6,80.6,0,180,0,{r:U}],["b",222.8,0,262.1,14.9,293,39.9]]}],nt=[{d:-1,v:[["m",0,0,{y:0,r:Q}],["l",0,352,{y:0,r:Q,f:1}]]},{d:-1,v:[["m",232,0,{y:0,r:Q}],["l",232,352,{y:0,r:Q,f:1}]]},{d:-1,v:[["m",0,164,{r:U,p:1}],["l",232,164,{r:U,f:1,p:1}]]}],lt=[{d:1,v:[["m",0,352,{y:0,r:Q,f:1}],["l",0,0,{y:0,r:Q}]]}],ft=[{d:1,v:[["m",0,311,{r:tt(0,311,16.2,341.6,49.3,356,86,356,0),f:1}],["b",16.2,341.6,49.3,356,86,356,{r:U}],["b",133.5,356,172,317.5,172,270],["l",172.5,0,{y:0,r:Q}]]}],ot=[{d:-1,v:[["m",0,352,{y:0,r:Q}],["l",0,0,{r:Q,f:1}],["l",3,0,{r:Q,p:1,f:1,v:1}],["l",247,351,{r:Q,p:1,f:1}],["l",250,351,{r:Q,f:1,v:1}],["l",250,0,{y:0,r:Q,f:1}]]}],ht=[{d:1,v:[["m",360,180,{r:Q,p:1,f:1}],["b",360,279.4,279.4,360,180,360,{r:U}],["b",80.6,360,0,279.4,0,180,{r:Q}],["b",0,80.6,80.6,0,180,0,{r:U}],["b",279.4,0,360,80.6,360,180,{r:Q,c:1}]]}],yt=[{d:1,v:[["m",0,295.4,{r:tt(0,295.4,17.6,332.1,58.3,360,110.3,360,0),f:1}],["b",17.6,332.1,58.3,360,110.3,360],["b",173.9,360,223.8,329.6,224,271],["b",224.2,214.7,180.7,189.6,112.4,173.3],["b",47.3,157.7,10.9,130.6,12,84.4],["b",13.3,29.8,57.3,0,114.8,0],["b",158.4,0,196.5,20.5,212,51.3]]}],dt=[{d:1,v:[["m",250,0,{y:0,r:Q}],["l",250,231,{r:Q}],["b",250,300,194,356,125,356,{r:U}],["b",56,356,0,300,0,231,{r:Q}],["l",0,0,{y:0,r:Q}]]}],ct=[{d:-1,v:[["m",0,0,{x:.6,y:.3,r:$(0,0,135,186)}],["l",135,186,{r:Q,f:1}],["l",270,0,{x:.6,y:.3,f:1}]]},{d:-1,v:[["m",135,186,{r:Q,p:1}],["l",135,352,{y:0,f:1}]]}],pt={A:Y(620,290,352,0,0,0,0,JSON.parse(JSON.stringify(rt))),B:Y(596,209,352,-10,-10,0,0,[{d:1,v:[["m",0,164,{r:U,p:1}],["l",116,164,{r:U,p:1,f:1}],["b",167.4,164,209,205.6,209,257,{r:Q}],["b",209,308.4,167.4,352,116,352,{r:U}],["l",0,352,{r:Q,f:1}],["l",0,0,{r:Q,f:1}],["l",116,0,{r:U}],["b",161.3,0,198,36.7,198,82,{r:Q}],["b",198,127.3,161.3,164,116,164,{r:U}]]}]),C:Y(700,293.1,360,0,0,0,0,JSON.parse(JSON.stringify(it))),D:Y(721,270,352,-10,-10,0,0,JSON.parse(JSON.stringify(et))),E:Y(520,192,352,-5,-80,0,0,JSON.parse(JSON.stringify(at))),F:Y(510,192,352,-5,-80,0,0,[{d:-1,v:[["m",192,0,{x:0,r:U}],["l",0,0,{r:Q,f:1,x:.5}],["l",0,352,{y:0,f:1,x:.5}]]},{d:-1,v:[["m",0,164,{r:U,p:1,x:.5}],["l",180,164,{x:0,r:U,f:1}]]}]),G:Y(840,352,360,0,0,0,0,JSON.parse(JSON.stringify(st))),H:Y(684,232,352,0,0,0,0,JSON.parse(JSON.stringify(nt))),I:Y(249,0,352,0,0,0,0,JSON.parse(JSON.stringify(lt))),J:Y(472,172.5,355.5,10,20,-2,-2,JSON.parse(JSON.stringify(ft))),K:Y(616,232,352,-10,-20,0,0,[{d:-1,v:[["m",0,0,{y:0,r:Q}],["l",0,352,{y:0,r:Q,f:1}]]},{d:-1,v:[["m",212,0,{x:.7,y:.7,r:$(212,0,0,162.5)}],["l",0,162.5,{r:U,p:1}],["l",0,165.5,{r:U,p:1,v:1}],["l",232,352,{x:.7,y:.7,f:1}]]}]),L:Y(529,192,352,-10,-20,0,0,[{d:-1,v:[["m",0,0,{y:0}],["l",0,352,{f:1}],["l",192,352,{x:0,f:1}]]}]),M:Y(885,330,352,0,0,0,0,[{d:-1,v:[["m",0,352,{y:0,r:Q}],["l",0,0,{r:Q,f:1}],["l",3,0,{r:Q,p:1,f:1,v:1}],["l",163.5,330,{r:$(163.5,330,163.5,330),f:1}],["l",166.5,330,{r:$(166.5,330,327,0),f:1,v:1}],["l",327,0,{r:Q,p:1,f:1}],["l",330,0,{r:Q,f:1,v:1}],["l",330,352,{y:0,r:Q,f:1}]]}]),N:Y(721,250,352,0,0,0,0,JSON.parse(JSON.stringify(ot))),O:Y(850,360,360,0,0,0,0,JSON.parse(JSON.stringify(ht))),P:Y(568,210,352,-10,-10,-.5,-.5,[{d:1,v:[["m",0,352,{y:0,f:1}],["l",0,0,{f:1}],["l",117,0,{r:U}],["b",168.4,0,210,41.6,210,93,{r:Q}],["b",210,144.4,168.4,186,117,186,{r:U}],["l",0,186,{r:U,p:1}]]}]),Q:Y(850,360,360,0,0,0,0,[{d:-1,v:[["m",360,180,{r:U,p:1,f:1}],["b",360,80.6,279.4,0,180,0,{r:U}],["b",80.6,0,0,80.6,0,180,{r:Q}],["b",0,279.4,80.6,360,180,360,{r:U}],["b",279.4,360,360,279.4,360,180,{r:Q,c:1,f:1}]]},{d:-1,v:[["m",222,222,{x:.5,y:.5,r:$(222,222,360,360)}],["l",360,360,{x:.5,y:.5,f:1}]]}]),R:Y(634,232,352,-10,-10,-.5,-.5,[{d:-1,v:[["m",0,186,{r:U,p:1}],["l",139,186,{r:U}],["b",190.4,186,232,144.4,232,93,{r:Q}],["b",232,41.6,190.4,0,139,0,{r:U}],["l",0,0,{r:Q,f:1}],["l",0,352,{y:0,f:1}]]},{d:-1,v:[["m",139,186,{p:1,r:$(139,186,232,352)}],["l",232,352,{x:.5,y:.39,f:1}]]}]),S:Y(560,224,360,0,0,0,0,JSON.parse(JSON.stringify(yt))),T:Y(568,232,352,0,0,-.5,-.5,[{d:-1,v:[["m",0,0,{x:0,r:U}],["l",232,0,{x:0,r:U,f:1}]]},{d:-1,v:[["m",116,0,{r:Q,p:1}],["l",116,352,{y:0,r:Q,f:1}]]}]),U:Y(712,250,355,0,0,-.5,-.5,JSON.parse(JSON.stringify(dt))),V:Y(650,270,352,0,0,0,0,[{d:-1,v:[["m",0,0,{x:.6,y:.1,r:$(0,0,133.5,352)}],["l",133.5,352,{r:$(0,0,133.5,352),f:1}],["l",136.5,352,{r:$(136.5,352,270,0),f:1,v:1}],["l",270,0,{x:.6,y:.1,f:1}]]}]),W:Y(894,390,352,0,0,0,0,[{d:-1,v:[["m",0,0,{x:.6,y:.05,r:$(0,0,84.5,352)}],["l",84.5,352,{r:$(0,0,84.5,352),f:1}],["l",87.5,352,{r:$(87.5,352,193.5,0),f:1,v:1}],["l",193.5,0,{r:$(87.5,352,193.5,0),f:1}],["l",196.5,0,{r:$(196.5,0,302.5,352),f:1,v:1}],["l",302.5,352,{r:$(196.5,0,302.5,352),f:1}],["l",305.5,352,{r:$(305.5,352,390,0),f:1,v:1}],["l",390,0,{x:.6,y:.05,f:1}]]}]),X:Y(660,270,352,0,0,0,-7,[{d:-1,v:[["m",10,0,{x:.5,y:.3,r:$(10,0,270,352)}],["l",270,352,{x:.5,y:.5,f:1}]]},{d:-1,v:[["m",260,0,{x:.5,y:.3,r:$(260,0,0,352)}],["l",0,352,{x:.5,y:.5,f:1}]]}]),Y:Y(673,270,352,0,0,0,0,JSON.parse(JSON.stringify(ct))),Z:Y(558,232,352,0,-5,0,0,[{d:-1,v:[["m",8,0,{x:0,r:U}],["l",224,0,{r:U,f:1}],["l",224,3,{r:Q,p:1,v:1}],["l",0,349,{r:Q,p:1}],["l",0,352,{r:U,f:1,v:1}],["l",232,352,{x:0,r:U,f:1}]]}])},vt=[{d:-1,v:[["m",232,8,{y:-3.4,r:Q}],["l",232,116,{r:V}],["b",232,180.1,180.1,232,116,232,{r:U}],["b",51.9,232,0,180.1,0,116,{r:Q}],["b",0,51.9,51.9,0,116,0,{r:U}],["b",180.1,0,232,51.9,232,116,{r:Q}],["l",232,224,{y:-.1,r:Q,f:1}]]}],xt=[{d:1,v:[["m",212.1,182.9,{r:tt(212.1,182.9,191.1,213.2,156.1,233.1,116.5,233.1,0),f:1}],["b",191.1,213.2,156.1,233.1,116.5,233.1,{r:U}],["b",52.4,233.1,.5,181.2,.5,117.1,{r:Q}],["b",.5,53,52.4,1.1,116.5,1.1,{r:U}],["b",156.1,1.1,191.1,21,212.1,51.3]]}],ut=[{d:-1,v:[["m",232,0,{y:0}],["l",232,239,{r:V}],["b",232,303.1,180.1,355,116,355,{r:U}],["b",51.9,355,0,303.1,0,239,{r:Q}],["b",0,174.9,51.9,123,116,123,{r:U}],["b",180.1,123,232,174.9,232,239,{r:Q}],["l",232,352,{y:0,f:1}]]}],gt=[{d:1,v:[["m",211.6,182.9,{r:tt(211.6,182.9,191.1,213.2,156.1,233.1,116.5,233.1,0),f:1}],["b",191.1,213.2,156.1,233.1,116.5,233.1,{r:U}],["b",52.4,233.1,.5,181.2,.5,117.1,{r:Q}],["b",.5,53,52.4,1.1,116.5,1.1,{r:U}],["b",176.4,1.1,224.9,47.2,225.5,106.1,{r:Q}],["l",.5,106.1,{r:Q,p:1}]]}],bt=[{d:-1,v:[["m",232,5,{y:-2.8}],["l",232,116,{r:V}],["b",232,180.1,180.1,232,116,232,{r:U}],["b",51.9,232,0,180.1,0,116,{r:Q}],["b",0,51.9,51.9,0,116,0,{r:U}],["b",180.1,0,232,51.9,232,116,{r:Q}],["l",232,222],["b",234.5,300.3,180.2,338.5,116,338,{y:.64,r:U}],["b",76.2,337.7,36.6,320.7,15.7,290.1,{y:.64,f:1}]]}],St=[{d:-1,v:[["m",0,0,{y:0,r:Q}],["l",0,352,{y:0,f:1}]]},{d:-1,v:[["m",0,214,{r:V}],["b",0,163.7,40.7,123,91,123,{r:U}],["b",141.3,123,182,163.7,182,214,{r:Q}],["l",182,352,{y:0,f:1}]]}],mt=[{d:-1,v:[["m",0,130,{y:-3.3}],["l",0,352,{y:0,f:1}]]},{d:-1,v:[["m",0,214,{y:0,r:Q,p:1}],["b",0,163.7,40.7,123,91,123,{r:U}],["b",141.3,123,182,163.7,182,214,{r:Q}],["l",182,352,{y:0,f:1}]]}],Ot=[{d:1,v:[["m",232,116,{r:Q,p:1,f:1}],["b",232,180.1,180.1,232,116,232,{r:U}],["b",51.9,232,0,180.1,0,116,{r:Q}],["b",0,51.9,51.9,0,116,0,{r:U}],["b",180.1,0,232,51.9,232,116,{r:Q,c:1}]]}],Jt=[{d:1,v:[["m",0,295.4*.642,{r:tt(0,295.4*.642,11.2992,332.1*.642,58.3*.642,231.12,70.8126,231.12,0),f:1}],["b",11.2992,332.1*.642,58.3*.642,231.12,70.8126,231.12],["b",173.9*.642,231.12,223.8*.642,329.6*.642,143.808,173.982],["b",143.9364,137.8374,116.0094,121.7232,112.4*.642,173.3*.642],["b",30.3666,101.2434,10.9*.642,130.6*.642,12*.642,54.1848],["b",8.5386,29.8*.642,36.7866,0,73.7016,0],["b",101.6928,0,126.153,13.161,136.104,51.3*.642]]}],Nt=[{d:-1,v:[["m",0,130,{y:-3}],["l",0,265,{r:Q}],["b",0,315.3,40.7,356,91,356,{r:U}],["b",141.3,356,182,315.3,182,265,{r:Q,p:1,f:1}]]},{d:-1,v:[["m",182,130,{y:-3}],["l",182,352,{y:0,f:1}]]}],_t=[{d:-1,v:[["m",225.5,0,{y:-3,r:$(225.5,0,116.3,248.8)}],["l",116.3,248.8,{x:.5,y:.64}],["b",71.8,349.6,0,331.5,0,331.5,{x:.5,y:.64,r:tt(0,331.5,71.8,349.6,116.3,248.8,0,331.5,0),f:1}]]},{d:-1,v:[["m",3.2,0,{y:-3,r:$(3.2,0,125.7,226.6)}],["l",125.7,226.6,{p:1,f:1}]]}],wt={a:Y(600,232,232,10,2,-64,-64,JSON.parse(JSON.stringify(vt))),b:Y(600,232,352,-10,-2,0,0,[{d:-1,v:[["m",0,0,{y:0,r:Q}],["l",0,239,{r:V}],["b",0,303.1,51.9,355,116,355,{r:U}],["b",180.1,355,232,303.1,232,239,{r:Q}],["b",232,174.9,180.1,123,116,123,{r:U}],["b",51.9,123,0,174.9,0,239,{r:Q}],["l",0,352,{y:0,r:Q,f:1}]]}]),c:Y(520,212.1,233.1,2,-10,-64,-64,JSON.parse(JSON.stringify(xt))),d:Y(600,232,352,10,2,0,0,JSON.parse(JSON.stringify(ut))),e:Y(570,225.5,233.1,0,0,-64,-64,JSON.parse(JSON.stringify(gt))),f:Y(356,232,352,-40,-40,0,0,[{d:-1,v:[["m",166.6,33,{x:.5,r:tt(166.6,33,159.3,13.1,139.2,0,116.9,0,0)}],["b",159.3,13.1,139.2,0,116.9,0,{r:U}],["b",88.2,0,65,23.2,65,51.9,{r:Q}],["l",65,352,{y:0,f:1}]]},{d:-1,v:[["m",0,130,{x:0,r:U}],["l",154,130,{x:0,f:1}]]}]),g:Y(600,232,338,10,2,-117,-117,JSON.parse(JSON.stringify(bt))),h:Y(520,182,352,0,0,0,0,JSON.parse(JSON.stringify(St))),i:Y(200,0,352,0,0,0,0,[{d:1,v:[["a",0,90,{y:-3}]]},{d:1,v:[["m",0,352,{y:0,f:1}],["l",0,130,{y:-3}]]}]),j:Y(220,115.9,352,-60,-60,0,0,[{d:1,v:[["a",0,90,{y:-3}]]},{d:1,v:[["m",-115.9,444,{x:.4,y:.63,r:tt(-115.9,444,12.6-115.9,454.4,29.6-115.9,460.2,-70,461.2,0),f:1}],["b",12.6-115.9,454.4,29.6-115.9,460.2,-70,461.2,{x:.4,y:.63,r:U}],["b",84.5-115.9,463.5,0,435.1,0,396.4,{x:.4,y:.63,r:Q}],["l",0,130,{y:-3}]]}]),k:Y(450,164,352,-10,-10,0,0,[{d:-1,v:[["m",0,0,{y:0,r:Q}],["l",0,352,{y:0,f:1}]]},{d:-1,v:[["m",160,130,{x:.7,y:0,r:$(164,130,0,234.5),f:1}],["l",0,234.5,{r:U,p:1}],["l",0,237.5,{r:U,p:1,v:1}],["l",164,352,{x:.7,y:.7,f:1}]]}]),l:Y(200,0,352,0,0,0,0,[{d:1,v:[["m",0,352,{y:0,f:1}],["l",0,0,{y:0}]]}]),m:Y(740,300,352,0,0,0,0,[{d:-1,v:[["m",0,130,{y:-3.6}],["l",0,352,{y:0,f:1}]]},{d:-1,v:[["m",0,198,{y:0,r:Q,p:1}],["b",0,156.6,33.6,123,75,123,{r:U}],["b",116.4,123,150,156.6,150,198,{r:Q}],["l",150,352,{y:0,f:1}]]},{d:-1,v:[["m",150,198,{y:0,r:Q,p:1}],["b",150,156.6,183.6,123,225,123,{r:U}],["b",266.4,123,300,156.6,300,198,{r:Q}],["l",300,352,{y:0,f:1}]]}]),n:Y(520,182,352,0,0,0,0,JSON.parse(JSON.stringify(mt))),o:Y(580,232,232,0,0,-64,-64,JSON.parse(JSON.stringify(Ot))),p:Y(600,232,338,-10,-2,-117,-117,[{d:-1,v:[["m",0,5,{y:-2.8}],["l",0,116,{r:V}],["b",0,180.1,51.9,232,116,232,{r:U}],["b",180.1,232,232,180.1,232,116,{r:Q}],["b",232,51.9,180.1,0,116,0,{r:U}],["b",51.9,0,0,51.9,0,116,{r:Q}],["l",0,338,{y:0,f:1}]]}]),q:Y(600,232,338,10,2,-117,-117,[{d:-1,v:[["m",232,5,{y:-2.8}],["l",232,116,{r:V}],["b",232,180.1,180.1,232,116,232,{r:U}],["b",51.9,232,0,180.1,0,116,{r:Q}],["b",0,51.9,51.9,0,116,0,{r:U}],["b",180.1,0,232,51.9,232,116,{r:Q}],["l",232,338,{y:0,f:1}]]}]),r:Y(340,119.2,352,-20,-20,0,0,[{d:-1,v:[["m",0,130,{y:-3.3}],["l",0,352,{y:0,f:1}]]},{d:-1,v:[["m",0,181,{r:Q,p:1}],["b",0,181,41.9,101.2,119.2,128.5,{x:0,y:2,r:tt(119.2,128.5,41.9,101.2,0,181,119.2,128.5,0),f:1}]]}]),s:Y(400,143.808,231.12,0,0,-64,-64,JSON.parse(JSON.stringify(Jt))),t:Y(356,232,352,-30,-30,0,0,[{d:-1,v:[["m",65,0,{y:0}],["l",65,304.2],["b",65,332.9,88.2,356.1,116.9,356.1,{r:U}],["b",139.2,356.1,159.3,343,166.6,317.1,{x:0,f:1}]]},{d:-1,v:[["m",0,130,{x:0,r:U}],["l",154,130,{x:0,f:1}]]}]),u:Y(520,182,352,0,0,0,0,JSON.parse(JSON.stringify(Nt))),v:Y(500,200,352,0,0,0,0,[{d:-1,v:[["m",0,130,{x:.6,y:-3,r:$(0,130,98.5,352)}],["l",98.5,352,{r:$(0,130,98.5,352),f:1}],["l",101.5,352,{r:$(101.5,352,200,130),f:1,v:1}],["l",200,130,{x:.6,y:-3,f:1}]]}]),w:Y(700,310,352,0,0,0,0,[{d:-1,v:[["m",0,130,{x:.6,y:-3,r:$(0,130,76.5,352)}],["l",76.5,352,{r:$(0,130,76.5,352),f:1}],["l",79.5,352,{r:$(79.5,352,153.5,130),f:1,v:1}],["l",153.5,130,{y:1,r:$(79.5,352,153.5,130),f:1}],["l",156.5,130,{y:1,r:$(156.5,130,231.5,352),f:1,v:1}],["l",231.5,352,{r:$(156.5,130,231.5,352),f:1}],["l",234.5,352,{r:$(234.5,352,310,130),f:1,v:1}],["l",310,130,{x:.6,y:-3,f:1}]]}]),x:Y(490,210,352,0,0,0,-7,[{d:-1,v:[["m",10,130,{x:.5,y:-1,r:$(10,130,210,352)}],["l",210,352,{x:.5,y:.5,f:1}]]},{d:-1,v:[["m",200,130,{x:.5,y:-1,r:$(200,130,0,352)}],["l",0,352,{x:.5,y:.5,f:1}]]}]),y:Y(500,225.5,331.5,10,10,-119,-119,JSON.parse(JSON.stringify(_t))),z:Y(420,172,352,0,0,0,0,[{d:-1,v:[["m",6,130,{x:-.5,y:1,r:U}],["l",166,130,{x:1.8,y:1,r:U,f:1}],["l",166,133,{x:1.8,y:1,r:Q,p:1,v:1}],["l",0,349,{x:1.7,r:Q,p:1}],["l",0,352,{x:1.7,r:U,f:1,v:1}],["l",172,352,{x:-.4,r:U,f:1}]]}])},Pt={0:Y(660,270,360,0,0,0,0,[{d:1,v:[["m",270,180,{r:Q,p:1,f:1}],["b",270,279.4,209.6,360,135,360,{r:U}],["b",60.4,360,0,279.4,0,180,{r:Q}],["b",0,80.6,60.4,0,135,0,{r:U}],["b",209.6,0,270,80.6,270,180,{r:Q,c:1}]]}]),1:Y(380,76,352,15,15,0,0,[{d:-1,v:[["m",0,51,{x:-2,y:2,r:$(0,51,73,0)}],["l",73,0,{r:Q,p:1}],["l",76,0,{r:Q,f:1,v:1}],["l",76,352,{y:0,f:1}]]}]),2:Y(580,210,356,0,0,2,2,[{d:-1,v:[["m",3.9,68.8,{x:1.2,y:1.2,r:tt(3.9,68.8,16.7,29,54.2,3.1,98.2,.2,0)}],["b",16.7,29,54.2,3.1,98.2,.2],["b",151.8,-3.3,208.5,38.3,198.9,100.1],["b",197.1,111.8,196.4,142.4,101.5,235.2],["b",11.4,323.2,0,353,0,353,{r:V}],["l",0,353,{r:U,p:1}],["l",0,356,{r:U,f:1,v:1}],["l",210,356,{x:-.5,f:1}]]}]),3:Y(580,222.1,360,0,0,0,0,[{d:-1,v:[["m",10.7,66.3,{r:tt(10.7,66.3,11.2,64.8,11.7,63.3,12.3,61.8,0)}],["b",11.2,64.8,11.7,63.3,12.3,61.8,{r:V}],["b",25.8,25.9,64.5,0,110.1,0,{r:U}],["b",167,0,213.1,40.3,213.1,90,{r:Q}],["b",213.1,139.7,167,180,110.1,179.9,{r:U,f:1}],["l",100.1,179.9,{x:-5,y:1,r:U,f:1}],["l",110.1,180,{r:U,p:1}],["b",172,180,222.1,220.3,222.1,270,{r:Q}],["b",222.1,319.7,172,360,110.1,360,{r:U}],["b",56.9,360,12.4,330.2,1,290.3,{f:1}]]}]),4:Y(596,236,352,0,0,0,0,[{d:1,v:[["m",175,352,{y:0,f:1}],["l",175,0,{f:1}],["l",172,0,{r:U,p:1,v:1}],["l",0,273,{r:Q,p:1}],["l",0,276,{r:U,f:1,v:1}],["l",236,276,{x:-.5}]]}]),5:Y(596,208.5,356,0,-5,-2,-2,[{d:1,v:[["m",0,295.7,{r:tt(0,295.7,15.3,333.8,52.2,356.2,97.5,356,0),f:1}],["b",15.3,333.8,52.2,356.2,97.5,356,{r:U}],["b",159.1,355.7,206.1,306.9,208.5,240.8,{r:Q}],["b",210.9,173.9,162.7,120.8,97.5,125.6,{r:U}],["b",59.4,128.4,25.5,145.8,5.6,176.4,{f:1}],["l",5.6,176.4,{r:V}],["l",5.6-3,176.4,{r:Q,p:1,v:1}],["l",11.5,0,{r:U,f:1}],["l",193.5,0,{x:-.5}]]}]),6:Y(596,215.8,360,0,-2,0,0,[{d:1,v:[["m",7.6,272.3,{r:Q,p:1,f:1}],["b",6.4,265.8,5.8,259.1,5.8,252.2,{r:Q}],["b",5.8,192.6,52.8,144.2,110.8,144.2,{r:U}],["b",168.7,144.2,215.8,192.6,215.8,252.2,{r:Q}],["b",215.8,311.9,168.7,360,110.8,360,{r:U}],["b",59.5,360,16.8,322.4,7.6,272.4,{r:V}],["b",7.6,272.4,-44.1,8.8,122.2,.2],["b",165.5,-2.1,193.8,21,212.1,56.4]]}]),7:Y(540,213,352,0,0,0,0,[{d:-1,v:[["m",0,0,{x:0,r:U}],["l",213,0,{r:U,f:1}],["l",213,.1,{r:V}],["l",72.7,352,{y:.1,f:1}]]}]),8:Y(596,224,360,0,0,0,0,[{d:1,v:[["m",112,180,{r:Q,p:1,f:1}],["b",50.1,180,0,220.3,0,270,{r:Q}],["b",0,319.7,50.1,360,112,360,{r:U}],["b",173.9,360,224,319.7,224,270,{r:Q}],["b",224,220.3,173.9,180,112,180,{r:U}],["b",55.1,180,9,139.7,9,90,{r:Q}],["b",9,40.3,55.1,0,112,0,{r:U}],["b",168.9,0,215,40.3,215,90,{r:Q}],["b",215,139.7,168.9,180,112,180,{r:Q,p:1,f:1}]]}]),9:Y(596,215.8,360,0,-2,0,0,[{d:-1,v:[["m",208.2,88,{r:Q,p:1,f:1}],["b",209.4,94.5,210,101.2,210,108,{r:Q}],["b",210,167.6,163,216,105,216,{r:U}],["b",47,216,-0,167.6,0,108,{r:Q}],["b",0,48.4,47,-0,105,0,{r:U}],["b",156.3,0,199,37.8,208.2,87.8,{r:V}],["b",208.2,87.8,259.8,351.4,93.5,360],["b",50.3,362.3,21.9,339.2,3.6,303.8,{f:1}]]}])},Wt={" ":Y(336,0,0,0,0,0,0,[{d:1,v:[]}]),tofu:Y(672,232,352,0,0,0,0,[{d:-1,v:[["m",0,0,{r:Q}],["l",232,0,{r:Q,f:1}],["l",232,352,{r:Q,f:1}],["l",0,352,{r:Q,f:1}],["l",0,0,{r:Q,p:1,f:1,c:1}]]},{d:1,v:[["m",0,0,{r:Q,p:1,f:1}],["l",232,352,{r:V}]]}]),"?":Y(520,190.348,360,0,-5,0,0,[{d:1,v:[["a",89.174,356]]},{d:-1,v:[["m",0,87.8,{r:tt(0,87.8,12,-2.3,99.1,0,0,87.8,0)}],["b",0,87.8,12,-2.3,99.1,0,{r:U}],["b",186.2,2.4,204.5,75.2,180.9,121.4],["b",157.3,167.6,119.7,178.3,97.4,223.2],["b",90.5,237.1,88.1,249.8,88,260.8,{r:Q,f:1}]]}]),"¿":Y(520,190.348,360,0,-5,0,0,[{d:1,v:[["a",101.174,93]]},{d:-1,v:[["m",190.3,361,{r:tt(190.3,361,178.3,451.1,91.2,448.8,190.3,361,0)}],["b",190.3,361,178.3,451.1,91.2,448.8,{r:U}],["b",4.1,446.4,-14.2,373.6,9.4,327.4],["b",33,281.2,70.6,270.5,92.9,225.6],["b",99.8,211.7,102.2,199,102.3,188,{r:Q,f:1}]]}]),"!":Y(465,8,355,0,-5,0,0,[{d:1,v:[["a",4,356]]},{d:-1,v:[["m",4,0,{y:0}],["l",4,260.8,{f:1}]]}]),"¡":Y(465,8,355,0,-5,0,0,[{d:1,v:[["a",4,93]]},{d:-1,v:[["m",4,188],["l",4,448.8,{f:1,y:.3}]]}]),$:Y(568,224,360,0,0,0,0,[{d:-1,v:[["m",212,51.3,{r:tt(0,295.4,17.6,332.1,58.3,360,110.3,360,0),f:1}],["b",196.5,20.5,158.4,0,114.8,0],["b",57.3,0,13.3,29.8,12,84.4],["b",10.9,130.6,47.3,157.7,112.4,173.3],["b",180.7,189.6,224.2,214.7,224,271],["b",223.8,329.6,173.9,360,110.3,360],["b",58.3,360,17.6,332.1,0,295.4,{f:1}]]},{d:-1,v:[["m",112,-30,{y:0}],["l",112,390,{y:0,f:1}]]}]),"@":Y(820,343.425,360,0,0,-30,-30,[{d:-1,v:[["m",251.9,92.9,{r:$(251.9,92.9,238.5,181.7)}],["l",238.5,181.7,{r:V}],["b",227.8,236,194.7,267.2,143.7,259.2],["b",99.1,252.2,87.7,208.5,90.1,177.5],["b",92.5,148.4,118.1,91,183.3,99.1],["b",251,107.5,238.5,181.7,238.5,181.7,{r:V}],["l",232.5,221.5],["b",232.5,221.5,227.2,257.6,256,263.6],["b",284.9,269.7,309,241.3,309,241.3,{r:V}],["b",309,241.3,343.4,209,343.4,146.7],["b",343.4,84.3,297.4,3.5,178.6,.1],["b",59.7,-3.4,-5.3,105.2,.3,203.4],["b",6.1,303.7,93.2,354.5,175.5,359.5],["b",175.5,359.5,246.5,364.9,302.7,339.8,{f:1}]]}]),"#":Y(760,314,352,0,0,0,0,[{d:-1,v:[["m",117,0,{y:0,r:$(117,0,47,352)}],["l",47,352,{y:0,f:1}]]},{d:-1,v:[["m",267,0,{y:0,r:$(267,0,197,352)}],["l",197,352,{y:0,f:1}]]},{d:-1,v:[["m",24,117,{x:0,r:U}],["l",314,117,{x:0,f:1}]]},{d:-1,v:[["m",0,235,{x:0,r:U}],["l",290,235,{x:0,f:1}]]}]),"%":Y(920,388,360,0,0,0,0,[{d:-1,v:[["m",307.1,5.1,{x:0,y:0,r:$(307.1,5.1,80.9,354.9)}],["l",80.9,354.9,{x:0,y:0,f:1}]]},{d:-1,v:[["m",146,73,{r:Q,p:1}],["b",146,113.3,113.3,146,73,146,{r:U}],["b",32.7,146,0,113.3,0,73,{r:Q}],["b",0,32.7,32.7,0,73,0,{r:U}],["b",113.3,0,146,32.7,146,73,{r:Q,c:1,f:1}]]},{d:-1,v:[["m",388,287,{r:Q,p:1}],["b",388,327.3,355.3,360,315,360,{r:U}],["b",274.7,360,242,327.3,242,287,{r:Q}],["b",242,246.7,274.7,214,315,214,{r:U}],["b",355.3,214,388,246.7,388,287,{r:Q,c:1,f:1}]]}]),"^":Y(596,176,352,0,0,0,0,[{d:-1,v:[["m",0,150,{r:$(0,150,86.5,0)}],["l",86.5,0,{r:$(0,150,86.5,0),f:1}],["l",89.5,0,{r:$(89.5,0,176,150),f:1,v:1}],["l",176,150,{f:1}]]}]),"·":Y(231,8,355,0,0,0,0,[{d:1,v:[["a",4,183.5]]}]),"×":Y(712,176.8,176.8,0,0,0,0,[{d:-1,v:[["m",0,0,{x:0,y:0,r:$(0,0,176.8,176.8)}],["l",176.8,176.8,{x:0,y:0,f:1}]]},{d:-1,v:[["m",176.8,0,{x:0,y:0,r:$(176.8,0,0,176.88)}],["l",0,176.8,{x:0,y:0,f:1}]]}]),"÷":Y(712,188,0,0,0,0,0,[{d:1,v:[["a",94,110]]},{d:1,v:[["a",94,-110]]},{d:-1,v:[["m",0,0,{x:0,y:0,r:U}],["l",188,0,{x:0,y:0,f:1}]]}]),"«":Y(896,310,236,0,0,0,0,[{d:1,v:[["m",150,236,{r:$(150,236,0,119.5),f:1}],["l",0,119.5,{r:$(150,236,0,119.5),f:1}],["l",0,116.5,{r:$(0,116.5,150,0),f:1,v:1}],["l",150,0]]},{d:1,v:[["m",310,236,{r:$(310,236,160,119.5),f:1}],["l",160,119.5,{r:$(310,236,160,119.5),f:1}],["l",160,116.5,{r:$(160,116.5,310,0),f:1,v:1}],["l",310,0]]}]),"»":Y(896,310,236,0,0,0,0,[{d:1,v:[["m",0,236,{r:$(0,236,150,119.5),f:1}],["l",150,119.5,{r:$(0,236,0,119.5),f:1}],["l",150,116.5,{r:$(150,116.5,0,0),f:1,v:1}],["l",0,0]]},{d:1,v:[["m",160,236,{r:$(160,236,310,119.5),f:1}],["l",310,119.5,{r:$(0,236,0,119.5),f:1}],["l",310,116.5,{r:$(310,116.5,160,0),f:1,v:1}],["l",160,0]]}]),"&":Y(660,259.191,360,0,0,0,0,[{d:1,v:[["m",257.9,355,{x:.5,y:.5,r:$(257.9,355,52.8,135.3),f:1}],["l",52.8,135.3],["b",52.8,135.3,-2.2,79.5,46.6,26.7],["b",46.6,26.7,68.1,0,101.8,0,{r:U}],["b",137.2,0,174.1,21.1,181.2,65.3],["b",188.6,111.7,142.6,142.9,108.9,162.9],["b",75.2,182.8,40.8,211.4,40.8,211.4,{r:V}],["b",35,217.1,-34.7,273.7,22.2,330.5],["b",22.2,330.5,48.1,360,93.4,360,{r:U}],["b",138.6,360,212.2,322,259.2,200.5]]}]),"*":Y(558,183.597,212,0,0,0,0,[{d:-1,v:[["m",91.8,0,{x:0,y:0}],["l",91.8,212,{x:0,y:0,f:1}]]},{d:-1,v:[["m",0,53,{x:0,y:0,r:$(0,53,183.6,159)}],["l",183.6,159,{x:0,y:0,f:1}]]},{d:-1,v:[["m",0,159,{x:0,y:0,r:$(0,159,183.6,53)}],["l",183.6,53,{x:0,y:0,f:1}]]}]),"+":Y(712,250,250,0,0,0,0,[{d:-1,v:[["m",125,0,{x:0,y:0}],["l",125,250,{x:0,y:0,f:1}]]},{d:-1,v:[["m",0,125,{x:0,y:0,r:U}],["l",250,125,{x:0,y:0,f:1}]]}]),"=":Y(712,216,86,0,0,0,0,[{d:-1,v:[["m",0,0,{x:0,y:0,r:U}],["l",216,0,{x:0,y:0,f:1}]]},{d:-1,v:[["m",0,86,{x:0,y:0,r:U}],["l",216,86,{x:0,y:0,f:1}]]}]),"-":Y(712,188,0,0,0,0,0,[{d:-1,v:[["m",0,0,{x:0,y:0,r:U}],["l",188,0,{x:0,y:0,f:1}]]}]),_:Y(481,235,400,0,0,0,0,[{d:-1,v:[["m",0,400,{x:0,y:0,r:U}],["l",235,400,{x:0,y:0,f:1}]]}]),":":Y(231,8,355,0,0,0,0,[{d:1,v:[["a",4,183.5]]},{d:1,v:[["a",4,353.5]]}]),";":Y(231,8,355,0,0,0,0,[{d:1,v:[["a",4,183.5]]},{d:-1,v:[["m",4,350,{x:0,y:2,r:$(4,350,-6,430)}],["l",-6,430,{x:0,y:.5,f:1}]]}]),".":Y(231,8,355,0,0,0,0,[{d:1,v:[["a",4,353.5]]}]),",":Y(231,10,355,10,10,0,0,[{d:-1,v:[["m",10,350,{x:0,y:2,r:$(10,350,0,430)}],["l",0,430,{x:0,y:.5,f:1}]]}]),"'":Y(173,0,360,0,0,0,0,[{d:-1,v:[["m",0,0,{x:0,y:0}],["l",0,80,{x:0,y:0,f:1}]]}]),'"':Y(297,60,360,0,0,0,0,[{d:-1,v:[["m",0,0,{x:-1.5,y:0}],["l",0,80,{x:-1.5,y:0,f:1}]]},{d:-1,v:[["m",60,0,{x:-1.5,y:0}],["l",60,80,{x:-1.5,y:0,f:1}]]}]),"~":Y(731,199.391,47.063,0,0,0,0,[{d:1,v:[["m",199.4,20.7,{x:0,y:0,r:tt(199.4,20.7,187.6,36.6,168.2,47.1,148.2,47.1,0),f:1}],["b",187.6,36.6,168.2,47.1,148.2,47.1,{x:0,y:0,r:U}],["b",129.1,47.1,112.1,36.6,95.3,25.5,{x:0,y:0}],["b",76.8,13.2,59.1,0,39.6,0,{x:0,y:0,r:U}],["b",22.3,0,10.9,8.9,0,20,{x:0,y:0}]]}]),"(":Y(365,107.865,360,0,0,0,0,[{d:1,v:[["m",107.9,360,{y:.8,r:tt(107.9,360,39.7,321.1,0,259.8,0,182.9,0),f:1}],["b",39.7,321.1,0,259.8,0,182.9,{y:.8,r:Q}],["b",0,100.2,39.7,38.9,107.9,0,{y:.8}]]}]),")":Y(365,107.865,360,0,0,0,0,[{d:-1,v:[["m",0,0,{y:.8,r:tt(0,0,68.2,38.9,107.9,100.2,107.9,177,0)}],["b",68.2,38.9,107.9,100.2,107.9,177,{y:.8,r:Q}],["b",107.9,259.8,68.2,321.1,0,360,{y:.8,f:1}]]}]),"{":Y(385,107.865,360,0,0,0,0,[{d:1,v:[["m",94.5,360,{x:-.5,r:U}],["l",77.9,360,{x:-.5}],["b",57.4,360,37,343,37,310.7,{x:-.5}],["l",37,233.4,{x:-.5}],["b",37,207.9,24.3,183.7,3.8,180.7,{x:-.5,r:U}],["l",3.8,179.8,{x:-.5,r:U,p:1}],["b",24.3,176.8,37,153.1,37,126.7,{x:-.5}],["l",37,49.4,{x:-.5}],["b",37,17.1,57.4,.1,77.9,.1,{x:-.5}],["l",94.5,.1,{x:-.5}]]}]),"}":Y(385,107.865,360,0,0,0,0,[{d:-1,v:[["m",13.4,.1,{x:-.5,r:U}],["l",30,.1,{x:-.5}],["b",50.4,.1,70.8,17.1,70.8,49.4,{x:-.5}],["l",70.8,126.7,{x:-.5}],["b",70.8,153.1,83.6,176.8,104,179.8,{x:-.5,r:U}],["l",104,180.7,{x:-.5,r:U,p:1}],["b",83.6,183.7,70.8,207.9,70.8,233.4,{x:-.5}],["l",70.8,310.7,{x:-.5}],["b",70.8,343,50.4,360,30,360,{x:-.5}],["l",13.4,360,{x:-.5}]]}]),"[":Y(365,66,352,0,0,0,0,[{d:-1,v:[["m",66,0,{x:-1,r:U}],["l",0,0,{r:Q,f:1}],["l",0,352,{r:Q,f:1}],["l",66,352,{x:-1,f:1}]]}]),"]":Y(365,66,352,0,0,0,0,[{d:-1,v:[["m",0,0,{x:-1,r:U}],["l",66,0,{r:Q,f:1}],["l",66,352,{r:Q,f:1}],["l",0,352,{x:-1,f:1}]]}]),"<":Y(423,90,352,0,0,0,0,[{d:-1,v:[["m",90,0,{x:-1,y:.3,r:$(90,0,0,176)}],["l",0,176,{r:Q,f:1}],["l",90,352,{x:-1,y:.3,f:1}]]}]),">":Y(423,90,352,0,0,0,0,[{d:-1,v:[["m",0,0,{x:-1,y:.3,r:$(0,0,90,176)}],["l",90,176,{r:Q,f:1}],["l",0,352,{x:-1,y:.3,f:1}]]}]),"/":Y(433,130,352,0,0,0,0,[{d:1,v:[["m",0,352,{r:$(0,352,130,0),f:1,y:0}],["l",130,0,{y:0}]]}]),"þ":Y(600,232,338,-10,-2,-117,-117,[{d:-1,v:[["m",0,-106,{y:0}],["l",0,116,{r:V}],["b",0,180.1,51.9,232,116,232,{r:U}],["b",180.1,232,232,180.1,232,116,{r:Q}],["b",232,51.9,180.1,0,116,0,{r:U}],["b",51.9,0,0,51.9,0,116,{r:Q}],["l",0,338,{y:0,f:1}]]}]),"Þ":Y(520,162,352,-5,-70,0,0,[{d:-1,v:[["m",0,0,{x:0,y:0,r:Q}],["l",0,352,{x:0,y:0,r:Q,f:1}]]},{d:1,v:[["m",0,281.6,{x:0,r:U,f:1,p:1}],["l",57,281.6,{x:-.5,r:U,f:1}],["b",115,281.6,162,233.4,162,175.4,{x:-.5,r:Q}],["b",162,117.4,115,70.4,57,70.4,{x:-.5,r:U}],["l",0,70.4,{x:0,r:U,f:1,p:1}]]}]),"ß":Y(596,209,352,-10,-10,0,0,[{d:1,v:[["m",0,348.3,{r:Q,f:1,x:0,y:0}],["l",0,104.3,{x:0}],["b",0,46,36,0,98.9,0,{x:0}],["b",145.2,0,191,27.9,191,81,{x:1}],["b",191,110.7,165.6,131.8,151.8,140.9],["l",140,148.8],["b",120.6,161.7,110.8,172.8,110.8,185.5],["b",110.8,206.7,131.6,213.8,140,217.5],["b",190.6,241.1,211,262.7,211,289.6],["b",211,329.5,174.8,352,142.5,352],["b",97.3,352,75.2,319.7,72.3,289.3]]}])};function kt(t,r){var i=t,e=-60+r;return[{d:-1,v:[["m",-40+i,e,{x:0,y:0,r:$(-40+i,e,0+i,60+e)}],["l",0+i,60+e,{x:0,y:0,f:1}]]}]}function Dt(t,r){var i=t,e=-60+r;return[{d:-1,v:[["m",40+i,e,{x:0,y:0,r:$(40+i,e,0+i,60+e)}],["l",0+i,60+e,{x:0,y:0,f:1}]]}]}function Tt(t,r){var i=-68+t,e=0+r;return[{d:-1,v:[["m",0+i,50+e,{r:$(0+i,50+e,66.5+i,0+e),y:0,x:0}],["l",66.5+i,0+e,{r:$(0+i,50+e,66.5+i,0+e),y:0,x:0,f:1}],["l",69.5+i,0+e,{r:$(69.5+i,0+e,136+i,50+e),y:0,x:0,f:1,v:1}],["l",136+i,50+e,{y:0,x:0,f:1}]]}]}function It(t,r){var i=t-76.24,e=r;return[{d:1,v:[["m",159.52+i,16.56+e,{x:-1,y:-.2,r:tt(159.52+i,16.56+e,150.08+i,29.28+e,134.56+i,37.68+e,118.56+i,37.68+e,0),f:1}],["b",150.08+i,29.28+e,134.56+i,37.68+e,118.56+i,37.68+e,{x:-1,y:-.2,r:U}],["b",103.28+i,37.68+e,89.68+i,29.28+e,76.24+i,20.4+e,{x:-1,y:-.2}],["b",61.44+i,10.56+e,47.28+i,0+e,31.68+i,0+e,{x:-1,y:-.2,r:U}],["b",17.84+i,0+e,8.72+i,7.12+e,0+i,16+e,{x:-1,y:-.2}]]}]}function Rt(t,r){return[{d:1,v:[["a",-50+t,r,{x:0,y:0}]]},{d:1,v:[["a",50+t,r,{x:0,y:0}]]}]}function Ft(t,r){var i=t-57,e=r;return[{d:1,v:[["m",112.7+i,0+e,{r:tt(112.7+i,0+e+i,10.1+e,110.1+i,19.3+e,105+i,27.7+e,0),x:0,y:0,f:1}],["b",112.7+i,10.1+e,110.1+i,19.3+e,105+i,27.7+e,{x:0,y:0}],["b",99.8+i,36.1+e,92.9+i,42.8+e,84.3+i,47.7+e,{x:0,y:0}],["b",75.7+i,52.6+e,66.7+i,55+e,57.3+i,55+e,{x:0,y:0}],["b",47.5+i,55+e,38.3+i,52.6+e,29.6+i,47.7+e,{x:0,y:0}],["b",20.8+i,42.8+e,13.8+i,36.1+e,8.5+i,27.7+e,{x:0,y:0}],["b",3.2+i,19.3+e,.5+i,10.1+e,.5+i,0+e,{x:0,y:0}]]}]}function Mt(t,r){var i=88+t,e=-116+r;return[{d:1,v:[["m",116+i,58+e,{r:Q,p:1,f:1}],["b",116+i,90.05+e,90.05+i,116+e,58+i,116+e,{r:U}],["b",25.95+i,116+e,0+i,90.05+e,0+i,58+e,{r:Q}],["b",0+i,25.95+e,25.95+i,0+e,58+i,0+e,{r:U}],["b",90.05+i,0+e,116+i,25.95+e,116+i,58+e,{r:Q,c:1}]]}]}function Gt(t,r){return[{d:1,v:[["m",t-40,r,{x:0,y:1,r:U}],["l",100+t,r,{x:0,y:1,f:1}]]}]}function zt(t,r){return[{d:-1,v:[["m",t,r,{p:1}],["b",9.3+t,11.6+r,15.6+t,27.1+r,15.6+t,40.9+r],["b",15.6+t,83.3+r,-18.2+t,107.8+r,-59.5+t,107.8+r],["b",-70.9+t,107.8+r,-82.9+t,106.2+r,-93.7+t,102.7+r,{x:.5,f:1}]]}]}function Lt(t,r){return[{d:-1,v:[["m",t,r,{p:1}],["b",-19.6+t,14.8+r,-42.2+t,37.9+r,-42.2+t,64.1+r],["b",-42.2+t,100.3+r,30.2-42.2+t,118.8+r,21.4+t,118.8+r],["b",68.3-42.2+t,118.8+r,72.9-42.2+t,118.4+r,35.2+t,117.6+r,{x:.5,f:1}]]}]}function jt(t,r){return[{d:1,v:[["a",t,r,{x:0,y:0}]]}]}function Ct(t,r){var i=-68+t,e=r;return[{d:-1,v:[["m",0+i,e,{r:$(0+i,e,66.5+i,50+e),y:0,x:0}],["l",66.5+i,50+e,{r:$(0+i,e,66.5+i,50+e),y:0,x:0,f:1}],["l",69.5+i,50+e,{r:$(69.5+i,50+e,136+i,e),y:0,x:0,f:1,v:1}],["l",136+i,e,{y:0,x:0,f:1}]]}]}function At(t,r){return[{d:1,v:[["m",t-50,r,{x:0,y:0}],["l",t+50,r,{x:0,y:0,f:1}]]}]}var qt,Xt,Et=[{d:1,v:[["m",0,352,{y:0,f:1}],["l",0,130,{y:-3}]]}],Bt=[{d:1,v:[["m",-115.9,444,{x:.4,y:.63,r:tt(-115.9,444,12.6-115.9,454.4,29.6-115.9,460.2,-70,461.2,0),f:1}],["b",12.6-115.9,454.4,29.6-115.9,460.2,-70,461.2,{x:.4,y:.63,r:U}],["b",84.5-115.9,463.5,0,435.1,0,396.4,{x:.4,y:.63,r:Q}],["l",0,130,{y:-3}]]}],Ht={"Æ":Y(996,426,352,0,0,0,0,[{d:-1,v:[["m",426,0,{x:0,r:U}],["l",234,0,{x:.5,f:1,r:$(234,0,0,352)}],["l",0,352,{x:.5,y:.5,f:1}]]},{d:-1,v:[["m",234,0,{x:.5,p:1}],["l",234,352,{f:1,x:.5}],["l",426,352,{f:1,x:0}]]},{d:-1,v:[["m",76.4,237,{r:U,p:1}],["l",234,237,{f:1,r:U,p:1}]]},{d:-1,v:[["m",234,164,{r:U,p:1,x:.5}],["l",414,164,{f:1,x:0}]]}]),"æ":Y(1e3,457.5,232,0,0,-64,-64,[{d:-1,v:[["m",232,8,{y:-3.4,r:Q}],["l",232,116,{r:V}],["b",232,180.1,180.1,232,116,232,{r:U}],["b",51.9,232,0,180.1,0,116,{r:Q}],["b",0,51.9,51.9,0,116,0,{r:U}],["b",180.1,0,232,51.9,232,116,{r:Q}],["l",232,224,{y:-.1,r:Q,f:1}]]},{d:1,v:[["m",443.6,182.9,{r:tt(443.6,182.9,423.1,213.2,388.1,233.1,348.5,233.1,0),f:1}],["b",423.1,213.2,388.1,233.1,348.5,233.1,{r:U}],["b",284.4,233.1,232.5,181.2,232.5,117.1,{r:Q}],["b",232.5,53,284.4,1.1,348.5,1.1,{r:U}],["b",408.4,1.1,456.9,47.2,457.5,106.1,{r:Q}],["l",232.5,106.1,{r:Q,p:1}]]}]),"À":Y(620,290,352,0,0,0,0,JSON.parse(JSON.stringify(rt)).concat(kt(145,-50))),"Á":Y(620,290,352,0,0,0,0,JSON.parse(JSON.stringify(rt)).concat(Dt(145,-50))),"Â":Y(620,290,352,0,0,0,0,JSON.parse(JSON.stringify(rt)).concat(Tt(145,-100))),"Ã":Y(620,290,352,0,0,0,0,JSON.parse(JSON.stringify(rt)).concat(It(145,-90))),"Ä":Y(620,290,352,0,0,0,0,JSON.parse(JSON.stringify(rt)).concat(Rt(145,-70))),"Å":Y(620,290,352,0,0,0,0,JSON.parse(JSON.stringify(rt)).concat(Mt(0,0))),"Ă":Y(620,290,352,0,0,0,0,JSON.parse(JSON.stringify(rt)).concat(Ft(145,-110))),"Ą":Y(620,290,352,0,0,0,0,JSON.parse(JSON.stringify(rt)).concat(Lt(290,352))),"à":Y(600,232,232,10,2,-64,-64,JSON.parse(JSON.stringify(vt)).concat(kt(116,-60))),"á":Y(600,232,232,10,2,-64,-64,JSON.parse(JSON.stringify(vt)).concat(Dt(116,-60))),"â":Y(600,232,232,10,2,-64,-64,JSON.parse(JSON.stringify(vt)).concat(Tt(116,-110))),"ã":Y(600,232,232,10,2,-64,-64,JSON.parse(JSON.stringify(vt)).concat(It(116,-100))),"ä":Y(600,232,232,10,2,-64,-64,JSON.parse(JSON.stringify(vt)).concat(Rt(116,-80))),"å":Y(600,232,232,10,2,-64,-64,JSON.parse(JSON.stringify(vt)).concat(Mt(-30,0))),"ă":Y(600,232,232,10,2,-64,-64,JSON.parse(JSON.stringify(vt)).concat(Ft(116,-120))),"ą":Y(600,232,232,10,2,-64,-64,JSON.parse(JSON.stringify(vt)).concat(Lt(232,224))),"Ć":Y(700,293.1,360,0,0,0,0,JSON.parse(JSON.stringify(it)).concat(kt(180,-60))),"Ĉ":Y(700,293.1,360,0,0,0,0,JSON.parse(JSON.stringify(it)).concat(Tt(180,-110))),"Ċ":Y(700,293.1,360,0,0,0,0,JSON.parse(JSON.stringify(it)).concat(jt(180,-80))),"Č":Y(700,293.1,360,0,0,0,0,JSON.parse(JSON.stringify(it)).concat(Ct(180,-110))),"Ç":Y(700,293.1,360,0,0,0,0,JSON.parse(JSON.stringify(it)).concat(zt(180,360))),"ć":Y(520,212.1,233.1,2,-10,-64,-64,JSON.parse(JSON.stringify(xt)).concat(kt(116.5,-68.9))),"ĉ":Y(520,212.1,233.1,2,-10,-64,-64,JSON.parse(JSON.stringify(xt)).concat(Tt(116.5,-118.9))),"ċ":Y(520,212.1,233.1,2,-10,-64,-64,JSON.parse(JSON.stringify(xt)).concat(jt(116.5,-88.9))),"č":Y(520,212.1,233.1,2,-10,-64,-64,JSON.parse(JSON.stringify(xt)).concat(Ct(116.5,-118.9))),"ç":Y(520,212.1,233.1,2,-10,-64,-64,JSON.parse(JSON.stringify(xt)).concat(zt(116.5,233.1))),"Đ":Y(721,270,352,-10,-10,0,0,JSON.parse(JSON.stringify(et)).concat(Gt(0,176))),"Ď":Y(721,270,352,-10,-10,0,0,JSON.parse(JSON.stringify(et)).concat(Ct(100,-110))),"ď":Y(600,232,352,10,2,0,0,JSON.parse(JSON.stringify(ut)).concat((qt=300,Xt=0,[{d:-1,v:[["m",qt,Xt,{x:0,y:0}],["l",qt,80+Xt,{x:0,y:0,f:1}]]}]))),"đ":Y(600,232,352,10,2,0,0,JSON.parse(JSON.stringify(ut)).concat(Gt(180,40))),"È":Y(520,192,352,-5,-80,0,0,JSON.parse(JSON.stringify(at)).concat(kt(96,-60))),"É":Y(520,192,352,-5,-80,0,0,JSON.parse(JSON.stringify(at)).concat(Dt(96,-60))),"Ê":Y(520,192,352,-5,-80,0,0,JSON.parse(JSON.stringify(at)).concat(Tt(96,-110))),"Ë":Y(520,192,352,-5,-80,0,0,JSON.parse(JSON.stringify(at)).concat(Rt(96,-80))),"Ē":Y(520,192,352,-5,-80,0,0,JSON.parse(JSON.stringify(at)).concat(At(96,-80))),"Ĕ":Y(520,192,352,-5,-80,0,0,JSON.parse(JSON.stringify(at)).concat(Ft(96,-120))),"Ė":Y(520,192,352,-5,-80,0,0,JSON.parse(JSON.stringify(at)).concat(jt(96,-80))),"Ě":Y(520,192,352,-5,-80,0,0,JSON.parse(JSON.stringify(at)).concat(Ct(96,-110))),"è":Y(570,225.5,233.1,0,0,-64,-64,JSON.parse(JSON.stringify(gt)).concat(kt(112,-60))),"é":Y(570,225.5,233.1,0,0,-64,-64,JSON.parse(JSON.stringify(gt)).concat(Dt(112,-60))),"ê":Y(570,225.5,233.1,0,0,-64,-64,JSON.parse(JSON.stringify(gt)).concat(Tt(112,-110))),"ë":Y(570,225.5,233.1,0,0,-64,-64,JSON.parse(JSON.stringify(gt)).concat(Rt(112,-80))),"ē":Y(570,225.5,233.1,0,0,-64,-64,JSON.parse(JSON.stringify(gt)).concat(At(112,-80))),"ĕ":Y(570,225.5,233.1,0,0,-64,-64,JSON.parse(JSON.stringify(gt)).concat(Ft(112,-120))),"ė":Y(570,225.5,233.1,0,0,-64,-64,JSON.parse(JSON.stringify(gt)).concat(jt(112,-90))),"ě":Y(570,225.5,233.1,0,0,-64,-64,JSON.parse(JSON.stringify(gt)).concat(Ct(112,-120))),"Ĝ":Y(840,352,360,0,0,0,0,JSON.parse(JSON.stringify(st)).concat(Tt(180,-110))),"Ğ":Y(840,352,360,0,0,0,0,JSON.parse(JSON.stringify(st)).concat(Ft(180,-120))),"Ġ":Y(840,352,360,0,0,0,0,JSON.parse(JSON.stringify(st)).concat(jt(180,-80))),"Ģ":Y(840,352,360,0,0,0,0,JSON.parse(JSON.stringify(st)).concat(zt(180,360))),"ĝ":Y(600,232,338,10,2,-117,-117,JSON.parse(JSON.stringify(bt)).concat(Tt(116,-118.9))),"ğ":Y(600,232,338,10,2,-117,-117,JSON.parse(JSON.stringify(bt)).concat(Ft(116,-120))),"ġ":Y(600,232,338,10,2,-117,-117,JSON.parse(JSON.stringify(bt)).concat(jt(116,-90))),"ģ":Y(600,232,338,10,2,-117,-117,JSON.parse(JSON.stringify(bt)).concat(Dt(116,-70))),"Ĥ":Y(684,232,352,0,0,0,0,JSON.parse(JSON.stringify(nt)).concat(Tt(116,-110))),"ĥ":Y(520,182,352,0,0,0,0,JSON.parse(JSON.stringify(St)).concat(Tt(91,-110))),"Ì":Y(249,0,352,0,0,0,0,JSON.parse(JSON.stringify(lt)).concat(kt(0,-60))),"Í":Y(249,0,352,0,0,0,0,JSON.parse(JSON.stringify(lt)).concat(Dt(0,-60))),"Î":Y(249,0,352,0,0,0,0,JSON.parse(JSON.stringify(lt)).concat(Tt(0,-110))),"Ï":Y(249,0,352,0,0,0,0,JSON.parse(JSON.stringify(lt)).concat(Rt(0,-80))),"ì":Y(200,0,352,0,0,0,0,JSON.parse(JSON.stringify(Et)).concat(kt(0,70))),"í":Y(200,0,352,0,0,0,0,JSON.parse(JSON.stringify(Et)).concat(Dt(0,70))),"î":Y(200,0,352,0,0,0,0,JSON.parse(JSON.stringify(Et)).concat(Tt(0,10))),"ï":Y(200,0,352,0,0,0,0,JSON.parse(JSON.stringify(Et)).concat(Rt(0,50))),"Ĵ":Y(472,172.5,355.5,10,20,-2,-2,JSON.parse(JSON.stringify(ft)).concat(Tt(172.5,-110))),"ĵ":Y(220,115.9,352,-60,-60,0,0,JSON.parse(JSON.stringify(Bt)).concat(Tt(0,20))),"Ñ":Y(721,250,352,0,0,0,0,JSON.parse(JSON.stringify(ot)).concat(It(125,-100))),"ñ":Y(520,182,352,0,0,0,0,JSON.parse(JSON.stringify(mt)).concat(It(91,30))),"Ò":Y(850,360,360,0,0,0,0,JSON.parse(JSON.stringify(ht)).concat(kt(180,-60))),"Ó":Y(850,360,360,0,0,0,0,JSON.parse(JSON.stringify(ht)).concat(Dt(180,-60))),"Ô":Y(850,360,360,0,0,0,0,JSON.parse(JSON.stringify(ht)).concat(Tt(180,-110))),"Õ":Y(850,360,360,0,0,0,0,JSON.parse(JSON.stringify(ht)).concat(It(180,-100))),"Ö":Y(850,360,360,0,0,0,0,JSON.parse(JSON.stringify(ht)).concat(Rt(180,-80))),"Ø":Y(850,360,360,0,0,0,0,JSON.parse(JSON.stringify(ht)).concat([{d:1,v:[["m",0,360,{r:$(0,360,360,0),f:1,x:0,y:1}],["l",360,0,{x:0,y:1}]]}])),"ò":Y(580,232,232,0,0,-64,-64,JSON.parse(JSON.stringify(Ot)).concat(kt(116,-60))),"ó":Y(580,232,232,0,0,-64,-64,JSON.parse(JSON.stringify(Ot)).concat(Dt(116,-60))),"ô":Y(580,232,232,0,0,-64,-64,JSON.parse(JSON.stringify(Ot)).concat(Tt(116,-110))),"õ":Y(580,232,232,0,0,-64,-64,JSON.parse(JSON.stringify(Ot)).concat(It(116,-100))),"ö":Y(580,232,232,0,0,-64,-64,JSON.parse(JSON.stringify(Ot)).concat(Rt(116,-80))),"ø":Y(580,232,232,0,0,-64,-64,JSON.parse(JSON.stringify(Ot)).concat([{d:1,v:[["m",0,232,{r:$(0,232,232,0),f:1,x:0,y:1}],["l",232,0,{x:0,y:1}]]}])),"Ŝ":Y(560,224,360,0,0,0,0,JSON.parse(JSON.stringify(yt)).concat(Tt(112.4,-110))),"ŝ":Y(400,143.808,231.12,0,0,-64,-64,JSON.parse(JSON.stringify(Jt)).concat(Tt(112.4*.642,-110))),"Ş":Y(560,224,360,0,0,0,0,JSON.parse(JSON.stringify(yt)).concat(zt(110.3,360))),"ş":Y(400,143.808,231.12,0,0,-64,-64,JSON.parse(JSON.stringify(Jt)).concat(zt(70.8126,231.12))),"Ù":Y(712,250,355,0,0,-.5,-.5,JSON.parse(JSON.stringify(dt)).concat(kt(125,-50))),"Ú":Y(712,250,355,0,0,-.5,-.5,JSON.parse(JSON.stringify(dt)).concat(Dt(125,-50))),"Û":Y(712,250,355,0,0,-.5,-.5,JSON.parse(JSON.stringify(dt)).concat(Tt(125,-100))),"Ŭ":Y(712,250,355,0,0,-.5,-.5,JSON.parse(JSON.stringify(dt)).concat(Ft(125,-110))),"Ü":Y(712,250,355,0,0,-.5,-.5,JSON.parse(JSON.stringify(dt)).concat(Rt(125,-70))),"ù":Y(520,182,352,0,0,0,0,JSON.parse(JSON.stringify(Nt)).concat(kt(91,70))),"ú":Y(520,182,352,0,0,0,0,JSON.parse(JSON.stringify(Nt)).concat(Dt(91,70))),"û":Y(520,182,352,0,0,0,0,JSON.parse(JSON.stringify(Nt)).concat(Tt(91,20))),"ŭ":Y(520,182,352,0,0,0,0,JSON.parse(JSON.stringify(Nt)).concat(Ft(91,10))),"ü":Y(520,182,352,0,0,0,0,JSON.parse(JSON.stringify(Nt)).concat(Rt(91,50))),"Ý":Y(673,270,352,0,0,0,0,JSON.parse(JSON.stringify(ct)).concat(Dt(135,-60))),"ý":Y(500,225.5,331.5,10,10,-119,-119,JSON.parse(JSON.stringify(_t)).concat(Dt(116.3,-60))),"ÿ":Y(500,225.5,331.5,10,10,-119,-119,JSON.parse(JSON.stringify(_t)).concat(Rt(116.3,-90)))},Kt=Object.assign({},pt,wt,Pt,Wt,Ht);function Qt(t){var r=(Kt[t]||Kt.tofu).clone();return r.v=t,r}function Ut(t,r,i,e){var a;return a=t.indexOf("\n")>0?t.split("\n"):t.indexOf("\\n")>0?t.split("\\n"):[t],0==i?function(t){var r,i=[],e=t.length;for(r=0;r<e;r++)i[r]=t[r].split("");return i}(a):e?function(t,r,i){var e,a,n,l,f,o,h,y,d=0,c=0,p=[];for(n=t.length,a=0;a<n;a++){for(h=t[a],d=0,0,p[c]=[],f=h.length,l=0;l<f;l++)y=h[l],e=Qt(y),o=s(e,r),d+=o.w,p[c].push(y),d>=i&&(c+=1,d=o.w,p[c]=[]);c+=1}var v=[];for(n=p.length,a=0;a<n;a++)(e=p[a]).length>0&&(" "==e[0]&&e.shift()," "==e[e.length-1]&&e.pop(),e.length>0&&v.push(e));return v}(a,r,i):function(t,r,i){var e,a,n,l,f,o,h,y,d,c,p=0,v=0,x=0,u=[];for(y=t.length,f=0;f<y;f++){for(e=t[f].split(" "),u[x]=[],d=e.length,o=0;o<d;o++){for(v=0,a=e[o],c=a.length,h=0;h<c;h++)n=Qt(a[h]),l=s(n,r),v+=l.w;n=Qt(" "),l=s(n,r),v+=l.w,(p+=v)>i&&(p=v,u[x+=1]=[]),u[x].push(a)}x+=1,p=0}y=u.length;var g=[];for(f=0;f<y;f++)(n=u[f].join(" ").split("")).length>0&&g.push(n);return g}(a,r,i)}function Vt(t,r){return{c:(t-r)/2,r:t-r,l:0}}class Yt{constructor(){this.lineWidth_=1,this.drawing_=[],this.data_=null,this.paths_=null,this.lines_=null,this.rect_={x:0,y:0,w:0,h:0},this.align_="left",this.scale_=1,this.fontRatio_=1}get data(){return this.data_}get paths(){return this.paths_}get lines(){return this.lines_}set lines(t){this.lines_=t}get lineWidth(){return this.lineWidth_}get fontRatio(){return this.fontRatio_}get scale(){return this.scale_}get rect(){return this.rect_}get drawing(){return this.drawing_}set align(t){this.align_!=t&&(this.align_=t,this.setPosition())}get align(){return this.align_}position(t,r){return(this.rect_.x!=t||this.rect_.y!=r)&&(this.rect_.x=t,this.rect_.y=r,this.setPosition(),!0)}setPosition(){var t,r,i,e,a=this.data_.length;for(t=0;t<a;t++)(r=this.data_[t]).rect.x=r.originPos.x+this.rect_.x+(i=this.align_,e=r.alignGapX,"center"==i?e.c:"right"==i?e.r:e.l),r.rect.y=r.originPos.y+this.rect_.y}updateDrawingPaths(){var t,r,i=this.data_.length;for(t=0;t<i;t++)(r=this.data_[t]).drawingPaths=h(q(this,r,-1,!1),r)}updatePatternPaths(t){var r,i,e=this.data_.length;for(r=0;r<e;r++)(i=this.data_[r]).rawPaths=q(this,i,t,!0)}updateWavePaths(t){var r,i,e=this.data_.length;for(r=0;r<e;r++)(i=this.data_[r]).rawWavePaths=q(this,i,t,!1)}updateGuide(){var t,r,i=this.data_.length;for(t=0;t<i;t++)(r=this.data_[t]).guide=M(r.typo,this.scale),r.grid=G(r.typo,this.scale)}update(t,r,i,a,f,o,h){var y=function(t){return(70-e)/(900-e)*(t-e)+e}(a),d=function(t){return 1/(80-e)*(t-e)}(y),c=function(t){return 54/(80-e)*(t-e)+4}(y),p=function(t){return t/500}(f),v=function(t,r){return 50*t*r}(o,p),x=function(t,r){return 50*t*r}(h,p),u=function(t){return(.78-1)*t+1}(d);this.fontRatio_=u,this.scale_=p,this.lineWidth_=function(t,r){var i=t*r;return i<1&&(i=1),i}(y,p);var g,b,S,m,J,N,_,w,P,W=Ut(t,p,r,i),k=W.length,D=k-1,T=0,I=0,R=0,F=0,M=0,G=0,z=[];for(g=0;g<k;g++){for(m=(S=(J=W[g]).length)-1,T=0,R=0,z[g]={tw:0,arr:[]},b=0;b<S;b++)T+=(w=s(N=Qt(_=J[b]),p)).w,I=w.h,b<m&&(T+=v),g<D&&(I+=x),w.x=R,w.y=F,P={x:R,y:F},z[g].arr[b]={str:_,typo:N,rect:w,originPos:P,center:n(w.w,w.h,p),range:l(N,d,c)},R=T;F+=I,z[g].tw=T,M=Math.max(M,T),G+=I}this.rect_.w=M,this.rect_.h=G,this.drawing_=[];var L,j,C=[];for(var A of z)for(var q of(L=Vt(M,A.tw),A.arr))for(var X of(q.alignGapX=L,q.pointsLength=O(q,this),C.push(q),j={value:1},this.drawing_.push(j),q.drawing=j,q.typo.p))for(var E of(X.cv=[],X.v))X.cv.push(E.convert(q,this));this.data_=C,this.setPosition()}updatePathsForRect(){var t,r,i=this.data_.length,e=[];for(t=0;t<i;t++)(r=this.data_[t]).rawWavePaths&&(r.wavePaths=h(r.rawWavePaths,r)),r.rawPaths&&(r.paths=h(r.rawPaths,r),Array.prototype.push.apply(e,r.paths));this.paths_=e}updateLinesForRect(){var t,r,i=this.data_.length;for(t=0;t<i;t++)(r=this.data_[t]).lines=o(r)}reset(){this.lineWidth_=1,this.drawing_=[],this.data_=null,this.paths_=null,this.lines_=null,this.rect_={x:0,y:0,w:0,h:0},this.align_="left",this.scale_=1,this.fontRatio_=1}}class Zt extends class{constructor(){this.handlers_={update:{listeners:[]}}}on(t,r){return"function"!=typeof r?(console.error("The listener callback must be a function, the given type is ".concat(typeof r)),!1):"string"!=typeof t?(console.error("The event name must be a string, the given type is ".concat(typeof t)),!1):(void 0===this.handlers_[t]&&(this.handlers_[t]={listeners:[]}),void this.handlers_[t].listeners.push(r))}off(t,r){if(void 0===this.handlers_[t])return console.error("This event: ".concat(t," does not exist")),!1;this.handlers_[t].listeners=this.handlers_[t].listeners.filter(t=>t.toString()!==r.toString())}dispatch(t,r){this.handlers_[t].listeners.forEach(t=>{t(r)})}}{constructor(){var{text:t="",size:r=500,weight:i=e,color:a=["#000000"],colorful:s=["#c5d73f","#9d529c","#49a9db","#fec330","#5eb96e","#fc5356","#f38f31"],tracking:n=0,leading:l=0,align:f="left",pathGap:o=.5,amplitude:h=.5,width:y=0,breakWord:d=!1,fps:c=30,isPath:p=!1,isWave:v=!1}=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};super(),this.size_=r,this.weight_=i,this.color_=a,this.colorful_=function(t){for(var r,i,e=t.slice(),a=e.length,s=a;s--;)r=Math.random()*a|0,i=e[s],e[s]=e[r],e[r]=i;return e}(s),this.tracking_=n,this.leading_=l,this.pathGap_=o,this.amplitude_=h,this.width_=y,this.breakWord_=d,this.fps_=c,this.fpsTime_=1e3/this.fps_,this.isPath_=p,this.isWave_=v,this.model=new Yt,this.str_=null,this.time_=null,this.isFps_=!1,this.isForceRander_=!1,this.updateID_=0,this.dPathsID_=null,this.pPathsID_=null,this.wPathsID_=null,this.guideID_=null,this.text=t,this.model.align=f}on(t,r){super.on(t,r),this.update()}off(t,r){super.off(t,r)}get text(){return this.str_}set text(t){this.str_!=t&&(this.str_=t,this.update())}get size(){return this.size_}set size(t){this.size_!=t&&(this.size_=t,this.update(),this.isForceRander_=!0)}get weight(){return this.weight_}set weight(t){t<e?t=e:t>900&&(t=900),this.weight_!=t&&(this.weight_=t,this.update(),this.isForceRander_=!0)}get color(){return this.color_}set color(t){this.color_!=t&&(this.color_=t)}get tracking(){return this.tracking_}set tracking(t){this.tracking_!=t&&(this.tracking_=t,this.update(),this.isForceRander_=!0)}get leading(){return this.leading_}set leading(t){this.leading_!=t&&(this.leading_=t,this.update(),this.isForceRander_=!0)}get align(){return this.model.align}set align(t){this.model.align!=t&&(this.model.align=t,this.updateID_++,this.updateSignal())}get pathGap(){return this.pathGap_}set pathGap(t){this.pathGap_!=t&&(this.pathGap_=t,this.updatePatternPaths(!0),this.updateWavePaths(!0),this.isForceRander_=!0)}get amplitude(){return this.amplitude_}set amplitude(t){this.amplitude_=t}get rect(){return this.model.rect}set maxWidth(t){this.width_!=t&&(this.width_=t,this.update())}get maxWidth(){return this.width_}set breakWord(t){this.breakWord_!=t&&(this.breakWord_=t,this.update())}get breakWord(){return this.breakWord_}get isPath(){return this.isPath_}set isPath(t){this.isPath_=t,this.updatePatternPaths(!0)}get isWave(){return this.isWave_}set isWave(t){this.isWave_=t,this.updateWavePaths(!0)}get fps(){return this.fps_}set fps(t){this.fps_=t,this.fpsTime_=1e3/this.fps_}get lineWidth(){return this.model.lineWidth}get scale(){return this.model.scale}get drawing(){return this.model.drawing}get data(){return this.model.data}get paths(){return this.model.paths}get drawingPaths(){return this.model.drawingPaths}get wavePaths(){return this.model.wavePaths}position(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:0,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;this.model.position(t,r)&&(this.updateID_++,this.updateSignal())}update(){this.updateID_++,this.model.update(this.str_,this.width_,this.breakWord_,this.weight_,this.size_,this.tracking_,this.leading_),this.isPath_||this.isWave_?(this.updatePatternPaths(),this.updateWavePaths()):this.updateSignal()}updateGuide(){this.guideID_!=this.updateID_&&(this.guideID_=this.updateID_,this.model.updateGuide())}updateDrawingPaths(){this.dPathsID_!=this.updateID_&&(this.dPathsID_=this.updateID_,this.model.updateDrawingPaths())}updatePatternPaths(t){this.isPath_&&(t||this.pPathsID_!=this.updateID_)&&(this.pPathsID_=this.updateID_,this.model.updatePatternPaths(this.pathGap_),this.isForceRander_=!0,this.updateSignal())}updateWavePaths(t){this.isWave_&&(t||this.wPathsID_!=this.updateID_)&&(this.wPathsID_=this.updateID_,this.model.updateWavePaths(this.pathGap_),this.isForceRander_=!0,this.updateSignal())}updateSignal(){this.model.updateLinesForRect(),this.model.updatePathsForRect(),this.dispatch("update",this.model)}reset(){this.size_=500,this.weight_=e,this.color_=["#000000"],this.tracking_=0,this.leading_=0,this.pathGap_=.5,this.amplitude_=.5,this.width_=0,this.breakWord_=!1,this.fps_=30,this.fpsTime_=1e3/this.fps_,this.isPath_=!1,this.isWave_=!1,this.str_=null,this.time_=null,this.isFps_=!1,this.isForceRander_=!1,this.updateID_=0,this.dPathsID_=null,this.pPathsID_=null,this.wPathsID_=null,this.guideID_=null,this.model.reset()}dispose(){this.reset(),this.model=null}drawPixi(t){var r,i,e,a=this.model.data.length;for(r=0;r<a;r++)i=this.model.data[r],e=F(r,0,this.color_),T(t,i,this.lineWidth,e)}draw(t){t.lineWidth=this.lineWidth;var r,i,e=this.model.data.length;for(r=0;r<e;r++)m(t,r,i=this.model.data[r],this.color_),y(t,i)}drawColorful(t){t.lineWidth=this.lineWidth,function(t,r,i){W=-1,P=(x=i).length;var e,s,n,l,f,o,h,y,d,c,p=r.data.length;for(e=0;e<p;e++)for(y=(s=r.data[e]).pointsLength.max,c=0,l=s.lines.length,h=null,n=0;n<l;n++)"a"==(o=(f=s.lines[n]).pos).type?(k(t),t.beginPath(),t.arc(o.x,o.y,o.radius*s.drawing.value,0,a),t.fill(),t.closePath()):"m"==o.type?h=o:"l"==o.type?((d=w(h.x,h.y,o.x,o.y))/r.scale>10&&(k(t),t.beginPath(),h&&t.moveTo(h.x,h.y),t.lineTo(o.x,o.y),c+=D(t,f,d,y,s,c)),h=o):"b"==o.type&&((d=N(h.x,h.y,o.x,o.y,o.x2,o.y2,o.x3,o.y3))/r.scale>10&&(k(t),t.beginPath(),h&&t.moveTo(h.x,h.y),t.bezierCurveTo(o.x,o.y,o.x2,o.y2,o.x3,o.y3),c+=D(t,f,d,y,s,c)),h={x:o.x3,y:o.y3})}(t,this.model,this.colorful_)}wave(t,r){(t.lineWidth=this.lineWidth,r)&&(this.time_||(this.time_=r),r-this.time_>this.fpsTime_||this.isForceRander_?(this.time_=r,this.isFps_=!0):this.isFps_=!1);this.isForceRander_=!1;var i,e,a=this.model.data.length;for(i=0;i<a;i++)m(t,i,e=this.model.data[i],this.color_),b(t,e,this.model.scale,this.amplitude_,this.weight_,this.isFps_)}pattern(t,r,i){var e,a=r*this.model.scale,s=i*this.model.scale,n=this.model.data.length;for(e=0;e<n;e++)S(t,this.model.data[e],a,s)}grid(t){this.updateGuide();var r,i=this.model.data.length;for(r=0;r<i;r++)v(t,this.model.data[r])}point(t){var r,i=this.model.data.length;for(r=0;r<i;r++)d(t,this.model.data[r])}box(t){t.lineWidth=1,t.beginPath(),t.strokeStyle="#0b90dc",t.rect(this.model.rect.x,this.model.rect.y,this.model.rect.w,this.model.rect.h),t.stroke()}}}]);


================================================
FILE: examples/all.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <title>Leon Sans - All</title>

    <style>
        html, body {
            width: 100%;
            height: 100%;
            overflow: hidden;
            outline: 0;
            margin: 0;
            padding: 0;
            background-color: #f0f0f0;
            cursor: move;
        }
    </style>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.js"></script>
</head>

<body>
    <script src="../dist/leon.js"></script>
    <script src="js/util.js"></script>
    <script>
        let leon, controll;

        function init() {
            generateCanvas();

            controll = {
                align: {},
                box: false,
                grids: false,
                points: false,
                drawing: () => {
                    let i, total = leon.drawing.length;
                    for (i = 0; i < total; i++) {
                        TweenMax.killTweensOf(leon.drawing[i]);
                        TweenMax.fromTo(leon.drawing[i], 2, {
                            value: 0
                        }, {
                            value: 1,
                            ease: Power3.easeOut
                        });
                    }
                }
            };        

            leon = new LeonSans({
                text: 'abcdefghijklmn\nopqrstuvwxyz\nABCDEFGHIJK\nLMNOPQRST\nUVWXYZ\n0123456789\n?!$^&*@#%:;\n(){}[]<>«»~_\n\'"·+=-×÷¿¡,.\nÀÁÂÃÄÅĂĄÆ\nÞßĆĈĊČÇĤÝ\nĎĐÈÉÊËĒĔĖĚ\nĜĞĠĢÙÚÛÜŬ\nŜŞĴÑÌÍÎÏ\nàáâãåäăąæ\nþćĉċčçĥýÿ\nďđèéêëēĕėě\nĝğġģùúûüŭ\nŝşĵñìíîï',
                color: ['#342f2e'],
                size: getSize(90),
                weight: 200,
                tracking: 2,
                leading: 2, 
                align: 'center'
            });

            const gui = new dat.GUI();
             gui.add(leon, 'text');
            gui.add(leon, 'size', 20, 1000);
            gui.add(leon, 'weight', 1, 900);
            gui.add(leon, 'tracking', -3, 10);
            gui.add(leon, 'leading', -8, 10);
            gui.add(controll, 'drawing');
            gui.add(controll, 'box');
            gui.add(controll, 'grids');
            gui.add(controll, 'points');

            requestAnimationFrame(animate);
        }

        function animate(t) {
            requestAnimationFrame(animate);

            ctx.clearRect(0, 0, sw, sh);

            const x = (sw - leon.rect.w) / 2;
            let y = (sh - leon.rect.h) / 2;
            if (y < 0) y = 0;
            leon.position(x + moveX, y + moveY);

            ctx.save();
            if (controll.grids) leon.grid(ctx);
            if (controll.box) leon.box(ctx);
            ctx.restore();

            ctx.save();
            leon.draw(ctx);
            ctx.restore();

            if (controll.points) {
                ctx.save();
                leon.point(ctx);
                ctx.restore();
            }
        }

        window.onload = () => {
            init();
        };
    </script>
</body>

</html>

================================================
FILE: examples/canvas-basic.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <title>Leon Sans - Canvas Basic</title>

    <style>
        html, body {
            width: 100%;
            height: 100%;
            overflow: hidden;
            outline: 0;
            margin: 0;
            padding: 0;
            background-color: #f0f0f0;
            cursor: move;
        }
    </style>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.js"></script>
</head>

<body>
    <script src="../dist/leon.js"></script>
    <script src="js/util.js"></script>
    <script>
        let leon, controll;

        function init() {
            generateCanvas();

            controll = {
                color: {},
                align: {},
                drawing: () => {
                    let i, total = leon.drawing.length;
                    for (i = 0; i < total; i++) {
                        TweenMax.killTweensOf(leon.drawing[i]);
                        TweenMax.fromTo(leon.drawing[i], 1.6, {
                            value: 0
                        }, {
                            delay: i * 0.05,
                            value: 1,
                            ease: Power4.easeOut
                        });
                    }
                }
            };

            leon = new LeonSans({
                text: 'The quick brown\nfox jumps over\nthe lazy dog',
                color: ['#342f2e'],
                size: getSize(120),
                weight: 300
            });

            const gui = new dat.GUI();
            gui.add(leon, 'text');
            gui.add(leon, 'size', 20, 1000);
            gui.add(leon, 'weight', 1, 900);
            gui.add(leon, 'tracking', -3, 10);
            gui.add(leon, 'leading', -8, 10);
            const alignControll = gui.add(controll, 'align', [ 'left', 'center', 'right'] );
            gui.add(leon, 'maxWidth', 0, 2000);
            gui.add(leon, 'breakWord');
            gui.add(controll, 'drawing');
            const colorControll = gui.add(controll, 'color', [ 'black', 'white', 'yellow', 'red - blue', 'mixed'] );

            alignControll.onChange((value) => {
                leon.align = value;
            });
            alignControll.setValue('left');

            colorControll.onChange((value) => {
                if (value == 'black') {
                    document.body.style.backgroundColor = '#f0f0f0';
                    leon.color = ['#342f2e'];
                } else if (value == 'white') {
                    document.body.style.backgroundColor = '#000000';
                    leon.color = ['#ffffff'];
                } else if (value == 'yellow') {
                    document.body.style.backgroundColor = '#57c4e2';
                    leon.color = ['#ffd93c'];
                } else if (value == 'red - blue') {
                    document.body.style.backgroundColor = '#ffffff';
                    leon.color = [['#ff94a7', '#1c7dd1']];
                } else if (value == 'mixed') {
                    document.body.style.backgroundColor = '#ffffff';
                    leon.color = ['#ff5892', '#7bc92f', ['#3eda4e', '#f4bf14', '#fa314c', '#074aee'], '#ffd93c', '#c0008b'];
                }
            });
            colorControll.setValue('black');
            
            requestAnimationFrame(animate);
        }

        function animate(t) {
            requestAnimationFrame(animate);

            ctx.clearRect(0, 0, sw, sh);

            const x = (sw - leon.rect.w) / 2;
            const y = (sh - leon.rect.h) / 2;
            leon.position(x + moveX, y + moveY);

            leon.draw(ctx);
        }

        window.onload = () => {
            init();
        };
    </script>
</body>

</html>

================================================
FILE: examples/color-pattern.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <title>LeonSans - Color Pattern</title>

    <style>
        html, body {
            width: 100%;
            height: 100%;
            overflow: hidden;
            outline: 0;
            margin: 0;
            padding: 0;
            background-color: #121212;
            cursor: move;
        }
    </style>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.js"></script>
</head>

<body>
    <script src="../dist/leon.js"></script>
    <script src="js/util.js"></script>
    <script>
        const speed = 10;
        const fps = 1000 / 30;
        const PI2 = 2 * Math.PI;
        let cValue = 0, mode;
        let leon, controll, time;

        function init() {
            generateCanvas();
            
            controll = {
                size: 200,
                pathGap: 0,
                patternWidth: 2,
                visual: {},
                drawing: () => {
                    let i, total = leon.drawing.length;
                    for (i = 0; i < total; i++) {
                        TweenMax.killTweensOf(leon.drawing[i]);
                        TweenMax.fromTo(leon.drawing[i], 2, {
                            value: 0
                        }, {
                            delay: i * 0.1,
                            value: 1,
                            ease: Power4.easeOut
                        });
                    }
                }
            };

            leon = new LeonSans({
                text: 'abcdefg',
                size: getSize(200),
                weight: 500,
                pathGap: -1,
                isPath: true
            });

            const gui = new dat.GUI();
            gui.add(leon, 'text');
            gui.add(leon, 'size', 10, 1000);
            const weightControll = gui.add(controll, 'patternWidth', 1, 100);
            gui.add(controll, 'drawing');
            const visControll = gui.add(controll, 'pathGap', [ '-1', '0'] );

            visControll.onChange((value) => {
                mode = value;
                if (mode == '-1') {
                    weightControll.setValue(40);
                    leon.pathGap = -1;
                    leon.tracking = 1;
                } else if (mode == '0') {
                    weightControll.setValue(40);
                    leon.pathGap = 0;
                    leon.tracking = 1;
                }
            });
            visControll.setValue('-1');

            requestAnimationFrame(animate);
        }

        function update() {
            ctx.clearRect(0, 0, sw, sh);
            ctx.lineWidth = 0.2;
            const w = controll.patternWidth * leon.scale;
            const total = leon.data.length;
            let i, p, pos, no = 0; 
            let d, j, j_total;

            for (i = 0; i < total; i++) {
                d = leon.data[i].paths;
                j_total = Math.round(d.length * leon.drawing[i].value);
                for (j = 0; j < j_total; j++) {
                    pos = d[j];
                    ctx.fillStyle = randomColor(no);
                    ctx.strokeStyle = randomColor(no);
                    ctx.beginPath();
                    ctx.arc(pos.x, pos.y, w, 0, PI2);
                    ctx.stroke();
                    no += 1;
                }
            }

            cValue -= speed;
        }

        function randomColor(no) {
            return "hsl(" + (no + cValue) + ',' + '70%,' + '50%)';
        }

        function animate(t) {
            requestAnimationFrame(animate);

            const x = (sw - leon.rect.w) / 2;
            const y = (sh - leon.rect.h) / 2;
            leon.position(x + moveX, y + moveY);

            if (t) {
                if (!time) time = t;
                if (t - time > fps) {
                    time = t;
                    update();
                }
            }
        }

        window.onload = () => {
            init();
        };
    </script>
</body>

</html>

================================================
FILE: examples/colorful.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <title>Leon Sans - Colorful</title>

    <style>
        html,
        body {
            width: 100%;
            height: 100%;
            overflow: hidden;
            outline: 0;
            margin: 0;
            padding: 0;
            background-color: #f0f0f0;
            cursor: move;
        }
    </style>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.js"></script>
</head>

<body>
    <script src="../dist/leon.js"></script>
    <script src="js/util.js"></script>
    <script>
        let leon, controll;

        function init() {
            generateCanvas();

            controll = {
                color: {},
                roundCap: true,
                multiply: true,
                drawing: () => {
                    let i, total = leon.drawing.length;
                    for (i = 0; i < total; i++) {
                        TweenMax.killTweensOf(leon.drawing[i]);
                        TweenMax.fromTo(leon.drawing[i], 2, {
                            value: 0
                        }, {
                            value: 1,
                            ease: Cubic.easeOut
                        });
                    }
                }
            };

            leon = new LeonSans({
                text: 'The quick brown\nfox jumps over\nthe lazy dog',
                color: ['#000000'],
                size: getSize(120),
                weight: 500
            });

            const gui = new dat.GUI();
            gui.add(leon, 'text');
            gui.add(leon, 'size', 20, 300);
            gui.add(leon, 'weight', 1, 900);
            gui.add(leon, 'tracking', -3, 10);
            gui.add(leon, 'leading', -8, 10);
            gui.add(controll, 'drawing');
            const roundCapControll = gui.add(controll, 'roundCap');
            const multiplyControll = gui.add(controll, 'multiply');

            roundCapControll.onChange((value) => {
                if (value) {
                    ctx.lineCap = "round";
                } else {
                    ctx.lineCap = "butt";
                }
            });

            multiplyControll.onChange((value) => {
                if (value) {
                    ctx.globalCompositeOperation = 'multiply';
                } else {
                    ctx.globalCompositeOperation = 'source-over';
                }
            });
            
            requestAnimationFrame(animate);

            roundCapControll.setValue(true);
            multiplyControll.setValue(true);
        }

        function animate(t) {
            requestAnimationFrame(animate);

            ctx.clearRect(0, 0, sw, sh);

            const x = (sw - leon.rect.w) / 2;
            const y = (sh - leon.rect.h) / 2;
            leon.position(x + moveX, y + moveY);

            leon.drawColorful(ctx);
        }

        window.onload = () => {
            init();
        };
    </script>
</body>

</html>

================================================
FILE: examples/gradient.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <title>Leon Sans - Gradient</title>

    <style>
        html, body {
            width: 100%;
            height: 100%;
            overflow: hidden;
            outline: 0;
            margin: 0;
            padding: 0;
            background-color: #f0f0f0;
            cursor: move;
        }
    </style>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.js"></script>
</head>

<body>
    <script src="../dist/leon.js"></script>
    <script src="js/util.js"></script>
    <script>
        let leon, controll;

        function init() {
            generateCanvas();

            controll = {
                box: false,
                grids: false,
                points: false,
                drawing: () => {
                    let i, total = leon.drawing.length;
                    for (i = 0; i < total; i++) {
                        TweenMax.killTweensOf(leon.drawing[i]);
                        TweenMax.fromTo(leon.drawing[i], 2, {
                            value: 0
                        }, {
                            value: 1,
                            ease: Power4.easeOut
                        });
                    }
                }
            };

            leon = new LeonSans({
                text: 'mug',
                color: [
                    ['#64d3ce', '#2a92ce'],
                    ['#e7c4c4', '#aae898', '#e1ea73', '#ff8974'],
                    ['#fd46aa', '#8ad781']
                ],
                size: getSize(500),
                weight: 140
            });

            const gui = new dat.GUI();
            gui.add(leon, 'text');
            gui.add(leon, 'size', 20, 1000);
            gui.add(leon, 'weight', 1, 900);
            gui.add(controll, 'drawing');
            gui.add(controll, 'box');
            gui.add(controll, 'grids');
            gui.add(controll, 'points');
                        
            requestAnimationFrame(animate);
        }

        function animate(t) {
            requestAnimationFrame(animate);

            ctx.clearRect(0, 0, sw, sh);

            const x = (sw - leon.rect.w) / 2;
            const y = (sh - leon.rect.h) / 2;
            leon.position(x + moveX, y + moveY);

            ctx.save();
            if (controll.grids) leon.grid(ctx);
            if (controll.box) leon.box(ctx);
            ctx.restore();

            ctx.save();
            leon.draw(ctx);
            ctx.restore();

            if (controll.points) {
                ctx.save();
                leon.point(ctx);
                ctx.restore();
            }
        }

        window.onload = () => {
            init();
        };
    </script>
</body>

</html>

================================================
FILE: examples/grid.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <title>Leon Sans - Grids</title>

    <style>
        html, body {
            width: 100%;
            height: 100%;
            overflow: hidden;
            outline: 0;
            margin: 0;
            padding: 0;
            background-color: #f0f0f0;
            cursor: move;
        }
    </style>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.js"></script>
</head>

<body>
    <script src="../dist/leon.js"></script>
    <script src="js/util.js"></script>
    <script>
        let leon, controll;

        function init() {
            generateCanvas();

            controll = {
                box: true,
                grids: true,
                points: true,
            };

            leon = new LeonSans({
                text: 'Ttypog',
                color: ['#342f2e'],
                size: getSize(300),
                weight: 400
            });

            const gui = new dat.GUI();
            gui.add(leon, 'text');
            gui.add(leon, 'size', 100, 1000);
            gui.add(leon, 'weight', 1, 900);
            gui.add(leon, 'tracking', -3, 10);
            gui.add(leon, 'leading', -8, 10);
            gui.add(controll, 'box');
            gui.add(controll, 'grids');
            gui.add(controll, 'points');

            requestAnimationFrame(animate);
        }

        function animate(t) {
            requestAnimationFrame(animate);

            ctx.clearRect(0, 0, sw, sh);

            const x = (sw - leon.rect.w) / 2;
            const y = (sh - leon.rect.h) / 2;
            leon.position(x + moveX, y + moveY);

            ctx.save();
            if (controll.grids) leon.grid(ctx);
            if (controll.box) leon.box(ctx);
            ctx.restore();

            ctx.save();
            leon.draw(ctx);
            ctx.restore();

            if (controll.points) {
                ctx.save();
                leon.point(ctx);
                ctx.restore();
            }
        }

        window.onload = () => {
            init();
        };
    </script>
</body>

</html>

================================================
FILE: examples/index.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <title>Leon Sans examples</title>
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="apple-mobile-web-app-title" content="Leon Sans examples">
    <meta name="description" content="Leon Sans is a geometric sans-serif typeface made with code in 2019 by Jongmin Kim.">
    <meta itemprop="name" content="Leon Sans examples" />
    <meta itemprop="description" content="Leon Sans is a geometric sans-serif typeface made with code in 2019 by Jongmin Kim."/>
    <meta itemprop="image" content="https://leon-kim.com/img/share.png" />
    <meta property="og:site_name" content="Leon Sans examples" />
    <meta property="og:type" content="website" />
    <meta property="og:title" content="Leon Sans examples" />
    <meta property="og:url" content="https://leon-kim.com" />
    <meta property="og:image" content="https://leon-kim.com/img/share.png" />
    <meta property="og:description" content="Leon Sans is a geometric sans-serif typeface made with code in 2019 by Jongmin Kim." />

    <style>
        html,
        body {
            outline: 0;
            margin: 0;
            padding: 0;
            height: 100%;
            color: #ffffff;
            font-size: 14px;
            line-height: 30px;
            -webkit-text-size-adjust: 100%;
            font-family: 'Helvetica', sans-serif;
            font-weight: 400;
        }

        #menu-m {
            position: fixed;
            z-index: 4;
            width: 60px;
            height: 56px;
            left: 0;
            top: 0;
            background-color: #222222;
            cursor: pointer;
        }

        #menu-m > p {
            display: block;
            width: 30px;
            height: 2px;
            background-color: #ffffff;
            position: absolute;
            left: 15px;
        }
        #menu-m > p:nth-child(1) {
            top: 5px;
        }
        #menu-m > p:nth-child(2) {
            top: 12px;
        }
        #menu-m > p:nth-child(3) {
            top: 19px;
        }

        #menu-bg {
            position: fixed;
            z-index: 2;
            width: 100%;
            height: 100%;
            left: 0;
            top: 0;
            background-color:rgba(0,0,0,0.3);
            display: none;
        }

        #menu {
            position: fixed;
            z-index: 6;
            left: 0px;
            width: 170px;
            height: 100%;
            overflow-y: auto;
            overflow-x: hidden;
            background-color: #222222;
        }
        #menu.show {
            transform: translate(170px, 0);
        }

        #header {
            margin: 0;
        }

        #version {
            font-size: 9px;
            line-height: 9px;
            color: rgba(255,255,255,0.5);
            padding: 0 0 0 20px;
        }

        #list {
            margin: -10px 0 20px 0;
        }

        h2 {
            font-size: 18px;
            font-weight: 400;
            margin: 40px 0 6px 0;
            padding: 0 0 0 20px;
        }

        h2 > a {
            font-size: 12px;
        }
        .item {
            padding: 0 0 0 20px;
            display: block;
        }

        .item:hover {
            opacity: 1;
            background-color: #000;
        }

        .item.selected {
            opacity: 1;
            background-color: #000;
        }

        a {
            color: #ffffff;
            opacity: 0.6;
            text-decoration: none;
        }

        #iframe {
            position: absolute;
            border: 0px;
            right: 0;
            right: 0;
            width: calc(100% - 170px);
            height: 100%;
            overflow: auto;
        }

        @media (max-width: 600px) {
            #iframe {
                width: 100%;
            }
            #menu {
                left: -170px;
            }
        }
    </style>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
    <script src="../dist/leon.js"></script>
</head>

<body>
    <div id="menu-m">
        <p></p>
        <p></p>
        <p></p>
    </div>
    <div id="menu-bg"></div>
    <div id="menu">
        <canvas id="header"></canvas>
        <div id="version">VERSION 1.5</div>
        <div id="list">
            <h2>Canvas</h2>
            <a class="item" href="all.html" target="iframe">all</a>
            <a class="item" href="canvas-basic.html" target="iframe">basic</a>
            <a class="item" href="gradient.html" target="iframe">gradient</a>
            <a class="item" href="grid.html" target="iframe">grid</a>
            <a class="item" href="pattern.html" target="iframe">pattern</a>
            <a class="item" href="wave.html" target="iframe">wave</a>
            <a class="item" href="colorful.html" target="iframe">colorful</a>
            <a class="item" href="color-pattern.html" target="iframe">color pattern</a>
            <h2>WebGL <a href="https://www.pixijs.com/" target="_blank">(PIXI.js)</a></h2>
            <a class="item" href="webgl-basic-pixi.html" target="iframe">basic</a>
            <a class="item" href="metaball-pixi.html" target="iframe">metaball</a>
            <a class="item" href="morphing-pixi.html" target="iframe">morphing</a>
            <a class="item" href="plants-pixi.html" target="iframe">plants</a>
            <a class="item" href="mask-tiling-pixi.html" target="iframe">mask + tiling</a>
        </div>
    </div>
    <iframe id="iframe" name="iframe" allowfullscreen="" allowvr="" onmousewheel=""></iframe>

    <script>
        window.onload = () => {

            let isShow = false;
            const menuM = document.getElementById('menu-m');
            const menuBg = document.getElementById('menu-bg');
            const menu = document.getElementById('menu');
            menuM.addEventListener( 'click', (event) => {
                onClickMenu();
            });
            menuBg.addEventListener( 'click', (event) => {
                onClickMenu();
            });

            function onClickMenu() {
                isShow = !isShow;
                if (isShow) {
                    menuBg.style.display = 'block';
                    menu.className = 'show';
                } else {
                    menuBg.style.display = 'none';
                    menu.className = '';
                }
            }


            const sw = 170;
            const sh = 50;
            const iframe = document.getElementById('iframe');
            const canvas = document.getElementById('header');
            const ctx = canvas.getContext("2d");
            canvas.width = sw * 2;
            canvas.height = sh * 2;
            canvas.style.width = sw + 'px'
            canvas.style.height = sh + 'px'
            ctx.scale(2, 2);

            const leon = new LeonSans({
                text: 'Leon Sans',
                color: ['#ffffff'],
                size: 26,
                weight: 300
            });
            leon.on('update', (model) => {  
                ctx.clearRect(0, 0, sw, sh);
                leon.position(20, 20);
                leon.draw(ctx);
            });

            const list = document.getElementById('list');
            const arr = list.getElementsByClassName('item');
            const total = arr.length;
            const links = {};
            let cur = null;
            let i;
            for (i = 0; i < total; i++) {
                const vv = arr[i].href.split('/');
                const name = vv[vv.length - 1].split('.')[0];
                links[name] = arr[i];

                arr[i].addEventListener( 'click', (event) => {
                    const vv = event.target.href.split('/');
                    const name = vv[vv.length - 1].split('.')[0];
                    checkMenu(name);
                });
            }

            if (window.location.hash !== '') {
                const name = window.location.hash.substring(1);
                const url = name + '.html';
                iframe.src = url;
                checkMenu(name);
            } else {
                const name = 'all';
                iframe.src = name + '.html';
                checkMenu(name);
            }
            
            function checkMenu(name) {
                if (cur) links[cur].classList.remove('selected');
                cur = name;
                links[cur].classList.add('selected');
                window.location.hash = name;
                iframe.focus();
            };
        };
    </script>
</body>

</html>

================================================
FILE: examples/js/util.js
================================================
const pixelRatio = 2;
let isDown = false, moveX = 0, moveY = 0, offsetX = 0, offsetY = 0;
let canvas, ctx;
let renderer, stage;
let sw = document.body.clientWidth;
let sh = document.body.clientHeight;

function generateCanvas() {
    canvas = document.createElement('canvas');
    document.body.appendChild(canvas);
    ctx = canvas.getContext("2d");

    window.addEventListener('resize', canvasResize, false);
    canvasResize();

    moveEvent(canvas);
}

function canvasResize() {
    sw = document.body.clientWidth;
    sh = document.body.clientHeight;

    canvas.width = sw * pixelRatio;
    canvas.height = sh * pixelRatio;
    canvas.style.width = sw + 'px';
    canvas.style.height = sh + 'px';
    ctx.scale(pixelRatio, pixelRatio);
}

function generatePixi(bgcolor) {
    renderer = new PIXI.Renderer({
        width: sw,
        height: sh,
        antialias: true,
        transparent: false,
        autoDensity: true,
        resolution: pixelRatio,//window.devicePixelRatio > 1 ? 2 : 1,
        powerPreference: "high-performance",
        backgroundColor: bgcolor
    });
    document.body.appendChild(renderer.view);
    stage = new PIXI.Container();

    window.addEventListener('resize', pixiResize, false);
    pixiResize();

    moveEvent(renderer.view);
}

function pixiResize() {
    sw = document.body.clientWidth;
    sh = document.body.clientHeight;

    renderer.resize(sw, sh);
}

function moveEvent(canvas) {
    const hammer = new Hammer(canvas);
    hammer.add(new Hammer.Pan({direction: Hammer.DIRECTION_ALL, threshold: 0}));
    hammer.on("pan", (e) => {                
        moveX = e.deltaX + offsetX;
        moveY = e.deltaY + offsetY;
        if (e.isFinal) {
            offsetX = moveX;
            offsetY = moveY;
        }
    });
}

function getSize(size) {
    let ratio = Math.sqrt(sw * sw + sh * sh) / 1800;
    if (ratio > 1) ratio = 1;
    else if (ratio < 0.5) ratio = 0.5;
    return size * ratio;
}

================================================
FILE: examples/mask-tiling-pixi.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <title>Leon Sans - MASK + Tiling PIXI</title>

    <style>
        html,
        body {
            width: 100%;
            height: 100%;
            overflow: hidden;
            outline: 0;
            margin: 0;
            padding: 0;
            cursor: move;
        }
    </style>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.0.4/pixi.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.js"></script>
</head>

<body>
    <script src="../dist/leon.js"></script>
    <script src="js/util.js"></script>
    <script>
        let container, loader, textures = [];
        let tiling = [], cur = -1;
        let leon, controll;

        function init() {
            generatePixi(0x000000);

            container = new PIXI.Container();
            stage.addChild(container);

            loader = new PIXI.Loader();
            loader.add('tile1', 'data/tile1.png')
            .add('tile2', 'data/tile2.png')
            .add('tile3', 'data/tile3.png')
            .add('tile4', 'data/tile4.png')
            .add('tile5', 'data/tile5.png')
            .add('tile6', 'data/tile6.png');

            loader.load((loader, resources) => {
                textures.push(resources.tile1.texture);
                textures.push(resources.tile2.texture);
                textures.push(resources.tile3.texture);
                textures.push(resources.tile4.texture);
                textures.push(resources.tile5.texture);
                textures.push(resources.tile6.texture);
                textures = shuffle(textures);

                loaded();
            });
        }


        function loaded() {
            controll = {
                align: {},
            };

            leon = new LeonSans({
                text: '012\n345',
                size: getSize(400),
                weight: 900,
                tracking: 1,
                leading: -1,
                align: 'center'
            });
            leon.on('update', (model) => {  
                update();
            });

            const gui = new dat.GUI();
            gui.add(leon, 'text');
            gui.add(leon, 'size', 10, 1000);
            gui.add(leon, 'weight', 1, 900);

            requestAnimationFrame(animate);
        }


        function update() {
            while(container.children[0]) { 
                container.removeChild(container.children[0]);
            }
            
            const total = leon.data.length;
            let i, d, color, line, pos;
            let j, j_total, lineW = leon.lineWidth;

            let graphics, tilingSprite;

            tiling = [];

            for (i = 0; i < total; i++) {
                d = leon.data[i];

                graphics = new PIXI.Graphics();
                container.addChild(graphics);

                tilingSprite = new PIXI.TilingSprite(
                    textures[getNum()],
                    d.rect.w * 2,
                    d.rect.h * 2
                );
                tilingSprite.x = d.rect.x - d.rect.w /2;
                tilingSprite.y = d.rect.y - d.rect.h / 2;
                tilingSprite.tileScale.x = tilingSprite.tileScale.y = leon.scale * 0.5;
                
                container.addChild(tilingSprite);

                tilingSprite.mask = graphics;
                tiling.push({
                    item: tilingSprite,
                    x: (Math.random() * 2 + 1 - 2) * 2,
                    y: (Math.random() * 2 + 1 - 2) * 2
                });

                j_total = d.lines.length;
                for (j = 0; j < j_total; j++) {
                    line = d.lines[j];
                    pos = d.lines[j].pos;

                    if (pos.type == 'a') {
                        graphics.lineStyle(0, color, 0);
                        graphics.beginFill(color);
                        graphics.drawCircle(pos.x, pos.y, pos.radius);
                        graphics.endFill();
                    } else if (pos.type == 'm') {
                        graphics.lineStyle(lineW, color, 1);
                        graphics.moveTo(pos.x, pos.y);
                    } else if (pos.type == 'l') {
                        graphics.lineTo(pos.x, pos.y);
                    } else if (pos.type == 'b') {
                        graphics.bezierCurveTo(pos.x, pos.y, pos.x2, pos.y2, pos.x3, pos.y3);
                    }
                    if (line.closePath) {
                        graphics.closePath();
                    }
                }
                
            }
        }

        function animate(t) {
            requestAnimationFrame(animate);

            const x = (sw - leon.rect.w) / 2;
            const y = (sh - leon.rect.h) / 2;
            leon.position(x + moveX, y + moveY);

            const total = tiling.length;
            let i, p;
            for (i = 0; i < total; i++) {
                p = tiling[i];
                p.item.tilePosition.x += p.x * leon.scale;
                p.item.tilePosition.y += p.y * leon.scale;
            }

            renderer.render(stage);
        }

        function getNum() {
            cur += 1;
            if (cur == textures.length) {
                cur = 0;
            }
            return cur;
        }

        function shuffle(oldArray) {
            var newArray = oldArray.slice(),
                len = newArray.length,
                i = len, p, t;
            while (i--) {
                p = (Math.random()*len) | 0;
                t = newArray[i];
                newArray[i] = newArray[p];
                newArray[p] = t;
            }
            return newArray;
        }

        window.onload = () => {
            init();
        };
    </script>
</body>

</html>

================================================
FILE: examples/metaball-pixi.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <title>Leon Sans - Metaball PIXI</title>
    <style>
        html,
        body {
            width: 100%;
            height: 100%;
            overflow: hidden;
            outline: 0;
            margin: 0;
            padding: 0;
            cursor: move;
        }
    </style>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.0.4/pixi.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.js"></script>
</head>

<body>
    <script src="../dist/leon.js"></script>
    <script src="js/util.js"></script>
    <script>
        let container, texture, particleCon;
        let leon, controll, weightControll;
        const particleTotal = 10000;
        let particles = [];
        
        function init() {
            generatePixi(0x000000);

            texture = PIXI.Texture.from('data/drop-alpha.png');
            particleCon = new PIXI.ParticleContainer(particleTotal, {
                vertices: false,
                scale: true,
                position: true,
                rotation: false,
                uvs: false,
                alpha: false
            });
            stage.addChild(particleCon);

            let p, i;
            for (i = 0; i < particleTotal; i++) {
                p = new PIXI.Sprite(texture);
                p.x = sw / 2;
                p.y = sh / 2;
                p.anchor.set(0.5);
                p.scale.x = p.scale.y = 0;
                particleCon.addChild(p);
                particles.push(p);
            }

            const blurFilter = new PIXI.filters.BlurFilter();
            blurFilter.blur = 10;
            blurFilter.autoFit = true;

            const fragSource = [
                    'precision mediump float;',
                    'varying vec2 vTextureCoord;',
                    'uniform sampler2D uSampler;',
                    'uniform float threshold;',
                    'uniform float mr;',
                    'uniform float mg;',
                    'uniform float mb;',
                    'void main(void)',
                    '{',
                    '    vec4 color = texture2D(uSampler, vTextureCoord);',
                    '    vec3 mcolor = vec3(mr, mg, mb);',
                    '    if (color.a > threshold) {',
                    '       gl_FragColor = vec4(mcolor, 1.0);',
                    '    } else {',
                    '       gl_FragColor = vec4(vec3(0.0), 0.0);',
                    '    }',
                    '}'
                ].join('\n');

            const uniformsData = {
                threshold: 0.5,
                mr: 255.0/255.0,
                mg: 255.0/255.0,
                mb: 255.0/255.0,
            };

            const thresholdFilter = new PIXI.Filter(null, fragSource, uniformsData);
            stage.filters = [blurFilter, thresholdFilter];
            stage.filterArea = renderer.screen;

            controll = {
                weight: 3,
                color: {},
                outline: true,
                drawing: () => {
                    let i;
                    for (i = 0; i < particleTotal; i++) {
                        TweenMax.killTweensOf(particles[i].scale);
                        TweenMax.set(particles[i].scale, {
                            x: 0,
                            y: 0
                        });
                        TweenMax.to(particles[i].scale, 3, {
                            delay: 0.001 * i,
                            x: particles[i].saveScale,
                            y: particles[i].saveScale,
                            ease: Circ.easeOut
                        });
                    }
                }
            };

            leon = new LeonSans({
                text: 'TOP\n678',
                size: getSize(400),
                weight: 700,
                pathGap: -1,
                isPath: true,
                tracking: 0
            });
            leon.on('update', (model) => {  
                update();
            });
            
            const gui = new dat.GUI();
            gui.add(leon, 'text');
            const sizeControll = gui.add(leon, 'size', 200, 1000);
            gui.add(leon, 'tracking', -6, 10);
            gui.add(leon, 'leading', -8, 10);
            weightControll = gui.add(controll, 'weight', 1, 9);
            gui.add(controll, 'drawing');
            const colorControll = gui.add(controll, 'color', [ 'white', 'black', 'red'] );

            sizeControll.onChange((value) => {
                sizeWeight();
            });

            weightControll.onChange((value) => {
                update();
            });

            colorControll.onChange((value) => {
                if (value == 'white') {
                    renderer.backgroundColor = 0x000000;
                    uniformsData.mr = 255.0/255.0;
                    uniformsData.mg = 255.0/255.0;
                    uniformsData.mb = 255.0/255.0;
                } else if (value == 'black') {
                    renderer.backgroundColor = 0xffffff;
                    uniformsData.mr = 0.0/255.0;
                    uniformsData.mg = 0.0/255.0;
                    uniformsData.mb = 0.0/255.0;
                }  else if (value == 'red') {
                    renderer.backgroundColor = 0xe4c143;
                    uniformsData.mr = 244.0/255.0;
                    uniformsData.mg = 46.0/255.0;
                    uniformsData.mb = 33.0/255.0;
                } 
            });
            colorControll.setValue('white');

            requestAnimationFrame(animate);

            sizeWeight();

            TweenMax.delayedCall(0.1, () => {
                controll.drawing();
            });            
        }

        function sizeWeight() {
            let w;
            if (leon.size > 400) {
                w = (1.5 - 3) / (1000 - 400) * (leon.size - 400) + 3;
            } else {
                w = (3 - 6) / (400 - 200) * (leon.size - 200) + 6;
            }
            weightControll.setValue(w);
        }

        function update() {
            const total = leon.paths.length;
            const sw2 = sw / 2;
            const sh2 = sh / 2;
            let i, p, pos, scale; 
            for (i = 0; i < particleTotal; i++) {
                p = particles[i];
                TweenMax.killTweensOf(p.scale);
                if (i < total) {
                    pos = leon.paths[i];
                    if (pos.type == 'a') {
                        scale = controll.weight * 0.025* leon.scale;
                    } else {
                        scale = controll.weight * 0.01* leon.scale;
                    }
                    p.saveScale = scale;
                    p.x = pos.x;
                    p.y = pos.y;
                    p.scale.x = p.scale.y = scale;
                } else {
                    p.saveScale = 0;
                    p.x = -1000;
                    p.y = -1000;
                    p.scale.x = p.scale.y = 0;                   
                }
            }        
        }

        function animate(t) {
            requestAnimationFrame(animate);

            const x = (sw - leon.rect.w) / 2;
            const y = (sh - leon.rect.h) / 2;
            leon.position(x + moveX, y + moveY);

            renderer.render(stage);
        }

        window.onload = () => {
            init();
        };
    </script>
</body>

</html>

================================================
FILE: examples/morphing-pixi.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <title>Leon Sans - Morphing PIXI</title>

    <style>
        html,
        body {
            width: 100%;
            height: 100%;
            overflow: hidden;
            outline: 0;
            margin: 0;
            padding: 0;
            cursor: move;
        }
    </style>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.0.4/pixi.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/pixi-filters@latest/dist/pixi-filters.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.js"></script>
</head>

<body>
    <script src="../dist/leon.js"></script>
    <script src="js/util.js"></script>
    <script>
        let container, texture, particleCon;
        let leon, controll;
        const particleTotal = 5000;
        let particles = [];
        let myText = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789?!$^&*(){}[]<>~:;,.\'"+=-_@#%'.split('');
        const textTotal = myText.length;
        let curText = -1;
        let DELAY_TIME = 0.8;

        function init() {
            generatePixi(0xfec82e);

            myText = shuffle(myText);

            texture = PIXI.Texture.from('data/drop-alpha.png');

            particleCon = new PIXI.ParticleContainer(particleTotal, {
                vertices: false,
                scale: true,
                position: true,
                rotation: false,
                uvs: false,
                alpha: false
            });
            stage.addChild(particleCon);

            let p, i;
            for (i = 0; i < particleTotal; i++) {
                p = new PIXI.Sprite(texture);
                p.x = sw / 2;
                p.y = sh / 2;
                p.anchor.set(0.5);
                p.scale.x = p.scale.y = 0;
                particleCon.addChild(p);
                particles.push(p);
            }

            const blurFilter = new PIXI.filters.BlurFilter();
            blurFilter.blur = 10;
            blurFilter.autoFit = true;

            const fragSource = [
                    'precision mediump float;',
                    'varying vec2 vTextureCoord;',
                    'uniform sampler2D uSampler;',
                    'uniform float threshold;',
                    'uniform float mr;',
                    'uniform float mg;',
                    'uniform float mb;',
                    'void main(void)',
                    '{',
                    '    vec4 color = texture2D(uSampler, vTextureCoord);',
                    '    vec3 mcolor = vec3(mr, mg, mb);',
                    '    if (color.a > threshold) {',
                    '       gl_FragColor = vec4(mcolor, 1.0);',
                    '    } else {',
                    '       gl_FragColor = vec4(vec3(0.0), 0.0);',
                    '    }',
                    '}'
                ].join('\n');

            const uniformsData = {
                threshold: 0.5,
                mr: 255.0/255.0,
                mg: 255.0/255.0,
                mb: 255.0/255.0,
            };

            const thresholdFilter = new PIXI.Filter(null, fragSource, uniformsData );

            const outlineFilterBlue = new PIXI.filters.OutlineFilter(1, 0x000000);

            stage.filters = [blurFilter, thresholdFilter, outlineFilterBlue];
            stage.filterArea = renderer.screen;

            controll = {
                weight: 6,
                outline: true
            };

            leon = new LeonSans({
                text: '',
                size: 600,
                weight: 700,
                pathGap: -1,
                isPath: true
            });
            leon.on('update', (data) => {  
                update(data);
            });
            
            const gui = new dat.GUI();
            gui.add(leon, 'size', 400, 1000);
            gui.add(controll, 'weight', 3, 9);
            const otControll = gui.add(controll, 'outline');
            otControll.onChange((value) => {
                if (value) {
                    stage.filters = [blurFilter, thresholdFilter, outlineFilterBlue];
                } else {
                    stage.filters = [blurFilter, thresholdFilter];
                }
            });

            requestAnimationFrame(animate);

            showText();
        }

        function nextText() {
            TweenMax.killDelayedCallsTo(showText);
            TweenMax.delayedCall(DELAY_TIME, showText);
        }

        function showText() {
            curText += 1;
            if (curText == textTotal) curText = 0;
            leon.text = myText[curText];
            nextText();
        }

        function shuffle(oldArray) {
            var newArray = oldArray.slice(),
                len = newArray.length,
                i = len, p, t;
            while (i--) {
                p = (Math.random()*len) | 0;
                t = newArray[i];
                newArray[i] = newArray[p];
                newArray[p] = t;
            }
            return newArray;
        }

        function update(model) {
            const total = model.paths.length;
            const sw2 = sw / 2;
            const sh2 = sh / 2;
            let i, p, pos, scale; 
            for (i = 0; i < particleTotal; i++) {
                p = particles[i];
                TweenMax.killTweensOf(p);
                if (i < total) {
                    pos = model.paths[i];
                    if (pos.type == 'a') {
                        scale = controll.weight * 0.02* leon.scale;
                    } else {
                        scale = controll.weight * 0.01* leon.scale;
                    }
                    TweenMax.to(p, 0.4, {
                        x: sw2, 
                        y: sh2,
                        ease: Sine.easeIn
                    });
                    TweenMax.to(p, 0.5, {
                        delay: 0.3,
                        x: pos.x, 
                        y: pos.y,
                        ease: Expo.easeOut
                    });
                    TweenMax.to(p.scale, 0.5, {
                        delay: 0.3,
                        x: scale, 
                        y: scale,
                        ease: Expo.easeOut
                    });
                } else {
                    TweenMax.to(p, 0.3, {
                        x: sw2, 
                        y: sh2,
                        ease: Sine.easeIn
                    });
                    TweenMax.to(p.scale, 0.3, {
                        x: 0, 
                        y: 0,
                        ease: Sine.easeIn
                    });
                   
                }
            }
        }

        function animate(t) {
            requestAnimationFrame(animate);

            const x = (sw - leon.rect.w) / 2;
            const y = (sh - leon.rect.h) / 2;
            leon.position(x, y);

            renderer.render(stage);
        }

        window.onload = () => {
            init();
        };

    </script>
</body>

</html>

================================================
FILE: examples/pattern.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <title>Leon Sans - Pattern</title>

    <style>
        html, body {
            width: 100%;
            height: 100%;
            overflow: hidden;
            outline: 0;
            margin: 0;
            padding: 0;
            background-color: #502c8d;
            cursor: move;
        }
    </style>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.js"></script>
</head>

<body>
    <script src="../dist/leon.js"></script>
    <script src="js/util.js"></script>
    <script>
        let leon, controll;

        function init() {
            generateCanvas();

            controll = {
                color: {},
                align: {},
                patternWidth: 40,
                patternHeight: 10,
                drawing: () => {
                    let i, total = leon.drawing.length;
                    for (i = 0; i < total; i++) {
                        TweenMax.killTweensOf(leon.drawing[i]);
                        TweenMax.fromTo(leon.drawing[i], 2, {
                            value: 0
                        }, {
                            delay: i * 0.05,
                            value: 1,
                            ease: Power4.easeOut
                        });
                    }
                }
            };

            leon = new LeonSans({
                text: 'The quick brown\nfox jumps over\nthe lazy dog',
                size: getSize(120),
                weight: 400,
                isPath: true,
                pathGap: 0.2
            });

            const gui = new dat.GUI();
            gui.add(leon, 'text');
            gui.add(leon, 'size', 20, 300);
            gui.add(leon, 'pathGap', 0, 1);
            gui.add(controll, 'patternWidth', 1, 200);
            gui.add(controll, 'patternHeight', 1, 100);
            gui.add(controll, 'drawing');

            requestAnimationFrame(animate);
        }

        function animate(t) {
            requestAnimationFrame(animate);

            ctx.clearRect(0, 0, sw, sh);

            const x = (sw - leon.rect.w) / 2;
            const y = (sh - leon.rect.h) / 2;
            leon.position(x + moveX, y + moveY);

            leon.pattern(ctx, controll.patternWidth, controll.patternHeight);
        }

        window.onload = () => {
            init();
        };
    </script>
</body>

</html>

================================================
FILE: examples/plants-pixi.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <title>Leon Sans - Plants PIXI</title>
    <style>
        html,
        body {
            width: 100%;
            height: 100%;
            overflow: hidden;
            outline: 0;
            margin: 0;
            padding: 0;
            cursor: move;
        }
    </style>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.0.4/pixi.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.js"></script>
</head>

<body>
    <script src="../dist/leon.js"></script>
    <script src="js/util.js"></script>
    <script>
        let container, loader, resource;
        let leafs = [], flowers = [];
        let leon, controll;
        const tintLeaf = [
            0xFFFFFF,
            0xFFFF00,
            0xccff00,
            0x00ff1e,
            0xffb300,
            0xa2ff00
        ];
        const tintFlower = [
            0xFFFFFF,
            0xffeea1,
            0xffa1a1,
            0xeca1ff,
            0xa1dbff,
            0xffa1d6,
            0xd2ffa1,
        ];

        function init() {
            generatePixi(0xf0f0f0);

            container = new PIXI.Container();
            stage.addChild(container);

            loader = new PIXI.Loader();
            loader.add('branch_long', 'data/branch_long.png')
            .add('branch_circle', 'data/branch_circle.png')
            .add('flower1', 'data/flower1.png')
            .add('flower2', 'data/flower2.png')
            .add('flower3', 'data/flower3.png')
            .add('leaf1', 'data/leaf1.png')
            .add('leaf2', 'data/leaf2.png');

            loader.load((loader, resources) => {
                resource = resources;

                flowers.push('flower1');
                flowers.push('flower2');
                flowers.push('flower3');

                leafs.push('leaf1');
                leafs.push('leaf1');
                leafs.push('leaf2');

                loaded();
            });            
        }

        function loaded() {
            controll = {
                color: {},
            };

            leon = new LeonSans({
                text: 'ONE',
                size: getSize(500),
                weight: 1,
                pathGap: -1,
                tracking: 0,
                isPath: true
            });
            leon.on('update', (data) => {  
                update(data);
            });

            const gui = new dat.GUI();
            gui.add(leon, 'text');
            gui.add(leon, 'tracking', -3, 10);

            window.addEventListener('resize', resize, false);
            requestAnimationFrame(animate);
        }

        function resize() {
            sw = document.body.clientWidth;
            sh = document.body.clientHeight;

            renderer.resize(sw, sh);
        }

        function update() {
            while(container.children[0]) { 
                TweenMax.killTweensOf(container.children[0]);
                container.removeChild(container.children[0]);
            }

            let points, saveFlowers = [], saveLeafs = [];
            let total = leon.model.data.length;
            let i, j, j_total, d, pos;
            for (i = 0; i < total; i++) {
                d = leon.model.data[i];
                j_total = d.paths.length;
                points = [];
                for (j = 0; j < j_total; j++) {
                    pos = d.paths[j];

                    if (pos.type == 'a') {
                        const dot = new PIXI.Sprite(resource.branch_circle.texture);
                        dot.anchor.set(0.5);
                        dot.x = pos.x;
                        dot.y = pos.y;
                        const scale = 0.15 * leon.scale;
                        dot.scale.x = dot.scale.y = scale;
                        container.addChild(dot);  
                    } else if (pos.start == 1) {
                        if (points.length > 0) {
                            addBranch(points);
                        }
                        points = [];
                        points.push(new PIXI.Point(pos.x, pos.y));
                    } else { 
                        points.push(new PIXI.Point(pos.x, pos.y));
                    }

                    if (Math.random() > 0.99) {
                        saveFlowers.push(pos);
                    }

                    if (Math.random() > 0.84) {
                        saveLeafs.push(pos);
                    }
                }

                if (points.length > 0) {
                    addBranch(points);
                }
            }

            function addBranch(points) {
                const branch = new PIXI.SimpleRope(resource.branch_long.texture, points);
                container.addChild(branch);  
            }

            total = saveLeafs.length;
            for (i = 0; i < total; i++) {
                pos = saveLeafs[i];
                d = leafs[Math.floor(0.5 + (Math.random()*(leafs.length-1)))];
                const leaf = new PIXI.Sprite(resource[d].texture);
                leaf.anchor.set(0.5, 1);
                leaf.x = pos.x;
                leaf.y = pos.y;
                const scale = 0.1 * (0.2 + Math.random() * (1.2 - 0.2)) * leon.scale;
                leaf.scale.x = leaf.scale.y = 0;
                leaf.rotation = (pos.rotation + (90 * (Math.PI / 180)) * (Math.random() > 0.5 ? 1 : -1)) + (Math.random() * (Math.PI / 2) - (Math.PI / 4));
                container.addChild(leaf);
                leaf.tint = tintLeaf[Math.floor(0.5 + (Math.random()*(tintLeaf.length-1)))];     
                TweenMax.to(leaf.scale, 0.8, {
                    delay: 0.004 * i,
                    x: scale,
                    y: scale,
                    ease: Power3.easeOut
                });
            }

            total = saveFlowers.length;
            for (i = 0; i < total; i++) {
                pos = saveFlowers[i];
                d = flowers[Math.floor(0.5 + (Math.random()*(flowers.length-1)))];
                const flower = new PIXI.Sprite(resource[d].texture);
                flower.anchor.set(0.5);
                flower.x = pos.x;
                flower.y = pos.y;
                const scale = 0.04 * (0.6 + Math.random() * (1.2 - 0.6)) * leon.scale;
                flower.scale.x = flower.scale.y = 0;
                flower.rotation = Math.random() * Math.PI * 2;
                container.addChild(flower);
                flower.tint = tintFlower[Math.floor(0.5 + (Math.random()*(tintFlower.length-1)))];    
                TweenMax.to(flower.scale, 0.8, {
                    delay: 0.05 * i + 0.6,
                    x: scale,
                    y: scale,
                    ease: Power3.easeOut
                });
            }
        }

        function animate(t) {
            requestAnimationFrame(animate);

            const x = (sw - leon.rect.w) / 2;
            const y = (sh - leon.rect.h) / 2;
            leon.position(x + moveX, y + moveY);

            renderer.render(stage);
        }

        window.onload = () => {
            init();
        };
    </script>
</body>

</html>

================================================
FILE: examples/wave.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <title>Leon Sans - Wave</title>

    <style>
        html, body {
            width: 100%;
            height: 100%;
            overflow: hidden;
            outline: 0;
            margin: 0;
            padding: 0;
            background-color: #000000;
            cursor: move;
        }
    </style>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.js"></script>
</head>

<body>
    <script src="../dist/leon.js"></script>
    <script src="js/util.js"></script>
    <script>
        let leon, controll;

        function init() {
            generateCanvas();

            const controll = {
                color: {},
                align: {},
            };

            leon = new LeonSans({
                text: 'The quick brown\nfox jumps over\nthe lazy dog',
                color: ['#ffffff'],
                size: getSize(120),
                weight: 1,
                isWave: true,
                pathGap: 0.3,
                amplitude: 0.5,
                fps: 30
            });

            const gui = new dat.GUI();
            gui.add(leon, 'text');
            gui.add(leon, 'size', 20, 300);
            gui.add(leon, 'weight', 1, 300);
            gui.add(leon, 'pathGap', 0, 1);
            gui.add(leon, 'amplitude', 0, 1);
            gui.add(leon, 'fps', 10, 60);

            requestAnimationFrame(animate);
        }

        function animate(t) {
            requestAnimationFrame(animate);

            ctx.clearRect(0, 0, sw, sh);

            const x = (sw - leon.rect.w) / 2;
            const y = (sh - leon.rect.h) / 2;
            leon.position(x + moveX, y + moveY);

            leon.wave(ctx, t);
        }

        window.onload = () => {
            init();
        };
    </script>
</body>

</html>

================================================
FILE: examples/webgl-basic-pixi.html
================================================
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
    <title>Leon Sans - WebGL Basic PIXI</title>

    <style>
        html, body {
            width: 100%;
            height: 100%;
            overflow: hidden;
            outline: 0;
            margin: 0;
            padding: 0;
            cursor: move;
        }
    </style>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.0.4/pixi.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.6/dat.gui.js"></script>
</head>

<body>
    <script src="../dist/leon.js"></script>
    <script src="js/util.js"></script>
    <script>
        let graphics;
        let leon, controll;

        function init() {
            generatePixi(0x000000);

            graphics = new PIXI.Graphics();
            stage.addChild(graphics);

            controll = {
                color: {},
                align: {},
                drawing: () => {
                    leon.updateDrawingPaths();

                    let i, total = leon.drawing.length;
                    for (i = 0; i < total; i++) {
                        TweenMax.killTweensOf(leon.drawing[i]);
                        TweenMax.fromTo(leon.drawing[i], 1.6, {
                            value: 0
                        }, {
                            delay: i * 0.05,
                            value: 1,
                            ease: Power4.easeOut
                        });
                    }
                },
            };

            leon = new LeonSans({
                text: 'The quick brown\nfox jumps over\nthe lazy dog',
                color: [0xffffff],
                size: getSize(120),
                weight: 300
            });

            const gui = new dat.GUI();
            gui.add(leon, 'text');
            gui.add(leon, 'size', 10, 2000);
            gui.add(leon, 'weight', 1, 900);
            gui.add(leon, 'tracking', -3, 10);
            gui.add(leon, 'leading', -8, 10);
            const alignControll = gui.add(controll, 'align', [ 'left', 'center', 'right'] );
            gui.add(leon, 'maxWidth', 0, 2000);
            gui.add(leon, 'breakWord');
            gui.add(controll, 'drawing');
            const colorControll = gui.add(controll, 'color', [ 'black', 'white', 'yellow' , 'mixed'] );

            alignControll.onChange((value) => {
                leon.align = value;
            });
            alignControll.setValue('left');

            colorControll.onChange((value) => {
                if (value == 'black') {
                    renderer.backgroundColor = 0xf0f0f0;
                    leon.color = [0x342f2e];
                } else if (value == 'white') {
                    renderer.backgroundColor = 0x000000;
                    leon.color = [0xffffff];
                } else if (value == 'yellow') {
                    renderer.backgroundColor = 0x57c4e2;
                    leon.color = [0xffd93c];
                } else if (value == 'mixed') {
                    document.body.style.backgroundColor = '#ffffff';
                    leon.color = [0xff5892, 0xbc92f, 0xffd93c, 0xc0008b];
                }
            });
            colorControll.setValue('white');

            requestAnimationFrame(animate);
        }

        function animate(t) {
            requestAnimationFrame(animate);

            const x = (sw - leon.rect.w) / 2;
            const y = (sh - leon.rect.h) / 2;
            leon.position(x + moveX, y + moveY);

            graphics.clear();
            leon.drawPixi(graphics);

            renderer.render(stage);
        }

        window.onload = () => {
            init();
        };
    </script>
</body>

</html>

================================================
FILE: src/core/align.js
================================================
export function setAlignGapX(sw, tw) {
    return {
        c: (sw - tw) / 2,
        r: sw - tw,
        l: 0
    };
}

export function getAlignGapX(align, alignGapX) {
    if (align == 'center') {
        return alignGapX.c;
    } else if (align == 'right') {
        return alignGapX.r;
    } else {
        return alignGapX.l;
    }
}

================================================
FILE: src/core/dispatcher.js
================================================
export class Dispatcher {
    constructor() {
        this.handlers_ = {
            update: {
                listeners: []
            }
        };
    }

    on(event, callback) {
        if (typeof callback !== 'function') {
            console.error(`The listener callback must be a function, the given type is ${typeof callback}`);
            return false;
        }

        if (typeof event !== 'string') {
            console.error(`The event name must be a string, the given type is ${typeof event}`);
            return false;
        }

        if (this.handlers_[event] === undefined) {
            this.handlers_[event] = {
                listeners: []
            };
        }

        this.handlers_[event].listeners.push(callback);
    }

    off(event, callback) {
        if (this.handlers_[event] === undefined) {
            console.error(`This event: ${event} does not exist`);
            return false;
        }

        this.handlers_[event].listeners = this.handlers_[event].listeners.filter(listener => {
            return listener.toString() !== callback.toString();
        });
    }

    dispatch(event, data) {
        this.handlers_[event].listeners.forEach((listener) => {
            listener(data);
        });
    }
}

================================================
FILE: src/core/group.js
================================================
import {
    getRect
} from './util.js';
import {
    typo
} from '../font/index.js';

export function getTextGroup(text, scale, width, isBreakAll) {
    let group;
    if (text.indexOf('\n') > 0) {
        group = text.split('\n');
    } else if (text.indexOf('\\n') > 0) {
        group = text.split('\\n');
    } else {
        group = [text];
    }
    if (width == 0) return keepAll(group);
    else if (isBreakAll) return breakAll(group, scale, width);
    else return breakWord(group, scale, width);
}

function keepAll(group) {
    const textGroup = [];
    const total = group.length;
    let i;
    for (i = 0; i < total; i++) {
        textGroup[i] = group[i].split('');
    }
    return textGroup;
}

function breakWord(group, scale, width) {
    let g2, g3, t, m_rect,
        tw = 0,
        tw2 = 0,
        i, j, k,
        total, j_total, k_total,
        index = 0;
    const tg = [];
    total = group.length;
    for (i = 0; i < total; i++) {
        g2 = group[i].split(' ');
        tg[index] = [];
        j_total = g2.length;
        for (j = 0; j < j_total; j++) {
            tw2 = 0;
            g3 = g2[j];
            k_total = g3.length;
            for (k = 0; k < k_total; k++) {
                t = typo(g3[k]);
                m_rect = getRect(t, scale);
                tw2 += m_rect.w;
            }
            t = typo(' ');
            m_rect = getRect(t, scale);
            tw2 += m_rect.w;
            tw += tw2;
            if (tw > width) {
                index += 1;
                tw = tw2;
                tg[index] = [];
            }
            tg[index].push(g3);
        }
        index += 1;
        tw = 0;
    }

    total = tg.length;
    const textGroup = [];
    for (i = 0; i < total; i++) {
        t = tg[i].join(' ').split('');
        if (t.length > 0) {
            textGroup.push(t);
        }
    }

    return textGroup;
}

function breakAll(group, scale, width) {
    let t,
        i, total,
        j, j_total,
        m_rect,
        g2, g3,
        tw = 0,
        index = 0,
        tx = 0;
    const tg = [];

    total = group.length;
    for (i = 0; i < total; i++) {
        g2 = group[i];
        tw = 0;
        tx = 0;
        tg[index] = [];
        j_total = g2.length;
        for (j = 0; j < j_total; j++) {
            g3 = g2[j];
            t = typo(g3);
            m_rect = getRect(t, scale);
            tw += m_rect.w;
            tg[index].push(g3);
            if (tw >= width) {
                index += 1;
                tw = m_rect.w;
                tg[index] = [];
            }
        }
        index += 1;
    }

    const textGroup = [];
    total = tg.length;
    for (i = 0; i < total; i++) {
        t = tg[i];
        if (t.length > 0) {
            if (t[0] == ' ') t.shift();
            if (t[t.length - 1] == ' ') t.pop();
            if (t.length > 0) textGroup.push(t);
        }
    }
    return textGroup;
}

================================================
FILE: src/core/guide.js
================================================
import {
    RECT_RATIO
} from './util.js';

/**
 * @name getGuide
 * @property {Object} - typo data object from 'font/index.js'
 * @property {Number} - scale
 * @returns {Object} the guide pos array
 * @description get a guide pos
 */
export function getGuide(d, scale) {
    let guide = [],
        ggap = 10,
        i, gvx, gvy;
    for (i = 0; i < 6; i++) {
        gvx = (ggap * i) + 20;
        gvy = (ggap * i) + 90;
        guide[i] = {
            x1: (gvx * RECT_RATIO) * scale,
            x2: ((d.rect.w - (gvx * 2)) * RECT_RATIO) * scale,
            y1: (gvy * RECT_RATIO) * scale,
            y2: (((d.rect.h - gvy) * RECT_RATIO) * scale) - ((i * ggap * RECT_RATIO) * scale),
        };
    }

    return guide;
}

/**
 * @name getGuide
 * @property {Object} - typo data object from 'font/index.js'
 * @property {Number} - scale
 * @returns {Object} the guide pos array
 * @description get a guide pos
 */
export function getGrid(d, scale) {
    let grid = [],
        i, gvy = [98, 340, 815];
    for (i = 0; i < 3; i++) {
        grid[i] = (gvy[i] * RECT_RATIO) * scale;
    }

    return grid;
}

================================================
FILE: src/core/length.js
================================================
export function getLengths(item, model) {
    const total = item.typo.p.length;
    let c, p,
        arr = [],
        lt = [],
        max = 0,
        i;
    for (i = 0; i < total; i++) {
        p = item.typo.p[i];
        c = getEachPath(item, p.v, model);
        max += c.l;
        arr.push(c.v);
        lt.push(c.l);
    }
    return {
        max: max,
        lines: arr,
        lengths: lt
    };
}

function getEachPath(item, points, model) {
    const total = points.length;
    let i, p,
        line, cp1, cp2, prev,
        lines = [],
        length = 0;

    for (i = 0; i < total; i++) {
        p = points[i];
        line = {};
        cp2 = p.convert(item, model);

        if (i == 0 || p.type == 'a') {
            line.x1 = cp2.x;
            line.y1 = cp2.y;
            line.distance = 0;
            line.radius = cp2.radius;
        } else {
            cp1 = prev.convert(item, model);

            if (prev.type == 'b') {
                line.x1 = cp1.x3;
                line.y1 = cp1.y3;
            } else {
                line.x1 = cp1.x;
                line.y1 = cp1.y;
            }

            line.x2 = cp2.x;
            line.y2 = cp2.y;

            if (p.type == 'b') {
                line.x3 = cp2.x2;
                line.y3 = cp2.y2;
                line.x4 = cp2.x3;
                line.y4 = cp2.y3;
                line.distance = cubicBezierLength(line.x1, line.y1, line.x2, line.y2, line.x3, line.y3, line.x4, line.y4);
            } else {
                line.distance = distance(line.x1, line.y1, line.x2, line.y2);
            }
        }

        line.type = p.type;
        line.rotation = p.ratio.r;
        line.pat = p.ratio.p;
        line.fix = p.ratio.f;
        line.vt = p.ratio.v;

        lines.push(line);
        length += line.distance;

        prev = p;
    }

    return {
        v: lines,
        l: length
    };
}

export function cubicBezierLength(x1, y1, x2, y2, x3, y3, x4, y4, sampleCount) {
    const ptCount = sampleCount || 40;
    let totDist = 0;
    let lastX = x1;
    let lastY = y1;
    let dx, dy, i, pt;
    for (i = 1; i < ptCount; i++) {
        pt = cubicQxy(i / ptCount, x1, y1, x2, y2, x3, y3, x4, y4);
        dx = pt.x - lastX;
        dy = pt.y - lastY;
        totDist += Math.sqrt(dx * dx + dy * dy);
        lastX = pt.x;
        lastY = pt.y;
    }
    dx = x4 - lastX;
    dy = y4 - lastY;
    totDist += Math.sqrt(dx * dx + dy * dy);
    return totDist;
}

function cubicQxy(t, x1, y1, x2, y2, x3, y3, x4, y4) {
    x1 += (x2 - x1) * t;
    x2 += (x3 - x2) * t;
    x3 += (x4 - x3) * t;
    x1 += (x2 - x1) * t;
    x2 += (x3 - x2) * t;
    y1 += (y2 - y1) * t;
    y2 += (y3 - y2) * t;
    y3 += (y4 - y3) * t;
    y1 += (y2 - y1) * t;
    y2 += (y3 - y2) * t;
    return {
        x: x1 + (x2 - x1) * t,
        y: y1 + (y2 - y1) * t
    };
}

export function distance(x1, y1, x2, y2) {
    const a = (x2 - x1),
        b = (y2 - y1);
    return Math.sqrt(a * a + b * b);
}

================================================
FILE: src/core/model.js
================================================
import {
    getFontW,
    getWeightRatio,
    getCircleRound,
    getScale,
    getTracking,
    getLeading,
    getFontRatio,
    getLineW,
    getRect,
    getCenter,
    getRange,
    getLines,
    addRectToPaths,
} from './util.js';
import {
    getGuide,
    getGrid
} from './guide.js';
import {
    getTextGroup
} from './group.js';
import {
    setAlignGapX,
    getAlignGapX
} from './align.js';
import {
    typo
} from '../font/index.js';
import {
    getLengths
} from './length.js';
import {
    getPaths
} from './paths.js';


export class Model {
    constructor() {
        this.lineWidth_ = 1;
        this.drawing_ = [];
        this.data_ = null;
        this.paths_ = null;
        this.lines_ = null;
        this.rect_ = {
            x: 0,
            y: 0,
            w: 0,
            h: 0
        };
        this.align_ = 'left';
        this.scale_ = 1;
        this.fontRatio_ = 1;
    }

    get data() {
        return this.data_;
    }

    get paths() {
        return this.paths_;
    }

    get lines() {
        return this.lines_;
    }

    set lines(v) {
        this.lines_ = v;
    }

    get lineWidth() {
        return this.lineWidth_;
    }

    get fontRatio() {
        return this.fontRatio_;
    }

    get scale() {
        return this.scale_;
    }

    get rect() {
        return this.rect_;
    }

    get drawing() {
        return this.drawing_;
    }

    set align(v) {
        if (this.align_ != v) {
            this.align_ = v;
            this.setPosition();
        }
    }

    get align() {
        return this.align_;
    }

    position(x, y) {
        if (this.rect_.x != x || this.rect_.y != y) {
            this.rect_.x = x;
            this.rect_.y = y;
            this.setPosition();
            return true;
        } else {
            return false;
        }
    }

    setPosition() {
        const total = this.data_.length;
        let i, d;
        for (i = 0; i < total; i++) {
            d = this.data_[i];
            d.rect.x = d.originPos.x + this.rect_.x + getAlignGapX(this.align_, d.alignGapX);
            d.rect.y = d.originPos.y + this.rect_.y;
        }
    }

    updateDrawingPaths() {
        const total = this.data_.length;
        let i, d;
        for (i = 0; i < total; i++) {
            d = this.data_[i];
            d.drawingPaths = addRectToPaths(getPaths(this, d, -1, false), d);
        }
    }

    updatePatternPaths(pathGap) {
        const total = this.data_.length;
        let i, d;
        for (i = 0; i < total; i++) {
            d = this.data_[i];
            d.rawPaths = getPaths(this, d, pathGap, true);
        }
    }

    updateWavePaths(pathGap) {
        const total = this.data_.length;
        let i, d;
        for (i = 0; i < total; i++) {
            d = this.data_[i];
            d.rawWavePaths = getPaths(this, d, pathGap, false);
        }
    }

    updateGuide() {
        const total = this.data_.length;
        let i, d;
        for (i = 0; i < total; i++) {
            d = this.data_[i];
            d.guide = getGuide(d.typo, this.scale);
            d.grid = getGrid(d.typo, this.scale);
        }
    }

    update(text, width, breakWord, weight, size, tracking, leading) {
        const fontW = getFontW(weight);
        const weightRatio = getWeightRatio(fontW);
        const circleRound = getCircleRound(fontW);
        const scale = getScale(size);
        const m_tracking = getTracking(tracking, scale);
        const m_leading = getLeading(leading, scale);
        const fontRatio = getFontRatio(weightRatio);

        this.fontRatio_ = fontRatio;
        this.scale_ = scale;
        this.lineWidth_ = getLineW(fontW, scale);

        const textGroup = getTextGroup(text, scale, width, breakWord);

        let total = textGroup.length;
        const total2 = total - 1;
        let i, j, j_total, j_total2,
            gt,
            t, str,
            m_rect,
            s_pos,
            tw = 0,
            th = 0,
            tx = 0,
            ty = 0,
            maxW = 0,
            maxH = 0,
            tmp = [];
        for (i = 0; i < total; i++) {
            gt = textGroup[i];
            j_total = gt.length;
            j_total2 = j_total - 1;
            tw = 0;
            tx = 0;
            tmp[i] = {
                tw: 0,
                arr: []
            };
            for (j = 0; j < j_total; j++) {
                str = gt[j];
                t = typo(str);
                m_rect = getRect(t, scale);
                tw += m_rect.w;
                th = m_rect.h;
                if (j < j_total2) {
                    tw += m_tracking;
                }
                if (i < total2) {
                    th += m_leading;
                }
                m_rect.x = tx;
                m_rect.y = ty;
                s_pos = {
                    x: tx,
                    y: ty
                };

                tmp[i].arr[j] = {
                    str: str,
                    typo: t,
                    rect: m_rect,
                    originPos: s_pos,
                    center: getCenter(m_rect.w, m_rect.h, scale),
                    range: getRange(t, weightRatio, circleRound)
                };

                tx = tw;
            }
            ty += th;
            tmp[i].tw = tw;
            maxW = Math.max(maxW, tw);
            maxH += th;
        }

        this.rect_.w = maxW;
        this.rect_.h = maxH;

        this.drawing_ = [];
        const arr = [];
        let aGapX, drawing;
        for (const a of tmp) {
            aGapX = setAlignGapX(maxW, a.tw);
            for (const b of a.arr) {
                b.alignGapX = aGapX;
                b.pointsLength = getLengths(b, this);
                arr.push(b);
                drawing = {
                    value: 1
                };
                this.drawing_.push(drawing);
                b.drawing = drawing;

                // add converted Vector
                for (const c of b.typo.p) {
                    c.cv = [];
                    for (const d of c.v) {
                        c.cv.push(d.convert(b, this));
                    }
                }
            }
        }

        this.data_ = arr;
        this.setPosition();
    }

    updatePathsForRect() {
        const total = this.data_.length;
        const paths = [];
        let i, d;
        for (i = 0; i < total; i++) {
            d = this.data_[i];
            if (d.rawWavePaths) {
                d.wavePaths = addRectToPaths(d.rawWavePaths, d);
            }
            if (d.rawPaths) {
                d.paths = addRectToPaths(d.rawPaths, d);
                Array.prototype.push.apply(paths, d.paths);
            }
        }

        this.paths_ = paths;
    }

    updateLinesForRect() {
        const total = this.data_.length;
        let i, d;
        for (i = 0; i < total; i++) {
            d = this.data_[i];
            d.lines = getLines(d);
        }
    }

    reset() {
        this.lineWidth_ = 1;
        this.drawing_ = [];
        this.data_ = null;
        this.paths_ = null;
        this.lines_ = null;
        this.rect_ = {
            x: 0,
            y: 0,
            w: 0,
            h: 0
        };
        this.align_ = 'left';
        this.scale_ = 1;
        this.fontRatio_ = 1;
    }
}

================================================
FILE: src/core/paths.js
================================================
import {
    getCurrent
} from './util.js';
import {
    ROTATE_NONE
} from '../font/util.js';
import {
    Point
} from './point.js';

let prevPoint = null;

/**
 * @name getPaths
 * @property {Model} model - mode.js
 * @property {Object} data - data object
 * @property {Number} pathGap 
 * @returns {Array} Returns paths array
 * @description get a guide pos
 */
export function getPaths(model, data, pathGap, isPattern) {
    const lines = data.pointsLength.lines;
    const scale = model.scale;
    let total = lines.length,
        i, j_total, j,
        line, lg, direction,
        arr = [],
        paths = [],
        paths2 = [];


    for (i = 0; i < total; i++) {
        line = lines[i];
        prevPoint = null;
        arr.push(getDotPos(line, pathGap, scale));
    }

    total = arr.length;
    for (i = 0; i < total; i++) {
        lg = arr[i];
        j_total = lg.length;

        paths2 = [];
        for (j = 0; j < j_total; j++) {
            line = lg[j];
            if (line.rotation != ROTATE_NONE) {
                if (isPattern) {
                    // If the 'p' value of the font data is 1, it's not included in the pattern paths.
                    if (!line.pat) {
                        paths2.push(line);
                    }
                } else {
                    paths2.push(line);
                }
            }
        }
        direction = data.typo.p[i].d;
        if (direction == 1) {
            paths2.reverse();
        }

        if (paths2.length > 0) {
            paths2[0].start = 1;
            Array.prototype.push.apply(paths, paths2);
        }
    }

    return paths;
}

function getDotPos(lines, pathGap, scale) {
    const total = lines.length;
    let i, j, j_total;
    let line;
    let curPoint;
    let num, pp;
    let arr = [];
    let isFirst = 1;
    let pgap = 1;
    if (pathGap > -1) pgap = getCurrent(pathGap, 1, 0, 80, 10) * scale;

    for (i = 0; i < total; i++) {
        line = lines[i];

        if (line.type == 'a') {
            arr.push(new Point({
                x: line.x1,
                y: line.y1,
                rotation: 0,
                type: 'a',
                pat: line.pat,
                fix: line.fix,
                radius: line.radius
            }));
        } else if (line.distance == 0) {
            // it should be type m
            curPoint = new Point({
                x: line.x1,
                y: line.y1,
                rotation: line.rotation,
                type: line.type,
                pat: line.pat,
                fix: line.fix
            });
            pp = setPointValues(curPoint, prevPoint, line, 1);
            if (pp != null) {
                if (isFirst) {
                    pp.type = 'm';
                    isFirst = 0;
                }
                arr.push(pp);
            }
            prevPoint = new Point(curPoint); //Object.assign({}, curPoint)
        } else {
            j_total = Math.ceil(line.distance / pgap);

            if (j_total < 3) j_total = 3;
            if (line.vt) j_total = 2;

            for (j = 1; j < j_total; j++) {
                num = j / (j_total - 1);
                if (line.type == 'b') {
                    curPoint = getCubicBezierXYatT(line, num);
                } else {
                    curPoint = new Point({
                        x: line.x1 + ((line.x2 - line.x1) * num),
                        y: line.y1 + ((line.y2 - line.y1) * num),
                        type: line.type
                    });
                }

                if (line.rotation != 0 && num == 1) curPoint.rotation = line.rotation;

                if (line.pat && num == 1) curPoint.pat = line.pat;

                if (line.fix && num == 1) curPoint.fix = line.fix;

                if (j_total > 0) {
                    pp = setPointValues(curPoint, prevPoint, line, num);
                    if (pp != null) {
                        if (isFirst) {
                            pp.type = 'm';
                            isFirst = 0;
                        }
                        arr.push(pp);
                    }
                }
                prevPoint = new Point(curPoint); //Object.assign({}, curPoint)
            }
        }
    }
    return arr;
}

function setPointValues(cur, prev, line, num) {
    cur.type = line.type;
    cur.distance = line.distance;
    cur.num = num;

    if (!prev || cur.rotation != null) {
        cur.rotation = cur.rotation;
    } else {
        const dx = cur.x - prev.x;
        const dy = cur.y - prev.y;
        const rad = Math.atan2(dx, dy);
        cur.rotation = -rad;
    }

    if (cur.rotation == ROTATE_NONE) {
        return null;
    } else {
        return cur;
    }
}

function getCubicBezierXYatT(line, t) {
    const x = CubicN(line.x1, line.x2, line.x3, line.x4, t);
    const y = CubicN(line.y1, line.y2, line.y3, line.y4, t);
    const tx = bezierTangent(line.x1, line.x2, line.x3, line.x4, t);
    const ty = bezierTangent(line.y1, line.y2, line.y3, line.y4, t);
    const rotation = -Math.atan2(tx, ty);

    return new Point({
        x: x,
        y: y,
        rotation: rotation
    });
}

function CubicN(a, b, c, d, t) {
    const t2 = t * t;
    const t3 = t2 * t;
    return a + (-a * 3 + t * (3 * a - a * t)) * t + (3 * b + t * (-6 * b + b * 3 * t)) * t + (c * 3 - c * 3 * t) * t2 + d * t3;
}

//http://qaru.site/questions/10657973/quadratic-curve-with-rope-pattern
//https://stackoverflow.com/questions/32322966/quadratic-curve-with-rope-pattern
export function bezierTangent(a, b, c, d, t) {
    return (3 * t * t * (-a + 3 * b - 3 * c + d) + 6 * t * (a - 2 * b + c) + 3 * (-a + b));
}

================================================
FILE: src/core/point.js
================================================
export function Point(mp) {
    Object.assign(this, mp);
}

Object.assign(Point.prototype, {
    addRect: function (rect) {
        const vv = new Point(this);
        vv.x = this.x + rect.x;
        vv.y = this.y + rect.y;
        vv.x2 = this.x2 + rect.x;
        vv.y2 = this.y2 + rect.y;
        vv.x3 = this.x3 + rect.x;
        vv.y3 = this.y3 + rect.y;
        vv.rx = this.rx + rect.x;
        vv.ry = this.ry + rect.y;
        vv.sx = this.sx + rect.x;
        vv.sy = this.sy + rect.y;
        if (vv.radius < 0.5) vv.radius = 0.5;
        return vv;
    }
});

================================================
FILE: src/core/util.js
================================================
const DEFAULT_FONT_SIZE = 500;
export const MIN_FONT_WEIGHT = 1;
export const MAX_FONT_WEIGHT = 900;
const MAX_LINE_WIDTH = 70;
const FONT_WEIGHT_LIMIT = 80;
const FR_1 = 1;
const FR_2 = 0.78;
export const RECT_RATIO = 0.49;
const MAX_SHAKE = 120;
export const PI2 = 2 * Math.PI;

export function getAmplitude(amplitude, scale) {
    return (MAX_SHAKE * amplitude) * scale;
}

export function getFontW(weight) {
    return (MAX_LINE_WIDTH - MIN_FONT_WEIGHT) / (MAX_FONT_WEIGHT - MIN_FONT_WEIGHT) * (weight - MIN_FONT_WEIGHT) + MIN_FONT_WEIGHT;
}

export function getWeightRatio(fontW) {
    return (1) / (FONT_WEIGHT_LIMIT - MIN_FONT_WEIGHT) * (fontW - MIN_FONT_WEIGHT);
}

export function getCircleRound(fontW) {
    return (58 - 4) / (FONT_WEIGHT_LIMIT - MIN_FONT_WEIGHT) * (fontW - MIN_FONT_WEIGHT) + 4;
}

export function getScale(size) {
    return size / DEFAULT_FONT_SIZE;
}

export function getLineW(fontW, scale) {
    let lw = fontW * scale;
    if (lw < 1) lw = 1;
    //if (weight == 1) lw = 1
    return lw;
}

export function getTracking(tracking, scale) {
    return tracking * 50 * scale;
}

export function getLeading(leading, scale) {
    return leading * 50 * scale;
}

export function getFontRatio(weightRatio) {
    return (FR_2 - FR_1) * weightRatio + FR_1;
}

export function getRect(d, scale, x = 0, y = 0) {
    const w = (d.rect.w * RECT_RATIO) * scale;
    const h = ((d.rect.h + 220) * RECT_RATIO) * scale;
    return {
        x: x,
        y: y,
        w: w,
        h: h
    };
}

/**
 * @name getGap
 * @property {Object} - typo data object from 'font/index.js'
 * @property {Number} - weightRatio
 * @returns {Object} the gap x and y
 * @description get a typo gap from thin to bold weight
 */
/*
export function getGap(d, weightRatio) {
    const gx1 = d.ratio.x1
    const gx2 = d.ratio.x2
    const gy1 = d.ratio.y1
    const gy2 = d.ratio.y2
    const x = (gx2 - gx1) * weightRatio + gx1
    const y = (gy2 - gy1) * weightRatio + gy1
    return {
        x: x,
        y: y
    }
}
*/

/**
 * @name getCenter
 * @property {Number} - typo rect width
 * @property {Number} - typo rect height
 * @property {Number} - typo scale
 * @returns {Object} center position x and y
 * @description get a center position of a typo
 */
export function getCenter(w, h, scale) {
    const x = w / 2;
    const y = (h - ((220 - 90) * RECT_RATIO * scale)) / 2;
    return {
        x: x,
        y: y
    };
}

/**
 * @name getRange
 * @property {Object} - typo data object from 'font/index.js'
 * @property {Number} - weightRatio
 * @property {Number} - circleRound
 * @returns {Object} ratio range
 * @description save ratio range to control each line's coordinate 
 */
export function getRange(d, weightRatio, circleRound) {
    const gx1 = d.ratio.x1;
    const gx2 = d.ratio.x2;
    const gy1 = d.ratio.y1;
    const gy2 = d.ratio.y2;
    return {
        r: weightRatio,
        cr: circleRound,
        fr1: FR_1,
        fr2: FR_2,
        gx1: gx1,
        gx2: gx2,
        gy1: gy1,
        gy2: gy2,
    };
}

export function getCurrent(v, vmax, vmin, max, min) {
    let value = (max - min) / (vmax - vmin) * (v - vmin) + min;
    if (value < min) value = min;
    else if (value > max) value = max;
    return value;
}

export function getLines(data) {
    const total = data.typo.p.length;
    const lines = [];
    let i, j, k, j_total;
    let d2, d3, cp, dir, lt, ltRatio, prevRatio;
    for (i = 0; i < total; i++) {
        d2 = data.typo.p[i];
        j_total = d2.cv.length;
        for (j = 0; j < j_total; j++) {
            d3 = d2.cv[j];
            // add current position to all points
            cp = d3.addRect(data.rect);
            dir = d2.d;
            lt = data.pointsLength.lengths[i];
            ltRatio = lt / data.pointsLength.max;
            prevRatio = 0;
            if (i > 0) {
                for (k = 0; k < i; k++) {
                    prevRatio += (data.pointsLength.lengths[k] / data.pointsLength.max);
                }
            }
            ltRatio += prevRatio;

            lines.push({
                pos: cp,
                drawing: data.drawing,
                direction: dir,
                lengths: lt,
                maxDrawing: ltRatio,
                minDrawing: prevRatio,
                closePath: d3.ratio.c,
                stroke: (ctx, d) => {
                    let dv = getCurrent(d.drawing.value, d.maxDrawing, d.minDrawing, 1, 0);
                    //if (d.direction == 1) {
                    //    dv = getCurrent(1 - d.drawing.value, d.minDrawing, d.maxDrawing, 1, 0);
                    //}
                    if (dv > 0 && d.pos.type != 'a') {
                        const frac = d.lengths * dv;
                        ctx.setLineDash([d.lengths]);
                        ctx.lineDashOffset = d.direction * (frac + d.lengths);
                        ctx.stroke();
                    }
                },
            });
        }
    }

    return lines;
}


export function addRectToPaths(path, data) {
    const total = path.length;
    const arr = [];
    let i, cp, p;
    for (i = 0; i < total; i++) {
        p = path[i];
        cp = p.addRect(data.rect);
        arr.push(cp);
    }
    return arr;
}

export function randomBrightColor() {
    return "hsl(" + 360 * Math.random() + ',' +
        '100%,' +
        '50%)';
}

export function shuffle(oldArray) {
    let newArray = oldArray.slice(),
        len = newArray.length,
        i = len,
        p, t;
    while (i--) {
        p = (Math.random() * len) | 0;
        t = newArray[i];
        newArray[i] = newArray[p];
        newArray[p] = t;
    }
    return newArray;
}

================================================
FILE: src/core/vector.js
================================================
import {
    Point
} from './point.js';

export function Vector(mp) {
    this.type = mp[0];

    this.x = mp[1] || 0;
    this.y = mp[2] || 0;

    if (this.type == 'b') {
        this.x2 = mp[3] || 0;
        this.y2 = mp[4] || 0;
        this.x3 = mp[5] || 0;
        this.y3 = mp[6] || 0;
        if (mp[7] == null) {
            this.ratio = {
                x: 1,
                y: 1,
                r: 0, // rotation : if the rotation is ROTATE_NONE, it will hide in the 'pattern' and 'paths'
                p: 0, // 1 is hide the point in the pattern paths
                f: 0, // 1 is fixed position for wave paths
                c: 0, // 1 is close path for PIXI bug - graphics.closePath()
                v: 0 // 1 is vertex, it's only for the vertex shape like V, W, A
            };
        } else {
            this.ratio = {};
            this.ratio.x = (mp[7].x == null) ? 1 : mp[7].x;
            this.ratio.y = (mp[7].y == null) ? 1 : mp[7].y;
            this.ratio.r = mp[7].r || 0;
            this.ratio.p = mp[7].p || 0;
            this.ratio.f = mp[7].f || 0;
            this.ratio.c = mp[7].c || 0;
            this.ratio.v = mp[7].v || 0;
        }
    } else {
        if (mp[3] == null) {
            this.ratio = {
                x: 1,
                y: 1,
                r: 0,
                p: 0,
                f: 0,
                c: 0,
                v: 0
            };
        } else {
            this.ratio = {};
            this.ratio.x = (mp[3].x == null) ? 1 : mp[3].x;
            this.ratio.y = (mp[3].y == null) ? 1 : mp[3].y;
            this.ratio.r = mp[3].r || 0;
            this.ratio.p = mp[3].p || 0;
            this.ratio.f = mp[3].f || 0;
            this.ratio.c = mp[3].c || 0;
            this.ratio.v = mp[3].v || 0;
        }
    }
}

Object.assign(Vector.prototype, {
    convert: function (pos, model) {
        const x = convertX(this.x, pos, this.ratio, model);
        const y = convertY(this.y, pos, this.ratio, model);
        const x2 = convertX(this.x2, pos, this.ratio, model);
        const y2 = convertY(this.y2, pos, this.ratio, model);
        const x3 = convertX(this.x3, pos, this.ratio, model);
        const y3 = convertY(this.y3, pos, this.ratio, model);
        const rd = convertR(this.type, pos, model);

        const vv = new Point(this);
        vv.x = x;
        vv.y = y;
        vv.x2 = x2;
        vv.y2 = y2;
        vv.x3 = x3;
        vv.y3 = y3;
        vv.radius = rd;

        return vv;
    }
});

function convertR(type, pos, model) {
    let rd = 0;
    if (type == 'a') rd = pos.range.cr * model.scale * model.fontRatio;
    return rd;
}

function convertX(x, pos, ratio, model) {
    const rr = pos.range.r * ratio.x;
    const gx = (pos.range.gx2 - pos.range.gx1) * rr + pos.range.gx1;
    const fr = (pos.range.fr2 - pos.range.fr1) * rr + pos.range.fr1;
    return pos.center.x + (((x - gx)) * model.scale * fr); // + pos.rect.x
}

function convertY(y, pos, ratio, model) {
    const rr = pos.range.r * ratio.y;
    const gy = (pos.range.gy2 - pos.range.gy1) * rr + pos.range.gy1;
    const fr = (pos.range.fr2 - pos.range.fr1) * rr + pos.range.fr1;
    return pos.center.y + (((y - gy)) * model.scale * fr); // + pos.rect.y
}

================================================
FILE: src/draw/canvas/color.js
================================================
export function Color(ctx, no, data, color) {
    let c_total = color.length;
    const cur = (no + (c_total * (Math.abs((no / 10) | 0) + 1))) % c_total;
    if (Array.isArray(color[cur])) {
        c_total = color[cur].length;
        const vv = 1 / (c_total + 1);
        const g = ctx.createLinearGradient(data.rect.x, data.rect.y, data.rect.x, data.rect.y + data.rect.h);
        let i;
        g.addColorStop(vv, color[cur][0]);
        for (i = 0; i < c_total; i++) {
            g.addColorStop(vv * (i + 1), color[cur][i]);
        }
        g.addColorStop(vv * (c_total + 1), color[cur][c_total - 1]);
        ctx.strokeStyle = g;
        ctx.fillStyle = g;
    } else {
        ctx.strokeStyle = color[cur];
        ctx.fillStyle = color[cur];
    }
}

================================================
FILE: src/draw/canvas/colorful.js
================================================
import {
    PI2,
    getCurrent
} from '../../core/util.js';
import {
    cubicBezierLength,
    distance
} from '../../core/length.js';

let colorArr;
let curColor = -1;
let colorTotal;
const MIN_DISTANCE = 10;

export function Colorful(ctx, model, colors) {
    curColor = -1;
    colorArr = colors;
    colorTotal = colorArr.length;
    const total = model.data.length;
    let i, d, j, j_total, line, pos, prev;
    let max, length, prevRatio;
    for (i = 0; i < total; i++) {
        d = model.data[i];
        max = d.pointsLength.max;
        prevRatio = 0;
        j_total = d.lines.length;
        prev = null;
        for (j = 0; j < j_total; j++) {
            line = d.lines[j];
            pos = line.pos;
            if (pos.type == 'a') {
                setColor(ctx);
                ctx.beginPath();
                ctx.arc(pos.x, pos.y, pos.radius * d.drawing.value, 0, PI2);
                ctx.fill();
                ctx.closePath();
            } else if (pos.type == 'm') {
                prev = pos;
            } else if (pos.type == 'l') {
                length = distance(prev.x, prev.y, pos.x, pos.y);
                if (length / model.scale > MIN_DISTANCE) {
                    // ignore short distance paths
                    setColor(ctx);
                    ctx.beginPath();
                    if (prev) ctx.moveTo(prev.x, prev.y);
                    ctx.lineTo(pos.x, pos.y);
                    prevRatio += draw(ctx, line, length, max, d, prevRatio);
                }
                prev = pos;
            } else if (pos.type == 'b') {
                length = cubicBezierLength(prev.x, prev.y, pos.x, pos.y, pos.x2, pos.y2, pos.x3, pos.y3);
                if (length / model.scale > MIN_DISTANCE) {
                    setColor(ctx);
                    ctx.beginPath();
                    if (prev) ctx.moveTo(prev.x, prev.y);
                    ctx.bezierCurveTo(pos.x, pos.y, pos.x2, pos.y2, pos.x3, pos.y3);
                    prevRatio += draw(ctx, line, length, max, d, prevRatio);
                }
                prev = {
                    x: pos.x3,
                    y: pos.y3
                };
            }
        }
    }
}

function setColor(ctx) {
    const color = getColor();
    ctx.fillStyle = color;
    ctx.strokeStyle = color;
}

function getColor() {
    curColor++;
    if (curColor == colorTotal) curColor = 0;
    return colorArr[curColor];
}

function draw(ctx, line, length, max, d, prevRatio) {
    const ltRatio = length / max;
    let dv = getCurrent(d.drawing.value, prevRatio + ltRatio, prevRatio, 1, 0);
    if (line.direction == 1) {
        dv = getCurrent(1 - d.drawing.value, prevRatio, prevRatio + ltRatio, 1, 0);
    }
    if (dv > 0) {
        const frac = length * dv;
        ctx.setLineDash([length]);
        ctx.lineDashOffset = line.direction * (frac + length);
        ctx.stroke();
    }
    return ltRatio;
}

================================================
FILE: src/draw/canvas/grids.js
================================================
export function Grids(ctx, data) {
    ctx.save();

    ctx.beginPath();
    ctx.lineWidth = 1;
    ctx.strokeStyle = "#aaaaaa";
    let i, total = data.guide.length,
        grid;
    for (i = 0; i < total; i++) {
        grid = data.rect.y + data.grid[i];
        ctx.moveTo(data.rect.x, grid);
        ctx.lineTo(data.rect.x + data.rect.w, grid);
    }
    ctx.stroke();

    ctx.lineWidth = 1;
    ctx.beginPath();
    ctx.strokeStyle = "#aaaaaa";
    ctx.rect(data.rect.x, data.rect.y, data.rect.w, data.rect.h);
    ctx.stroke();

    ctx.restore();
}

================================================
FILE: src/draw/canvas/lines.js
================================================
import {
    PI2
} from '../../core/util.js';

export function Lines(ctx, data) {
    const total = data.lines.length;
    let i, d, pos;
    for (i = 0; i < total; i++) {
        d = data.lines[i];
        pos = d.pos;
        if (pos.type == 'a') {
            ctx.beginPath();
            ctx.arc(pos.x, pos.y, pos.radius * d.drawing.value, 0, PI2);
            ctx.fill();
            ctx.closePath();
        } else if (pos.type == 'm') {
            ctx.beginPath();
            ctx.moveTo(pos.x, pos.y);
        } else if (pos.type == 'l') {
            ctx.lineTo(pos.x, pos.y);
            d.stroke(ctx, d);
        } else if (pos.type == 'b') {
            ctx.bezierCurveTo(pos.x, pos.y, pos.x2, pos.y2, pos.x3, pos.y3);
            d.stroke(ctx, d);
        }
    }
}


================================================
FILE: src/draw/canvas/pattern.js
================================================
import {
    PI2
} from '../../core/util.js';

export function Pattern(ctx, data, w, h) {
    const total = Math.round(data.paths.length * data.drawing.value);
    const w2 = w / 2;
    const w3 = w / 3;
    const h2 = h / 2;
    let i, p;
    for (i = 0; i < total; i++) {
        p = data.paths[i];
        if (p.num == 1) {
            ctx.fillStyle = "#ff00c5";
        } else {
            ctx.fillStyle = "#ff95f8";
        }
        if (p.type == 'a') {
            ctx.beginPath();
            ctx.arc(p.x, p.y, w3, 0, PI2);
            ctx.fill();
        } else {
            ctx.beginPath();
            ctx.save();
            ctx.translate(p.x, p.y);
            ctx.rotate(p.rotation);
            ctx.fillRect(-w2, -h2, w, h);
            ctx.restore();
        }
    }
}

================================================
FILE: src/draw/canvas/points.js
================================================
import {
    PI2
} from '../../core/util.js';

export function Points(ctx, data) {
    ctx.save();
    ctx.lineWidth = 1;
    let total = data.lines.length;
    let i;
    for (i = 0; i < total; i++) {
        eachLine_(ctx, data.lines[i]);
    }
    ctx.restore();

    ctx.save();
    ctx.lineWidth = 1;
    total = data.typo.p.length;
    for (i = 0; i < total; i++) {
        eachPoint_(ctx, data.typo.p[i], data);
    }
    ctx.restore();
}

function eachPoint_(ctx, p, data) {
    const total = p.v.length;
    let i, mp, cp;
    for (i = 0; i < total; i++) {
        mp = p.cv[i];
        cp = mp.addRect(data.rect);
        if (mp.type == 'b') {
            ctx.fillStyle = "#ff2a00";
            ctx.beginPath();
            ctx.arc(cp.x3 + (cp.x3 - cp.x2), cp.y3 + (cp.y3 - cp.y2), 1.5, 0, PI2);
            ctx.fill();
            ctx.beginPath();
            ctx.arc(cp.x2, cp.y2, 1.5, 0, PI2);
            ctx.fill();
            ctx.beginPath();
            ctx.moveTo(cp.x2, cp.y2);
            ctx.lineTo(cp.x3, cp.y3);
            ctx.lineTo(cp.x3 + (cp.x3 - cp.x2), cp.y3 + (cp.y3 - cp.y2));
            ctx.stroke();
            ctx.beginPath();
            ctx.fillStyle = "#ffffff";
            ctx.arc(cp.x3, cp.y3, 2.5, 0, PI2);
            ctx.fill();
            ctx.stroke();
        } else {
            ctx.beginPath();
            ctx.fillStyle = "#ffffff";
            ctx.strokeStyle = "#ff2a00";
            ctx.arc(cp.x, cp.y, 2.5, 0, PI2);
            ctx.fill();
            ctx.stroke();
        }
    }
}

function eachLine_(ctx, d) {
    const pos = d.pos;
    if (pos.type != 'a') {
        if (pos.type == 'm') {
            ctx.strokeStyle = "#ff2a00";
            ctx.beginPath();
            ctx.moveTo(pos.x, pos.y);
        } else if (pos.type == 'l') {
            ctx.lineTo(pos.x, pos.y);
        } else if (pos.type == 'b') {
            ctx.bezierCurveTo(pos.x, pos.y, pos.x2, pos.y2, pos.x3, pos.y3);
        }
        ctx.stroke();
    }
}

================================================
FILE: src/draw/canvas/wave.js
================================================
import {
    PI2,
    getAmplitude
} from '../../core/util.js';

const THIN_LIMIT = 110;
const COS = Math.cos;
const SIN = Math.sin;

export function Wave(ctx, data, scale, amplitude, weight, fps) {
    const total = data.wavePaths.length;
    const m_amplitude = getAmplitude(amplitude, scale);
    let i, p, prev, qx, qy, saveDot = [];

    ctx.beginPath();
    for (i = 0; i < total; i++) {
        p = data.wavePaths[i];
        if (fps) {
            const ranx = (Math.random() * m_amplitude) - (m_amplitude / 2);
            const rany = (Math.random() * m_amplitude) - (m_amplitude / 2);
            p.rx = p.x + ranx * COS(p.rotation);
            p.ry = p.y + ranx * SIN(p.rotation);
            p.sx = p.x + ranx;
            p.sy = p.y + rany;
        }

        if (p.type == 'a') {
            saveDot.push(p);
        } else if (p.start == 1) {
            ctx.moveTo(p.x, p.y);
        } else if (p.fix) {
            ctx.lineTo(p.x, p.y);
        } else {
            if (weight < THIN_LIMIT) {
                prev = data.wavePaths[i - 1];
                if (prev) {
                    qx = prev.x + ((p.x - prev.x) * 0.5);
                    qy = prev.y + ((p.y - prev.y) * 0.5);
                    ctx.quadraticCurveTo(qx, qy, p.rx, p.ry);
                }
            } else {
                ctx.lineTo(p.rx, p.ry);
            }
        }
    }
    ctx.stroke();

    for (i = 0; i < saveDot.length; i++) {
        p = saveDot[i];
        ctx.beginPath();
        ctx.arc(p.x, p.y, p.radius, 0, PI2);
        ctx.fill();
    }
}

================================================
FILE: src/draw/pixi/color.js
================================================
export function PixiColor(no, data, color) {
    let c_total = color.length;
    const cur = (no + (c_total * (Math.abs((no / 10) | 0) + 1))) % c_total;
    if (Array.isArray(color[cur])) {
        /*
        c_total = color[cur].length;
        const vv = 1 / (c_total - 1);
        const g = ctx.createLinearGradient(data.rect.x, data.rect.y, data.rect.x, data.rect.y + data.rect.h);
        let i;
        for (i = 0; i < c_total; i++) {
            g.addColorStop(vv * i, color[cur][i]);
        }
        ctx.strokeStyle = g;
        ctx.fillStyle = g;
        */
        /*
        c_total = color[cur].length;
        const vv = 1 / (c_total - 1);
        const c = document.createElement("canvas");
        const ctx = c.getContext("2d");
        const g = ctx.createLinearGradient(0, 0, data.rect.w, data.rect.h);
        let i;
        for (i = 0; i < c_total; i++) {
            g.addColorStop(vv * i, color[cur][i]);
        }
        ctx.fillStyle = g;
        ctx.fillRect(0, 0, data.rect.w, data.rect.h);
        return new PIXI.Texture.from(c);
        */
    } else {
        return color[cur];
    }
}

================================================
FILE: src/draw/pixi/lines.js
================================================
export function PixiLines(graphics, data, lineW, color) {
    let total, i;
    if (data.drawing.value == 1) {
        total = data.lines.length;
        for (i = 0; i < total; i++) {
            eachLine_(graphics, data.lines[i], lineW, color);
        }
    } else {
        total = data.drawingPaths.length * data.drawing.value;
        for (i = 0; i < total; i++) {
            
            eachPath_(graphics, data.drawingPaths[i], lineW, color, data.drawing.value);
        }
    }
}

function eachLine_(graphics, data, lineW, color) {
    const pos = data.pos;
    if (pos.type == 'a') {
        graphics.lineStyle(0, color, 0);
        graphics.beginFill(color);
        graphics.drawCircle(pos.x, pos.y, pos.radius);
        graphics.endFill();
    } else if (pos.type == 'm') {
        graphics.lineStyle(lineW, color, 1);
        graphics.moveTo(pos.x, pos.y);
    } else if (pos.type == 'l') {
        graphics.lineTo(pos.x, pos.y);
    } else if (pos.type == 'b') {
        graphics.bezierCurveTo(pos.x, pos.y, pos.x2, pos.y2, pos.x3, pos.y3);
    }
    if (data.closePath) {
        graphics.closePath();
    }
}

function eachPath_(graphics, pos, lineW, color, dValue) {
    if (pos.type == 'a') {
        graphics.lineStyle(0, color, 0);
        graphics.beginFill(color);
        graphics.drawCircle(pos.x, pos.y, pos.radius * dValue);
        graphics.endFill();
    } else {
        if (pos.start == 1) {
            graphics.lineStyle(lineW, color, 1);
            graphics.moveTo(pos.x, pos.y);
        } else {
            graphics.lineTo(pos.x, pos.y, 1);
        }
    }
}

================================================
FILE: src/font/index.js
================================================
import {
    UPPER
} from './upper.js';
import {
    LOWER
} from './lower.js';
import {
    NUMBER
} from './number.js';
import {
    SPECIAL
} from './special.js';
import {
    LATIN
} from './latin.js';
import {
    TOFU
} from './util.js';

const DATA = Object.assign({}, UPPER, LOWER, NUMBER, SPECIAL, LATIN);

export function typo(v) {
    const t = DATA[v] || DATA[TOFU];
    const clone = t.clone();
    clone.v = v;
    return clone;
}

================================================
FILE: src/font/latin.js
================================================
import {
    generateFontData,
    ROTATE_HORIZONTAL,
    ROTATE_VERTICAL,
    ROTATE_NONE,
    getR,
    getCurveR
} from './util.js';
import {
    getLatin1,
    getLatin2,
    getLatin3,
    getLatin4,
    getLatin5,
    getLatin6,
    getLatin7,
    getLatin8,
    getLatin9,
    getLatin10,
    getLatin11,
    getLatin12,
    getLatin13,
    getLatin14
} from './latinutil.js';
import {
    DATA_UA,
    DATA_UC,
    DATA_UD,
    DATA_UE,
    DATA_UG,
    DATA_UH,
    DATA_UI,
    DATA_UJ,
    DATA_UN,
    DATA_UO,
    DATA_US,
    DATA_UU,
    DATA_UY
} from './upper.js';
import {
    DATA_LA,
    DATA_LC,
    DATA_LD,
    DATA_LE,
    DATA_LG,
    DATA_LH,
    DATA_LN,
    DATA_LO,
    DATA_LS,
    DATA_LU,
    DATA_LY
} from './lower.js';

const DATA_LI = [{
    d: 1,
    v: [
        ['m', 0, 352, {
            y: 0,
            f: 1
        }],
        ['l', 0, 130, {
            y: -3
        }],
    ]
}];

const DATA_LJ = [{
    d: 1,
    v: [
        ['m', 0 - 115.9, 317 + 127, {
            x: 0.4,
            y: 0.63,
            r: getCurveR(0 - 115.9, 317 + 127, 12.6 - 115.9, 327.4 + 127, 29.6 - 115.9, 333.2 + 127, 45.9 - 115.9, 334.2 + 127, 0),
            f: 1
        }],
        ['b', 12.6 - 115.9, 327.4 + 127, 29.6 - 115.9, 333.2 + 127, 45.9 - 115.9, 334.2 + 127, {
            x: 0.4,
            y: 0.63,
            r: ROTATE_VERTICAL
        }],
        ['b', 84.5 - 115.9, 336.5 + 127, 0, 308.1 + 127, 0, 269.4 + 127, {
            x: 0.4,
            y: 0.63,
            r: ROTATE_HORIZONTAL
        }],
        ['l', 0, 0 + 127 + 3, {
            y: -3
        }],
    ]
}];

export const LATIN = {
    'Æ': generateFontData(
        996, 426, 352,
        0, 0, 0, 0,
        [{
            d: -1,
            v: [
                ['m', 426.0, 0.0, {
                    x: 0,
                    r: ROTATE_VERTICAL
                }],
                ['l', 234.0, 0.0, {
                    x: 0.5,
                    f: 1,
                    r: getR(234.0, 0.0, .0, 352.0),
                }],
                ['l', 0.0, 352.0, {
                    x: 0.5,
                    y: 0.5,
                    f: 1
                }],
            ]
        }, {
            d: -1,
            v: [
                ['m', 234.0, 0.0, {
                    x: 0.5,
                    p: 1,
                }],
                ['l', 234.0, 352.0, {
                    f: 1,
                    x: 0.5
                }],
                ['l', 426.0, 352.0, {
                    f: 1,
                    x: 0
                }]
            ]
        }, {
            d: -1,
            v: [
                ['m', 76.4, 237.0, {
                    r: ROTATE_VERTICAL,
                    p: 1,
                }],
                ['l', 234.0, 237.0, {
                    f: 1,
                    r: ROTATE_VERTICAL,
                    p: 1,
                }]
            ]
        }, {
            d: -1,
            v: [
                ['m', 234.0, 164.0, {
                    r: ROTATE_VERTICAL,
                    p: 1,
                    x: 0.5
                }],
                ['l', 414.0, 164.0, {
                    f: 1,
                    x: 0
                }]
            ]
        }]
    ),
    'æ': generateFontData(
        1000, 232 + 225.5, 232,
        0, 0, -64, -64,
        [{
            d: -1,
            v: [
                ['m', 232, 8, {
                    y: -3.4,
                    r: ROTATE_HORIZONTAL
                }],
                ['l', 232, 116, {
                    r: ROTATE_NONE
                }],
                ['b', 232, 180.1, 180.1, 232, 116, 232, {
                    r: ROTATE_VERTICAL
                }],
                ['b', 51.9, 232, 0, 180.1, 0, 116, {
                    r: ROTATE_HORIZONTAL
                }],
                ['b', 0, 51.9, 51.9, 0, 116, 0, {
                    r: ROTATE_VERTICAL
                }],
                ['b', 180.1, 0, 232, 51.9, 232, 116, {
                    r: ROTATE_HORIZONTAL
                }],
                ['l', 232, 224, {
                    y: -0.1,
                    r: ROTATE_HORIZONTAL,
                    f: 1
                }]
            ]
        }, {
            d: 1,
            v: [
                ['m', 211.6 + 232, 182.9, {
                    r: getCurveR(211.6 + 232, 182.9, 191.1 + 232, 213.2, 156.1 + 232, 233.1, 116.5 + 232, 233.1, 0),
                    f: 1
                }],
                ['b', 191.1 + 232, 213.2, 156.1 + 232, 233.1, 116.5 + 232, 233.1, {
                    r: ROTATE_VERTICAL
                }],
                ['b', 52.4 + 232, 233.1, 0.5 + 232, 181.2, 0.5 + 232, 117.1, {
                    r: ROTATE_HORIZONTAL
                }],
                ['b', 0.5 + 232, 53, 52.4 + 232, 1.1, 116.5 + 232, 1.1, {
                    r: ROTATE_VERTICAL
                }],
                ['b', 176.4 + 232, 1.1, 224.9 + 232, 47.2, 225.5 + 232, 106.1, {
                    r: ROTATE_HORIZONTAL
                }],
                ['l', 0.5 + 232, 106.1, {
                    r: ROTATE_HORIZONTAL,
                    p: 1
                }],
            ]
        }]
    ),
    'À': generateFontData(
        620, 290, 352,
        0, 0, 0, 0,
        JSON.parse(JSON.stringify(DATA_UA)).concat(getLatin1(145, -50))
    ),
    'Á': generateFontData(
        620, 290, 352,
        0, 0, 0, 0,
        JSON.parse(JSON.stringify(DATA_UA)).concat(getLatin2(145, -50))
    ),
    'Â': generateFontData(
        620, 290, 352,
        0, 0, 0, 0,
        JSON.parse(JSON.stringify(DATA_UA)).concat(getLatin3(145, -100))
    ),
    'Ã': generateFontData(
        620, 290, 352,
        0, 0, 0, 0,
        JSON.parse(JSON.stringify(DATA_UA)).concat(getLatin4(145, -90))
    ),
    'Ä': generateFontData(
        620, 290, 352,
        0, 0, 0, 0,
        JSON.parse(JSON.stringify(DATA_UA)).concat(getLatin5(145, -70))
    ),
    'Å': generateFontData(
        620, 290, 352,
        0, 0, 0, 0,
        JSON.parse(JSON.stringify(DATA_UA)).concat(getLatin7(0, 0))
    ),
    'Ă': generateFontData(
        620, 290, 352,
        0, 0, 0, 0,
        JSON.parse(JSON.stringify(DATA_UA)).concat(getLatin6(145, -110))
    ),
    'Ą': generateFontData(
        620, 290, 352,
        0, 0, 0, 0,
        JSON.parse(JSON.stringify(DATA_UA)).concat(getLatin10(290, 352))
    ),
    'à': generateFontData(
        600, 232, 232,
        10, 2, -64, -64,
        JSON.parse(JSON.stringify(DATA_LA)).concat(getLatin1(116, -60))
    ),
    'á': generateFontData(
        600, 232, 232,
        10, 2, -64, -64,
        JSON.parse(JSON.stringify(DATA_LA)).concat(getLatin2(116, -60))
    ),
    'â': generateFontData(
        600, 232, 232,
        10, 2, -64, -64,
        JSON.parse(JSON.stringify(DATA_LA)).concat(getLatin3(116, -110))
    ),
    'ã': generateFontData(
        600, 232, 232,
        10, 2, -64, -64,
        JSON.parse(JSON.stringify(DATA_LA)).concat(getLatin4(116, -100))
    ),
    'ä': generateFontData(
        600, 232, 232,
        10, 2, -64, -64,
        JSON.parse(JSON.stringify(DATA_LA)).concat(getLatin5(116, -80))
    ),
    'å': generateFontData(
        600, 232, 232,
        10, 2, -64, -64,
        JSON.parse(JSON.stringify(DATA_LA)).concat(getLatin7(-30, 0))
    ),
    'ă': generateFontData(
        600, 232, 232,
        10, 2, -64, -64,
        JSON.parse(JSON.stringify(DATA_LA)).concat(getLatin6(116, -120))
    ),
    'ą': generateFontData(
        600, 232, 232,
        10, 2, -64, -64,
        JSON.parse(JSON.stringify(DATA_LA)).concat(getLatin10(232, 224))
    ),
    'Ć': generateFontData(
        700, 293.1, 360,
        0, 0, 0, 0,
        JSON.parse(JSON.stringify(DATA_UC)).concat(getLatin1(180, -60))
    ),
    'Ĉ': generateFontData(
        700, 293.1, 360,
        0, 0, 0, 0,
        JSON.parse(JSON.stringify(DATA_UC)).concat(getLatin3(180, -110))
    ),
    'Ċ': generateFontData(
        700, 293.1, 360,
        0, 0, 0, 0,
        JSON.parse(JSON.stringify(DATA_UC)).concat(getLatin11(180, -80))
    ),
    'Č': generateFontData(
        700, 293.1, 360,
        0, 0, 0, 0,
        JSON.parse(JSON.stringify(DATA_UC)).concat(getLatin12(180, -110))
    ),
    'Ç': generateFontData(
        700, 293.1, 360,
        0, 0, 0, 0,
        JSON.parse(JSON.stringify(DATA_UC)).concat(getLatin9(180, 360))
    ),
    'ć': generateFontData(
        520, 212.1, 233.1,
        2, -10, -64, -64,
        JSON.parse(JSON.stringify(DATA_LC)).concat(getLatin1(116.5, 1.1 - 70))
    ),
    'ĉ': generateFontData(
        520, 212.1, 233.1,
        2, -10, -64, -64,
        JSON.parse(JSON.stringify(DATA_LC)).concat(getLatin3(116.5, 1.1 - 120))
    ),
    'ċ': generateFontData(
        520, 212.1, 233.1,
        2, -10, -64, -64,
        JSON.parse(JSON.stringify(DATA_LC)).concat(getLatin11(116.5, 1.1 - 90))
    ),
    'č': generateFontData(
        520, 212.1, 233.1,
        2, -10, -64, -64,
        JSON.parse(JSON.stringify(DATA_LC)).concat(getLatin12(116.5, 1.1 - 120))
    ),
    'ç': generateFontData(
        520, 212.1, 233.1,
        2, -10, -64, -64,
        JSON.parse(JSON.stringify(DATA_LC)).concat(getLatin9(116.5, 233.1))
    ),
    'Đ': generateFontData(
        721, 270, 352,
        -10, -10, 0, 0,
        JSON.parse(JSON.stringify(DATA_UD)).concat(getLatin8(0, 352 / 2))
    ),
    'Ď': generateFontData(
        721, 270, 352,
        -10, -10, 0, 0,
        JSON.parse(JSON.stringify(DATA_UD)).concat(getLatin12(100, -110))
    ),
    'ď': generateFontData(
        600, 232, 352,
        10, 2, 0, 0,
        JSON.parse(JSON.stringify(DATA_LD)).concat(getLatin13(300, 0))
    ),
    'đ': generateFontData(
        600, 232, 352,
        10, 2, 0, 0,
        JSON.parse(JSON.stringify(DATA_LD)).concat(getLatin8(180, 40))
    ),
    'È': generateFontData(
        520, 192, 352,
        -5, -80, 0, 0,
        JSON.parse(JSON.stringify(DATA_UE)).concat(getLatin1(96, -60))
    ),
    'É': generateFontData(
        520, 192, 352,
        -5, -80, 0, 0,
        JSON.parse(JSON.stringify(DATA_UE)).concat(getLatin2(96, -60))
    ),
    'Ê': generateFontData(
        520, 192, 352,
        -5, -80, 0, 0,
        JSON.parse(JSON.stringify(DATA_UE)).concat(getLatin3(96, -110))
    ),
    'Ë': generateFontData(
        520, 192, 352,
        -5, -80, 0, 0,
        JSON.parse(JSON.stringify(DATA_UE)).concat(getLatin5(96, -80))
    ),
    'Ē': generateFontData(
        520, 192, 352,
        -5, -80, 0, 0,
        JSON.parse(JSON.stringify(DATA_UE)).concat(getLatin14(96, -80))
    ),
    'Ĕ': generateFontData(
        520, 192, 352,
        -5, -80, 0, 0,
        JSON.parse(JSON.stringify(DATA_UE)).concat(getLatin6(96, -120))
    ),
    'Ė': generateFontData(
        520, 192, 352,
        -5, -80, 0, 0,
        JSON.parse(JSON.stringify(DATA_UE)).concat(getLatin11(96, -80))
    ),
    'Ě': generateFontData(
        520, 192, 352,
        -5, -80, 0, 0,
        JSON.parse(JSON.stringify(DATA_UE)).concat(getLatin12(96, -110))
    ),
    'è': generateFontData(
        570, 225.5, 233.1,
        0, 0, -64, -64,
        JSON.parse(JSON.stringify(DATA_LE)).concat(getLatin1(112, -60))
    ),
    'é': generateFontData(
        570, 225.5, 233.1,
        0, 0, -64, -64,
        JSON.parse(JSON.stringify(DATA_LE)).concat(getLatin2(112, -60))
    ),
    'ê': generateFontData(
        570, 225.5, 233.1,
        0, 0, -64, -64,
Download .txt
gitextract_04kbmd_5/

├── .gitignore
├── LICENSE
├── README.md
├── dist/
│   └── leon.js
├── examples/
│   ├── all.html
│   ├── canvas-basic.html
│   ├── color-pattern.html
│   ├── colorful.html
│   ├── gradient.html
│   ├── grid.html
│   ├── index.html
│   ├── js/
│   │   └── util.js
│   ├── mask-tiling-pixi.html
│   ├── metaball-pixi.html
│   ├── morphing-pixi.html
│   ├── pattern.html
│   ├── plants-pixi.html
│   ├── wave.html
│   └── webgl-basic-pixi.html
└── src/
    ├── core/
    │   ├── align.js
    │   ├── dispatcher.js
    │   ├── group.js
    │   ├── guide.js
    │   ├── length.js
    │   ├── model.js
    │   ├── paths.js
    │   ├── point.js
    │   ├── util.js
    │   └── vector.js
    ├── draw/
    │   ├── canvas/
    │   │   ├── color.js
    │   │   ├── colorful.js
    │   │   ├── grids.js
    │   │   ├── lines.js
    │   │   ├── pattern.js
    │   │   ├── points.js
    │   │   └── wave.js
    │   └── pixi/
    │       ├── color.js
    │       └── lines.js
    ├── font/
    │   ├── index.js
    │   ├── latin.js
    │   ├── latinutil.js
    │   ├── lower.js
    │   ├── number.js
    │   ├── special.js
    │   ├── upper.js
    │   └── util.js
    ├── index.js
    └── leonsans.js
Download .txt
SYMBOL INDEX (362 symbols across 30 files)

FILE: dist/leon.js
  function i (line 8) | function i(e){if(r[e])return r[e].exports;var a=r[e]={i:e,l:!1,exports:{...
  function s (line 8) | function s(t,r){var i=arguments.length>2&&void 0!==arguments[2]?argument...
  function n (line 8) | function n(t,r,i){return{x:t/2,y:(r-130*.49*i)/2}}
  function l (line 8) | function l(t,r,i){return{r:r,cr:i,fr1:1,fr2:.78,gx1:t.ratio.x1,gx2:t.rat...
  function f (line 8) | function f(t,r,i,e,a){var s=(e-a)/(r-i)*(t-i)+a;return s<a?s=a:s>e&&(s=e...
  function o (line 8) | function o(t){var r,i,e,a,s,n,l,o,h,y,d,c=t.typo.p.length,p=[];for(r=0;r...
  function h (line 8) | function h(t,r){var i,e,a=t.length,s=[];for(i=0;i<a;i++)e=t[i].addRect(r...
  function y (line 8) | function y(t,r){var i,e,s,n=r.lines.length;for(i=0;i<n;i++)"a"==(s=(e=r....
  function d (line 8) | function d(t,r){t.save(),t.lineWidth=1;var i,e=r.lines.length;for(i=0;i<...
  function c (line 8) | function c(t,r,i){var e,s,n,l=r.v.length;for(e=0;e<l;e++)n=(s=r.cv[e]).a...
  function p (line 8) | function p(t,r){var i=r.pos;"a"!=i.type&&("m"==i.type?(t.strokeStyle="#f...
  function v (line 8) | function v(t,r){t.save(),t.beginPath(),t.lineWidth=1,t.strokeStyle="#aaa...
  function b (line 8) | function b(t,r,i,e,s,n){var l,f,o,h,y,d=r.wavePaths.length,c=function(t,...
  function S (line 8) | function S(t,r,i,e){var s,n,l=Math.round(r.paths.length*r.drawing.value)...
  function m (line 8) | function m(t,r,i,e){var a=e.length,s=(r+a*(Math.abs(r/10|0)+1))%a;if(Arr...
  function O (line 8) | function O(t,r){var i,e,a=t.typo.p.length,s=[],n=[],l=0;for(e=0;e<a;e++)...
  function J (line 8) | function J(t,r,i){var e,a,s,n,l,f,o=r.length,h=[],y=0;for(e=0;e<o;e++)s=...
  function N (line 8) | function N(t,r,i,e,a,s,n,l,f){var o,h,y,d,c=f||40,p=0,v=t,x=r;for(y=1;y<...
  function _ (line 8) | function _(t,r,i,e,a,s,n,l,f){return r+=(e-r)*t,i+=(a-i)*t,{x:(r+=((e+=(...
  function w (line 8) | function w(t,r,i,e){var a=i-t,s=e-r;return Math.sqrt(a*a+s*s)}
  function k (line 8) | function k(t){var r=function(){++W==P&&(W=0);return x[W]}();t.fillStyle=...
  function D (line 8) | function D(t,r,i,e,a,s){var n=i/e,l=f(a.drawing.value,s+n,s,1,0);if(1==r...
  function T (line 8) | function T(t,r,i,e){var a,s;if(1==r.drawing.value)for(a=r.lines.length,s...
  function I (line 8) | function I(t,r,i,e){var a=r.pos;"a"==a.type?(t.lineStyle(0,e,0),t.beginF...
  function R (line 8) | function R(t,r,i,e,a){"a"==r.type?(t.lineStyle(0,e,0),t.beginFill(e),t.d...
  function F (line 8) | function F(t,r,i){var e=i.length,a=(t+e*(Math.abs(t/10|0)+1))%e;if(!Arra...
  function M (line 8) | function M(t,r){var i,e,a,s=[];for(i=0;i<6;i++)e=10*i+20,a=10*i+90,s[i]=...
  function G (line 8) | function G(t,r){var i,e=[],a=[98,340,815];for(i=0;i<3;i++)e[i]=.49*a[i]*...
  function z (line 8) | function z(t){Object.assign(this,t)}
  function L (line 8) | function L(t){this.type=t[0],this.x=t[1]||0,this.y=t[2]||0,"b"==this.typ...
  function j (line 8) | function j(t,r,i,e){var a=r.range.r*i.x,s=(r.range.gx2-r.range.gx1)*a+r....
  function C (line 8) | function C(t,r,i,e){var a=r.range.r*i.y,s=(r.range.gy2-r.range.gy1)*a+r....
  function q (line 8) | function q(t,r,i,e){var a,s,n,l,f,o=r.pointsLength.lines,h=t.scale,y=o.l...
  function X (line 8) | function X(t,r,i){var e,a,s,n,l,o,h,y=t.length,d=[],c=1,p=1;for(r>-1&&(p...
  function E (line 8) | function E(t,r,i,e){if(t.type=i.type,t.distance=i.distance,t.num=e,r&&nu...
  function B (line 8) | function B(t,r){var i=H(t.x1,t.x2,t.x3,t.x4,r),e=H(t.y1,t.y2,t.y3,t.y4,r...
  function H (line 8) | function H(t,r,i,e,a){var s=a*a;return t+(3*-t+a*(3*t-t*a))*a+(3*r+a*(-6...
  function K (line 8) | function K(t,r,i,e,a){return 3*a*a*(3*r-t-3*i+e)+6*a*(t-2*r+i)+3*(-t+r)}
  function Y (line 8) | function Y(t,r,i,e,a,s,n,l){var f,o=[],h=l.length;for(f=0;f<h;f++)o.push...
  function Z (line 8) | function Z(t,r,i){var e,a,s=t.length,n=r/2,l=i/2,f=[];for(a=0;a<s;a++)(e...
  function $ (line 8) | function $(t,r,i,e){var a=t-i,s=r-e;return-Math.atan2(a,s)}
  function tt (line 8) | function tt(t,r,i,e,a,s,n,l,f){var o=K(t,i,a,n,f),h=K(r,e,s,l,f);return-...
  function kt (line 8) | function kt(t,r){var i=t,e=-60+r;return[{d:-1,v:[["m",-40+i,e,{x:0,y:0,r...
  function Dt (line 8) | function Dt(t,r){var i=t,e=-60+r;return[{d:-1,v:[["m",40+i,e,{x:0,y:0,r:...
  function Tt (line 8) | function Tt(t,r){var i=-68+t,e=0+r;return[{d:-1,v:[["m",0+i,50+e,{r:$(0+...
  function It (line 8) | function It(t,r){var i=t-76.24,e=r;return[{d:1,v:[["m",159.52+i,16.56+e,...
  function Rt (line 8) | function Rt(t,r){return[{d:1,v:[["a",-50+t,r,{x:0,y:0}]]},{d:1,v:[["a",5...
  function Ft (line 8) | function Ft(t,r){var i=t-57,e=r;return[{d:1,v:[["m",112.7+i,0+e,{r:tt(11...
  function Mt (line 8) | function Mt(t,r){var i=88+t,e=-116+r;return[{d:1,v:[["m",116+i,58+e,{r:Q...
  function Gt (line 8) | function Gt(t,r){return[{d:1,v:[["m",t-40,r,{x:0,y:1,r:U}],["l",100+t,r,...
  function zt (line 8) | function zt(t,r){return[{d:-1,v:[["m",t,r,{p:1}],["b",9.3+t,11.6+r,15.6+...
  function Lt (line 8) | function Lt(t,r){return[{d:-1,v:[["m",t,r,{p:1}],["b",-19.6+t,14.8+r,-42...
  function jt (line 8) | function jt(t,r){return[{d:1,v:[["a",t,r,{x:0,y:0}]]}]}
  function Ct (line 8) | function Ct(t,r){var i=-68+t,e=r;return[{d:-1,v:[["m",0+i,e,{r:$(0+i,e,6...
  function At (line 8) | function At(t,r){return[{d:1,v:[["m",t-50,r,{x:0,y:0}],["l",t+50,r,{x:0,...
  function Qt (line 8) | function Qt(t){var r=(Kt[t]||Kt.tofu).clone();return r.v=t,r}
  function Ut (line 8) | function Ut(t,r,i,e){var a;return a=t.indexOf("\n")>0?t.split("\n"):t.in...
  function Vt (line 8) | function Vt(t,r){return{c:(t-r)/2,r:t-r,l:0}}
  class Yt (line 8) | class Yt{constructor(){this.lineWidth_=1,this.drawing_=[],this.data_=nul...
    method constructor (line 8) | constructor(){this.lineWidth_=1,this.drawing_=[],this.data_=null,this....
    method data (line 8) | get data(){return this.data_}
    method paths (line 8) | get paths(){return this.paths_}
    method lines (line 8) | get lines(){return this.lines_}
    method lines (line 8) | set lines(t){this.lines_=t}
    method lineWidth (line 8) | get lineWidth(){return this.lineWidth_}
    method fontRatio (line 8) | get fontRatio(){return this.fontRatio_}
    method scale (line 8) | get scale(){return this.scale_}
    method rect (line 8) | get rect(){return this.rect_}
    method drawing (line 8) | get drawing(){return this.drawing_}
    method align (line 8) | set align(t){this.align_!=t&&(this.align_=t,this.setPosition())}
    method align (line 8) | get align(){return this.align_}
    method position (line 8) | position(t,r){return(this.rect_.x!=t||this.rect_.y!=r)&&(this.rect_.x=...
    method setPosition (line 8) | setPosition(){var t,r,i,e,a=this.data_.length;for(t=0;t<a;t++)(r=this....
    method updateDrawingPaths (line 8) | updateDrawingPaths(){var t,r,i=this.data_.length;for(t=0;t<i;t++)(r=th...
    method updatePatternPaths (line 8) | updatePatternPaths(t){var r,i,e=this.data_.length;for(r=0;r<e;r++)(i=t...
    method updateWavePaths (line 8) | updateWavePaths(t){var r,i,e=this.data_.length;for(r=0;r<e;r++)(i=this...
    method updateGuide (line 8) | updateGuide(){var t,r,i=this.data_.length;for(t=0;t<i;t++)(r=this.data...
    method update (line 8) | update(t,r,i,a,f,o,h){var y=function(t){return(70-e)/(900-e)*(t-e)+e}(...
    method updatePathsForRect (line 8) | updatePathsForRect(){var t,r,i=this.data_.length,e=[];for(t=0;t<i;t++)...
    method updateLinesForRect (line 8) | updateLinesForRect(){var t,r,i=this.data_.length;for(t=0;t<i;t++)(r=th...
    method reset (line 8) | reset(){this.lineWidth_=1,this.drawing_=[],this.data_=null,this.paths_...
  class Zt (line 8) | class Zt extends class{constructor(){this.handlers_={update:{listeners:[...
    method constructor (line 8) | constructor(){this.handlers_={update:{listeners:[]}}}
    method on (line 8) | on(t,r){return"function"!=typeof r?(console.error("The listener callba...
    method off (line 8) | off(t,r){if(void 0===this.handlers_[t])return console.error("This even...
    method dispatch (line 8) | dispatch(t,r){this.handlers_[t].listeners.forEach(t=>{t(r)})}
    method constructor (line 8) | constructor(){var{text:t="",size:r=500,weight:i=e,color:a=["#000000"],...
    method on (line 8) | on(t,r){super.on(t,r),this.update()}
    method off (line 8) | off(t,r){super.off(t,r)}
    method text (line 8) | get text(){return this.str_}
    method text (line 8) | set text(t){this.str_!=t&&(this.str_=t,this.update())}
    method size (line 8) | get size(){return this.size_}
    method size (line 8) | set size(t){this.size_!=t&&(this.size_=t,this.update(),this.isForceRan...
    method weight (line 8) | get weight(){return this.weight_}
    method weight (line 8) | set weight(t){t<e?t=e:t>900&&(t=900),this.weight_!=t&&(this.weight_=t,...
    method color (line 8) | get color(){return this.color_}
    method color (line 8) | set color(t){this.color_!=t&&(this.color_=t)}
    method tracking (line 8) | get tracking(){return this.tracking_}
    method tracking (line 8) | set tracking(t){this.tracking_!=t&&(this.tracking_=t,this.update(),thi...
    method leading (line 8) | get leading(){return this.leading_}
    method leading (line 8) | set leading(t){this.leading_!=t&&(this.leading_=t,this.update(),this.i...
    method align (line 8) | get align(){return this.model.align}
    method align (line 8) | set align(t){this.model.align!=t&&(this.model.align=t,this.updateID_++...
    method pathGap (line 8) | get pathGap(){return this.pathGap_}
    method pathGap (line 8) | set pathGap(t){this.pathGap_!=t&&(this.pathGap_=t,this.updatePatternPa...
    method amplitude (line 8) | get amplitude(){return this.amplitude_}
    method amplitude (line 8) | set amplitude(t){this.amplitude_=t}
    method rect (line 8) | get rect(){return this.model.rect}
    method maxWidth (line 8) | set maxWidth(t){this.width_!=t&&(this.width_=t,this.update())}
    method maxWidth (line 8) | get maxWidth(){return this.width_}
    method breakWord (line 8) | set breakWord(t){this.breakWord_!=t&&(this.breakWord_=t,this.update())}
    method breakWord (line 8) | get breakWord(){return this.breakWord_}
    method isPath (line 8) | get isPath(){return this.isPath_}
    method isPath (line 8) | set isPath(t){this.isPath_=t,this.updatePatternPaths(!0)}
    method isWave (line 8) | get isWave(){return this.isWave_}
    method isWave (line 8) | set isWave(t){this.isWave_=t,this.updateWavePaths(!0)}
    method fps (line 8) | get fps(){return this.fps_}
    method fps (line 8) | set fps(t){this.fps_=t,this.fpsTime_=1e3/this.fps_}
    method lineWidth (line 8) | get lineWidth(){return this.model.lineWidth}
    method scale (line 8) | get scale(){return this.model.scale}
    method drawing (line 8) | get drawing(){return this.model.drawing}
    method data (line 8) | get data(){return this.model.data}
    method paths (line 8) | get paths(){return this.model.paths}
    method drawingPaths (line 8) | get drawingPaths(){return this.model.drawingPaths}
    method wavePaths (line 8) | get wavePaths(){return this.model.wavePaths}
    method position (line 8) | position(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0...
    method update (line 8) | update(){this.updateID_++,this.model.update(this.str_,this.width_,this...
    method updateGuide (line 8) | updateGuide(){this.guideID_!=this.updateID_&&(this.guideID_=this.updat...
    method updateDrawingPaths (line 8) | updateDrawingPaths(){this.dPathsID_!=this.updateID_&&(this.dPathsID_=t...
    method updatePatternPaths (line 8) | updatePatternPaths(t){this.isPath_&&(t||this.pPathsID_!=this.updateID_...
    method updateWavePaths (line 8) | updateWavePaths(t){this.isWave_&&(t||this.wPathsID_!=this.updateID_)&&...
    method updateSignal (line 8) | updateSignal(){this.model.updateLinesForRect(),this.model.updatePathsF...
    method reset (line 8) | reset(){this.size_=500,this.weight_=e,this.color_=["#000000"],this.tra...
    method dispose (line 8) | dispose(){this.reset(),this.model=null}
    method drawPixi (line 8) | drawPixi(t){var r,i,e,a=this.model.data.length;for(r=0;r<a;r++)i=this....
    method draw (line 8) | draw(t){t.lineWidth=this.lineWidth;var r,i,e=this.model.data.length;fo...
    method drawColorful (line 8) | drawColorful(t){t.lineWidth=this.lineWidth,function(t,r,i){W=-1,P=(x=i...
    method wave (line 8) | wave(t,r){(t.lineWidth=this.lineWidth,r)&&(this.time_||(this.time_=r),...
    method pattern (line 8) | pattern(t,r,i){var e,a=r*this.model.scale,s=i*this.model.scale,n=this....
    method grid (line 8) | grid(t){this.updateGuide();var r,i=this.model.data.length;for(r=0;r<i;...
    method point (line 8) | point(t){var r,i=this.model.data.length;for(r=0;r<i;r++)d(t,this.model...
    method box (line 8) | box(t){t.lineWidth=1,t.beginPath(),t.strokeStyle="#0b90dc",t.rect(this...

FILE: examples/js/util.js
  function generateCanvas (line 8) | function generateCanvas() {
  function canvasResize (line 19) | function canvasResize() {
  function generatePixi (line 30) | function generatePixi(bgcolor) {
  function pixiResize (line 50) | function pixiResize() {
  function moveEvent (line 57) | function moveEvent(canvas) {
  function getSize (line 70) | function getSize(size) {

FILE: src/core/align.js
  function setAlignGapX (line 1) | function setAlignGapX(sw, tw) {
  function getAlignGapX (line 9) | function getAlignGapX(align, alignGapX) {

FILE: src/core/dispatcher.js
  class Dispatcher (line 1) | class Dispatcher {
    method constructor (line 2) | constructor() {
    method on (line 10) | on(event, callback) {
    method off (line 30) | off(event, callback) {
    method dispatch (line 41) | dispatch(event, data) {

FILE: src/core/group.js
  function getTextGroup (line 8) | function getTextGroup(text, scale, width, isBreakAll) {
  function keepAll (line 22) | function keepAll(group) {
  function breakWord (line 32) | function breakWord(group, scale, width) {
  function breakAll (line 81) | function breakAll(group, scale, width) {

FILE: src/core/guide.js
  function getGuide (line 12) | function getGuide(d, scale) {
  function getGrid (line 37) | function getGrid(d, scale) {

FILE: src/core/length.js
  function getLengths (line 1) | function getLengths(item, model) {
  function getEachPath (line 22) | function getEachPath(item, points, model) {
  function cubicBezierLength (line 82) | function cubicBezierLength(x1, y1, x2, y2, x3, y3, x4, y4, sampleCount) {
  function cubicQxy (line 102) | function cubicQxy(t, x1, y1, x2, y2, x3, y3, x4, y4) {
  function distance (line 119) | function distance(x1, y1, x2, y2) {

FILE: src/core/model.js
  class Model (line 38) | class Model {
    method constructor (line 39) | constructor() {
    method data (line 56) | get data() {
    method paths (line 60) | get paths() {
    method lines (line 64) | get lines() {
    method lines (line 68) | set lines(v) {
    method lineWidth (line 72) | get lineWidth() {
    method fontRatio (line 76) | get fontRatio() {
    method scale (line 80) | get scale() {
    method rect (line 84) | get rect() {
    method drawing (line 88) | get drawing() {
    method align (line 92) | set align(v) {
    method align (line 99) | get align() {
    method position (line 103) | position(x, y) {
    method setPosition (line 114) | setPosition() {
    method updateDrawingPaths (line 124) | updateDrawingPaths() {
    method updatePatternPaths (line 133) | updatePatternPaths(pathGap) {
    method updateWavePaths (line 142) | updateWavePaths(pathGap) {
    method updateGuide (line 151) | updateGuide() {
    method update (line 161) | update(text, width, breakWord, weight, size, tracking, leading) {
    method updatePathsForRect (line 268) | updatePathsForRect() {
    method updateLinesForRect (line 286) | updateLinesForRect() {
    method reset (line 295) | reset() {

FILE: src/core/paths.js
  function getPaths (line 21) | function getPaths(model, data, pathGap, isPattern) {
  function getDotPos (line 71) | function getDotPos(lines, pathGap, scale) {
  function setPointValues (line 155) | function setPointValues(cur, prev, line, num) {
  function getCubicBezierXYatT (line 176) | function getCubicBezierXYatT(line, t) {
  function CubicN (line 190) | function CubicN(a, b, c, d, t) {
  function bezierTangent (line 198) | function bezierTangent(a, b, c, d, t) {

FILE: src/core/point.js
  function Point (line 1) | function Point(mp) {

FILE: src/core/util.js
  constant DEFAULT_FONT_SIZE (line 1) | const DEFAULT_FONT_SIZE = 500;
  constant MIN_FONT_WEIGHT (line 2) | const MIN_FONT_WEIGHT = 1;
  constant MAX_FONT_WEIGHT (line 3) | const MAX_FONT_WEIGHT = 900;
  constant MAX_LINE_WIDTH (line 4) | const MAX_LINE_WIDTH = 70;
  constant FONT_WEIGHT_LIMIT (line 5) | const FONT_WEIGHT_LIMIT = 80;
  constant FR_1 (line 6) | const FR_1 = 1;
  constant FR_2 (line 7) | const FR_2 = 0.78;
  constant RECT_RATIO (line 8) | const RECT_RATIO = 0.49;
  constant MAX_SHAKE (line 9) | const MAX_SHAKE = 120;
  constant PI2 (line 10) | const PI2 = 2 * Math.PI;
  function getAmplitude (line 12) | function getAmplitude(amplitude, scale) {
  function getFontW (line 16) | function getFontW(weight) {
  function getWeightRatio (line 20) | function getWeightRatio(fontW) {
  function getCircleRound (line 24) | function getCircleRound(fontW) {
  function getScale (line 28) | function getScale(size) {
  function getLineW (line 32) | function getLineW(fontW, scale) {
  function getTracking (line 39) | function getTracking(tracking, scale) {
  function getLeading (line 43) | function getLeading(leading, scale) {
  function getFontRatio (line 47) | function getFontRatio(weightRatio) {
  function getRect (line 51) | function getRect(d, scale, x = 0, y = 0) {
  function getCenter (line 92) | function getCenter(w, h, scale) {
  function getRange (line 109) | function getRange(d, weightRatio, circleRound) {
  function getCurrent (line 126) | function getCurrent(v, vmax, vmin, max, min) {
  function getLines (line 133) | function getLines(data) {
  function addRectToPaths (line 184) | function addRectToPaths(path, data) {
  function randomBrightColor (line 196) | function randomBrightColor() {
  function shuffle (line 202) | function shuffle(oldArray) {

FILE: src/core/vector.js
  function Vector (line 5) | function Vector(mp) {
  function convertR (line 83) | function convertR(type, pos, model) {
  function convertX (line 89) | function convertX(x, pos, ratio, model) {
  function convertY (line 96) | function convertY(y, pos, ratio, model) {

FILE: src/draw/canvas/color.js
  function Color (line 1) | function Color(ctx, no, data, color) {

FILE: src/draw/canvas/colorful.js
  constant MIN_DISTANCE (line 13) | const MIN_DISTANCE = 10;
  function Colorful (line 15) | function Colorful(ctx, model, colors) {
  function setColor (line 68) | function setColor(ctx) {
  function getColor (line 74) | function getColor() {
  function draw (line 80) | function draw(ctx, line, length, max, d, prevRatio) {

FILE: src/draw/canvas/grids.js
  function Grids (line 1) | function Grids(ctx, data) {

FILE: src/draw/canvas/lines.js
  function Lines (line 5) | function Lines(ctx, data) {

FILE: src/draw/canvas/pattern.js
  function Pattern (line 5) | function Pattern(ctx, data, w, h) {

FILE: src/draw/canvas/points.js
  function Points (line 5) | function Points(ctx, data) {
  function eachPoint_ (line 24) | function eachPoint_(ctx, p, data) {
  function eachLine_ (line 59) | function eachLine_(ctx, d) {

FILE: src/draw/canvas/wave.js
  constant THIN_LIMIT (line 6) | const THIN_LIMIT = 110;
  constant COS (line 7) | const COS = Math.cos;
  constant SIN (line 8) | const SIN = Math.sin;
  function Wave (line 10) | function Wave(ctx, data, scale, amplitude, weight, fps) {

FILE: src/draw/pixi/color.js
  function PixiColor (line 1) | function PixiColor(no, data, color) {

FILE: src/draw/pixi/lines.js
  function PixiLines (line 1) | function PixiLines(graphics, data, lineW, color) {
  function eachLine_ (line 17) | function eachLine_(graphics, data, lineW, color) {
  function eachPath_ (line 37) | function eachPath_(graphics, pos, lineW, color, dValue) {

FILE: src/font/index.js
  constant DATA (line 20) | const DATA = Object.assign({}, UPPER, LOWER, NUMBER, SPECIAL, LATIN);
  function typo (line 22) | function typo(v) {

FILE: src/font/latin.js
  constant DATA_LI (line 54) | const DATA_LI = [{
  constant DATA_LJ (line 67) | const DATA_LJ = [{
  constant LATIN (line 92) | const LATIN = {

FILE: src/font/latinutil.js
  function getLatin1 (line 10) | function getLatin1(x, y) {
  function getLatin2 (line 30) | function getLatin2(x, y) {
  function getLatin3 (line 50) | function getLatin3(x, y) {
  function getLatin4 (line 83) | function getLatin4(x, y) {
  function getLatin5 (line 117) | function getLatin5(x, y) {
  function getLatin6 (line 137) | function getLatin6(x, y) {
  function getLatin7 (line 177) | function getLatin7(x, y) {
  function getLatin8 (line 206) | function getLatin8(x, y) {
  function getLatin9 (line 224) | function getLatin9(x, y) {
  function getLatin10 (line 241) | function getLatin10(x, y) {
  function getLatin11 (line 259) | function getLatin11(x, y) {
  function getLatin12 (line 272) | function getLatin12(x, y) {
  function getLatin13 (line 306) | function getLatin13(x, y) {
  function getLatin14 (line 323) | function getLatin14(x, y) {

FILE: src/font/lower.js
  constant DATA_LA (line 12) | const DATA_LA = [{
  constant DATA_LC (line 42) | const DATA_LC = [{
  constant DATA_LD (line 62) | const DATA_LD = [{
  constant DATA_LE (line 90) | const DATA_LE = [{
  constant DATA_LG (line 116) | const DATA_LG = [{
  constant DATA_LH (line 149) | const DATA_LH = [{
  constant DATA_LN (line 181) | const DATA_LN = [{
  constant DATA_LO (line 213) | const DATA_LO = [{
  constant DATA_LS (line 237) | const DATA_LS = [{
  constant DATA_LU (line 253) | const DATA_LU = [{
  constant DATA_LY (line 286) | const DATA_LY = [{
  constant LOWER (line 320) | const LOWER = {

FILE: src/font/number.js
  constant NUMBER (line 11) | const NUMBER = {

FILE: src/font/special.js
  constant SPECIAL (line 11) | const SPECIAL = {

FILE: src/font/upper.js
  constant DATA_UA (line 11) | const DATA_UA = [{
  constant DATA_UC (line 51) | const DATA_UC = [{
  constant DATA_UD (line 65) | const DATA_UD = [{
  constant DATA_UE (line 93) | const DATA_UE = [{
  constant DATA_UG (line 133) | const DATA_UG = [{
  constant DATA_UH (line 156) | const DATA_UH = [{
  constant DATA_UI (line 200) | const DATA_UI = [{
  constant DATA_UJ (line 215) | const DATA_UJ = [{
  constant DATA_UN (line 233) | const DATA_UN = [{
  constant DATA_UO (line 268) | const DATA_UO = [{
  constant DATA_US (line 292) | const DATA_US = [{
  constant DATA_UU (line 308) | const DATA_UU = [{
  constant DATA_UY (line 331) | const DATA_UY = [{
  constant UPPER (line 365) | const UPPER = {

FILE: src/font/util.js
  constant ROTATE_HORIZONTAL (line 8) | const ROTATE_HORIZONTAL = 180 * (Math.PI / 180);
  constant ROTATE_VERTICAL (line 9) | const ROTATE_VERTICAL = 90 * (Math.PI / 180);
  constant ROTATE_NONE (line 10) | const ROTATE_NONE = -100;
  constant VERTEX_GAP (line 11) | const VERTEX_GAP = 3;
  constant VERTEX_GAP2 (line 12) | const VERTEX_GAP2 = VERTEX_GAP / 2;
  constant TOFU (line 13) | const TOFU = 'tofu';
  constant FONT_HEIGHT (line 14) | const FONT_HEIGHT = 824;
  function generateFontData (line 16) | function generateFontData(w, fw, fh, x1, x2, y1, y2, path) {
  function setCenter (line 69) | function setCenter(arr, fw, fh) {
  function getR (line 91) | function getR(x1, y1, x2, y2) {
  function getCurveR (line 97) | function getCurveR(x1, y1, x2, y2, x3, y3, x4, y4, t) {

FILE: src/leonsans.js
  class LeonSans (line 48) | class LeonSans extends Dispatcher {
    method constructor (line 49) | constructor({
    method on (line 102) | on(event, callback) {
    method off (line 107) | off(event, callback) {
    method text (line 111) | get text() {
    method text (line 115) | set text(str) {
    method size (line 121) | get size() {
    method size (line 125) | set size(v) {
    method weight (line 132) | get weight() {
    method weight (line 136) | set weight(v) {
    method color (line 148) | get color() {
    method color (line 152) | set color(v) {
    method tracking (line 157) | get tracking() {
    method tracking (line 161) | set tracking(v) {
    method leading (line 168) | get leading() {
    method leading (line 172) | set leading(v) {
    method align (line 179) | get align() {
    method align (line 183) | set align(v) {
    method pathGap (line 191) | get pathGap() {
    method pathGap (line 195) | set pathGap(v) {
    method amplitude (line 204) | get amplitude() {
    method amplitude (line 208) | set amplitude(v) {
    method rect (line 212) | get rect() {
    method maxWidth (line 216) | set maxWidth(v) {
    method maxWidth (line 222) | get maxWidth() {
    method breakWord (line 226) | set breakWord(v) {
    method breakWord (line 232) | get breakWord() {
    method isPath (line 236) | get isPath() {
    method isPath (line 240) | set isPath(v) {
    method isWave (line 245) | get isWave() {
    method isWave (line 249) | set isWave(v) {
    method fps (line 254) | get fps() {
    method fps (line 258) | set fps(v) {
    method lineWidth (line 263) | get lineWidth() {
    method scale (line 267) | get scale() {
    method drawing (line 271) | get drawing() {
    method data (line 275) | get data() {
    method paths (line 279) | get paths() {
    method drawingPaths (line 283) | get drawingPaths() {
    method wavePaths (line 287) | get wavePaths() {
    method position (line 291) | position(x = 0, y = 0) {
    method update (line 298) | update() {
    method updateGuide (line 319) | updateGuide() {
    method updateDrawingPaths (line 329) | updateDrawingPaths() {
    method updatePatternPaths (line 340) | updatePatternPaths(force) {
    method updateWavePaths (line 353) | updateWavePaths(force) {
    method updateSignal (line 362) | updateSignal() {
    method reset (line 368) | reset() {
    method dispose (line 398) | dispose() {
    method drawPixi (line 407) | drawPixi(graphics) {
    method draw (line 421) | draw(ctx) {
    method drawColorful (line 436) | drawColorful(ctx) {
    method wave (line 446) | wave(ctx, t) {
    method pattern (line 476) | pattern(ctx, w, h) {
    method grid (line 492) | grid(ctx) {
    method point (line 507) | point(ctx) {
    method box (line 521) | box(ctx) {
Condensed preview — 48 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (330K chars).
[
  {
    "path": ".gitignore",
    "chars": 44,
    "preview": "\nexamples/.DS_Store\nexamples/data/.DS_Store\n"
  },
  {
    "path": "LICENSE",
    "chars": 1068,
    "preview": "MIT License\n\nCopyright (c) 2019 Jongmin Kim\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
  },
  {
    "path": "README.md",
    "chars": 9481,
    "preview": "# Leon Sans\nLeon Sans is a geometric sans-serif typeface made with code in 2019 by Jongmin Kim. It allows to change font"
  },
  {
    "path": "dist/leon.js",
    "chars": 59396,
    "preview": "/*!\n * VERSION: 1.6.5\n * DATE: 2020-09-20\n * https://leon-sans.com\n *\n * @license Copyright (c) 2019-2020, Jongmin Kim. "
  },
  {
    "path": "examples/all.html",
    "chars": 3409,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=e"
  },
  {
    "path": "examples/canvas-basic.html",
    "chars": 4124,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=e"
  },
  {
    "path": "examples/color-pattern.html",
    "chars": 4393,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=e"
  },
  {
    "path": "examples/colorful.html",
    "chars": 3373,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=e"
  },
  {
    "path": "examples/gradient.html",
    "chars": 3131,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=e"
  },
  {
    "path": "examples/grid.html",
    "chars": 2509,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=e"
  },
  {
    "path": "examples/index.html",
    "chars": 8903,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=e"
  },
  {
    "path": "examples/js/util.js",
    "chars": 1955,
    "preview": "const pixelRatio = 2;\nlet isDown = false, moveX = 0, moveY = 0, offsetX = 0, offsetY = 0;\nlet canvas, ctx;\nlet renderer,"
  },
  {
    "path": "examples/mask-tiling-pixi.html",
    "chars": 6186,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=e"
  },
  {
    "path": "examples/metaball-pixi.html",
    "chars": 7843,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=e"
  },
  {
    "path": "examples/morphing-pixi.html",
    "chars": 7442,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=e"
  },
  {
    "path": "examples/pattern.html",
    "chars": 2792,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=e"
  },
  {
    "path": "examples/plants-pixi.html",
    "chars": 7554,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=e"
  },
  {
    "path": "examples/wave.html",
    "chars": 2219,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=e"
  },
  {
    "path": "examples/webgl-basic-pixi.html",
    "chars": 4080,
    "preview": "<!DOCTYPE html>\n<html lang=\"en\">\n\n<head>\n    <meta charset=\"UTF-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=e"
  },
  {
    "path": "src/core/align.js",
    "chars": 338,
    "preview": "export function setAlignGapX(sw, tw) {\n    return {\n        c: (sw - tw) / 2,\n        r: sw - tw,\n        l: 0\n    };\n}\n"
  },
  {
    "path": "src/core/dispatcher.js",
    "chars": 1256,
    "preview": "export class Dispatcher {\n    constructor() {\n        this.handlers_ = {\n            update: {\n                listeners"
  },
  {
    "path": "src/core/group.js",
    "chars": 2924,
    "preview": "import {\n    getRect\n} from './util.js';\nimport {\n    typo\n} from '../font/index.js';\n\nexport function getTextGroup(text"
  },
  {
    "path": "src/core/guide.js",
    "chars": 1114,
    "preview": "import {\n    RECT_RATIO\n} from './util.js';\n\n/**\n * @name getGuide\n * @property {Object} - typo data object from 'font/i"
  },
  {
    "path": "src/core/length.js",
    "chars": 2987,
    "preview": "export function getLengths(item, model) {\n    const total = item.typo.p.length;\n    let c, p,\n        arr = [],\n        "
  },
  {
    "path": "src/core/model.js",
    "chars": 7310,
    "preview": "import {\n    getFontW,\n    getWeightRatio,\n    getCircleRound,\n    getScale,\n    getTracking,\n    getLeading,\n    getFon"
  },
  {
    "path": "src/core/paths.js",
    "chars": 5670,
    "preview": "import {\n    getCurrent\n} from './util.js';\nimport {\n    ROTATE_NONE\n} from '../font/util.js';\nimport {\n    Point\n} from"
  },
  {
    "path": "src/core/point.js",
    "chars": 570,
    "preview": "export function Point(mp) {\n    Object.assign(this, mp);\n}\n\nObject.assign(Point.prototype, {\n    addRect: function (rect"
  },
  {
    "path": "src/core/util.js",
    "chars": 5662,
    "preview": "const DEFAULT_FONT_SIZE = 500;\nexport const MIN_FONT_WEIGHT = 1;\nexport const MAX_FONT_WEIGHT = 900;\nconst MAX_LINE_WIDT"
  },
  {
    "path": "src/core/vector.js",
    "chars": 3243,
    "preview": "import {\n    Point\n} from './point.js';\n\nexport function Vector(mp) {\n    this.type = mp[0];\n\n    this.x = mp[1] || 0;\n "
  },
  {
    "path": "src/draw/canvas/color.js",
    "chars": 760,
    "preview": "export function Color(ctx, no, data, color) {\n    let c_total = color.length;\n    const cur = (no + (c_total * (Math.abs"
  },
  {
    "path": "src/draw/canvas/colorful.js",
    "chars": 2919,
    "preview": "import {\n    PI2,\n    getCurrent\n} from '../../core/util.js';\nimport {\n    cubicBezierLength,\n    distance\n} from '../.."
  },
  {
    "path": "src/draw/canvas/grids.js",
    "chars": 557,
    "preview": "export function Grids(ctx, data) {\n    ctx.save();\n\n    ctx.beginPath();\n    ctx.lineWidth = 1;\n    ctx.strokeStyle = \"#"
  },
  {
    "path": "src/draw/canvas/lines.js",
    "chars": 780,
    "preview": "import {\n    PI2\n} from '../../core/util.js';\n\nexport function Lines(ctx, data) {\n    const total = data.lines.length;\n "
  },
  {
    "path": "src/draw/canvas/pattern.js",
    "chars": 786,
    "preview": "import {\n    PI2\n} from '../../core/util.js';\n\nexport function Pattern(ctx, data, w, h) {\n    const total = Math.round(d"
  },
  {
    "path": "src/draw/canvas/points.js",
    "chars": 1991,
    "preview": "import {\n    PI2\n} from '../../core/util.js';\n\nexport function Points(ctx, data) {\n    ctx.save();\n    ctx.lineWidth = 1"
  },
  {
    "path": "src/draw/canvas/wave.js",
    "chars": 1556,
    "preview": "import {\n    PI2,\n    getAmplitude\n} from '../../core/util.js';\n\nconst THIN_LIMIT = 110;\nconst COS = Math.cos;\nconst SIN"
  },
  {
    "path": "src/draw/pixi/color.js",
    "chars": 1119,
    "preview": "export function PixiColor(no, data, color) {\n    let c_total = color.length;\n    const cur = (no + (c_total * (Math.abs("
  },
  {
    "path": "src/draw/pixi/lines.js",
    "chars": 1596,
    "preview": "export function PixiLines(graphics, data, lineW, color) {\n    let total, i;\n    if (data.drawing.value == 1) {\n        t"
  },
  {
    "path": "src/font/index.js",
    "chars": 444,
    "preview": "import {\n    UPPER\n} from './upper.js';\nimport {\n    LOWER\n} from './lower.js';\nimport {\n    NUMBER\n} from './number.js'"
  },
  {
    "path": "src/font/latin.js",
    "chars": 20804,
    "preview": "import {\n    generateFontData,\n    ROTATE_HORIZONTAL,\n    ROTATE_VERTICAL,\n    ROTATE_NONE,\n    getR,\n    getCurveR\n} fr"
  },
  {
    "path": "src/font/latinutil.js",
    "chars": 8493,
    "preview": "import {\n    ROTATE_HORIZONTAL,\n    ROTATE_VERTICAL,\n    VERTEX_GAP2,\n    getR,\n    getCurveR\n} from './util.js';\n\n//À\ne"
  },
  {
    "path": "src/font/lower.js",
    "chars": 24180,
    "preview": "import {\n    generateFontData,\n    ROTATE_HORIZONTAL,\n    ROTATE_VERTICAL,\n    ROTATE_NONE,\n    VERTEX_GAP,\n    VERTEX_G"
  },
  {
    "path": "src/font/number.js",
    "chars": 10101,
    "preview": "import {\n    generateFontData,\n    ROTATE_HORIZONTAL,\n    ROTATE_VERTICAL,\n    ROTATE_NONE,\n    VERTEX_GAP,\n    getR,\n  "
  },
  {
    "path": "src/font/special.js",
    "chars": 32249,
    "preview": "import {\n    generateFontData,\n    ROTATE_HORIZONTAL,\n    ROTATE_VERTICAL,\n    ROTATE_NONE,\n    getR,\n    getCurveR,\n   "
  },
  {
    "path": "src/font/upper.js",
    "chars": 23178,
    "preview": "import {\n    generateFontData,\n    ROTATE_HORIZONTAL,\n    ROTATE_VERTICAL,\n    VERTEX_GAP,\n    VERTEX_GAP2,\n    getR,\n  "
  },
  {
    "path": "src/font/util.js",
    "chars": 2283,
    "preview": "import {\n    Vector\n} from '../core/vector.js';\nimport {\n    bezierTangent\n} from '../core/paths.js';\n\nexport const ROTA"
  },
  {
    "path": "src/index.js",
    "chars": 74,
    "preview": "const LeonSans = require('./leonsans').default;\nmodule.exports = LeonSans;"
  },
  {
    "path": "src/leonsans.js",
    "chars": 11669,
    "preview": "/*!\n * VERSION: 1.6.3\n * DATE: 2019-09-13\n * https://leon-sans.com\n *\n * @license Copyright (c) 2019, Jongmin Kim. All r"
  }
]

About this extraction

This page contains the full source code of the cmiscm/leonsans GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 48 files (309.1 KB), approximately 104.1k tokens, and a symbol index with 362 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!