@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.
@@ -0,0 +1,654 @@
1
+ import { C as Color16, a as Canvas, W as Widget, b as Color, B as Bounds, D as DrawContext } from './widget-DABrpucj.js';
2
+ export { c as BLACK, T as TRANSPARENT, d as WHITE, e as bounds, f as color16, m as maxFrameCount, g as modInt, p as parseColor } from './widget-DABrpucj.js';
3
+ import { WidgetSpec, RootSpec } from '@koiosdigital/matrx-sdk';
4
+ export { D as DEFAULT_SCREEN_DELAY_MILLIS, F as FrameEncoder, I as Image, W as WebpDecoder, e as encodeWebp, s as setWebpDecoder } from './webp-D106DLhy.js';
5
+
6
+ /**
7
+ * BDF bitmap-font parser — a line-for-line port of zachomedia/go-bdf
8
+ * (the parser pixlet uses), including its quirks, because Text rendering
9
+ * parity depends on them:
10
+ *
11
+ * - Metrics come from FONT_ASCENT / FONT_DESCENT properties.
12
+ * - Glyph advance is DWIDTH's x component; BBX gives the bitmap size and
13
+ * the lower-left offset (LowerPoint).
14
+ * - Bitmap rows are hex, MSB-first across bytes; BPP defaults to 1 and each
15
+ * pixel scales to 0..255 (binary for BPP=1).
16
+ * - Character code → rune mapping: go-bdf consults a charmap for
17
+ * ISO8859-1/2/9/15 registries, but BDF files quote the registry value
18
+ * (`CHARSET_REGISTRY "ISO10646"`), and go-bdf's lookup key includes those
19
+ * quotes — so the lookup never matches for any bundled font and the
20
+ * mapping is codepoint identity. (For ISO8859-1, the charmap *is* the
21
+ * identity anyway.) We implement identity, which is byte-identical for
22
+ * all twelve bundled fonts.
23
+ * - DEFAULT_CHAR: missing runes fall back to this glyph; if the property is
24
+ * absent the fallback code is 0 (go-bdf initializes 32, then always
25
+ * overwrites it after the property scan).
26
+ */
27
+ interface Glyph {
28
+ name: string;
29
+ /** Character code (codepoint identity — see module docs). */
30
+ code: number;
31
+ /** DWIDTH x — horizontal advance in pixels. */
32
+ advanceX: number;
33
+ /** BBX width/height. */
34
+ w: number;
35
+ h: number;
36
+ /** BBX lower-left offset (lx, ly). */
37
+ lx: number;
38
+ ly: number;
39
+ /** Alpha bitmap, w*h bytes, row-major, 0..255 (binary for BPP=1). */
40
+ bitmap: Uint8Array;
41
+ }
42
+ interface BdfFont {
43
+ name: string;
44
+ ascent: number;
45
+ descent: number;
46
+ capHeight: number;
47
+ xHeight: number;
48
+ /** DEFAULT_CHAR code; 0 when the property is absent. */
49
+ defaultCode: number;
50
+ glyphs: Map<number, Glyph>;
51
+ }
52
+ /** go-bdf lookup(): exact glyph, else DEFAULT_CHAR's glyph, else null. */
53
+ declare function lookupGlyph(font: BdfFont, code: number): Glyph | null;
54
+ declare function parseBdf(text: string): BdfFont;
55
+
56
+ /**
57
+ * Font registry + text measurement/rasterization.
58
+ * Mirrors pixlet render/fonts.go (GetFont, lazy parse + cache) and the
59
+ * font.Drawer semantics that gg's MeasureString/drawString build on.
60
+ */
61
+
62
+ declare function getFontList(): string[];
63
+ declare function getFont(name: string): BdfFont;
64
+ /**
65
+ * Sum of glyph advances in pixels. Mirrors font.Drawer.MeasureString via
66
+ * gg.MeasureString: kerning is always 0 for BDF faces; code points missing
67
+ * from the font (after DEFAULT_CHAR fallback) are skipped without advance.
68
+ * BDF advances are integral, so the 26.6 fixed-point floor is exact.
69
+ */
70
+ declare function measureString(font: BdfFont, s: string): number;
71
+ declare function renderText(font: BdfFont, content: string, color: Color16, height: number, offset: number): Canvas;
72
+
73
+ /**
74
+ * Minimal deterministic PNG encoder (8-bit RGBA, zlib stored blocks).
75
+ * Zero dependencies so it runs identically in Node, Workers, and tests.
76
+ * Output is not size-optimized — it exists for golden fixtures, previews,
77
+ * and the CLI, not for production delivery (production output is WebP).
78
+ */
79
+
80
+ /**
81
+ * Encode a canvas as PNG. The canvas holds premultiplied RGBA; PNG wants
82
+ * straight alpha, so we un-premultiply exactly like Go's image/png does for
83
+ * image.RGBA input (NRGBAModel conversion: v = v16 * 0xffff / a16, >> 8).
84
+ */
85
+ declare function encodePng(canvas: Canvas): Uint8Array;
86
+
87
+ /**
88
+ * Hydration: `WidgetSpec` JSON (produced by app isolates via @koiosdigital/matrx-sdk
89
+ * builders) → paintable widget instances, plus the top-level render entry
90
+ * point. This is the host side of the D1 boundary: the isolate returns a
91
+ * serializable tree; layout/rasterization happen here.
92
+ */
93
+
94
+ /** Hydrate a (non-root) widget spec and run all pending init()s. */
95
+ declare function buildWidget(spec: WidgetSpec): Promise<Widget>;
96
+ interface RenderResult {
97
+ frames: Canvas[];
98
+ /** Frame delay in milliseconds (Root.delay). */
99
+ delay: number;
100
+ /** Expiration time in seconds (Root.maxAge). */
101
+ maxAge: number;
102
+ showFullAnimation: boolean;
103
+ }
104
+ /**
105
+ * Render a root spec to frames. Canvas dimensions come from the render call
106
+ * (device-provided), not the app — handoff §10.
107
+ */
108
+ declare function renderRoot(spec: RootSpec, opts?: {
109
+ width?: number;
110
+ height?: number;
111
+ maxFrameCount?: number;
112
+ solidBackground?: boolean;
113
+ }): Promise<RenderResult>;
114
+
115
+ /** Box — port of pixlet render/box.go. */
116
+
117
+ declare class Box implements Widget {
118
+ child: Widget | null;
119
+ width: number;
120
+ height: number;
121
+ padding: number;
122
+ color: Color | null;
123
+ constructor(props?: {
124
+ child?: Widget | null;
125
+ width?: number;
126
+ height?: number;
127
+ padding?: number;
128
+ color?: Color | null;
129
+ });
130
+ paintBounds(b: Bounds, _frameIdx: number): Bounds;
131
+ paint(dc: DrawContext, b: Bounds, frameIdx: number): void;
132
+ frameCount(): number;
133
+ }
134
+
135
+ /**
136
+ * Vector — port of pixlet render/vector.go: the shared layout engine behind
137
+ * Row and Column. Ported line-for-line, including the child-measurement
138
+ * overflow breaks, residual-space distribution, and the space_between
139
+ * `offset = -1` residual trick. Integer divisions use Math.trunc to match
140
+ * Go's truncating division (cross offsets can go negative when a child is
141
+ * taller than the clamped vector).
142
+ */
143
+
144
+ type MainAlign = "start" | "end" | "center" | "space_between" | "space_evenly" | "space_around" | "";
145
+ type CrossAlign = "start" | "center" | "end" | "";
146
+ declare class Vector implements Widget {
147
+ children: Widget[];
148
+ mainAlign: MainAlign;
149
+ crossAlign: CrossAlign;
150
+ expanded: boolean;
151
+ vertical: boolean;
152
+ constructor(props: {
153
+ children: Widget[];
154
+ mainAlign?: MainAlign;
155
+ crossAlign?: CrossAlign;
156
+ expanded?: boolean;
157
+ vertical?: boolean;
158
+ });
159
+ paintBounds(b: Bounds, frameIdx: number): Bounds;
160
+ paint(dc: DrawContext, b: Bounds, frameIdx: number): void;
161
+ frameCount(): number;
162
+ }
163
+ /** Row — port of pixlet render/row.go (a horizontal Vector). */
164
+ declare class Row extends Vector {
165
+ constructor(props: {
166
+ children: Widget[];
167
+ mainAlign?: MainAlign;
168
+ crossAlign?: CrossAlign;
169
+ expanded?: boolean;
170
+ });
171
+ }
172
+ /** Column — port of pixlet render/column.go (a vertical Vector). */
173
+ declare class Column extends Vector {
174
+ constructor(props: {
175
+ children: Widget[];
176
+ mainAlign?: MainAlign;
177
+ crossAlign?: CrossAlign;
178
+ expanded?: boolean;
179
+ });
180
+ }
181
+
182
+ /** Stack — port of pixlet render/stack.go. Children painted in order, later on top. */
183
+
184
+ declare class Stack implements Widget {
185
+ children: Widget[];
186
+ constructor(props: {
187
+ children: Widget[];
188
+ });
189
+ paintBounds(b: Bounds, frameIdx: number): Bounds;
190
+ paint(dc: DrawContext, b: Bounds, frameIdx: number): void;
191
+ frameCount(): number;
192
+ }
193
+
194
+ /** Padding — port of pixlet render/padding.go, including the negative-pad
195
+ * positioning hack and the clip/translate ordering. */
196
+
197
+ interface Insets {
198
+ left: number;
199
+ top: number;
200
+ right: number;
201
+ bottom: number;
202
+ }
203
+ declare class Padding implements Widget {
204
+ child: Widget;
205
+ pad: Insets;
206
+ expanded: boolean;
207
+ color: Color | null;
208
+ constructor(props: {
209
+ child: Widget;
210
+ pad?: Insets;
211
+ expanded?: boolean;
212
+ color?: Color | null;
213
+ });
214
+ paintBounds(b: Bounds, frameIdx: number): Bounds;
215
+ paint(dc: DrawContext, b: Bounds, frameIdx: number): void;
216
+ frameCount(): number;
217
+ }
218
+
219
+ /** Text — port of pixlet render/text.go: single line, prerendered at init. */
220
+
221
+ declare const DEFAULT_FONT_FACE = "tb-8";
222
+ declare class Text implements Widget {
223
+ content: string;
224
+ font: string;
225
+ height: number;
226
+ offset: number;
227
+ color: Color | null;
228
+ private img;
229
+ constructor(props: {
230
+ content: string;
231
+ font?: string;
232
+ height?: number;
233
+ offset?: number;
234
+ color?: Color | null;
235
+ });
236
+ init(): void;
237
+ private image;
238
+ size(): [number, number];
239
+ paintBounds(_b: Bounds, _frameIdx: number): Bounds;
240
+ paint(dc: DrawContext, _b: Bounds, _frameIdx: number): void;
241
+ frameCount(): number;
242
+ }
243
+
244
+ /**
245
+ * Root — port of pixlet render/root.go.
246
+ *
247
+ * Divergence from the fork (documented): the Go fork falls back to mutable
248
+ * package globals for dimensions (pre-thread-safety compat). Here dimensions
249
+ * are instance-only, defaulting to 64×32 — the behavior fork commit 665d55b
250
+ * was moving toward.
251
+ */
252
+
253
+ declare const DEFAULT_FRAME_WIDTH = 64;
254
+ declare const DEFAULT_FRAME_HEIGHT = 32;
255
+ declare const DEFAULT_MAX_FRAME_COUNT = 2000;
256
+ declare class Root {
257
+ child: Widget;
258
+ /** Frame delay in milliseconds. */
259
+ delay: number;
260
+ /** Expiration time in seconds. */
261
+ maxAge: number;
262
+ showFullAnimation: boolean;
263
+ /** Canvas dimensions; 0 → defaults. */
264
+ width: number;
265
+ height: number;
266
+ constructor(props: {
267
+ child: Widget;
268
+ delay?: number;
269
+ maxAge?: number;
270
+ showFullAnimation?: boolean;
271
+ width?: number;
272
+ height?: number;
273
+ });
274
+ /** Render all frames. Mirrors Root.Paint (sequentially — no goroutines). */
275
+ paint(opts?: {
276
+ solidBackground?: boolean;
277
+ maxFrameCount?: number;
278
+ }): Canvas[];
279
+ }
280
+
281
+ /** Animation — port of pixlet render/animation.go: each child is one frame. */
282
+
283
+ declare class Animation implements Widget {
284
+ children: Widget[];
285
+ constructor(props: {
286
+ children: Widget[];
287
+ });
288
+ frameCount(): number;
289
+ paintBounds(b: Bounds, frameIdx: number): Bounds;
290
+ paint(dc: DrawContext, b: Bounds, frameIdx: number): void;
291
+ }
292
+
293
+ /**
294
+ * Sequence — port of pixlet render/sequence.go (Koios fork, including the
295
+ * `duration` loop extension): children rendered one after another, each for
296
+ * its own frame count.
297
+ */
298
+
299
+ declare class Sequence implements Widget {
300
+ children: Widget[];
301
+ /** Total duration in frames (0 = play once, >0 = loop children to fill). */
302
+ duration: number;
303
+ constructor(props: {
304
+ children: Widget[];
305
+ duration?: number;
306
+ });
307
+ /** Natural frame count of one complete pass through all children. */
308
+ baseCycleFrameCount(): number;
309
+ frameCount(): number;
310
+ private resolveFrameIdx;
311
+ paintBounds(b: Bounds, frameIdx: number): Bounds;
312
+ paint(dc: DrawContext, b: Bounds, frameIdx: number): void;
313
+ }
314
+
315
+ /**
316
+ * Marquee — port of pixlet render/marquee.go (Koios fork: delay, endDelay,
317
+ * loop). Frame-count formulas are reproduced exactly (handoff §5).
318
+ *
319
+ * Ported quirk: frameCount() measures the child against the *default*
320
+ * 64×32 frame dimensions (the fork does this for thread safety), while
321
+ * paint() measures against the actual bounds. Keep it that way for parity.
322
+ */
323
+
324
+ declare class Marquee implements Widget {
325
+ child: Widget;
326
+ width: number;
327
+ height: number;
328
+ offsetStart: number;
329
+ offsetEnd: number;
330
+ scrollDirection: string;
331
+ align: string;
332
+ delay: number;
333
+ endDelay: number;
334
+ loop: boolean;
335
+ constructor(props: {
336
+ child: Widget;
337
+ width?: number;
338
+ height?: number;
339
+ offsetStart?: number;
340
+ offsetEnd?: number;
341
+ scrollDirection?: string;
342
+ align?: string;
343
+ delay?: number;
344
+ endDelay?: number;
345
+ loop?: boolean;
346
+ });
347
+ private isVertical;
348
+ paintBounds(b: Bounds, _frameIdx: number): Bounds;
349
+ frameCount(): number;
350
+ paint(dc: DrawContext, b: Bounds, frameIdx: number): void;
351
+ private paintLoop;
352
+ }
353
+
354
+ /**
355
+ * Easing curves — port of pixlet render/animation/curve.go.
356
+ */
357
+ type Curve = (t: number) => number;
358
+ declare const linearCurve: Curve;
359
+ /**
360
+ * Cubic bezier easing, solved by bisection exactly like the Go code
361
+ * (epsilon 0.0001 on the x axis). The Go loop is unbounded; we cap the
362
+ * iteration count as a safety net — at 64 halvings the interval is far below
363
+ * any float64 epsilon, so a convergent input (monotone x, i.e. a,c ∈ [0,1])
364
+ * terminates identically to Go long before the cap.
365
+ */
366
+ declare function cubicBezierCurve(a: number, b: number, c: number, d: number): Curve;
367
+ declare const easeIn: Curve;
368
+ declare const easeOut: Curve;
369
+ declare const easeInOut: Curve;
370
+ /** Port of animation.ParseCurve. */
371
+ declare function parseCurve(str: string): Curve;
372
+
373
+ /**
374
+ * Transforms and their interpolation — port of pixlet
375
+ * render/animation/{transform,translate,scale,rotate,rounding,util,vector}.go.
376
+ */
377
+
378
+ declare function rescale(fromMin: number, fromMax: number, toMin: number, toMax: number, v: number): number;
379
+ declare function lerp(from: number, to: number, t: number): number;
380
+ type RoundingMode = "round" | "floor" | "ceil" | "none";
381
+ declare function applyRounding(mode: RoundingMode, v: number): number;
382
+ type Transform = {
383
+ kind: "translate";
384
+ x: number;
385
+ y: number;
386
+ } | {
387
+ kind: "scale";
388
+ x: number;
389
+ y: number;
390
+ } | {
391
+ kind: "rotate";
392
+ angle: number;
393
+ };
394
+ /**
395
+ * Pairwise interpolation of transform lists; lists of unequal length are
396
+ * extended with per-kind defaults. Mismatched kinds at the same position
397
+ * would require matrix-level interpolation, which pixlet does not support —
398
+ * returns ok=false, and no transforms are applied.
399
+ */
400
+ declare function interpolateTransforms(lhs: Transform[], rhs: Transform[], progress: number): {
401
+ transforms: Transform[];
402
+ ok: boolean;
403
+ };
404
+
405
+ /**
406
+ * Keyframes, origin, direction, fill mode — port of pixlet
407
+ * render/animation/{keyframe,origin,direction,fill_mode,transformation}.go
408
+ * (the keyframe-processing half of transformation.go lives here).
409
+ */
410
+
411
+ interface Keyframe {
412
+ /** Point in time, 0.0 .. 1.0. */
413
+ percentage: number;
414
+ transforms: Transform[];
415
+ curve: Curve;
416
+ }
417
+ /**
418
+ * Sort keyframes (stable) and add 0%/100% keyframes if missing.
419
+ * See https://www.w3.org/TR/css-animations-1/#keyframes
420
+ */
421
+ declare function processKeyframes(arr: Keyframe[]): Keyframe[];
422
+ /**
423
+ * Find the adjacent keyframes for a progress value. Returns null when the
424
+ * value is out of range (including NaN progress from a zero-length
425
+ * animation, which flows through comparisons exactly like in Go) — the
426
+ * caller then applies no transforms.
427
+ */
428
+ declare function findKeyframes(arr: Keyframe[], p: number): [Keyframe, Keyframe] | null;
429
+ interface Origin {
430
+ x: number;
431
+ y: number;
432
+ }
433
+ declare const DEFAULT_ORIGIN: Origin;
434
+ type DirectionMode = "normal" | "reverse" | "alternate" | "alternate_reverse";
435
+ type FillMode = "forwards" | "backwards";
436
+
437
+ /**
438
+ * Transformation — port of pixlet render/animation/transformation.go:
439
+ * CSS-like keyframe animation of translate/scale/rotate on a child widget.
440
+ */
441
+
442
+ declare class Transformation implements Widget {
443
+ child: Widget;
444
+ keyframes: Keyframe[];
445
+ duration: number;
446
+ delay: number;
447
+ width: number;
448
+ height: number;
449
+ origin: Origin;
450
+ direction: DirectionMode;
451
+ fillMode: FillMode;
452
+ rounding: RoundingMode;
453
+ waitForChild: boolean;
454
+ constructor(props: {
455
+ child: Widget;
456
+ keyframes: Keyframe[];
457
+ duration: number;
458
+ delay?: number;
459
+ width?: number;
460
+ height?: number;
461
+ origin?: Origin;
462
+ direction?: DirectionMode;
463
+ fillMode?: FillMode;
464
+ rounding?: RoundingMode;
465
+ waitForChild?: boolean;
466
+ });
467
+ init(): void;
468
+ frameCount(): number;
469
+ paintBounds(b: Bounds, _frameIdx: number): Bounds;
470
+ paint(dc: DrawContext, b: Bounds, frameIdx: number): void;
471
+ }
472
+
473
+ /**
474
+ * WrappedText — port of pixlet render/wrappedtext.go + gg's wordWrap and
475
+ * DrawStringWrapped line placement. Lines are rasterized with the shared
476
+ * text pipeline and blitted at the exact positions gg's anchored draw
477
+ * produces (fixed-point dot quantization → floor at .5 offsets).
478
+ */
479
+
480
+ /** Port of gg wordWrap. */
481
+ declare function wordWrap(font: BdfFont, s: string, width: number): string[];
482
+ declare class WrappedText implements Widget {
483
+ content: string;
484
+ font: string;
485
+ height: number;
486
+ width: number;
487
+ lineSpacing: number;
488
+ color: Color | null;
489
+ align: string;
490
+ private face;
491
+ constructor(props: {
492
+ content: string;
493
+ font?: string;
494
+ height?: number;
495
+ width?: number;
496
+ lineSpacing?: number;
497
+ color?: Color | null;
498
+ align?: string;
499
+ });
500
+ init(): void;
501
+ private fontFace;
502
+ paintBounds(b: Bounds, _frameIdx: number): Bounds;
503
+ paint(dc: DrawContext, b: Bounds, frameIdx: number): void;
504
+ frameCount(): number;
505
+ }
506
+
507
+ /** Circle — port of pixlet render/circle.go. */
508
+
509
+ declare class Circle implements Widget {
510
+ child: Widget | null;
511
+ color: Color;
512
+ diameter: number;
513
+ constructor(props: {
514
+ child?: Widget | null;
515
+ color: Color;
516
+ diameter: number;
517
+ });
518
+ paintBounds(_b: Bounds, _frameIdx: number): Bounds;
519
+ paint(dc: DrawContext, _b: Bounds, frameIdx: number): void;
520
+ frameCount(): number;
521
+ }
522
+
523
+ /** PieChart — port of pixlet render/pie_chart.go. */
524
+
525
+ declare class PieChart implements Widget {
526
+ colors: Color[];
527
+ weights: number[];
528
+ diameter: number;
529
+ constructor(props: {
530
+ colors: Color[];
531
+ weights: number[];
532
+ diameter: number;
533
+ });
534
+ paintBounds(_b: Bounds, _frameIdx: number): Bounds;
535
+ paint(dc: DrawContext, _b: Bounds, _frameIdx: number): void;
536
+ frameCount(): number;
537
+ }
538
+
539
+ /** PolyLine — port of pixlet render/paths.go (Bresenham line enumeration). */
540
+ interface PathPoint {
541
+ x: number;
542
+ y: number;
543
+ }
544
+ declare class PolyLine {
545
+ vertices: PathPoint[];
546
+ private path;
547
+ constructor(vertices: PathPoint[]);
548
+ length(): number;
549
+ point(i: number): [number, number];
550
+ private compute;
551
+ private addLineSegment;
552
+ }
553
+
554
+ /**
555
+ * Plot — port of pixlet render/plot.go: XY line/scatter chart drawn with
556
+ * raw pixel stores along a Bresenham polyline. NaN in xLim/yLim means
557
+ * "infer from data", exactly like the Go NaN sentinels.
558
+ *
559
+ * Ported quirk: the scatter branch pokes untransformed coordinates (the Go
560
+ * code skips TransformPoint there) — keep it for parity.
561
+ */
562
+
563
+ declare const DEFAULT_PLOT_COLOR: Color;
564
+ /** Surface fill gets line color dampened by this factor. */
565
+ declare const FILL_DAMP_FACTOR = 85;
566
+ declare class Plot implements Widget {
567
+ data: [number, number][];
568
+ width: number;
569
+ height: number;
570
+ color: Color | null;
571
+ colorInverted: Color | null;
572
+ xLim: [number, number];
573
+ yLim: [number, number];
574
+ fill: boolean;
575
+ chartType: string;
576
+ fillColor: Color | null;
577
+ fillColorInverted: Color | null;
578
+ private invThreshold;
579
+ constructor(props: {
580
+ data: [number, number][];
581
+ width: number;
582
+ height: number;
583
+ color?: Color | null;
584
+ colorInverted?: Color | null;
585
+ xLim?: [number, number];
586
+ yLim?: [number, number];
587
+ fill?: boolean;
588
+ chartType?: string;
589
+ fillColor?: Color | null;
590
+ fillColorInverted?: Color | null;
591
+ });
592
+ /** Port of plot.go computeLimits. */
593
+ computeLimits(): [number, number, number, number];
594
+ /** Port of plot.go translatePoints (also computes invThreshold). */
595
+ translatePoints(): PathPoint[];
596
+ paintBounds(_b: Bounds, _frameIdx: number): Bounds;
597
+ paint(dc: DrawContext, _b: Bounds, _frameIdx: number): void;
598
+ frameCount(): number;
599
+ }
600
+
601
+ /**
602
+ * PNG decoder (pure TS + fflate inflate). Supports the formats that matter
603
+ * for pixel-art app assets: bit depths 1/2/4/8, color types gray, RGB,
604
+ * palette (incl. tRNS), gray+alpha, RGBA; filters 0–4. 16-bit channels and
605
+ * Adam7 interlacing are rejected with a clear error.
606
+ *
607
+ * Output is straight (non-premultiplied) RGBA, like Go's image.Decode
608
+ * producing NRGBA — premultiplication happens when frames are converted to
609
+ * Canvas.
610
+ */
611
+ interface DecodedImage {
612
+ width: number;
613
+ height: number;
614
+ /** Straight RGBA. */
615
+ rgba: Uint8Array;
616
+ }
617
+ declare function isPng(data: Uint8Array): boolean;
618
+ declare function decodePng(data: Uint8Array): DecodedImage;
619
+
620
+ /**
621
+ * GIF decoder (pure TS): header/LSD/GCT parsing, LZW, per-frame rects,
622
+ * local palettes, transparency, interlacing, disposal + delays. Produces
623
+ * raw frame data; frame *composition* (Go's Image.InitFromGIF quirks
624
+ * included) lives in the Image widget.
625
+ */
626
+ declare const enum GifDisposal {
627
+ None = 0,// includes "unspecified"
628
+ DoNotDispose = 1,
629
+ Background = 2,
630
+ Previous = 3
631
+ }
632
+ interface GifFrame {
633
+ x: number;
634
+ y: number;
635
+ width: number;
636
+ height: number;
637
+ /** Palette indices, width*height. */
638
+ indices: Uint8Array;
639
+ /** RGB triples. */
640
+ palette: Uint8Array;
641
+ transparentIndex: number | null;
642
+ disposal: GifDisposal;
643
+ /** Delay in 1/100s (GIF native units, like Go's gif.GIF.Delay). */
644
+ delayCS: number;
645
+ }
646
+ interface DecodedGif {
647
+ width: number;
648
+ height: number;
649
+ frames: GifFrame[];
650
+ }
651
+ declare function isGif(data: Uint8Array): boolean;
652
+ declare function decodeGif(data: Uint8Array): DecodedGif;
653
+
654
+ export { Animation, type BdfFont, Bounds, Box, Canvas, Circle, Color, Color16, Column, type CrossAlign, type Curve, DEFAULT_FONT_FACE, DEFAULT_FRAME_HEIGHT, DEFAULT_FRAME_WIDTH, DEFAULT_MAX_FRAME_COUNT, DEFAULT_ORIGIN, DEFAULT_PLOT_COLOR, type DirectionMode, DrawContext, FILL_DAMP_FACTOR, type FillMode, type Glyph, type Insets, type Keyframe, type MainAlign, Marquee, type Origin, Padding, type PathPoint, PieChart, Plot, PolyLine, type RenderResult, Root, type RoundingMode, Row, Sequence, Stack, Text, type Transform, Transformation, Vector, Widget, WrappedText, applyRounding, buildWidget, cubicBezierCurve, decodeGif, decodePng, easeIn, easeInOut, easeOut, encodePng, findKeyframes, getFont, getFontList, interpolateTransforms, isGif, isPng, lerp, linearCurve, lookupGlyph, measureString, parseBdf, parseCurve, processKeyframes, renderRoot, renderText, rescale, wordWrap };