A modular Rust engine core for real-time graphics, audio and physics, built around a single geometric-algebra spatial layer instead of separate matrix / transform conventions per subsystem.
Rust 1.92+ (edition 2024). Licensed under MPL-2.0.
meridian-foundation zero-dependency shared primitives (errors, feature detection)
meridian-numeric-core scalar types (float + deterministic Fixed), SIMD helpers, numeric traits
meridian-gac-core geometric algebra: vectors, rotors, motors, transforms — float and Fixed flavors
meridian-memory-core arenas, resource pools, generational handles
meridian-resource-core typed resource handles, versioning, dependency tracking
meridian-task-core job graph scheduler
meridian-platform-core window (real, winit-backed), input, filesystem, time, threading
meridian-gpu-driver shared wgpu device/buffer/shader/compute-pipeline mechanics
meridian-compute-driver low-level CPU-SIMD (real) and GPU-compute (real, via gpu-driver) dispatch abstraction
meridian-compute-runtime compute dispatch runtime (device/context, buffers, ComputeKernel), no algorithms
meridian-gac-compute GAC + Fixed-point batch kernels (Motor3 transforms, WGSL Fixed arithmetic) — adapter between gac-core and compute-runtime
meridian-asset-core image/mesh/audio/shader loading & decoding
meridian-ecs-core archetype ECS, SoA storage
meridian-graphics-driver GPU device abstraction: headless + windowed wgpu device, render pipeline, swapchain
meridian-audio-driver low-level audio device abstraction
meridian-physics-driver low-level physics execution backend (memory, SIMD/GPU dispatch, sync)
meridian-graphics-core render graph, culling, lighting, materials, camera
meridian-physics-core broad/narrow phase collision, constraint solver — generic over GaFlavor (float or deterministic Fixed)
meridian-physics-compute GPU/job-graph-batched rigid-body kernels — adapter between physics-core and compute-runtime/task-core
meridian-audio-core spatial mixer, DSP graph, listener/emitter
meridian-engine-core Runtime: the single JobGraph-based frame-work entry point (physics/audio/compute stages, fine-grained locking)
meridian-dsl-core domain-blind tag/attribute markup parser + typed-tag registry (the mechanics under the scene DSL)
meridian-dsl-macros #[dsl_tag(name = "...")] — the code-gen half of the DSL, lets a game register its own tags
meridian-sdk application entry point: re-exports every type above, plus resource loading, the extensible scene DSL, and windowed-app/render-stage scaffolding
Applications depend on meridian-sdk alone — see
examples/ (magic_figures, physic_figures), both of
which import everything through meridian_sdk::*, never the individual
crates above directly.
Dependencies flow bottom-up: foundation / memory-core / task-core /
platform-core have none, engine-core sits on top of everything.
gac-core (math) and compute-runtime (dispatch execution) are
deliberately independent of each other — neither depends on the other.
gac-compute is the adapter crate that depends on both, so batched Motor3
work can run on CPU-SIMD or GPU compute without gac-core ever knowing a
GPU exists (see ADR 007).
graphics-driver and compute-driver both depend on gpu-driver, the
crate that owns the actual wgpu device/buffer/shader/compute-pipeline
mechanics shared between rendering and general GPU compute (see
ADR 011). The full graph, and
the rules for which direction a dependency is allowed to point, are
documented in docs/dependency-rules.md.
Windowing is real (winit, see ADR 010),
GPU rendering and compute are real (wgpu), and the workspace is
async-native on genuine I/O only — a tokio runtime drives OS/driver
handshakes and GPU readbacks, everything else (recording, allocation, ECS
queries, GA math) stays synchronous (see
ADR 009).
Both examples build their scene from a .mel file (Meridian Engine
Language — today the tag/attribute DSL; a Razor-style scripting
extension is planned, see ADR 015)
under examples/assets/scenes/, parsed via meridian_sdk::dsl —
magic_figures registers its own <Glow>/<Orbit>/<Audio> tags
alongside the SDK's built-ins, the concrete demonstration that a game
extends the DSL without touching meridian-sdk itself. Lighting is a
real shadow-mapped directional light (with a visible "sun" sphere
marking its direction) plus a two-color hemisphere ambient fill, not a
flat constant — see docs/graphics-design.md.
./build.sh run magic_figures renders three orbiting, textured, glowing
shapes (sphere/cube/pyramid) each playing their own spatialized music
track in a different audio format, with bloom, to a real window end to
end — its own hand-assembled BinauralRenderer pipeline runs alongside
(not through) engine-core::Runtime, since per-sample binaural
synthesis doesn't reduce to a Runtime::Stage cleanly (see
meridian-engine-core's own module doc). ./build.sh run physic_figures
drops the same three shapes as real physics-core rigid bodies onto a
textured floor, driven end-to-end through engine-core::Runtime: a
registered PhysicsStepStage (ticked 0-8×/frame by a fixed-timestep
accumulator) and a registered render-presenting Stage
(meridian_sdk::RenderStage, ticked exactly once/frame) both run
through the same JobGraph-based Runtime, not a hand-rolled loop or a
runtime-bypassing render call — see Runtime::tick_only's own doc for
why physics and rendering need selective ticks rather than one
Runtime::tick() running both together every time.
docs/architecture.md— layering and the "why" behind the big decisionsdocs/dependency-rules.md— the enforceable rules for which crate may depend on whichdocs/gac-design.md,docs/ecs-design.md,docs/graphics-design.md,docs/physics-design.md,docs/memory-model.md,docs/threading-model.md— per-subsystem designdocs/roadmap.md— current state and implementation orderdocs/adr/— architecture decision records
./build.sh build # whole workspace
./build.sh test # cargo test --workspace
./build.sh check-deps # verify the crate graph matches docs/dependency-rules.md
./build.sh run magic_figures -- --foo bar # run an example, forwarding args
./build.sh list-examples
./build.sh cleanSee examples/examples/ for example programs (standard Cargo [[example]]
convention).
./release.sh meridian-gac-core --minor # bump + cascade + publish
./release.sh meridian-engine-core --patch # no cascade, patch is link-compatible
./release.sh meridian-gac-core # no bump: publish current version if not already on crates.io
./release.sh --publish-all --patch # bump + publish every crate in the workspace
./release.sh --publish-all # publish whatever isn't already on crates.io, no bump--publish-all replaces <crate-name> and builds the plan from the whole
workspace (topologically) instead of one crate's cascade. A bump type
(--patch/--minor/--major) is always optional — omitting it (or passing
--no-bump explicitly) means "don't change the version," and for each crate
in the plan the script checks crates.io and publishes only what isn't
already there.
Before bumping a "round" version (patch bump is never round; a minor bump is
round when patch == 0; a major bump is round when minor == 0 && patch == 0) the script checks whether that version is actually published — if not,
it publishes the current version as-is instead of skipping past an
unreleased one. --no-check-ver disables this and bumps/publishes blindly.
Add --dry-run to preview, --no-publish to bump without publishing.