灵符lingfu
L

ling-sys

↓ 0 downloads

System activity and performance monitor in the Ling Design System — dials, meshes, drums and crosshatch for CPU, GPU, memory, disk, network, board, processes and audio, with every subsystem given a voice. A LingOS app for rpi5: live board/CPU/memory/process stats from the kernel (stats-lingos.ling).

Windows · x86-64macOS · Intel x86-64Linux · x86-64LingOS · x86-64LingOS · Pi 5 ARM64Web · WASM
lingfu install ling-sys
Authorsling-lin
READMECode / FilesVersionsDependency GraphDependentsSecurityBuildsSettings

Code / Files (13)

main.ling
# ============================================================
# LINGSYS — system activity and performance monitor
# Drawn in the Ling Design System: line work on black, seven
# semantic hues, Daemon in tiles, Chesilin on rings, Consolas
# for stats when the TXT switch asks for English. Every
# subsystem is an instrument; every instrument has a voice.
#   asm BOARD · lit GPU AUDIO · bind MEM DISK · ctl CPU ·
#   call NET · fn PROC · mod ROOT
# Tabs: 1 OVERVIEW · 2 CPU · 3 GPU · 4 MEM · 5 DISK · 6 NET ·
#   7 BOARD · 8 PROC · 9 AUDIO   (keys or click; TAB cycles)
# Run from this folder:  ling run main.ling
# ============================================================

use "lds.ling"
use "stats.ling"
use "stats-lingos.ling"
use "sound.ling"

# ---------- small helpers ----------
fn clampf(x, lo, hi) {
    if x < lo { return lo }
    if x > hi { return hi }
    return x
}

fn sm(key, target, dt, rate) {
    bind v = st_get(key, target)
    bind k = clampf(dt * rate, 0.0, 1.0)
    bind v = v + (target - v) * k
    st_set(key, v)
    return v
}

fn fmtint(x) { return num_str(round(x)) }
fn fmt1(x) { return num_str(round(x * 10.0) / 10.0) }

fn fmtbytes(b) {
    if b < 1000.0 { return num_str(round(b)) + "B" }
    if b < 1000000.0 { return num_str(round(b / 1000.0)) + "K" }
    if b < 1000000000.0 {
        bind m = b / 1000000.0
        if m < 10.0 { return fmt1(m) + "M" }
        return num_str(round(m)) + "M"
    }
    bind g = b / 1000000000.0
    if g < 10.0 { return fmt1(g) + "G" }
    return num_str(round(g)) + "G"
}

fn fmtcount(b) {
    if b < 1000.0 { return num_str(round(b)) }
    if b < 1000000.0 { return num_str(round(b / 1000.0)) + "K" }
    return fmt1(b / 1000000.0) + "M"
}

fn hex2(n) {
    bind v = round(n)
    bind hi = floor(v / 16.0) % 16.0
    bind lo = v % 16.0
    bind digits = "0123456789ABCDEF"
    return str_slice(digits, hi, 1) + str_slice(digits, lo, 1)
}

# str_contains is not a real builtin, so test membership by scanning
fn char_ok(ch) {
    bind ok = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.- "
    bind i = 0
    while i < 40 {
        if str_slice(ok, i, 1) == ch { return 1 }
        bind i = i + 1
    }
    return 0
}

fn sanitize(s, maxn) {
    bind up = str_upper(s)
    bind out = ""
    bind n = len(up)
    if n > maxn { bind n = maxn }
    bind i = 0
    while i < n {
        if char_ok(str_slice(up, i, 1)) == 1 {
            bind out = out + str_slice(up, i, 1)
        } else {
            bind out = out + " "
        }
        bind i = i + 1
    }
    return str_trim(out)
}

fn last_tokens(s, n) {
    bind parts = str_split(str_trim(s), " ")
    bind c = len(parts)
    bind from = c - n
    if from < 0 { bind from = 0 }
    bind out = ""
    bind i = from
    while i < c {
        if len(out) > 0 { bind out = out + " " }
        bind out = out + list_get(parts, i)
        bind i = i + 1
    }
    return out
}

fn fmtup(sec) {
    bind d = floor(sec / 86400.0)
    bind h = floor((sec % 86400.0) / 3600.0)
    bind m = floor((sec % 3600.0) / 60.0)
    if d > 0.0 { return num_str(d) + "D " + num_str(h) + "H " + num_str(m) + "M" }
    if h > 0.0 { return num_str(h) + "H " + num_str(m) + "M" }
    return num_str(m) + "M"
}

fn hitrect(mx, my, x, y, w, h) {
    if mx < x { return 0 }
    if my < y { return 0 }
    if mx > x + w { return 0 }
    if my > y + h { return 0 }
    return 1
}

fn lvl_log(x, lo, span) {
    bind v = (log10(1.0 + x) - lo) / span * 4.0
    return clampf(v, 0.0, 4.0)
}

# ---------- title, status ----------
fn draw_titleplate(x, y, aa) {
    word("LINGSYS", x, y, 28.0, "mod", aa)
    bind tx = x + word_w("LINGSYS", 28.0) + 24.0
    stext("SYSTEM ACTIVITY MONITOR . REV 2030.1 . UP " + fmtup(st_get("s_uptime", 0.0)), tx, y + 2.0, 12.0, "ink", 0.8 * aa)
    bind host = sanitize(st_get("i_host", "HOST"), 12)
    bind cpun = sanitize(last_tokens(st_get("i_cpu_name", "CPU"), 1), 12)
    bind gpun = sanitize(last_tokens(st_get("i_gpu_name", "GPU"), 2), 12)
    bind thr = to_number(st_get("i_cpu_threads", "0"))
    stext(host + " . " + cpun + " . " + gpun + " . " + fmtint(thr) + " THREADS", tx, y + 4.0 + tsize(17.0), 12.0, "ink", 0.7 * aa)
    return 0
}

# ---------- history mesh ----------
fn draw_histmesh(x, y, cols, cw, chh, name, key, vmax, caption, aa) {
    bind c = pcol(key)
    bind cink = pcol("ink")
    bind l = st_get("h_" + name, list_new())
    bind n = len(l)
    bind i = 0.0
    while i < cols {
        bind idx = n - cols + i
        bind cx0 = x + i * cw
        bind filled = 0.0
        if idx >= 0.0 {
            bind v = clampf(list_get(l, idx) / vmax, 0.0, 0.999)
            if v > 0.02 {
                bind filled = 1.0
                bind den = 1.0 + floor(v * 4.0)
                bind sp = chh * 0.22 * den_mul(den)
                if sp < 2.6 { bind sp = 2.6 }
                px_outline(cx0 + 1.0, y + 1.0, cw - 2.0, chh - 2.0, c, 0.4 * aa)
                if (i % 2.0) == 0.0 {
                    px_hatch(cx0 + 2.0, y + 2.0, cw - 4.0, chh - 4.0, c, 0.0, sp, 0.55 * aa)
                    px_hatch(cx0 + 2.0, y + 2.0, cw - 4.0, chh - 4.0, c, 90.0, sp, 0.55 * aa)
                } else {
                    px_hatch(cx0 + 2.0, y + 2.0, cw - 4.0, chh - 4.0, c, 45.0, sp, 0.55 * aa)
                    px_hatch(cx0 + 2.0, y + 2.0, cw - 4.0, chh - 4.0, c, 315.0, sp, 0.55 * aa)
                }
            }
        }
        if filled == 0.0 {
            px_outline(cx0 + 1.0, y + 1.0, cw - 2.0, chh - 2.0, cink, 0.18 * aa)
        }
        bind i = i + 1
    }
    stext(caption, x, y + chh + 8.0, 13.0, key, 0.85 * aa)
    return 0
}

# ---------- CPU dial: nested counter-rotating rings ----------
fn draw_cpu(cx, cy, r, t, dt, aa) {
    bind cpu = st_get("d_cpu", 0.0)
    bind mo = st_get("motion", 1.0)
    if st_get("p_spin", 1.0) < 1.0 { bind mo = 0.0 }
    dialbezel(cx, cy, r, "ctl", aa)
    bind bt = tsize(20.0)
    bind txt = "CENTRAL PROCESSOR . " + fmtint(st_get("s_cpu_count", 0.0)) + " CORES . "
    bind mark = floor(t * 7.0) % len(txt)
    ringtext(cx, cy, r - 13.0 - bt, r - 13.0, txt, t * 0.074 * mo, 6.2831853, "ctl", mark, aa)
    # a counter-turning segment ring: speed and density follow the load
    bind s1 = r - 17.0 - bt
    bind s0 = s1 - tsize(9.0)
    bind segden = 1.0 + floor(clampf(cpu, 0.0, 99.0) / 25.0)
    segring(cx, cy, s0, s1, 28.0, 0.0 - t * (0.1 + cpu * 0.004) * mo, "ctl", segden, 0.8 * aa)
    bind n = st_get("s_cpu_count", 0.0)
    if n > 0.0 {
        bind r0 = r * 0.42
        bind r1 = r * 0.63
        bind sw = 6.2831853 / n
        bind c = pcol("ctl")
        bind i = 0.0
        while i < n {
            bind load = st_get("s_core" + num_str(i), 0.0)
            bind p0 = i * sw
            px_line(ckx(cx, r0, p0), cky(cy, r0, p0), ckx(cx, r1, p0), cky(cy, r1, p0), c, 0.35 * aa)
            bind den = 1.0 + floor(clampf(load, 0.0, 99.0) / 25.0)
            bind sp = (r1 - r0) * 0.16 * den_mul(den)
            if sp < 3.5 { bind sp = 3.5 }
            bind ang = 45.0
            if (i % 2.0) == 1.0 { bind ang = 30.0 }
            if load > 1.5 {
                hatch_sector(cx, cy, r0 + 2.0, r1 - 2.0, p0 + sw * 0.08, sw * 0.84, c, ang, sp, (0.4 + load * 0.005) * aa)
            }
            bind i = i + 1
        }
        setcola(c, 0.55 * aa)
        arcpx(cx, cy, r0, 0.0, 6.2831853)
        arcpx(cx, cy, r1, 0.0, 6.2831853)
    }
    # a quick inner ring, turning with the clock: small rings spin faster
    segring(cx, cy, r * 0.325, r * 0.385, 12.0, t * (0.25 + cpu * 0.01) * mo, "ctl", 2.0, 0.7 * aa)
    bind hubr = r * 0.28
    setcola(pcol("ctl"), 0.8 * aa)
    arcpx(cx, cy, hubr, 0.0, 6.2831853)
    bind phi = sm("ph_cpu", cpu / 100.0 * 6.2831853, dt, 4.0)
    hand(cx, cy, r * 0.61, phi, 7.0, "ctl", aa)
    if st_get("ev_tick", 0.0) > 0.0 {
        px_disc(cx, cy, 4.5, pcol("ctl"), aa)
        st_set("ev_tick", st_get("ev_tick", 0.0) - 0.34)
    }
    wordc(fmtint(cpu), cx, cy - 34.0, 22.0, "ctl", aa)
    stextc("PCT LOAD", cx, cy + 10.0, 12.0, "ctl", 0.8 * aa)
    bind base = to_number(st_get("i_cpu_mhz", "0")) * 0.001
    bind perf = st_get("s_cpu_perf", 0.0)
    bind l2y = cy + 10.0 + tsize(16.0)
    if perf > 1.0 {
        stextc(fmt1(base * perf / 100.0) + " GHZ NOW", cx, l2y, 12.0, "ctl", 0.65 * aa)
    } else {
        stextc(fmt1(base) + " GHZ BASE", cx, l2y, 12.0, "ctl", 0.65 * aa)
    }
    wordc("CPU", cx, cy + r + 12.0, 15.0, "ctl", aa)
    return 0
}

