@oidoid/void 0.1.0-2 → 0.1.0-4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/atlas/anim.d.ts +30 -0
- package/dist/atlas/anim.js +16 -0
- package/dist/atlas/anim.js.map +1 -0
- package/dist/atlas/atlas.d.ts +1 -9
- package/dist/graphics/renderer.d.ts +1 -1
- package/dist/graphics/renderer.js +1 -2
- package/dist/graphics/renderer.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/sprite/sprite.d.ts +1 -1
- package/dist/text/font.d.ts +1 -1
- package/dist/void.js +4 -4
- package/dist/void.js.map +2 -2
- package/dist/void.meta.json +9 -19
- package/package.json +9 -6
- package/src/atlas/anim.js +17 -0
- package/tools/atlas-parser.js +120 -0
- package/tools/void.js +143 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @template {AnimTag} T
|
|
3
|
+
* @typedef {object} Anim
|
|
4
|
+
* @prop {readonly Readonly<import('../types/2d.js').XY>[]} cels
|
|
5
|
+
* @prop {Readonly<import('../types/2d.js').Box>} hitbox
|
|
6
|
+
* @prop {number} id A multiple of 16 (maxAnimCels).
|
|
7
|
+
* @prop {number} w
|
|
8
|
+
* @prop {number} h
|
|
9
|
+
* @prop {T & AnimTag} tag
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* `--tagname-format={title}--{tag}`.
|
|
13
|
+
* @typedef {`${string}--${string}`} AnimTag
|
|
14
|
+
*/
|
|
15
|
+
export const maxAnimCels: 16;
|
|
16
|
+
export type Anim<T extends `${string}--${string}`> = {
|
|
17
|
+
cels: readonly Readonly<import('../types/2d.js').XY>[];
|
|
18
|
+
hitbox: Readonly<import('../types/2d.js').Box>;
|
|
19
|
+
/**
|
|
20
|
+
* A multiple of 16 (maxAnimCels).
|
|
21
|
+
*/
|
|
22
|
+
id: number;
|
|
23
|
+
w: number;
|
|
24
|
+
h: number;
|
|
25
|
+
tag: T & AnimTag;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* `--tagname-format={title}--{tag}`.
|
|
29
|
+
*/
|
|
30
|
+
export type AnimTag = `${string}--${string}`;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @template {AnimTag} T
|
|
3
|
+
* @typedef {object} Anim
|
|
4
|
+
* @prop {readonly Readonly<import('../types/2d.js').XY>[]} cels
|
|
5
|
+
* @prop {Readonly<import('../types/2d.js').Box>} hitbox
|
|
6
|
+
* @prop {number} id A multiple of 16 (maxAnimCels).
|
|
7
|
+
* @prop {number} w
|
|
8
|
+
* @prop {number} h
|
|
9
|
+
* @prop {T & AnimTag} tag
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* `--tagname-format={title}--{tag}`.
|
|
13
|
+
* @typedef {`${string}--${string}`} AnimTag
|
|
14
|
+
*/
|
|
15
|
+
export const maxAnimCels = 16;
|
|
16
|
+
//# sourceMappingURL=anim.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anim.js","sourceRoot":"","sources":["../../src/atlas/anim.js"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;GAGG;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG,EAAE,CAAA"}
|
package/dist/atlas/atlas.d.ts
CHANGED
|
@@ -1,12 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { AnimTag } from './aseprite.js';
|
|
1
|
+
import type { Anim, AnimTag } from './anim.js';
|
|
3
2
|
export type Atlas<T extends AnimTag = AnimTag> = {
|
|
4
3
|
readonly [tag in T]: Anim<T>;
|
|
5
4
|
};
|
|
6
|
-
export type Anim<T extends AnimTag = AnimTag> = {
|
|
7
|
-
readonly cels: readonly Readonly<XY>[];
|
|
8
|
-
readonly hitbox: Readonly<Box>;
|
|
9
|
-
/** A multiple of 16 (maxAnimCels). */
|
|
10
|
-
readonly id: number;
|
|
11
|
-
readonly tag: T;
|
|
12
|
-
} & Readonly<WH>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../src/graphics/renderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,WAAW,
|
|
1
|
+
{"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../src/graphics/renderer.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AnimTag } from './atlas/
|
|
1
|
+
import type { Anim, AnimTag } from './atlas/anim.js';
|
|
2
2
|
import type { Atlas } from './atlas/atlas.js';
|
|
3
3
|
import { Synth } from './audio/synth.js';
|
|
4
4
|
import { type Bitmap } from './graphics/bitmap.js';
|
|
@@ -12,7 +12,7 @@ export { fontCharToTag } from './text/font.js';
|
|
|
12
12
|
export { layoutText, type TextLayout } from './text/text-layout.js';
|
|
13
13
|
export type { Box, WH, XY } from './types/2d.js';
|
|
14
14
|
export { Sprite };
|
|
15
|
-
export type { AnimTag, Atlas };
|
|
15
|
+
export type { Anim, AnimTag, Atlas };
|
|
16
16
|
export declare class Void<Tag extends AnimTag = AnimTag, Button extends string = StandardButton> {
|
|
17
17
|
#private;
|
|
18
18
|
static new<Tag extends AnimTag = AnimTag, Button extends string = StandardButton>(): Promise<Void<Tag, Button>>;
|
package/dist/sprite/sprite.d.ts
CHANGED
package/dist/text/font.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Font } from 'mem-font';
|
|
2
|
-
import type { AnimTag } from '../atlas/
|
|
2
|
+
import type { AnimTag } from '../atlas/anim.js';
|
|
3
3
|
export declare function fontCharToTag(self: Font, char: string): AnimTag;
|
|
4
4
|
/** @arg rhs Undefined means end of line. */
|
|
5
5
|
export declare function fontKerning(self: Font, lhs: string, rhs: string | undefined): number;
|
package/dist/void.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var l=class{#t;beep(t,e,i,r){this.#t??=new AudioContext;let s=this.#t.currentTime,a=s+r,o=this.#t.createOscillator();o.type=t,o.frequency.setValueAtTime(e,s),o.frequency.exponentialRampToValueAtTime(i,a);let h=this.#t.createGain();h.gain.setValueAtTime(1,s),h.gain.exponentialRampToValueAtTime(.01,a),o.connect(h),h.connect(this.#t.destination),o.start(),o.stop(a)}};var f=class{buffer;size=0;constructor(t){this.buffer=new Uint32Array(t*3)}push(t){this.buffer[this.size*3]=t._xy,this.buffer[this.size*3+1]=t._wh,this.buffer[this.size*3+2]=t._iffzz,this.size++}};var m=class{minWH={w:256,h:256};minScale=1;x=0;y=0;lvl={x:-4096,y:-4096,w:8191,h:8191};#t={w:1,h:1};#e=1;#n=this.minWH.w;#i=this.minWH.h;get h(){return this.#i}resize(t){this.#t.w=innerWidth,this.#t.h=innerHeight;let e=Math.round(this.#t.w*devicePixelRatio),i=Math.round(this.#t.h*devicePixelRatio);this.#e=Math.max(this.minScale,Math.floor(Math.min(e/this.minWH.w,i/this.minWH.h))-(t??0)),this.#n=Math.floor(e/this.#e),this.#i=Math.floor(i/this.#e)}get scale(){return this.#e}toLevelXY(t){return{x:Math.round(this.x+t.x/this.#t.w*this.#n),y:Math.round(this.y+t.y/this.#t.h*this.#i)}}get w(){return this.#n}};var d=class{#t=0;#e={};#n={};get bits(){return this.#t}mapAxis(t,e,i){this.#e[t]=[e,i]}mapButton(t,e){this.#n[t]=e}poll(){if(isSecureContext){this.#t=0;for(let t of navigator.getGamepads()){for(let[e,i]of t?.axes.entries()??[]){let r=this.#e[e];if(r==null)continue;let s=i<0?r[0]:i===0?0:r[1];this.#t|=Math.abs(i)>=.5?s:0}for(let[e,i]of t?.buttons.entries()??[]){let r=this.#n[e];r!=null&&(this.#t|=i.pressed?r:0)}}}}reset(){this.#t=0}};var c=class{#t=0;#e={};get bits(){return this.#t}map(t,e){this.#e[t]=e}register(t){let e=`${t}EventListener`;globalThis[e]("blur",this.reset,{capture:!0,passive:!0});for(let i of["keydown","keyup"]){let r=this.#n;globalThis[e](i,r,{capture:!0,passive:!0})}}reset=()=>{this.#t=0};#n=t=>{let e=t.type==="keydown",i=this.#e[t.key];i!=null&&(this.#t=e?this.#t|i:this.#t&~i)}};var p=class{#t={};#e=0;#n;#i;#o={x:0,y:0};#s;#r;constructor(t,e){this.#n=t,this.#i=e}get bits(){return this.#e}map(t,e){this.#t[t]=e}get type(){return this.#s}register(t){let e=`${t}EventListener`;this.#i[e]("pointercancel",this.reset,{capture:!0,passive:!0});for(let i of["pointerdown","pointermove","pointerup"])this.#i[e](i,this.#u,{capture:!0,passive:i!=="pointerdown"});this.#i[e]("contextmenu",this.#h,{capture:!0})}reset=()=>{this.#e=0,this.#s=void 0,this.#r=void 0};get xy(){return this.#r}#h=t=>t.preventDefault();#u=t=>{if(!t.isPrimary)return;t.type==="pointerdown"&&this.#i.setPointerCapture(t.pointerId),{clientX:this.#o.x,clientY:this.#o.y}=t,this.#e=this.#a(t.buttons),this.#s=["mouse","touch","pen"].find(i=>i===t.pointerType),this.#r=this.#n.toLevelXY(this.#o),t.type!=="pointerdown"||t.preventDefault()};#a(t){let e=0;for(let i=1;i<=t;i<<=1)(i&t)===i&&(e|=this.#t[i]??0);return e}};var
|
|
1
|
+
var l=class{#t;beep(t,e,i,r){this.#t??=new AudioContext;let s=this.#t.currentTime,a=s+r,o=this.#t.createOscillator();o.type=t,o.frequency.setValueAtTime(e,s),o.frequency.exponentialRampToValueAtTime(i,a);let h=this.#t.createGain();h.gain.setValueAtTime(1,s),h.gain.exponentialRampToValueAtTime(.01,a),o.connect(h),h.connect(this.#t.destination),o.start(),o.stop(a)}};var f=class{buffer;size=0;constructor(t){this.buffer=new Uint32Array(t*3)}push(t){this.buffer[this.size*3]=t._xy,this.buffer[this.size*3+1]=t._wh,this.buffer[this.size*3+2]=t._iffzz,this.size++}};var m=class{minWH={w:256,h:256};minScale=1;x=0;y=0;lvl={x:-4096,y:-4096,w:8191,h:8191};#t={w:1,h:1};#e=1;#n=this.minWH.w;#i=this.minWH.h;get h(){return this.#i}resize(t){this.#t.w=innerWidth,this.#t.h=innerHeight;let e=Math.round(this.#t.w*devicePixelRatio),i=Math.round(this.#t.h*devicePixelRatio);this.#e=Math.max(this.minScale,Math.floor(Math.min(e/this.minWH.w,i/this.minWH.h))-(t??0)),this.#n=Math.floor(e/this.#e),this.#i=Math.floor(i/this.#e)}get scale(){return this.#e}toLevelXY(t){return{x:Math.round(this.x+t.x/this.#t.w*this.#n),y:Math.round(this.y+t.y/this.#t.h*this.#i)}}get w(){return this.#n}};var d=class{#t=0;#e={};#n={};get bits(){return this.#t}mapAxis(t,e,i){this.#e[t]=[e,i]}mapButton(t,e){this.#n[t]=e}poll(){if(isSecureContext){this.#t=0;for(let t of navigator.getGamepads()){for(let[e,i]of t?.axes.entries()??[]){let r=this.#e[e];if(r==null)continue;let s=i<0?r[0]:i===0?0:r[1];this.#t|=Math.abs(i)>=.5?s:0}for(let[e,i]of t?.buttons.entries()??[]){let r=this.#n[e];r!=null&&(this.#t|=i.pressed?r:0)}}}}reset(){this.#t=0}};var c=class{#t=0;#e={};get bits(){return this.#t}map(t,e){this.#e[t]=e}register(t){let e=`${t}EventListener`;globalThis[e]("blur",this.reset,{capture:!0,passive:!0});for(let i of["keydown","keyup"]){let r=this.#n;globalThis[e](i,r,{capture:!0,passive:!0})}}reset=()=>{this.#t=0};#n=t=>{let e=t.type==="keydown",i=this.#e[t.key];i!=null&&(this.#t=e?this.#t|i:this.#t&~i)}};var p=class{#t={};#e=0;#n;#i;#o={x:0,y:0};#s;#r;constructor(t,e){this.#n=t,this.#i=e}get bits(){return this.#e}map(t,e){this.#t[t]=e}get type(){return this.#s}register(t){let e=`${t}EventListener`;this.#i[e]("pointercancel",this.reset,{capture:!0,passive:!0});for(let i of["pointerdown","pointermove","pointerup"])this.#i[e](i,this.#u,{capture:!0,passive:i!=="pointerdown"});this.#i[e]("contextmenu",this.#h,{capture:!0})}reset=()=>{this.#e=0,this.#s=void 0,this.#r=void 0};get xy(){return this.#r}#h=t=>t.preventDefault();#u=t=>{if(!t.isPrimary)return;t.type==="pointerdown"&&this.#i.setPointerCapture(t.pointerId),{clientX:this.#o.x,clientY:this.#o.y}=t,this.#e=this.#a(t.buttons),this.#s=["mouse","touch","pen"].find(i=>i===t.pointerType),this.#r=this.#n.toLevelXY(this.#o),t.type!=="pointerdown"||t.preventDefault()};#a(t){let e=0;for(let i=1;i<=t;i<<=1)(i&t)===i&&(e|=this.#t[i]??0);return e}};var y=class{handled=!1;maxInterval=300;minHeld=300;#t=0;#e=0;#n=[];#i={};#o=new d;#s=new c;#r;#h=0;#u=0;constructor(t,e){this.#r=new p(t,e)}isCombo(...t){if(t.length!==this.#n.length)return!1;for(let[e,i]of t.entries()){let r=this.#f(i);if(this.#n[e]!==r)return!1}return this.#n[t.length-1]===this.#a}isComboStart(...t){return this.isCombo(...t)&&!!t.at(-1)?.every(e=>this.isOnStart(e))}isHeld(){return this.#t>=this.minHeld}isOffStart(...t){return!this.isOn(...t)&&this.isStart(...t)}isOn(...t){let e=this.#f(t);return(this.#a&e)===e}isOnStart(...t){return this.isOn(...t)&&this.isStart(...t)}isStart(...t){let e=this.#f(t);return(this.#a&e)!==(this.#e&e)}mapAxis(t,e,...i){for(let r of i)this.#o.mapAxis(r,this.#l(t),this.#l(e))}mapButton(t,...e){for(let i of e)this.#o.mapButton(i,this.#l(t))}mapClick(t,...e){for(let i of e)this.#r.map(i,this.#l(t))}mapStandard(){this.mapKey("L","ArrowLeft","a"),this.mapKey("R","ArrowRight","d"),this.mapKey("U","ArrowUp","w"),this.mapKey("D","ArrowDown","s"),this.mapKey("C","z"),this.mapKey("B","x"),this.mapKey("A","c"),this.mapKey("S","Enter","Escape"),this.mapAxis("L","R",0,2),this.mapAxis("U","D",1,3),this.mapButton("L",14),this.mapButton("R",15),this.mapButton("U",12),this.mapButton("D",13),this.mapButton("A",0),this.mapButton("S",9),this.mapClick("A",1)}mapKey(t,...e){for(let i of e)this.#s.map(i,this.#l(t))}get point(){return this.#r.xy}get pointType(){return this.#r.type}poll(t){this.handled=!1,this.#t+=this.#u,this.#e=this.#h,this.#o.poll(),this.#t>this.maxInterval&&(this.#a===0||this.#a!==this.#e)?(this.#t=0,this.#n.length=0):this.#a!==this.#e?(this.#t=0,this.#a!==0&&this.#n.push(this.#a)):this.#a!==0&&this.#a===this.#e&&(this.#n.pop(),this.#n.push(this.#a)),this.#u=t,this.#h=this.#a}register(t){this.#s.register(t),this.#r.register(t)}reset(){this.handled=!1,this.#o.reset(),this.#s.reset(),this.#r.reset()}get#a(){return this.#o.bits|this.#s.bits|this.#r.bits}#f(t){let e=0;for(let i of t)e|=this.#i[i]??0;return e}#l(t){return this.#i[t]??=1<<Object.keys(this.#i).length}};var B=`#version 300 es
|
|
2
2
|
uniform mediump sampler2D uSpritesheet;
|
|
3
3
|
uniform mediump uvec2 uSpritesheetSize;
|
|
4
4
|
|
|
@@ -11,7 +11,7 @@ void main() {
|
|
|
11
11
|
highp vec2 px = vec2(vTexXYWH.xy) + mod(vDstWH, vec2(vTexXYWH.zw));
|
|
12
12
|
oFrag = texture(uSpritesheet, px / vec2(uSpritesheetSize));
|
|
13
13
|
if(oFrag.a < 1.) discard;
|
|
14
|
-
}`;var
|
|
14
|
+
}`;var w=`#version 300 es
|
|
15
15
|
// https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#essl300_minimum_requirements_webgl_2
|
|
16
16
|
uniform lowp usampler2D uCels;
|
|
17
17
|
uniform mediump ivec4 uCam;
|
|
@@ -55,6 +55,6 @@ void main() {
|
|
|
55
55
|
gl_Position = vec4(clip, depth, 1);
|
|
56
56
|
vTexXYWH = ivec4(texXYWH);
|
|
57
57
|
vDstWH = vec2(targetWH * ivec2(flipX ? -1 : 1, flipY ? -1 : 1));
|
|
58
|
-
}`;var
|
|
59
|
-
`?o=Y(n,r):/^\s*$/.test(a)?o=U(n,r,e,L(n,a,t[s+1])):(o=S(n,r,e,t,s),r.x>0&&o.cursor.y===u(n,r.y).y&&e-r.x+o.cursor.x<=e&&(r=u(n,r.y),o=S(n,r,e,t,s))),i.push(...o.chars),r.x=o.cursor.x,r.y=o.cursor.y}return{chars:i,cursor:r}}function S(n,t,e,i,r){let s=[],{x:a,y:o}=t;for(;;){let h=i[r];if(!h||/^\s*$/.test(h))break;let
|
|
58
|
+
}`;var R=new Int8Array([1,1,0,1,1,0,0,0]),x=class{#t=null;#e;#n;#i;#o=null;#s;#r={};#h=null;constructor(t,e,i){this.#e=e,this.#s=i,this.#n=new Uint16Array(H(t))}clearColor(t){this.#i.clearColor((t>>>24&255)/255,(t>>>16&255)/255,(t>>>8&255)/255,(t>>>0&255)/255)}initGL(){let t=this.#e.getContext("webgl2",{antialias:!1,desynchronized:!0,powerPreference:"high-performance"});if(!t)throw Error("WebGL v2 unsupported");this.#i=t,t.enable(t.BLEND),t.blendFunc(t.SRC_ALPHA,t.ONE_MINUS_SRC_ALPHA),t.enable(t.DEPTH_TEST),t.depthRange(0,1),t.clearDepth(1),t.depthFunc(t.LESS),t.pixelStorei(t.UNPACK_COLORSPACE_CONVERSION_WEBGL,!1);let e=I(t,w,B);this.#r=C(t,e),t.uniform2ui(this.#r.uSpritesheetSize,this.#s.naturalWidth,this.#s.naturalHeight),this.#h=t.createVertexArray(),t.bindVertexArray(this.#h);let i=t.createBuffer();t.bindBuffer(t.ARRAY_BUFFER,i),t.enableVertexAttribArray(0),t.vertexAttribIPointer(0,2,t.BYTE,0,0),t.bindBuffer(t.ARRAY_BUFFER,null),this.#t=t.createBuffer(),t.bindBuffer(t.ARRAY_BUFFER,this.#t),t.enableVertexAttribArray(1),t.vertexAttribIPointer(1,1,t.UNSIGNED_INT,12,0),t.vertexAttribDivisor(1,1),t.enableVertexAttribArray(2),t.vertexAttribIPointer(2,1,t.UNSIGNED_INT,12,4),t.vertexAttribDivisor(2,1),t.enableVertexAttribArray(3),t.vertexAttribIPointer(3,1,t.UNSIGNED_INT,12,8),t.vertexAttribDivisor(3,1),t.bindBuffer(t.ARRAY_BUFFER,null),t.bindVertexArray(null),t.bindBuffer(t.ARRAY_BUFFER,i),t.bufferData(t.ARRAY_BUFFER,R,t.STATIC_DRAW),t.bindBuffer(this.#i.ARRAY_BUFFER,null),t.uniform1i(this.#r.uCels,0),t.activeTexture(t.TEXTURE0);let r=t.createTexture();t.bindTexture(t.TEXTURE_2D,r),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.NEAREST),t.texImage2D(t.TEXTURE_2D,0,t.RGBA16UI,1,this.#n.length/4,0,t.RGBA_INTEGER,t.UNSIGNED_SHORT,this.#n),t.uniform1i(this.#r.uSpritesheet,1),t.activeTexture(t.TEXTURE1);let s=t.createTexture();t.bindTexture(t.TEXTURE_2D,s),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,t.NEAREST),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,t.NEAREST),t.texImage2D(t.TEXTURE_2D,0,t.RGBA,t.RGBA,t.UNSIGNED_BYTE,this.#s),this.#o=t.getExtension("WEBGL_lose_context")}get loseContext(){return this.#o}hasContext(){return!this.#i.isContextLost()}render(t,e,i){this.#u(t),this.#i.clear(this.#i.COLOR_BUFFER_BIT|this.#i.DEPTH_BUFFER_BIT),this.#i.uniform4i(this.#r.uCam,t.x,t.y,t.w,t.h),this.#i.uniform1ui(this.#r.uFrame,e),this.#i.bindVertexArray(this.#h),this.#i.bindBuffer(this.#i.ARRAY_BUFFER,this.#t),this.#i.bufferData(this.#i.ARRAY_BUFFER,i.buffer,this.#i.STREAM_DRAW),this.#i.bindBuffer(this.#i.ARRAY_BUFFER,null),this.#i.drawArraysInstanced(this.#i.TRIANGLE_STRIP,0,R.length/2,i.size),this.#i.bindVertexArray(null)}#u(t){let e=this.#e,i={w:t.w*t.scale,h:t.h*t.scale};(e.width!==i.w||e.height!==i.h)&&(e.width=i.w,e.height=i.h,this.#i.viewport(0,0,i.w,i.h));let r=i.w/devicePixelRatio,s=i.h/devicePixelRatio,a=Number.parseFloat(e.style.width.slice(0,-2))-r,o=Number.parseFloat(e.style.height.slice(0,-2))-s;(!Number.isFinite(a)||Math.abs(a)>=.5||!Number.isFinite(o)||Math.abs(o)>=.5)&&(e.style.width=`${r}px`,e.style.height=`${s}px`)}};function E(n,t,e){let i=n.createShader(t);if(!i)throw Error("shader creation failed");n.shaderSource(i,e.trim()),n.compileShader(i);let r=n.getShaderInfoLog(i)?.slice(0,-1);return r&&console.warn(r),i}function C(n,t){if(!t)return{};let e=n.getProgramParameter(t,n.ACTIVE_UNIFORMS),i={};for(let r=0;r<e;++r){let s=n.getActiveUniform(t,r);if(s==null)throw Error(`missing shader uniform at index ${r}`);i[s.name]=n.getUniformLocation(t,s.name)}return i}function I(n,t,e){let i=n.createProgram();if(!i)return null;let r=E(n,n.VERTEX_SHADER,t),s=E(n,n.FRAGMENT_SHADER,e);n.attachShader(i,r),n.attachShader(i,s),n.linkProgram(i),n.useProgram(i);let a=n.getProgramInfoLog(i)?.slice(0,-1);return a&&console.warn(a),n.detachShader(i,s),n.detachShader(i,r),n.deleteShader(s),n.deleteShader(r),i}function H(n){let t=[];for(let e of Object.values(n)){for(let i of e.cels)t.push(i.x,i.y,e.w,e.h);for(let i=e.cels.length;i<16;i++){let r=e.cels[i%e.cels.length];t.push(r.x,r.y,e.w,e.h)}}return t}var b=class{age=0;tick=0;#t;#e;#n;#i;#o;#s;constructor(t,e,i){this.#t=t,this.#o=e,this.#s=i}cancel(){this.#e!=null&&cancelAnimationFrame(this.#e),this.#e=void 0,this.tick=0,this.#i=void 0,this.#o.reset(),this.#n=void 0}get frame(){return Math.trunc(this.age/16.666666666666668)}register(t){let e=`${t}EventListener`;for(let i of["webglcontextrestored","webglcontextlost"])this.#t[e](i,this.#h,!0);globalThis[e]("visibilitychange",this.#h,!0),t==="add"&&this.#s.initGL(),this.#o.register(t)}render(t,e,i){this.#n=i,!(!this.#r()||!this.#s.hasContext())&&(this.#n&&(this.#e??=requestAnimationFrame(this.#u)),this.#s.render(t,this.frame,e))}#r(){return document.visibilityState==="visible"}#h=t=>{t.preventDefault(),t.type==="webglcontextrestored"&&this.#s.initGL(),this.#s.hasContext()&&this.#r()?this.#n&&(this.#e??=requestAnimationFrame(this.#u)):(this.#e!=null&&cancelAnimationFrame(this.#e),this.#e=void 0,this.tick=0,this.#i=void 0,this.#o.reset())};#u=t=>{this.#e=void 0,this.tick=t-(this.#i??t),this.#i=t,this.age+=this.tick;let e=this.#n;this.#n=void 0,this.#o.poll(this.tick),e?.()}};var g=class n{static parse(t,e){if(!(e.tag in t))throw Error(`atlas missing tag "${e.tag}"`);let i=new n(t,e.tag);return i.cel=e.cel??0,i.flipX=e.flip==="X"||e.flip==="XY",i.flipY=e.flip==="Y"||e.flip==="XY",i.x=e.x??0,i.y=e.y??0,i.z=e.z??0,i.zend=e.zend??!1,e.w!=null&&(i.w=e.w),e.h!=null&&(i.h=e.h),i}hitbox={x:0,y:0,w:0,h:0};_iffzz=0;_xy=0;_wh=0;#t={};#e;constructor(t,e){this.#e=t,this.tag=e}above(t){return(this.z===t.z?(t.zend?t.y+t.h:t.y)-(this.zend?this.y+this.h:this.y):this.z-t.z)<0}get cel(){return this._iffzz>>6&15}set cel(t){this._iffzz=this._iffzz&4294966335|(t&15)<<6}get flipX(){return!!(this._iffzz&32)}set flipX(t){if(this.flipX!==t)if(t){this._iffzz|=32;let e=this.hitbox.x-this.x;this.hitbox.x=this.x+this.hitbox.w-e}else{this._iffzz&=4294967263;let e=this.hitbox.x-this.hitbox.w;this.hitbox.x=this.x+e}}get flipY(){return!!(this._iffzz&16)}set flipY(t){if(this.flipY!==t)if(t){this._iffzz|=16;let e=this.hitbox.y-this.y;this.hitbox.y=this.y+this.hitbox.h-e}else{this._iffzz&=4294967279;let e=this.hitbox.y-this.hitbox.h;this.hitbox.y=this.y+e}}get h(){return this._wh&4095}set h(t){this._wh=this._wh&4294963200|t&4095}hits(t){return!this.hitbox.w||!this.hitbox.h?!1:(t instanceof n&&(t=t.hitbox),this.hitbox.x<t.x+(t.w??0)&&this.hitbox.x+this.hitbox.w>t.x&&this.hitbox.y<t.y+(t.h??0)&&this.hitbox.y+this.hitbox.h>t.y)}overlaps(t){return this.x<t.x+(t.w??0)&&this.x+this.w>t.x&&this.y<t.y+(t.h??0)&&this.y+this.h>t.y}get tag(){return this.#t.tag}set tag(t){if(t===this.#t.tag)return;this.#t=this.#e[t];let{hitbox:e}=this.#t;this.hitbox.x=this.x+(this.flipX?e.w-e.x:e.x),this.hitbox.y=this.y+(this.flipY?e.h-e.y:e.y),this.hitbox.w=this.#t.hitbox.w,this.hitbox.h=this.#t.hitbox.h,this.w=this.#t.w,this.h=this.#t.h,this._iffzz=this._iffzz&68717379647|this.#t.id<<6}toString(){return`${this.tag} (${this.x}, ${this.y}) ${this.w}\xD7${this.h}`}get w(){return this._wh>>12&4095}set w(t){this._wh=this._wh&4278194175|(t&4095)<<12}get x(){return(this._xy>>16)/8}set x(t){let e=t-this.x;this._xy=this._xy&65535|(8*t&65535)<<16,this.hitbox.x+=e}set xy(t){this.x=t.x,this.y=t.y}get y(){return(this._xy<<16>>16)/8}set y(t){let e=t-this.y;this._xy=this._xy&4294901760|8*t&65535,this.hitbox.y+=e}get z(){return this._iffzz&7}set z(t){this._iffzz=this._iffzz&4294967288|t&7}get zend(){return!!(this._iffzz&8)}set zend(t){t?this._iffzz|=8:this._iffzz&=4294967287}};var v=class{get(t){let e=localStorage.getItem(t);return e==null?void 0:JSON.parse(e)}put(t,e){e==null?localStorage.removeItem(t):localStorage.setItem(t,JSON.stringify(e))}};function W(n,t){let e=t.codePointAt(0);return(e==null||e>255)&&(e=63),`${n.id}--${e.toString(16).padStart(2,"0")}`}function _(n,t,e){return e==null?n.endOfLineKerning:/^\s*$/.test(t)||/^\s*$/.test(e)?n.whitespaceKerning:n.kerning[t+e]??n.defaultKerning}function T(n,t){return n.charWidth[t]??n.defaultCharWidth}function X(n,t,e){let i=[],r={x:0,y:0};for(;i.length<t.length;){let s=i.length,a=t[s],o;a===`
|
|
59
|
+
`?o=Y(n,r):/^\s*$/.test(a)?o=U(n,r,e,L(n,a,t[s+1])):(o=S(n,r,e,t,s),r.x>0&&o.cursor.y===u(n,r.y).y&&e-r.x+o.cursor.x<=e&&(r=u(n,r.y),o=S(n,r,e,t,s))),i.push(...o.chars),r.x=o.cursor.x,r.y=o.cursor.y}return{chars:i,cursor:r}}function S(n,t,e,i,r){let s=[],{x:a,y:o}=t;for(;;){let h=i[r];if(!h||/^\s*$/.test(h))break;let A=L(n,h,i[r+1]);a>0&&a+A>e&&({x:a,y:o}=u(n,o)),s.push({x:a,y:o,w:T(n,h),h:n.cellHeight}),a+=A,r++}return{chars:s,cursor:{x:a,y:o}}}function u(n,t){return{x:0,y:t+n.lineHeight}}function Y(n,t){return{chars:[void 0],cursor:u(n,t.y)}}function U(n,t,e,i){let r=t.x>0&&t.x+i>=e?u(n,t.y):{x:t.x+i,y:t.y};return{chars:[void 0],cursor:r}}function L(n,t,e){return T(n,t)+_(n,t,e)}var z=class n{static async new(){return new n(await G(atlasURI))}atlas=atlas;cam=new m;ctrl;kv=new v;synth=new l;#t=new f(1e6);#e;#n;constructor(t){let e=document.createElement("meta");e.name="viewport",e.content="maximum-scale=1, minimum-scale=1, user-scalable=no",document.head.appendChild(e),document.body.style.margin="0",document.body.style.width="100vw",document.body.style.height="100vh",document.body.style.overflow="hidden";let i=document.createElement("canvas");i.style.cursor="none",i.style.display="block",i.style.imageRendering="pixelated",i.style.touchAction="none",document.body.append(i),this.ctrl=new y(this.cam,i),this.#n=new x(atlas,i,t),this.#e=new b(i,this.ctrl,this.#n),this.#e.register("add"),this.background=255}set background(t){document.body.style.background=`#${t.toString(16).padStart(8,"0")}`,this.#n.clearColor(t)}blit(t){this.#t.push(t)}get frame(){return this.#e.frame}render(t){this.cam.resize(),this.#e.render(this.cam,this.#t,t),this.#t.size=0}sprite(t){return new g(this.atlas,t)}stop(){this.#e.cancel(),this.#e.register("remove"),this.ctrl.register("remove")}};function G(n){return new Promise((t,e)=>{let i=new Image;i.onload=()=>t(i),i.onerror=()=>e(i),i.src=n})}export{g as Sprite,z as Void,W as fontCharToTag,X as layoutText};
|
|
60
60
|
//# sourceMappingURL=void.js.map
|
package/dist/void.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/audio/synth.ts", "../src/graphics/bitmap.ts", "../src/graphics/cam.ts", "../src/input/gamepad-poller.ts", "../src/input/keyboard-poller.ts", "../src/input/pointer-poller.ts", "../src/input/input.ts", "../src/graphics/frag.glsl.ts", "../src/graphics/vert.glsl.ts", "../src/graphics/renderer.ts", "../src/graphics/frame-listener.ts", "../src/sprite/sprite.ts", "../src/storage/json-storage.ts", "../src/text/font.ts", "../src/text/text-layout.ts", "../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["export class Synth {\n #context?: AudioContext\n\n beep(\n type: OscillatorType,\n startHz: number,\n endHz: number,\n duration: number // why can't this be short?\n ): void {\n this.#context ??= new AudioContext()\n const now = this.#context.currentTime\n const end = now + duration\n\n const oscillator = this.#context.createOscillator()\n oscillator.type = type\n oscillator.frequency.setValueAtTime(startHz, now)\n oscillator.frequency.exponentialRampToValueAtTime(endHz, end)\n\n const gain = this.#context.createGain()\n gain.gain.setValueAtTime(1, now)\n gain.gain.exponentialRampToValueAtTime(0.01, end)\n\n oscillator.connect(gain)\n gain.connect(this.#context.destination)\n\n oscillator.start()\n oscillator.stop(end)\n }\n}\n", "export type Bitmap = {\n /** 8x: i16, 8y: i16 */\n readonly _xy: number\n /** w: u12, h: u12 */\n readonly _wh: number\n /** id+cel: u15, flipX: b1, flipY: b1, zend: b1, z: u3 */\n readonly _iffzz: number\n}\n\nexport class BitmapBuffer {\n readonly buffer: Uint32Array\n size = 0\n\n constructor(capacity: number) {\n this.buffer = new Uint32Array(capacity * 3)\n }\n\n push(bmp: Readonly<Bitmap>): void {\n this.buffer[this.size * 3] = bmp._xy\n this.buffer[this.size * 3 + 1] = bmp._wh\n this.buffer[this.size * 3 + 2] = bmp._iffzz\n this.size++\n }\n}\n", "import type {Box, WH, XY} from '../types/2d.js'\n\nexport class Cam implements Box {\n minWH: WH = {w: 256, h: 256}\n minScale: number = 1\n x: number = 0 //xy?\n y: number = 0\n lvl: Box = {x: -4096, y: -4096, w: 8191, h: 8191}\n\n readonly #clientWH: WH = {w: 1, h: 1}\n #scale = 1\n #w = this.minWH.w\n #h = this.minWH.h\n\n get h(): number {\n return this.#h\n }\n\n /** Fill or just barely not fill the viewport in scaled pixels. */\n resize(zoomOut?: number): void {\n // WH of body in CSS px; document.body.getBoundingClientRect() returns\n // incorrectly large sizing on mobile that includes the address bar\n this.#clientWH.w = innerWidth\n this.#clientWH.h = innerHeight\n\n const nativeW = Math.round(this.#clientWH.w * devicePixelRatio) // physical\n const nativeH = Math.round(this.#clientWH.h * devicePixelRatio)\n\n this.#scale = Math.max(\n this.minScale,\n Math.floor(Math.min(nativeW / this.minWH.w, nativeH / this.minWH.h)) -\n (zoomOut ?? 0) // Default is to zoom in as much as possible.\n )\n this.#w = Math.floor(nativeW / this.#scale)\n this.#h = Math.floor(nativeH / this.#scale)\n }\n\n get scale(): number {\n return this.#scale\n }\n\n /** Returns the integral position in level coordinates. */\n toLevelXY(clientXY: Readonly<XY>): XY {\n return {\n x: Math.round(this.x + (clientXY.x / this.#clientWH.w) * this.#w),\n y: Math.round(this.y + (clientXY.y / this.#clientWH.h) * this.#h)\n }\n }\n\n get w(): number {\n return this.#w\n }\n}\n", "export class GamepadPoller {\n #bits = 0\n readonly #bitByAxis: {[axis: number]: [less: number, more: number]} = {}\n readonly #bitByButton: {[btn: number]: number} = {}\n\n get bits(): number {\n return this.#bits\n }\n\n mapAxis(axis: number, lessBit: number, moreBit: number): void {\n this.#bitByAxis[axis] = [lessBit, moreBit]\n }\n\n mapButton(button: number, bit: number): void {\n this.#bitByButton[button] = bit\n }\n\n poll(): void {\n if (!isSecureContext) return\n this.#bits = 0\n for (const pad of navigator.getGamepads()) {\n for (const [index, axis] of pad?.axes.entries() ?? []) {\n const bits = this.#bitByAxis[index]\n if (bits == null) continue\n const bit = axis < 0 ? bits[0] : axis === 0 ? 0 : bits[1]\n this.#bits |= Math.abs(axis) >= 0.5 ? bit : 0\n }\n for (const [index, button] of pad?.buttons.entries() ?? []) {\n const bit = this.#bitByButton[index]\n if (bit == null) continue\n this.#bits |= button.pressed ? bit : 0\n }\n }\n }\n\n reset(): void {\n this.#bits = 0\n }\n}\n", "export class KeyboardPoller {\n #bits = 0\n readonly #bitByKey: {[key: string]: number} = {}\n\n get bits(): number {\n return this.#bits\n }\n\n map(key: string, bit: number): void {\n this.#bitByKey[key] = bit\n }\n\n register(op: 'add' | 'remove'): void {\n const fn = <const>`${op}EventListener`\n // keyup is not received if window loses focus.\n globalThis[fn]('blur', this.reset, {capture: true, passive: true})\n for (const type of ['keydown', 'keyup']) {\n const callback = <EventListenerOrEventListenerObject>this.#onKey\n globalThis[fn](type, callback, {capture: true, passive: true})\n }\n }\n\n reset = (): void => {\n this.#bits = 0\n }\n\n #onKey = (ev: KeyboardEvent): void => {\n const on = ev.type === 'keydown'\n const bit = this.#bitByKey[ev.key]\n if (bit == null) return\n this.#bits = on ? this.#bits | bit : this.#bits & ~bit\n }\n}\n", "import {Cam} from '../graphics/cam.js'\nimport type {XY} from '../types/2d.js'\n\nexport class PointerPoller {\n readonly #bitByButton: {[btn: number]: number} = {}\n #bits: number = 0\n readonly #cam: Readonly<Cam>\n readonly #canvas: HTMLCanvasElement\n readonly #clientXY: XY = {x: 0, y: 0}\n #type?: 'mouse' | 'touch' | 'pen' | undefined\n #xy?: Readonly<XY> | undefined\n\n constructor(cam: Readonly<Cam>, canvas: HTMLCanvasElement) {\n this.#cam = cam\n this.#canvas = canvas\n }\n\n get bits(): number {\n return this.#bits\n }\n\n map(button: number, bit: number): void {\n this.#bitByButton[button] = bit\n }\n\n get type(): 'mouse' | 'touch' | 'pen' | undefined {\n return this.#type\n }\n\n register(op: 'add' | 'remove'): void {\n const fn = <const>`${op}EventListener`\n this.#canvas[fn]('pointercancel', this.reset, {\n capture: true,\n passive: true\n })\n for (const type of ['pointerdown', 'pointermove', 'pointerup']) {\n this.#canvas[fn](\n type,\n <EventListenerOrEventListenerObject>this.#onPointEvent,\n {capture: true, passive: type !== 'pointerdown'}\n )\n }\n this.#canvas[fn]('contextmenu', this.#onContextMenuEvent, {capture: true})\n }\n\n reset = (): void => {\n this.#bits = 0\n this.#type = undefined\n this.#xy = undefined\n }\n\n get xy(): Readonly<XY> | undefined {\n return this.#xy\n }\n\n #onContextMenuEvent = (ev: Event): void => ev.preventDefault()\n\n #onPointEvent = (ev: PointerEvent): void => {\n // Ignore non-primary inputs to avoid flickering between distant points.\n if (!ev.isPrimary) return\n\n if (ev.type === 'pointerdown') this.#canvas.setPointerCapture(ev.pointerId)\n ;({clientX: this.#clientXY.x, clientY: this.#clientXY.y} = ev)\n\n this.#bits = this.#evButtonsToBits(ev.buttons)\n this.#type = (<const>['mouse', 'touch', 'pen']).find(\n type => type === ev.pointerType\n )\n this.#xy = this.#cam.toLevelXY(this.#clientXY)\n\n const passive = ev.type !== 'pointerdown'\n if (!passive) ev.preventDefault()\n }\n\n #evButtonsToBits(buttons: number): number {\n let bits = 0\n for (let button = 1; button <= buttons; button <<= 1) {\n if ((button & buttons) !== button) continue\n bits |= this.#bitByButton[button] ?? 0\n }\n return bits\n }\n}\n", "import {Cam} from '../graphics/cam.js'\nimport type {XY} from '../types/2d.js'\nimport {GamepadPoller} from './gamepad-poller.js'\nimport {KeyboardPoller} from './keyboard-poller.js'\nimport {PointerPoller} from './pointer-poller.js'\n\n// prettier-ignore\nexport type StandardButton =\n 'L' | 'R' | 'U' | 'D' | // Dpad.\n 'C' | 'B' | 'A' | // Primary, secondary, tertiary.\n 'S' // Start.\n\nexport class Input<Button extends string = StandardButton> {\n handled = false\n /** The maximum duration in milliseconds permitted between combo inputs. */\n maxInterval = 300\n /** The minimum duration in milliseconds for an input to be considered held. */\n minHeld = 300\n\n /** The time in milliseconds since the input changed. */\n #duration = 0\n /** Prior button state, possibly 0, but not necessarily a combo member. */\n #prevBits = 0\n /**\n * A sequence of nonzero buttons ordered from oldest (first) to latest (last).\n * Combos are terminated only by expiration.\n */\n readonly #combo: number[] = []\n /** Logical button to bit. */\n readonly #bitByButton = <{[btn in Button]: number}>{}\n readonly #gamepad = new GamepadPoller()\n readonly #keyboard = new KeyboardPoller()\n readonly #pointer: PointerPoller\n #pollBits = 0\n #pollTick = 0\n\n constructor(cam: Readonly<Cam>, canvas: HTMLCanvasElement) {\n this.#pointer = new PointerPoller(cam, canvas)\n }\n\n /**\n * Combos are interpreted exactly both in buttons pressed per tick (eg, up\n * will not match up and down the way `isOn('Up')` will) and sequence (order\n * and length). Combos only test button on state.\n */\n isCombo(...combo: readonly (readonly Button[])[]): boolean {\n if (combo.length !== this.#combo.length) return false\n for (const [i, buttons] of combo.entries()) {\n const bits = this.#buttonsToBits(buttons)\n if (this.#combo[i] !== bits) return false\n }\n // #combo is a historical record of buttons. Whenever buttons changes, a new\n // entry is pushed. Make sure the current entry is the current state and\n // that the last entry's buttons haven't been released.\n return this.#combo[combo.length - 1] === this.#bits\n }\n\n /** Like isOnCombo() but test if the last button set is triggered. */\n isComboStart(...combo: readonly (readonly Button[])[]): boolean {\n return (\n this.isCombo(...combo) &&\n !!combo.at(-1)?.every(button => this.isOnStart(button))\n )\n }\n\n /** True if held on or off. */\n isHeld(): boolean {\n return this.#duration >= this.minHeld\n }\n\n isOffStart(...buttons: readonly Button[]): boolean {\n return !this.isOn(...buttons) && this.isStart(...buttons)\n }\n\n /**\n * Test if all buttons are on. True if the buttons are pressed regardless of\n * whether other buttons are pressed. Eg, `isOn('Up')` will return true when\n * up is pressed or when up and down are pressed.\n */\n isOn(...buttons: readonly Button[]): boolean {\n const bits = this.#buttonsToBits(buttons)\n return (this.#bits & bits) === bits\n }\n\n isOnStart(...buttons: readonly Button[]): boolean {\n return this.isOn(...buttons) && this.isStart(...buttons)\n }\n\n /** True if triggered on or off. */\n isStart(...buttons: readonly Button[]): boolean {\n const bits = this.#buttonsToBits(buttons)\n return (this.#bits & bits) !== (this.#prevBits & bits)\n }\n\n mapAxis(less: Button, more: Button, ...axes: readonly number[]): void {\n for (const axis of axes) {\n this.#gamepad.mapAxis(axis, this.#map(less), this.#map(more))\n }\n }\n\n mapButton(button: Button, ...indices: readonly number[]): void {\n for (const index of indices) {\n this.#gamepad.mapButton(index, this.#map(button))\n }\n }\n\n mapClick(button: Button, ...clicks: readonly number[]): void {\n for (const click of clicks) this.#pointer.map(click, this.#map(button))\n }\n\n mapStandard(): void {\n this.mapKey(<Button>'L', 'ArrowLeft', 'a')\n this.mapKey(<Button>'R', 'ArrowRight', 'd')\n this.mapKey(<Button>'U', 'ArrowUp', 'w')\n this.mapKey(<Button>'D', 'ArrowDown', 's')\n this.mapKey(<Button>'C', 'z')\n this.mapKey(<Button>'B', 'x')\n this.mapKey(<Button>'A', 'c')\n this.mapKey(<Button>'S', 'Enter', 'Escape')\n\n // https://w3c.github.io/gamepad/#remapping\n this.mapAxis(<Button>'L', <Button>'R', 0, 2)\n this.mapAxis(<Button>'U', <Button>'D', 1, 3)\n this.mapButton(<Button>'L', 14)\n this.mapButton(<Button>'R', 15)\n this.mapButton(<Button>'U', 12)\n this.mapButton(<Button>'D', 13)\n this.mapButton(<Button>'A', 0)\n this.mapButton(<Button>'S', 9)\n\n this.mapClick(<Button>'A', 1)\n }\n\n mapKey(button: Button, ...keys: readonly string[]): void {\n for (const key of keys) this.#keyboard.map(key, this.#map(button))\n }\n\n get point(): Readonly<XY> | undefined {\n return this.#pointer.xy\n }\n\n get pointType(): 'mouse' | 'touch' | 'pen' | undefined {\n return this.#pointer.type\n }\n\n poll(tick: number): void {\n this.handled = false\n this.#duration += this.#pollTick\n this.#prevBits = this.#pollBits\n\n this.#gamepad.poll()\n if (\n this.#duration > this.maxInterval &&\n (this.#bits === 0 || this.#bits !== this.#prevBits)\n ) {\n // Expired.\n this.#duration = 0\n this.#combo.length = 0\n } else if (this.#bits !== this.#prevBits) {\n // Some button state has changed and at least one button is still pressed.\n this.#duration = 0\n if (this.#bits !== 0) this.#combo.push(this.#bits)\n } else if (this.#bits !== 0 && this.#bits === this.#prevBits) {\n // Held. Update combo with the latest buttons.\n this.#combo.pop()\n this.#combo.push(this.#bits)\n }\n\n this.#pollTick = tick\n this.#pollBits = this.#bits\n }\n\n register(op: 'add' | 'remove'): void {\n this.#keyboard.register(op)\n this.#pointer.register(op)\n }\n\n reset(): void {\n this.handled = false\n this.#gamepad.reset()\n this.#keyboard.reset()\n this.#pointer.reset()\n }\n\n /**\n * The current state and prospective combo member. A zero value can never be a\n * combo member but is necessary to persist in previous to distinguish the off\n * state between repeated button presses like up, up.\n */\n get #bits(): number {\n return this.#gamepad.bits | this.#keyboard.bits | this.#pointer.bits\n }\n\n #buttonsToBits(buttons: readonly Button[]): number {\n let bits = 0\n for (const button of buttons) bits |= this.#bitByButton[button] ?? 0\n return bits\n }\n\n #map(button: Button): number {\n return (this.#bitByButton[button] ??=\n 1 << Object.keys(this.#bitByButton).length)\n }\n}\n", "export const fragGLSL = `#version 300 es\nuniform mediump sampler2D uSpritesheet;\nuniform mediump uvec2 uSpritesheetSize;\n\nflat in highp ivec4 vTexXYWH;\nin highp vec2 vDstWH;\n\nout highp vec4 oFrag;\n\nvoid main() {\n highp vec2 px = vec2(vTexXYWH.xy) + mod(vDstWH, vec2(vTexXYWH.zw));\n oFrag = texture(uSpritesheet, px / vec2(uSpritesheetSize));\n if(oFrag.a < 1.) discard;\n}`\n", "export const vertGLSL = `#version 300 es\n// https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#essl300_minimum_requirements_webgl_2\nuniform lowp usampler2D uCels;\nuniform mediump ivec4 uCam;\nuniform highp uint uFrame;\n\nlayout (location=0) in lowp ivec2 iUV;\nlayout (location=1) in highp uint iXY;\nlayout (location=2) in highp uint iWH;\nlayout (location=3) in highp uint iIFFZZ;\n\nflat out highp ivec4 vTexXYWH;\nout highp vec2 vDstWH;\n\nconst mediump int maxY = 0x1000;\nconst lowp int maxZ = 8;\nconst mediump int maxDepth = maxY * maxZ;\n\nvoid main() {\n mediump int x = int(iXY) >> 19;\n mediump int y = int(iXY << 16) >> 19;\n lowp int z = int(iIFFZZ & 0x7u);\n bool zend = bool(iIFFZZ & 0x8u);\n bool flipX = bool(iIFFZZ & 0x20u);\n bool flipY = bool(iIFFZZ & 0x10u);\n mediump int id = int((iIFFZZ >> 6) & 0x7ff0u);\n lowp int cel = int((iIFFZZ >> 6) & 0xfu);\n mediump int w = int((iWH >> 12) & 0xfffu);\n mediump int h = int(iWH & 0xfffu);\n\n lowp int frame = ((int(uFrame) - cel) / 4) & 0xf;\n mediump uvec4 texXYWH = texelFetch(uCels, ivec2(0, id + frame), 0);\n\n // https://www.patternsgameprog.com/opengl-2d-facade-25-get-the-z-of-a-pixel\n highp float depth = float((z + 1) * maxY - (y + (zend ? 0 : h))) / float(maxDepth);\n\n highp ivec2 targetWH = ivec2(iUV) * ivec2(w, h);\n highp ivec2 origWH = ivec2(iUV) * ivec2(texXYWH.zw);\n\n highp vec2 end = vec2(x + targetWH.x, y + targetWH.y);\n highp vec2 clip = ((-2. * vec2(uCam.xy) + 2. * end) / vec2(uCam.zw) - 1.) * vec2(1, -1);\n gl_Position = vec4(clip, depth, 1);\n vTexXYWH = ivec4(texXYWH);\n vDstWH = vec2(targetWH * ivec2(flipX ? -1 : 1, flipY ? -1 : 1));\n}`\n", "import {maxAnimCels} from '../atlas/atlas-parser.js'\nimport {type Anim, type Atlas} from '../atlas/atlas.js'\nimport {BitmapBuffer} from './bitmap.js'\nimport {Cam} from './cam.js'\nimport {fragGLSL} from './frag.glsl.js'\nimport {vertGLSL} from './vert.glsl.js'\n\ntype GLUniforms = {readonly [name: string]: WebGLUniformLocation | null}\ntype GL = WebGL2RenderingContext\ntype GLProgram = WebGLProgram | null\n\nconst uv: Readonly<Int8Array> = new Int8Array([1, 1, 0, 1, 1, 0, 0, 0])\n\nexport class Renderer {\n #bmpBuffer: Readonly<WebGLBuffer> | null = null\n readonly #canvas: HTMLCanvasElement\n readonly #cels: Readonly<Uint16Array>\n #gl!: GL\n #loseContext: Readonly<WEBGL_lose_context | null> = null\n readonly #spritesheet: HTMLImageElement\n #uniforms: Readonly<GLUniforms> = {}\n #vertArray: WebGLVertexArrayObject | null = null\n\n constructor(\n atlas: Atlas,\n canvas: HTMLCanvasElement,\n spritesheet: HTMLImageElement\n ) {\n this.#canvas = canvas\n this.#spritesheet = spritesheet\n this.#cels = new Uint16Array(newCels(atlas))\n }\n\n clearColor(rgba: number): void {\n this.#gl.clearColor(\n ((rgba >>> 24) & 0xff) / 0xff,\n ((rgba >>> 16) & 0xff) / 0xff,\n ((rgba >>> 8) & 0xff) / 0xff,\n ((rgba >>> 0) & 0xff) / 0xff\n )\n }\n\n initGL(): void {\n const gl = this.#canvas.getContext('webgl2', {\n antialias: false,\n desynchronized: true, // breaks render stats\n powerPreference: 'high-performance'\n })\n if (!gl) throw Error('WebGL v2 unsupported')\n this.#gl = gl\n\n // Allow transparent textures to be layered.\n gl.enable(gl.BLEND)\n gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)\n\n // Enable z-buffer for [0, 1] ([foreground, background]).\n gl.enable(gl.DEPTH_TEST)\n gl.depthRange(0, 1)\n gl.clearDepth(1)\n gl.depthFunc(gl.LESS)\n\n // Disable image colorspace conversions. The default is browser dependent.\n gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, false)\n\n const pgm = loadProgram(gl, vertGLSL, fragGLSL)\n this.#uniforms = getUniformLocations(gl, pgm)\n\n gl.uniform2ui(\n this.#uniforms.uSpritesheetSize!,\n this.#spritesheet.naturalWidth,\n this.#spritesheet.naturalHeight\n )\n\n this.#vertArray = gl.createVertexArray()\n gl.bindVertexArray(this.#vertArray)\n\n const uvBuffer = gl.createBuffer()\n gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer)\n gl.enableVertexAttribArray(0)\n gl.vertexAttribIPointer(0, 2, gl.BYTE, 0, 0)\n gl.bindBuffer(gl.ARRAY_BUFFER, null)\n\n this.#bmpBuffer = gl.createBuffer()\n gl.bindBuffer(gl.ARRAY_BUFFER, this.#bmpBuffer)\n gl.enableVertexAttribArray(1)\n gl.vertexAttribIPointer(1, 1, gl.UNSIGNED_INT, 12, 0)\n gl.vertexAttribDivisor(1, 1)\n gl.enableVertexAttribArray(2)\n gl.vertexAttribIPointer(2, 1, gl.UNSIGNED_INT, 12, 4)\n gl.vertexAttribDivisor(2, 1)\n gl.enableVertexAttribArray(3)\n gl.vertexAttribIPointer(3, 1, gl.UNSIGNED_INT, 12, 8)\n gl.vertexAttribDivisor(3, 1)\n gl.bindBuffer(gl.ARRAY_BUFFER, null)\n\n gl.bindVertexArray(null)\n\n gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer)\n gl.bufferData(gl.ARRAY_BUFFER, uv, gl.STATIC_DRAW)\n gl.bindBuffer(this.#gl.ARRAY_BUFFER, null)\n\n gl.uniform1i(this.#uniforms.uCels!, 0)\n gl.activeTexture(gl.TEXTURE0)\n const dataTex = gl.createTexture()\n gl.bindTexture(gl.TEXTURE_2D, dataTex)\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n gl.RGBA16UI,\n 1,\n this.#cels.length / 4, // 4 u8s per row\n 0,\n gl.RGBA_INTEGER,\n gl.UNSIGNED_SHORT,\n this.#cels\n )\n\n gl.uniform1i(this.#uniforms.uSpritesheet!, 1)\n gl.activeTexture(gl.TEXTURE1)\n const spritesheetTex = gl.createTexture()\n gl.bindTexture(gl.TEXTURE_2D, spritesheetTex)\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n gl.RGBA,\n gl.RGBA,\n gl.UNSIGNED_BYTE,\n this.#spritesheet\n )\n\n this.#loseContext = gl.getExtension('WEBGL_lose_context')\n }\n\n get loseContext(): WEBGL_lose_context | null {\n return this.#loseContext\n }\n\n hasContext(): boolean {\n return !this.#gl.isContextLost()\n }\n\n render(\n cam: Readonly<Cam>,\n frame: number,\n bmps: Readonly<BitmapBuffer>\n ): void {\n this.#resize(cam)\n this.#gl.clear(this.#gl.COLOR_BUFFER_BIT | this.#gl.DEPTH_BUFFER_BIT)\n\n this.#gl.uniform4i(this.#uniforms.uCam!, cam.x, cam.y, cam.w, cam.h)\n this.#gl.uniform1ui(this.#uniforms.uFrame!, frame)\n\n this.#gl.bindVertexArray(this.#vertArray)\n\n this.#gl.bindBuffer(this.#gl.ARRAY_BUFFER, this.#bmpBuffer)\n this.#gl.bufferData(\n this.#gl.ARRAY_BUFFER,\n bmps.buffer,\n this.#gl.STREAM_DRAW\n )\n this.#gl.bindBuffer(this.#gl.ARRAY_BUFFER, null)\n\n this.#gl.drawArraysInstanced(\n this.#gl.TRIANGLE_STRIP,\n 0,\n uv.length / 2, // d\n bmps.size\n )\n\n this.#gl.bindVertexArray(null)\n }\n\n #resize(cam: Readonly<Cam>): void {\n const canvas = this.#canvas\n const nativeWH = {w: cam.w * cam.scale, h: cam.h * cam.scale}\n\n if (canvas.width !== nativeWH.w || canvas.height !== nativeWH.h) {\n canvas.width = nativeWH.w\n canvas.height = nativeWH.h\n this.#gl.viewport(0, 0, nativeWH.w, nativeWH.h)\n }\n\n // These pixels may be greater than, less than, or equal to native.\n const clientW = nativeWH.w / devicePixelRatio\n const clientH = nativeWH.h / devicePixelRatio\n const diffW = Number.parseFloat(canvas.style.width.slice(0, -2)) - clientW\n const diffH = Number.parseFloat(canvas.style.height.slice(0, -2)) - clientH\n if (\n !Number.isFinite(diffW) ||\n Math.abs(diffW) >= 0.5 ||\n !Number.isFinite(diffH) ||\n Math.abs(diffH) >= 0.5\n ) {\n canvas.style.width = `${clientW}px`\n canvas.style.height = `${clientH}px`\n }\n }\n}\n\nfunction compileShader(gl: GL, type: number, src: string): WebGLShader {\n const shader = gl.createShader(type)\n if (!shader) throw Error('shader creation failed')\n gl.shaderSource(shader, src.trim())\n gl.compileShader(shader)\n\n const log = gl.getShaderInfoLog(shader)?.slice(0, -1)\n if (log) console.warn(log)\n\n return shader\n}\n\nfunction getUniformLocations(gl: GL, pgm: GLProgram): GLUniforms {\n if (!pgm) return {}\n const len = gl.getProgramParameter(pgm, gl.ACTIVE_UNIFORMS)\n const locations: {[name: string]: WebGLUniformLocation | null} = {}\n for (let i = 0; i < len; ++i) {\n const uniform = gl.getActiveUniform(pgm, i)\n if (uniform == null) throw Error(`missing shader uniform at index ${i}`)\n locations[uniform.name] = gl.getUniformLocation(pgm, uniform.name)\n }\n return locations\n}\n\nfunction loadProgram(gl: GL, vertGLSL: string, fragGLSL: string): GLProgram {\n const pgm = gl.createProgram()\n if (!pgm) return null\n\n const vert = compileShader(gl, gl.VERTEX_SHADER, vertGLSL)\n const frag = compileShader(gl, gl.FRAGMENT_SHADER, fragGLSL)\n gl.attachShader(pgm, vert)\n gl.attachShader(pgm, frag)\n gl.linkProgram(pgm)\n gl.useProgram(pgm)\n\n const log = gl.getProgramInfoLog(pgm)?.slice(0, -1)\n if (log) console.warn(log)\n\n gl.detachShader(pgm, frag)\n gl.detachShader(pgm, vert)\n gl.deleteShader(frag)\n gl.deleteShader(vert)\n\n return pgm\n}\n\n/** XYWH ordered by ID and padded to 16-cel blocks. */\nfunction newCels(atlas: Atlas): readonly number[] {\n const cels = []\n for (const anim of Object.values<Anim>(atlas)) {\n // Animations are inserted in ID order.\n for (const cel of anim.cels) cels.push(cel.x, cel.y, anim.w, anim.h)\n for (let i = anim.cels.length; i < maxAnimCels; i++) {\n const cel = anim.cels[i % anim.cels.length]!\n cels.push(cel.x, cel.y, anim.w, anim.h)\n }\n }\n return cels\n}\n", "import {Input} from '../input/input.js'\nimport {BitmapBuffer} from './bitmap.js'\nimport {Cam} from './cam.js'\nimport {Renderer} from './renderer.js'\n\nexport class FrameListener {\n /** The running lifetime in milliseconds. */\n age = 0\n /** The exact duration in milliseconds to apply on a given update step. */\n tick = 0\n\n readonly #canvas: HTMLCanvasElement\n #frame?: number | undefined\n #loop?: (() => void) | undefined\n #time?: number | undefined\n readonly #input: Input\n readonly #renderer: Renderer\n\n constructor(\n canvas: HTMLCanvasElement,\n input: Input<string>,\n renderer: Renderer\n ) {\n this.#canvas = canvas\n this.#input = input\n this.#renderer = renderer\n }\n\n cancel(): void {\n if (this.#frame != null) cancelAnimationFrame(this.#frame)\n this.#frame = undefined\n this.tick = 0\n this.#time = undefined\n this.#input.reset()\n this.#loop = undefined\n }\n\n get frame(): number {\n // Assume 60 FPS so games can scale to this number regardless of actual.\n return Math.trunc(this.age / 16.666666666666668)\n }\n\n register(op: 'add' | 'remove'): void {\n const fn = <const>`${op}EventListener`\n for (const type of ['webglcontextrestored', 'webglcontextlost']) {\n this.#canvas[fn](type, this.#onEvent, true)\n }\n globalThis[fn]('visibilitychange', this.#onEvent, true)\n if (op === 'add') this.#renderer.initGL()\n this.#input.register(op)\n }\n\n render(cam: Readonly<Cam>, buffer: BitmapBuffer, loop?: () => void): void {\n this.#loop = loop\n if (!this.#isVisible() || !this.#renderer.hasContext()) return\n if (this.#loop) this.#frame ??= requestAnimationFrame(this.#onFrame)\n this.#renderer.render(cam, this.frame, buffer)\n }\n\n #isVisible(): boolean {\n return document.visibilityState === 'visible'\n }\n\n #onEvent = (event: Event): void => {\n event.preventDefault()\n if (event.type === 'webglcontextrestored') this.#renderer.initGL()\n\n if (this.#renderer.hasContext() && this.#isVisible()) {\n if (this.#loop) this.#frame ??= requestAnimationFrame(this.#onFrame)\n } else {\n if (this.#frame != null) cancelAnimationFrame(this.#frame)\n this.#frame = undefined\n this.tick = 0\n this.#time = undefined\n this.#input.reset()\n }\n }\n\n #onFrame = (time: number): void => {\n this.#frame = undefined\n this.tick = time - (this.#time ?? time)\n this.#time = time\n this.age += this.tick\n const loop = this.#loop\n this.#loop = undefined\n this.#input.poll(this.tick)\n loop?.()\n }\n}\n", "import type {AnimTag} from '../atlas/aseprite.js'\nimport type {Anim, Atlas} from '../atlas/atlas.js'\nimport type {Bitmap} from '../graphics/bitmap.js'\nimport type {Box, WH, XY} from '../types/2d.js'\n\nexport type SpriteJSON = {\n cel?: number\n flip?: string\n tag: string\n x?: number\n y?: number\n z?: number\n w?: number\n h?: number\n zend?: boolean\n}\n\nexport class Sprite<T extends AnimTag = AnimTag> implements Bitmap, Box {\n static parse<T extends AnimTag = AnimTag>(\n atlas: Atlas<T>,\n json: Readonly<SpriteJSON>\n ): Sprite<T> {\n if (!(json.tag in atlas)) throw Error(`atlas missing tag \"${json.tag}\"`)\n const sprite = new Sprite(atlas, <T>json.tag)\n sprite.cel = json.cel ?? 0\n sprite.flipX = json.flip === 'X' || json.flip === 'XY'\n sprite.flipY = json.flip === 'Y' || json.flip === 'XY'\n sprite.x = json.x ?? 0\n sprite.y = json.y ?? 0\n sprite.z = json.z ?? 0\n sprite.zend = json.zend ?? false\n if (json.w != null) sprite.w = json.w\n if (json.h != null) sprite.h = json.h\n return sprite\n }\n\n readonly hitbox: Box = {x: 0, y: 0, w: 0, h: 0}\n\n _iffzz = 0\n _xy = 0\n _wh = 0\n\n #anim: Anim<T> = <Anim<T>>{}\n #atlas: Atlas<T>\n\n constructor(atlas: Atlas<T>, tag: T) {\n this.#atlas = atlas\n this.tag = tag\n }\n\n above(sprite: Readonly<Sprite>): boolean {\n const compare =\n this.z === sprite.z\n ? (sprite.zend ? sprite.y + sprite.h : sprite.y) -\n (this.zend ? this.y + this.h : this.y)\n : this.z - sprite.z\n return compare < 0\n }\n\n get cel(): number {\n return (this._iffzz >> 6) & 0xf\n }\n\n /** Set to frame number to start at the beginning. */\n set cel(cel: number) {\n this._iffzz = (this._iffzz & 0xfffffc3f) | ((cel & 0xf) << 6)\n }\n\n get flipX(): boolean {\n return !!(this._iffzz & 0x20)\n }\n\n set flipX(flip: boolean) {\n if (this.flipX === flip) return\n if (flip) {\n this._iffzz |= 0x20\n const diff = this.hitbox.x - this.x\n this.hitbox.x = this.x + this.hitbox.w - diff\n } else {\n this._iffzz &= 0xffffffdf\n const diff = this.hitbox.x - this.hitbox.w\n this.hitbox.x = this.x + diff\n }\n }\n\n get flipY(): boolean {\n return !!(this._iffzz & 0x10)\n }\n\n set flipY(flip: boolean) {\n if (this.flipY === flip) return\n if (flip) {\n this._iffzz |= 0x10\n const diff = this.hitbox.y - this.y\n this.hitbox.y = this.y + this.hitbox.h - diff\n } else {\n this._iffzz &= 0xffffffef\n const diff = this.hitbox.y - this.hitbox.h\n this.hitbox.y = this.y + diff\n }\n }\n\n get h(): number {\n return this._wh & 0xfff\n }\n\n set h(h: number) {\n this._wh = (this._wh & 0xfffff000) | (h & 0xfff)\n }\n\n hits(box: Readonly<XY & Partial<WH>>): boolean {\n if (!this.hitbox.w || !this.hitbox.h) return false\n if (box instanceof Sprite) box = box.hitbox\n return (\n this.hitbox.x < box.x + (box.w ?? 0) &&\n this.hitbox.x + this.hitbox.w > box.x &&\n this.hitbox.y < box.y + (box.h ?? 0) &&\n this.hitbox.y + this.hitbox.h > box.y\n )\n }\n\n overlaps(box: Readonly<XY & Partial<WH>>): boolean {\n return (\n this.x < box.x + (box.w ?? 0) &&\n this.x + this.w > box.x &&\n this.y < box.y + (box.h ?? 0) &&\n this.y + this.h > box.y\n )\n }\n\n get tag(): T {\n return this.#anim.tag\n }\n\n set tag(tag: T) {\n if (tag === this.#anim.tag) return\n this.#anim = this.#atlas[tag]\n const {hitbox} = this.#anim\n this.hitbox.x = this.x + (this.flipX ? hitbox.w - hitbox.x : hitbox.x)\n this.hitbox.y = this.y + (this.flipY ? hitbox.h - hitbox.y : hitbox.y)\n this.hitbox.w = this.#anim.hitbox.w\n this.hitbox.h = this.#anim.hitbox.h\n this.w = this.#anim.w\n this.h = this.#anim.h\n this._iffzz = (this._iffzz & 0xfffe0003f) | (this.#anim.id << 6)\n }\n\n toString(): string {\n return `${this.tag} (${this.x}, ${this.y}) ${this.w}\u00D7${this.h}`\n }\n\n get w(): number {\n return (this._wh >> 12) & 0xfff\n }\n\n set w(w: number) {\n this._wh = (this._wh & 0xff000fff) | ((w & 0xfff) << 12)\n }\n\n get x(): number {\n return (this._xy >> 16) / 8\n }\n\n set x(x: number) {\n const diff = x - this.x\n this._xy = (this._xy & 0x0000ffff) | (((8 * x) & 0xffff) << 16)\n this.hitbox.x += diff\n }\n\n set xy(xy: Readonly<XY>) {\n this.x = xy.x\n this.y = xy.y\n }\n\n get y(): number {\n return ((this._xy << 16) >> 16) / 8\n }\n\n set y(y: number) {\n const diff = y - this.y\n this._xy = (this._xy & 0xffff0000) | ((8 * y) & 0xffff)\n this.hitbox.y += diff\n }\n\n get z(): number {\n return this._iffzz & 7\n }\n\n /** Greater is further. */\n set z(z: number) {\n this._iffzz = (this._iffzz & 0xfffffff8) | (z & 0x7)\n }\n\n get zend(): boolean {\n return !!(this._iffzz & 0x8)\n }\n\n set zend(end: boolean) {\n if (end) this._iffzz |= 0x8\n else this._iffzz &= 0xfffffff7\n }\n}\n", "export class JSONStorage {\n get<T>(key: string): T | undefined {\n const val = localStorage.getItem(key)\n return val == null ? undefined : JSON.parse(val)\n }\n\n put<T>(key: string, val: T): void {\n if (val == null) localStorage.removeItem(key)\n else localStorage.setItem(key, JSON.stringify(val))\n }\n}\n", "import type {Font} from 'mem-font'\nimport type {AnimTag} from '../atlas/aseprite.js'\n\nexport function fontCharToTag(self: Font, char: string): AnimTag {\n let pt = char.codePointAt(0)\n if (pt == null || pt > 0xff) pt = 63 // ?\n return `${self.id}--${pt.toString(16).padStart(2, '0')}`\n}\n\n/** @arg rhs Undefined means end of line. */\nexport function fontKerning(\n self: Font,\n lhs: string,\n rhs: string | undefined\n): number {\n if (rhs == null) return self.endOfLineKerning\n if (/^\\s*$/.test(lhs) || /^\\s*$/.test(rhs)) return self.whitespaceKerning\n return self.kerning[lhs + rhs] ?? self.defaultKerning\n}\n\nexport function fontCharWidth(self: Font, letter: string): number {\n return self.charWidth[letter] ?? self.defaultCharWidth\n}\n", "import type {Font} from 'mem-font'\nimport type {Box, XY} from '../types/2d.js'\nimport {fontCharWidth, fontKerning} from './font.js'\n\nexport type TextLayout = {\n /** The length of this array matches the string length. */\n readonly chars: (Readonly<Box> | undefined)[]\n /** The offset in pixels. to-do: should this be passed in? */\n readonly cursor: Readonly<XY>\n}\n\nexport function layoutText(font: Font, str: string, maxW: number): TextLayout {\n const chars = []\n let cursor = {x: 0, y: 0}\n while (chars.length < str.length) {\n const i = chars.length\n const char = str[i]!\n let layout\n if (char === '\\n') layout = layoutNewline(font, cursor)\n else if (/^\\s*$/.test(char)) {\n layout = layoutSpace(font, cursor, maxW, tracking(font, char, str[i + 1]))\n } else {\n layout = layoutWord(font, cursor, maxW, str, i)\n if (cursor.x > 0 && layout.cursor.y === nextLine(font, cursor.y).y) {\n const wordW = maxW - cursor.x + layout.cursor.x\n if (wordW <= maxW) {\n // Word can fit on one line if cursor is reset to the start of line.\n cursor = nextLine(font, cursor.y)\n layout = layoutWord(font, cursor, maxW, str, i)\n }\n }\n }\n chars.push(...layout.chars)\n cursor.x = layout.cursor.x\n cursor.y = layout.cursor.y\n }\n return {chars, cursor}\n}\n\n/** @internal */\nexport function layoutWord(\n font: Font,\n cursor: Readonly<XY>,\n maxW: number,\n word: string,\n index: number\n): TextLayout {\n const chars = []\n let {x, y} = cursor\n for (;;) {\n const char = word[index]\n if (!char || /^\\s*$/.test(char)) break\n\n const span = tracking(font, char, word[index + 1])\n if (x > 0 && x + span > maxW) ({x, y} = nextLine(font, y))\n\n // Width is not span since, with kerning, that may exceed the actual\n // width of the character's sprite. For example, if w has the maximal\n // character width of five pixels and a one pixel kerning for a given pair\n // of characters, it will have a span of six pixels which is greater than\n // the maximal five pixel sprite that can be rendered.\n chars.push({x, y, w: fontCharWidth(font, char), h: font.cellHeight})\n x += span\n\n index++\n }\n return {chars, cursor: {x, y}}\n}\n\nfunction nextLine(font: Font, y: number): XY {\n return {x: 0, y: y + font.lineHeight}\n}\n\nfunction layoutNewline(font: Font, cursor: Readonly<XY>): TextLayout {\n return {chars: [undefined], cursor: nextLine(font, cursor.y)}\n}\n\n/**\n * @arg span The distance in pixels from the start of the current character to\n * the start of the next including scale.\n */\nfunction layoutSpace(\n font: Font,\n cursor: Readonly<XY>,\n width: number,\n span: number\n): TextLayout {\n const nextCursor =\n cursor.x > 0 && cursor.x + span >= width\n ? nextLine(font, cursor.y)\n : {x: cursor.x + span, y: cursor.y}\n return {chars: [undefined], cursor: nextCursor}\n}\n\n/** Returns the distance in pixels from the start of lhs to the start of rhs. */\nfunction tracking(font: Font, lhs: string, rhs: string | undefined): number {\n return fontCharWidth(font, lhs) + fontKerning(font, lhs, rhs)\n}\n", "// \u2500\u2500\u2500oidoid>\u00B0\u2500\u2500\nimport type {AnimTag} from './atlas/aseprite.js'\nimport type {Atlas} from './atlas/atlas.js'\nimport {Synth} from './audio/synth.js'\nimport {BitmapBuffer, type Bitmap} from './graphics/bitmap.js'\nimport {Cam} from './graphics/cam.js'\nimport {FrameListener} from './graphics/frame-listener.js'\nimport {Renderer} from './graphics/renderer.js'\nimport {Input, type StandardButton} from './input/input.js'\nimport {Sprite} from './sprite/sprite.js'\nimport {JSONStorage} from './storage/json-storage.js'\n\nexport type {Font} from 'mem-font'\nexport type {SpriteJSON} from './sprite/sprite.js'\nexport {fontCharToTag} from './text/font.js'\nexport {layoutText, type TextLayout} from './text/text-layout.js'\nexport type {Box, WH, XY} from './types/2d.js'\nexport {Sprite}\nexport type {AnimTag, Atlas}\n\ndeclare const atlas: Atlas\ndeclare const atlasURI: string\n\nexport class Void<\n Tag extends AnimTag = AnimTag,\n Button extends string = StandardButton\n> {\n static async new<\n Tag extends AnimTag = AnimTag,\n Button extends string = StandardButton\n >(): Promise<Void<Tag, Button>> {\n return new Void(await loadImage(atlasURI))\n }\n\n readonly atlas: Atlas<Tag> = <Atlas<Tag>>atlas\n readonly cam: Cam = new Cam()\n readonly ctrl: Input<Button>\n readonly kv = new JSONStorage()\n readonly synth = new Synth()\n\n readonly #bitmaps: BitmapBuffer = new BitmapBuffer(1_000_000)\n readonly #framer: FrameListener\n readonly #renderer: Renderer\n\n constructor(spritesheet: HTMLImageElement) {\n const meta = document.createElement('meta')\n meta.name = 'viewport'\n // Don't wait for double-tap scaling on mobile.\n meta.content = 'maximum-scale=1, minimum-scale=1, user-scalable=no'\n document.head.appendChild(meta)\n\n document.body.style.margin = '0'\n document.body.style.width = '100vw'\n document.body.style.height = '100vh'\n document.body.style.overflow = 'hidden'\n\n const canvas = document.createElement('canvas')\n canvas.style.cursor = 'none'\n canvas.style.display = 'block' // No line height spacing.\n canvas.style.imageRendering = 'pixelated'\n // Update on each pointermove *touch* Event like *mouse* Events.\n canvas.style.touchAction = 'none'\n document.body.append(canvas)\n\n this.ctrl = new Input(this.cam, canvas)\n this.#renderer = new Renderer(atlas, canvas, spritesheet)\n this.#framer = new FrameListener(canvas, this.ctrl, this.#renderer)\n this.#framer.register('add')\n this.background = 0x000000ff\n }\n\n set background(rgba: number) {\n document.body.style.background = `#${rgba.toString(16).padStart(8, '0')}`\n this.#renderer.clearColor(rgba)\n }\n\n blit(bmp: Readonly<Bitmap>): void {\n this.#bitmaps.push(bmp)\n }\n\n get frame(): number {\n return this.#framer.frame\n }\n\n render(loop?: () => void): void {\n this.cam.resize()\n this.#framer.render(this.cam, this.#bitmaps, loop)\n this.#bitmaps.size = 0\n }\n\n sprite(tag: Tag): Sprite<Tag> {\n return new Sprite<Tag>(this.atlas, tag)\n }\n\n stop(): void {\n this.#framer.cancel()\n this.#framer.register('remove')\n this.ctrl.register('remove')\n }\n}\n\nfunction loadImage(src: string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image()\n img.onload = () => resolve(img)\n img.onerror = () => reject(img)\n img.src = src\n })\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["export class Synth {\n #context?: AudioContext\n\n beep(\n type: OscillatorType,\n startHz: number,\n endHz: number,\n duration: number // why can't this be short?\n ): void {\n this.#context ??= new AudioContext()\n const now = this.#context.currentTime\n const end = now + duration\n\n const oscillator = this.#context.createOscillator()\n oscillator.type = type\n oscillator.frequency.setValueAtTime(startHz, now)\n oscillator.frequency.exponentialRampToValueAtTime(endHz, end)\n\n const gain = this.#context.createGain()\n gain.gain.setValueAtTime(1, now)\n gain.gain.exponentialRampToValueAtTime(0.01, end)\n\n oscillator.connect(gain)\n gain.connect(this.#context.destination)\n\n oscillator.start()\n oscillator.stop(end)\n }\n}\n", "export type Bitmap = {\n /** 8x: i16, 8y: i16 */\n readonly _xy: number\n /** w: u12, h: u12 */\n readonly _wh: number\n /** id+cel: u15, flipX: b1, flipY: b1, zend: b1, z: u3 */\n readonly _iffzz: number\n}\n\nexport class BitmapBuffer {\n readonly buffer: Uint32Array\n size = 0\n\n constructor(capacity: number) {\n this.buffer = new Uint32Array(capacity * 3)\n }\n\n push(bmp: Readonly<Bitmap>): void {\n this.buffer[this.size * 3] = bmp._xy\n this.buffer[this.size * 3 + 1] = bmp._wh\n this.buffer[this.size * 3 + 2] = bmp._iffzz\n this.size++\n }\n}\n", "import type {Box, WH, XY} from '../types/2d.js'\n\nexport class Cam implements Box {\n minWH: WH = {w: 256, h: 256}\n minScale: number = 1\n x: number = 0 //xy?\n y: number = 0\n lvl: Box = {x: -4096, y: -4096, w: 8191, h: 8191}\n\n readonly #clientWH: WH = {w: 1, h: 1}\n #scale = 1\n #w = this.minWH.w\n #h = this.minWH.h\n\n get h(): number {\n return this.#h\n }\n\n /** Fill or just barely not fill the viewport in scaled pixels. */\n resize(zoomOut?: number): void {\n // WH of body in CSS px; document.body.getBoundingClientRect() returns\n // incorrectly large sizing on mobile that includes the address bar\n this.#clientWH.w = innerWidth\n this.#clientWH.h = innerHeight\n\n const nativeW = Math.round(this.#clientWH.w * devicePixelRatio) // physical\n const nativeH = Math.round(this.#clientWH.h * devicePixelRatio)\n\n this.#scale = Math.max(\n this.minScale,\n Math.floor(Math.min(nativeW / this.minWH.w, nativeH / this.minWH.h)) -\n (zoomOut ?? 0) // Default is to zoom in as much as possible.\n )\n this.#w = Math.floor(nativeW / this.#scale)\n this.#h = Math.floor(nativeH / this.#scale)\n }\n\n get scale(): number {\n return this.#scale\n }\n\n /** Returns the integral position in level coordinates. */\n toLevelXY(clientXY: Readonly<XY>): XY {\n return {\n x: Math.round(this.x + (clientXY.x / this.#clientWH.w) * this.#w),\n y: Math.round(this.y + (clientXY.y / this.#clientWH.h) * this.#h)\n }\n }\n\n get w(): number {\n return this.#w\n }\n}\n", "export class GamepadPoller {\n #bits = 0\n readonly #bitByAxis: {[axis: number]: [less: number, more: number]} = {}\n readonly #bitByButton: {[btn: number]: number} = {}\n\n get bits(): number {\n return this.#bits\n }\n\n mapAxis(axis: number, lessBit: number, moreBit: number): void {\n this.#bitByAxis[axis] = [lessBit, moreBit]\n }\n\n mapButton(button: number, bit: number): void {\n this.#bitByButton[button] = bit\n }\n\n poll(): void {\n if (!isSecureContext) return\n this.#bits = 0\n for (const pad of navigator.getGamepads()) {\n for (const [index, axis] of pad?.axes.entries() ?? []) {\n const bits = this.#bitByAxis[index]\n if (bits == null) continue\n const bit = axis < 0 ? bits[0] : axis === 0 ? 0 : bits[1]\n this.#bits |= Math.abs(axis) >= 0.5 ? bit : 0\n }\n for (const [index, button] of pad?.buttons.entries() ?? []) {\n const bit = this.#bitByButton[index]\n if (bit == null) continue\n this.#bits |= button.pressed ? bit : 0\n }\n }\n }\n\n reset(): void {\n this.#bits = 0\n }\n}\n", "export class KeyboardPoller {\n #bits = 0\n readonly #bitByKey: {[key: string]: number} = {}\n\n get bits(): number {\n return this.#bits\n }\n\n map(key: string, bit: number): void {\n this.#bitByKey[key] = bit\n }\n\n register(op: 'add' | 'remove'): void {\n const fn = <const>`${op}EventListener`\n // keyup is not received if window loses focus.\n globalThis[fn]('blur', this.reset, {capture: true, passive: true})\n for (const type of ['keydown', 'keyup']) {\n const callback = <EventListenerOrEventListenerObject>this.#onKey\n globalThis[fn](type, callback, {capture: true, passive: true})\n }\n }\n\n reset = (): void => {\n this.#bits = 0\n }\n\n #onKey = (ev: KeyboardEvent): void => {\n const on = ev.type === 'keydown'\n const bit = this.#bitByKey[ev.key]\n if (bit == null) return\n this.#bits = on ? this.#bits | bit : this.#bits & ~bit\n }\n}\n", "import {Cam} from '../graphics/cam.js'\nimport type {XY} from '../types/2d.js'\n\nexport class PointerPoller {\n readonly #bitByButton: {[btn: number]: number} = {}\n #bits: number = 0\n readonly #cam: Readonly<Cam>\n readonly #canvas: HTMLCanvasElement\n readonly #clientXY: XY = {x: 0, y: 0}\n #type?: 'mouse' | 'touch' | 'pen' | undefined\n #xy?: Readonly<XY> | undefined\n\n constructor(cam: Readonly<Cam>, canvas: HTMLCanvasElement) {\n this.#cam = cam\n this.#canvas = canvas\n }\n\n get bits(): number {\n return this.#bits\n }\n\n map(button: number, bit: number): void {\n this.#bitByButton[button] = bit\n }\n\n get type(): 'mouse' | 'touch' | 'pen' | undefined {\n return this.#type\n }\n\n register(op: 'add' | 'remove'): void {\n const fn = <const>`${op}EventListener`\n this.#canvas[fn]('pointercancel', this.reset, {\n capture: true,\n passive: true\n })\n for (const type of ['pointerdown', 'pointermove', 'pointerup']) {\n this.#canvas[fn](\n type,\n <EventListenerOrEventListenerObject>this.#onPointEvent,\n {capture: true, passive: type !== 'pointerdown'}\n )\n }\n this.#canvas[fn]('contextmenu', this.#onContextMenuEvent, {capture: true})\n }\n\n reset = (): void => {\n this.#bits = 0\n this.#type = undefined\n this.#xy = undefined\n }\n\n get xy(): Readonly<XY> | undefined {\n return this.#xy\n }\n\n #onContextMenuEvent = (ev: Event): void => ev.preventDefault()\n\n #onPointEvent = (ev: PointerEvent): void => {\n // Ignore non-primary inputs to avoid flickering between distant points.\n if (!ev.isPrimary) return\n\n if (ev.type === 'pointerdown') this.#canvas.setPointerCapture(ev.pointerId)\n ;({clientX: this.#clientXY.x, clientY: this.#clientXY.y} = ev)\n\n this.#bits = this.#evButtonsToBits(ev.buttons)\n this.#type = (<const>['mouse', 'touch', 'pen']).find(\n type => type === ev.pointerType\n )\n this.#xy = this.#cam.toLevelXY(this.#clientXY)\n\n const passive = ev.type !== 'pointerdown'\n if (!passive) ev.preventDefault()\n }\n\n #evButtonsToBits(buttons: number): number {\n let bits = 0\n for (let button = 1; button <= buttons; button <<= 1) {\n if ((button & buttons) !== button) continue\n bits |= this.#bitByButton[button] ?? 0\n }\n return bits\n }\n}\n", "import {Cam} from '../graphics/cam.js'\nimport type {XY} from '../types/2d.js'\nimport {GamepadPoller} from './gamepad-poller.js'\nimport {KeyboardPoller} from './keyboard-poller.js'\nimport {PointerPoller} from './pointer-poller.js'\n\n// prettier-ignore\nexport type StandardButton =\n 'L' | 'R' | 'U' | 'D' | // Dpad.\n 'C' | 'B' | 'A' | // Primary, secondary, tertiary.\n 'S' // Start.\n\nexport class Input<Button extends string = StandardButton> {\n handled = false\n /** The maximum duration in milliseconds permitted between combo inputs. */\n maxInterval = 300\n /** The minimum duration in milliseconds for an input to be considered held. */\n minHeld = 300\n\n /** The time in milliseconds since the input changed. */\n #duration = 0\n /** Prior button state, possibly 0, but not necessarily a combo member. */\n #prevBits = 0\n /**\n * A sequence of nonzero buttons ordered from oldest (first) to latest (last).\n * Combos are terminated only by expiration.\n */\n readonly #combo: number[] = []\n /** Logical button to bit. */\n readonly #bitByButton = <{[btn in Button]: number}>{}\n readonly #gamepad = new GamepadPoller()\n readonly #keyboard = new KeyboardPoller()\n readonly #pointer: PointerPoller\n #pollBits = 0\n #pollTick = 0\n\n constructor(cam: Readonly<Cam>, canvas: HTMLCanvasElement) {\n this.#pointer = new PointerPoller(cam, canvas)\n }\n\n /**\n * Combos are interpreted exactly both in buttons pressed per tick (eg, up\n * will not match up and down the way `isOn('Up')` will) and sequence (order\n * and length). Combos only test button on state.\n */\n isCombo(...combo: readonly (readonly Button[])[]): boolean {\n if (combo.length !== this.#combo.length) return false\n for (const [i, buttons] of combo.entries()) {\n const bits = this.#buttonsToBits(buttons)\n if (this.#combo[i] !== bits) return false\n }\n // #combo is a historical record of buttons. Whenever buttons changes, a new\n // entry is pushed. Make sure the current entry is the current state and\n // that the last entry's buttons haven't been released.\n return this.#combo[combo.length - 1] === this.#bits\n }\n\n /** Like isOnCombo() but test if the last button set is triggered. */\n isComboStart(...combo: readonly (readonly Button[])[]): boolean {\n return (\n this.isCombo(...combo) &&\n !!combo.at(-1)?.every(button => this.isOnStart(button))\n )\n }\n\n /** True if held on or off. */\n isHeld(): boolean {\n return this.#duration >= this.minHeld\n }\n\n isOffStart(...buttons: readonly Button[]): boolean {\n return !this.isOn(...buttons) && this.isStart(...buttons)\n }\n\n /**\n * Test if all buttons are on. True if the buttons are pressed regardless of\n * whether other buttons are pressed. Eg, `isOn('Up')` will return true when\n * up is pressed or when up and down are pressed.\n */\n isOn(...buttons: readonly Button[]): boolean {\n const bits = this.#buttonsToBits(buttons)\n return (this.#bits & bits) === bits\n }\n\n isOnStart(...buttons: readonly Button[]): boolean {\n return this.isOn(...buttons) && this.isStart(...buttons)\n }\n\n /** True if triggered on or off. */\n isStart(...buttons: readonly Button[]): boolean {\n const bits = this.#buttonsToBits(buttons)\n return (this.#bits & bits) !== (this.#prevBits & bits)\n }\n\n mapAxis(less: Button, more: Button, ...axes: readonly number[]): void {\n for (const axis of axes) {\n this.#gamepad.mapAxis(axis, this.#map(less), this.#map(more))\n }\n }\n\n mapButton(button: Button, ...indices: readonly number[]): void {\n for (const index of indices) {\n this.#gamepad.mapButton(index, this.#map(button))\n }\n }\n\n mapClick(button: Button, ...clicks: readonly number[]): void {\n for (const click of clicks) this.#pointer.map(click, this.#map(button))\n }\n\n mapStandard(): void {\n this.mapKey(<Button>'L', 'ArrowLeft', 'a')\n this.mapKey(<Button>'R', 'ArrowRight', 'd')\n this.mapKey(<Button>'U', 'ArrowUp', 'w')\n this.mapKey(<Button>'D', 'ArrowDown', 's')\n this.mapKey(<Button>'C', 'z')\n this.mapKey(<Button>'B', 'x')\n this.mapKey(<Button>'A', 'c')\n this.mapKey(<Button>'S', 'Enter', 'Escape')\n\n // https://w3c.github.io/gamepad/#remapping\n this.mapAxis(<Button>'L', <Button>'R', 0, 2)\n this.mapAxis(<Button>'U', <Button>'D', 1, 3)\n this.mapButton(<Button>'L', 14)\n this.mapButton(<Button>'R', 15)\n this.mapButton(<Button>'U', 12)\n this.mapButton(<Button>'D', 13)\n this.mapButton(<Button>'A', 0)\n this.mapButton(<Button>'S', 9)\n\n this.mapClick(<Button>'A', 1)\n }\n\n mapKey(button: Button, ...keys: readonly string[]): void {\n for (const key of keys) this.#keyboard.map(key, this.#map(button))\n }\n\n get point(): Readonly<XY> | undefined {\n return this.#pointer.xy\n }\n\n get pointType(): 'mouse' | 'touch' | 'pen' | undefined {\n return this.#pointer.type\n }\n\n poll(tick: number): void {\n this.handled = false\n this.#duration += this.#pollTick\n this.#prevBits = this.#pollBits\n\n this.#gamepad.poll()\n if (\n this.#duration > this.maxInterval &&\n (this.#bits === 0 || this.#bits !== this.#prevBits)\n ) {\n // Expired.\n this.#duration = 0\n this.#combo.length = 0\n } else if (this.#bits !== this.#prevBits) {\n // Some button state has changed and at least one button is still pressed.\n this.#duration = 0\n if (this.#bits !== 0) this.#combo.push(this.#bits)\n } else if (this.#bits !== 0 && this.#bits === this.#prevBits) {\n // Held. Update combo with the latest buttons.\n this.#combo.pop()\n this.#combo.push(this.#bits)\n }\n\n this.#pollTick = tick\n this.#pollBits = this.#bits\n }\n\n register(op: 'add' | 'remove'): void {\n this.#keyboard.register(op)\n this.#pointer.register(op)\n }\n\n reset(): void {\n this.handled = false\n this.#gamepad.reset()\n this.#keyboard.reset()\n this.#pointer.reset()\n }\n\n /**\n * The current state and prospective combo member. A zero value can never be a\n * combo member but is necessary to persist in previous to distinguish the off\n * state between repeated button presses like up, up.\n */\n get #bits(): number {\n return this.#gamepad.bits | this.#keyboard.bits | this.#pointer.bits\n }\n\n #buttonsToBits(buttons: readonly Button[]): number {\n let bits = 0\n for (const button of buttons) bits |= this.#bitByButton[button] ?? 0\n return bits\n }\n\n #map(button: Button): number {\n return (this.#bitByButton[button] ??=\n 1 << Object.keys(this.#bitByButton).length)\n }\n}\n", "export const fragGLSL = `#version 300 es\nuniform mediump sampler2D uSpritesheet;\nuniform mediump uvec2 uSpritesheetSize;\n\nflat in highp ivec4 vTexXYWH;\nin highp vec2 vDstWH;\n\nout highp vec4 oFrag;\n\nvoid main() {\n highp vec2 px = vec2(vTexXYWH.xy) + mod(vDstWH, vec2(vTexXYWH.zw));\n oFrag = texture(uSpritesheet, px / vec2(uSpritesheetSize));\n if(oFrag.a < 1.) discard;\n}`\n", "export const vertGLSL = `#version 300 es\n// https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#essl300_minimum_requirements_webgl_2\nuniform lowp usampler2D uCels;\nuniform mediump ivec4 uCam;\nuniform highp uint uFrame;\n\nlayout (location=0) in lowp ivec2 iUV;\nlayout (location=1) in highp uint iXY;\nlayout (location=2) in highp uint iWH;\nlayout (location=3) in highp uint iIFFZZ;\n\nflat out highp ivec4 vTexXYWH;\nout highp vec2 vDstWH;\n\nconst mediump int maxY = 0x1000;\nconst lowp int maxZ = 8;\nconst mediump int maxDepth = maxY * maxZ;\n\nvoid main() {\n mediump int x = int(iXY) >> 19;\n mediump int y = int(iXY << 16) >> 19;\n lowp int z = int(iIFFZZ & 0x7u);\n bool zend = bool(iIFFZZ & 0x8u);\n bool flipX = bool(iIFFZZ & 0x20u);\n bool flipY = bool(iIFFZZ & 0x10u);\n mediump int id = int((iIFFZZ >> 6) & 0x7ff0u);\n lowp int cel = int((iIFFZZ >> 6) & 0xfu);\n mediump int w = int((iWH >> 12) & 0xfffu);\n mediump int h = int(iWH & 0xfffu);\n\n lowp int frame = ((int(uFrame) - cel) / 4) & 0xf;\n mediump uvec4 texXYWH = texelFetch(uCels, ivec2(0, id + frame), 0);\n\n // https://www.patternsgameprog.com/opengl-2d-facade-25-get-the-z-of-a-pixel\n highp float depth = float((z + 1) * maxY - (y + (zend ? 0 : h))) / float(maxDepth);\n\n highp ivec2 targetWH = ivec2(iUV) * ivec2(w, h);\n highp ivec2 origWH = ivec2(iUV) * ivec2(texXYWH.zw);\n\n highp vec2 end = vec2(x + targetWH.x, y + targetWH.y);\n highp vec2 clip = ((-2. * vec2(uCam.xy) + 2. * end) / vec2(uCam.zw) - 1.) * vec2(1, -1);\n gl_Position = vec4(clip, depth, 1);\n vTexXYWH = ivec4(texXYWH);\n vDstWH = vec2(targetWH * ivec2(flipX ? -1 : 1, flipY ? -1 : 1));\n}`\n", "import {maxAnimCels, type Anim} from '../atlas/anim.js'\nimport type {AnimTag, Atlas} from '../index.js'\nimport {BitmapBuffer} from './bitmap.js'\nimport {Cam} from './cam.js'\nimport {fragGLSL} from './frag.glsl.js'\nimport {vertGLSL} from './vert.glsl.js'\n\ntype GLUniforms = {readonly [name: string]: WebGLUniformLocation | null}\ntype GL = WebGL2RenderingContext\ntype GLProgram = WebGLProgram | null\n\nconst uv: Readonly<Int8Array> = new Int8Array([1, 1, 0, 1, 1, 0, 0, 0])\n\nexport class Renderer {\n #bmpBuffer: Readonly<WebGLBuffer> | null = null\n readonly #canvas: HTMLCanvasElement\n readonly #cels: Readonly<Uint16Array>\n #gl!: GL\n #loseContext: Readonly<WEBGL_lose_context | null> = null\n readonly #spritesheet: HTMLImageElement\n #uniforms: Readonly<GLUniforms> = {}\n #vertArray: WebGLVertexArrayObject | null = null\n\n constructor(\n atlas: Atlas,\n canvas: HTMLCanvasElement,\n spritesheet: HTMLImageElement\n ) {\n this.#canvas = canvas\n this.#spritesheet = spritesheet\n this.#cels = new Uint16Array(newCels(atlas))\n }\n\n clearColor(rgba: number): void {\n this.#gl.clearColor(\n ((rgba >>> 24) & 0xff) / 0xff,\n ((rgba >>> 16) & 0xff) / 0xff,\n ((rgba >>> 8) & 0xff) / 0xff,\n ((rgba >>> 0) & 0xff) / 0xff\n )\n }\n\n initGL(): void {\n const gl = this.#canvas.getContext('webgl2', {\n antialias: false,\n desynchronized: true, // breaks render stats\n powerPreference: 'high-performance'\n })\n if (!gl) throw Error('WebGL v2 unsupported')\n this.#gl = gl\n\n // Allow transparent textures to be layered.\n gl.enable(gl.BLEND)\n gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)\n\n // Enable z-buffer for [0, 1] ([foreground, background]).\n gl.enable(gl.DEPTH_TEST)\n gl.depthRange(0, 1)\n gl.clearDepth(1)\n gl.depthFunc(gl.LESS)\n\n // Disable image colorspace conversions. The default is browser dependent.\n gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, false)\n\n const pgm = loadProgram(gl, vertGLSL, fragGLSL)\n this.#uniforms = getUniformLocations(gl, pgm)\n\n gl.uniform2ui(\n this.#uniforms.uSpritesheetSize!,\n this.#spritesheet.naturalWidth,\n this.#spritesheet.naturalHeight\n )\n\n this.#vertArray = gl.createVertexArray()\n gl.bindVertexArray(this.#vertArray)\n\n const uvBuffer = gl.createBuffer()\n gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer)\n gl.enableVertexAttribArray(0)\n gl.vertexAttribIPointer(0, 2, gl.BYTE, 0, 0)\n gl.bindBuffer(gl.ARRAY_BUFFER, null)\n\n this.#bmpBuffer = gl.createBuffer()\n gl.bindBuffer(gl.ARRAY_BUFFER, this.#bmpBuffer)\n gl.enableVertexAttribArray(1)\n gl.vertexAttribIPointer(1, 1, gl.UNSIGNED_INT, 12, 0)\n gl.vertexAttribDivisor(1, 1)\n gl.enableVertexAttribArray(2)\n gl.vertexAttribIPointer(2, 1, gl.UNSIGNED_INT, 12, 4)\n gl.vertexAttribDivisor(2, 1)\n gl.enableVertexAttribArray(3)\n gl.vertexAttribIPointer(3, 1, gl.UNSIGNED_INT, 12, 8)\n gl.vertexAttribDivisor(3, 1)\n gl.bindBuffer(gl.ARRAY_BUFFER, null)\n\n gl.bindVertexArray(null)\n\n gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer)\n gl.bufferData(gl.ARRAY_BUFFER, uv, gl.STATIC_DRAW)\n gl.bindBuffer(this.#gl.ARRAY_BUFFER, null)\n\n gl.uniform1i(this.#uniforms.uCels!, 0)\n gl.activeTexture(gl.TEXTURE0)\n const dataTex = gl.createTexture()\n gl.bindTexture(gl.TEXTURE_2D, dataTex)\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n gl.RGBA16UI,\n 1,\n this.#cels.length / 4, // 4 u8s per row\n 0,\n gl.RGBA_INTEGER,\n gl.UNSIGNED_SHORT,\n this.#cels\n )\n\n gl.uniform1i(this.#uniforms.uSpritesheet!, 1)\n gl.activeTexture(gl.TEXTURE1)\n const spritesheetTex = gl.createTexture()\n gl.bindTexture(gl.TEXTURE_2D, spritesheetTex)\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n gl.RGBA,\n gl.RGBA,\n gl.UNSIGNED_BYTE,\n this.#spritesheet\n )\n\n this.#loseContext = gl.getExtension('WEBGL_lose_context')\n }\n\n get loseContext(): WEBGL_lose_context | null {\n return this.#loseContext\n }\n\n hasContext(): boolean {\n return !this.#gl.isContextLost()\n }\n\n render(\n cam: Readonly<Cam>,\n frame: number,\n bmps: Readonly<BitmapBuffer>\n ): void {\n this.#resize(cam)\n this.#gl.clear(this.#gl.COLOR_BUFFER_BIT | this.#gl.DEPTH_BUFFER_BIT)\n\n this.#gl.uniform4i(this.#uniforms.uCam!, cam.x, cam.y, cam.w, cam.h)\n this.#gl.uniform1ui(this.#uniforms.uFrame!, frame)\n\n this.#gl.bindVertexArray(this.#vertArray)\n\n this.#gl.bindBuffer(this.#gl.ARRAY_BUFFER, this.#bmpBuffer)\n this.#gl.bufferData(\n this.#gl.ARRAY_BUFFER,\n bmps.buffer,\n this.#gl.STREAM_DRAW\n )\n this.#gl.bindBuffer(this.#gl.ARRAY_BUFFER, null)\n\n this.#gl.drawArraysInstanced(\n this.#gl.TRIANGLE_STRIP,\n 0,\n uv.length / 2, // d\n bmps.size\n )\n\n this.#gl.bindVertexArray(null)\n }\n\n #resize(cam: Readonly<Cam>): void {\n const canvas = this.#canvas\n const nativeWH = {w: cam.w * cam.scale, h: cam.h * cam.scale}\n\n if (canvas.width !== nativeWH.w || canvas.height !== nativeWH.h) {\n canvas.width = nativeWH.w\n canvas.height = nativeWH.h\n this.#gl.viewport(0, 0, nativeWH.w, nativeWH.h)\n }\n\n // These pixels may be greater than, less than, or equal to native.\n const clientW = nativeWH.w / devicePixelRatio\n const clientH = nativeWH.h / devicePixelRatio\n const diffW = Number.parseFloat(canvas.style.width.slice(0, -2)) - clientW\n const diffH = Number.parseFloat(canvas.style.height.slice(0, -2)) - clientH\n if (\n !Number.isFinite(diffW) ||\n Math.abs(diffW) >= 0.5 ||\n !Number.isFinite(diffH) ||\n Math.abs(diffH) >= 0.5\n ) {\n canvas.style.width = `${clientW}px`\n canvas.style.height = `${clientH}px`\n }\n }\n}\n\nfunction compileShader(gl: GL, type: number, src: string): WebGLShader {\n const shader = gl.createShader(type)\n if (!shader) throw Error('shader creation failed')\n gl.shaderSource(shader, src.trim())\n gl.compileShader(shader)\n\n const log = gl.getShaderInfoLog(shader)?.slice(0, -1)\n if (log) console.warn(log)\n\n return shader\n}\n\nfunction getUniformLocations(gl: GL, pgm: GLProgram): GLUniforms {\n if (!pgm) return {}\n const len = gl.getProgramParameter(pgm, gl.ACTIVE_UNIFORMS)\n const locations: {[name: string]: WebGLUniformLocation | null} = {}\n for (let i = 0; i < len; ++i) {\n const uniform = gl.getActiveUniform(pgm, i)\n if (uniform == null) throw Error(`missing shader uniform at index ${i}`)\n locations[uniform.name] = gl.getUniformLocation(pgm, uniform.name)\n }\n return locations\n}\n\nfunction loadProgram(gl: GL, vertGLSL: string, fragGLSL: string): GLProgram {\n const pgm = gl.createProgram()\n if (!pgm) return null\n\n const vert = compileShader(gl, gl.VERTEX_SHADER, vertGLSL)\n const frag = compileShader(gl, gl.FRAGMENT_SHADER, fragGLSL)\n gl.attachShader(pgm, vert)\n gl.attachShader(pgm, frag)\n gl.linkProgram(pgm)\n gl.useProgram(pgm)\n\n const log = gl.getProgramInfoLog(pgm)?.slice(0, -1)\n if (log) console.warn(log)\n\n gl.detachShader(pgm, frag)\n gl.detachShader(pgm, vert)\n gl.deleteShader(frag)\n gl.deleteShader(vert)\n\n return pgm\n}\n\n/** XYWH ordered by ID and padded to 16-cel blocks. */\nfunction newCels(atlas: Atlas): readonly number[] {\n const cels = []\n for (const anim of Object.values<Anim<AnimTag>>(atlas)) {\n // Animations are inserted in ID order.\n for (const cel of anim.cels) cels.push(cel.x, cel.y, anim.w, anim.h)\n for (let i = anim.cels.length; i < maxAnimCels; i++) {\n const cel = anim.cels[i % anim.cels.length]!\n cels.push(cel.x, cel.y, anim.w, anim.h)\n }\n }\n return cels\n}\n", "import {Input} from '../input/input.js'\nimport {BitmapBuffer} from './bitmap.js'\nimport {Cam} from './cam.js'\nimport {Renderer} from './renderer.js'\n\nexport class FrameListener {\n /** The running lifetime in milliseconds. */\n age = 0\n /** The exact duration in milliseconds to apply on a given update step. */\n tick = 0\n\n readonly #canvas: HTMLCanvasElement\n #frame?: number | undefined\n #loop?: (() => void) | undefined\n #time?: number | undefined\n readonly #input: Input\n readonly #renderer: Renderer\n\n constructor(\n canvas: HTMLCanvasElement,\n input: Input<string>,\n renderer: Renderer\n ) {\n this.#canvas = canvas\n this.#input = input\n this.#renderer = renderer\n }\n\n cancel(): void {\n if (this.#frame != null) cancelAnimationFrame(this.#frame)\n this.#frame = undefined\n this.tick = 0\n this.#time = undefined\n this.#input.reset()\n this.#loop = undefined\n }\n\n get frame(): number {\n // Assume 60 FPS so games can scale to this number regardless of actual.\n return Math.trunc(this.age / 16.666666666666668)\n }\n\n register(op: 'add' | 'remove'): void {\n const fn = <const>`${op}EventListener`\n for (const type of ['webglcontextrestored', 'webglcontextlost']) {\n this.#canvas[fn](type, this.#onEvent, true)\n }\n globalThis[fn]('visibilitychange', this.#onEvent, true)\n if (op === 'add') this.#renderer.initGL()\n this.#input.register(op)\n }\n\n render(cam: Readonly<Cam>, buffer: BitmapBuffer, loop?: () => void): void {\n this.#loop = loop\n if (!this.#isVisible() || !this.#renderer.hasContext()) return\n if (this.#loop) this.#frame ??= requestAnimationFrame(this.#onFrame)\n this.#renderer.render(cam, this.frame, buffer)\n }\n\n #isVisible(): boolean {\n return document.visibilityState === 'visible'\n }\n\n #onEvent = (event: Event): void => {\n event.preventDefault()\n if (event.type === 'webglcontextrestored') this.#renderer.initGL()\n\n if (this.#renderer.hasContext() && this.#isVisible()) {\n if (this.#loop) this.#frame ??= requestAnimationFrame(this.#onFrame)\n } else {\n if (this.#frame != null) cancelAnimationFrame(this.#frame)\n this.#frame = undefined\n this.tick = 0\n this.#time = undefined\n this.#input.reset()\n }\n }\n\n #onFrame = (time: number): void => {\n this.#frame = undefined\n this.tick = time - (this.#time ?? time)\n this.#time = time\n this.age += this.tick\n const loop = this.#loop\n this.#loop = undefined\n this.#input.poll(this.tick)\n loop?.()\n }\n}\n", "import type {Anim, AnimTag} from '../atlas/anim.js'\nimport type {Atlas} from '../atlas/atlas.js'\nimport type {Bitmap} from '../graphics/bitmap.js'\nimport type {Box, WH, XY} from '../types/2d.js'\n\nexport type SpriteJSON = {\n cel?: number\n flip?: string\n tag: string\n x?: number\n y?: number\n z?: number\n w?: number\n h?: number\n zend?: boolean\n}\n\nexport class Sprite<T extends AnimTag = AnimTag> implements Bitmap, Box {\n static parse<T extends AnimTag = AnimTag>(\n atlas: Atlas<T>,\n json: Readonly<SpriteJSON>\n ): Sprite<T> {\n if (!(json.tag in atlas)) throw Error(`atlas missing tag \"${json.tag}\"`)\n const sprite = new Sprite(atlas, <T>json.tag)\n sprite.cel = json.cel ?? 0\n sprite.flipX = json.flip === 'X' || json.flip === 'XY'\n sprite.flipY = json.flip === 'Y' || json.flip === 'XY'\n sprite.x = json.x ?? 0\n sprite.y = json.y ?? 0\n sprite.z = json.z ?? 0\n sprite.zend = json.zend ?? false\n if (json.w != null) sprite.w = json.w\n if (json.h != null) sprite.h = json.h\n return sprite\n }\n\n readonly hitbox: Box = {x: 0, y: 0, w: 0, h: 0}\n\n _iffzz = 0\n _xy = 0\n _wh = 0\n\n #anim: Anim<T> = <Anim<T>>{}\n #atlas: Atlas<T>\n\n constructor(atlas: Atlas<T>, tag: T) {\n this.#atlas = atlas\n this.tag = tag\n }\n\n above(sprite: Readonly<Sprite>): boolean {\n const compare =\n this.z === sprite.z\n ? (sprite.zend ? sprite.y + sprite.h : sprite.y) -\n (this.zend ? this.y + this.h : this.y)\n : this.z - sprite.z\n return compare < 0\n }\n\n get cel(): number {\n return (this._iffzz >> 6) & 0xf\n }\n\n /** Set to frame number to start at the beginning. */\n set cel(cel: number) {\n this._iffzz = (this._iffzz & 0xfffffc3f) | ((cel & 0xf) << 6)\n }\n\n get flipX(): boolean {\n return !!(this._iffzz & 0x20)\n }\n\n set flipX(flip: boolean) {\n if (this.flipX === flip) return\n if (flip) {\n this._iffzz |= 0x20\n const diff = this.hitbox.x - this.x\n this.hitbox.x = this.x + this.hitbox.w - diff\n } else {\n this._iffzz &= 0xffffffdf\n const diff = this.hitbox.x - this.hitbox.w\n this.hitbox.x = this.x + diff\n }\n }\n\n get flipY(): boolean {\n return !!(this._iffzz & 0x10)\n }\n\n set flipY(flip: boolean) {\n if (this.flipY === flip) return\n if (flip) {\n this._iffzz |= 0x10\n const diff = this.hitbox.y - this.y\n this.hitbox.y = this.y + this.hitbox.h - diff\n } else {\n this._iffzz &= 0xffffffef\n const diff = this.hitbox.y - this.hitbox.h\n this.hitbox.y = this.y + diff\n }\n }\n\n get h(): number {\n return this._wh & 0xfff\n }\n\n set h(h: number) {\n this._wh = (this._wh & 0xfffff000) | (h & 0xfff)\n }\n\n hits(box: Readonly<XY & Partial<WH>>): boolean {\n if (!this.hitbox.w || !this.hitbox.h) return false\n if (box instanceof Sprite) box = box.hitbox\n return (\n this.hitbox.x < box.x + (box.w ?? 0) &&\n this.hitbox.x + this.hitbox.w > box.x &&\n this.hitbox.y < box.y + (box.h ?? 0) &&\n this.hitbox.y + this.hitbox.h > box.y\n )\n }\n\n overlaps(box: Readonly<XY & Partial<WH>>): boolean {\n return (\n this.x < box.x + (box.w ?? 0) &&\n this.x + this.w > box.x &&\n this.y < box.y + (box.h ?? 0) &&\n this.y + this.h > box.y\n )\n }\n\n get tag(): T {\n return this.#anim.tag\n }\n\n set tag(tag: T) {\n if (tag === this.#anim.tag) return\n this.#anim = this.#atlas[tag]\n const {hitbox} = this.#anim\n this.hitbox.x = this.x + (this.flipX ? hitbox.w - hitbox.x : hitbox.x)\n this.hitbox.y = this.y + (this.flipY ? hitbox.h - hitbox.y : hitbox.y)\n this.hitbox.w = this.#anim.hitbox.w\n this.hitbox.h = this.#anim.hitbox.h\n this.w = this.#anim.w\n this.h = this.#anim.h\n this._iffzz = (this._iffzz & 0xfffe0003f) | (this.#anim.id << 6)\n }\n\n toString(): string {\n return `${this.tag} (${this.x}, ${this.y}) ${this.w}\u00D7${this.h}`\n }\n\n get w(): number {\n return (this._wh >> 12) & 0xfff\n }\n\n set w(w: number) {\n this._wh = (this._wh & 0xff000fff) | ((w & 0xfff) << 12)\n }\n\n get x(): number {\n return (this._xy >> 16) / 8\n }\n\n set x(x: number) {\n const diff = x - this.x\n this._xy = (this._xy & 0x0000ffff) | (((8 * x) & 0xffff) << 16)\n this.hitbox.x += diff\n }\n\n set xy(xy: Readonly<XY>) {\n this.x = xy.x\n this.y = xy.y\n }\n\n get y(): number {\n return ((this._xy << 16) >> 16) / 8\n }\n\n set y(y: number) {\n const diff = y - this.y\n this._xy = (this._xy & 0xffff0000) | ((8 * y) & 0xffff)\n this.hitbox.y += diff\n }\n\n get z(): number {\n return this._iffzz & 7\n }\n\n /** Greater is further. */\n set z(z: number) {\n this._iffzz = (this._iffzz & 0xfffffff8) | (z & 0x7)\n }\n\n get zend(): boolean {\n return !!(this._iffzz & 0x8)\n }\n\n set zend(end: boolean) {\n if (end) this._iffzz |= 0x8\n else this._iffzz &= 0xfffffff7\n }\n}\n", "export class JSONStorage {\n get<T>(key: string): T | undefined {\n const val = localStorage.getItem(key)\n return val == null ? undefined : JSON.parse(val)\n }\n\n put<T>(key: string, val: T): void {\n if (val == null) localStorage.removeItem(key)\n else localStorage.setItem(key, JSON.stringify(val))\n }\n}\n", "import type {Font} from 'mem-font'\nimport type {AnimTag} from '../atlas/anim.js'\n\nexport function fontCharToTag(self: Font, char: string): AnimTag {\n let pt = char.codePointAt(0)\n if (pt == null || pt > 0xff) pt = 63 // ?\n return `${self.id}--${pt.toString(16).padStart(2, '0')}`\n}\n\n/** @arg rhs Undefined means end of line. */\nexport function fontKerning(\n self: Font,\n lhs: string,\n rhs: string | undefined\n): number {\n if (rhs == null) return self.endOfLineKerning\n if (/^\\s*$/.test(lhs) || /^\\s*$/.test(rhs)) return self.whitespaceKerning\n return self.kerning[lhs + rhs] ?? self.defaultKerning\n}\n\nexport function fontCharWidth(self: Font, letter: string): number {\n return self.charWidth[letter] ?? self.defaultCharWidth\n}\n", "import type {Font} from 'mem-font'\nimport type {Box, XY} from '../types/2d.js'\nimport {fontCharWidth, fontKerning} from './font.js'\n\nexport type TextLayout = {\n /** The length of this array matches the string length. */\n readonly chars: (Readonly<Box> | undefined)[]\n /** The offset in pixels. to-do: should this be passed in? */\n readonly cursor: Readonly<XY>\n}\n\nexport function layoutText(font: Font, str: string, maxW: number): TextLayout {\n const chars = []\n let cursor = {x: 0, y: 0}\n while (chars.length < str.length) {\n const i = chars.length\n const char = str[i]!\n let layout\n if (char === '\\n') layout = layoutNewline(font, cursor)\n else if (/^\\s*$/.test(char)) {\n layout = layoutSpace(font, cursor, maxW, tracking(font, char, str[i + 1]))\n } else {\n layout = layoutWord(font, cursor, maxW, str, i)\n if (cursor.x > 0 && layout.cursor.y === nextLine(font, cursor.y).y) {\n const wordW = maxW - cursor.x + layout.cursor.x\n if (wordW <= maxW) {\n // Word can fit on one line if cursor is reset to the start of line.\n cursor = nextLine(font, cursor.y)\n layout = layoutWord(font, cursor, maxW, str, i)\n }\n }\n }\n chars.push(...layout.chars)\n cursor.x = layout.cursor.x\n cursor.y = layout.cursor.y\n }\n return {chars, cursor}\n}\n\n/** @internal */\nexport function layoutWord(\n font: Font,\n cursor: Readonly<XY>,\n maxW: number,\n word: string,\n index: number\n): TextLayout {\n const chars = []\n let {x, y} = cursor\n for (;;) {\n const char = word[index]\n if (!char || /^\\s*$/.test(char)) break\n\n const span = tracking(font, char, word[index + 1])\n if (x > 0 && x + span > maxW) ({x, y} = nextLine(font, y))\n\n // Width is not span since, with kerning, that may exceed the actual\n // width of the character's sprite. For example, if w has the maximal\n // character width of five pixels and a one pixel kerning for a given pair\n // of characters, it will have a span of six pixels which is greater than\n // the maximal five pixel sprite that can be rendered.\n chars.push({x, y, w: fontCharWidth(font, char), h: font.cellHeight})\n x += span\n\n index++\n }\n return {chars, cursor: {x, y}}\n}\n\nfunction nextLine(font: Font, y: number): XY {\n return {x: 0, y: y + font.lineHeight}\n}\n\nfunction layoutNewline(font: Font, cursor: Readonly<XY>): TextLayout {\n return {chars: [undefined], cursor: nextLine(font, cursor.y)}\n}\n\n/**\n * @arg span The distance in pixels from the start of the current character to\n * the start of the next including scale.\n */\nfunction layoutSpace(\n font: Font,\n cursor: Readonly<XY>,\n width: number,\n span: number\n): TextLayout {\n const nextCursor =\n cursor.x > 0 && cursor.x + span >= width\n ? nextLine(font, cursor.y)\n : {x: cursor.x + span, y: cursor.y}\n return {chars: [undefined], cursor: nextCursor}\n}\n\n/** Returns the distance in pixels from the start of lhs to the start of rhs. */\nfunction tracking(font: Font, lhs: string, rhs: string | undefined): number {\n return fontCharWidth(font, lhs) + fontKerning(font, lhs, rhs)\n}\n", "// \u2500\u2500\u2500oidoid>\u00B0\u2500\u2500\nimport type {Anim, AnimTag} from './atlas/anim.js'\nimport type {Atlas} from './atlas/atlas.js'\nimport {Synth} from './audio/synth.js'\nimport {BitmapBuffer, type Bitmap} from './graphics/bitmap.js'\nimport {Cam} from './graphics/cam.js'\nimport {FrameListener} from './graphics/frame-listener.js'\nimport {Renderer} from './graphics/renderer.js'\nimport {Input, type StandardButton} from './input/input.js'\nimport {Sprite} from './sprite/sprite.js'\nimport {JSONStorage} from './storage/json-storage.js'\n\nexport type {Font} from 'mem-font'\nexport type {SpriteJSON} from './sprite/sprite.js'\nexport {fontCharToTag} from './text/font.js'\nexport {layoutText, type TextLayout} from './text/text-layout.js'\nexport type {Box, WH, XY} from './types/2d.js'\nexport {Sprite}\nexport type {Anim, AnimTag, Atlas}\n\ndeclare const atlas: Atlas\ndeclare const atlasURI: string\n\nexport class Void<\n Tag extends AnimTag = AnimTag,\n Button extends string = StandardButton\n> {\n static async new<\n Tag extends AnimTag = AnimTag,\n Button extends string = StandardButton\n >(): Promise<Void<Tag, Button>> {\n return new Void(await loadImage(atlasURI))\n }\n\n readonly atlas: Atlas<Tag> = <Atlas<Tag>>atlas\n readonly cam: Cam = new Cam()\n readonly ctrl: Input<Button>\n readonly kv = new JSONStorage()\n readonly synth = new Synth()\n\n readonly #bitmaps: BitmapBuffer = new BitmapBuffer(1_000_000)\n readonly #framer: FrameListener\n readonly #renderer: Renderer\n\n constructor(spritesheet: HTMLImageElement) {\n const meta = document.createElement('meta')\n meta.name = 'viewport'\n // Don't wait for double-tap scaling on mobile.\n meta.content = 'maximum-scale=1, minimum-scale=1, user-scalable=no'\n document.head.appendChild(meta)\n\n document.body.style.margin = '0'\n document.body.style.width = '100vw'\n document.body.style.height = '100vh'\n document.body.style.overflow = 'hidden'\n\n const canvas = document.createElement('canvas')\n canvas.style.cursor = 'none'\n canvas.style.display = 'block' // No line height spacing.\n canvas.style.imageRendering = 'pixelated'\n // Update on each pointermove *touch* Event like *mouse* Events.\n canvas.style.touchAction = 'none'\n document.body.append(canvas)\n\n this.ctrl = new Input(this.cam, canvas)\n this.#renderer = new Renderer(atlas, canvas, spritesheet)\n this.#framer = new FrameListener(canvas, this.ctrl, this.#renderer)\n this.#framer.register('add')\n this.background = 0x000000ff\n }\n\n set background(rgba: number) {\n document.body.style.background = `#${rgba.toString(16).padStart(8, '0')}`\n this.#renderer.clearColor(rgba)\n }\n\n blit(bmp: Readonly<Bitmap>): void {\n this.#bitmaps.push(bmp)\n }\n\n get frame(): number {\n return this.#framer.frame\n }\n\n render(loop?: () => void): void {\n this.cam.resize()\n this.#framer.render(this.cam, this.#bitmaps, loop)\n this.#bitmaps.size = 0\n }\n\n sprite(tag: Tag): Sprite<Tag> {\n return new Sprite<Tag>(this.atlas, tag)\n }\n\n stop(): void {\n this.#framer.cancel()\n this.#framer.register('remove')\n this.ctrl.register('remove')\n }\n}\n\nfunction loadImage(src: string): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const img = new Image()\n img.onload = () => resolve(img)\n img.onerror = () => reject(img)\n img.src = src\n })\n}\n"],
|
|
5
|
+
"mappings": "AAAO,IAAMA,EAAN,KAAY,CACjBC,GAEA,KACEC,EACAC,EACAC,EACAC,EACM,CACN,KAAKJ,KAAa,IAAI,aACtB,IAAMK,EAAM,KAAKL,GAAS,YACpBM,EAAMD,EAAMD,EAEZG,EAAa,KAAKP,GAAS,iBAAiB,EAClDO,EAAW,KAAON,EAClBM,EAAW,UAAU,eAAeL,EAASG,CAAG,EAChDE,EAAW,UAAU,6BAA6BJ,EAAOG,CAAG,EAE5D,IAAME,EAAO,KAAKR,GAAS,WAAW,EACtCQ,EAAK,KAAK,eAAe,EAAGH,CAAG,EAC/BG,EAAK,KAAK,6BAA6B,IAAMF,CAAG,EAEhDC,EAAW,QAAQC,CAAI,EACvBA,EAAK,QAAQ,KAAKR,GAAS,WAAW,EAEtCO,EAAW,MAAM,EACjBA,EAAW,KAAKD,CAAG,CACrB,CACF,ECnBO,IAAMG,EAAN,KAAmB,CACf,OACT,KAAO,EAEP,YAAYC,EAAkB,CAC5B,KAAK,OAAS,IAAI,YAAYA,EAAW,CAAC,CAC5C,CAEA,KAAKC,EAA6B,CAChC,KAAK,OAAO,KAAK,KAAO,CAAC,EAAIA,EAAI,IACjC,KAAK,OAAO,KAAK,KAAO,EAAI,CAAC,EAAIA,EAAI,IACrC,KAAK,OAAO,KAAK,KAAO,EAAI,CAAC,EAAIA,EAAI,OACrC,KAAK,MACP,CACF,ECrBO,IAAMC,EAAN,KAAyB,CAC9B,MAAY,CAAC,EAAG,IAAK,EAAG,GAAG,EAC3B,SAAmB,EACnB,EAAY,EACZ,EAAY,EACZ,IAAW,CAAC,EAAG,MAAO,EAAG,MAAO,EAAG,KAAM,EAAG,IAAI,EAEvCC,GAAgB,CAAC,EAAG,EAAG,EAAG,CAAC,EACpCC,GAAS,EACTC,GAAK,KAAK,MAAM,EAChBC,GAAK,KAAK,MAAM,EAEhB,IAAI,GAAY,CACd,OAAO,KAAKA,EACd,CAGA,OAAOC,EAAwB,CAG7B,KAAKJ,GAAU,EAAI,WACnB,KAAKA,GAAU,EAAI,YAEnB,IAAMK,EAAU,KAAK,MAAM,KAAKL,GAAU,EAAI,gBAAgB,EACxDM,EAAU,KAAK,MAAM,KAAKN,GAAU,EAAI,gBAAgB,EAE9D,KAAKC,GAAS,KAAK,IACjB,KAAK,SACL,KAAK,MAAM,KAAK,IAAII,EAAU,KAAK,MAAM,EAAGC,EAAU,KAAK,MAAM,CAAC,CAAC,GAChEF,GAAW,EAChB,EACA,KAAKF,GAAK,KAAK,MAAMG,EAAU,KAAKJ,EAAM,EAC1C,KAAKE,GAAK,KAAK,MAAMG,EAAU,KAAKL,EAAM,CAC5C,CAEA,IAAI,OAAgB,CAClB,OAAO,KAAKA,EACd,CAGA,UAAUM,EAA4B,CACpC,MAAO,CACL,EAAG,KAAK,MAAM,KAAK,EAAKA,EAAS,EAAI,KAAKP,GAAU,EAAK,KAAKE,EAAE,EAChE,EAAG,KAAK,MAAM,KAAK,EAAKK,EAAS,EAAI,KAAKP,GAAU,EAAK,KAAKG,EAAE,CAClE,CACF,CAEA,IAAI,GAAY,CACd,OAAO,KAAKD,EACd,CACF,ECpDO,IAAMM,EAAN,KAAoB,CACzBC,GAAQ,EACCC,GAA6D,CAAC,EAC9DC,GAAwC,CAAC,EAElD,IAAI,MAAe,CACjB,OAAO,KAAKF,EACd,CAEA,QAAQG,EAAcC,EAAiBC,EAAuB,CAC5D,KAAKJ,GAAWE,CAAI,EAAI,CAACC,EAASC,CAAO,CAC3C,CAEA,UAAUC,EAAgBC,EAAmB,CAC3C,KAAKL,GAAaI,CAAM,EAAIC,CAC9B,CAEA,MAAa,CACX,GAAK,gBACL,MAAKP,GAAQ,EACb,QAAWQ,KAAO,UAAU,YAAY,EAAG,CACzC,OAAW,CAACC,EAAON,CAAI,IAAKK,GAAK,KAAK,QAAQ,GAAK,CAAC,EAAG,CACrD,IAAME,EAAO,KAAKT,GAAWQ,CAAK,EAClC,GAAIC,GAAQ,KAAM,SAClB,IAAMH,EAAMJ,EAAO,EAAIO,EAAK,CAAC,EAAIP,IAAS,EAAI,EAAIO,EAAK,CAAC,EACxD,KAAKV,IAAS,KAAK,IAAIG,CAAI,GAAK,GAAMI,EAAM,CAC9C,CACA,OAAW,CAACE,EAAOH,CAAM,IAAKE,GAAK,QAAQ,QAAQ,GAAK,CAAC,EAAG,CAC1D,IAAMD,EAAM,KAAKL,GAAaO,CAAK,EAC/BF,GAAO,OACX,KAAKP,IAASM,EAAO,QAAUC,EAAM,EACvC,CACF,EACF,CAEA,OAAc,CACZ,KAAKP,GAAQ,CACf,CACF,ECtCO,IAAMW,EAAN,KAAqB,CAC1BC,GAAQ,EACCC,GAAqC,CAAC,EAE/C,IAAI,MAAe,CACjB,OAAO,KAAKD,EACd,CAEA,IAAIE,EAAaC,EAAmB,CAClC,KAAKF,GAAUC,CAAG,EAAIC,CACxB,CAEA,SAASC,EAA4B,CACnC,IAAMC,EAAY,GAAGD,CAAE,gBAEvB,WAAWC,CAAE,EAAE,OAAQ,KAAK,MAAO,CAAC,QAAS,GAAM,QAAS,EAAI,CAAC,EACjE,QAAWC,IAAQ,CAAC,UAAW,OAAO,EAAG,CACvC,IAAMC,EAA+C,KAAKC,GAC1D,WAAWH,CAAE,EAAEC,EAAMC,EAAU,CAAC,QAAS,GAAM,QAAS,EAAI,CAAC,CAC/D,CACF,CAEA,MAAQ,IAAY,CAClB,KAAKP,GAAQ,CACf,EAEAQ,GAAUC,GAA4B,CACpC,IAAMC,EAAKD,EAAG,OAAS,UACjBN,EAAM,KAAKF,GAAUQ,EAAG,GAAG,EAC7BN,GAAO,OACX,KAAKH,GAAQU,EAAK,KAAKV,GAAQG,EAAM,KAAKH,GAAQ,CAACG,EACrD,CACF,EC7BO,IAAMQ,EAAN,KAAoB,CAChBC,GAAwC,CAAC,EAClDC,GAAgB,EACPC,GACAC,GACAC,GAAgB,CAAC,EAAG,EAAG,EAAG,CAAC,EACpCC,GACAC,GAEA,YAAYC,EAAoBC,EAA2B,CACzD,KAAKN,GAAOK,EACZ,KAAKJ,GAAUK,CACjB,CAEA,IAAI,MAAe,CACjB,OAAO,KAAKP,EACd,CAEA,IAAIQ,EAAgBC,EAAmB,CACrC,KAAKV,GAAaS,CAAM,EAAIC,CAC9B,CAEA,IAAI,MAA8C,CAChD,OAAO,KAAKL,EACd,CAEA,SAASM,EAA4B,CACnC,IAAMC,EAAY,GAAGD,CAAE,gBACvB,KAAKR,GAAQS,CAAE,EAAE,gBAAiB,KAAK,MAAO,CAC5C,QAAS,GACT,QAAS,EACX,CAAC,EACD,QAAWC,IAAQ,CAAC,cAAe,cAAe,WAAW,EAC3D,KAAKV,GAAQS,CAAE,EACbC,EACoC,KAAKC,GACzC,CAAC,QAAS,GAAM,QAASD,IAAS,aAAa,CACjD,EAEF,KAAKV,GAAQS,CAAE,EAAE,cAAe,KAAKG,GAAqB,CAAC,QAAS,EAAI,CAAC,CAC3E,CAEA,MAAQ,IAAY,CAClB,KAAKd,GAAQ,EACb,KAAKI,GAAQ,OACb,KAAKC,GAAM,MACb,EAEA,IAAI,IAA+B,CACjC,OAAO,KAAKA,EACd,CAEAS,GAAuBC,GAAoBA,EAAG,eAAe,EAE7DF,GAAiBE,GAA2B,CAE1C,GAAI,CAACA,EAAG,UAAW,OAEfA,EAAG,OAAS,eAAe,KAAKb,GAAQ,kBAAkBa,EAAG,SAAS,EACxE,CAAC,QAAS,KAAKZ,GAAU,EAAG,QAAS,KAAKA,GAAU,CAAC,EAAIY,EAE3D,KAAKf,GAAQ,KAAKgB,GAAiBD,EAAG,OAAO,EAC7C,KAAKX,GAAgB,CAAC,QAAS,QAAS,KAAK,EAAG,KAC9CQ,GAAQA,IAASG,EAAG,WACtB,EACA,KAAKV,GAAM,KAAKJ,GAAK,UAAU,KAAKE,EAAS,EAE7BY,EAAG,OAAS,eACdA,EAAG,eAAe,CAClC,EAEAC,GAAiBC,EAAyB,CACxC,IAAIC,EAAO,EACX,QAASV,EAAS,EAAGA,GAAUS,EAAST,IAAW,GAC5CA,EAASS,KAAaT,IAC3BU,GAAQ,KAAKnB,GAAaS,CAAM,GAAK,GAEvC,OAAOU,CACT,CACF,ECtEO,IAAMC,EAAN,KAAoD,CACzD,QAAU,GAEV,YAAc,IAEd,QAAU,IAGVC,GAAY,EAEZC,GAAY,EAKHC,GAAmB,CAAC,EAEpBC,GAA0C,CAAC,EAC3CC,GAAW,IAAIC,EACfC,GAAY,IAAIC,EAChBC,GACTC,GAAY,EACZC,GAAY,EAEZ,YAAYC,EAAoBC,EAA2B,CACzD,KAAKJ,GAAW,IAAIK,EAAcF,EAAKC,CAAM,CAC/C,CAOA,WAAWE,EAAgD,CACzD,GAAIA,EAAM,SAAW,KAAKZ,GAAO,OAAQ,MAAO,GAChD,OAAW,CAACa,EAAGC,CAAO,IAAKF,EAAM,QAAQ,EAAG,CAC1C,IAAMG,EAAO,KAAKC,GAAeF,CAAO,EACxC,GAAI,KAAKd,GAAOa,CAAC,IAAME,EAAM,MAAO,EACtC,CAIA,OAAO,KAAKf,GAAOY,EAAM,OAAS,CAAC,IAAM,KAAKK,EAChD,CAGA,gBAAgBL,EAAgD,CAC9D,OACE,KAAK,QAAQ,GAAGA,CAAK,GACrB,CAAC,CAACA,EAAM,GAAG,EAAE,GAAG,MAAMM,GAAU,KAAK,UAAUA,CAAM,CAAC,CAE1D,CAGA,QAAkB,CAChB,OAAO,KAAKpB,IAAa,KAAK,OAChC,CAEA,cAAcgB,EAAqC,CACjD,MAAO,CAAC,KAAK,KAAK,GAAGA,CAAO,GAAK,KAAK,QAAQ,GAAGA,CAAO,CAC1D,CAOA,QAAQA,EAAqC,CAC3C,IAAMC,EAAO,KAAKC,GAAeF,CAAO,EACxC,OAAQ,KAAKG,GAAQF,KAAUA,CACjC,CAEA,aAAaD,EAAqC,CAChD,OAAO,KAAK,KAAK,GAAGA,CAAO,GAAK,KAAK,QAAQ,GAAGA,CAAO,CACzD,CAGA,WAAWA,EAAqC,CAC9C,IAAMC,EAAO,KAAKC,GAAeF,CAAO,EACxC,OAAQ,KAAKG,GAAQF,MAAW,KAAKhB,GAAYgB,EACnD,CAEA,QAAQI,EAAcC,KAAiBC,EAA+B,CACpE,QAAWC,KAAQD,EACjB,KAAKnB,GAAS,QAAQoB,EAAM,KAAKC,GAAKJ,CAAI,EAAG,KAAKI,GAAKH,CAAI,CAAC,CAEhE,CAEA,UAAUF,KAAmBM,EAAkC,CAC7D,QAAWC,KAASD,EAClB,KAAKtB,GAAS,UAAUuB,EAAO,KAAKF,GAAKL,CAAM,CAAC,CAEpD,CAEA,SAASA,KAAmBQ,EAAiC,CAC3D,QAAWC,KAASD,EAAQ,KAAKpB,GAAS,IAAIqB,EAAO,KAAKJ,GAAKL,CAAM,CAAC,CACxE,CAEA,aAAoB,CAClB,KAAK,OAAe,IAAK,YAAa,GAAG,EACzC,KAAK,OAAe,IAAK,aAAc,GAAG,EAC1C,KAAK,OAAe,IAAK,UAAW,GAAG,EACvC,KAAK,OAAe,IAAK,YAAa,GAAG,EACzC,KAAK,OAAe,IAAK,GAAG,EAC5B,KAAK,OAAe,IAAK,GAAG,EAC5B,KAAK,OAAe,IAAK,GAAG,EAC5B,KAAK,OAAe,IAAK,QAAS,QAAQ,EAG1C,KAAK,QAAgB,IAAa,IAAK,EAAG,CAAC,EAC3C,KAAK,QAAgB,IAAa,IAAK,EAAG,CAAC,EAC3C,KAAK,UAAkB,IAAK,EAAE,EAC9B,KAAK,UAAkB,IAAK,EAAE,EAC9B,KAAK,UAAkB,IAAK,EAAE,EAC9B,KAAK,UAAkB,IAAK,EAAE,EAC9B,KAAK,UAAkB,IAAK,CAAC,EAC7B,KAAK,UAAkB,IAAK,CAAC,EAE7B,KAAK,SAAiB,IAAK,CAAC,CAC9B,CAEA,OAAOA,KAAmBU,EAA+B,CACvD,QAAWC,KAAOD,EAAM,KAAKxB,GAAU,IAAIyB,EAAK,KAAKN,GAAKL,CAAM,CAAC,CACnE,CAEA,IAAI,OAAkC,CACpC,OAAO,KAAKZ,GAAS,EACvB,CAEA,IAAI,WAAmD,CACrD,OAAO,KAAKA,GAAS,IACvB,CAEA,KAAKwB,EAAoB,CACvB,KAAK,QAAU,GACf,KAAKhC,IAAa,KAAKU,GACvB,KAAKT,GAAY,KAAKQ,GAEtB,KAAKL,GAAS,KAAK,EAEjB,KAAKJ,GAAY,KAAK,cACrB,KAAKmB,KAAU,GAAK,KAAKA,KAAU,KAAKlB,KAGzC,KAAKD,GAAY,EACjB,KAAKE,GAAO,OAAS,GACZ,KAAKiB,KAAU,KAAKlB,IAE7B,KAAKD,GAAY,EACb,KAAKmB,KAAU,GAAG,KAAKjB,GAAO,KAAK,KAAKiB,EAAK,GACxC,KAAKA,KAAU,GAAK,KAAKA,KAAU,KAAKlB,KAEjD,KAAKC,GAAO,IAAI,EAChB,KAAKA,GAAO,KAAK,KAAKiB,EAAK,GAG7B,KAAKT,GAAYsB,EACjB,KAAKvB,GAAY,KAAKU,EACxB,CAEA,SAASc,EAA4B,CACnC,KAAK3B,GAAU,SAAS2B,CAAE,EAC1B,KAAKzB,GAAS,SAASyB,CAAE,CAC3B,CAEA,OAAc,CACZ,KAAK,QAAU,GACf,KAAK7B,GAAS,MAAM,EACpB,KAAKE,GAAU,MAAM,EACrB,KAAKE,GAAS,MAAM,CACtB,CAOA,GAAIW,IAAgB,CAClB,OAAO,KAAKf,GAAS,KAAO,KAAKE,GAAU,KAAO,KAAKE,GAAS,IAClE,CAEAU,GAAeF,EAAoC,CACjD,IAAIC,EAAO,EACX,QAAWG,KAAUJ,EAASC,GAAQ,KAAKd,GAAaiB,CAAM,GAAK,EACnE,OAAOH,CACT,CAEAQ,GAAKL,EAAwB,CAC3B,OAAQ,KAAKjB,GAAaiB,CAAM,IAC9B,GAAK,OAAO,KAAK,KAAKjB,EAAY,EAAE,MACxC,CACF,EC3MO,IAAM+B,EAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;GCAjB,IAAMC,EAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;GCWxB,IAAMC,EAA0B,IAAI,UAAU,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,CAAC,CAAC,EAEzDC,EAAN,KAAe,CACpBC,GAA2C,KAClCC,GACAC,GACTC,GACAC,GAAoD,KAC3CC,GACTC,GAAkC,CAAC,EACnCC,GAA4C,KAE5C,YACEC,EACAC,EACAC,EACA,CACA,KAAKT,GAAUQ,EACf,KAAKJ,GAAeK,EACpB,KAAKR,GAAQ,IAAI,YAAYS,EAAQH,CAAK,CAAC,CAC7C,CAEA,WAAWI,EAAoB,CAC7B,KAAKT,GAAI,YACLS,IAAS,GAAM,KAAQ,KACvBA,IAAS,GAAM,KAAQ,KACvBA,IAAS,EAAK,KAAQ,KACtBA,IAAS,EAAK,KAAQ,GAC1B,CACF,CAEA,QAAe,CACb,IAAMC,EAAK,KAAKZ,GAAQ,WAAW,SAAU,CAC3C,UAAW,GACX,eAAgB,GAChB,gBAAiB,kBACnB,CAAC,EACD,GAAI,CAACY,EAAI,MAAM,MAAM,sBAAsB,EAC3C,KAAKV,GAAMU,EAGXA,EAAG,OAAOA,EAAG,KAAK,EAClBA,EAAG,UAAUA,EAAG,UAAWA,EAAG,mBAAmB,EAGjDA,EAAG,OAAOA,EAAG,UAAU,EACvBA,EAAG,WAAW,EAAG,CAAC,EAClBA,EAAG,WAAW,CAAC,EACfA,EAAG,UAAUA,EAAG,IAAI,EAGpBA,EAAG,YAAYA,EAAG,mCAAoC,EAAK,EAE3D,IAAMC,EAAMC,EAAYF,EAAIG,EAAUC,CAAQ,EAC9C,KAAKX,GAAYY,EAAoBL,EAAIC,CAAG,EAE5CD,EAAG,WACD,KAAKP,GAAU,iBACf,KAAKD,GAAa,aAClB,KAAKA,GAAa,aACpB,EAEA,KAAKE,GAAaM,EAAG,kBAAkB,EACvCA,EAAG,gBAAgB,KAAKN,EAAU,EAElC,IAAMY,EAAWN,EAAG,aAAa,EACjCA,EAAG,WAAWA,EAAG,aAAcM,CAAQ,EACvCN,EAAG,wBAAwB,CAAC,EAC5BA,EAAG,qBAAqB,EAAG,EAAGA,EAAG,KAAM,EAAG,CAAC,EAC3CA,EAAG,WAAWA,EAAG,aAAc,IAAI,EAEnC,KAAKb,GAAaa,EAAG,aAAa,EAClCA,EAAG,WAAWA,EAAG,aAAc,KAAKb,EAAU,EAC9Ca,EAAG,wBAAwB,CAAC,EAC5BA,EAAG,qBAAqB,EAAG,EAAGA,EAAG,aAAc,GAAI,CAAC,EACpDA,EAAG,oBAAoB,EAAG,CAAC,EAC3BA,EAAG,wBAAwB,CAAC,EAC5BA,EAAG,qBAAqB,EAAG,EAAGA,EAAG,aAAc,GAAI,CAAC,EACpDA,EAAG,oBAAoB,EAAG,CAAC,EAC3BA,EAAG,wBAAwB,CAAC,EAC5BA,EAAG,qBAAqB,EAAG,EAAGA,EAAG,aAAc,GAAI,CAAC,EACpDA,EAAG,oBAAoB,EAAG,CAAC,EAC3BA,EAAG,WAAWA,EAAG,aAAc,IAAI,EAEnCA,EAAG,gBAAgB,IAAI,EAEvBA,EAAG,WAAWA,EAAG,aAAcM,CAAQ,EACvCN,EAAG,WAAWA,EAAG,aAAcf,EAAIe,EAAG,WAAW,EACjDA,EAAG,WAAW,KAAKV,GAAI,aAAc,IAAI,EAEzCU,EAAG,UAAU,KAAKP,GAAU,MAAQ,CAAC,EACrCO,EAAG,cAAcA,EAAG,QAAQ,EAC5B,IAAMO,EAAUP,EAAG,cAAc,EACjCA,EAAG,YAAYA,EAAG,WAAYO,CAAO,EACrCP,EAAG,cAAcA,EAAG,WAAYA,EAAG,mBAAoBA,EAAG,OAAO,EACjEA,EAAG,cAAcA,EAAG,WAAYA,EAAG,mBAAoBA,EAAG,OAAO,EACjEA,EAAG,WACDA,EAAG,WACH,EACAA,EAAG,SACH,EACA,KAAKX,GAAM,OAAS,EACpB,EACAW,EAAG,aACHA,EAAG,eACH,KAAKX,EACP,EAEAW,EAAG,UAAU,KAAKP,GAAU,aAAe,CAAC,EAC5CO,EAAG,cAAcA,EAAG,QAAQ,EAC5B,IAAMQ,EAAiBR,EAAG,cAAc,EACxCA,EAAG,YAAYA,EAAG,WAAYQ,CAAc,EAC5CR,EAAG,cAAcA,EAAG,WAAYA,EAAG,mBAAoBA,EAAG,OAAO,EACjEA,EAAG,cAAcA,EAAG,WAAYA,EAAG,mBAAoBA,EAAG,OAAO,EACjEA,EAAG,WACDA,EAAG,WACH,EACAA,EAAG,KACHA,EAAG,KACHA,EAAG,cACH,KAAKR,EACP,EAEA,KAAKD,GAAeS,EAAG,aAAa,oBAAoB,CAC1D,CAEA,IAAI,aAAyC,CAC3C,OAAO,KAAKT,EACd,CAEA,YAAsB,CACpB,MAAO,CAAC,KAAKD,GAAI,cAAc,CACjC,CAEA,OACEmB,EACAC,EACAC,EACM,CACN,KAAKC,GAAQH,CAAG,EAChB,KAAKnB,GAAI,MAAM,KAAKA,GAAI,iBAAmB,KAAKA,GAAI,gBAAgB,EAEpE,KAAKA,GAAI,UAAU,KAAKG,GAAU,KAAOgB,EAAI,EAAGA,EAAI,EAAGA,EAAI,EAAGA,EAAI,CAAC,EACnE,KAAKnB,GAAI,WAAW,KAAKG,GAAU,OAASiB,CAAK,EAEjD,KAAKpB,GAAI,gBAAgB,KAAKI,EAAU,EAExC,KAAKJ,GAAI,WAAW,KAAKA,GAAI,aAAc,KAAKH,EAAU,EAC1D,KAAKG,GAAI,WACP,KAAKA,GAAI,aACTqB,EAAK,OACL,KAAKrB,GAAI,WACX,EACA,KAAKA,GAAI,WAAW,KAAKA,GAAI,aAAc,IAAI,EAE/C,KAAKA,GAAI,oBACP,KAAKA,GAAI,eACT,EACAL,EAAG,OAAS,EACZ0B,EAAK,IACP,EAEA,KAAKrB,GAAI,gBAAgB,IAAI,CAC/B,CAEAsB,GAAQH,EAA0B,CAChC,IAAMb,EAAS,KAAKR,GACdyB,EAAW,CAAC,EAAGJ,EAAI,EAAIA,EAAI,MAAO,EAAGA,EAAI,EAAIA,EAAI,KAAK,GAExDb,EAAO,QAAUiB,EAAS,GAAKjB,EAAO,SAAWiB,EAAS,KAC5DjB,EAAO,MAAQiB,EAAS,EACxBjB,EAAO,OAASiB,EAAS,EACzB,KAAKvB,GAAI,SAAS,EAAG,EAAGuB,EAAS,EAAGA,EAAS,CAAC,GAIhD,IAAMC,EAAUD,EAAS,EAAI,iBACvBE,EAAUF,EAAS,EAAI,iBACvBG,EAAQ,OAAO,WAAWpB,EAAO,MAAM,MAAM,MAAM,EAAG,EAAE,CAAC,EAAIkB,EAC7DG,EAAQ,OAAO,WAAWrB,EAAO,MAAM,OAAO,MAAM,EAAG,EAAE,CAAC,EAAImB,GAElE,CAAC,OAAO,SAASC,CAAK,GACtB,KAAK,IAAIA,CAAK,GAAK,IACnB,CAAC,OAAO,SAASC,CAAK,GACtB,KAAK,IAAIA,CAAK,GAAK,MAEnBrB,EAAO,MAAM,MAAQ,GAAGkB,CAAO,KAC/BlB,EAAO,MAAM,OAAS,GAAGmB,CAAO,KAEpC,CACF,EAEA,SAASG,EAAclB,EAAQmB,EAAcC,EAA0B,CACrE,IAAMC,EAASrB,EAAG,aAAamB,CAAI,EACnC,GAAI,CAACE,EAAQ,MAAM,MAAM,wBAAwB,EACjDrB,EAAG,aAAaqB,EAAQD,EAAI,KAAK,CAAC,EAClCpB,EAAG,cAAcqB,CAAM,EAEvB,IAAMC,EAAMtB,EAAG,iBAAiBqB,CAAM,GAAG,MAAM,EAAG,EAAE,EACpD,OAAIC,GAAK,QAAQ,KAAKA,CAAG,EAElBD,CACT,CAEA,SAAShB,EAAoBL,EAAQC,EAA4B,CAC/D,GAAI,CAACA,EAAK,MAAO,CAAC,EAClB,IAAMsB,EAAMvB,EAAG,oBAAoBC,EAAKD,EAAG,eAAe,EACpDwB,EAA2D,CAAC,EAClE,QAASC,EAAI,EAAGA,EAAIF,EAAK,EAAEE,EAAG,CAC5B,IAAMC,EAAU1B,EAAG,iBAAiBC,EAAKwB,CAAC,EAC1C,GAAIC,GAAW,KAAM,MAAM,MAAM,mCAAmCD,CAAC,EAAE,EACvED,EAAUE,EAAQ,IAAI,EAAI1B,EAAG,mBAAmBC,EAAKyB,EAAQ,IAAI,CACnE,CACA,OAAOF,CACT,CAEA,SAAStB,EAAYF,EAAQG,EAAkBC,EAA6B,CAC1E,IAAMH,EAAMD,EAAG,cAAc,EAC7B,GAAI,CAACC,EAAK,OAAO,KAEjB,IAAM0B,EAAOT,EAAclB,EAAIA,EAAG,cAAeG,CAAQ,EACnDyB,EAAOV,EAAclB,EAAIA,EAAG,gBAAiBI,CAAQ,EAC3DJ,EAAG,aAAaC,EAAK0B,CAAI,EACzB3B,EAAG,aAAaC,EAAK2B,CAAI,EACzB5B,EAAG,YAAYC,CAAG,EAClBD,EAAG,WAAWC,CAAG,EAEjB,IAAMqB,EAAMtB,EAAG,kBAAkBC,CAAG,GAAG,MAAM,EAAG,EAAE,EAClD,OAAIqB,GAAK,QAAQ,KAAKA,CAAG,EAEzBtB,EAAG,aAAaC,EAAK2B,CAAI,EACzB5B,EAAG,aAAaC,EAAK0B,CAAI,EACzB3B,EAAG,aAAa4B,CAAI,EACpB5B,EAAG,aAAa2B,CAAI,EAEb1B,CACT,CAGA,SAASH,EAAQH,EAAiC,CAChD,IAAMkC,EAAO,CAAC,EACd,QAAWC,KAAQ,OAAO,OAAsBnC,CAAK,EAAG,CAEtD,QAAWoC,KAAOD,EAAK,KAAMD,EAAK,KAAKE,EAAI,EAAGA,EAAI,EAAGD,EAAK,EAAGA,EAAK,CAAC,EACnE,QAAS,EAAIA,EAAK,KAAK,OAAQ,EAAI,GAAa,IAAK,CACnD,IAAMC,EAAMD,EAAK,KAAK,EAAIA,EAAK,KAAK,MAAM,EAC1CD,EAAK,KAAKE,EAAI,EAAGA,EAAI,EAAGD,EAAK,EAAGA,EAAK,CAAC,CACxC,CACF,CACA,OAAOD,CACT,CChQO,IAAMG,EAAN,KAAoB,CAEzB,IAAM,EAEN,KAAO,EAEEC,GACTC,GACAC,GACAC,GACSC,GACAC,GAET,YACEC,EACAC,EACAC,EACA,CACA,KAAKR,GAAUM,EACf,KAAKF,GAASG,EACd,KAAKF,GAAYG,CACnB,CAEA,QAAe,CACT,KAAKP,IAAU,MAAM,qBAAqB,KAAKA,EAAM,EACzD,KAAKA,GAAS,OACd,KAAK,KAAO,EACZ,KAAKE,GAAQ,OACb,KAAKC,GAAO,MAAM,EAClB,KAAKF,GAAQ,MACf,CAEA,IAAI,OAAgB,CAElB,OAAO,KAAK,MAAM,KAAK,IAAM,kBAAkB,CACjD,CAEA,SAASO,EAA4B,CACnC,IAAMC,EAAY,GAAGD,CAAE,gBACvB,QAAWE,IAAQ,CAAC,uBAAwB,kBAAkB,EAC5D,KAAKX,GAAQU,CAAE,EAAEC,EAAM,KAAKC,GAAU,EAAI,EAE5C,WAAWF,CAAE,EAAE,mBAAoB,KAAKE,GAAU,EAAI,EAClDH,IAAO,OAAO,KAAKJ,GAAU,OAAO,EACxC,KAAKD,GAAO,SAASK,CAAE,CACzB,CAEA,OAAOI,EAAoBC,EAAsBC,EAAyB,CACxE,KAAKb,GAAQa,EACT,GAAC,KAAKC,GAAW,GAAK,CAAC,KAAKX,GAAU,WAAW,KACjD,KAAKH,KAAO,KAAKD,KAAW,sBAAsB,KAAKgB,EAAQ,GACnE,KAAKZ,GAAU,OAAOQ,EAAK,KAAK,MAAOC,CAAM,EAC/C,CAEAE,IAAsB,CACpB,OAAO,SAAS,kBAAoB,SACtC,CAEAJ,GAAYM,GAAuB,CACjCA,EAAM,eAAe,EACjBA,EAAM,OAAS,wBAAwB,KAAKb,GAAU,OAAO,EAE7D,KAAKA,GAAU,WAAW,GAAK,KAAKW,GAAW,EAC7C,KAAKd,KAAO,KAAKD,KAAW,sBAAsB,KAAKgB,EAAQ,IAE/D,KAAKhB,IAAU,MAAM,qBAAqB,KAAKA,EAAM,EACzD,KAAKA,GAAS,OACd,KAAK,KAAO,EACZ,KAAKE,GAAQ,OACb,KAAKC,GAAO,MAAM,EAEtB,EAEAa,GAAYE,GAAuB,CACjC,KAAKlB,GAAS,OACd,KAAK,KAAOkB,GAAQ,KAAKhB,IAASgB,GAClC,KAAKhB,GAAQgB,EACb,KAAK,KAAO,KAAK,KACjB,IAAMJ,EAAO,KAAKb,GAClB,KAAKA,GAAQ,OACb,KAAKE,GAAO,KAAK,KAAK,IAAI,EAC1BW,IAAO,CACT,CACF,ECvEO,IAAMK,EAAN,MAAMC,CAA2D,CACtE,OAAO,MACLC,EACAC,EACW,CACX,GAAI,EAAEA,EAAK,OAAOD,GAAQ,MAAM,MAAM,sBAAsBC,EAAK,GAAG,GAAG,EACvE,IAAMC,EAAS,IAAIH,EAAOC,EAAUC,EAAK,GAAG,EAC5C,OAAAC,EAAO,IAAMD,EAAK,KAAO,EACzBC,EAAO,MAAQD,EAAK,OAAS,KAAOA,EAAK,OAAS,KAClDC,EAAO,MAAQD,EAAK,OAAS,KAAOA,EAAK,OAAS,KAClDC,EAAO,EAAID,EAAK,GAAK,EACrBC,EAAO,EAAID,EAAK,GAAK,EACrBC,EAAO,EAAID,EAAK,GAAK,EACrBC,EAAO,KAAOD,EAAK,MAAQ,GACvBA,EAAK,GAAK,OAAMC,EAAO,EAAID,EAAK,GAChCA,EAAK,GAAK,OAAMC,EAAO,EAAID,EAAK,GAC7BC,CACT,CAES,OAAc,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,CAAC,EAE9C,OAAS,EACT,IAAM,EACN,IAAM,EAENC,GAA0B,CAAC,EAC3BC,GAEA,YAAYJ,EAAiBK,EAAQ,CACnC,KAAKD,GAASJ,EACd,KAAK,IAAMK,CACb,CAEA,MAAMH,EAAmC,CAMvC,OAJE,KAAK,IAAMA,EAAO,GACbA,EAAO,KAAOA,EAAO,EAAIA,EAAO,EAAIA,EAAO,IAC3C,KAAK,KAAO,KAAK,EAAI,KAAK,EAAI,KAAK,GACpC,KAAK,EAAIA,EAAO,GACL,CACnB,CAEA,IAAI,KAAc,CAChB,OAAQ,KAAK,QAAU,EAAK,EAC9B,CAGA,IAAI,IAAII,EAAa,CACnB,KAAK,OAAU,KAAK,OAAS,YAAgBA,EAAM,KAAQ,CAC7D,CAEA,IAAI,OAAiB,CACnB,MAAO,CAAC,EAAE,KAAK,OAAS,GAC1B,CAEA,IAAI,MAAMC,EAAe,CACvB,GAAI,KAAK,QAAUA,EACnB,GAAIA,EAAM,CACR,KAAK,QAAU,GACf,IAAMC,EAAO,KAAK,OAAO,EAAI,KAAK,EAClC,KAAK,OAAO,EAAI,KAAK,EAAI,KAAK,OAAO,EAAIA,CAC3C,KAAO,CACL,KAAK,QAAU,WACf,IAAMA,EAAO,KAAK,OAAO,EAAI,KAAK,OAAO,EACzC,KAAK,OAAO,EAAI,KAAK,EAAIA,CAC3B,CACF,CAEA,IAAI,OAAiB,CACnB,MAAO,CAAC,EAAE,KAAK,OAAS,GAC1B,CAEA,IAAI,MAAMD,EAAe,CACvB,GAAI,KAAK,QAAUA,EACnB,GAAIA,EAAM,CACR,KAAK,QAAU,GACf,IAAMC,EAAO,KAAK,OAAO,EAAI,KAAK,EAClC,KAAK,OAAO,EAAI,KAAK,EAAI,KAAK,OAAO,EAAIA,CAC3C,KAAO,CACL,KAAK,QAAU,WACf,IAAMA,EAAO,KAAK,OAAO,EAAI,KAAK,OAAO,EACzC,KAAK,OAAO,EAAI,KAAK,EAAIA,CAC3B,CACF,CAEA,IAAI,GAAY,CACd,OAAO,KAAK,IAAM,IACpB,CAEA,IAAI,EAAEC,EAAW,CACf,KAAK,IAAO,KAAK,IAAM,WAAeA,EAAI,IAC5C,CAEA,KAAKC,EAA0C,CAC7C,MAAI,CAAC,KAAK,OAAO,GAAK,CAAC,KAAK,OAAO,EAAU,IACzCA,aAAeX,IAAQW,EAAMA,EAAI,QAEnC,KAAK,OAAO,EAAIA,EAAI,GAAKA,EAAI,GAAK,IAClC,KAAK,OAAO,EAAI,KAAK,OAAO,EAAIA,EAAI,GACpC,KAAK,OAAO,EAAIA,EAAI,GAAKA,EAAI,GAAK,IAClC,KAAK,OAAO,EAAI,KAAK,OAAO,EAAIA,EAAI,EAExC,CAEA,SAASA,EAA0C,CACjD,OACE,KAAK,EAAIA,EAAI,GAAKA,EAAI,GAAK,IAC3B,KAAK,EAAI,KAAK,EAAIA,EAAI,GACtB,KAAK,EAAIA,EAAI,GAAKA,EAAI,GAAK,IAC3B,KAAK,EAAI,KAAK,EAAIA,EAAI,CAE1B,CAEA,IAAI,KAAS,CACX,OAAO,KAAKP,GAAM,GACpB,CAEA,IAAI,IAAIE,EAAQ,CACd,GAAIA,IAAQ,KAAKF,GAAM,IAAK,OAC5B,KAAKA,GAAQ,KAAKC,GAAOC,CAAG,EAC5B,GAAM,CAAC,OAAAM,CAAM,EAAI,KAAKR,GACtB,KAAK,OAAO,EAAI,KAAK,GAAK,KAAK,MAAQQ,EAAO,EAAIA,EAAO,EAAIA,EAAO,GACpE,KAAK,OAAO,EAAI,KAAK,GAAK,KAAK,MAAQA,EAAO,EAAIA,EAAO,EAAIA,EAAO,GACpE,KAAK,OAAO,EAAI,KAAKR,GAAM,OAAO,EAClC,KAAK,OAAO,EAAI,KAAKA,GAAM,OAAO,EAClC,KAAK,EAAI,KAAKA,GAAM,EACpB,KAAK,EAAI,KAAKA,GAAM,EACpB,KAAK,OAAU,KAAK,OAAS,YAAgB,KAAKA,GAAM,IAAM,CAChE,CAEA,UAAmB,CACjB,MAAO,GAAG,KAAK,GAAG,KAAK,KAAK,CAAC,KAAK,KAAK,CAAC,KAAK,KAAK,CAAC,OAAI,KAAK,CAAC,EAC/D,CAEA,IAAI,GAAY,CACd,OAAQ,KAAK,KAAO,GAAM,IAC5B,CAEA,IAAI,EAAES,EAAW,CACf,KAAK,IAAO,KAAK,IAAM,YAAgBA,EAAI,OAAU,EACvD,CAEA,IAAI,GAAY,CACd,OAAQ,KAAK,KAAO,IAAM,CAC5B,CAEA,IAAI,EAAEC,EAAW,CACf,IAAML,EAAOK,EAAI,KAAK,EACtB,KAAK,IAAO,KAAK,IAAM,OAAiB,EAAIA,EAAK,QAAW,GAC5D,KAAK,OAAO,GAAKL,CACnB,CAEA,IAAI,GAAGM,EAAkB,CACvB,KAAK,EAAIA,EAAG,EACZ,KAAK,EAAIA,EAAG,CACd,CAEA,IAAI,GAAY,CACd,OAAS,KAAK,KAAO,IAAO,IAAM,CACpC,CAEA,IAAI,EAAEC,EAAW,CACf,IAAMP,EAAOO,EAAI,KAAK,EACtB,KAAK,IAAO,KAAK,IAAM,WAAgB,EAAIA,EAAK,MAChD,KAAK,OAAO,GAAKP,CACnB,CAEA,IAAI,GAAY,CACd,OAAO,KAAK,OAAS,CACvB,CAGA,IAAI,EAAEQ,EAAW,CACf,KAAK,OAAU,KAAK,OAAS,WAAeA,EAAI,CAClD,CAEA,IAAI,MAAgB,CAClB,MAAO,CAAC,EAAE,KAAK,OAAS,EAC1B,CAEA,IAAI,KAAKC,EAAc,CACjBA,EAAK,KAAK,QAAU,EACnB,KAAK,QAAU,UACtB,CACF,ECzMO,IAAMC,EAAN,KAAkB,CACvB,IAAOC,EAA4B,CACjC,IAAMC,EAAM,aAAa,QAAQD,CAAG,EACpC,OAAOC,GAAO,KAAO,OAAY,KAAK,MAAMA,CAAG,CACjD,CAEA,IAAOD,EAAaC,EAAc,CAC5BA,GAAO,KAAM,aAAa,WAAWD,CAAG,EACvC,aAAa,QAAQA,EAAK,KAAK,UAAUC,CAAG,CAAC,CACpD,CACF,ECPO,SAASC,EAAcC,EAAYC,EAAuB,CAC/D,IAAIC,EAAKD,EAAK,YAAY,CAAC,EAC3B,OAAIC,GAAM,MAAQA,EAAK,OAAMA,EAAK,IAC3B,GAAGF,EAAK,EAAE,KAAKE,EAAG,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CAAC,EACxD,CAGO,SAASC,EACdH,EACAI,EACAC,EACQ,CACR,OAAIA,GAAO,KAAaL,EAAK,iBACzB,QAAQ,KAAKI,CAAG,GAAK,QAAQ,KAAKC,CAAG,EAAUL,EAAK,kBACjDA,EAAK,QAAQI,EAAMC,CAAG,GAAKL,EAAK,cACzC,CAEO,SAASM,EAAcN,EAAYO,EAAwB,CAChE,OAAOP,EAAK,UAAUO,CAAM,GAAKP,EAAK,gBACxC,CCXO,SAASQ,EAAWC,EAAYC,EAAaC,EAA0B,CAC5E,IAAMC,EAAQ,CAAC,EACXC,EAAS,CAAC,EAAG,EAAG,EAAG,CAAC,EACxB,KAAOD,EAAM,OAASF,EAAI,QAAQ,CAChC,IAAMI,EAAIF,EAAM,OACVG,EAAOL,EAAII,CAAC,EACdE,EACAD,IAAS;AAAA,EAAMC,EAASC,EAAcR,EAAMI,CAAM,EAC7C,QAAQ,KAAKE,CAAI,EACxBC,EAASE,EAAYT,EAAMI,EAAQF,EAAMQ,EAASV,EAAMM,EAAML,EAAII,EAAI,CAAC,CAAC,CAAC,GAEzEE,EAASI,EAAWX,EAAMI,EAAQF,EAAMD,EAAKI,CAAC,EAC1CD,EAAO,EAAI,GAAKG,EAAO,OAAO,IAAMK,EAASZ,EAAMI,EAAO,CAAC,EAAE,GACjDF,EAAOE,EAAO,EAAIG,EAAO,OAAO,GACjCL,IAEXE,EAASQ,EAASZ,EAAMI,EAAO,CAAC,EAChCG,EAASI,EAAWX,EAAMI,EAAQF,EAAMD,EAAKI,CAAC,IAIpDF,EAAM,KAAK,GAAGI,EAAO,KAAK,EAC1BH,EAAO,EAAIG,EAAO,OAAO,EACzBH,EAAO,EAAIG,EAAO,OAAO,CAC3B,CACA,MAAO,CAAC,MAAAJ,EAAO,OAAAC,CAAM,CACvB,CAGO,SAASO,EACdX,EACAI,EACAF,EACAW,EACAC,EACY,CACZ,IAAMX,EAAQ,CAAC,EACX,CAAC,EAAAY,EAAG,EAAAC,CAAC,EAAIZ,EACb,OAAS,CACP,IAAME,EAAOO,EAAKC,CAAK,EACvB,GAAI,CAACR,GAAQ,QAAQ,KAAKA,CAAI,EAAG,MAEjC,IAAMW,EAAOP,EAASV,EAAMM,EAAMO,EAAKC,EAAQ,CAAC,CAAC,EAC7CC,EAAI,GAAKA,EAAIE,EAAOf,IAAO,CAAC,EAAAa,EAAG,EAAAC,CAAC,EAAIJ,EAASZ,EAAMgB,CAAC,GAOxDb,EAAM,KAAK,CAAC,EAAAY,EAAG,EAAAC,EAAG,EAAGE,EAAclB,EAAMM,CAAI,EAAG,EAAGN,EAAK,UAAU,CAAC,EACnEe,GAAKE,EAELH,GACF,CACA,MAAO,CAAC,MAAAX,EAAO,OAAQ,CAAC,EAAAY,EAAG,EAAAC,CAAC,CAAC,CAC/B,CAEA,SAASJ,EAASZ,EAAYgB,EAAe,CAC3C,MAAO,CAAC,EAAG,EAAG,EAAGA,EAAIhB,EAAK,UAAU,CACtC,CAEA,SAASQ,EAAcR,EAAYI,EAAkC,CACnE,MAAO,CAAC,MAAO,CAAC,MAAS,EAAG,OAAQQ,EAASZ,EAAMI,EAAO,CAAC,CAAC,CAC9D,CAMA,SAASK,EACPT,EACAI,EACAe,EACAF,EACY,CACZ,IAAMG,EACJhB,EAAO,EAAI,GAAKA,EAAO,EAAIa,GAAQE,EAC/BP,EAASZ,EAAMI,EAAO,CAAC,EACvB,CAAC,EAAGA,EAAO,EAAIa,EAAM,EAAGb,EAAO,CAAC,EACtC,MAAO,CAAC,MAAO,CAAC,MAAS,EAAG,OAAQgB,CAAU,CAChD,CAGA,SAASV,EAASV,EAAYqB,EAAaC,EAAiC,CAC1E,OAAOJ,EAAclB,EAAMqB,CAAG,EAAIE,EAAYvB,EAAMqB,EAAKC,CAAG,CAC9D,CC1EO,IAAME,EAAN,MAAMC,CAGX,CACA,aAAa,KAGmB,CAC9B,OAAO,IAAIA,EAAK,MAAMC,EAAU,QAAQ,CAAC,CAC3C,CAES,MAAgC,MAChC,IAAW,IAAIC,EACf,KACA,GAAK,IAAIC,EACT,MAAQ,IAAIC,EAEZC,GAAyB,IAAIC,EAAa,GAAS,EACnDC,GACAC,GAET,YAAYC,EAA+B,CACzC,IAAMC,EAAO,SAAS,cAAc,MAAM,EAC1CA,EAAK,KAAO,WAEZA,EAAK,QAAU,qDACf,SAAS,KAAK,YAAYA,CAAI,EAE9B,SAAS,KAAK,MAAM,OAAS,IAC7B,SAAS,KAAK,MAAM,MAAQ,QAC5B,SAAS,KAAK,MAAM,OAAS,QAC7B,SAAS,KAAK,MAAM,SAAW,SAE/B,IAAMC,EAAS,SAAS,cAAc,QAAQ,EAC9CA,EAAO,MAAM,OAAS,OACtBA,EAAO,MAAM,QAAU,QACvBA,EAAO,MAAM,eAAiB,YAE9BA,EAAO,MAAM,YAAc,OAC3B,SAAS,KAAK,OAAOA,CAAM,EAE3B,KAAK,KAAO,IAAIC,EAAM,KAAK,IAAKD,CAAM,EACtC,KAAKH,GAAY,IAAIK,EAAS,MAAOF,EAAQF,CAAW,EACxD,KAAKF,GAAU,IAAIO,EAAcH,EAAQ,KAAK,KAAM,KAAKH,EAAS,EAClE,KAAKD,GAAQ,SAAS,KAAK,EAC3B,KAAK,WAAa,GACpB,CAEA,IAAI,WAAWQ,EAAc,CAC3B,SAAS,KAAK,MAAM,WAAa,IAAIA,EAAK,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CAAC,GACvE,KAAKP,GAAU,WAAWO,CAAI,CAChC,CAEA,KAAKC,EAA6B,CAChC,KAAKX,GAAS,KAAKW,CAAG,CACxB,CAEA,IAAI,OAAgB,CAClB,OAAO,KAAKT,GAAQ,KACtB,CAEA,OAAOU,EAAyB,CAC9B,KAAK,IAAI,OAAO,EAChB,KAAKV,GAAQ,OAAO,KAAK,IAAK,KAAKF,GAAUY,CAAI,EACjD,KAAKZ,GAAS,KAAO,CACvB,CAEA,OAAOa,EAAuB,CAC5B,OAAO,IAAIC,EAAY,KAAK,MAAOD,CAAG,CACxC,CAEA,MAAa,CACX,KAAKX,GAAQ,OAAO,EACpB,KAAKA,GAAQ,SAAS,QAAQ,EAC9B,KAAK,KAAK,SAAS,QAAQ,CAC7B,CACF,EAEA,SAASN,EAAUmB,EAAwC,CACzD,OAAO,IAAI,QAAQ,CAACC,EAASC,IAAW,CACtC,IAAMC,EAAM,IAAI,MAChBA,EAAI,OAAS,IAAMF,EAAQE,CAAG,EAC9BA,EAAI,QAAU,IAAMD,EAAOC,CAAG,EAC9BA,EAAI,IAAMH,CACZ,CAAC,CACH",
|
|
6
6
|
"names": ["Synth", "#context", "type", "startHz", "endHz", "duration", "now", "end", "oscillator", "gain", "BitmapBuffer", "capacity", "bmp", "Cam", "#clientWH", "#scale", "#w", "#h", "zoomOut", "nativeW", "nativeH", "clientXY", "GamepadPoller", "#bits", "#bitByAxis", "#bitByButton", "axis", "lessBit", "moreBit", "button", "bit", "pad", "index", "bits", "KeyboardPoller", "#bits", "#bitByKey", "key", "bit", "op", "fn", "type", "callback", "#onKey", "ev", "on", "PointerPoller", "#bitByButton", "#bits", "#cam", "#canvas", "#clientXY", "#type", "#xy", "cam", "canvas", "button", "bit", "op", "fn", "type", "#onPointEvent", "#onContextMenuEvent", "ev", "#evButtonsToBits", "buttons", "bits", "Input", "#duration", "#prevBits", "#combo", "#bitByButton", "#gamepad", "GamepadPoller", "#keyboard", "KeyboardPoller", "#pointer", "#pollBits", "#pollTick", "cam", "canvas", "PointerPoller", "combo", "i", "buttons", "bits", "#buttonsToBits", "#bits", "button", "less", "more", "axes", "axis", "#map", "indices", "index", "clicks", "click", "keys", "key", "tick", "op", "fragGLSL", "vertGLSL", "uv", "Renderer", "#bmpBuffer", "#canvas", "#cels", "#gl", "#loseContext", "#spritesheet", "#uniforms", "#vertArray", "atlas", "canvas", "spritesheet", "newCels", "rgba", "gl", "pgm", "loadProgram", "vertGLSL", "fragGLSL", "getUniformLocations", "uvBuffer", "dataTex", "spritesheetTex", "cam", "frame", "bmps", "#resize", "nativeWH", "clientW", "clientH", "diffW", "diffH", "compileShader", "type", "src", "shader", "log", "len", "locations", "i", "uniform", "vert", "frag", "cels", "anim", "cel", "FrameListener", "#canvas", "#frame", "#loop", "#time", "#input", "#renderer", "canvas", "input", "renderer", "op", "fn", "type", "#onEvent", "cam", "buffer", "loop", "#isVisible", "#onFrame", "event", "time", "Sprite", "_Sprite", "atlas", "json", "sprite", "#anim", "#atlas", "tag", "cel", "flip", "diff", "h", "box", "hitbox", "w", "x", "xy", "y", "z", "end", "JSONStorage", "key", "val", "fontCharToTag", "self", "char", "pt", "fontKerning", "lhs", "rhs", "fontCharWidth", "letter", "layoutText", "font", "str", "maxW", "chars", "cursor", "i", "char", "layout", "layoutNewline", "layoutSpace", "tracking", "layoutWord", "nextLine", "word", "index", "x", "y", "span", "fontCharWidth", "width", "nextCursor", "lhs", "rhs", "fontKerning", "Void", "_Void", "loadImage", "Cam", "JSONStorage", "Synth", "#bitmaps", "BitmapBuffer", "#framer", "#renderer", "spritesheet", "meta", "canvas", "Input", "Renderer", "FrameListener", "rgba", "bmp", "loop", "tag", "Sprite", "src", "resolve", "reject", "img"]
|
|
7
7
|
}
|
package/dist/void.meta.json
CHANGED
|
@@ -62,13 +62,8 @@
|
|
|
62
62
|
],
|
|
63
63
|
"format": "esm"
|
|
64
64
|
},
|
|
65
|
-
"src/atlas/
|
|
66
|
-
"bytes":
|
|
67
|
-
"imports": [],
|
|
68
|
-
"format": "esm"
|
|
69
|
-
},
|
|
70
|
-
"src/atlas/atlas.ts": {
|
|
71
|
-
"bytes": 398,
|
|
65
|
+
"src/atlas/anim.js": {
|
|
66
|
+
"bytes": 424,
|
|
72
67
|
"imports": [],
|
|
73
68
|
"format": "esm"
|
|
74
69
|
},
|
|
@@ -83,17 +78,12 @@
|
|
|
83
78
|
"format": "esm"
|
|
84
79
|
},
|
|
85
80
|
"src/graphics/renderer.ts": {
|
|
86
|
-
"bytes":
|
|
81
|
+
"bytes": 7899,
|
|
87
82
|
"imports": [
|
|
88
83
|
{
|
|
89
|
-
"path": "src/atlas/
|
|
90
|
-
"kind": "import-statement",
|
|
91
|
-
"original": "../atlas/atlas-parser.js"
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
"path": "src/atlas/atlas.ts",
|
|
84
|
+
"path": "src/atlas/anim.js",
|
|
95
85
|
"kind": "import-statement",
|
|
96
|
-
"original": "../atlas/
|
|
86
|
+
"original": "../atlas/anim.js"
|
|
97
87
|
},
|
|
98
88
|
{
|
|
99
89
|
"path": "src/graphics/bitmap.ts",
|
|
@@ -145,7 +135,7 @@
|
|
|
145
135
|
"format": "esm"
|
|
146
136
|
},
|
|
147
137
|
"src/sprite/sprite.ts": {
|
|
148
|
-
"bytes":
|
|
138
|
+
"bytes": 4842,
|
|
149
139
|
"imports": [],
|
|
150
140
|
"format": "esm"
|
|
151
141
|
},
|
|
@@ -155,7 +145,7 @@
|
|
|
155
145
|
"format": "esm"
|
|
156
146
|
},
|
|
157
147
|
"src/text/font.ts": {
|
|
158
|
-
"bytes":
|
|
148
|
+
"bytes": 737,
|
|
159
149
|
"imports": [],
|
|
160
150
|
"format": "esm"
|
|
161
151
|
},
|
|
@@ -171,7 +161,7 @@
|
|
|
171
161
|
"format": "esm"
|
|
172
162
|
},
|
|
173
163
|
"src/index.ts": {
|
|
174
|
-
"bytes":
|
|
164
|
+
"bytes": 3361,
|
|
175
165
|
"imports": [
|
|
176
166
|
{
|
|
177
167
|
"path": "src/audio/synth.ts",
|
|
@@ -232,7 +222,7 @@
|
|
|
232
222
|
"imports": [],
|
|
233
223
|
"exports": [],
|
|
234
224
|
"inputs": {},
|
|
235
|
-
"bytes":
|
|
225
|
+
"bytes": 64251
|
|
236
226
|
},
|
|
237
227
|
"dist/void.js": {
|
|
238
228
|
"imports": [],
|
package/package.json
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "Stephen Niedzielski <stephen@oidoid.com> (https://oidoid.com)",
|
|
3
3
|
"bin": {
|
|
4
|
-
"
|
|
5
|
-
"void": "bin/void"
|
|
4
|
+
"void": "tools/void.js"
|
|
6
5
|
},
|
|
7
6
|
"bugs": "https://github.com/oidoid/void/issues",
|
|
8
7
|
"description": "Tiny 2D game engine.",
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"esbuild": "0.20.2",
|
|
10
|
+
"jsdom": "24.0.0"
|
|
11
|
+
},
|
|
9
12
|
"devDependencies": {
|
|
10
13
|
"@ampproject/filesize": "4.3.0",
|
|
11
14
|
"@types/jsdom": "21.1.6",
|
|
12
15
|
"@types/node": "20.11.30",
|
|
13
|
-
"esbuild": "0.20.2",
|
|
14
|
-
"jsdom": "24.0.0",
|
|
15
16
|
"mem-font": "11.0.0-2",
|
|
16
17
|
"prettier": "3.2.5",
|
|
17
18
|
"typescript": "5.4.3",
|
|
@@ -22,7 +23,9 @@
|
|
|
22
23
|
},
|
|
23
24
|
"files": [
|
|
24
25
|
"dist",
|
|
25
|
-
"!dist/**/tsconfig.tsbuildinfo"
|
|
26
|
+
"!dist/**/tsconfig.tsbuildinfo",
|
|
27
|
+
"src/atlas/anim.js",
|
|
28
|
+
"tools/atlas-parser.js"
|
|
26
29
|
],
|
|
27
30
|
"filesize": {
|
|
28
31
|
"dist/void.js": {
|
|
@@ -69,5 +72,5 @@
|
|
|
69
72
|
},
|
|
70
73
|
"type": "module",
|
|
71
74
|
"types": "dist/index.d.ts",
|
|
72
|
-
"version": "0.1.0-
|
|
75
|
+
"version": "0.1.0-4"
|
|
73
76
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @template {AnimTag} T
|
|
3
|
+
* @typedef {object} Anim
|
|
4
|
+
* @prop {readonly Readonly<import('../types/2d.js').XY>[]} cels
|
|
5
|
+
* @prop {Readonly<import('../types/2d.js').Box>} hitbox
|
|
6
|
+
* @prop {number} id A multiple of 16 (maxAnimCels).
|
|
7
|
+
* @prop {number} w
|
|
8
|
+
* @prop {number} h
|
|
9
|
+
* @prop {T & AnimTag} tag
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* `--tagname-format={title}--{tag}`.
|
|
14
|
+
* @typedef {`${string}--${string}`} AnimTag
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export const maxAnimCels = 16
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/** @typedef {import('./aseprite.js').Aseprite} Aseprite */
|
|
2
|
+
/** @typedef {import('./aseprite.js').AsepriteAnimTagFrame} AsepriteAnimTagFrame */
|
|
3
|
+
/** @typedef {import('./aseprite.js').AsepriteFrame} AsepriteFrame */
|
|
4
|
+
/** @typedef {import('./aseprite.js').AsepriteFrameMap} AsepriteFrameMap */
|
|
5
|
+
/** @typedef {import('./aseprite.js').AsepriteSlice} AsepriteSlice */
|
|
6
|
+
/** @typedef {import('./aseprite.js').AsepriteTagSpan} AsepriteTagSpan */
|
|
7
|
+
/** @typedef {import('../src/atlas/anim.js').Anim<AnimTag>} Anim */
|
|
8
|
+
/** @typedef {import('../src/atlas/anim.js').AnimTag} AnimTag */
|
|
9
|
+
/** @typedef {import('../src/atlas/atlas.js').Atlas} Atlas */
|
|
10
|
+
/** @typedef {import('../src/types/2d.js').Box} Box */
|
|
11
|
+
/** @typedef {import('../src/types/2d.js').WH} WH */
|
|
12
|
+
/** @typedef {import('../src/types/2d.js').XY} XY */
|
|
13
|
+
import {maxAnimCels} from '../src/atlas/anim.js'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @arg {Aseprite} ase
|
|
17
|
+
* @return {Atlas}
|
|
18
|
+
*/
|
|
19
|
+
export function parseAtlas(ase) {
|
|
20
|
+
const atlas = new Map()
|
|
21
|
+
for (const span of ase.meta.frameTags) {
|
|
22
|
+
const tag = parseTag(span.name)
|
|
23
|
+
if (atlas.has(tag)) throw Error(`duplicate tag "${tag}" in atlas`)
|
|
24
|
+
const id = atlas.size * maxAnimCels
|
|
25
|
+
atlas.set(tag, parseAnim(id, span, ase.frames, ase.meta.slices))
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const extraSlices = ase.meta.slices.filter(
|
|
29
|
+
slice => !atlas.has(parseTag(slice.name))
|
|
30
|
+
)
|
|
31
|
+
if (extraSlices.length)
|
|
32
|
+
throw Error(
|
|
33
|
+
`unknown hitbox tags in atlas: ${extraSlices.map(slice => slice.name).join(', ')}`
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
return Object.fromEntries(atlas)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @arg {number} id
|
|
41
|
+
* @arg {AsepriteTagSpan} span
|
|
42
|
+
* @arg {AsepriteFrameMap} map
|
|
43
|
+
* @arg {readonly AsepriteSlice[]} slices
|
|
44
|
+
* @return {Anim}
|
|
45
|
+
* @internal
|
|
46
|
+
*/
|
|
47
|
+
export function parseAnim(id, span, map, slices) {
|
|
48
|
+
const frames = [...parseAnimFrames(span, map)]
|
|
49
|
+
if (!frames[0]) throw Error('animation missing frames')
|
|
50
|
+
return {
|
|
51
|
+
id,
|
|
52
|
+
w: frames[0].sourceSize.w,
|
|
53
|
+
h: frames[0].sourceSize.h,
|
|
54
|
+
cels: frames.map(parseCel),
|
|
55
|
+
hitbox: parseHitbox(span, slices),
|
|
56
|
+
tag: parseTag(span.name)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @arg {AsepriteTagSpan} span
|
|
62
|
+
* @arg {AsepriteFrameMap} map
|
|
63
|
+
* @return {IterableIterator<AsepriteFrame>}
|
|
64
|
+
*/
|
|
65
|
+
function* parseAnimFrames(span, map) {
|
|
66
|
+
for (let i = span.from; i <= span.to && i - span.from < maxAnimCels; i++) {
|
|
67
|
+
const animTagFrame = /** @type {AsepriteAnimTagFrame} */ (
|
|
68
|
+
`${span.name}--${i}`
|
|
69
|
+
)
|
|
70
|
+
const frame = map[animTagFrame]
|
|
71
|
+
if (!frame) throw Error(`missing frame "${animTagFrame}"`)
|
|
72
|
+
yield frame
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @arg {AsepriteFrame} frame
|
|
78
|
+
* @return {Readonly<XY>}
|
|
79
|
+
* @internal
|
|
80
|
+
*/
|
|
81
|
+
export function parseCel(frame) {
|
|
82
|
+
return {
|
|
83
|
+
x: frame.frame.x + (frame.frame.w - frame.sourceSize.w) / 2,
|
|
84
|
+
y: frame.frame.y + (frame.frame.h - frame.sourceSize.h) / 2
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* @arg {AsepriteTagSpan} span
|
|
90
|
+
* @arg {readonly AsepriteSlice[]} slices
|
|
91
|
+
* @return {Readonly<Box>}
|
|
92
|
+
* @internal
|
|
93
|
+
*/
|
|
94
|
+
export function parseHitbox(span, slices) {
|
|
95
|
+
const tagSlices = slices.filter(slice => slice.name === span.name)
|
|
96
|
+
if (tagSlices.length > 1) {
|
|
97
|
+
throw Error(`tag "${span.name}" has multiple hitboxes`)
|
|
98
|
+
}
|
|
99
|
+
const box = tagSlices[0]?.keys[0]?.bounds ?? {x: 0, y: 0, w: 0, h: 0}
|
|
100
|
+
// https://github.com/aseprite/aseprite/issues/3524
|
|
101
|
+
for (const key of tagSlices[0]?.keys ?? []) {
|
|
102
|
+
if (
|
|
103
|
+
key.bounds.x !== box.x ||
|
|
104
|
+
key.bounds.y !== box.y ||
|
|
105
|
+
key.bounds.w !== box.w ||
|
|
106
|
+
key.bounds.h !== box.h
|
|
107
|
+
)
|
|
108
|
+
throw Error(`tag "${span.name}" hitbox varies across frames`)
|
|
109
|
+
}
|
|
110
|
+
return box
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @arg {string} tag
|
|
115
|
+
* @return {AnimTag}
|
|
116
|
+
*/
|
|
117
|
+
function parseTag(tag) {
|
|
118
|
+
if (!tag.includes('--')) throw Error(`tag "${tag}" is malformed`)
|
|
119
|
+
return /** @type {AnimTag} */ (tag)
|
|
120
|
+
}
|
package/tools/void.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --no-warnings
|
|
2
|
+
// Bundles sources into a single HTML file for distribution and development.
|
|
3
|
+
//
|
|
4
|
+
// void --html=file --out=dir [--watch] sprite...
|
|
5
|
+
// --watch Run development server. Serve on http://localhost:1234 and reload on
|
|
6
|
+
// code change.
|
|
7
|
+
//
|
|
8
|
+
// --no-warnings shebang works around JSON import warnings. See
|
|
9
|
+
// https://github.com/nodejs/node/issues/27355 and
|
|
10
|
+
// https://github.com/nodejs/node/issues/40940.
|
|
11
|
+
|
|
12
|
+
import {execFile} from 'child_process'
|
|
13
|
+
import esbuild from 'esbuild'
|
|
14
|
+
import {JSDOM} from 'jsdom'
|
|
15
|
+
import fs from 'node:fs/promises'
|
|
16
|
+
import path from 'node:path'
|
|
17
|
+
import pkg from '../package.json' assert {type: 'json'}
|
|
18
|
+
import {parseAtlas} from './atlas-parser.js'
|
|
19
|
+
|
|
20
|
+
const args = process.argv.filter(arg => !arg.startsWith('--'))
|
|
21
|
+
const opts = Object.fromEntries(
|
|
22
|
+
process.argv.filter(arg => arg.startsWith('--')).map(arg => arg.split('='))
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
const watch = '--watch' in opts
|
|
26
|
+
const inFilename = opts['--html']
|
|
27
|
+
if (!inFilename) throw Error('missing input')
|
|
28
|
+
const outDir = opts['--out']
|
|
29
|
+
if (!outDir) throw Error('missing output')
|
|
30
|
+
const doc = new JSDOM(await fs.readFile(inFilename, 'utf8')).window.document
|
|
31
|
+
let srcFilename = /** @type {HTMLScriptElement|null} */ (
|
|
32
|
+
doc.querySelector('script[type="module"][src]')
|
|
33
|
+
)?.src
|
|
34
|
+
if (!srcFilename) throw Error('missing script source')
|
|
35
|
+
srcFilename = `${path.dirname(inFilename)}/${srcFilename}`
|
|
36
|
+
const sprites = args.splice(2)
|
|
37
|
+
if (!sprites.length) throw Error('missing sprites')
|
|
38
|
+
|
|
39
|
+
const atlasPNGFilename = `${await fs.mkdtemp('/tmp/', {encoding: 'utf8'})}/atlas.png`
|
|
40
|
+
const [err, stdout, stderr] = await new Promise(resolve =>
|
|
41
|
+
execFile(
|
|
42
|
+
'aseprite',
|
|
43
|
+
[
|
|
44
|
+
'--batch',
|
|
45
|
+
'--color-mode=indexed',
|
|
46
|
+
'--filename-format={title}--{tag}--{frame}',
|
|
47
|
+
// '--ignore-empty', Breaks --tagname-format.
|
|
48
|
+
'--list-slices',
|
|
49
|
+
'--list-tags',
|
|
50
|
+
'--merge-duplicates',
|
|
51
|
+
`--sheet=${atlasPNGFilename}`,
|
|
52
|
+
'--sheet-pack',
|
|
53
|
+
'--tagname-format={title}--{tag}',
|
|
54
|
+
...sprites
|
|
55
|
+
],
|
|
56
|
+
(err, stdout, stderr) => resolve([err, stdout, stderr])
|
|
57
|
+
)
|
|
58
|
+
)
|
|
59
|
+
process.stderr.write(stderr)
|
|
60
|
+
if (err) throw err
|
|
61
|
+
|
|
62
|
+
const atlasJSON = JSON.stringify(parseAtlas(JSON.parse(stdout)))
|
|
63
|
+
const atlasURI =
|
|
64
|
+
await `data:image/png;base64,${(await fs.readFile(atlasPNGFilename)).toString('base64')}`
|
|
65
|
+
|
|
66
|
+
/** @type {Parameters<esbuild.PluginBuild['onEnd']>[0]} */
|
|
67
|
+
async function pluginOnEnd(result) {
|
|
68
|
+
const copy = /** @type {Document} */ (doc.cloneNode(true))
|
|
69
|
+
const manifestEl = /** @type {HTMLLinkElement|null} */ (
|
|
70
|
+
copy.querySelector('link[href][rel="manifest"]')
|
|
71
|
+
)
|
|
72
|
+
if (manifestEl) {
|
|
73
|
+
const manifestFilename = `${path.dirname(inFilename)}/${manifestEl.href}`
|
|
74
|
+
const manifest = JSON.parse(await fs.readFile(manifestFilename, 'utf8'))
|
|
75
|
+
for (const icon of manifest.icons) {
|
|
76
|
+
if (!icon.src) throw Error('missing manifest icon src')
|
|
77
|
+
if (!icon.type) throw Error('missing manifest icon type')
|
|
78
|
+
const file = await fs.readFile(
|
|
79
|
+
`${path.dirname(manifestFilename)}/${icon.src}`
|
|
80
|
+
)
|
|
81
|
+
icon.src = `data:${icon.type};base64,${file.toString('base64')}`
|
|
82
|
+
}
|
|
83
|
+
if (watch) manifest.start_url = 'http://localhost:1234'
|
|
84
|
+
manifest.version = pkg.version
|
|
85
|
+
manifestEl.href = `data:application/json,${encodeURIComponent(
|
|
86
|
+
JSON.stringify(manifest)
|
|
87
|
+
)}`
|
|
88
|
+
}
|
|
89
|
+
const iconEl = /** @type {HTMLLinkElement|null} */ (
|
|
90
|
+
copy.querySelector('link[href][rel="icon"][type]')
|
|
91
|
+
)
|
|
92
|
+
if (iconEl) {
|
|
93
|
+
const file = await fs.readFile(`${path.dirname(inFilename)}/${iconEl.href}`)
|
|
94
|
+
iconEl.href = `data:${iconEl.type};base64,${file.toString('base64')}`
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let js = ''
|
|
98
|
+
if (watch)
|
|
99
|
+
js +=
|
|
100
|
+
"new globalThis.EventSource('/esbuild').addEventListener('change', () => globalThis.location.reload());"
|
|
101
|
+
|
|
102
|
+
const outFiles =
|
|
103
|
+
result.outputFiles?.filter(file => file.path.endsWith('.js')) ?? []
|
|
104
|
+
if (outFiles.length > 1) throw Error('cannot concatenate JavaScript files')
|
|
105
|
+
if (outFiles[0]) js += outFiles[0].text
|
|
106
|
+
|
|
107
|
+
const scriptEl = /** @type {HTMLScriptElement|null} */ (
|
|
108
|
+
copy.querySelector('script[type="module"][src]')
|
|
109
|
+
)
|
|
110
|
+
if (!scriptEl) throw Error('missing script')
|
|
111
|
+
scriptEl.removeAttribute('src')
|
|
112
|
+
scriptEl.textContent = `
|
|
113
|
+
const atlasURI = '${atlasURI}'
|
|
114
|
+
const atlas = ${atlasJSON}
|
|
115
|
+
${js}
|
|
116
|
+
`
|
|
117
|
+
const outFilename = `${outDir}/${
|
|
118
|
+
watch ? 'index' : `${path.basename(inFilename, '.html')}-v${pkg.version}`
|
|
119
|
+
}.html`
|
|
120
|
+
await fs.mkdir(path.dirname(outFilename), {recursive: true})
|
|
121
|
+
await fs.writeFile(
|
|
122
|
+
outFilename,
|
|
123
|
+
`<!doctype html>${copy.documentElement.outerHTML}`
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** @type {esbuild.BuildOptions} */
|
|
128
|
+
const buildOpts = {
|
|
129
|
+
bundle: true,
|
|
130
|
+
entryPoints: [srcFilename],
|
|
131
|
+
format: 'esm',
|
|
132
|
+
logLevel: `info`, // Print the port and build demarcations.
|
|
133
|
+
minify: !watch,
|
|
134
|
+
outdir: outDir,
|
|
135
|
+
plugins: [{name: 'void', setup: build => build.onEnd(pluginOnEnd)}],
|
|
136
|
+
sourcemap: 'linked',
|
|
137
|
+
target: 'es2022', // https://esbuild.github.io/content-types/#tsconfig-json
|
|
138
|
+
write: false // Written by plugin.
|
|
139
|
+
}
|
|
140
|
+
if (watch) {
|
|
141
|
+
const ctx = await esbuild.context(buildOpts)
|
|
142
|
+
await Promise.race([ctx.watch(), ctx.serve({port: 1234, servedir: 'dist'})])
|
|
143
|
+
} else await esbuild.build(buildOpts)
|