oj#

oj is for getting something on screen fast, and then taking it wherever you want.

Write it in the browser on play.onejs.com with nothing installed, or in your own Unity project with the package. It is the same code either way, which is what makes the round trip work: prototype on the site, publish it so people can play it, then bring it into your project when it outgrows the sandbox.

A complete app, in one file:

import { View, Text, mount, useFrame, input } from "oj"
import { useState } from "react"

function App() {
    const [n, setN] = useState(0)
    useFrame(() => {
        if (input.keyboard.wasKeyPressed("Space")) setN((v) => v + 1)
    }, [])

    return <View className="items-center justify-center w-full h-full">
        <Text className="text-4xl text-white">{n}</Text>
    </View>
}

mount(<App />)

No root to plumb, no panel to size, no CS.*. mount knows where to render and useFrame runs before every frame with the seconds since the last one.

What you get#

A stagePick a size, work in those units, and it fits any window. Letterbox, cover, fluid or stretch.
A frame loopuseFrame, delta time, and none of the plumbing.
InputKeyboard, mouse, gamepad and touch, in stage units, read when you want them.
PhysicsA 2D world in a few lines, ticked for you.
DrawingParticles, shader effects, and a vector painter that takes plain numbers.
MathVector2, Color, Mathf, seeded random, all plain JavaScript.

Plus every component and hook you already know. Importing View from oj and from onejs-react gives you the same code.

The round trip#

Build it fast. Open the editor on play.onejs.com, or npm install onejs-play in a project you already have. No panel to size, no root to plumb, no C# to write.

Publish it. A game on the site is a URL anyone can play, with its source on the page, a leaderboard and multiplayer rooms if it wants them.

Take it to Unity. Eject hands you a Unity folder: unzip it inside Assets/, drag the prefab into a scene, and the game is running. Your source, your assets, the build config and the runtime it ran on come with it. Same file, no rewrite, and from there it is an ordinary OneJS project with the whole engine behind it.

Leaderboards and rooms are the only things that want the site behind them. Elsewhere they go quiet rather than throwing.

Getting it#

OneJS 3.2.3 and later already have it. For an older project:

npm install onejs-play

Then one entry in esbuild.config.mjs, so the bundler resolves it:

alias: {
    "oj": path.resolve(process.cwd(), "node_modules/onejs-play/src/index.ts"),
}

and one in tsconfig.json, so the editor does too:

"paths": {
    "oj": ["./node_modules/onejs-play/src"]
}

Both, not either. A project with only the alias builds while showing Cannot find module 'oj' on every import.

Next#

The stage and mount is the page to read first. Math and values, physics and a game's own files cover the rest.