Underground 2 Revived
Play Need for Speed: Underground 2 (2004) in Chrome and Firefox with WebGPU graphics, Web Audio, up to 120 fps widescreen, controller support, free roam and Online races with friends. Fan project, not
TypeScript용 타입 안전 ECS 런타임으로 입력, 멀티플레이어, 롤백 네트코드, 디버깅, 픽셀 아트·사운드·음악 도구를 제공합니다
A type-safe ECS runtime for TypeScript, with input, multiplayer, rollback netcode, debugging, and tools for pixel art, sound, and music.
게임TypeScript · MDXGitHub @typeonce-dev온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
The agent-first type safe ECS runtime
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗The all-in-one toolkit for agent-first game development.
🎮 You direct the mechanics and feel. Your coding agent writes the game.
Ritmo keeps the agent on track: wrong code does not compile and the error names the fix, and headless runs show lints, invariants, and why each value changed.
Ritmo works with your renderer and game loop. Drawing stays in your game.
pnpm add @typeonce/ritmo
Requires TypeScript 5.9 or newer. Leave noErrorTruncation off: errors name
the fix near their start, and an untruncated one can print a whole schema.
import { Clock, Descriptor, Schema } from "@typeonce/ritmo"
type Vec = { x: number; y: number }
// Define the world once: components, resources, and the fixed step.
const step = Clock.hz(60)
const Time = Clock.resource("Example/Time", step)
const Position = Descriptor.Component<Vec>()("Example/Position")
const Velocity = Descriptor.Component<Vec>()("Example/Velocity")
// Bind the schema to its game-facing APIs.
const Game = Schema.bind(
Schema.fragment({
components: { Position, Velocity },
resources: { Time }
})
)
const AdvanceTime = Clock.system(Game, {
name: "Example/AdvanceTime",
resource: Time
})
// Systems receive only the access they declare.
const Move = Game.System(
"Example/Move",
{
queries: {
moving: Game.Query({
selection: {
position: Game.Query.write(Position),
velocity: Game.Query.read(Velocity)
}
})
},
resources: { time: Game.System.readResource(Time) }
},
({ queries, resources }) => {
const { dt } = resources.time.get()
for (const match of queries.moving.each()) {
const position = match.data.position.get()
const velocity = match.data.velocity.get()
match.data.position.set({
x: position.x + velocity.x * dt,
y: position.y + velocity.y * dt
})
}
}
)
// Starting can fail (the clock is a validated resource),
// and so can a tick: both return a Result.
const made = Game.Runtime.make({
services: Game.Runtime.services(),
resources: { Time: Clock.start(step) }
})
if (made.ok) {
const runtime = made.value
const ticked = runtime.tick(Game.Schedule(AdvanceTime, Move))
if (!ticked.ok) console.error(ticked.error)
}
All packages are released together with the same version.
| Package | Contents |
|---|---|
@typeonce/ritmo | ECS runtime and fixed-step loop, seeded random, same-bits trig (Ops) |
@typeonce/ritmo-math | 2D helpers on plain data: vectors, angles, swept circle collision, flow field |
@typeonce/ritmo-browser | Animation-frame ticks; keyboard, gamepad, pointer, and touch actions, merged into one input or split across local players |
@typeonce/ritmo-render | Entity-to-node sync for any renderer |
@typeonce/ritmo-pixi | Pixi adapter for the render node registry |
@typeonce/ritmo-netcode | Online multiplayer: rollback and lockstep sessions over WebSocket, WebRTC, or any transport, with resyncs and desync checks |
@typeonce/ritmo-devtools | Headless debug sessions, reports, and ritmo-devtools lint |
@typeonce/oxlint-plugin-ritmo | Lint rules for deterministic, headless simulation code |
@typeonce/ritmo-tools | ritmo-tools, the asset command for agents: pixel art, animation sheets, sound effects, and music |
Try the tools' pages in the browser: the pixel fixer, the sound lab, and the music lab.
Paste this into your coding agent in the game's folder, then describe the game you want:
Set up Ritmo in this project by following
https://raw.githubusercontent.com/typeonce-dev/ritmo/main/packages/core/SETUP.md
SETUP.md installs the packages and checks every
Ritmo game uses and links the Ritmo skill
into the agent's skills folder. From then on, the agent follows the skill on
every change: where the docs are and how to structure the game.
To try a mechanic first, ask your agent for a prototype. The prototype skill gets a playable toy in front of you every round, checks only that it compiles and loads, and asks you one question you answer by playing; when you keep it, it graduates to the full checks.
applyDeferred() or
applyStateTransitions(...) in the schedule.