# ---------- GPU dial: nested counter-rotating rings ----------
fn draw_gpu(cx, cy, r, t, dt, aa) {
    bind gpu = st_get("d_gpu", 0.0)
    bind vu = st_get("s_gpu_mem_used", 0.0)
    bind vt = st_get("s_gpu_mem_total", 1.0)
    bind vfrac = clampf(vu / vt, 0.0, 1.0)
    bind mo = st_get("motion", 1.0)
    if st_get("p_spin", 1.0) < 1.0 { bind mo = 0.0 }
    dialbezel(cx, cy, r, "lit", aa)
    bind bt = tsize(18.0)
    bind txt = "GRAPHICS . VRAM . SHADERS . "
    bind mark = floor(t * 7.0 + 3.0) % len(txt)
    ringtext(cx, cy, r - 13.0 - bt, r - 13.0, txt, 0.0 - t * 0.09 * mo, 6.2831853, "lit", mark, aa)
    bind s1 = r - 17.0 - bt
    bind s0 = s1 - tsize(8.0)
    segring(cx, cy, s0, s1, 24.0, t * (0.1 + gpu * 0.005) * mo, "lit", 1.0 + floor(clampf(gpu, 0.0, 99.0) / 25.0), 0.8 * aa)
    bind r0 = r * 0.46
    bind r1 = r * 0.62
    bind c = pcol("lit")
    if vfrac > 0.01 {
        hatch_sector(cx, cy, r0, r1, 0.0, vfrac * 6.2831853, c, 45.0, 5.0, 0.55 * aa)
        hatch_sector(cx, cy, r0, r1, 0.0, vfrac * 6.2831853, c, 315.0, 5.0, 0.55 * aa)
    }
    setcola(c, 0.55 * aa)
    arcpx(cx, cy, r0, 0.0, 6.2831853)
    arcpx(cx, cy, r1, 0.0, 6.2831853)
    segring(cx, cy, r * 0.33, r * 0.39, 10.0, 0.0 - t * (0.3 + gpu * 0.012) * mo, "lit", 2.0, 0.7 * aa)
    setcola(c, 0.8 * aa)
    arcpx(cx, cy, r * 0.28, 0.0, 6.2831853)
    bind phi = sm("ph_gpu", gpu / 100.0 * 6.2831853, dt, 4.0)
    hand(cx, cy, r * 0.6, phi, 6.0, "lit", aa)
    wordc(fmtint(gpu), cx, cy - 32.0, 20.0, "lit", aa)
    stextc("PCT . " + fmtint(st_get("s_gpu_temp", 0.0)) + " C", cx, cy + 10.0, 12.0, "lit", 0.8 * aa)
    stextc("FAN " + fmtint(st_get("s_gpu_fan", 0.0)), cx, cy + 10.0 + tsize(16.0), 12.0, "lit", 0.65 * aa)
    wordc("GPU", cx, cy + r + 12.0, 15.0, "lit", aa)
    stextc("VRAM " + fmt1(vu / 1024.0) + "G OF " + fmtint(vt / 1024.0) + "G", cx, cy + r + 14.0 + tsize(20.0), 12.0, "lit", 0.75 * aa)
    return 0
}

# ---------- NET dial (overview): nested counter-rotating rings ----------
fn draw_net(cx, cy, r, t, dt, aa) {
    bind rx = st_get("s_net_rx", 0.0)
    bind tx = st_get("s_net_tx", 0.0)
    bind mo = st_get("motion", 1.0)
    if st_get("p_spin", 1.0) < 1.0 { bind mo = 0.0 }
    dialbezel(cx, cy, r, "call", aa)
    bind bt = tsize(17.0)
    bind txt = "NETWORK . IN AND OUT . "
    bind mark = floor(t * 7.0 + 6.0) % len(txt)
    ringtext(cx, cy, r - 12.0 - bt, r - 12.0, txt, t * 0.1 * mo, 6.2831853, "call", mark, aa)
    bind s1 = r - 16.0 - bt
    bind s0 = s1 - tsize(7.0)
    bind flow = lvl_log(rx + tx, 0.0, 9.0)
    segring(cx, cy, s0, s1, 20.0, 0.0 - t * (0.12 + flow * 0.1) * mo, "call", 1.0 + floor(flow), 0.8 * aa)
    bind prx = sm("ph_rx", lvl_log(rx, 0.0, 9.0) / 4.0 * 6.2831853, dt, 4.0)
    bind ptx = sm("ph_tx", lvl_log(tx, 0.0, 9.0) / 4.0 * 6.2831853, dt, 4.0)
    hand(cx, cy, r * 0.56, prx, 6.0, "call", aa)
    hand(cx, cy, r * 0.4, ptx, 5.0, "call", 0.7 * aa)
    setcola(pcol("call"), 0.8 * aa)
    arcpx(cx, cy, r * 0.3, 0.0, 6.2831853)
    stextc("RX " + fmtbytes(rx), cx, cy - 8.0 - tsize(16.0), 12.0, "call", aa)
    stextc("TX " + fmtbytes(tx), cx, cy - 4.0, 12.0, "call", 0.85 * aa)
    wordc("NET", cx, cy + r + 12.0, 15.0, "call", aa)
    return 0
}

# ---------- generic rate dial, log scale, nested rings ----------
fn logdial(cx, cy, r, key, txt, val, id, dirn, t, dt, aa) {
    bind mo = st_get("motion", 1.0)
    if st_get("p_spin", 1.0) < 1.0 { bind mo = 0.0 }
    dialbezel(cx, cy, r, key, aa)
    bind bt = tsize(18.0)
    bind mark = floor(t * 7.0) % len(txt)
    ringtext(cx, cy, r - 13.0 - bt, r - 13.0, txt, dirn * t * 0.085 * mo, 6.2831853, key, mark, aa)
    bind s1 = r - 17.0 - bt
    bind s0 = s1 - tsize(8.0)
    bind lv = lvl_log(val, 0.0, 9.0)
    segring(cx, cy, s0, s1, 22.0, 0.0 - dirn * t * (0.1 + lv * 0.09) * mo, key, 1.0 + floor(lv), 0.8 * aa)
    segring(cx, cy, r * 0.36, r * 0.42, 12.0, dirn * t * (0.26 + lv * 0.12) * mo, key, 2.0, 0.7 * aa)
    bind phi = sm("ph_" + id, clampf(log10(1.0 + val) / 9.0, 0.0, 1.0) * 6.2831853, dt, 4.0)
    hand(cx, cy, r * 0.58, phi, 6.0, key, aa)
    setcola(pcol(key), 0.8 * aa)
    arcpx(cx, cy, r * 0.31, 0.0, 6.2831853)
    stextc(fmtbytes(val), cx, cy - 6.0 - tsize(16.0), 14.0, key, aa)
    stextc("PER S", cx, cy + 6.0, 11.0, key, 0.7 * aa)
    return 0
}

# ---------- plain bounded dial (percent), nested rings ----------
fn pctdial(cx, cy, r, key, txt, val, id, t, dt, aa) {
    bind mo = st_get("motion", 1.0)
    if st_get("p_spin", 1.0) < 1.0 { bind mo = 0.0 }
    dialbezel(cx, cy, r, key, aa)
    bind bt = tsize(18.0)
    bind mark = floor(t * 7.0) % len(txt)
    ringtext(cx, cy, r - 13.0 - bt, r - 13.0, txt, t * 0.09 * mo, 6.2831853, key, mark, aa)
    bind s1 = r - 17.0 - bt
    bind s0 = s1 - tsize(8.0)
    segring(cx, cy, s0, s1, 22.0, 0.0 - t * (0.1 + val * 0.004) * mo, key, 1.0 + floor(clampf(val, 0.0, 99.0) / 25.0), 0.8 * aa)
    segring(cx, cy, r * 0.36, r * 0.42, 12.0, t * (0.26 + val * 0.01) * mo, key, 2.0, 0.7 * aa)
    bind phi = sm("ph_" + id, clampf(val, 0.0, 100.0) / 100.0 * 6.2831853, dt, 14.0)
    hand(cx, cy, r * 0.58, phi, 6.0, key, aa)
    setcola(pcol(key), 0.8 * aa)
    arcpx(cx, cy, r * 0.31, 0.0, 6.2831853)
    stextc(fmtint(val), cx, cy - 6.0 - tsize(16.0), 16.0, key, aa)
    stextc("PCT", cx, cy + 6.0, 11.0, key, 0.7 * aa)
    return 0
}

# VU ballistics: fast attack, slow release
fn vumeter(key, tgt, dt) {
    bind cur = st_get(key, 0.0)
    if tgt > cur {
        bind cur = cur + (tgt - cur) * clampf(dt * 16.0, 0.0, 1.0)
    } else {
        bind cur = cur + (tgt - cur) * clampf(dt * 3.0, 0.0, 1.0)
    }
    st_set(key, cur)
    return cur
}

# peak (percent of full scale) -> 0..1 along a 60 dB scale, as a VU meter reads
fn db_frac(pct) {
    bind lin = pct / 100.0
    if lin < 0.001 { return 0.0 }
    return clampf((20.0 * log10(lin) + 60.0) / 60.0, 0.0, 1.0)
}

