Marduk is a BabylonJS framework for rendering good web games.
- 🧵 Multithreaded — rendering happens in its own thread
- 🎳 Smart architecture — logic and rendering happen on separate threads
npm install @benev/mardukThe theater coordinates your rendering thread and displays the results onto a canvas.
The theater is split into two main parts. Each will live in its own separate bundle.
- The Frontstage hosts the visible canvas in the dom. It doesn't import Babylon, and will be lean in filesize.
- The Backstage runs inside a web worker, and performs rendering work. It imports Babylon, and will be fat in filesize.
- Write your
spec.tstype, which describes your renderable worldimport {AsFigmentSpec} from "@benev/marduk/theater" export type MySpec = AsFigmentSpec<{ // Describe a renderable object in your world, // in terms of serializable data. hippo: {hungry: boolean} }>
- notice the specific locations from where we're importing things
- Establish your
backstage.worker.bundle.tsmodule (this will be a web worker)import {MySpec} from "./spec.js" import {babylonBackstage, theaterWorker} from "@benev/marduk/theater/babylon" void async function() { // defining a babylon backstage // (you could make a backstage for a different kind of renderer) const backstage = await babylonBackstage<MySpec>(async stagecraft => ({ // now we define a renderer for this object hippo: (id, data) => { console.log("spawn", id, data) return { update: data => console.log("update", id, data), dispose: () => console.log("dispose", id, data), } }, })) // establishing the web worker await theaterWorker(backstage) }()
- now bundle this module as
backstage.worker.bundle.min.jsusingscute,rollup,esbuild,parcel,vite, or whatever
- now bundle this module as
- Create your
frontstage.tsmodule (this will be your app's main entrypoint)import {MySpec} from "./spec.js" import {Frontstage, register} from "@benev/marduk/theater/front" void async function() { const workerUrl = new URL("./backstage.bundle.js", import.meta.url) const frontstage = await Frontstage.make<MySpec>({workerUrl}) register(frontstage.getElements()) // okay, now you're ready to manipulate your world // spawn, then update, then delete a hippo (lol, just to exercise the full lifecycle) await frontstage.syncFigments([[0, ["hippo", {hungry: false}]]]) await frontstage.syncFigments([[0, ["hippo", {hungry: true}]]]) await frontstage.syncFigments([[0, undefined]]) }()
- now bundle this module as
frontstage.bundle.js
- now bundle this module as
- Load the frontstage bundle onto your web page
<script type=module src="./frontstage.bundle.js"></script>
- Place the
<marduk-theater>element in your html body<marduk-theater></marduk-theater>
- 🎉 You're done!
- If you run the page, you should see the console logging about the hippo lifecycle events.