Open Reality - a code first julia based game engine

Hi! I built OpenReality, a code-first game engine in Julia. I was inspired by RealityKit’s declarative API – you can build Vision Pro apps in ~20 lines of Swift. I wanted that elegance for games, but cross-platform and open source. Key features: - ECS architecture with immutable scene graph - 4 rendering backends (OpenGL, Metal, Vulkan, WebGPU) - Full PBR pipeline (deferred shading, CSM shadows, IBL) - Physics engine with GJK+EPA collision detection - Skeletal animation with glTF 2.0 support - 3D positional audio (OpenAL) - Exports to 400 KB WASM (vs Unity’s 200+ MB) Why Julia? Zero marshaling overhead. Unlike Unity (C#→C++) or Godot (GDScript→C++), there’s no FFI layer between your game code and the engine since they are both written in julia. Everything runs at native speed.
GitHub: GitHub - sinisterMage/Open-Reality: A Julia framework for building interactive 3D experiances
I’d love feedback on the architecture and API design. What features would make this useful for your projects?

Really cool :slight_smile:
Does the game engine produce any renders that you could share? :smiley: I havent found a single one in the repo…

Hey! Thank you so much!
Great point about the screenshots - I’m away
from my main PC right now, but I’ll add renders to the README this week.

In the meantime, feel free to check out the
examples/ directory if you want to see it running!
(note, metal examples will only work on macOS)

Thanks for taking a look!

Just added screenshots showing the
PBR materials system and rendering
pipeline! Check out the screenshots
folder - would love to hear your
thoughts on the rendering quality.

Hi @sinisterMage nice work! I see that you use an ECS architecture, looking inside your code it doesn’t seem too well optimized though, maybe you could use Ark.jl where we are actually trying to squeeze any performance drop we can. It would be awesome to see Ark.jl used in a project like yours!

Thanks for checking it out! Curious what optimizations you noticed - always looking to learn.

I’ll definitely check out Ark.jl! Would be interesting to compare approaches. If there are specific techniques that could benefit OpenReality, I’m all ears.

In general, I truly believe you can’t create an high-performance ECS without using generated functions, in Ark, we use them almost everywhere so that the code is well-inferred and non-allocating. Apart from that which is the major Julia specific trick, we use many other tricks to optimize performance in general. I woud be interested too to compare the approaches, we have a big amount of benchmarks here: Ark.jl/benchmark/benches at main · ark-ecs/Ark.jl · GitHub if you’d like to implement some of them we could compare Ark to your approach.

Hey @sinisterMage, I took the time to do some basic benchmarking:

Benchmarks OpenReality
using OpenReality, BenchmarkTools

struct Position <: Component
    x::Float64
    y::Float64
end

struct Velocity <: Component
    vx::Float64
    vy::Float64
end

function NewWorld(types...)
    for T in types
        register_component_type(T)
    end
    return World()
end

function new_entity!(world::World, components::Tuple)
    e = create_entity!(world)
    for c in components
        add_component!(e, c)
    end
    return e
end

function setup_world(n_entities::Int)
    world = NewWorld(Position, Velocity)
    entities = Vector{EntityID}()
    for i in 1:n_entities
        e = new_entity!(world, (Position(Float64(i), Float64(i * 2)),))
        push!(entities, e)
    end
    return (entities, world)
end

function benchmark_world_get_1(entities, world)
    sum = 0.0
    for e in entities
        pos = get_component(e, Position)
        sum += pos.x
    end
    return sum
end

function benchmark_world_set_1(entities, world)
    for e in entities
        add_component!(e, Position(1.0, 2.0))
    end
end

function benchmark_world_add_remove_1(entities, world)
    for e in entities
        add_component!(e, Velocity(0.0, 0.0))
    end
    for e in entities
        remove_component!(e, Velocity)
    end
end

e, w = setup_world(10^5);

@benchmark benchmark_world_get_1($e, $w)

@benchmark benchmark_world_set_1($e, $w)

@benchmark benchmark_world_add_remove_1($e, $w)
Benchmarks Ark
using Ark, BenchmarkTools

struct Position
    x::Float64
    y::Float64
end

struct Velocity
    dx::Float64
    dy::Float64
end

function setup_world(n_entities::Int)
    world = World(Position, Velocity)
    entities = Vector{Entity}()
    for i in 1:n_entities
        e = new_entity!(world, (Position(i, i * 2),))
        push!(entities, e)
    end
    return (entities, world)
end

function benchmark_world_get_1(entities, world)
    sum = 0.0
    for e in entities
        pos, = get_components(world, e, (Position,))
        sum += pos.x
    end
    return sum
end

function benchmark_world_set_1(entities, world)
    for e in entities
        set_components!(world, e, (Position(1, 2),))
    end
end

function benchmark_world_add_remove_1(entities, world)
    for e in entities
        add_components!(world, e, (Velocity(0, 0),))
    end
    for e in entities
        remove_components!(world, e, (Velocity,))
    end
end

e, w = setup_world(10^5);

@benchmark benchmark_world_get_1($e, $w)

@benchmark benchmark_world_set_1($e, $w)

@benchmark benchmark_world_add_remove_1($e, $w)

I just implemented getting, setting and adding+removing a single component:

Results OpenReality
julia> @benchmark benchmark_world_get_1($e, $w)
BenchmarkTools.Trial: 2324 samples with 1 evaluation per sample.
 Range (min … max):  1.978 ms …   4.029 ms  ┊ GC (min … max): 0.00% … 0.00%
 Time  (median):     2.089 ms               ┊ GC (median):    0.00%
 Time  (mean ± σ):   2.144 ms ± 203.739 μs  ┊ GC (mean ± σ):  0.00% ± 0.00%

     ▆█▇▆▄▄▃▃▂▁                                               ▁
  ▅▆█████████████▇▇▃▅▅▃▅▅▄▄▅▃▅▅▄▅▄▄▃▆▅▃▄▄▁▄▄▄▅▅▅▄▅▃▃▄▅▄▃▁▃▁▄▅ █
  1.98 ms      Histogram: log(frequency) by time      3.23 ms <

 Memory estimate: 0 bytes, allocs estimate: 0.

julia> @benchmark benchmark_world_set_1($e, $w)
BenchmarkTools.Trial: 691 samples with 1 evaluation per sample.
 Range (min … max):  5.810 ms … 23.962 ms  ┊ GC (min … max): 0.00% … 54.76%
 Time  (median):     6.303 ms              ┊ GC (median):    0.00%
 Time  (mean ± σ):   7.231 ms ±  2.078 ms  ┊ GC (mean ± σ):  6.47% ± 10.17%

  ▄█▇▇▅▄▁▁  ▂▁    ▁ ▁▂                ▁                       
  █████████▇███████████▄▁▇▆▁▆▅▇▇▄▁▇▅▇▇█████▆▄▇▁▄▁▇▄▅▁▇▁▁▁▁▄▅ █
  5.81 ms      Histogram: log(frequency) by time     13.6 ms <

 Memory estimate: 4.57 MiB, allocs estimate: 199489.

julia> @benchmark benchmark_world_add_remove_1($e, $w)
BenchmarkTools.Trial: 200 samples with 1 evaluation per sample.
 Range (min … max):  20.435 ms … 42.006 ms  ┊ GC (min … max): 0.00% … 30.75%
 Time  (median):     24.446 ms              ┊ GC (median):    0.00%
 Time  (mean ± σ):   25.062 ms ±  2.674 ms  ┊ GC (mean ± σ):  1.04% ±  3.93%

           ▆▃▃▅▅█▅▆  ▁▃ ▂                                      
  ▃▁▁▃▃▁▃▃▄█████████▆████▅▇▅▄▄▄▃▁▃▃▃▄▃▁▁▁▁▁▁▁▄▁▁▃▁▁▁▁▁▁▁▁▁▁▁▄ ▄
  20.4 ms         Histogram: frequency by time        35.2 ms <

 Memory estimate: 3.05 MiB, allocs estimate: 100000.
Results Ark
julia> @benchmark benchmark_world_get_1($e, $w)
BenchmarkTools.Trial: 10000 samples with 1 evaluation per sample.
 Range (min … max):  122.597 μs … 213.813 μs  ┊ GC (min … max): 0.00% … 0.00%
 Time  (median):     128.403 μs               ┊ GC (median):    0.00%
 Time  (mean ± σ):   129.955 μs ±   6.004 μs  ┊ GC (mean ± σ):  0.00% ± 0.00%

  ▁▃ ▂▁▁▇█▄▄ ▂▄▆▆▅▄▂▁▁▁▂▂▂▂▂▁ ▁▁▁▁▁▁                            ▂
  ████████████████████████████████████▇▇█▇█▇▇▆▆▇▆▆▆▆▅▅▆▅▄▄▅▄▄▄▅ █
  123 μs        Histogram: log(frequency) by time        155 μs <

 Memory estimate: 0 bytes, allocs estimate: 0.

julia> @benchmark benchmark_world_set_1($e, $w)
BenchmarkTools.Trial: 10000 samples with 1 evaluation per sample.
 Range (min … max):  220.766 μs … 298.245 μs  ┊ GC (min … max): 0.00% … 0.00%
 Time  (median):     230.044 μs               ┊ GC (median):    0.00%
 Time  (mean ± σ):   231.946 μs ±   5.353 μs  ┊ GC (mean ± σ):  0.00% ± 0.00%

                ▅█▃▆▂                                            
  ▁▁▁▁▁▁▁▁▁▁▁▂▃▅█████▃▂▂▃▄▄▄▅▄▃▃▃▂▂▂▂▂▂▂▂▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁ ▂
  221 μs           Histogram: frequency by time          253 μs <

 Memory estimate: 0 bytes, allocs estimate: 0.

julia> @benchmark benchmark_world_add_remove_1($e, $w)
BenchmarkTools.Trial: 1081 samples with 1 evaluation per sample.
 Range (min … max):  4.464 ms …  4.914 ms  ┊ GC (min … max): 0.00% … 0.00%
 Time  (median):     4.609 ms              ┊ GC (median):    0.00%
 Time  (mean ± σ):   4.615 ms ± 35.980 μs  ┊ GC (mean ± σ):  0.00% ± 0.00%

                              ▁▄▃█▆▅▅▅▃                       
  ▂▁▁▁▁▁▁▁▁▂▂▂▂▂▃▂▁▃▁▃▃▃▄▄▄▅▆██████████▇██▅▆▅▆▅▅▅▄▄▄▄▃▃▁▃▃▃▂ ▄
  4.46 ms        Histogram: frequency by time        4.71 ms <

 Memory estimate: 0 bytes, allocs estimate: 0.

so Ark.jl is more than an order of magnitude faster. Though I guess with operations on more components this difference will be higher.

I did this as a sort of encouragement to try Ark in your project (and helping out if you’d like!) :slight_smile:

Hey! This is fantastic - thank you so much for taking
the time to run these benchmarks!
An order of magnitude speedup would help OpenReality a lot, and your zero-allocation design is way better than my current implementation. I’d absolutely love to integrate Ark.jl into the engine
Would you be interested in collaborating on this?

  • Use Ark.jl as the core ECS (it’s clearly superior)
  • Maintain OpenReality’s API as a wrapper layer
  • List you as a core contributor
  • Use OpenReality as a production showcase for Ark.jl
    Really excited about this - and yes, definitely using
    Ark in the project! The encouragement means a lot

Nice! Yes, I can try to work on integrating Ark into the project, I will give it a try and let you know!

This is awesome! I’m actually very interested in being able to export to WASM for my projects and was curious if you had any documentation on that or insights? I would love to be able to do that with my engine, but I suspect it’s probably a major architectural difference just peeking at your code a bit.

Thank you! my WASM pipeline for open reality works in 2 parts
the Julia side exports the scene to a binary format (.orsb) and there is also a rust based WASM runtime required for running the orsb binary in the browser, i am not sure this is the most Julia centric approach there is since both parts of the exports are depended on rust. hopefully that gave you some insight to the WASM pipeline, you are welcome to ask questions about my pipeline if you want :smiley:

Very cool! Thanks for the insight on that. Definitely want to play with it myself here soon. I’ll let you know if I have any more questions. Thanks again!

Not my style being the guy that pop the joy but this project is far from a game engine anyone can use for anything outside of the narrow scope it was built for.

I dedicated myself to extensively studying game engines and without any doubt this is not even comparable to most game engine out there.

Just the readme has so much red flags

Quick Start

Install

One-liner (recommended):

# Linux / macOS
curl -fsSL https://open-reality.com/install.sh | sh

# Windows PowerShell
irm https://open-reality.com/install.ps1 | iex

To me this is a red flag with flying colors, why on earth should someone take the risk of getting somme bash commands from somewhere on the web to install this while there is an increduble package manager for julia ?
Why should i download myself SDK when PKG.jl already manage this extremely well with artifacts ?

OpenReality provides AAA-quality rendering with a clean functional API. Define scenes as composable entity trees, attach PBR materials and physics, and render with a single function call — on OpenGL, Vulkan, WebGPU or Metal.

From what I saw in the code this not 4 rendering backend, it’s 4 renderer each with his own behaviors, no architectural work (command buffers, abstractions, abstract render graph, uniform resource management)

All the features cited in the readme are cool but a game engines mostly define itself by his archtecture first and how each systems interact with each other. Talking of systems the order of systems is basically hardcoded in the engine making it litteraly use less for a tons of games

It’s been a long time engines use Frame graph to manage task

  • Entity Component System with O(1) component operations

That ECS before Ark.jl was extremely inefficiencient without any kind of real optimizations (O(1) components are the baseline not an optimization)

  • Immutable, functional scene graph

Using an ECS + a Scene graph is a well known anti-pattern as ECS is a flat database and scene graph a hierarchical structure. It requires extremely advanced technique to merge the two into a coherent structure which is not the case here
Plus the architecture feels in incoherent, is just feel like a scene tree with just “composition over inheritance” not an engine optimized with ECS, so basically Godot but way worse (because each core engine server use his own kind of optimizations and the scene tree is just the user interface)

  • Full-featured impulse-based physics engine (PGS solver with warm-starting)

As I noted with the incoherent architecture, thr physic system implementation highly depend on the engine architecture making this statement confusing alone without talking about how it’s pligged in the engine.

  • 3D positional audio (OpenAL) with spatial attenuation and Doppler effect

Well audio is the point everyone neglect as I see, can’t blame you for that :joy:

  • Built-in FPS player controller

That’s a huge problem… game logics should NEVER be hardcoded in an engine. Unreal allows to make FPS but through things like templates or blueprint, premade skeleton not built in the engine.

  • Scene export to binary ORSB format for web deployment

Well on this point I think it’s a good point (but julia wasm export is on the working so if it become ready this will become useless)

  • GameContext for deferred entity spawning/despawning

This means race conditions everywhere in multithreaded environment if I try deffering 2 same op at the same time on 2 thread

  • ScriptComponent lifecycle (on_start, on_update, on_destroy)

Why a script components ? That’s an OOP pattern in an engine using an ECS, a total anti pattern. ECS like Flecs have a ScriptComponent for scripting language to interact with the core
So this is totally useless an counter productive

  • Game Config with TOML loading, difficulty presets, hot-reload

Curious on what is hot-reload here since julia use JIT
If it’s for assets weird that there is not filesystem to back it up.

  • Cooperative coroutines with yield_wait, yield_frames, yield_until

Julia has an incredible async/multithreading management. Making this mostly useless.

  • Health & damage: armor, typed resistances, knockback, auto-despawn
  • Inventory & items: slot-based inventory, item registry, world pickups
  • Quest & objectives: kill/collect/reach/interact/custom objectives, auto-tracking
  • Dialogue system: branching trees, per-choice conditions, quest integration

Those are game logic, why are they part of a game engine ?

  • Opt-in multithreading with snapshot-based parallelism
    Julia also already do this

Hello World

using OpenReality

reset_entity_counter!()
reset_component_stores!()
...

That is not declarative programming that’s imperative and shows that the game life cycle isn’t automatically managed

Controls

Key Action
W / A / S / D Move
Mouse Look around
Shift Sprint
Space Up
Ctrl Down
Escape Release cursor

Is this a game engine or a game ?

TL;DR: if this is a just a game and not a game engine then fine, this project is cool and fine if it work.
If it’s a game engine then it’s extremely badly designed and would need to be remade from the ground up

People are allowed to post and create whatever they would like. This is mostly not constructive criticism. This is just you pushing your opinions on what a game engine should be onto someone else. This seems as if you are trying to puff your chest out and show superiority. I refrain from engaging in conversations like this on here, but I couldn’t help myself here. You can criticize without being rude. Where are your games? At the end of the day, it’s a tool. Everyone has different opinions, but that doesn’t give you the right to be so inflammatory about someone else’s hard work.

I understand what you say, and my pb is that effort don’t seems to have been put in this (if it’s the case then sorry and he is free to explain his building process which is, whether it is, valid)
Many things of this is cool and stuff and are amazing idea, but looking at everything, the commits, the modules, the fact that this use rust dependencies for things julia has (like wgpu binding, vulkan), the fact that it doesn’t use the package manager nor follow the naming convention etc, this seems rushed.
The first thing I did when seeing this is looking at the code (like I always do) to see how to improve myself but from what it is, I can only conclude at best that this is an extremely rushed project.
Like me taking a picture somewhere and going to an art class, your are free to show your art, but art you actually putted efforts in, even if it’s ugly, it’s the effort you put in it that make everyone accept it.

Hello! i see where you are coming from, so i would like to explain a bit better about OpenReality and why it was built the way it is, first of all, the reason OpenReality is not in the general registery is because it has rust and swift deps (metal and webGPU) and i cannot package that cleanly with Pkg, if you know a good way to package those cleanly ill be happy to know!
about the curl | sh install script, that was done because i couldnt submit OpenReality to the general registery, although i will work on submitting it to homebrew (via taps), conda and maybe nix in the future
the curl | sh script is also open source Open-Reality/open-reality-website/public/install.sh at main · sinisterMage/Open-Reality · GitHub
i also noticed you said that vulkan is using rust, which is not true, the vulkan backend uses vulkan.jl with a Julia implementation, only metal and webGPU are non Julia, hopefully that helped clear up your concerns :slight_smile: