Skip to content

Repository files navigation

GiftUI

GiftUI is an experimental declarative user-interface framework for embedded systems, inspired by SwiftUI's source-level model.

This repository contains the operable macOS simulator for PoC A. It includes generic view expansion, deterministic stack layout, runtime-owned @State, full-root invalidation, button hit testing, backend-independent display lists, an in-memory RGBA framebuffer, a bounded RGB565 tile renderer, a compiled bitmap font, AppKit presentation, and the interactive thermostat example.

Requirements

  • macOS 15 or newer
  • Xcode 16.3 or newer
  • Swift 6 toolchain
  • Xcode command-line tools

Check the local setup:

scripts/check-environment.sh

Build and test

swift build
swift test

Run the simulator demo:

swift run GiftUIExampleThermostat

The demo opens a 720×720 point window that presents a 240×240 logical RGBA framebuffer at 3× scale with nearest-neighbor interpolation. Click - and + to update the runtime-owned target temperature and redraw the complete view graph.

Raspberry Pi 1 cross-compilation

The project pins both the official Swift.org 6.3.2 macOS compiler and an ARMv6 SDK for Raspberry Pi OS Bookworm. They are downloaded and unpacked into the ignored .toolchains/ directory, without modifying /opt, Xcode, or the global Swift installation. Allow roughly 8 GB of free disk space for the cached packages and unpacked tools.

Set up and verify the toolchain:

scripts/raspberry-pi/setup-toolchain.sh
scripts/raspberry-pi/doctor.sh --probe

Cross-build a Raspberry Pi executable product:

scripts/raspberry-pi/build.sh \
--product GiftUIExampleThermostatRaspberryPi

Configure machine-local deployment defaults:

cp scripts/raspberry-pi/local.env.example \
scripts/raspberry-pi/local.env

Then deploy atomically over SSH:

scripts/raspberry-pi/deploy.sh \
--product GiftUIExampleThermostatRaspberryPi

The Raspberry Pi executable uses the kernel-managed framebuffer path, which is the preferred first integration for the 3.5-inch PiScreen: the OS driver owns SPI and panel initialization, and GiftUI writes bounded RGB565 tiles through /dev/fb1. The first frame initializes the full display; later frames update only the union of the previous and current UI bounds, leaving unchanged pixels in the kernel framebuffer and panel GRAM. The default 240×240 configuration uses a 240×16×2-byte (7,680-byte) pixel buffer instead of a 230,400-byte RGBA surface. The device path, logical dimensions, and rotation are runtime options:

GiftUIExampleThermostatRaspberryPi \
--display fbdev \
--device /dev/fb1 \
--width 240 \
--height 240 \
--rotation 0 \
--touch

Touch input is read from /dev/input/event0 by default and maps evdev absolute coordinates through the framebuffer's aspect-fit and rotation transform. Use --touch-device for a stable device path; runtime swap/invert options are available for panels whose Device Tree overlay does not calibrate the axes.

Enable three active-low GPIO buttons with internal pull-ups:

GiftUIExampleThermostatRaspberryPi \
--device /dev/fb1 \
--gpio-buttons

The defaults use BCM GPIO 17 for previous, 27 for next, and 22 for activate. Previous/next move an amber focus border; activate dispatches the focused GiftUI button. All GPIO lines, polarity, bias, and debounce timing are configurable through --help.

Use --once for a one-frame hardware smoke test and --help for all options. The adapter accepts 16-, 24-, or 32-bit framebuffer formats, honors device stride, converts RGB565 tiles to the reported device bitfields, and aspect-fits with nearest-neighbor scaling. Logical dimensions outside the bounded RGB565 renderer's 480×320 limits retain the RGBA8888 compatibility path. See docs/GiftUI_Raspberry_Pi_Platform.md for PiScreen setup and runtime details.

Agent workflows are defined in skills/giftui-pi-toolchain and skills/giftui-pi-build-deploy.

Nordic nRF52840-DK development environment

