TempleOS Desktop Docs

DLIST binary format (guest reader spec)

Edited 2026-10-27browser/host/dlist-format.md

Status: v1, written with stream 2 (M2 host half). The reference encoder is browser/host/dlist.py; the reference painter is browser/host/dlist_paint_ref.py; tests/browser/dlist_test.py decodes the hex example below. Decisions where the spec (docs/browser-architecture.md c) was ambiguous are listed at the top of dlist.py (D1 to D19).

Conventions#

  • All integers little endian. Coordinates are i32 in 1/16 CSS px, page origin (scroll 0). Band i covers 4096 units (256 CSS px): [i*4096, (i+1)*4096).
  • Colour refs are u8: 0xFF none, 0..254 index into the band colour table.
  • String refs are u16: 0xFFFF none. Strings are UTF-8, ASCII in v1.
  • Scale: device px = units * scale / 16 (scale 1 or 2).

Band payload (one DLIST message, type 0x06)#

Offset Size Field
0 2 band index (u16)
2 2 flags (u16): bit0 last band, bit1 band holds FIXED ops
4 4 band version (u32)
8 8 band hash (u64), FNV-1a 64 over bytes 16 to end
16 4 band top y (i32, units)
20 4 band bottom y (i32, units, exclusive)
24 2 n_colours (u16, 0..255)
26 2 n_strings (u16)
28 4 n_ops (u32)
32 4 x n_colours colour table: R, G, B, A bytes
then per string: 2 + len u16 length, UTF-8 bytes
then per op opcode (u8), fields in the order below

The guest reads header, colours and strings, then ops until n_ops are consumed. Any other byte count after the last op is an error. The hash lets the guest skip a band it already holds (BANDREQ/HAVE in b5).

Ops#

Field codes: i i32, I u32, Q u64, H u16, B u8, h i16, b i8. Sizes include the opcode.

Op Code Fields Size
BOX 01 x y w h i, fill B, border B, bw B, rad B, flags B 22
TEXT 02 x y i, w H (px), str H, face B, col B, deco B, flags B 17
IMAGE 03 x y w h i, id Q, fit B (0 fill, 1 contain, 2 cover, 3 none), flags B 27
CLIP 04 x y w h i 17
CLIP_POP 05 none 1
LINK 06 x y w h i, str H 19
CONTROL 07 kind B, id H, x y w h i, val H, label H, state B 25
SCROLL_BEGIN 08 sid H, x y w h i, content_h i, offset i, overflow B 28
SCROLL_END 09 none 1
RUNIMG 0A hash Q, x y w h i 25
TILE 0B id I, x y w h i, kind B (low nibble kind, high nibble alpha 0..15) 22
FIXED 0C prefix for the next op (viewport coordinates) 1
STICKY 0D min i, max i, top i; prefix for the next op 13
(XFORM) 0E reserved, never emitted
DECOR 0F x y w h i, kind B, col B 19
(STR) 10 reserved
GRAD 11 x y w h i, a B, b B, angle B, rad B 21
SHADOW 12 x y w h i, dx h, dy h, blur B, spread b, col B, rad B 25

BOX: fill and border are colour refs; border is drawn bw px wide inside the box rectangle. flags bits are reserved (0). TEXT: face bits are bold (bit0), size class (bits 1-2: 0 <= 12 px, 1 <= 16, 2 <= 24, 3 larger), mono (bit3), italic (bit4), serif (bit5). deco bits: underline 1, line-through 2, overline 4. IMAGE: flags bits 0-3 alpha 0..15 (15 opaque), bit4 placeholder (no content yet), bit5 CSS background. TILE kind: 0 svg, 1 canvas or webgl, 2 video, 4 embed. CONTROL kind: 0 text, 1 password (val is 0xFFFF, never sent), 2 checkbox, 3 radio, 4 button, 5 select, 6 textarea, 7 file, 8 range, 9 submit, 10 reset, 11 other. CONTROL state bits: 0 disabled, 1 checked, 2 readonly, 3 required. GRAD: linear two-stop from a to b; angle 0 = to top, 64 = to right, 128 = to bottom, 192 = to left. SHADOW: offsets in units, blur and spread in px.

Prefix ops: FIXED and STICKY apply to the op that follows them, and nothing else. A STICKY op paints at y + shift, where shift = clamp(scroll_y + top, min, max) - min. Paint an op only in the band that holds its shifted top. FIXED ops are in band 0 and use viewport coordinates.

Clip groups: CLIP (or SCROLL_BEGIN) opens a group, CLIP_POP (or SCROLL_END) closes it. Groups do not nest; the encoder never opens one inside another.

Worked example (hex)#

A 200 x 200 px page: white background, "Hello" in black, a link "Example" underlined in blue, and a button with the value "Go". Source: dlist_test.py decodes this block and compares it with the listing below. Each line is hex bytes, then ; and the annotation.

00 00 ; band index u16 = 0 01 00 ; flags u16 = 1 (bit0 last band) 01 00 00 00 ; band version u32 = 1 c1 45 ce 40 34 8c 86 33 ; band hash u64 (FNV-1a 64 over bytes 16..end) 00 00 00 00 ; band top y i32 = 0 (1/16 px units) 00 10 00 00 ; band bottom y i32 = 4096 04 00 ; n_colours u16 = 4 04 00 ; n_strings u16 = 4 06 00 00 00 ; n_ops u32 = 6 ff ff ff ff ; colour C0 = R G B A 00 00 00 ff ; colour C1 = R G B A 00 00 ee ff ; colour C2 = R G B A e0 e0 e0 ff ; colour C3 = R G B A 07 00 45 78 61 6d 70 6c 65 ; string S0: u16 length 7 + UTF-8 "Example" 05 00 48 65 6c 6c 6f ; string S1: u16 length 5 + UTF-8 "Hello" 14 00 68 74 74 70 73 3a 2f 2f 65 78 61 6d 70 6c 65 2e 63 6f 6d 2f ; string S2: u16 length 20 + UTF-8 "https://example.com/" 02 00 47 6f ; string S3: u16 length 2 + UTF-8 "Go" 01 00 00 00 00 00 00 00 00 80 0c 00 00 80 07 00 00 00 ff 00 00 00 ; op BOX (0x01) 0 0 3200 1920 0 255 0 0 0 02 80 00 00 00 80 00 00 00 38 00 01 00 02 01 00 00 ; op TEXT (0x02) 128 128 56 1 2 1 0 0 06 80 00 00 00 c0 00 00 00 e8 03 00 00 00 01 00 00 02 00 ; op LINK (0x06) 128 192 1000 256 2 02 80 00 00 00 c0 00 00 00 38 00 00 00 02 02 01 00 ; op TEXT (0x02) 128 192 56 0 2 2 1 0 01 40 06 00 00 60 09 00 00 00 0a 00 00 80 02 00 00 03 ff 00 00 00 ; op BOX (0x01) 1600 2400 2560 640 3 255 0 0 0 07 04 01 00 40 06 00 00 60 09 00 00 00 0a 00 00 80 02 00 00 03 00 ff ff 00 ; op CONTROL (0x07) 4 1 1600 2400 2560 640 3 65535 0

Decoded listing (the output of dlist.dump_band):

text
BAND 0 flags=1 version=1 y=0..4096 ops=6 colours=4 strings=4
  C0 #ffffff/255
  C1 #000000/255
  C2 #0000ee/255
  C3 #e0e0e0/255
  S0 Example
  S1 Hello
  S2 https://example.com/
  S3 Go
  BOX 0 0 3200 1920 0 255 0 0 0
  TEXT 128 128 56 1 2 1 0 0
  LINK 128 192 1000 256 2
  TEXT 128 192 56 0 2 2 1 0
  BOX 1600 2400 2560 640 3 255 0 0 0
  CONTROL 4 1 1600 2400 2560 640 3 65535 0

Reading order for the guest#

  1. Read the 32-byte header. Check the hash if the band is new (guest FNV-1a 64 over the bytes from offset 16 to the end).
  2. Read the colour table and the string table into arrays.
  3. Read n_ops ops. Keep a clip state (none, CLIP rect, or SCROLL rect) and the pending FIXED or STICKY prefix.
  4. Paint ops in order. Ops of bands are painted in band index order; band 0 FIXED ops last.
TempleOS Desktop Docs. Built from the Markdown sources; offline, no external requests. Back to top