Skip to content

Diorama

This logo is rendered in-engine by Diorama: pixel-art sprites composited in world space with the gem's own CRT scanline pass.

lint O3DE 26.05 status: beta v0.6.0 license: Apache-2.0 OR MIT

Diorama

World-space 2D and 2.5D for the Open 3D Engine.

Diorama is an O3DE gem that renders sprites and tilemaps as world objects through Atom, so flat content lives inside real 3D scenes with lighting, physics, and depth. It is the world-space counterpart to LyShine's screen-space UI: LyShine owns the UI layer, Diorama owns world-space 2D content. It ships as a clean, upstreamable gem, not an engine fork.

Status: beta (v0.6.0-beta)

Diorama is in beta. The feature set is broad (see the status table below) and the gem builds with its unit tests green on both Linux and Windows. The API, serialized formats, and component layout may still change before 1.0 without a compatibility guarantee, so it is not yet recommended for production. Feedback and issues are welcome.

Why

O3DE has no first-class path for world-space 2D. LyShine is screen-space UI and Atom is a 3D PBR renderer, so building a 2D or 2.5D game today means working against the engine: abusing UI canvases, hand-rolling quads, or bolting sprites onto 3D meshes. Diorama fills that gap by rendering 2D through Atom, which also gives 2.5D for free: camera-facing billboards, depth-sorted layers, and sprites freely mixed with 3D geometry, lighting, particles, and post effects. See VISION.md for the full rationale and design priorities.

  • 2D: flat content composed in the world. Sprites, tilemaps, sprite-sheet and skeletal animation (cutout, DragonBones weighted-mesh deform, and surface / FFD deform), orthographic and pixel-perfect cameras.
  • 2.5D: those flat elements living inside a 3D scene, with depth sorting, parallax, and free mixing with 3D content. This is the sweet spot pure-2D engines cannot reach.

At a glance

Diorama feature overview: sprites, rendering, depth and shadows, 2.5D and parallax, tilemap, animation, lighting, effects, post, camera, gameplay, scripting, determinism, grid intelligence, audio, samples

Feature status

Area Capability Status
Sprite World-space sprite quad rendered through Atom Working
Sprite Editor viewport preview via a shared presenter Working
Sprite Atlas UV sub-regions, horizontal/vertical flip, anti-diagonal transpose (90° rotations) Working
Sprite Billboard (camera-facing) and fixed orientation Working
Sprite Point filter (crisp pixel art) Working
Sprite Sprite-sheet / flipbook animation + frame events (OnAnimationFrame) Working
Sprite Playback speed / time-scale (hit-stop, slow motion) Working
Sprite Afterimage trails (fading ghost copies; dash / super effect) Working
Sprite Palette recolor (three-stop luminance ramp; team / alt colors) Working
Rendering Batched feature processor (texture + sort-layer batching) Working
Rendering Automatic camera-distance depth sort Working
Rendering Off-screen sprite culling (view side-plane frustum reject) Working
Rendering Soft ground shadows under billboards Working
Tilemap Atlas-grid tilemap component + typed bus Working
2.5D Depth-sorted layers + tilted 2.5D camera Working
Scripting Typed per-feature request buses (Lua, Python, ScriptCanvas) Working
Gameplay 2D collision: colliders, triggers, and queries reachable from scripts Working
Gameplay Pushbox resolution (ComputeBoxPushOut minimum-translation) Working
Gameplay Frame-data hitboxes/hurtboxes (OnHit/OnHurt over the 2D collision world) Working
Gameplay Typed interaction boxes: pushbox/throwbox/armor/proximity + attack payloads on OnBoxEvent, clash/armor/throw matrix, world-space box overlay, bone-attached boxes Working
Gameplay One-way platforms + ramp ground-follow (ProbeGroundY, side-scroller) Working
Input Rebindable input action mapping (Button / Axis1D / Axis2D actions) Working
Input Motion inputs (numpad sequences: quarter-circle, dragon-punch) Working
Gameplay 2.5D brawler depth lanes (depth lift/sort + depth-aware combat) Working
Gameplay Grid intelligence cores: FOV/fog, movement range, A* pathfinding Working
Simulation Fixed-step 2D Simulation Clock (OnSimTick, pause/single-step) + seeded RNG Working
Simulation Snapshot/restore with state hash + slots (rollback-ready; CI determinism proof) Working
Simulation Per-sim-frame input ring: frame queries + InjectActionState (replays, bots, rollback) Working
Simulation Per-component sim-clock advance (Use Simulation Clock) + timed super-freeze (FreezeFor, cinematic pause) Working
2.5D Parallax background layers Working
Camera 2D camera controller (follow, deadzone, bounds, shake) Working
Camera Versus framing (two-target midpoint) + distance zoom/dolly Working
Camera Orthographic / pixel-perfect camera Working
Lighting 2D dynamic lights + normal-mapped sprites Working
Lighting Day/night cycle (time-of-day color/intensity/direction over a light) Working
Effects 2D particle emitter Working
Effects Bullet-pattern emitter (danmaku: ring/fan/spiral, pooled, collidable) Working
Effects Sprite materials (flash, outline, emissive/bloom) Working
Tilemap In-editor tile paint tool (editor component mode) Working
Tilemap Autotiling: 4-bit edge set and 47-tile blob (corner-aware) Working
Tilemap Custom rule-tile autotiling (neighbor-mask → tile offset) Working
Post 2D Look: bloom + vignette over Atom's PostProcess Working
Post Retro CRT scanline overlay Working
Animation Skeletal cutout clip player (keyframed bone hierarchy) + cross-fade + 1D blend trees Working
Animation Skinned Sprite mesh deform (DragonBones weighted-mesh import + CPU skinning + clip playback) Working
Animation Surface + FFD deform (DragonBones surface rigs: control-point-grid warp, nested surfaces, per-vertex FFD, type-40 parameter composition) Working
Animation Aseprite sprite-sheet import (tags + per-frame timing) Working
Animation Animation state machine (parameter-driven clip switching) Working
Asset pipeline Native .aseprite AssetBuilder (packs atlas + sheet metadata) Working
Asset pipeline Native .aseprite: indexed + grayscale color depths, separable blend modes Working
Asset pipeline Runtime asset reference: play a .dioramasheet product directly Working
Audio One-shot SFX + music via MiniAudio Working
Project Diorama2DGame "New 2.5D Game" project template Working
Asset pipeline Dedicated tilemap asset + builder (.dtilemap JSON or Tiled .tmj → validated .dtilemapc), multi-layer + per-tile flip/rotate Working

