Brush Project Structure: Workspace Layout, Applications, and Core Crates

The Brush project is organized as a Rust workspace containing four cross-platform applications and sixteen specialized crates that collectively implement a 3D Gaussian splatting pipeline with support for desktop, mobile, web, and CLI targets.

The Brush repository follows a modular architecture defined in the top-level Cargo.toml, which declares a workspace grouping independent yet interoperable components. This structure separates rendering algorithms, training logic, and platform-specific user interfaces, enabling the codebase to target native GPU backends (CUDA/Metal) and WebAssembly simultaneously according to the ArthurBrussee/brush source code.

Workspace Structure and Configuration

The foundation of the Brush project structure resides in the root Cargo.toml, which defines the workspace members array spanning lines 4-18. As implemented in ArthurBrussee/brush, this declaration lists every crate and app as a first-class component, allowing independent compilation or unified builds while sharing dependency patches across the entire project.

Dependency Patches

Because Brush targets WebGPU for cross-platform rendering, the workspace patches the wgpu and cubecl crates to include custom WebGPU interop and subgroup primitives. These patches, located at lines 18-34 of the top-level Cargo.toml, ensure identical shader code executes on native drivers and browser-based WebAssembly environments.

Applications (apps/)

The apps/ directory contains four distinct entry points that expose Brush functionality to different platforms and use cases.

Desktop and Mobile UI (brush-app)

The brush-app crate delivers a full-featured graphical interface built with eframe and egui, targeting desktop and Android devices. The application entry point at apps/brush-app/src/main.rs initializes the GUI event loop, while Android-specific Gradle build files in the same directory handle mobile deployment.

Command-Line Interface (brush-cli)

For automated training and batch processing, brush-cli exposes subcommands including train, render, and debug utilities. The command definitions reside in apps/brush-cli/src/lib.rs, which parses arguments and delegates to the underlying brush-process and brush-train crates. Users invoke the CLI via the brush binary installed from this crate.

WebAssembly Demo (brush-js)

The brush-js application compiles the rendering pipeline to WebAssembly using wasm-pack, enabling browser-based Gaussian splatting visualization. The TypeScript entry point at apps/brush-js/web/src/main.ts initializes the WASM module and connects it to a Vite-based frontend, configured via apps/brush-js/web/vite.config.ts.

C Bindings (brush-c)

Though not currently listed in the workspace members array, brush-c provides minimal C bindings for integrating Brush into existing C/C++ codebases. The FFI interface is implemented in apps/brush-c/src/lib.rs, exposing core splatting functions to foreign code.

Core Library Crates

The crates/ directory houses sixteen specialized libraries that implement the mathematical and rendering operations, organized by functional responsibility.

Rendering Pipeline

brush-render implements the forward-rendering pipeline—culing, depth-sorting, and rasterizing 3D Gaussians. In crates/brush-render/src/lib.rs (lines 12-35), the crate exposes the render_splats function and SplatOps trait, which abstract GPU kernel execution across different backends. The companion crate brush-render-bwd mirrors this structure but implements gradient-aware rasterization for differentiable rendering during training.

Data Management

brush-dataset handles loaders for COLMAP and Nerfstudio data formats, parsing camera parameters and images in src/scene_loader.rs. This crate relies on brush-vfs, which provides a virtual-file-system abstraction allowing data streams from local disk, HTTP, or in-memory buffers through a unified interface defined in crates/brush-vfs/src/lib.rs.

Training Infrastructure

brush-process orchestrates the training loop through message-passing channels and configuration structs defined in src/lib.rs. This crate wires together datasets, models, and optimizers while managing state transitions. The brush-train crate builds upon this to implement high-level training logic, checkpoint scheduling, and optimizer step management.

Platform Abstractions

brush-async contains platform-agnostic async runtime helpers that bridge native Tokio runtimes and WASM single-threaded execution, located in crates/brush-async/src/lib.rs. brush-cube provides utilities for the cubecl backend required by the Burn machine learning framework.

Supporting Utilities

Additional specialized crates include brush-sort (spatial sorting algorithms), brush-prefix-sum (parallel scan operations), brush-loss (photometric loss functions), brush-serde (serialization formats), lpips and lpips-convert (perceptual image metrics), colmap-reader (COLMAP format parsing), rrfd (RAW file handling), and brush-bench-test (GPU kernel benchmarking and fuzz testing).

Implementation Examples

The modular Brush project structure enables flexible integration across different contexts.

Rendering from Rust

To render a scene using the core library:

use brush_render::{render_splats, SplatRenderMode, MainBackend};
use brush_vfs::Vfs;
use brush_dataset::Scene;

fn main() {
    // Load a scene (COLMAP or Nerfstudio format)
    let scene = Scene::load("my_dataset/scene.json").unwrap();

    // Build the renderer
    let renderer = MainBackend::default();

    // Render with default camera and mode
    let output = render_splats(
        &renderer,
        &scene,
        SplatRenderMode::Color,
        /* background */ [0.0, 0.0, 0.0].into(),
    )
    .await
    .unwrap();

    // Save the image
    output.write_to_path("render.png").unwrap();
}

Source references: crates/brush-render/src/lib.rs exposes render_splats, while crates/brush-dataset/src/scene.rs handles scene loading.

Training via CLI

The command-line interface supports headless training with viewer support:

brush train \
   --data ./my_dataset \
   --output ./results \
   --epochs 200 \
   --with-viewer

Web Deployment

To run the WebAssembly demonstration locally:

cd apps/brush-js
npm install
npm run dev   # Starts Vite with the WASM bundle

This executes the entry point at apps/brush-js/web/src/main.ts, which loads the compiled module.

Summary

  • The Brush project structure is defined by a Cargo workspace in the root Cargo.toml spanning lines 4-18, grouping four applications and sixteen crates.
  • Applications in apps/ provide platform-specific entry points: desktop/mobile GUI (brush-app), CLI tools (brush-cli), web demos (brush-js), and C bindings (brush-c).
  • Core crates separate concerns into rendering (brush-render, brush-render-bwd), data loading (brush-dataset, brush-vfs), and training orchestration (brush-process, brush-train).
  • Dependency patches for wgpu and cubecl at lines 18-34 of the workspace root enable simultaneous compilation for native CUDA/Metal and WebAssembly targets.
  • Key source files include crates/brush-render/src/lib.rs (forward rendering API), crates/brush-process/src/lib.rs (training loop), and apps/brush-cli/src/lib.rs (command definitions).

Frequently Asked Questions

What is the difference between brush-render and brush-render-bwd?

brush-render implements the forward-only rasterization pipeline for image synthesis, exposing render_splats and SplatOps traits in crates/brush-render/src/lib.rs. brush-render-bwd mirrors this structure but implements gradient-aware rasterization required for training, computing derivatives with respect to Gaussian parameters during the backward pass.

How does the Brush project support both native and web platforms?

The brush-async crate abstracts runtime differences between native Tokio and single-threaded WASM environments. Additionally, the root Cargo.toml patches wgpu and cubecl (lines 18-34) to include WebGPU interop, allowing identical GPU kernels to compile for CUDA/Metal and WebAssembly targets.

Which crate handles loading COLMAP datasets?

brush-dataset manages data ingestion for COLMAP and Nerfstudio formats, specifically through src/scene_loader.rs which parses camera intrinsics, extrinsics, and image files. This crate depends on brush-vfs to abstract file system operations, enabling the same loading code to work with local datasets, remote HTTP streams, or in-memory buffers.

Where is the training loop implemented?

The training loop resides in brush-process, which orchestrates message-passing between dataset loaders, the renderer, and optimizers in crates/brush-process/src/lib.rs. While brush-process handles the communication infrastructure, brush-train provides the high-level logic for building models, scheduling optimization steps, and recording checkpoints.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →