Skip to content

tschk/crepuscularity

Repository files navigation

Crepuscularity

Stability: This project is unstable and in active development. APIs, CLI flags, and template semantics may change without a semver-major release until 1.0. Pin exact dependency versions and expect occasional breakage.

Think React Native turned into a systems UI toolkit: one compact .crepus language can drive GPUI desktop apps, Ratatui terminal UIs, Chromium/Firefox extensions, web output, native mobile shells, embedded panels, and LVGL Pro. Crepuscularity also ships hot reload, runtime rendering, and a GPUI desktop shell with an embedded V8 bridge for Capacitor-shaped native plugins.

Write UI in a concise, indentation-based template DSL (.crepus files). Templates compile at build time via the view! macro or render at runtime with full hot-reload support. The same .crepus syntax drives native desktop (GPUI), terminal UIs (Ratatui), browser extensions (MV3), HTML output, and React/JSX — and is the foundation for native mobile backends targeting SwiftUI and Jetpack Compose.

Use Aurorality for united SwiftUI macOS + iOS apps.

Why Crepuscularity

  • GPUI component workflow with hot reload — live template updates without recompiling app code
  • Rust-owned MV3 extension target — write popup, background, and content-script surfaces in .crepus, then emit Chromium or Firefox bundles without adopting a JavaScript framework or app bundler as the primary authoring model
  • One syntax, multiple backends — the same template works across GPUI (native desktop), HTML, React/JSX, and browser extensions today; crepuscularity-native lowers .crepus to JSON View IR for SwiftUI / Jetpack Compose shells (see examples/native-shells)
  • Polyglot plugin contract — host languages consume View IR JSON through crepus native ir or the optional crepuscularity-abi C session API, then create UI from the typed node tree; drop-in reference packages and native workspace files live under plugins/
  • Terminal UIs without a second UI languagecrepuscularity-tui maps .crepus elements, includes, slots, control flow, and Tailwind-style terminal classes onto Ratatui frames
  • Embedded panels (in testing)crepuscularity-embedded renders .crepus into an RGB565 buffer you flush over SPI (ILI9341, ST7789) or into an LTDC framebuffer on STM32/ESP32; see docs/embedded.md and examples/embedded-dashboard
  • Desktop shell for embedded guest appscrepuscularity-lite embeds V8 in a GPUI host with a Capacitor-shaped Rust bridge, optional file watching, workers, plugin capabilities, and TypeScript/TSX guest transpilation
  • Compile-time and runtime pathsview! macro for zero-overhead AOT compilation; parse_template / render_nodes for full runtime flexibility and hot reload

Quick Start

# Install the CLI
cargo install --path crates/crepuscularity-cli

# If `crepus` is not found, Cargo still installed the binary under ~/.cargo/bin — add it to PATH,
# e.g. for zsh:  export PATH="$HOME/.cargo/bin:$PATH"
# (Rustup normally prepends this for login shells; some terminals omit it.)

# Create a new GPUI app
crepus init gpui my-app
cd my-app
SDKROOT=$(xcrun --show-sdk-path) cargo run

# Or create a browser extension
crepus init webext my-extension
cd my-extension
crepus build
# Load dist/unpacked/ in chrome://extensions

Minimal target builds

Put every output in one crepus.toml, then run one command:

[[targets]]
type = "web"
id = "site"
site = "docs-site"
out = "docs-site/dist"
entry = "index.crepus"

[[targets]]
type = "lvgl"
id = "panel"
template = "ui.crepus"
out = "dist/panel.xml"
name = "Panel"
root = "screen"

[targets.vars]
device = "STM32F411"
crepus build
crepus build web
crepus build panel
crepus build --target panel

Rust build scripts can use the same manifest for render-output targets:

let artifacts = crepuscularity::target::write_manifest_file("crepus.toml")?;

Template Syntax (or you can write React JSX)

div w-full h-full bg-zinc-950 text-white flex flex-col p-8
  div text-2xl font-bold mb-4
    "Hello {name}"
  if {score > 50}
    div text-green-400
      "High score!"
  else
    div text-red-400
      "Keep going"

Features

  • .crepus syntax — indentation-based, Tailwind-style classes
  • Semantic native tags — optional component tags for native shells (navigationstack, sidebar, item, menu, label, SF symbols, etc. in the SwiftUI swiftgen path)
  • Control flowif/else, match, for
  • String interpolation"Hello {name}"
  • Expressions — arithmetic, comparison, logical operators, property access
  • Components — single-file and multi-component files with slot support
  • Hot reload — live template updates via the runtime renderer
  • Web SEO metadatacrepus.toml web targets generate document head tags, social cards, robots.txt, and sitemap.xml
  • Browser extensionscrepus webext commands for MV3 extensions; typed Rust browser API wrappers; popup pre-rendered at build time; release WASM optimization when wasm-opt is installed; no JS bundler needed
  • IDE integration — structured JSON events with --emit-events

