Restructure into pnpm monorepo with game shell, docs, and SpacetimeDB backend

- Restructure flat static prototype into pnpm workspace monorepo
- apps/game: playable shell with R3F 3D scene, HUD, SpacetimeDB connection
- apps/docs: design docs and prototypes
- apps/site: landing page
- packages/ui: shared Button and Panel primitives
- services/spacetimedb: backend module (9 tables, 11 reducers)
- Archive legacy static files to archive/legacy-static/
- Game loop: connect, undock, target, approach, dock, mine, sell
- Add pnpm-workspace.yaml, tsconfig.base.json, spacetime.json
This commit is contained in:
2026-05-31 17:56:56 -04:00
parent 436f282fa8
commit 316a44661b
234 changed files with 3717 additions and 101 deletions

View File

@@ -0,0 +1,60 @@
import { useEffect, useMemo, useState } from "react";
import type { DbConnection } from "../module_bindings";
import { createSpacetimeConnection, type ConnectionStatus, type IdentityLike } from "./client";
const defaultUri = import.meta.env.VITE_SPACETIME_URI ?? import.meta.env.VITE_SPACETIMEDB_HOST ?? "http://localhost:3000";
const defaultDatabase =
import.meta.env.VITE_SPACETIME_DATABASE ?? import.meta.env.VITE_SPACETIMEDB_DB_NAME ?? "void-nav-dev";
export function useSpacetimeConnection(displayName: string) {
const [status, setStatus] = useState<ConnectionStatus>("idle");
const [message, setMessage] = useState<string>();
const [identity, setIdentity] = useState<IdentityLike>();
const [connection, setConnection] = useState<DbConnection | null>(null);
const [revision, setRevision] = useState(0);
const [reducerStatus, setReducerStatus] = useState<{ message: string; isError: boolean }>();
const config = useMemo(
() => ({
uri: defaultUri,
database: defaultDatabase,
}),
[],
);
useEffect(() => {
const conn = createSpacetimeConnection({
...config,
displayName,
onStatus: (nextStatus, nextMessage) => {
setStatus(nextStatus);
setMessage(nextMessage);
},
onIdentity: setIdentity,
onDataChanged: () => setRevision((value) => value + 1),
onReducerStatus: (nextMessage, isError = false) => setReducerStatus({ message: nextMessage, isError }),
});
setConnection(conn);
const refresh = window.setInterval(() => {
if (conn) setRevision((value) => value + 1);
}, 1500);
return () => {
window.clearInterval(refresh);
conn?.disconnect?.();
};
}, [config, displayName]);
return {
connection,
status,
message,
identity,
revision,
reducerStatus,
uri: config.uri,
database: config.database,
};
}