An open API service indexing awesome lists of open source software.

https://github.com/tschk/crepuscularity

write react for gpui tui and embedded, write rust for web extensions, write both for websites, swiftui, mobile apps and more.
https://github.com/tschk/crepuscularity

crepuscularity gpui jetpack-compose mv3 mv3-extension rust swiftui wasm

Last synced: 21 days ago
JSON representation

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

Awesome Lists containing this project

README

          

# 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 native capabilities.

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](https://github.com/tschk/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`](examples/native-shells/README.md))
- **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/`](plugins/README.md)
- **Terminal UIs without a second UI language** — **`crepuscularity-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`](docs/embedded.md) and [`examples/embedded-dashboard`](examples/embedded-dashboard/README.md)
- **Desktop shell for embedded guest apps** — **`crepuscularity-lite`** embeds V8 in a GPUI host with a Rust native-capability bridge, optional file watching, workers, plugin capabilities, and TypeScript/TSX guest transpilation
- **Compile-time and runtime paths** — `view!` macro for zero-overhead AOT compilation; `parse_template` / `render_nodes` for full runtime flexibility and hot reload

## Quick Start

```bash
# 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:

```toml
[[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"
```

```bash
crepus build
crepus build web
crepus build panel
crepus build --target panel
```

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

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

## Template Syntax (or you can write React JSX)

```text
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 flow** — `if/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 metadata** — `crepus.toml` web targets generate document head tags, social cards, `robots.txt`, and `sitemap.xml`
- **Browser extensions** — `crepus 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`](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 `` style, and both compile to the same AST.

## CLI Commands

```bash
crepus init # Scaffold web, webext, tui, mobile, native, ios, or gpui apps
crepus new # Alias for crepus init gpui
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 # Live preview

crepus web new # Alias for crepus init web
crepus webext new # Alias for crepus init webext
crepus webext build [--app PATH] [--browser chromium|firefox] # Build to dist/unpacked/ or dist//
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 # Scaffold SwiftUI + Rust project

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

crepus mobile new # Preferred iOS + Android scaffold
crepus mobile dev [--platform all] # View IR hot-reload server on port 4001
crepus mobile build --platform android|ios|all
crepus mobile run --platform android|ios

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

crepus embedded check # 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](https://crepuscularity.undivisible.dev) — WASM landing page plus HTML generated from the Markdown in [`docs/`](docs/). Built in CI with `crepus web build --manifest docs-site/crepus.toml`.
- **Sources:** [docs/README.md](docs/README.md) indexes [DSL](docs/dsl.md) (including SwiftUI semantic tag mappings), [components](docs/components.md), [CLI](docs/cli.md), [runtime/reactivity](docs/runtime.md), [GPUI](docs/gpui.md), [TUI](docs/tui.md), [embedded / framebuffer](docs/embedded.md) (**UNSTABLE** — STM32, ESP32, SPI panels), [Lite](docs/lite.md), [native shells](docs/native.md), [polyglot plugins](docs/polyglot.md), and [extensions](docs/webext.md). Compiler-focused detail stays in-repo as [CREPUS_WEB_IMPLEMENTATION_SPEC.md](docs/CREPUS_WEB_IMPLEMENTATION_SPEC.md) but is not shipped on the public docs site.
- **Native shells:** [examples/native-shells](examples/native-shells/README.md) — SwiftUI/XcodeGen (**`ios/`**), Gradle/Compose (**`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`**](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-thin` → `font-black`), style (`italic`), size (`text-xs` → `text-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-2xs` → `shadow-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

```text
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-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/ SwiftUI/XcodeGen and Gradle View IR hosts
```

## Building

Install the CLI:

```bash
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:

```bash
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:

```bash
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](LICENSE).