Editor preview scope: components that have a viewport preview (Sprite, Tilemap, 2D Light, 2D Look, Skeletal, Skinned Sprite, Aseprite) live-update as you edit their Inspector properties. Behaviors that only exist at run time (input, collision, particles, camera follow, the animation state machine, CRT and parallax scroll) and any state set through the runtime request buses are seen in play / game mode, not in the static edit-mode preview. This mirrors O3DE's split between authored state (the Inspector and the saved prefab) and runtime state (transient, not written back to the prefab), and is by design rather than a pending fix.

Requirements

  • Open 3D Engine 26.05 (built and verified against the 26.05 SDK).
  • The Atom_RPI gem (a Diorama dependency, included with O3DE).
  • A C++ toolchain and CMake matching your O3DE setup. Linux and Windows are verified (the gem builds and its unit tests pass on both); macOS is targeted but unverified. On Windows, Visual Studio 2022 or 2026 with the C++ workload.

Install

Register the gem with your engine, enable it in a project, then build the project. Replace the paths with your own.

# 1. Register the gem with O3DE (one time)
<engine>/scripts/o3de.sh register --gem-path /path/to/o3de-diorama

# 2. Enable it in your project
<engine>/scripts/o3de.sh enable-gem --gem-name Diorama --project-path /path/to/YourProject

# 3. Configure and build the project (profile config shown)
cmake -B /path/to/YourProject/build/linux -S /path/to/YourProject -G "Ninja Multi-Config"
cmake --build /path/to/YourProject/build/linux --config profile

The same register / enable / cmake steps build any configuration; swap --config profile for debug (unoptimized, for stepping through gem code) or release (the optimized shipping build).

On Windows, use o3de.bat and a Visual Studio CMake generator (Visual Studio 18 2026 for VS2026, Visual Studio 17 2022 for VS2022). The helper scripts/ci_build_test.ps1 automates the whole register / configure / build / test flow and auto-detects the newest installed Visual Studio:

$env:O3DE_ENGINE_PATH = "C:\O3DE\26.05"   # folder with scripts\o3de.bat
$env:DIORAMA_PROJECT  = "C:\path\to\YourProject"
$env:GEM_PATH         = "C:\path\to\o3de-diorama"
powershell -ExecutionPolicy Bypass -File C:\path\to\o3de-diorama\scripts\ci_build_test.ps1

Quick start

  1. Open your project in the O3DE Editor with the Diorama gem enabled.
  2. Create an entity and add the Sprite component.
  3. Assign a texture to Config | Texture.
  4. Optionally set an atlas sub-region under Config | Atlas / UV Region (UV Min / UV Max, plus Flip Horizontal / Flip Vertical), a world Size, Billboard, and a 2.5D Layering | Sort Offset.

The sprite renders in world space and is visible both in the editor viewport and at runtime.

Start a whole project from the template

To scaffold a fresh 2.5D project with the gem already enabled, register the bundled project template once and create a project from it:

<engine>/scripts/o3de.sh register --template-path /path/to/o3de-diorama/Templates/Diorama2DGame
<engine>/scripts/o3de.sh create-project --project-path /path/to/MyGame --template-name Diorama2DGame

The new project ships with Diorama enabled, 2.5D starter assets, and a STARTING.md first-steps guide. See How-To: Start a New 2.5D Game from the Template.

