Each workspace package was still pinning `typescript: ~5.5.x` or `~5.8.2` in its own devDependencies even though the root bumped to 6.0.3 in 60b1143. The pins were dead (yarn 1 hoists from root) but they're misleading when reading a single package.json. Bring them all to `^6.0.3` to match the root. Other: - @thumbmarkjs/thumbmarkjs 1.8.1 → 1.9.0 (root + communication package) - yarn.lock regenerated from a clean install (vitest 4 hoisting was flaking on the patch vite bump; reverted vite to ^8.0.10) Adds CLAUDE.md at the repo root: short project context for future sessions — stack, the 12-workspace layout, the React-friendly v2.1.0 additions (`subscribe()`, `subscribeMessage()`, snapshot getters), build scripts, and known gotchas (`SessionDataManager.getUserData` does NOT exist; sendChat* expects 3 args; dispatchEvent is sync).
5.1 KiB
Nitro_Render_V3 — Claude project context
Pure-TypeScript renderer library for the Nitro retro Habbo client. Wraps PixiJS v8 for room/avatar rendering and provides the WebSocket
- event-bus infrastructure that the React client (
../Nitro-V3) sits on top of.
Stack
- TypeScript 6.0 (root) + tsgo (
@typescript/native-preview, TS 7 preview compiler — used byyarn compile:fast, ~7× faster on this codebase) - PixiJS v8 (
pixi.js@8.18) - Vite 8 for build + bundling
- Vitest 4 for unit tests
- Yarn 1.22 workspaces (
packages/*) — note: yarn 1, NOT yarn 4 like the client. The two repos use different package managers on purpose. - No React — this is a pure TS library; React lives in
../Nitro-V3.
Workspace layout
Twelve internal packages under packages/*/src/, each pinning
typescript: ^6.0.3 in its own devDependencies:
packages/
api public interfaces (IEventDispatcher, ISessionDataManager, ...)
assets asset loading + caching
avatar avatar rendering / figure resolution
camera in-room camera widget
communication WebSocket + composer/parser pipeline
configuration runtime config loader
events EventDispatcher + NitroEventType + per-domain events
localization LocalizationManager
room RoomEngine + RoomVisualization
session SessionDataManager + RoomSessionManager + handlers
sound SoundManager (howler-based)
utils shared utilities (BinaryReader, Logger, …)
Root index.ts re-exports everything from @nitrots/* so the React
client gets a flat import { … } from '@nitrots/nitro-renderer'.
React-friendly API additions (v2.1.0)
Three additions matter for the React client integration. Keep these backwards-compatible:
EventDispatcher.subscribe(type, callback): () => void
Signature matches what useSyncExternalStore expects — returns an
unsubscriber, no need to juggle callback identity. Implemented in
packages/events/src/EventDispatcher.ts. The legacy
addEventListener / removeEventListener still work.
CommunicationManager.subscribeMessage(eventCtor, handler): () => void
Equivalent for packet streams. Implemented in
packages/communication/src/CommunicationManager.ts.
Snapshot getters on SessionDataManager + RoomSessionManager
getUserDataSnapshot(): Readonly<IUserDataSnapshot>
getActiveRoomSessionSnapshot(): Readonly<IRoomSessionSnapshot> | null
Returns referentially-stable values: the same object reference is
returned across reads until invalidated. Invalidation happens via the
new event types NitroEventType.SESSION_DATA_UPDATED and
NitroEventType.ROOM_SESSION_UPDATED.
When you mutate any field that the snapshot exposes, call the private
invalidateUserDataSnapshot() / invalidateRoomSessionSnapshot() —
that drops the cached snapshot and dispatches the invalidation event.
The React side rebuilds via useSyncExternalStore.
The interface contracts live in:
packages/api/src/nitro/session/IUserDataSnapshot.tspackages/api/src/nitro/session/IRoomSessionSnapshot.ts
Scripts
yarn build # vite build
yarn compile # tsc --project ./tsconfig.json --noEmit false
yarn compile:fast # tsgo (~7× faster, TS 7 preview)
yarn eslint # lint src + packages/*/src
yarn test # vitest run
yarn test:watch # vitest watch
yarn test:coverage # vitest with v8 coverage
Consumed by
../Nitro-V3 consumes this library via link:../Nitro_Render_V3
(yarn 4 node-modules linker). DO NOT use yarn link — it confuses
vite's asset resolution. The client's vite.config.js then maps each
@nitrots/* package directly to its source index.ts so there's no
build step needed for development.
When making changes to renderer APIs the React client uses, the
client's feat/react19-* branches contain consumers — check
Nitro-V3/src/hooks/events/ and Nitro-V3/src/hooks/{session,rooms}/
for the React-side bridge code.
Gotchas
SessionDataManager.getUserData(id)does NOT exist. Some legacy code in the React client used it under agetUserData ?truthy guard; the branch was always dead. OnlygetUserDataSnapshot()exists.IRoomSession.sendChatMessage/sendShoutMessagerequire 3 args (text, styleId, chatColour). The React client's chat-input legacy passes 2 — known pre-existing gap, do not "fix" the client without also threading chatColour through the chat composer pipeline.- The renderer is synchronous:
EventDispatcher.dispatchEventis a synchronous loop over listeners. Don't addawaitinside theprocessEventloop — it would change ordering guarantees that consumers rely on. - Workspace package devDeps pin TS at
^6.0.3soyarn compileinside any single package keeps working. The root TS 6 is the source of truth.
Sister projects in the same DEV folder
../Nitro-V3— React 19 client (consumes this lib via link)../Arcturus-Morningstar-Extended— Java emulator (server side)../NitroV3-Housekeeping— Next.js + Prisma admin CMS