UI

Displays get the same treatment as everything else: author with HTML and CSS, and the build compiles it — layout solved at build time (Yoga), styles folded into draw lists, fonts subsetted to the glyphs you use, pixels as RGB565. Nothing like a browser runs on the board.

format

the .ui file

A single file: markup, style, and a script. Point the config's entry at it and the transpiler does the rest. The syntax is Svelte-compatible — braces interpolate, on: and bind: wire events and values.

Example first

app.ui
<screen>
  <view class="col">
    <text class="title">{count} taps</text>
    <button on:click={() => count++}>tap me</button>
  </view>
</screen>

<style>
  .col { flex-direction: column; gap: 12; align-items: center; }
  .title { font-size: 24; }
  button { padding: 10 20; }
</style>

<script lang="ts">
  import { ui } from '@typecad/ui';
  const count = ui.signal(0);
</script>
typecad-hal.config.ts
import type { TypecadConfig } from '@typecad/hal/config';

const config: TypecadConfig = {
  entry: './src/app.ui',
  display: {
    driver: 'ilitek,ili9341',  // any panel your Zephyr SDK binds — drop-in
    width: 320, height: 240,
    rotation: 90,
    backlightPin: 23,
  },
};

export default config;
functions

the ui API

The script side: reactive state, bindings, input, and canvases. Everything is a compile-time construct — each call lowers to specific draw or read code.

Example first

CallWhat it does
ui.mount(tree, opts?)Mount a screen — display facts usually live in the config’s display block
ui.signal(initial)Reactive value: call it to read, .set() to write — screens re-render on change
ui.bind(node, prop, compute)Bind a node property to a computed value
ui.bindList(node, countFn, itemFn, onTap?)Virtualized list — only visible items render
ui.bindInput(node, onCommit)On-screen keyboard input
ui.watchPin(pin, onFalling)Poll a physical button (~20 ms, no ISRs)
await ui.onTap(node?)Awaitable taps — menus and flows read top to bottom
ui.drawCanvas(node, draw)Canvas drawing — CSS colors become RGB565 at build time

Elements

GroupElements
Layout<screen> root · <view> containers · <text> · <img>
Input<button> · <check> · <radio> · <select> · <input> · <range>
Display<progress> · <range> · <canvas>
Wiring{expr} interpolation · on:click/hold/release/change · bind:text / bind:value · ref=
reference

the CSS subset

The layout-critical part of CSS, resolved entirely at build time. Unsupported properties are build warnings — errors with --strict-css.

Example first

AreaSupported
LayoutFlexbox — direction, gap, grow/shrink, align/justify, wrap, position, z-index
BoxesPadding/margin shorthands, borders, border-radius, aspect-ratio, overflow scroll
TypeFont shorthand, size, weight, text-align/decoration, custom fonts with build-time glyph subsetting
ColorAll CSS formats plus the named colors
States & themes:pressed, CSS variables, theme imports
CostZero at runtime — layout resolves at build time, styles compile to draw lists
© 2026 typeCAD — code-defined electronics github