# How to Contribute to the Brush Project: A Complete Guide for 3D Gaussian Splat Developers

> Learn how to contribute to the Brush project by forking the repo, setting up Rust, running tests, and submitting changes with conventional commits. A complete guide for 3D Gaussian Splat developers.

- Repository: [Arthur Brussee/brush](https://github.com/ArthurBrussee/brush)
- Tags: how-to-guide
- Published: 2026-05-14

---

**To contribute to the Brush project, fork the repository, install Rust ≥ 1.88 with Android and WASM targets, run `cargo test --all` to verify your setup, then submit changes following the conventional commit format and the upstream CI workflow.**

Brush is a **Rust-first, cross-platform 3D reconstruction engine** that implements Gaussian splatting using the Burn machine learning framework. Whether you want to optimize GPU kernels, extend the desktop UI, or improve the WebAssembly demo, understanding the crate structure and contribution workflow is essential. This guide walks you through the exact steps needed to modify the codebase at `github.com/ArthurBrussee/brush` and submit a successful pull request.

## Understanding the Brush Architecture

Brush is organized as a Cargo workspace with separate crates handling distinct stages of the 3D reconstruction pipeline. Before contributing, identify which crate aligns with your goal:

- **brush-render** – Core forward rendering kernels located in [`crates/brush-render/src/kernels/map_gaussians.rs`](https://github.com/ArthurBrussee/brush/blob/main/crates/brush-render/src/kernels/map_gaussians.rs) handling rasterization and splat mapping.
- **brush-render-bwd** – Back-propagation kernels for gradient-based training in [`crates/brush-render-bwd/src/kernels/rasterize_backwards.rs`](https://github.com/ArthurBrussee/brush/blob/main/crates/brush-render-bwd/src/kernels/rasterize_backwards.rs).
- **brush-loss** – Loss functions and training utilities in [`crates/brush-loss/src/lib.rs`](https://github.com/ArthurBrussee/brush/blob/main/crates/brush-loss/src/lib.rs).
- **brush-app** – Native desktop viewer and trainer built with WGPU, with UI code in [`apps/brush-app/src/ui/app.rs`](https://github.com/ArthurBrussee/brush/blob/main/apps/brush-app/src/ui/app.rs).
- **brush-js** – WebAssembly front-end using Next.js, documented in [`apps/brush-js/README.md`](https://github.com/ArthurBrussee/brush/blob/main/apps/brush-js/README.md).
- **brush-cli** – Command-line interface for training and conversion in [`apps/brush-cli/src/lib.rs`](https://github.com/ArthurBrussee/brush/blob/main/apps/brush-cli/src/lib.rs).
- **brush-rerun** – Integration with the Rerun visualization tool.

The workspace configuration resides in the root [`Cargo.toml`](https://github.com/ArthurBrussee/brush/blob/main/Cargo.toml), which defines shared dependencies and Rust version requirements (≥ 1.88) across all crates.

## Setting Up Your Development Environment

### 1. Fork and Clone the Repository

Start by creating a personal fork via the GitHub UI, then clone it locally:

```bash
git clone https://github.com/<your-username>/brush.git
cd brush

```

### 2. Install the Rust Toolchain

Brush requires **Rust ≥ 1.88**. Install the latest stable toolchain and add required compilation targets:

```bash
rustup update stable
rustup target add aarch64-linux-android   # Required for Android builds

rustup target add wasm32-unknown-unknown  # Required for WASM builds

```

Install additional platform-specific tools:

```bash
cargo install cargo-ndk   # Android cross-compilation helper

cargo install wasm-pack   # WASM packaging utility

cargo install cargo-bloat   # Optional: binary size analysis

cargo install rerun-cli     # Optional: visualization support

```

## The Contribution Workflow

### Running the Test Suite

Verify your environment by executing the full test suite locally. Passing tests locally prevents CI failures on your pull request:

```bash
cargo test --all

```

This command mirrors the **GitHub Actions workflow** defined in [`.github/workflows/ci.yml`](https://github.com/ArthurBrussee/brush/blob/main/.github/workflows/ci.yml).

### Making Your Changes

Select the appropriate crate based on your contribution type:

- **New GPU kernels** → Modify `crates/brush-render` or `crates/brush-render-bwd`.
- **New loss terms** → Add code to `crates/brush-loss`.
- **UI modifications** → Edit files under `crates/brush-app/src/ui/`.
- **Web demo improvements** → Work within `apps/brush-js`.

Before committing, enforce the project’s code style:

```bash
cargo fmt
cargo clippy -- -D warnings

```

Every new public API requires unit or integration tests in the same crate. Reference existing test patterns, such as those in [`crates/brush-loss/tests/reference.rs`](https://github.com/ArthurBrussee/brush/blob/main/crates/brush-loss/tests/reference.rs).

### Building and Verifying Across Platforms

Validate your changes on the target platform:

| Platform | Build Command |
|----------|---------------|
| Desktop (Linux/macOS/Windows) | `cargo run --release` |
| Web (WASM) | `npm run dev` (inside `apps/brush-js`) |
| Android | `cargo ndk -t arm64-v8a -o crates/brush-app/app/src/main/jniLibs/ build --release` then `./gradlew installDebug` |

Ensure the application launches correctly and new functionality behaves as expected on your target platform.

### Committing and Submitting Your Changes

Create a feature branch using conventional commit naming:

```bash
git checkout -b feature/my-new-kernel
git add .
git commit -m "feat(render): implement fast Gaussian splat kernel"
git push origin feature/my-new-kernel

```

Open a pull request against the `main` branch. Fill out the auto-generated PR template completely. The CI pipeline will run `cargo test --all` across all supported targets. Respond promptly to reviewer feedback, which may involve updating documentation or adjusting code in files like [`Cargo.toml`](https://github.com/ArthurBrussee/brush/blob/main/Cargo.toml) or kernel implementations.

## Code Example: Adding a New Rendering Kernel

The following example demonstrates adding a custom GPU kernel to the `brush-render` crate, following the pattern established in [`crates/brush-render/src/kernels/map_gaussians.rs`](https://github.com/ArthurBrussee/brush/blob/main/crates/brush-render/src/kernels/map_gaussians.rs):

```rust
// File: crates/brush-render/src/kernels/my_custom_kernel.rs
//! A simple example kernel that multiplies splat colour by a constant factor.

use wgpu::util::DeviceExt;

/// Entry point called by the CPU side.
pub fn run_my_kernel(
    device: &wgpu::Device,
    queue: &wgpu::Queue,
    gaussian_buffer: &wgpu::Buffer,
    output_buffer: &wgpu::Buffer,
    factor: f32,
) {
    // Load the shader (WGSL) from the same directory.
    let shader = device.create_shader_module(&wgpu::ShaderModuleDescriptor {
        label: Some("my_custom_kernel"),
        source: wgpu::ShaderSource::Wgsl(include_str!("my_custom_kernel.wgsl").into()),
    });

    // Create a pipeline layout and compute pipeline.
    let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
        label: Some("my_custom_kernel_layout"),
        bind_group_layouts: &[],
        push_constant_ranges: &[],
    });

    let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
        label: Some("my_custom_kernel_pipeline"),
        layout: Some(&pipeline_layout),
        module: &shader,
        entry_point: "main",
    });

    // Encode commands.
    let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
        label: Some("my_custom_kernel_encoder"),
    });
    {
        let mut compute_pass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
            label: Some("my_custom_kernel_pass"),
        });
        compute_pass.set_pipeline(&pipeline);
        compute_pass.set_bind_group(0, &gaussian_buffer.create_bind_group(&device), &[]);
        compute_pass.set_bind_group(1, &output_buffer.create_bind_group(&device), &[]);
        compute_pass.set_push_constants(0, bytemuck::bytes_of(&factor));
        compute_pass.dispatch_workgroups( (gaussian_buffer.size() / 256) as u32, 1, 1);
    }
    queue.submit(Some(encoder.finish()));
}

```

After creating the kernel file, expose the function in [`crates/brush-render/src/lib.rs`](https://github.com/ArthurBrussee/brush/blob/main/crates/brush-render/src/lib.rs) and write a unit test verifying the output buffer values. Update the crate-level documentation using `///` comments and add a minimal example to the `examples/` folder if applicable.

## Summary

- **Fork and clone** the repository from `github.com/ArthurBrussee/brush`, then install Rust ≥ 1.88 with Android and WASM targets.
- **Target the correct crate:** use `brush-render` for GPU kernels, `brush-app` for UI changes, and `brush-js` for web improvements.
- **Validate locally** by running `cargo test --all`, `cargo fmt`, and `cargo clippy -- -D warnings` before submitting.
- **Build per platform** using `cargo run --release` for desktop, `npm run dev` for WASM, or `cargo ndk` for Android.
- **Follow conventions:** use conventional commit messages, fill out the PR template, and ensure CI passes in [`.github/workflows/ci.yml`](https://github.com/ArthurBrussee/brush/blob/main/.github/workflows/ci.yml).

## Frequently Asked Questions

### What Rust version is required to contribute to Brush?

Brush requires **Rust 1.88 or newer** as specified in the root [`Cargo.toml`](https://github.com/ArthurBrussee/brush/blob/main/Cargo.toml). Install it via `rustup update stable` and ensure you add targets for `aarch64-linux-android` and `wasm32-unknown-unknown` if you plan to build for mobile or web platforms.

### Which crate should I modify to add a new rendering kernel?

Add new forward rendering kernels to **`crates/brush-render/src/kernels/`** following the pattern in [`map_gaussians.rs`](https://github.com/ArthurBrussee/brush/blob/main/map_gaussians.rs). For back-propagation kernels used during training, use **`crates/brush-render-bwd/src/kernels/`** instead, referencing [`rasterize_backwards.rs`](https://github.com/ArthurBrussee/brush/blob/main/rasterize_backwards.rs) for implementation details.

### How do I build the web demo locally?

Navigate to `apps/brush-js` and run `npm run dev`. This requires `wasm-pack` to be installed and the `wasm32-unknown-unknown` target to be available. The README at [`apps/brush-js/README.md`](https://github.com/ArthurBrussee/brush/blob/main/apps/brush-js/README.md) contains additional build instructions for the Next.js front-end.

### How do I run the full CI pipeline locally before submitting a PR?

Execute `cargo test --all && cargo bench && npm run build` to replicate the GitHub Actions workflow defined in [`.github/workflows/ci.yml`](https://github.com/ArthurBrussee/brush/blob/main/.github/workflows/ci.yml). Running these commands ensures your changes pass formatting, linting, and testing requirements before reviewers examine your pull request.