Architecture

  • Two-module split. A lightweight runtime client module and a separate Qt editor module. Shipped games carry only the runtime, with no Qt or AzToolsFramework dependency, so adding 2D costs little at runtime while authors still get full editor tooling.
  • Integration over reinvention. Diorama builds on existing O3DE systems (transforms, prefabs, scripting, physics) instead of inventing parallel ones.
  • A path designed to scale. Rendering goes through a batched Atom feature processor: sprites and tilemap tiles that share a texture collapse into one draw call, so a busy scene stays cheap.
  • Deterministic when you want it. An opt-in fixed-step simulation clock with seeded randomness, full state snapshot/restore (with a verifiable state hash), and a per-frame input ring make the same inputs replay to the same result: the foundation for replays, training-mode rewind, and rollback netcode readiness, proven by a determinism test that runs in CI on every change.

For the full design with diagrams (module split, data model, persistence, and the render path) see Docs/architecture.md. In-depth references live under Docs/reference/: every Sprite and Tilemap parameter, and the typed bus API for scripts and agents.

Roadmap

The learning ladder is complete through the current feature set: the step-by-step how-to guides (full outline in Docs/examples-outline.md) run from Hello Sprite up through animation, atlases, tilemaps + autotiling, parallax, lighting, camera, particles, materials, post, audio, the project template, genre building blocks (fighting, bullet patterns, platforming, brawler, shmup), day/night, grid intelligence, and the deterministic simulation layer -- matching the feature table above.

A first sample showcase is the cartoon solar-system diorama (DioramaSolarSystem): a layered 2.5D scene that exercises much of the stack at once -- a setting sun, planets, a rabbit-marked moon, and a comet over normal-mapped terrain, animated with a panning parallax camera, a particle campfire and comet trail, flickering dynamic firelight, emissive glow, and a twilight sky. It is authored offline by scripts/gen_diorama_solar_level.py from procedurally generated art (scripts/gen_cartoon_*.py). It is an early effort; a more ambitious flagship showcase is still a goal.

Still ahead

  • A scene-to-image export API (render a Diorama scene to a PNG at any resolution), which doubles as a deterministic headless capture path.
  • Toward 1.0: settle and freeze the bus API surface, and stand up an always-available build/test CI gate (the Windows host build is now verified; see the status note above).

Versioning

Diorama follows Semantic Versioning. Before 1.0 the version stays on the 0.x line, where minor (0.MINOR.0) bumps may include breaking changes and patch (0.x.PATCH) bumps are fixes. Each release is an annotated git tag (vMAJOR.MINOR.PATCH) and is recorded in CHANGELOG.md. The version field in gem.json tracks the current release. A stable API is the goal of the eventual 1.0.

Contributing

Diorama complements the engine and contributes fixes back upstream. If something in O3DE (Atom, AzCore, asset builders, and so on) is found broken or improvable while working on Diorama, it is flagged and contributed back to o3de/o3de rather than patched around.

See CONTRIBUTING.md for how to build, test, and submit changes, and CODE_OF_CONDUCT.md for the standards expected in project spaces.

Guidelines:

  • Keep the runtime client module free of Qt and AzToolsFramework. Editor-only code lives in the editor module.
  • Treat asset-sourced data as untrusted: validate and bound it in builders and at load. No unchecked sizes feed GPU buffers.
  • No per-frame allocations in the render loop.
  • Match the surrounding code style and the existing SPDX file headers.
  • If you change the gem version or its dependencies, regenerate the SBOM (python3 scripts/gen_sbom.py) and commit sbom.spdx.json; CI rejects a stale SBOM.

Continuous integration

Two workflows run in CI:

  • lint (always on, GitHub-hosted): clang-format (pinned), SPDX headers, whitespace/EOF hygiene, JSON manifest validation, and an SBOM freshness check (sbom.spdx.json must match scripts/gen_sbom.py output). This is the gate every push and pull request must pass. Format C++ with clang-format 18.1.8 to match it (a newer local version may format differently).
  • build-test (opt-in, GitHub-hosted): compiles the gem through a host O3DE project and runs the unit tests. Both legs run on free GitHub-hosted runners, so untrusted PR code never touches local hardware. The Linux leg runs in a Fedora container with the SDK baked in (built by the ci-image workflow); the Windows leg installs the O3DE SDK on windows-latest at runtime. It is opt-in: add the ci:build label (Windows) or ci:build-linux label (Linux) to a pull request, or trigger it manually. You can run the same checks locally with scripts/ci_build_test.sh (Linux) or scripts/ci_build_test.ps1 (Windows). See Docs/ci-build-test.md.

Security

Diorama vendors no third-party code; its dependencies are the O3DE engine and a few O3DE gems. A minimal SPDX SBOM of that direct surface is at sbom.spdx.json (regenerate with scripts/gen_sbom.py); the transitive third-party tree is owned and documented by O3DE. To report a vulnerability, see SECURITY.md -- use GitHub's private vulnerability reporting, not a public issue.

License

Licensed under either of

at your option. Every source file carries SPDX-License-Identifier: Apache-2.0 OR MIT declaring the same dual license.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

About

A 2D/2.5D rendering and game gem for Open 3D Engine: world-space sprites with Atom lighting, materials, post-processing, a 2D camera, collision, particles, parallax, UI/HUD, and audio.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

11 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages