A small Rust-first 2D game engine prototype with desktop rendering, assets, audio, and a future-safe FFI boundary.
View Example
·
Report Bug
·
Request Feature
seishin is a native 2D game engine prototype written in Rust. The project starts with a small desktop MVP and is designed around a stable public API boundary so future language bindings can call into the engine through C ABI / FFI instead of touching Rust internals.
The current MVP opens a desktop window or browser canvas, renders a sprite, loads assets, handles keyboard input, and exposes a small future-safe FFI lifecycle boundary.
- About
- Current Status
- Built With
- Getting Started
- Usage
- Project Layout
- Development
- Testing
- Contributing
- License
- Acknowledgments
seishin is a focused engine-learning project with a pragmatic architecture:
Rust Engine Core
-> Stable public Rust API
-> C ABI / FFI
-> Future bindingsDesign goals:
- keep gameplay code independent from renderer internals;
- keep backend crates such as
wgpu,winit,kira, andimagebehind engine APIs; - expose simple handles, IDs, and C-compatible values across FFI;
- avoid large framework-scale architecture until the MVP proves a real need;
- keep the developer experience pleasant through the
seishinfacade crate andseishin::prelude::*.
Initial targets:
- Windows desktop
- Linux desktop
- WebAssembly/browser MVP
Future targets:
- Android
- Go bindings through C ABI / FFI
- additional tooling after the engine core stabilizes
The repository currently contains the MVP vertical slice:
- desktop window through
winit; - update/render loop;
- keyboard input;
wgpu-backed clear pass and sprite rendering;- simple camera support;
- asset loading from disk;
- simple audio playback with graceful degradation;
- browser/WebAssembly build support with no-op audio fallback;
- playable
examples/basic_2dexample; - C ABI lifecycle smoke boundary in
seishin_ffi.
Manual visual/audio validation is still required on a desktop session after automated checks pass.
- Rust
- Cargo Workspaces
winitfor desktop window and eventswgpufor GPU renderingimagefor image loadingkirafor audio playbackraw-window-handlefor window/render integrationbytemuckfor safe GPU buffer casts
Planned or future-facing:
- a more complete ECS may be evaluated later, but it is intentionally deferred for the first MVP slice.
- a physics backend may be evaluated later for physics.
Install Rust with rustup:
rustup toolchain install stable
rustup default stableThis workspace currently uses:
- Rust edition:
2021 - MSRV declared in Cargo:
1.75
On Linux, winit, wgpu, and kira may require system packages for windowing, graphics, and audio depending on your distribution. Typical dependencies include X11/Wayland, Vulkan or GPU driver support, ALSA/PulseAudio/PipeWire development packages.
git clone <repo-url>
cd seishincargo build --workspacecargo run -p seishin_basic_2dInstall the wasm target and wasm-bindgen CLI, then export the example:
rustup target add wasm32-unknown-unknown
cargo install wasm-bindgen-cli
cargo run -p xtask -- web-build --example basic_2dThe export is written to target/web/basic_2d. Serve it locally with:
cargo run -p xtask -- web-serve --example basic_2dThe web MVP keeps the same game entry point (seishin::run::<Game>()) but runs with browser-specific runtime internals. Audio is currently a no-op fallback on wasm; assets and resources are fetched from the static export using the existing asset:// and res:// schemes.
Controls:
- Arrow keys or WASD: move sprite through the configured
moveinput action - Space or Enter: open/close the MVP dialogue flow in logs
- Escape: close the demo
Game/example code should normally depend on the facade crate and import the prelude:
use seishin::prelude::*;
mod components;
use components::PlayerController;
struct Game;
impl Game2D for Game {
fn new(ctx: &mut StartupContext) -> GameResult<Self> {
ctx.components()
.register::<PlayerController>("PlayerController")?;
Ok(Self)
}
}
fn main() -> GameResult<()> {
seishin::run::<Game>()
}Projects are configured by Seishin.toml. Virtual path schemes are explicit:
asset://resolves under[assets].rootfor images, audio, video, fonts, and other media.res://resolves under[resources].rootfor scenes, prefabs, configuration, scripts, markup, and data files.user://is reserved for writable user data such as saves/settings.
For larger games, prefer scene/prefab/component composition over storing every entity handle in main.rs:
resources/scenes/ map and screen placement
resources/prefabs/ reusable entity composition
resources/data/ characters, items, quests, dialogue, and other game data
src/components/ Rust behavior registered by type namemain.rs can register custom behavior and load the scene:
ctx.components()
.register::<PlayerController>("PlayerController")?;seishin::run::<Game>() discovers Seishin.toml, lets Game2D::new register components, then automatically loads [game].main_scene.
Scenes can also carry audio and UI data. Audio refs are loaded as assets and can be played by entity from FrameContext; UI refs are backend-free ECS data for layout, text, image, and interaction. The facade extracts UI entities into RenderContext::ui_elements() and dispatches interaction actions through FrameContext, while visual text/UI drawing remains layered above the current renderer.
Components can load their own game data/configuration through the resource API:
let config = ctx
.resources()
.toml("res://data/components/player_controller.toml")?;
let speed = config.f32("speed").unwrap_or(180.0);The current dialogue MVP opens/closes via the configured interact action and presents text through tracing logs. On-screen text/UI rendering is still a future rendering feature.
See the complete example in examples/basic_2d.
crates/
seishin/ Facade crate and gameplay prelude
seishin_core/ Engine config, lifecycle, transforms, IDs, core errors
seishin_world/ Backend-free world, scenes, UI data, reload, procedural builders
seishin_runtime/ Headless and desktop runtime orchestration
seishin_render/ 2D render types and wgpu renderer
seishin_render_graph/ Backend-free frame/render ordering graph
seishin_input/ Normalized input state
seishin_assets/ Asset paths, roots, handles, image loading
seishin_audio/ Audio facade and private kira backend
seishin_physics/ Placeholder for future 2D collision/physics
seishin_ffi/ C ABI boundary with opaque handles
examples/
minimal/ Headless loop smoke example
basic_2d/ Playable MVP demo
bindings/
go/ Future Go binding notes
tools/
xtask/ Internal automation helperEach crate keeps src/lib.rs as a small facade and places implementation in domain modules such as engine, desktop, renderer, loader, state, or ffi.
Recommended workflow before submitting changes:
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace --all-targets
cargo build --workspaceUseful commands:
cargo run -p seishin_basic_2d
cargo run -p xtask -- check
cargo run -p xtask -- web-build --example basic_2d
cargo run -p xtask -- web-serve --example basic_2d
cargo test -p seishin_core
cargo test -p seishin_renderRust repository practices used here:
- workspace-level dependency declarations;
Cargo.locktracked for reproducible workspace/example builds;- MSRV declared with
rust-version; - strict Clippy gate with
-D warnings; xtaskreserved for internal automation;- crate-level tests for pure logic;
- manual checklist for render/audio behavior that cannot be fully unit-tested.
Automated baseline:
cargo test --workspace --all-targets
cargo build --workspaceFull local gate:
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace --all-targets
cargo build --workspace
cargo build --target wasm32-unknown-unknown -p seishin_basic_2dManual demo checklist:
- Run
cargo run -p seishin_basic_2d. - Confirm a desktop window opens.
- Confirm the sprite appears over a clear background.
- Confirm arrow keys and WASD move the sprite through the configured
moveinput action. - Press Escape or close the window and confirm clean shutdown.
This project is still early. Contributions should keep the MVP philosophy intact: small, explicit, validated changes.
Suggested flow:
- Open an issue or discussion for larger changes.
- Create a feature branch.
- Keep PRs focused on one subsystem or vertical slice.
- Run the full local gate before submitting.
- Include manual validation notes when touching windowing, rendering, input, or audio.
Please avoid:
- exposing backend internals in public APIs;
- expanding FFI before the safe Rust API is stable;
- adding broad ECS/editor/hot-reload abstractions before they are required;
- mixing unrelated refactors and features in one change.
Distributed under the MIT License. See LICENSE for more information.
- The README structure is inspired by Best-README-Template.
- Rust game development projects and crates such as
wgpu,winit,kira, andimageprovide the foundation for this prototype.