Hoplite
A creative coding framework for Rust that gets out of your way.
Write shaders, render 3D scenes, and build visualizations with a single closure. No boilerplate, no ceremony—just code for the screen.
use *;
Philosophy
Hoplite is built on three principles:
-
One closure, one call — Your setup and frame logic live in closures. No trait implementations, no engine lifecycle to memorize.
-
Hot reload everything — Edit your WGSL shaders and watch them update instantly. No restart required.
-
Escape hatches everywhere — Start simple, access the full wgpu API when you need it.
Features
Shader-First Rendering
run;
Effects and post-process passes chain automatically. The render graph handles ping-pong buffers, texture binding, and presentation.
3D Mesh Rendering
run;
Meshes render with depth testing, respecting effect passes and post-processing in the pipeline.
Textured Meshes
run;
2D Sprites
run;
Sprites render in the 2D overlay layer on top of all 3D content and effects.
Orbit Camera
let mut orbit = new
.target
.distance
.fov
.mode; // or AutoRotate { speed: 0.5 }
move |frame|
Interactive mode: drag to rotate, scroll to zoom. Auto-rotate mode for demos and visualizations.
Immediate-Mode 2D
move |frame|
All 2D draws are batched and rendered as an overlay after your render pipeline completes.
Runtime Hot Reload
Edit any .wgsl file passed to hot_effect* or hot_post_process* methods. Hoplite watches the filesystem and recompiles shaders on change. If compilation fails, the previous working shader stays active.
[hot-reload] Reloading shader: "shaders/nebula.wgsl"
[hot-reload] Shader compiled successfully
Quick Start
[]
= { = "https://github.com/xandwr/hoplite" }
use *;
Examples
Run the black hole demo with gravitational lensing:
API Reference
Setup Context (SetupContext)
| Method | Description |
|---|---|
default_font(size) |
Load the default font at given pixel size |
effect(shader) |
Add a screen-space effect pass |
effect_world(shader) |
Add a world-space effect with camera uniforms |
post_process(shader) |
Add screen-space post-processing |
post_process_world(shader) |
Add world-space post-processing |
hot_effect(path) |
Hot-reloadable screen-space effect |
hot_effect_world(path) |
Hot-reloadable world-space effect |
hot_post_process(path) |
Hot-reloadable screen-space post-process |
hot_post_process_world(path) |
Hot-reloadable world-space post-process |
enable_mesh_rendering() |
Enable 3D mesh pipeline |
mesh_cube() |
Create a unit cube mesh |
mesh_sphere(segments, rings) |
Create a UV sphere mesh |
mesh_plane(size) |
Create a flat plane mesh |
add_texture(texture) |
Add a texture, returns index |
texture_from_file(path) |
Load texture from file |
texture_from_bytes(bytes, label) |
Load texture from memory |
texture_minecraft_noise(size, seed) |
Procedural dirt/stone texture |
texture_minecraft_grass(size, seed) |
Procedural grass texture |
texture_minecraft_cobblestone(size, seed) |
Procedural cobblestone texture |
add_sprite(sprite) |
Add a sprite, returns SpriteId |
sprite_from_file(path) |
Load sprite from file (linear filtering) |
sprite_from_file_nearest(path) |
Load sprite from file (pixel art) |
sprite_from_bytes(bytes, label) |
Load sprite from memory |
Frame Context (Frame)
| Method | Description |
|---|---|
fps() |
Current frames per second |
width() / height() |
Screen dimensions in pixels |
text(x, y, str) |
Draw text at position |
text_color(x, y, str, color) |
Draw colored text |
rect(x, y, w, h, color) |
Draw filled rectangle |
panel(x, y, w, h) |
Draw a bordered panel |
panel_titled(x, y, w, h, title) |
Panel with title bar |
draw_mesh(index, transform, color) |
Draw a 3D mesh |
draw_mesh_textured(index, transform, color, tex) |
Draw a textured 3D mesh |
sprite(id, x, y) |
Draw sprite at position |
sprite_tinted(id, x, y, tint) |
Draw sprite with color tint |
sprite_scaled(id, x, y, w, h) |
Draw sprite at custom size |
sprite_scaled_tinted(id, x, y, w, h, tint) |
Draw scaled sprite with tint |
sprite_region(id, x, y, w, h, sx, sy, sw, sh) |
Draw sprite sub-region |
Frame Fields
| Field | Type | Description |
|---|---|---|
time |
f32 |
Total elapsed time in seconds |
dt |
f32 |
Delta time since last frame |
input |
&Input |
Keyboard and mouse state |
camera |
&mut Camera |
Current camera (modify to change view) |
gpu |
&GpuContext |
Low-level GPU access |
draw |
&mut Draw2d |
Low-level 2D API |
Shader Uniforms
World-space shaders receive these uniforms:
struct Uniforms {
resolution: vec2f,
time: f32,
fov: f32,
camera_pos: vec3f,
_pad1: f32,
camera_forward: vec3f,
_pad2: f32,
camera_right: vec3f,
_pad3: f32,
camera_up: vec3f,
aspect: f32,
}
@group(0) @binding(0) var<uniform> u: Uniforms;
Post-process shaders also get the input texture:
@group(0) @binding(1) var input_texture: texture_2d<f32>;
@group(0) @binding(2) var input_sampler: sampler;
Dependencies
Hoplite builds on solid foundations:
- wgpu — Cross-platform GPU abstraction
- winit — Window creation and input handling
- glam — Fast math types (Vec3, Mat4, Quat)
- fontdue — Font rasterization
- bytemuck — Safe casting for GPU buffers
License
MIT