crepuscularity-cli 0.7.1

crepus CLI — scaffolding and builds for Crepuscularity (UNSTABLE; in active development).
# 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.

The first GPUI component and runtime system with hot reloading, and the first non-web-language, plug-and-play browser extension framework. It also ships a Ratatui terminal backend 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.

## Why Crepuscularity

- **First GPUI component system with hot reload** — live template updates without recompiling; no other GPUI framework offers this
- **First plug-and-play browser extension framework in Rust** — write your popup/background/content scripts in `.crepus`, get a MV3-compliant extension bundle out; no JavaScript framework or bundler required
- **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))
- **Terminal UIs without a second UI language** — **`crepuscularity-tui`** maps `.crepus` elements, includes, slots, control flow, and Tailwind-style terminal classes onto Ratatui frames
- **Desktop shell for embedded guest apps** — **`crepuscularity-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 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 new my-app
cd my-app
SDKROOT=$(xcrun --show-sdk-path) cargo run

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

## Template Syntax

```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
- **Browser extensions** — `crepus webext` commands for MV3 extensions; popup pre-rendered at build time; 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-web`    | HTML strings — server rendering, WASM, browser extensions      |
| `crepuscularity-webext` | MV3 browser extensions — manifest, assets, capability scanning |


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

```bash
crepus new <name>                    # Scaffold GPUI app
crepus dev [--emit-events]           # Hot-reload dev loop
crepus build [--release]             # Build wrapper
crepus preview <file.crepus>         # Live preview

crepus webext new <name>             # Scaffold browser extension
crepus webext build [--app PATH]     # Build to dist/unpacked/ (WASM + manifest + popup pre-render)
crepus webext manifest               # Print manifest.json

crepus ios new <name>                # XcodeGen + SwiftPM NativeShell (View IR) host app
crepus ios generate [--dir]          # Run xcodegen (finds crepus.toml [ios] upward)
crepus ios build [--dir] [...]       # Simulator build via xcodebuild
```

## 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 --site docs-site`.
- **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), [Lite](docs/lite.md), [native shells](docs/native.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) — 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`**](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-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/
  weather/                  Weather app example
  quicknote/                Browser extension example
  native-shells/            SwiftPM 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).