# ---------- VU dial: a 270 degree dB scale, hatched level band, peak hold ----------
# state: 1 live · 0 off · -1 refused (the mic when Windows blocks it)
fn vudial(cx, cy, r, key, txt, peak, id, state, t, dt, aa) {
    bind mo = st_get("motion", 1.0)
    if st_get("p_spin", 1.0) < 1.0 { bind mo = 0.0 }
    bind c = pcol(key)
    dialbezel(cx, cy, r, key, aa)
    bind bt = tsize(18.0)
    bind mark = floor(t * 7.0) % len(txt)
    ringtext(cx, cy, r - 13.0 - bt, r - 13.0, txt, t * 0.09 * mo, 6.2831853, key, mark, aa)
    bind s1 = r - 17.0 - bt
    bind s0 = s1 - tsize(8.0)
    bind f = vumeter("vf_" + id, db_frac(peak), dt)
    segring(cx, cy, s0, s1, 22.0, 0.0 - t * (0.1 + f * 0.5) * mo, key, 1.0 + floor(f * 3.9), 0.8 * aa)
    # the scale: 225 degrees (lower left) clockwise through the top to 135
    bind a0 = 3.9269908
    bind sw = 4.712389
    bind r0 = r * 0.40
    bind r1 = r * 0.58
    setcola(c, 0.6 * aa)
    arc_clock(cx, cy, r0, a0, sw)
    arc_clock(cx, cy, r1, a0, sw)
    px_line(ckx(cx, r0, a0), cky(cy, r0, a0), ckx(cx, r1, a0), cky(cy, r1, a0), c, 0.7 * aa)
    px_line(ckx(cx, r0, a0 + sw), cky(cy, r0, a0 + sw), ckx(cx, r1, a0 + sw), cky(cy, r1, a0 + sw), c, 0.7 * aa)
    # the level band fills with crosshatch as the signal rises
    if f > 0.01 {
        hatch_sector(cx, cy, r0 + 2.0, r1 - 2.0, a0, f * sw, c, 45.0, 4.0, 0.8 * aa)
        hatch_sector(cx, cy, r0 + 2.0, r1 - 2.0, a0, f * sw, c, 315.0, 4.0, 0.6 * aa)
    }
    # dB marks outside the band, labelled at the round numbers
    bind k = 0
    while k < 7 {
        bind db = 0.0 - 60.0
        if k == 1 { bind db = 0.0 - 40.0 }
        if k == 2 { bind db = 0.0 - 20.0 }
        if k == 3 { bind db = 0.0 - 10.0 }
        if k == 4 { bind db = 0.0 - 6.0 }
        if k == 5 { bind db = 0.0 - 3.0 }
        if k == 6 { bind db = 0.0 }
        bind ph = a0 + (db + 60.0) / 60.0 * sw
        bind tl = 7.0
        if db == 0.0 - 20.0 { bind tl = 11.0 }
        if db == 0.0 { bind tl = 11.0 }
        px_line(ckx(cx, r1 + 2.0, ph), cky(cy, r1 + 2.0, ph), ckx(cx, r1 + 2.0 + tl, ph), cky(cy, r1 + 2.0 + tl, ph), c, 0.9 * aa)
        if k == 0 { stextc("-60", ckx(cx, r1 + tsize(22.0), ph), cky(cy, r1 + tsize(22.0), ph) - tsize(5.0), 9.0, key, 0.8 * aa) }
        if k == 2 { stextc("-20", ckx(cx, r1 + tsize(22.0), ph), cky(cy, r1 + tsize(22.0), ph) - tsize(5.0), 9.0, key, 0.8 * aa) }
        if k == 6 { stextc("0", ckx(cx, r1 + tsize(18.0), ph), cky(cy, r1 + tsize(18.0), ph) - tsize(5.0), 9.0, key, 0.8 * aa) }
        bind k = k + 1
    }
    # the peak-hold needle falls slowly behind the level
    bind pk = st_get("pk_" + id, 0.0) - dt * 0.25
    if f > pk { bind pk = f }
    st_set("pk_" + id, pk)
    bind pph = a0 + pk * sw
    px_line(ckx(cx, r0 - 5.0, pph), cky(cy, r0 - 5.0, pph), ckx(cx, r1 + 5.0, pph), cky(cy, r1 + 5.0, pph), c, aa)
    hand(cx, cy, r * 0.5, a0 + f * sw, 5.0, key, aa)
    setcola(c, 0.8 * aa)
    arcpx(cx, cy, r * 0.17, 0.0, 6.2831853)
    # numeric readout in dB, or why there is none
    bind lin = peak / 100.0
    bind lab = "-INF"
    if lin >= 0.001 { bind lab = fmtint(20.0 * log10(lin)) }
    if state < 0.0 {
        stextc("NO ACCESS", cx, cy + r * 0.3, 11.0, key, 0.9 * aa)
    } else {
        if state == 0.0 {
            stextc("OFF", cx, cy + r * 0.3, 11.0, key, 0.9 * aa)
        } else {
            stextc(lab + " DB", cx, cy + r * 0.3, 12.0, key, aa)
        }
    }
    return 0
}

# ---------- DISK bands (overview) ----------
fn draw_disk(x, y, w, h, t, aa) {
    framebox(x, y, w, h, "DISK", "bind", aa)
    bind c = pcol("bind")
    bind bx = x + 86.0
    bind bw = w - 170.0
    bind ry = y + 24.0
    bind wy = y + h - 40.0
    bind rlev = lvl_log(st_get("s_disk_read", 0.0), 3.0, 6.5)
    bind wlev = lvl_log(st_get("s_disk_write", 0.0), 3.0, 6.5)
    stext("READ", x + 18.0, ry, 12.0, "bind", 0.85 * aa)
    stext("WRIT", x + 18.0, wy, 12.0, "bind", 0.85 * aa)
    px_outline(bx, ry - 2.0, bw, 18.0, c, 0.55 * aa)
    px_outline(bx, wy - 2.0, bw, 18.0, c, 0.55 * aa)
    if rlev > 0.1 {
        bind den = 1.0 + floor(clampf(rlev, 0.0, 3.9))
        px_hatch(bx + 2.0, ry, bw * clampf(rlev / 4.0, 0.06, 1.0) - 4.0, 14.0, c, 45.0, 3.4 * den_mul(den), 0.75 * aa)
    }
    if wlev > 0.1 {
        bind den = 1.0 + floor(clampf(wlev, 0.0, 3.9))
        px_hatch(bx + 2.0, wy, bw * clampf(wlev / 4.0, 0.06, 1.0) - 4.0, 14.0, c, 30.0, 3.4 * den_mul(den), 0.75 * aa)
    }
    stextr(fmtbytes(st_get("s_disk_read", 0.0)), x + w - 14.0, ry, 12.0, "bind", 0.9 * aa)
    stextr(fmtbytes(st_get("s_disk_write", 0.0)), x + w - 14.0, wy, 12.0, "bind", 0.9 * aa)
    stextc("BUSY " + fmtint(st_get("s_disk_busy", 0.0)) + " PCT", x + w * 0.5, y + h - 21.0, 11.0, "bind", 0.65 * aa)
    return 0
}

# ---------- MEM grid mesh ----------
fn draw_memgrid(x, y, cols, rows, cell, t, aa) {
    bind mt = st_get("s_mem_total", 1.0)
    bind mu = st_get("s_mem_used", 0.0)
    bind frac = clampf(mu / mt, 0.0, 1.0)
    bind c = pcol("bind")
    bind cink = pcol("ink")
    bind total = cols * rows
    bind used = round(frac * total)
    bind gx = x + 30.0
    bind rowgb = mt / 1024.0 / rows
    bind rr = 0.0
    while rr < rows {
        tile(hex2(rr * rowgb), x - 8.0, y + rr * cell + cell * 0.5 - 10.0, 15.0, "bind", 0.65 * aa)
        bind cc = 0.0
        while cc < cols {
            bind idx = rr * cols + cc
            bind cx0 = gx + cc * cell
            bind cy0 = y + rr * cell
            if idx < used {
                px_outline(cx0 + 1.0, cy0 + 1.0, cell - 2.0, cell - 2.0, c, 0.5 * aa)
                if st_get("p_hatch", 1.0) > 0.0 {
                    bind sp = cell * 0.24
                    if sp < 4.0 { bind sp = 4.0 }
                    if (rr + cc) % 2.0 == 0.0 {
                        px_hatch(cx0 + 2.0, cy0 + 2.0, cell - 4.0, cell - 4.0, c, 0.0, sp, 0.55 * aa)
                        px_hatch(cx0 + 2.0, cy0 + 2.0, cell - 4.0, cell - 4.0, c, 90.0, sp, 0.55 * aa)
                    } else {
                        px_hatch(cx0 + 2.0, cy0 + 2.0, cell - 4.0, cell - 4.0, c, 45.0, sp, 0.55 * aa)
                        px_hatch(cx0 + 2.0, cy0 + 2.0, cell - 4.0, cell - 4.0, c, 315.0, sp, 0.55 * aa)
                    }
                }
            } else {
                px_outline(cx0 + 1.0, cy0 + 1.0, cell - 2.0, cell - 2.0, cink, 0.2 * aa)
            }
            if idx == used {
                bind blink = 0.45 + 0.4 * sin(t * 5.0)
                px_outline(cx0 + 1.0, cy0 + 1.0, cell - 2.0, cell - 2.0, c, blink * aa)
            }
            bind cc = cc + 1.0
        }
        bind rr = rr + 1.0
    }
    word("MEM", x - 8.0, y + rows * cell + 12.0, 15.0, "bind", aa)
    stext(fmt1(mu / 1024.0) + "G OF " + fmtint(mt / 1024.0) + "G . " + fmtint(frac * 100.0) + " PCT", x + 76.0, y + rows * cell + 16.0, 13.0, "bind", 0.85 * aa)
    return 0
}

# ---------- the mainboard ----------
fn board_key(i) {
    if i == 0.0 { return "asm" }
    if i == 1.0 { return "lit" }
    if i == 2.0 { return "bind" }
    if i == 3.0 { return "ctl" }
    if i == 4.0 { return "call" }
    return "fn"
}

fn board_label(i) {
    if i == 0.0 { return "BOARD" }
    if i == 1.0 { return "GPU" }
    if i == 2.0 { return "MEM" }
    if i == 3.0 { return "CPU" }
    if i == 4.0 { return "NET" }
    return "PROC"
}

fn board_level(i) {
    if i == 0.0 { return clampf((log10(1.0 + st_get("s_cswitch", 0.0)) - 3.0) * 1.3, 0.0, 4.0) }
    if i == 1.0 { return st_get("d_gpu", 0.0) / 25.0 }
    if i == 2.0 { return st_get("d_mem", 0.0) / 25.0 }
    if i == 3.0 { return st_get("d_cpu", 0.0) / 25.0 }
    if i == 4.0 { return lvl_log(st_get("s_net_rx", 0.0) + st_get("s_net_tx", 0.0), 2.0, 1.75) }
    return clampf((log10(1.0 + st_get("s_threads", 0.0)) - 2.0) * 2.0, 0.0, 4.0)
}

fn draw_board(cx, cy, rr, t, dt, aa) {
    bind showpk = st_get("p_packets", 1.0)
    bind labels = st_get("p_labels", 1.0)
    bind hubk = sm("kick_mod", st_get("kick_mod_t", 0.0), dt, 10.0)
    st_set("kick_mod_t", st_get("kick_mod_t", 0.0) * exp(0.0 - dt * 4.0))
    bind i = 0.0
    while i < 6.0 {
        bind key = board_key(i)
        bind phi = i * 1.0471976
        bind lv = board_level(i)
        bind kick = st_get("kick_" + key, 0.0) * exp(0.0 - dt * 4.0)
        st_set("kick_" + key, kick)
        bind nr = rr + kick * 6.0
        bind nx = ckx(cx, nr, phi)
        bind ny = cky(cy, nr, phi)
        bind ex0 = ckx(cx, 34.0, phi)
        bind ey0 = cky(cy, 34.0, phi)
        bind ex1 = ckx(cx, nr - 26.0, phi)
        bind ey1 = cky(cy, nr - 26.0, phi)
        connector(ex1, ey1, ex0, ey0, key, 1, 0.7 * aa)
        bind lx0 = ex1 + (ey1 - ey0) * 0.055
        bind ly0 = ey1 - (ex1 - ex0) * 0.055
        bind lx1 = ex0 + (ey1 - ey0) * 0.055
        bind ly1 = ey0 - (ex1 - ex0) * 0.055
        connector(lx1, ly1, lx0, ly0, key, 0, 0.45 * aa)
        if showpk > 0.0 {
            bind nin = ceil(clampf(lv, 0.0, 4.0))
            bind ev = packets("in" + key, ex1, ey1, ex0, ey0, key, nin, t, 0.9 * aa)
            if ev > 0.0 {
                st_set("kick_mod_t", clampf(st_get("kick_mod_t", 0.0) + ev * 0.5, 0.0, 1.6))
                snd_packet(i)
            }
            bind nout = ceil(clampf(lv * 0.5, 0.0, 2.0))
            bind ev2 = packets("out" + key, lx1, ly1, lx0, ly0, key, nout, t, 0.7 * aa)
            if ev2 > 0.0 {
                st_set("kick_" + key, clampf(kick + ev2 * 0.5, 0.0, 1.6))
            }
        }
        node(key, nx, ny, 22.0, 1.0 + clampf(lv, 0.0, 3.0), aa)
        if labels > 0.0 {
            stextc(board_label(i), nx, ny + 32.0, 13.0, key, 0.9 * aa)
        }
        bind i = i + 1
    }
    bind hr = 30.0 + hubk * 3.0
    node("mod", cx, cy, hr, 2.0, aa)
    bind fk = st_get("fcjk", 0.0 - 1.0)
    if fk >= 0.0 {
        bind gpx = 34.0
        bind w = font_width(fk, gpx, "灵")
        setcola(pcol("mod"), aa)
        font_text(fk, cx - w * 0.5, cy - gpx * 0.5, gpx, "灵")
    } else {
        wordc("LING", cx, cy - 7.0, 11.0, "mod", aa)
    }
    if labels > 0.0 {
        bind hname = sanitize(st_get("i_host", "ROOT"), 10)
        stextc(hname, cx, cy + 46.0, 13.0, "mod", 0.9 * aa)
    }
    return 0
}

# ---------- process drum ----------
fn draw_drum(cx, ytop, r, rowsmax, gsize0, t, aa) {
    bind gsize = tsize(gsize0)
    bind cink = pcol("ink")
    bind nproc = st_get("s_proc_n", 0.0)
    if nproc > rowsmax { bind nproc = rowsmax }
    bind rowh = gsize + 8.0
    bind fcd = st_get("fc", 1.0)
    bind voffc = st_get("voff_c", 0.25)
    if st_get("p_txt", 1.0) >= 2.0 && st_get("fe", 0.0) >= 0.0 {
        bind fcd = st_get("fe", 1.0)
        bind voffc = st_get("voff_e", 0.45)
    }
    bind cfn = pcol("fn")
    bind ybot = ytop + nproc * rowh
    if nproc < 1.0 {
        stext("NO PROCESS DATA YET", cx - 90.0, ytop + 4.0, 13.0, "ink", 0.5 * aa)
        return 0
    }
    px_hatch(cx - r, ytop - 9.0, r * 2.0, 7.0, cink, 55.0, 6.0, 0.35 * aa)
    px_hatch(cx - r, ybot + 2.0, r * 2.0, 7.0, cink, 125.0, 6.0, 0.35 * aa)
    thick(cx - r - 5.0, ytop - 9.0, cx - r - 5.0, ybot + 9.0, cink, 0.7 * aa)
    thick(cx + r + 5.0, ytop - 9.0, cx + r + 5.0, ybot + 9.0, cink, 0.7 * aa)
    bind i = 0.0
    while i < nproc {
        bind rec = st_get("s_proc" + num_str(i), "")
        bind parts = str_split(rec, "|")
        if len(parts) >= 3 {
            bind pname = sanitize(list_get(parts, 0), 15)
            bind pcpu = to_number(list_get(parts, 1))
            bind pmem = to_number(list_get(parts, 2))
            bind rowy = ytop + i * rowh
            px_line(cx - r, rowy + rowh - 1.0, cx + r, rowy + rowh - 1.0, cink, 0.25 * aa)
            bind txt = pname + " " + fmt1(pcpu) + " PCT " + fmtbytes(pmem * 1048576.0)
            bind dir = 1.0
            if (i % 2.0) == 1.0 { bind dir = 0.0 - 1.0 }
            bind sp = (0.10 + pcpu * 0.012) * st_get("motion", 1.0) * dir
            bind turn = t * sp
            bind cellw = 6.2831853 / 42.0
            bind n = len(txt)
            bind j = 0.0
            while j < n {
                bind th = turn + j * cellw
                bind rel = th % 6.2831853
                if rel < 0.0 { bind rel = rel + 6.2831853 }
                if rel > 3.14159265 { bind rel = rel - 6.2831853 }
                bind cs = cos(rel)
                if cs > 0.15 {
                    bind ch = str_slice(txt, j, 1)
                    if ch != " " {
                        bind gs = gsize * (0.4 + 0.6 * cs)
                        bind w = font_width(fcd, gs, ch)
                        bind gx = cx + r * 0.94 * sin(rel) - w * 0.5
                        bind gy = rowy + rowh * 0.5 - gs * voffc
                        bind br = 0.3 + 0.7 * cs
                        setcola(cfn, br * aa)
                        font_text(fcd, gx, gy, gs, ch)
                        font_text(fcd, gx + 0.55, gy, gs, ch)
                    }
                }
                bind j = j + 1
            }
        }
        bind i = i + 1
    }
    stextc("PROC DRUM . TOP OF " + fmtint(st_get("s_procs", 0.0)), cx, ybot + 14.0, 12.0, "fn", 0.8 * aa)
    return 0
}

# ---------- legend ----------
fn draw_legend(x, y, aa) {
    bind i = 0.0
    bind xx = x
    while i < 6.0 {
        bind key = board_key(i)
        node(key, xx + 8.0, y + 7.0, 7.0, 2.0, 0.9 * aa)
        bind lab = board_label(i)
        stext(lab, xx + 21.0, y + 1.0, 12.0, key, 0.9 * aa)
        bind xx = xx + 32.0 + stext_w(lab, 12.0)
        bind i = i + 1
    }
    node("mod", xx + 8.0, y + 7.0, 7.0, 2.0, 0.9 * aa)
    stext("ROOT", xx + 21.0, y + 1.0, 12.0, "mod", 0.9 * aa)
    return 0
}

# ---------- tabs ----------
fn tab_name(i) {
    if i == 0.0 { return "OVERVIEW" }
    if i == 1.0 { return "CPU" }
    if i == 2.0 { return "GPU" }
    if i == 3.0 { return "MEM" }
    if i == 4.0 { return "DISK" }
    if i == 5.0 { return "NET" }
    if i == 6.0 { return "BOARD" }
    if i == 7.0 { return "PROC" }
    return "AUDIO"
}

fn tab_hue(i) {
    if i == 1.0 { return "ctl" }
    if i == 2.0 { return "lit" }
    if i == 3.0 { return "bind" }
    if i == 4.0 { return "bind" }
    if i == 5.0 { return "call" }
    if i == 6.0 { return "asm" }
    if i == 7.0 { return "fn" }
    if i == 8.0 { return "lit" }
    return "mod"
}

fn draw_tabs(x, y, mx, my, clicked, aa) {
    bind tab = st_get("tab", 0.0)
    bind th = tsize(14.0) + 12.0
    bind i = 0.0
    bind xx = x
    while i < 9.0 {
        bind name = tab_name(i)
        bind key = tab_hue(i)
        bind w = stext_w(name, 14.0) + 20.0
        if tab == i {
            px_outline(xx, y - 6.0, w, th, pcol(key), 0.95 * aa)
            px_outline(xx + 1.0, y - 5.0, w - 2.0, th - 2.0, pcol(key), 0.5 * aa)
            px_hatch(xx + 2.0, y - 4.0, w - 4.0, th - 4.0, pcol(key), 45.0, 7.0, 0.16 * aa)
            stext(name, xx + 10.0, y, 14.0, key, aa)
        } else {
            px_outline(xx, y - 6.0, w, th, pcol("ink"), 0.4 * aa)
            stext(name, xx + 10.0, y, 14.0, "ink", 0.75 * aa)
        }
        if clicked == 1.0 {
            if hitrect(mx, my, xx, y - 6.0, w, th) == 1.0 {
                st_set("tab", i)
                ui_sound("click")
            }
        }
        bind xx = xx + w + 8.0
        bind i = i + 1
    }
    return 0
}

# ---------- info line ----------
fn infoline(x, y, label, value, key, aa) {
    stext(label, x, y, 13.0, "ink", 0.7 * aa)
    # the value clears the label in whichever face is active
    bind vx = x + tsize(115.0)
    bind lw = stext_w(label, 13.0) + 14.0
    if lw > tsize(115.0) { bind vx = x + lw }
    stext(value, vx, y, 13.0, key, 0.95 * aa)
    return 0
}

# ---------- tab layouts ----------
fn tab_overview(wdt, hgt, mn, t, dt, aa) {
    draw_cpu(wdt * 0.165, hgt * 0.4, mn * 0.19, t, dt, aa)
    draw_memgrid(wdt * 0.052, hgt * 0.69, 16.0, 7.0, 19.0, t, aa)
    framebox(wdt * 0.3, hgt * 0.175, wdt * 0.375, hgt * 0.645, "MAINBOARD", "ink", 0.8 * aa)
    draw_board(wdt * 0.487, hgt * 0.49, mn * 0.235, t, dt, aa)
    draw_drum(wdt * 0.5, hgt * 0.838, wdt * 0.095, 4.0, 13.0, t, aa)
    draw_gpu(wdt * 0.845, hgt * 0.33, mn * 0.15, t, dt, aa)
    draw_net(wdt * 0.845, hgt * 0.7, mn * 0.115, t, dt, aa)
    draw_disk(wdt * 0.715, hgt * 0.86, wdt * 0.245, hgt * 0.1, t, aa)
    draw_legend(wdt * 0.052, hgt * 0.935, aa)
    return 0
}

fn tab_cpu(wdt, hgt, mn, t, dt, aa) {
    draw_cpu(wdt * 0.24, hgt * 0.48, mn * 0.27, t, dt, aa)
    bind n = st_get("s_cpu_count", 0.0)
    bind cols = 8.0
    if n > 64.0 { bind cols = 16.0 }
    bind rows = ceil(n / cols)
    if rows < 1.0 { bind rows = 1.0 }
    bind cell = 42.0
    bind gx = wdt * 0.55
    bind gy = hgt * 0.22
    bind amax = hgt * 0.36
    if rows * cell > amax { bind cell = amax / rows }
    bind c = pcol("ctl")
    word("CORE FIELD", gx, gy - 30.0, 14.0, "ctl", aa)
    bind rr = 0.0
    while rr < rows {
        tile(hex2(rr * cols), gx - 32.0, gy + rr * cell + cell * 0.5 - 10.0, 15.0, "ctl", 0.65 * aa)
        bind cc = 0.0
        while cc < cols {
            bind idx = rr * cols + cc
            if idx < n {
                bind load = st_get("s_core" + num_str(idx), 0.0)
                bind cx0 = gx + cc * cell
                bind cy0 = gy + rr * cell
                px_outline(cx0 + 1.0, cy0 + 1.0, cell - 2.0, cell - 2.0, c, 0.45 * aa)
                if load > 1.5 {
                    bind den = 1.0 + floor(clampf(load, 0.0, 99.0) / 25.0)
                    bind sp = cell * 0.2 * den_mul(den)
                    if sp < 3.0 { bind sp = 3.0 }
                    if (rr + cc) % 2.0 == 0.0 {
                        px_hatch(cx0 + 3.0, cy0 + 3.0, cell - 6.0, cell - 6.0, c, 45.0, sp, 0.6 * aa)
                        px_hatch(cx0 + 3.0, cy0 + 3.0, cell - 6.0, cell - 6.0, c, 315.0, sp, 0.6 * aa)
                    } else {
                        px_hatch(cx0 + 3.0, cy0 + 3.0, cell - 6.0, cell - 6.0, c, 30.0, sp, 0.6 * aa)
                        px_hatch(cx0 + 3.0, cy0 + 3.0, cell - 6.0, cell - 6.0, c, 300.0, sp, 0.6 * aa)
                    }
                }
                if load > 90.0 {
                    bind blink = 0.5 + 0.45 * sin(t * 7.0)
                    px_outline(cx0 + 1.0, cy0 + 1.0, cell - 2.0, cell - 2.0, c, blink * aa)
                }
            }
            bind cc = cc + 1.0
        }
        bind rr = rr + 1.0
    }
    bind pp = tsize(20.0)
    bind iy = gy + rows * cell + 28.0
    infoline(gx, iy, "PROCS", fmtint(st_get("s_procs", 0.0)) + " . THREADS " + fmtint(st_get("s_threads", 0.0)), "ctl", aa)
    infoline(gx, iy + pp, "CSWITCH", fmtcount(st_get("s_cswitch", 0.0)) + " PER S", "ctl", aa)
    bind base = to_number(st_get("i_cpu_mhz", "0")) * 0.001
    bind perf = st_get("s_cpu_perf", 100.0)
    infoline(gx, iy + pp * 2.0, "CLOCK", fmt1(base * perf / 100.0) + " GHZ OF " + fmt1(base) + " BASE", "ctl", aa)
    infoline(gx, iy + pp * 3.0, "VOICE", "TICK TOCK PACES WITH LOAD", "ctl", 0.8 * aa)
    draw_histmesh(wdt * 0.06, hgt * 0.8, 84.0, wdt * 0.0104, 30.0, "cpu", "ctl", 100.0, "CPU LOAD . LAST 96 TICKS . NOW " + fmtint(st_get("d_cpu", 0.0)) + " PCT", aa)
    return 0
}

fn tab_gpu(wdt, hgt, mn, t, dt, aa) {
    draw_gpu(wdt * 0.24, hgt * 0.46, mn * 0.25, t, dt, aa)
    bind vu = st_get("s_gpu_mem_used", 0.0)
    bind vt = st_get("s_gpu_mem_total", 1.0)
    bind cols = 10.0
    bind rows = 4.0
    bind cell = 36.0
    bind gx = wdt * 0.55
    bind gy = hgt * 0.22
    bind c = pcol("lit")
    word("VRAM FIELD", gx, gy - 30.0, 14.0, "lit", aa)
    bind used = round(clampf(vu / vt, 0.0, 1.0) * cols * rows)
    bind rr = 0.0
    while rr < rows {
        bind cc = 0.0
        while cc < cols {
            bind idx = rr * cols + cc
            bind cx0 = gx + cc * cell
            bind cy0 = gy + rr * cell
            if idx < used {
                px_outline(cx0 + 1.0, cy0 + 1.0, cell - 2.0, cell - 2.0, c, 0.45 * aa)
                bind sp = cell * 0.22
                if (rr + cc) % 2.0 == 0.0 {
                    px_hatch(cx0 + 3.0, cy0 + 3.0, cell - 6.0, cell - 6.0, c, 0.0, sp, 0.55 * aa)
                    px_hatch(cx0 + 3.0, cy0 + 3.0, cell - 6.0, cell - 6.0, c, 90.0, sp, 0.55 * aa)
                } else {
                    px_hatch(cx0 + 3.0, cy0 + 3.0, cell - 6.0, cell - 6.0, c, 45.0, sp, 0.55 * aa)
                    px_hatch(cx0 + 3.0, cy0 + 3.0, cell - 6.0, cell - 6.0, c, 315.0, sp, 0.55 * aa)
                }
            } else {
                px_outline(cx0 + 1.0, cy0 + 1.0, cell - 2.0, cell - 2.0, pcol("ink"), 0.2 * aa)
            }
            bind cc = cc + 1.0
        }
        bind rr = rr + 1.0
    }
    bind pp = tsize(20.0)
    bind iy = gy + rows * cell + 28.0
    bind cardname = sanitize(st_get("i_gpu_name", ""), 26)
    infoline(gx, iy, "CARD", cardname, "lit", aa)
    infoline(gx, iy + pp, "VRAM", fmt1(vu / 1024.0) + "G OF " + fmt1(vt / 1024.0) + "G", "lit", aa)
    infoline(gx, iy + pp * 2.0, "HEAT", fmtint(st_get("s_gpu_temp", 0.0)) + " C . FAN " + fmtint(st_get("s_gpu_fan", 0.0)) + " PCT", "lit", aa)
    infoline(gx, iy + pp * 3.0, "POWER", fmt1(st_get("s_gpu_power", 0.0)) + " W", "lit", aa)
    infoline(gx, iy + pp * 4.0, "VOICE", "WHINE WITH LOAD . FAN FLUTTER", "lit", 0.8 * aa)
    draw_histmesh(wdt * 0.06, hgt * 0.8, 84.0, wdt * 0.0104, 30.0, "gpu", "lit", 100.0, "GPU LOAD . LAST 96 TICKS . NOW " + fmtint(st_get("d_gpu", 0.0)) + " PCT", aa)
    return 0
}

fn tab_mem(wdt, hgt, mn, t, dt, aa) {
    draw_memgrid(wdt * 0.07, hgt * 0.22, 20.0, 8.0, hgt * 0.048, t, aa)
    bind gx = wdt * 0.66
    bind gy = hgt * 0.23
    bind pp = tsize(20.0)
    bind mt = st_get("s_mem_total", 1.0)
    bind mu = st_get("s_mem_used", 0.0)
    infoline(gx, gy, "USED", fmt1(mu / 1024.0) + "G . " + fmtint(mu / mt * 100.0) + " PCT", "bind", aa)
    infoline(gx, gy + pp, "FREE", fmt1((mt - mu) / 1024.0) + "G", "bind", aa)
    infoline(gx, gy + pp * 2.0, "COMMIT", fmt1(st_get("s_mem_commit", 0.0) / 1024.0) + "G", "bind", aa)
    infoline(gx, gy + pp * 3.0, "CACHE", fmt1(st_get("s_mem_cache", 0.0) / 1024.0) + "G", "bind", aa)
    infoline(gx, gy + pp * 4.0, "FAULTS", fmtcount(st_get("s_mem_faults", 0.0)) + " PER S", "bind", aa)
    infoline(gx, gy + pp * 5.0, "VOICE", "DRONE AS PAGES FILL", "bind", 0.8 * aa)
    logdial(wdt * 0.78, hgt * 0.58, mn * 0.13, "bind", "PAGE FAULTS . ", st_get("s_mem_faults", 0.0), "flt", 1.0, t, dt, aa)
    draw_histmesh(wdt * 0.06, hgt * 0.8, 84.0, wdt * 0.0104, 30.0, "mem", "bind", 100.0, "MEMORY IN USE . LAST 96 TICKS", aa)
    return 0
}

fn tab_disk(wdt, hgt, mn, t, dt, aa) {
    bind pp = tsize(20.0)
    logdial(wdt * 0.15, hgt * 0.37, mn * 0.155, "bind", "READ BYTES EACH SECOND . ", st_get("s_disk_read", 0.0), "rdd", 1.0, t, dt, aa)
    wordc("READ", wdt * 0.15, hgt * 0.37 + mn * 0.155 + 12.0, 15.0, "bind", aa)
    logdial(wdt * 0.4, hgt * 0.37, mn * 0.155, "bind", "WRITE BYTES EACH SECOND . ", st_get("s_disk_write", 0.0), "wrr", 0.0 - 1.0, t, dt, aa)
    wordc("WRITE", wdt * 0.4, hgt * 0.37 + mn * 0.155 + 12.0, 15.0, "bind", aa)
    bind sy = hgt * 0.37 + mn * 0.155 + 12.0 + pp * 1.6
    stext("TOTAL R " + fmtbytes(st_get("tot_rd", 0.0)) + " . TOTAL W " + fmtbytes(st_get("tot_wr", 0.0)) + " THIS SESSION", wdt * 0.06, sy, 12.0, "bind", 0.9 * aa)
    stext("BUSY " + fmtint(st_get("s_disk_busy", 0.0)) + " PCT . VOICE . READS SCRATCH HIGH . WRITES LOW", wdt * 0.06, sy + pp, 12.0, "bind", 0.75 * aa)
    # logical volumes: capacity bands, two columns, all of them
    bind vy = sy + pp * 2.4
    word("VOLUMES", wdt * 0.06, vy, 13.0, "bind", aa)
    bind nv = st_get("s_drv_n", 0.0)
    if nv > 8.0 { bind nv = 8.0 }
    bind c = pcol("bind")
    bind i = 0.0
    while i < nv {
        bind rec = st_get("s_drv" + num_str(i), "")
        bind parts = str_split(rec, "|")
        if len(parts) >= 3 {
            bind colx = wdt * (0.06 + 0.25 * floor(i / 4.0))
            bind ry = vy + pp * 1.3 + (i % 4.0) * pp * 1.15
            bind letter = list_get(parts, 0)
            bind totg = to_number(list_get(parts, 1))
            bind freg = to_number(list_get(parts, 2))
            bind usedfrac = 0.0
            if totg > 0.0 { bind usedfrac = (totg - freg) / totg }
            tile(letter, colx, ry - 3.0, 15.0, "bind", aa)
            bind bw = wdt * 0.085
            px_outline(colx + tsize(24.0), ry, bw, 15.0, c, 0.55 * aa)
            if usedfrac > 0.02 {
                px_hatch(colx + tsize(24.0) + 2.0, ry + 2.0, (bw - 4.0) * usedfrac, 11.0, c, 45.0, 3.4, 0.7 * aa)
                px_hatch(colx + tsize(24.0) + 2.0, ry + 2.0, (bw - 4.0) * usedfrac, 11.0, c, 315.0, 3.4, 0.7 * aa)
            }
            stext(fmtint(freg) + "G OF " + fmtint(totg) + "G", colx + tsize(24.0) + bw + 8.0, ry, 11.0, "bind", 0.85 * aa)
        }
        bind i = i + 1
    }
    # each physical disk is its own small instrument, all of them
    bind gx = wdt * 0.66
    bind gy = hgt * 0.19
    word("SPINDLES", gx, gy - 30.0, 13.0, "bind", aa)
    bind nd = st_get("s_dsk_n", 0.0)
    if nd > 8.0 { bind nd = 8.0 }
    bind dpitch = tsize(46.0)
    if nd > 0.0 {
        bind avail = hgt * 0.76 - gy
        if dpitch * nd > avail { bind dpitch = avail / nd }
    }
    bind i = 0.0
    while i < nd {
        bind rec = st_get("s_dsk" + num_str(i), "")
        bind parts = str_split(rec, "|")
        if len(parts) >= 4 {
            bind ry = gy + i * dpitch
            bind dname = sanitize(list_get(parts, 0), 12)
            bind drd = to_number(list_get(parts, 1))
            bind dwr = to_number(list_get(parts, 2))
            bind dbz = to_number(list_get(parts, 3))
            bind dr = dpitch * 0.38
            dialbezel(gx + dr, ry + dr, dr, "bind", 0.9 * aa)
            hand(gx + dr, ry + dr, dr * 0.62, dbz / 100.0 * 6.2831853, 3.0, "bind", 0.9 * aa)
            stext(dname, gx + dpitch * 0.95, ry + 1.0, 12.0, "bind", aa)
            stext("R " + fmtbytes(drd) + " . W " + fmtbytes(dwr) + " . BUSY " + fmtint(dbz), gx + dpitch * 0.95, ry + 1.0 + pp * 0.85, 11.0, "bind", 0.8 * aa)
        }
        bind i = i + 1
    }
    draw_histmesh(wdt * 0.06, hgt * 0.8, 40.0, wdt * 0.0104, 30.0, "rd", "bind", 9.0, "READ . LOG SCALE", aa)
    draw_histmesh(wdt * 0.54, hgt * 0.8, 40.0, wdt * 0.0104, 30.0, "wr", "bind", 9.0, "WRITE . LOG SCALE", aa)
    return 0
}

fn tab_net(wdt, hgt, mn, t, dt, aa) {
    logdial(wdt * 0.22, hgt * 0.44, mn * 0.2, "call", "RECEIVING . PINGS INBOUND . ", st_get("s_net_rx", 0.0), "rxx", 1.0, t, dt, aa)
    wordc("RX IN", wdt * 0.22, hgt * 0.44 + mn * 0.2 + 12.0, 15.0, "call", aa)
    logdial(wdt * 0.52, hgt * 0.44, mn * 0.2, "call", "SENDING . WOOSHES OUT . ", st_get("s_net_tx", 0.0), "txx", 0.0 - 1.0, t, dt, aa)
    wordc("TX OUT", wdt * 0.52, hgt * 0.44 + mn * 0.2 + 12.0, 15.0, "call", aa)
    bind pp = tsize(20.0)
    bind iy = hgt * 0.3
    infoline(wdt * 0.73, iy, "SESSION RX", fmtbytes(st_get("tot_rx", 0.0)), "call", aa)
    infoline(wdt * 0.73, iy + pp, "SESSION TX", fmtbytes(st_get("tot_tx", 0.0)), "call", aa)
    infoline(wdt * 0.73, iy + pp * 2.0, "RATE RX", fmtbytes(st_get("s_net_rx", 0.0)) + " PER S", "call", aa)
    infoline(wdt * 0.73, iy + pp * 3.0, "RATE TX", fmtbytes(st_get("s_net_tx", 0.0)) + " PER S", "call", aa)
    infoline(wdt * 0.73, iy + pp * 4.0, "VOICE", "PINGS IN . WOOSHES OUT", "call", 0.8 * aa)
    draw_histmesh(wdt * 0.06, hgt * 0.8, 40.0, wdt * 0.0104, 30.0, "rx", "call", 9.0, "RECEIVED . LOG SCALE", aa)
    draw_histmesh(wdt * 0.54, hgt * 0.8, 40.0, wdt * 0.0104, 30.0, "tx", "call", 9.0, "SENT . LOG SCALE", aa)
    return 0
}

fn tab_board(wdt, hgt, mn, t, dt, aa) {
    framebox(wdt * 0.38, hgt * 0.17, wdt * 0.56, hgt * 0.58, "MAINBOARD", "ink", 0.8 * aa)
    draw_board(wdt * 0.66, hgt * 0.46, mn * 0.22, t, dt, aa)
    bind gx = wdt * 0.06
    bind gy = hgt * 0.22
    bind vhost = sanitize(st_get("i_host", ""), 20)
    bind vboard = sanitize(last_tokens(st_get("i_board", ""), 4), 26)
    bind vbios = sanitize(st_get("i_bios", ""), 16)
    bind vos = sanitize(last_tokens(st_get("i_os", ""), 4), 26)
    bind vcpu = sanitize(last_tokens(st_get("i_cpu_name", ""), 3), 26)
    bind vgpu = sanitize(last_tokens(st_get("i_gpu_name", ""), 3), 26)
    bind pp = tsize(20.0)
    infoline(gx, gy, "HOST", vhost, "asm", aa)
    infoline(gx, gy + pp, "BOARD", vboard, "asm", aa)
    infoline(gx, gy + pp * 2.0, "BIOS", vbios, "asm", aa)
    infoline(gx, gy + pp * 3.0, "OS", vos, "asm", aa)
    infoline(gx, gy + pp * 4.0, "CPU", vcpu, "asm", aa)
    infoline(gx, gy + pp * 5.0, "GPU", vgpu, "asm", aa)
    infoline(gx, gy + pp * 6.0, "UP", fmtup(st_get("s_uptime", 0.0)), "asm", aa)
    bind btemp = st_get("s_board_temp", 0.0)
    if btemp > 0.0 {
        infoline(gx, gy + pp * 7.0, "TEMP", fmt1(btemp) + " C", "asm", aa)
    }
    infoline(gx, gy + pp * 8.0, "VOICE", "THE DEEP DRONE UNDER ALL", "asm", 0.8 * aa)
    draw_legend(wdt * 0.06, hgt * 0.69, aa)
    draw_histmesh(wdt * 0.06, hgt * 0.8, 84.0, wdt * 0.0104, 30.0, "cs", "asm", 6.0, "CONTEXT SWITCHES . LOG SCALE . NOW " + fmtcount(st_get("s_cswitch", 0.0)) + " PER S", aa)
    return 0
}

fn tab_proc(wdt, hgt, mn, t, dt, aa) {
    bind pp = tsize(20.0)
    draw_drum(wdt * 0.27, hgt * 0.26, wdt * 0.16, 6.0, 18.0, t, aa)
    bind gx = wdt * 0.58
    bind gy = hgt * 0.2
    bind c1 = tsize(200.0)
    bind c2 = tsize(370.0)
    stext("NAME", gx, gy, 12.0, "ink", 0.7 * aa)
    stext("CPU", gx + c1, gy, 12.0, "ink", 0.7 * aa)
    stext("MEM", gx + c2, gy, 12.0, "ink", 0.7 * aa)
    bind c = pcol("fn")
    bind nproc = st_get("s_proc_n", 0.0)
    if nproc > 8.0 { bind nproc = 8.0 }
    bind rpitch = pp * 1.3
    bind i = 0.0
    while i < nproc {
        bind rec = st_get("s_proc" + num_str(i), "")
        bind parts = str_split(rec, "|")
        if len(parts) >= 3 {
            bind ry = gy + pp * 1.4 + i * rpitch
            bind pname = sanitize(list_get(parts, 0), 16.0)
            stext(pname, gx, ry, 13.0, "fn", aa)
            bind pcpu = to_number(list_get(parts, 1))
            bind bw = clampf(pcpu / 25.0, 0.04, 1.0) * (c2 - c1 - tsize(70.0))
            px_outline(gx + c1, ry + 1.0, c2 - c1 - tsize(66.0), 15.0, c, 0.45 * aa)
            bind den = 1.0 + floor(clampf(pcpu / 6.0, 0.0, 3.0))
            px_hatch(gx + c1 + 2.0, ry + 3.0, bw, 11.0, c, 45.0, 3.0 * den_mul(den), 0.7 * aa)
            stextr(fmt1(pcpu), gx + c2 - tsize(14.0), ry, 13.0, "fn", 0.9 * aa)
            stext(fmtbytes(to_number(list_get(parts, 2)) * 1048576.0), gx + c2, ry, 13.0, "fn", 0.9 * aa)
        }
        bind i = i + 1
    }
    bind iy = gy + pp * 1.4 + 8.0 * rpitch + 10.0
    infoline(gx, iy, "PROCS", fmtint(st_get("s_procs", 0.0)) + " . THREADS " + fmtint(st_get("s_threads", 0.0)), "fn", aa)
    infoline(gx, iy + pp, "VOICE", "A DING WHEN THE POPULATION CHANGES", "fn", 0.8 * aa)
    return 0
}

# ---------- AUDIO tab: inputs, outputs, and the app's own voice ----------
fn voicebar(x, y, label, amp, stamp, t, maxr, aa) {
    bind c = pcol("lit")
    stext(label, x, y, 12.0, "lit", 0.85 * aa)
    # the bar clears the widest label in whichever face is active
    bind bx = x + stext_w("DISK SCRATCH", 12.0) + 14.0
    bind bw = tsize(118.0)
    bind lim = maxr - 26.0 - bx
    if bw > lim { bind bw = lim }
    if bw < 60.0 { bind bw = 60.0 }
    px_outline(bx, y + 1.0, bw, 15.0, c, 0.5 * aa)
    bind f = clampf(amp * 22.0, 0.0, 1.0)
    if f > 0.02 {
        bind den = 1.0 + floor(f * 3.9)
        px_hatch(bx + 2.0, y + 3.0, (bw - 4.0) * f, 11.0, c, 45.0, 3.0 * den_mul(den), 0.75 * aa)
    }
    if t - stamp < 0.35 {
        px_outline(bx + bw + 8.0, y + 2.0, 12.0, 12.0, c, aa)
        px_hatch(bx + bw + 10.0, y + 4.0, 8.0, 8.0, c, 45.0, 2.2, aa)
    }
    return 0
}