Output Targets

The .crepus DSL is the primary language. Each output target is a renderer that consumes the same parsed template — not a different framework.

Crate Output
crepuscularity-gpui Native desktop (GPUI elements) — primary target
crepuscularity-tui Ratatui terminal frames with .crepus templates and typed handles
crepuscularity-lite GPUI desktop shell with embedded V8, Rust plugins, and guest workers
crepuscularity-native View IR JSON for SwiftUI / Compose host apps (not an on-screen renderer)
crepuscularity-abi Optional C ABI sessions for in-process IR rendering and event dispatch
crepuscularity-web HTML strings — server rendering, WASM, browser extensions
crepuscularity-webext MV3 browser extensions — manifest, assets, capability scanning
crepuscularity-embedded UNSTABLE — RGB565 framebuffer for SPI/LTDC panels (ILI9341, ST7789, ESP-LCD, …); see docs/embedded.md

JSX/HTML tag syntax is supported as an input format in the core parser — the same .crepus templates can be written in either indentation style or <tag> style, and both compile to the same AST.

CLI Commands

crepus init <kind> <name>            # Scaffold web, webext, tui, native, ios, or gpui apps
crepus new <name>                    # Alias for crepus init gpui <name>
crepus dev [--emit-events]           # Hot-reload dev loop
crepus build [type-or-id] [--target ID]  # Build crepus.toml targets, selected type/id, or cargo fallback
crepus preview <file.crepus>         # Live preview

crepus web new <name>                # Alias for crepus init web <name>
crepus webext new <name>             # Alias for crepus init webext <name>
crepus webext build [--app PATH] [--browser chromium|firefox]  # Build to dist/unpacked/ or dist/<browser>/
crepus webext manifest [--app PATH] [--browser chromium|firefox]  # Print manifest.json

crepus aurora dev [--watch DIR]      # SwiftUI hot-reload dev server (via Aurorality)
crepus aurora build [--watch DIR]    # Compile .crepus → View IR JSON
crepus aurora new <name>             # Scaffold SwiftUI + Rust project

crepus ios new <name>                # Alias for crepus init ios <name>
crepus ios generate [--dir]          # Run xcodegen (finds crepus.toml [ios] upward)
crepus ios build [--dir] [...]       # Simulator build via xcodebuild

crepus native ir <file.crepus>       # Emit View IR JSON for plugins and native shells
crepus native sync <file.crepus> --dir <app> [--out FILE]  # Write View IR fixtures into native containers

crepus embedded check <file.crepus>  # UNSTABLE: validate template for firmware CI
crepus embedded snapshot … --out x.ppm  # UNSTABLE: debug PPM only (use Ui + rgb565() on device)

Documentation

  • Rendered site (GitHub Pages): here — WASM landing page plus HTML generated from the Markdown in docs/. Built in CI with crepus web build --manifest docs-site/crepus.toml.
  • Sources: docs/README.md indexes DSL (including SwiftUI semantic tag mappings), components, CLI, runtime/reactivity, GPUI, TUI, embedded / framebuffer (UNSTABLE — STM32, ESP32, SPI panels), Lite, native shells, polyglot plugins, and extensions. Compiler-focused detail stays in-repo as CREPUS_WEB_IMPLEMENTATION_SPEC.md but is not shipped on the public docs site.
  • Native shells: examples/native-shells — SwiftPM (ios/), Gradle (android/), and shared View IR fixture.json next to crepuscularity-native (replaces the old separate crepuscularity-native-ui checkout).
  • Contributors & coding agents: root AGENTS.md is the canonical instructions (macOS SDKROOT, cargo fmt / clippy / test before push, workspace layout, DSL notes). CLAUDE.md is a symlink to AGENTS.md so duplicate context files cannot drift.

GPUI — Tailwind Class Support

The GPUI renderer maps Tailwind-style class strings to native GPUI style calls. This is a native desktop renderer, not a browser, so the mapping is intentionally selective.

Supported

Category Classes
Layout flex, grid, block, hidden, flex-col/row, flex-wrap, flex-1/auto/none, grow, shrink
Justify / Align justify-start/end/center/between/around, items-start/end/center/baseline, content-*
Align self self-start, self-end, self-center, self-stretch, self-baseline, self-auto
Sizing w-*, h-*, size-*, min-w/h-*, max-w/h-* — numbers, fractions, full, auto, [Npx]
Aspect ratio aspect-square, aspect-video, aspect-auto, aspect-[N/M]
Spacing p-*, px-*, py-*, pt/pb/pl/pr-*, m-*, mx/my-*, mt/mb/ml/mr-*, gap-*, gap-x/y-*
Position absolute, relative, top/bottom/left/right/inset-*
Overflow overflow-hidden, overflow-x/y-hidden
Colors Full Tailwind palette (bg/text/border-{family}-{shade}), hex (bg-[#rrggbb]), hsla, rgba with /alpha
Border border, border-0/2/4/8, per-side border-t/b/l/r-*, border-dashed
Border radius rounded-* — all sizes, all sides, all corners
Typography Font weight (font-thinfont-black), style (italic), size (text-xstext-9xl, text-[Npx])
Typography Alignment (text-left/center/right), decoration (underline, line-through, decoration-*)
Typography Line height (leading-*, leading-[N]), tracking (tracking-*, tracking-[Npx]), truncation (truncate, text-ellipsis, whitespace-nowrap)
Typography Text transform (uppercase, lowercase, capitalize, normal-case)
Font font-['Family'], line-clamp-N, font-features via FontFeatures API
Shadow shadow-2xsshadow-2xl, shadow-none
Ring ring, ring-0/1/2/4/8, ring-[Npx] — rendered as box-shadow spread
Opacity opacity-N (0–100), opacity-{expr}
Cursor cursor-default/pointer/text/move/not-allowed and all resize variants
Grid grid-cols-N, grid-rows-N, col-span-N, col-start/end-N, row-span/start/end-N
Arbitrary values w-[Npx], bg-[#hex], text-[size], rounded-[Npx], border-[Npx], aspect-[N/M], etc.
Dynamic context bg-{expr}, text-{expr}, border-{expr}, opacity-{expr} — evaluated against template context
State prefixes hover:, focus:, active: — accepted silently (state styling requires .hover()/.on_click() handlers in code)

Not Supported (GPUI hard limits)

These cannot be added without forking GPUI itself:

Gap Reason
ring-{color} Ring color customisation requires architectural change; default ring is blue-500/50
md: / lg: / xl: breakpoints No CSS cascade or viewport queries — GPUI uses Taffy layout
dark: variant No built-in dark mode detection — use bg-{theme.surface} context expressions instead
group-hover: / peer: No selector/relationship system
before: / after: pseudo-elements No pseudo-elements — add child div nodes in the template instead
z-* (z-index) GPUI uses painter's algorithm / GPU layers, not z-index
float Not supported by Taffy layout engine
ring-inset GPUI has no inset box-shadow — accepted silently

Project Structure

crates/
  crepuscularity/           Facade re-exporting prelude
  crepuscularity-core/      AST, parser, evaluator
  crepuscularity_macros/    Compile-time view! proc-macro
  crepuscularity-runtime/   Hot-reload renderer (Tailwind → GPUI styler)
  crepuscularity-web/       HTML backend
  crepuscularity-webext/    Browser extension support
  crepuscularity-gpui/      GPUI prelude + view! macro
  crepuscularity-tui/       Ratatui backend + template_refs! handles
  crepuscularity-lite/      GPUI + V8 shell and native plugin bridge
  crepuscularity-lite-macros/ Compile-time macros for lite plugin bindings
  crepuscularity-native/    View IR JSON for SwiftUI / Compose shells
  crepuscularity-reactive/  WASM signals, memos, effects, hydration lifecycle
  crepuscularity-ssr/       Server-rendering helpers
  crepuscularity-dev/       crepus-dev hot-reload server
  crepuscularity-cli/       crepus CLI
examples/
  examples.toml             Catalog by target (see examples/README.md)
  extensions/               Git symlinks to undivisible/anywhere, rs_vimium
  weather/                  Weather app example
  quicknote/                Browser extension example (in-repo)
  native-shells/            SwiftPM and Gradle View IR hosts

Building

Install the CLI:

cargo install --path crates/crepuscularity-cli

Pre-built binaries for Linux and Windows are in the repo root (crepus-linux-x86_64, crepus-windows-x86_64.exe).

On macOS, GPUI requires the Xcode SDK path:

SDKROOT=$(xcrun --show-sdk-path) cargo build

When Xcode uses the downloadable Metal Toolchain component, let Cargo inherit the exact Xcode environment GPUI's build script needs:

eval "$(scripts/metal-env.sh)"
cargo build
scripts/metal-env.sh -- cargo check -p crepuscularity-gpui
scripts/metal-env.sh --check

The required variables are SDKROOT for SDK headers, DEVELOPER_DIR for the active Xcode, and TOOLCHAINS=Metal for xcrun toolchain selection. scripts/metal-env.sh reads the downloaded Metal toolchain search path from xcodebuild -showComponent MetalToolchain -json, exports the short selector that xcrun -sdk macosx metal accepts, and prepends Metal.xctoolchain/usr/bin to PATH for direct metal / metallib probes. If --check reports xcrun_metal=failed, run xcodebuild -downloadComponent MetalToolchain or install the component from Xcode Settings > Components before debugging Cargo code.

License

Mozilla Public License 2.0 — see LICENSE.

About

write react for gpui tui and embedded, write rust for web extensions, write both for websites, swiftui, mobile apps and more.

Topics

Resources

License

Stars

Watchers

Forks

Contributors