The proposed microcontroller port uses a separately pinned, project-local Embedded Swift and Zephyr environment. Swift, Zephyr 4.3.0, the Zephyr SDK ARM toolchain, Nordic modules, and the locked Python environment remain under .toolchains/nrf52840/; firmware and reports remain under .build/nrf52840/. Nothing changes Xcode's selected toolchain or the global swift command.

macOS needs CMake 3.29 or newer, Ninja 1.10 or newer, Devicetree Compiler 1.6 or newer, Git, and Python 3.10 through 3.13. Python 3.12.13 is the pinned baseline. Machine-specific paths can be configured by copying scripts/nrf52840/local.env.example to the ignored scripts/nrf52840/local.env.

Set up and run the hardware-free C-to-Swift Zephyr probe:

scripts/nrf52840/setup-toolchain.sh
scripts/nrf52840/doctor.sh --probe

Activate paths in an interactive shell only when needed:

source scripts/nrf52840/env.sh

Build a named firmware application:

scripts/nrf52840/build.sh --application skeleton

build.sh emits the ELF, HEX, map, resolved Devicetree, section/symbol data, and size report. Flashing is never a build side effect. A connected board is changed only through an explicit command:

scripts/nrf52840/flash.sh --application skeleton

The included probe proves Zephyr can call an Embedded Swift function for the nRF52840 target and exercises the DK's first LED/button when flashed. It is a toolchain milestone, not the completed thermostat, ILI9486 display, or ADS7846 touch port. Those later phases remain governed by docs/GiftUI_nRF52840_DK_Platform_Spec.md.

The skeleton application is the first application-shaped Swift firmware. Swift owns its persistent event loop and calls a narrow Zephyr bridge for time, UART logging, LED1, and Button 1. LED1 blinks while idle and remains lit while Button 1 is held. It intentionally stops before the static GiftUI runtime, RGB565 renderer, ILI9486 display, and ADS7846 touch phases.

The Phase 5 ili9486 application now provides project-local ILI9486 SPI transport at a conservative 4 MHz, an eight-bar C/Zephyr diagnostic, and the portable thermostat rendered by Embedded Swift through bounded 480 × 4 RGB565 tiles. Build and inspect it without changing a connected board:

scripts/nrf52840/build.sh --application ili9486

The tracked overlay intentionally omits backlight control until the exact PiScreen polarity and transistor stage are verified. Hardware provenance, continuity, power, flashing, visual checks, and measurements are tracked in docs/GiftUI_ILI9486_Bring_Up_Record.md. The Phase 5 hardware gate remains open; successful compilation is not a claim of tested board support.

The same application now includes the hardware-free Phase 6 ADS7846 path: a separate 2 MHz touch device on the shared SPI bus, bounded five-point calibration, median and pressure filtering, rotation-aware pointer events, and static thermostat hit testing with typed action dispatch. The physical touch gate and its 100-press-per-control acceptance matrix are tracked in docs/GiftUI_ADS7846_Bring_Up_Record.md. No board was flashed while implementing this path.

Phase 7 adds retained-GRAM dirty updates, bounded SPI segmentation, runtime stack and latency telemetry, explicit heap exclusion, rate-limited fault counters, and a one-minute endurance heartbeat. Static layout comparison narrows a 21→22 thermostat update to 24 × 12 pixels; the solid-rectangle path writes 648 RGB565 payload bytes instead of rerasterizing the previous 7,168-byte root region. Connected-board timing and soak results belong in docs/GiftUI_PiScreen_Phase_7_Validation_Record.md; the Phase 7 gate remains open until those physical checks pass.

Swift 6.3.2 names its bundled ARMv7E-M standard module armv7em-none-none-eabi. Zephyr supplies the Cortex-M4F and -mfloat-abi=hard flags, and the build rejects firmware whose ELF does not declare the VFP hard-float calling convention.

Agent workflows are defined in skills/giftui-nrf-toolchain and skills/giftui-nrf-build-flash.

Debug in Xcode

No generated .xcodeproj is required. Open the package directly:

open Package.swift

Choose the GiftUIExampleThermostat scheme and run it with the My Mac destination. Breakpoints can be placed in the example, runtime, framebuffer, or simulator targets.

Package layout