fn tab_audio(wdt, hgt, mn, t, dt, aa) {
    # the mic dial reads the stream the collector opens for it: live, off, or refused
    bind micstate = st_get("s_aud_mic", 0.0)
    if st_get("p_mic", 1.0) < 1.0 { bind micstate = 0.0 }
    if st_get("p_mic", 1.0) >= 1.0 {
        if micstate == 0.0 { bind micstate = 1.0 }
    }
    vudial(wdt * 0.2, hgt * 0.44, mn * 0.2, "lit", "OUTPUT . SPEAKERS . ", st_get("s_aud_out", 0.0), "aout", 1.0, t, dt, aa)
    wordc("OUT", wdt * 0.2, hgt * 0.44 + mn * 0.2 + 12.0, 15.0, "lit", aa)
    stextc("SPEAKERS . DB BELOW FULL SCALE", wdt * 0.2, hgt * 0.44 + mn * 0.2 + 34.0, 12.0, "lit", 0.7 * aa)
    vudial(wdt * 0.5, hgt * 0.44, mn * 0.2, "lit", "INPUT . MICROPHONE . ", st_get("s_aud_in", 0.0), "ain", micstate, t, dt, aa)
    wordc("MIC", wdt * 0.5, hgt * 0.44 + mn * 0.2 + 12.0, 15.0, "lit", aa)
    stextc("MICROPHONE . LEVEL ONLY, NOTHING RECORDED", wdt * 0.5, hgt * 0.44 + mn * 0.2 + 34.0, 12.0, "lit", 0.7 * aa)
    # the voices of this instrument panel
    bind pp = tsize(20.0)
    bind gx = wdt * 0.68
    bind gy = hgt * 0.32
    word("VOICES", gx, gy - 30.0, 14.0, "lit", aa)
    bind vmr = wdt * 0.975
    voicebar(gx, gy, "CPU HUM", st_get("ta_0", 0.0), st_get("bl_tick", 0.0 - 9.0), t, vmr, aa)
    voicebar(gx, gy + pp, "MEM DRONE", st_get("ta_1", 0.0), 0.0 - 9.0, t, vmr, aa)
    voicebar(gx, gy + pp * 2.0, "GPU WHINE", st_get("ta_2", 0.0), 0.0 - 9.0, t, vmr, aa)
    voicebar(gx, gy + pp * 3.0, "NET AIR", st_get("ta_3", 0.0), st_get("bl_rx", 0.0 - 9.0), t, vmr, aa)
    voicebar(gx, gy + pp * 4.0, "BOARD DRONE", st_get("ta_4", 0.0), 0.0 - 9.0, t, vmr, aa)
    voicebar(gx, gy + pp * 5.0, "DISK SCRATCH", 0.0, st_get("bl_rd", 0.0 - 9.0), t, vmr, aa)
    voicebar(gx, gy + pp * 6.0, "TX WOOSH", 0.0, st_get("bl_tx", 0.0 - 9.0), t, vmr, aa)
    voicebar(gx, gy + pp * 7.0, "PROC DING", 0.0, st_get("bl_ding", 0.0 - 9.0), t, vmr, aa)
    bind iy = gy + pp * 8.0 + 14.0
    infoline(gx, iy, "SYS VOL", fmtint(st_get("s_aud_vol", 0.0)) + " PCT", "lit", aa)
    infoline(gx, iy + pp, "APP VOL", fmtint(st_get("p_vol", 2.0)) + " OF 4", "lit", aa)
    # devices
    bind dy = hgt * 0.72
    word("DEVICES", wdt * 0.07, dy - 8.0, 14.0, "lit", aa)
    bind ndn = to_number(st_get("i_snd_n", "0"))
    if ndn > 8.0 { bind ndn = 8.0 }
    bind dpitch = tsize(16.0)
    bind avail = hgt * 0.94 - dy - 18.0
    if ndn > 0.0 {
        if dpitch * ndn > avail { bind dpitch = avail / ndn }
    }
    bind i = 0.0
    while i < ndn {
        bind dn = sanitize(st_get("i_snd" + num_str(i), ""), 40)
        stext(dn, wdt * 0.07, dy + 18.0 + i * dpitch, 11.0, "ink", 0.8 * aa)
        bind i = i + 1
    }
    infoline(wdt * 0.42, dy + 18.0, "VOICE", "THIS TAB IS THE MIX ITSELF", "lit", 0.8 * aa)
    draw_histmesh(wdt * 0.42, dy + 18.0 + pp * 1.4, 44.0, wdt * 0.0104, 26.0, "aout", "lit", 100.0, "OUTPUT PEAK . LAST TICKS", aa)
    return 0
}

# ---------- panel ----------
fn panel_toggle(x, y, w, label, key, mx, my, clicked, aa) {
    bind on = st_get(key, 1.0)
    bind c = pcol("ctl")
    if on < 1.0 { bind c = pcol("ink") }
    px_outline(x, y, 16.0, 16.0, c, 0.9 * aa)
    if on >= 1.0 {
        px_hatch(x + 2.0, y + 2.0, 12.0, 12.0, c, 45.0, 3.0, 0.8 * aa)
        px_hatch(x + 2.0, y + 2.0, 12.0, 12.0, c, 315.0, 3.0, 0.8 * aa)
    }
    bind lk = "ctl"
    if on < 1.0 { bind lk = "ink" }
    stext(label, x + 24.0, y + 1.0, 12.0, lk, 0.9 * aa)
    if clicked == 1.0 {
        if hitrect(mx, my, x - 4.0, y - 3.0, w, 24.0) == 1.0 {
            st_set(key, 1.0 - on)
            ui_sound("toggle")
        }
    }
    return 0
}

fn panel_steps(x, y, w, label, key, maxv, dflt, mx, my, clicked, aa) {
    bind cur = st_get(key, dflt)
    bind sp = tsize(18.0)
    bind i = 0.0
    while i <= maxv {
        bind tx = x + i * sp
        bind k = "ink"
        if i == cur { bind k = "ctl" }
        tile(num_str(i), tx, y, 13.0, k, aa)
        if clicked == 1.0 {
            if hitrect(mx, my, tx - 2.0, y - 2.0, sp, sp + 6.0) == 1.0 {
                st_set(key, i)
                ui_sound("tick")
            }
        }
        bind i = i + 1
    }
    stext(label, x + (maxv + 1.0) * sp + 8.0, y + 2.0, 12.0, "ink", 0.8 * aa)
    return 0
}

# right edge of the title block and the tab row: the controls panel must stay clear of it
fn header_end() {
    bind xx = 30.0
    bind i = 0.0
    while i < 9.0 {
        bind xx = xx + stext_w(tab_name(i), 14.0) + 28.0
        bind i = i + 1
    }
    bind tx = 30.0 + word_w("LINGSYS", 28.0) + 24.0
    bind w1 = stext_w("SYSTEM ACTIVITY MONITOR . REV 2030.1 . UP 99D 23H 59M", 12.0)
    bind w2 = stext_w("XXXXXXXXXXXX . XXXXXXXXXXXX . XXXXXXXXXXXX . 99 THREADS", 12.0)
    bind te = tx + w2
    if w1 > w2 { bind te = tx + w1 }
    if te > xx { return te + 24.0 }
    return xx + 24.0
}

fn panel_steps_w(label, maxv) {
    return (maxv + 1.0) * tsize(18.0) + 8.0 + stext_w(label, 12.0) + 18.0
}

fn panel_toggle_w(label) {
    return stext_w(label, 12.0) + 40.0
}

# the controls laid out flat in the header band, beside the title and tabs, so they
# never cover a dial or a table; false when the window is too narrow for that
fn draw_panel_wide(wdt, mx, my, clicked, aa) {
    bind pp = tsize(20.0)
    bind row1 = panel_toggle_w("SOUND") + panel_toggle_w("PACKETS") + panel_toggle_w("SPIN") + panel_toggle_w("LABELS") + panel_toggle_w("MIC")
    bind row2 = panel_steps_w("TXT", 2.0) + panel_steps_w("SPD", 4.0) + panel_steps_w("VOL", 4.0) + 40.0
    bind pw = row1
    if row2 > pw { bind pw = row2 }
    bind x = wdt - pw - 36.0
    if x < header_end() { return 0 }
    bind y = 26.0
    bind ph = pp * 2.0 + 30.0
    px_rect(x - 8.0, y - 6.0, pw + 16.0, ph + 12.0, 0.0, 0.74)
    px_outline(x - 8.0, y - 6.0, pw + 16.0, ph + 12.0, pcol("ink"), 0.9 * aa)
    px_outline(x - 13.0, y - 11.0, pw + 26.0, ph + 22.0, pcol("ink"), 0.5 * aa)
    word("CONTROLS", x, y + 2.0, 12.0, "mod", aa)
    bind ry = y + pp + 4.0
    bind xx = x
    panel_toggle(xx, ry, panel_toggle_w("SOUND"), "SOUND", "p_sound", mx, my, clicked, aa)
    bind xx = xx + panel_toggle_w("SOUND")
    panel_toggle(xx, ry, panel_toggle_w("PACKETS"), "PACKETS", "p_packets", mx, my, clicked, aa)
    bind xx = xx + panel_toggle_w("PACKETS")
    panel_toggle(xx, ry, panel_toggle_w("SPIN"), "SPIN", "p_spin", mx, my, clicked, aa)
    bind xx = xx + panel_toggle_w("SPIN")
    panel_toggle(xx, ry, panel_toggle_w("LABELS"), "LABELS", "p_labels", mx, my, clicked, aa)
    bind xx = xx + panel_toggle_w("LABELS")
    panel_toggle(xx, ry, panel_toggle_w("MIC"), "MIC", "p_mic", mx, my, clicked, aa)
    bind ry2 = ry + pp + 4.0
    bind sx1 = x
    bind sx2 = sx1 + panel_steps_w("TXT", 2.0) + 20.0
    bind sx3 = sx2 + panel_steps_w("SPD", 4.0) + 20.0
    panel_steps(sx1, ry2, 0.0, "TXT", "p_txt", 2.0, 1.0, mx, my, clicked, aa)
    panel_steps(sx2, ry2, 0.0, "SPD", "p_speed", 4.0, 2.0, mx, my, clicked, aa)
    panel_steps(sx3, ry2, 0.0, "VOL", "p_vol", 4.0, 2.0, mx, my, clicked, aa)
    return 1
}

fn draw_panel(wdt, mx, my, clicked, aa) {
    if draw_panel_wide(wdt, mx, my, clicked, aa) == 1 { return 0 }
    bind pp = tsize(20.0)
    bind w = 90.0 + tsize(100.0)
    bind x = wdt - w - 26.0
    bind y = 26.0
    bind open = st_get("p_open", 1.0)
    bind h = pp + 8.0
    if open >= 1.0 { bind h = pp * 9.5 + 16.0 }
    px_rect(x - 6.0, y - 6.0, w + 12.0, h + 12.0, 0.0, 0.74)
    px_outline(x - 6.0, y - 6.0, w + 12.0, h + 12.0, pcol("ink"), 0.9 * aa)
    px_outline(x - 11.0, y - 11.0, w + 22.0, h + 22.0, pcol("ink"), 0.5 * aa)
    word("CONTROLS", x + 4.0, y + 2.0, 12.0, "mod", aa)
    bind sw = "-"
    if open < 1.0 { bind sw = "+" }
    tile(sw, x + w - 22.0, y, 15.0, "mod", aa)
    if clicked == 1.0 {
        if hitrect(mx, my, x + w - 28.0, y - 3.0, 32.0, 26.0) == 1.0 {
            st_set("p_open", 1.0 - open)
            ui_sound("click")
        }
    }
    if open >= 1.0 {
        px_line(x - 2.0, y + pp + 4.0, x + w + 2.0, y + pp + 4.0, pcol("ink"), 0.5 * aa)
        bind ry = y + pp + 12.0
        panel_toggle(x + 4.0, ry, w, "SOUND", "p_sound", mx, my, clicked, aa)
        panel_toggle(x + 4.0, ry + pp, w, "PACKETS", "p_packets", mx, my, clicked, aa)
        panel_toggle(x + 4.0, ry + pp * 2.0, w, "SPIN", "p_spin", mx, my, clicked, aa)
        panel_toggle(x + 4.0, ry + pp * 3.0, w, "LABELS", "p_labels", mx, my, clicked, aa)
        panel_toggle(x + 4.0, ry + pp * 4.0, w, "MIC", "p_mic", mx, my, clicked, aa)
        panel_steps(x + 4.0, ry + pp * 5.0, w, "TXT", "p_txt", 2.0, 1.0, mx, my, clicked, aa)
        panel_steps(x + 4.0, ry + pp * 6.1, w, "SPD", "p_speed", 4.0, 2.0, mx, my, clicked, aa)
        panel_steps(x + 4.0, ry + pp * 7.2, w, "VOL", "p_vol", 4.0, 2.0, mx, my, clicked, aa)
    }
    return 0
}

# ---------- entry ----------
bind start = do {
    # size the window to the monitor
    bind mw = monitor_width()
    bind mh = monitor_height()
    if mw < 800.0 { bind mw = 1720.0 }
    if mh < 500.0 { bind mh = 1020.0 }
    open_window(round(clampf(mw * 0.9, 1200.0, 2400.0)), round(clampf(mh * 0.86, 720.0, 1400.0)), "LINGSYS", 1)
    set_fps(30)
    set_antialias(1)
    set_font_antialias(1)
    pal_init()
    st_set("fd", font_load("assets/fonts/Daemon.otf", 400.0))
    st_set("fc", font_load("assets/fonts/Chesilin.ttf", 400.0))
    # the English face: Consolas, else another system font. On LingOS none of these
    # exist, fe stays -1, and etext falls back to the kernel's 8x8 pixel font.
    bind fe = font_load("C:/Windows/Fonts/consola.ttf", 400.0)
    if fe < 0.0 { bind fe = font_load("C:/Windows/Fonts/cour.ttf", 400.0) }
    if fe < 0.0 { bind fe = font_load("C:/Windows/Fonts/arial.ttf", 400.0) }
    if fe < 0.0 { bind fe = font_load("C:/Windows/Fonts/segoeui.ttf", 400.0) }
    # Linux, then macOS (a font that is not there just returns -1)
    if fe < 0.0 { bind fe = font_load("/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", 400.0) }
    if fe < 0.0 { bind fe = font_load("/usr/share/fonts/TTF/DejaVuSansMono.ttf", 400.0) }
    if fe < 0.0 { bind fe = font_load("/usr/share/fonts/truetype/liberation/LiberationMono-Regular.ttf", 400.0) }
    if fe < 0.0 { bind fe = font_load("/usr/share/fonts/liberation-mono/LiberationMono-Regular.ttf", 400.0) }
    if fe < 0.0 { bind fe = font_load("/System/Library/Fonts/Supplemental/Courier New.ttf", 400.0) }
    if fe < 0.0 { bind fe = font_load("/System/Library/Fonts/Supplemental/Arial.ttf", 400.0) }
    if fe < 0.0 { bind fe = font_load("/Library/Fonts/Arial.ttf", 400.0) }
    st_set("fe", fe)
    # glyph fitting: Daemon caps run 0.63px tall centred at y+0.35px;
    # Chesilin glyphs run 1.04px tall centred at y+0.25px; Consolas
    # caps centre near y+0.45px. tscale makes every word bigger.
    st_set("fit_d", 1.55)
    st_set("voff_d", 0.35)
    st_set("fit_c", 0.96)
    st_set("voff_c", 0.25)
    st_set("voff_e", 0.45)
    st_set("tscale", 1.3)
    bind fk = font_load("C:/Windows/Fonts/msyh.ttc", 400.0)
    if fk < 0.0 { bind fk = font_load("C:/Windows/Fonts/msyhl.ttc", 400.0) }
    if fk < 0.0 { bind fk = font_load("C:/Windows/Fonts/simsun.ttc", 400.0) }
    st_set("fcjk", fk)
    st_set("p_sound", 1.0)
    st_set("p_packets", 1.0)
    st_set("p_spin", 1.0)
    st_set("p_labels", 1.0)
    st_set("p_hatch", 1.0)
    st_set("p_mic", 1.0)
    write_file("mic.cfg", "1")
    st_set("mic_sent", 1.0)
    st_set("p_txt", clampf(to_number(env_get("LINGSYS_TXT", "1")), 0.0, 2.0))
    st_set("p_speed", 2.0)
    st_set("p_vol", 2.0)
    st_set("p_open", 0.0)
    st_set("tab", to_number(env_get("LINGSYS_TAB", "0")))
    stats_start()
    snd_init()
    bind autoshot = env_get("LINGSYS_SHOT", "0")
    bind tprev = time_now()
    bind frame = 0.0
    bind quit = 0.0
    while window_is_open() && quit < 1.0 {
        bind t = time_now()
        bind dt = t - tprev
        bind tprev = t
        if dt > 0.25 { bind dt = 0.25 }
        stats_poll(t)
        stats_audio(t)
        st_set("motion", st_get("p_speed", 2.0) / 2.0)
        sm("d_cpu", st_get("s_cpu_total", 0.0), dt, 4.0)
        bind mt = st_get("s_mem_total", 1.0)
        sm("d_mem", st_get("s_mem_used", 0.0) / mt * 100.0, dt, 4.0)
        sm("d_gpu", st_get("s_gpu_load", 0.0), dt, 4.0)

        fill(0, 0, 0)
        bind wdt = get_width()
        bind hgt = get_height()
        bind mn = hgt
        if wdt < hgt { bind mn = wdt }
        # text rides with the resolution: the whole sheet stays legible
        st_set("tscale", clampf(mn / 980.0, 0.85, 1.7) * 1.3)
        bind aa = clampf(t * 0.7, 0.0, 1.0)

        framebox(10.0, 10.0, wdt - 20.0, hgt - 20.0, "", "ink", 0.8 * aa)
        draw_titleplate(30.0, 26.0, aa)

        bind mdn = 0.0
        if mouse_down() { bind mdn = 1.0 }
        bind clicked = 0.0
        if mdn == 1.0 {
            if st_get("md_prev", 0.0) == 0.0 { bind clicked = 1.0 }
        }
        st_set("md_prev", mdn)
        bind mx = mouse_x()
        bind my = mouse_y()

        draw_tabs(30.0, 100.0, mx, my, clicked, aa)

        bind tab = st_get("tab", 0.0)
        if tab == 0.0 { tab_overview(wdt, hgt, mn, t, dt, aa) }
        if tab == 1.0 { tab_cpu(wdt, hgt, mn, t, dt, aa) }
        if tab == 2.0 { tab_gpu(wdt, hgt, mn, t, dt, aa) }
        if tab == 3.0 { tab_mem(wdt, hgt, mn, t, dt, aa) }
        if tab == 4.0 { tab_disk(wdt, hgt, mn, t, dt, aa) }
        if tab == 5.0 { tab_net(wdt, hgt, mn, t, dt, aa) }
        if tab == 6.0 { tab_board(wdt, hgt, mn, t, dt, aa) }
        if tab == 7.0 { tab_proc(wdt, hgt, mn, t, dt, aa) }
        if tab == 8.0 { tab_audio(wdt, hgt, mn, t, dt, aa) }

        draw_panel(wdt, mx, my, clicked, aa)

        # tell the audio collector when the MIC switch changes
        if st_get("p_mic", 1.0) != st_get("mic_sent", 1.0) {
            st_set("mic_sent", st_get("p_mic", 1.0))
            write_file("mic.cfg", num_str(st_get("p_mic", 1.0)))
        }

        bind fps =sm("fps", 1.0 / clampf(dt, 0.001, 1.0), dt, 2.0)
        stextr(fmtint(fps) + " FPS . 1-9 TABS . F12 SHOT . ESC QUIT", wdt - 36.0, hgt - 34.0, 11.0, "ink", 0.6 * aa)

        snd_update(t, dt)

        if key_pressed("1") { st_set("tab", 0.0) }
        if key_pressed("2") { st_set("tab", 1.0) }
        if key_pressed("3") { st_set("tab", 2.0) }
        if key_pressed("4") { st_set("tab", 3.0) }
        if key_pressed("5") { st_set("tab", 4.0) }
        if key_pressed("6") { st_set("tab", 5.0) }
        if key_pressed("7") { st_set("tab", 6.0) }
        if key_pressed("8") { st_set("tab", 7.0) }
        if key_pressed("9") { st_set("tab", 8.0) }
        if key_pressed("tab") { st_set("tab", (st_get("tab", 0.0) + 1.0) % 9.0) }
        if key_pressed("f12") { screenshot("lingsys") }
        if key_down("escape") { bind quit = 1.0 }
        if frame % 90.0 == 0.0 { write_file("app.beat", num_str(t)) }
        if autoshot != "0" {
            bind shotframe = to_number(autoshot)
            if shotframe < 75.0 { bind shotframe = 75.0 }
            if frame == shotframe {
                screenshot("auto")
                bind quit = 1.0
            }
        }
        present()
        bind frame = frame + 1.0
    }
    stats_stop()
}

← Back to index