- 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
143 lines
7.7 KiB
JavaScript
143 lines
7.7 KiB
JavaScript
window.GDD = window.GDD || {};
|
||
|
||
function RisksPage() {
|
||
return (
|
||
<div className="content-inner">
|
||
<h1 style={{ marginBottom: '8px' }}>Risks and Open Questions</h1>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.95rem', maxWidth: '680px' }}>
|
||
Known risks and their mitigations. Each risk is assessed for impact and likelihood.
|
||
</p>
|
||
|
||
<div style={{ marginTop: 'var(--sp-6)' }}>
|
||
{[
|
||
{
|
||
risk: 'SpacetimeDB learning curve',
|
||
severity: 'medium',
|
||
mitigation: 'Start with one table, one reducer, one subscription before adding game complexity. Build the skeleton phase slowly.',
|
||
impact: 'Could slow Phase 0–1 significantly if the SDK has undocumented behavior.',
|
||
},
|
||
{
|
||
risk: 'Renderer coupling',
|
||
severity: 'high',
|
||
mitigation: 'Create view models and renderer boundary before adding many meshes/effects. Keep renderer-specific code in /renderers/r3f only.',
|
||
impact: 'Without a clean boundary, migrating to Unity/Bevy later requires rewriting most of the client.',
|
||
},
|
||
{
|
||
risk: 'Too much UI scope',
|
||
severity: 'medium',
|
||
mitigation: 'Build only inventory, chat, station, and market-lite for MVP. Everything else is Phase 7+.',
|
||
impact: 'Scope creep in panels/screens is the #1 way the prototype never ships.',
|
||
},
|
||
{
|
||
risk: 'Movement update frequency',
|
||
severity: 'medium',
|
||
mitigation: 'Use destination-based movement, not frame-based syncing. Server updates positions periodically, not per-frame.',
|
||
impact: 'Per-frame state writes would overwhelm SpacetimeDB and make multiplayer unreliable.',
|
||
},
|
||
{
|
||
risk: 'Economy complexity explosion',
|
||
severity: 'low',
|
||
mitigation: 'Begin with fixed station pricing. Add market orders only after core loop works.',
|
||
impact: 'Market manipulation, arbitrage, and order matching are deep rabbit holes.',
|
||
},
|
||
{
|
||
risk: '3D asset rabbit hole',
|
||
severity: 'medium',
|
||
mitigation: 'Use primitives/icons/placeholders until gameplay works. Visual fidelity is Phase 7+.',
|
||
impact: 'Spending time on ship models and particle effects before the loop works is pure waste.',
|
||
},
|
||
{
|
||
risk: 'Authentication complexity',
|
||
severity: 'low',
|
||
mitigation: 'Use SpacetimeDB identity for the MVP. Add proper account/auth only when persistence is proven.',
|
||
impact: 'OAuth/session management is a distraction until the game actually works multiplayer.',
|
||
},
|
||
{
|
||
risk: 'World simulation tuning',
|
||
severity: 'medium',
|
||
mitigation: 'Start with a simple world tick that spawns one event type (anomalies only). Add faction conflicts and fauna migrations iteratively. Make all event parameters tunable via a config table so adjustments don\'t require redeployment.',
|
||
impact: 'If event spawn rates are wrong, the galaxy either feels dead or chaotic. Faction AI that escalates too fast could lock players out of systems permanently. Fauna migrations that overlap trade hubs could crash local economies.',
|
||
},
|
||
].map((r, i) => (
|
||
<div key={i} className="card" style={{ marginBottom: 'var(--sp-4)' }}>
|
||
<div style={{ display: 'flex', alignItems: 'center', gap: 'var(--sp-3)', marginBottom: 'var(--sp-3)' }}>
|
||
<span className={`pill ${r.severity === 'high' ? 'pill-red' : r.severity === 'medium' ? 'pill-amber' : 'pill-green'}`}>
|
||
{r.severity.toUpperCase()}
|
||
</span>
|
||
<h4 style={{ margin: 0 }}>{r.risk}</h4>
|
||
</div>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: '0 0 var(--sp-3) 0' }}>
|
||
<strong style={{ color: 'var(--cyan)' }}>Mitigation:</strong> {r.mitigation}
|
||
</p>
|
||
<div style={{ background: 'var(--surface-raised)', borderRadius: 'var(--radius-md)', padding: 'var(--sp-2) var(--sp-3)', fontSize: '0.82rem', color: 'var(--fg-dim)' }}>
|
||
<strong style={{ color: 'var(--muted)', fontFamily: 'var(--font-mono)', fontSize: '0.7rem' }}>IMPACT: </strong>
|
||
{r.impact}
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
<div className="section-header" style={{ marginTop: 'var(--sp-8)' }}>
|
||
<span className="section-num">RISK-?</span>
|
||
<h2 style={{ margin: 0 }}>Open Questions</h2>
|
||
</div>
|
||
|
||
<div className="grid-2">
|
||
<div className="card">
|
||
<h4 style={{ color: 'var(--accent)' }}>Scale targets</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0 }}>
|
||
Build for 2–5 concurrent testers first. What's the target for the beta? 50? 500?
|
||
SpacetimeDB scaling characteristics are unproven at our scale.
|
||
</p>
|
||
</div>
|
||
<div className="card">
|
||
<h4 style={{ color: 'var(--cyan)' }}>Persistence strategy</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0 }}>
|
||
Keep player, inventory, market, and world tables persistent from day one. But: do we
|
||
need world resets? How do we handle schema migrations?
|
||
</p>
|
||
</div>
|
||
<div className="card">
|
||
<h4 style={{ color: 'var(--green)' }}>Combat depth</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0 }}>
|
||
The MVP is explicitly not a twitch-combat game. When do we add targeting, weapon cycles,
|
||
damage types? What's the minimum viable combat?
|
||
</p>
|
||
</div>
|
||
<div className="card">
|
||
<h4 style={{ color: 'var(--purple)' }}>Testing approach</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0 }}>
|
||
Open multiple browser windows with separate identities to validate shared state. Do we
|
||
need automated integration tests? Playwright against the game client?
|
||
</p>
|
||
</div>
|
||
<div className="card">
|
||
<h4 style={{ color: 'var(--accent)' }}>Galaxy event balance</h4>
|
||
<p style={{ color: 'var(--fg-dim)', fontSize: '0.85rem', margin: 0 }}>
|
||
How many world events should be active simultaneously? Too few and the galaxy feels static;
|
||
too many and players get event fatigue. What's the right spawn rate per region? How does
|
||
event density scale with player count?
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="section-header" style={{ marginTop: 'var(--sp-8)' }}>
|
||
<span className="section-num">RISK-REF</span>
|
||
<h2 style={{ margin: 0 }}>References</h2>
|
||
</div>
|
||
|
||
<table className="data-table">
|
||
<thead><tr><th>Source</th><th>Relevant Point</th><th>URL</th></tr></thead>
|
||
<tbody>
|
||
<tr><td>SpacetimeDB</td><td style={{ color: 'var(--fg-dim)' }}>Real-time backend for apps and games</td><td><a href="https://spacetimedb.com/" target="_blank">spacetimedb.com</a></td></tr>
|
||
<tr><td>SpacetimeDB GitHub</td><td style={{ color: 'var(--fg-dim)' }}>Clients connect to database, logic runs in DB</td><td><a href="https://github.com/clockworklabs/spacetimedb" target="_blank">GitHub</a></td></tr>
|
||
<tr><td>React Three Fiber</td><td style={{ color: 'var(--fg-dim)' }}>React renderer for Three.js</td><td><a href="https://r3f.docs.pmnd.rs/" target="_blank">docs.pmnd.rs</a></td></tr>
|
||
<tr><td>Vite</td><td style={{ color: 'var(--fg-dim)' }}>Frontend build tooling</td><td><a href="https://vite.dev/" target="_blank">vite.dev</a></td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
window.GDD.RisksPage = RisksPage;
|