Sources/
├── GiftUI/ # Portable declarations and semantic contracts
├── GiftUIDynamicConveniences/ # Opt-in String and callback APIs
├── GiftUIRuntimeDynamic/ # Replaceable dynamic PoC runtime
├── GiftUIBackendFramebuffer/ # Platform-neutral RGBA framebuffer
├── GiftUIBackendRGB565/ # Bounded RGB565 scan-line/tile renderer
├── GiftUIInputADS7846/ # Bounded resistive-touch calibration/filter
├── GiftUIBuiltinFont/ # Shared allocation-free bitmap glyphs
├── GiftUISimulatorMac/ # AppKit/CoreGraphics presentation shell
├── GiftUIPlatformLinux/ # Linux loop and framebuffer presentation
├── GiftUIPlatformRaspberryPi/ # Raspberry Pi defaults/configuration
├── GiftUIExampleThermostatView/ # Shared platform-neutral client view
├── GiftUIExampleThermostat/ # Runnable macOS client
└── GiftUIExampleThermostatRaspberryPi/ # Runnable Raspberry Pi client
Tests/
├── GiftUITests/
├── GiftUIDynamicConveniencesTests/
├── GiftUIRuntimeDynamicTests/
├── GiftUIBackendFramebufferTests/
├── GiftUIBackendRGB565Tests/
├── GiftUIIntegrationTests/
├── GiftUIPlatformLinuxTests/
└── GiftUIPlatformRaspberryPiTests/

Portable application views import only GiftUI. The current thermostat also imports GiftUIDynamicConveniences because it uses interpolated String text and escaping button callbacks. AppKit and CoreGraphics are isolated to GiftUISimulatorMac; Linux framebuffer and Raspberry Pi configuration code are isolated to their platform modules.

The implementation specifications are in docs/GiftUI_Framework_Spec.md and docs/GiftUI_PoC_A_macOS_Simulator_Spec.md. The reviewed, staged implementation path from the current dynamic PoC to separate portable/static and dynamic profiles is in docs/GiftUI_Runtime_Profile_Migration_Plan.md. The proposed Embedded Swift/Zephyr port for the Nordic nRF52840-DK and an ILI9486/ADS7846 PiScreen is specified separately in docs/GiftUI_nRF52840_DK_Platform_Spec.md. The separate KMRTM24024-SPI/ILI9341 240 × 320 firmware now includes an XPT2046-compatible 2 MHz shared-SPI transport, five-point calibration, and static thermostat touch dispatch. Optional GRAM readback and advanced rendering work remain specified in docs/GiftUI_KMRTM24024_SPI_nRF52840_Spec.md.

PoC runtime constraints

The current PoC intentionally uses heap-backed arrays and dictionaries, escaping button closures, String, task-local build context, a full RGBA framebuffer, and full-root redraws. The runtime and backend already have useful module seams, but some dynamic storage still lives in the client-facing GiftUI module. The runtime-profile migration plan inventories that coupling instead of treating the present module layout as allocation-free readiness.

Core implementation status

The PoC Core implements fixed generic result-builder composition through the five-child acceptance arity, branch-specific structural state identity, proposal-based measure/place layout, checked layout arithmetic, render-operation sinks, frame-consistent interaction snapshots, and serialized input dispatch. Dynamic runtimes can retain operations in a DisplayList; allocation-bounded runtimes can provide a custom RenderOperationSink and report capacity exhaustion without changing view declarations.

Hit testing is resolved by Core against the interaction snapshot built for the presented frame. Later, deeper regions win when controls overlap. State writes that occur while a frame is being emitted leave the application invalid so the next render delivers the update; multiple writes before that render coalesce into one frame.

Structural identity is intentionally topology-based for PoC A. Reordering or inserting siblings can therefore move state between paths. Explicit identity and reconciliation remain future static/runtime work. Identified, non-closure button actions, bounded decimal text, and the fixed node/action arena now combine with typed numeric state slots to provide the portable runtime path. The class-backed @State wrapper remains a dynamic-runtime API.

About

GiftUI is a declarative user-interface framework for embedded systems, inspired by SwiftUI's source-level model

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages