@koiosdigital/matrx-render 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -0
- package/dist/chunk-NASKU36A.js +551 -0
- package/dist/encode/webp-jsquash.d.ts +37 -0
- package/dist/encode/webp-jsquash.js +86 -0
- package/dist/index.d.ts +654 -0
- package/dist/index.js +2788 -0
- package/dist/testing/index.d.ts +22 -0
- package/dist/testing/index.js +76 -0
- package/dist/webp-D106DLhy.d.ts +84 -0
- package/dist/widget-DABrpucj.d.ts +174 -0
- package/package.json +41 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { a as Canvas, W as Widget, B as Bounds } from '../widget-DABrpucj.js';
|
|
2
|
+
export { e as bounds } from '../widget-DABrpucj.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Test utilities — port of pixlet render/testutil.go. Expected images are
|
|
6
|
+
* ASCII art with a color palette; comparison is byte-exact against the
|
|
7
|
+
* premultiplied canvas, just like the Go tests compare against image.RGBA.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
type Palette = Record<string, [number, number, number, number]>;
|
|
11
|
+
declare const DEFAULT_PALETTE: Palette;
|
|
12
|
+
declare function printImage(im: Canvas, palette?: Palette): string;
|
|
13
|
+
/**
|
|
14
|
+
* Assert the canvas matches the expected ASCII art. Throws with an
|
|
15
|
+
* EXPECTED/ACTUAL dump on mismatch (Go's checkImage returns an error).
|
|
16
|
+
*/
|
|
17
|
+
declare function checkImage(expected: string[], actual: Canvas, palette?: Palette): void;
|
|
18
|
+
/** Port of testutil.PaintWidget: canvas sized by the widget's paintBounds,
|
|
19
|
+
* painted with the given layout bounds. */
|
|
20
|
+
declare function paintWidget(w: Widget, b: Bounds, frameIdx: number): Canvas;
|
|
21
|
+
|
|
22
|
+
export { DEFAULT_PALETTE, type Palette, checkImage, paintWidget, printImage };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Canvas,
|
|
3
|
+
DrawContext,
|
|
4
|
+
bounds
|
|
5
|
+
} from "../chunk-NASKU36A.js";
|
|
6
|
+
|
|
7
|
+
// src/testing/index.ts
|
|
8
|
+
var DEFAULT_PALETTE = {
|
|
9
|
+
r: [255, 0, 0, 255],
|
|
10
|
+
g: [0, 255, 0, 255],
|
|
11
|
+
b: [0, 0, 255, 255],
|
|
12
|
+
w: [255, 255, 255, 255],
|
|
13
|
+
".": [0, 0, 0, 0],
|
|
14
|
+
x: [0, 0, 0, 255]
|
|
15
|
+
};
|
|
16
|
+
function printImage(im, palette = DEFAULT_PALETTE) {
|
|
17
|
+
const toAscii = /* @__PURE__ */ new Map();
|
|
18
|
+
for (const [ch, rgba] of Object.entries(palette)) {
|
|
19
|
+
toAscii.set(rgba.join(","), ch);
|
|
20
|
+
}
|
|
21
|
+
let out = "";
|
|
22
|
+
for (let y = 0; y < im.height; y++) {
|
|
23
|
+
for (let x = 0; x < im.width; x++) {
|
|
24
|
+
out += toAscii.get(im.at(x, y).join(",")) ?? "?";
|
|
25
|
+
}
|
|
26
|
+
out += "\n";
|
|
27
|
+
}
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
function diff(expected, actual, palette) {
|
|
31
|
+
return `EXPECTED
|
|
32
|
+
${expected.join("\n")}
|
|
33
|
+
ACTUAL
|
|
34
|
+
${printImage(actual, palette)}`;
|
|
35
|
+
}
|
|
36
|
+
function checkImage(expected, actual, palette = DEFAULT_PALETTE) {
|
|
37
|
+
if (expected.length !== actual.height) {
|
|
38
|
+
throw new Error(
|
|
39
|
+
`expected ${expected.length} rows, found ${actual.height}
|
|
40
|
+
` + diff(expected, actual, palette)
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
for (let y = 0; y < actual.height; y++) {
|
|
44
|
+
const row = expected[y];
|
|
45
|
+
if (row.length !== actual.width) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`row ${y}: expected ${row.length} columns, found ${actual.width}
|
|
48
|
+
` + diff(expected, actual, palette)
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
for (let x = 0; x < actual.width; x++) {
|
|
52
|
+
const want = palette[row[x]];
|
|
53
|
+
const got = actual.at(x, y);
|
|
54
|
+
if (!want || want[0] !== got[0] || want[1] !== got[1] || want[2] !== got[2] || want[3] !== got[3]) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
`color differs at ${x},${y}
|
|
57
|
+
` + diff(expected, actual, palette)
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function paintWidget(w, b, frameIdx) {
|
|
64
|
+
const pb = w.paintBounds(b, frameIdx);
|
|
65
|
+
const canvas = new Canvas(pb.w, pb.h);
|
|
66
|
+
const dc = new DrawContext(canvas);
|
|
67
|
+
w.paint(dc, b, frameIdx);
|
|
68
|
+
return canvas;
|
|
69
|
+
}
|
|
70
|
+
export {
|
|
71
|
+
DEFAULT_PALETTE,
|
|
72
|
+
bounds,
|
|
73
|
+
checkImage,
|
|
74
|
+
paintWidget,
|
|
75
|
+
printImage
|
|
76
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { W as Widget, B as Bounds, D as DrawContext, a as Canvas } from './widget-DABrpucj.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Image — port of pixlet render/image.go. Decodes PNG / animated GIF /
|
|
5
|
+
* WebP (via an injected decoder), scales with nearest-neighbor when
|
|
6
|
+
* width/height are set (aspect preserved when only one is given), and for
|
|
7
|
+
* animated GIFs replays Go Image.InitFromGIF's frame-composition logic —
|
|
8
|
+
* including its disposal-method quirks — exactly.
|
|
9
|
+
*
|
|
10
|
+
* JPEG and SVG are not supported yet (M3); they fail with a clear error.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** Optional WebP decoder (WASM), injected by the host/runtime. */
|
|
14
|
+
type WebpDecoder = (data: Uint8Array) => Promise<{
|
|
15
|
+
width: number;
|
|
16
|
+
height: number;
|
|
17
|
+
rgba: Uint8Array;
|
|
18
|
+
}>;
|
|
19
|
+
declare function setWebpDecoder(decoder: WebpDecoder | null): void;
|
|
20
|
+
declare class Image implements Widget {
|
|
21
|
+
/** Binary image data. */
|
|
22
|
+
src: Uint8Array;
|
|
23
|
+
width: number;
|
|
24
|
+
height: number;
|
|
25
|
+
/** (Read-only) frame delay in ms, for animated GIFs. */
|
|
26
|
+
delay: number;
|
|
27
|
+
private imgs;
|
|
28
|
+
constructor(props: {
|
|
29
|
+
src: Uint8Array;
|
|
30
|
+
width?: number;
|
|
31
|
+
height?: number;
|
|
32
|
+
});
|
|
33
|
+
private initFromGif;
|
|
34
|
+
init(): Promise<void>;
|
|
35
|
+
private frame;
|
|
36
|
+
size(): [number, number];
|
|
37
|
+
paintBounds(_b: Bounds, frameIdx: number): Bounds;
|
|
38
|
+
paint(dc: DrawContext, _b: Bounds, frameIdx: number): void;
|
|
39
|
+
frameCount(): number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Animated WebP encoding — the TS counterpart of pixlet encode/webp.go +
|
|
44
|
+
* encode/encode.go.
|
|
45
|
+
*
|
|
46
|
+
* Per-frame bitstream encoding is delegated to an injected `FrameEncoder`
|
|
47
|
+
* (WASM libwebp — see webp-jsquash.ts); this module owns the deterministic
|
|
48
|
+
* parts: frame-duration policy (delay + maxDuration cap, ported from
|
|
49
|
+
* EncodeWebP) and the animation container mux (VP8X/ANIM/ANMF assembly,
|
|
50
|
+
* the moral equivalent of libwebp's WebPAnimEncoderAssemble with
|
|
51
|
+
* kmin=kmax=0 — every frame an independent keyframe, no blending).
|
|
52
|
+
*
|
|
53
|
+
* Determinism: container assembly is pure; frame bitstreams are
|
|
54
|
+
* deterministic for a pinned libwebp build + settings (handoff §8 — fold
|
|
55
|
+
* the encoder version into the cache key at the render-plane layer).
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
/** Encodes one straight-RGBA frame to a complete (still) WebP file. */
|
|
59
|
+
type FrameEncoder = (rgba: Uint8Array, width: number, height: number) => Promise<Uint8Array>;
|
|
60
|
+
/** encode.go DefaultScreenDelayMillis. */
|
|
61
|
+
declare const DEFAULT_SCREEN_DELAY_MILLIS = 50;
|
|
62
|
+
interface EncodeWebpOptions {
|
|
63
|
+
encoder: FrameEncoder;
|
|
64
|
+
/**
|
|
65
|
+
* Frame delay in ms (Root.delay). Values <= 0 fall back to the default
|
|
66
|
+
* 50ms, mirroring encode.go ScreensFromRoots.
|
|
67
|
+
*/
|
|
68
|
+
delayMs?: number;
|
|
69
|
+
/**
|
|
70
|
+
* Cap on total animation duration in ms; 0 disables the cap. Frame
|
|
71
|
+
* durations are truncated and trailing frames dropped, mirroring
|
|
72
|
+
* EncodeWebP's remainingDuration loop.
|
|
73
|
+
*/
|
|
74
|
+
maxDurationMs?: number;
|
|
75
|
+
/** ANIM loop count; 0 = loop forever (libwebp default). */
|
|
76
|
+
loopCount?: number;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Encode frames to an animated WebP. Returns an empty array for zero frames
|
|
80
|
+
* (EncodeWebP returns []byte{}).
|
|
81
|
+
*/
|
|
82
|
+
declare function encodeWebp(frames: Canvas[], opts: EncodeWebpOptions): Promise<Uint8Array>;
|
|
83
|
+
|
|
84
|
+
export { DEFAULT_SCREEN_DELAY_MILLIS as D, type FrameEncoder as F, Image as I, type WebpDecoder as W, encodeWebp as e, setWebpDecoder as s };
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Colors. Mirrors `pixlet/render/colors.go` (ParseColor) and Go's
|
|
3
|
+
* `color.NRGBA` — straight (non-premultiplied) 8-bit RGBA.
|
|
4
|
+
*/
|
|
5
|
+
/** Straight-alpha 8-bit color, like Go color.NRGBA. */
|
|
6
|
+
interface Color {
|
|
7
|
+
readonly r: number;
|
|
8
|
+
readonly g: number;
|
|
9
|
+
readonly b: number;
|
|
10
|
+
readonly a: number;
|
|
11
|
+
}
|
|
12
|
+
declare const WHITE: Color;
|
|
13
|
+
declare const BLACK: Color;
|
|
14
|
+
declare const TRANSPARENT: Color;
|
|
15
|
+
/**
|
|
16
|
+
* Parse `#RGB`, `#RGBA`, `#RRGGBB`, `#RRGGBBAA` (leading `#` optional — one is
|
|
17
|
+
* stripped, mirroring Go strings.TrimPrefix). Port of render.ParseColor.
|
|
18
|
+
*/
|
|
19
|
+
declare function parseColor(scol: string): Color;
|
|
20
|
+
/**
|
|
21
|
+
* 16-bit premultiplied color, i.e. what Go's `color.NRGBA.RGBA()` returns.
|
|
22
|
+
* All blend math runs on these, mirroring Go exactly:
|
|
23
|
+
* v16 = (v8 * 0x101 * a8) / 0xff (integer division)
|
|
24
|
+
*/
|
|
25
|
+
interface Color16 {
|
|
26
|
+
readonly r: number;
|
|
27
|
+
readonly g: number;
|
|
28
|
+
readonly b: number;
|
|
29
|
+
readonly a: number;
|
|
30
|
+
}
|
|
31
|
+
declare function color16(c: Color): Color16;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Canvas — an RGBA pixel buffer with premultiplied alpha, mirroring Go's
|
|
35
|
+
* `image.RGBA` (which is what gg renders into). 4 bytes per pixel, row-major.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
declare class Canvas {
|
|
39
|
+
readonly width: number;
|
|
40
|
+
readonly height: number;
|
|
41
|
+
/** Premultiplied RGBA, length = width * height * 4. */
|
|
42
|
+
readonly pix: Uint8Array;
|
|
43
|
+
constructor(width: number, height: number);
|
|
44
|
+
/**
|
|
45
|
+
* Fill every pixel with `c`, ignoring any clip — mirrors gg.Clear()
|
|
46
|
+
* (draw.Src over the whole image). Used by Root for solid backgrounds.
|
|
47
|
+
*/
|
|
48
|
+
clear(c: Color): void;
|
|
49
|
+
/** Premultiplied RGBA of pixel (x, y). Out of bounds returns zeros. */
|
|
50
|
+
at(x: number, y: number): [number, number, number, number];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Analytic polygon-coverage rasterization for affine-transformed rectangles
|
|
55
|
+
* (Transformation with scale/rotate, and eventually Circle/Plot paths).
|
|
56
|
+
*
|
|
57
|
+
* Parity note: pixlet rasterizes through freetype/raster, whose span
|
|
58
|
+
* accumulation produces near-exact area coverage. We compute exact per-pixel
|
|
59
|
+
* polygon area (Sutherland–Hodgman clip against each pixel square). Results
|
|
60
|
+
* are integer-identical for axis-aligned integer rectangles and within the
|
|
61
|
+
* project's perceptual-tolerance bar (§14, "locked") for AA edges. Integer
|
|
62
|
+
* translations never reach this path — they use the exact fast paths.
|
|
63
|
+
*/
|
|
64
|
+
interface Pt {
|
|
65
|
+
x: number;
|
|
66
|
+
y: number;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* DrawContext — the subset of tidbyt/gg's Context that pixlet's widgets use:
|
|
71
|
+
* Push/Pop, Translate/Scale/Rotate (+ *About variants), SetColor,
|
|
72
|
+
* DrawRectangle+Fill, DrawRectangle+Clip, DrawImage.
|
|
73
|
+
*
|
|
74
|
+
* Two rendering regimes, chosen per-operation:
|
|
75
|
+
*
|
|
76
|
+
* - Integer translation (all of pixlet's static widgets): exact fast paths
|
|
77
|
+
* whose integer blend math mirrors freetype/gg byte-for-byte. This is the
|
|
78
|
+
* regime the ported pixlet unit tests pin down.
|
|
79
|
+
* - General affine (Transformation's scale/rotate): rectangles become
|
|
80
|
+
* convex quads filled via analytic polygon coverage; images are
|
|
81
|
+
* inverse-mapped with bilinear sampling (x/image/draw-style). Perceptual
|
|
82
|
+
* parity per the locked bar (§14) — byte-exact freetype span replication
|
|
83
|
+
* is deliberately out of scope.
|
|
84
|
+
*
|
|
85
|
+
* The clip is a full-canvas alpha mask (like gg's `mask *image.Alpha`).
|
|
86
|
+
* Intersection is per-pixel multiplication — gg.Clip()'s DrawMask(Over onto
|
|
87
|
+
* empty) composition. Push/Pop snapshot {matrix, color, mask}; masks are
|
|
88
|
+
* immutable once installed, so snapshots share them.
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
declare class DrawContext {
|
|
92
|
+
readonly canvas: Canvas;
|
|
93
|
+
private st;
|
|
94
|
+
private stack;
|
|
95
|
+
constructor(canvas: Canvas);
|
|
96
|
+
push(): void;
|
|
97
|
+
pop(): void;
|
|
98
|
+
translate(dx: number, dy: number): void;
|
|
99
|
+
scale(sx: number, sy: number): void;
|
|
100
|
+
/** Anticlockwise rotation about the origin, radians. */
|
|
101
|
+
rotate(angle: number): void;
|
|
102
|
+
scaleAbout(sx: number, sy: number, x: number, y: number): void;
|
|
103
|
+
rotateAbout(angle: number, x: number, y: number): void;
|
|
104
|
+
setColor(c: Color): void;
|
|
105
|
+
/** Transformed corners of rect (x,y,w,h), in path order. */
|
|
106
|
+
private rectQuad;
|
|
107
|
+
/**
|
|
108
|
+
* gg DrawRectangle(x,y,w,h) + Fill().
|
|
109
|
+
* A negative width/height rectangle is a reversed-winding path covering
|
|
110
|
+
* [x+w, x] × [y+h, y]; the non-zero winding rule still fills it.
|
|
111
|
+
*/
|
|
112
|
+
fillRect(x: number, y: number, w: number, h: number): void;
|
|
113
|
+
/**
|
|
114
|
+
* gg DrawRectangle(x,y,w,h) + Clip(): intersect the clip region with the
|
|
115
|
+
* given rectangle (in current-transform space).
|
|
116
|
+
*/
|
|
117
|
+
clipRect(x: number, y: number, w: number, h: number): void;
|
|
118
|
+
/**
|
|
119
|
+
* gg SetPixel: sets the pixel to the current color, converting like Go's
|
|
120
|
+
* image.RGBA.Set (NRGBA → premultiplied). Note: like gg, this *ignores*
|
|
121
|
+
* the clip mask and compositing — it is a raw store. Plot depends on it.
|
|
122
|
+
*/
|
|
123
|
+
setPixel(x: number, y: number): void;
|
|
124
|
+
/** Apply the current matrix to a point (gg TransformPoint). */
|
|
125
|
+
transformPoint(x: number, y: number): Pt;
|
|
126
|
+
/**
|
|
127
|
+
* Fill an arbitrary polygon given in local (pre-transform) coordinates
|
|
128
|
+
* with the current color — the gg path-Fill equivalent for non-rect
|
|
129
|
+
* shapes (Circle, PieChart). Coverage-based AA, honors the clip mask.
|
|
130
|
+
*/
|
|
131
|
+
fillPolygon(localPts: Pt[]): void;
|
|
132
|
+
/** gg DrawImage(src, x, y) with the current transform and clip. */
|
|
133
|
+
drawCanvas(src: Canvas, x: number, y: number): void;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Bounds is the (width, height) of a layout rectangle.
|
|
138
|
+
*
|
|
139
|
+
* Pixlet passes Go `image.Rectangle` values constructed as
|
|
140
|
+
* `image.Rect(0, 0, w, h)` throughout layout, and widgets only ever consume
|
|
141
|
+
* `Dx()`/`Dy()`. Go canonicalizes rectangles — negative extents swap min/max —
|
|
142
|
+
* so `Dx()`/`Dy()` come out as the *absolute value*. Pixlet relies on this:
|
|
143
|
+
* e.g. `Padding.PaintBounds` computes `bounds.Dx()-Left-Right`, which can go
|
|
144
|
+
* negative and silently becomes positive again (see TestPadding "small
|
|
145
|
+
* bounds": a 4×4 bound with pad l1/t2/r3/b4 measures the child against 0×2).
|
|
146
|
+
*
|
|
147
|
+
* `bounds()` mirrors that behavior exactly. Do not "fix" it — parity with the
|
|
148
|
+
* Go renderer depends on it.
|
|
149
|
+
*/
|
|
150
|
+
interface Bounds {
|
|
151
|
+
readonly w: number;
|
|
152
|
+
readonly h: number;
|
|
153
|
+
}
|
|
154
|
+
/** Mirror of Go `image.Rect(0, 0, w, h)` → `(Dx(), Dy())`. */
|
|
155
|
+
declare function bounds(w: number, h: number): Bounds;
|
|
156
|
+
|
|
157
|
+
/** Widget contract. Mirrors pixlet render/widget.go. */
|
|
158
|
+
|
|
159
|
+
interface Widget {
|
|
160
|
+
/** Bounds of the area that will actually be drawn to when paint() is called. */
|
|
161
|
+
paintBounds(bounds: Bounds, frameIdx: number): Bounds;
|
|
162
|
+
paint(dc: DrawContext, bounds: Bounds, frameIdx: number): void;
|
|
163
|
+
frameCount(): number;
|
|
164
|
+
/** Widgets can require initialization (Text, Image, WrappedText). */
|
|
165
|
+
init?(): void | Promise<void>;
|
|
166
|
+
/** WidgetStaticSize: inherent size known before painting. */
|
|
167
|
+
size?(): [number, number];
|
|
168
|
+
}
|
|
169
|
+
/** Computes a (mod m), non-negative. */
|
|
170
|
+
declare function modInt(a: number, m: number): number;
|
|
171
|
+
/** Maximum frame count of a slice of widgets (minimum 1). */
|
|
172
|
+
declare function maxFrameCount(widgets: Widget[]): number;
|
|
173
|
+
|
|
174
|
+
export { type Bounds as B, type Color16 as C, DrawContext as D, TRANSPARENT as T, type Widget as W, Canvas as a, type Color as b, BLACK as c, WHITE as d, bounds as e, color16 as f, modInt as g, maxFrameCount as m, parseColor as p };
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@koiosdigital/matrx-render",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": "./dist/index.js",
|
|
7
|
+
"./testing": "./dist/testing/index.js",
|
|
8
|
+
"./webp-jsquash": "./dist/encode/webp-jsquash.js",
|
|
9
|
+
"./package.json": "./package.json"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@jsquash/webp": "^1.5.0",
|
|
13
|
+
"fflate": "^0.8.3",
|
|
14
|
+
"@koiosdigital/matrx-sdk": "0.1.0"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/node": "^26.1.0",
|
|
18
|
+
"typescript": "^5.8.0",
|
|
19
|
+
"vitest": "^3.2.0"
|
|
20
|
+
},
|
|
21
|
+
"license": "GPL-3.0-only",
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/koiosdigital/matrx-render.git",
|
|
25
|
+
"directory": "packages/render"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc -p tsconfig.json",
|
|
35
|
+
"test": "vitest run",
|
|
36
|
+
"gen:fonts": "node scripts/gen-fonts.mjs",
|
|
37
|
+
"build:dist": "tsup src/index.ts src/testing/index.ts src/encode/webp-jsquash.ts --format esm --dts --clean --out-dir dist"
|
|
38
|
+
},
|
|
39
|
+
"main": "./dist/index.js",
|
|
40
|
+
"types": "./dist/index.d.ts"
|
|
41
|
+
}
|