Reactive signals · Single-file components · Flexbox layout · Skia rendering
Quick start · Documentation · Tutorials · CLI reference · Architecture · Template syntax · Feature status · Guides
| Requirement | Why | Check |
|---|---|---|
| Rust 1.85+ | the workspace crates use edition 2024 | rustc --version |
| Git | scaffolds fall back to git dependencies | git --version |
| C toolchain | linker and build tools for native dependencies | see below |
Platform-specific build tools
# Linux (Debian/Ubuntu)
sudo apt-get install build-essential pkg-config libssl-dev
# macOS
xcode-select --install
# Windows
# Microsoft Visual C++ Build Tools: https://visualstudio.microsoft.com/visual-cpp-build-tools/cargo install veloxcThat puts a single binary, veloxc, on your PATH. Every command on this
page is veloxc <subcommand> — veloxc --help lists them, and
veloxc <subcommand> --help is the authoritative flag reference.
veloxc version # prints the CLI version and your platformTip
Working from a checkout? Install the main branch directly instead of waiting
for a crates.io release:
cargo install --path veloxc --force# 1. Scaffold
veloxc init my-first-app
cd my-first-app
# 2. Watch, build, run — reload with `r`, quit with `q`
veloxc dev
# 3. One-shot build
veloxc build
veloxc build --release
# 4. Build and launch once
veloxc runveloxc dev watches the project, rebuilds on save, and re-launches the app —
hot reload means the running window updates as soon as the build lands:
A quick veloxc lint src/App.vx checks the generated component before you edit
anything.
Commands run from the current working directory, not from the Velox source tree.
Important
Where the scaffold points at Velox. veloxc init wires your Cargo.toml
to the workspace crates in one of three ways:
| How you got the CLI | Dependencies written into your project |
|---|---|
cargo install --path veloxc (from a clone) |
relative path = … entries into that clone |
veloxc init --local <path> |
the same, pinned to the checkout you name |
cargo install veloxc (crates.io) |
git = "https://github.com/fahimaloy/velox" pinned to the commit the binary was built from |
A crates.io-installed veloxc has no git metadata; generate_cargo_toml detects rev == "unknown" (the VELOX_GIT_REV_FALLBACK sentinel) and emits plain version dependencies, so the scaffold is always resolvable. See CLI Reference.
my-first-app/
├── Cargo.toml dependencies wired to Velox
├── build.rs compiles .vx files during `cargo build`
├── README.md
├── assets/
│ ├── velox-logo.svg
│ └── velox-logo.png
└── src/
├── App.vx entry component
├── main.rs Rust entry point
└── components/
├── Confirm.vx
├── Modal.vx
├── TodoInput.vx
├── TodoItem.vx
└── Todos.vx
Every subcommand veloxc exposes. Flags below are transcribed from
veloxc <command> --help; nothing here is inferred.
| Command | What it does |
|---|---|
veloxc init |
Scaffold a new project |
veloxc build |
Build the project, or compile one .vx file to Rust |
veloxc run |
Build and run once |
veloxc dev |
Watch, rebuild, restart |
veloxc lint |
Check .vx files |
veloxc add component |
Generate a component scaffold |
veloxc version |
Version and platform info |
veloxc init <name> [options]
| Flag | Default | Description |
|---|---|---|
-t, --template <name> |
default |
Template variant |
--local <path> |
— | Wire the scaffold to a local Velox checkout |
<name> is a package name or a path — myapp, /tmp/myapp,
../projects/myapp. Dots and whitespace normalize to -; the name must start
with a letter or _.
veloxc init myapp # in the current directory
veloxc init /tmp/myapp # absolute path
veloxc init ../projects/myapp # relative pathveloxc build [--release] # the current project
veloxc build <file.vx> [-o <dir>] # one component tree
| Flag | Applies to | Effect |
|---|---|---|
--release |
project build | optimized binary in target/release/ |
-o, --out-dir <dir> |
single-file mode | where generated .rs files land (default target/velox-gen) |
Note
Single-file mode recurses through every component the input imports and emits Rust source for inspection. It is not an executable.
veloxc run [--release]
Build and launch in one step — equivalent to cargo build && cargo run, with
--release passed through.
veloxc dev [options]
| Flag | Default | Description |
|---|---|---|
-w, --watch <path> |
. |
Project root to build and watch |
--release |
— | Build in release mode |
Watching is event-driven — notify uses inotify on Linux rather than a
polling interval, so a save reaches the build loop the moment it lands.
target/, .git/, .vscode/, .idea/ and dot-directories are excluded from
the watch.
file change (inotify)
↓
50 ms debounce
↓
cargo build ← full rebuild
↓
app process stopped and re-spawned
The dev server also opens an HMR control channel on 127.0.0.1:31313 and
sends the app a FullReload message — the app exits and is restarted.
Module-level HotReload exists in the protocol but is not implemented.
Type a command and press Enter:
| Key | Action |
|---|---|
r |
rebuild |
c |
clear |
q |
quit |
Warning
veloxc dev is a watch-and-rebuild loop, not hot reload. In-process state
does not survive a restart — treat the rebuild time as the cost of every save.
Raising the inotify watch limit (Linux)
Watching is backed by inotify, a finite kernel resource. If the limit is
exhausted the dev server reports the error and keeps running, but files may stop
being detected — press r to rebuild by hand.
sudo sysctl -w fs.inotify.max_user_watches=524288
sudo sysctl -w fs.inotify.max_user_instances=1024To persist, write those two lines to a file under /etc/sysctl.d/ and run
sudo sysctl --system.
veloxc lint [target] [--fix]
| Target | Effect |
|---|---|
| (none) | every .vx file under src/ |
src/App.vx |
a single file |
components/ |
every .vx under a directory |
--fix |
also fix trailing whitespace and a missing final newline |
Reports parse errors, reactive-idiom advisories in <script>, and every CSS
property that parses but paints nothing (see Feature status).
veloxc add component <name> [-s, --slots <NAME,NAME>]
| Flag | Description |
|---|---|
-s, --slots <NAME,NAME> |
Named slots to declare, comma-separated |
Generates src/components/<Name>.vx — <name> folds to PascalCase
(side-bar → SideBar). The implicit default slot is always created;
--slots header,footer adds named ones. The command refuses to overwrite an
existing file and must be run inside a project (it walks up looking for
src/App.vx).
veloxc add component button
veloxc add component card --slots header,footerveloxc version
Prints the CLI version, the toolchain edition and your platform.
Velox is a workspace of six published crates plus three example apps. Every crate below is on crates.io; use any combination of them.
graph TD
subgraph tool["Tooling"]
cli["veloxc — CLI and dev server"]
end
subgraph libs["Published libraries"]
sfc["velox-sfc — .vx compiler"]
rnd["velox-renderer — backends, events, paint"]
stl["velox-style — CSS cascade"]
dom["velox-dom — VNode and layout"]
cor["velox-core — signals and effects"]
end
subgraph apps["Example apps"]
ex["veloxc-init-default · dashboard · task-board"]
end
cli --> sfc
cli --> stl
cli --> rnd
rnd --> cor
rnd --> dom
rnd --> stl
stl --> dom
ex --> cor
ex --> dom
ex --> stl
ex --> rnd
ex -. build-dependency .-> cli
| Crate | Purpose | Workspace dependencies |
|---|---|---|
velox-core |
Reactive primitives: signals, effects, lifecycle hooks | — leaf |
velox-dom |
VNode types, block + flex layout, positioning, overflow |
— leaf |
velox-style |
CSS parsing, selectors, cascade; styles applied to VNode |
velox-dom |
velox-renderer |
Rendering backends, event dispatch, hit testing | velox-core, velox-dom, velox-style |
velox-sfc |
Single-file component compiler (pest grammar) → Rust | dev only: velox-core, velox-dom, velox-renderer |
veloxc |
The CLI and dev server | velox-sfc, velox-style, velox-renderer |
Notable external dependencies: cssparser + selectors in velox-style,
pest in velox-sfc, clap + anyhow + notify in veloxc, and the
optional graphics stack in velox-renderer. The example apps depend on
velox-core, velox-dom, velox-style and velox-renderer with the
skia-native feature, and use veloxc as a build-dependency.
| Feature | Enables |
|---|---|
default = [] |
nothing — opt in when you're ready |
skia |
the Skia API surface, no native dependencies |
svg |
resvg rasterisation for <img src="*.svg"> |
skia-native |
the windowed backend: winit, skia-safe, egl, glow, softbuffer — implies skia and svg |
.vx files are Velox's single-file component format:
<!-- src/App.vx -->
<template>
<div class="container">
<h1>{{ title }}</h1>
<p v-if="count > 0">Count is positive</p>
<p v-else>Count is zero or negative</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup>
use velox_core::ergonomics::Ref;
pub struct State {
count: Ref<i32>,
}
impl State {
pub fn new() -> Self {
Self { count: velox_core::r#ref!(0) }
}
// Interpolations and event handlers take `&self` — state lives in
// interior-mutable `Ref<T>` signals, not behind `&mut self`.
pub fn count(&self) -> i32 {
self.count.get()
}
pub fn increment(&self) {
self.count.set(self.count.get() + 1);
}
}
</script>
<style>
.container {
padding: 24px;
font-size: 18px;
border-radius: 8px;
opacity: 0.9;
}
</style>| Directive | Usage |
|---|---|
{{ expr }} |
Template interpolation |
v-if="cond" |
Conditional rendering |
v-else-if="cond" |
Additional condition |
v-else |
Fallback |
v-for="item in items" |
List rendering |
v-show="cond" |
Toggle display without unmounting |
v-model="field" |
Two-way binding on form controls |
@event="handler" |
Event binding |
:attr="expr" |
Attribute binding — :class, :style, :key, props |
v-slot:name / #name |
Named slot fill (the value is parsed; slot props are not bound) |
Child components are imported in <script setup> and used as elements:
<Todos />See event payload handling for on:<event>-payload
and inline closures.
What actually works today, stated plainly. Nothing here is aspirational.
| Category | Features |
|---|---|
| SFC | .vx parsing · {{ expr }} · v-if/v-else-if/v-else · component imports |
| Layout | Block layout · Flex layout · static/relative/absolute/fixed/sticky · z-index · overflow clipping |
| CSS | Selectors · cascade · font-size · font-weight · line-height · text-decoration · border-radius · opacity |
| Rendering | Skia immediate-mode paint · event hit-testing · skia-native backend |
| Events | click · input · change · keyboard · mouse |
These properties parse successfully, survive the cascade, and produce no
visual change. veloxc lint reports each one when you use it.
box-shadow · font-style · letter-spacing · visibility · overflow-x · overflow-y · background-image · transition · border-style · border-color · transform (stacking only, no visual transform)
Why isn't the reconciler in production? (read before asking)
The render loop is immediate-mode. run_window_vnode_skia takes the &VNode,
runs compute_layout over the whole tree, and paints it. There is no retained
tree, no previous frame to compare, and no patch applier.
velox-dom ships a complete, duplicate-key-safe keyed reconciler (diff::diff)
but it has zero production callers — only tests invoke it.
The renderer's reconcile_keyed_children was deleted: it had no production
callers and had a stale-content bug on key match.
v-for reordering: correctness comes from VNode child order, not from
:key. An <input> inside a reordered v-for loses focus/caret to whichever
item occupies its index. This is a known limitation, not an oversight.
Full decision record: docs/internal/RECONCILER.md
Five example apps ship in examples/:
A display or compositor is required to see a window.
git clone https://github.com/fahimaloy/velox.git
cd velox
# Build everything
cargo build --workspace
cargo build --workspace --release
# Full test suite
cargo test --workspace --all-targets
# Skia backend only
cargo build -p velox-renderer --features skia-native
# A single crate
cargo test -p velox-core
cargo test -p velox-sfc
cargo test -p velox-rendererAny workspace-wide cargo command turns on velox-renderer/skia-native,
because veloxc declares it as a dev-dependency feature and the examples
build-depend on veloxc. Expect a heavy first build.
| Document | What's in it |
|---|---|
| Documentation book | Getting started, three tutorials, feature reference, and the advanced internals |
ARCHITECTURE.md |
Workspace layout, data flow, backends |
CHANGELOG.md |
Release history and unreleased changes |
docs/src/advanced/reconciler.md |
Why :key reordering works without a production reconciler |
docs/src/advanced/rendering-pipeline.md |
How Velox paints, and the measurements behind it |
docs/src/advanced/viewport.md |
The make_view(w, h) viewport contract |
docs/src/features/events.md |
Event payloads: on:<event>-payload and inline closures |
docs/internal/ |
Audit records, plans, tasks, and the headless Skia-native CI notes |
API documentation: docs.rs/velox-core · docs.rs/veloxc · docs.rs/velox-renderer
CI runs on every push and pull request, on every branch. The blocking job
is build-test:
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace --no-fail-fastBefore opening a PR:
# Full test suite, including ignored compile and measurement tests
cargo test --workspace --all-targets
cargo test -p velox-sfc --test integration_compile -- --ignored
cargo test -p velox-renderer --test frame_cost_bench -- --ignored --nocapture
# Release build (not gated by CI)
cargo build --workspace --release
# Smoke-test the scaffolding
veloxc init test-app && cd test-app
veloxc lint src/ && veloxc build src/App.vx
cd ..Update this README when behavior changes.
Code: Dual-licensed under MIT OR Apache-2.0 — pick whichever suits your
project. See LICENSE for the MIT terms and
LICENSE-APACHE for Apache 2.0.
Copyright © 2026 FAHIM AHMED.
"Velox" is a trademark of this project. Both licenses grant the right to copy, modify, and redistribute the code and the logo as part of a Velox project or derivative. They do not grant the right to use the name or logo in a way that suggests Velox project endorsement of a third-party product.
If you want the logo in a project that is not derived from Velox, ask first — that is a trademark question, not a license one.




