Files
jacob-mathison 1e9d3f0917
ci/woodpecker/push/woodpecker Pipeline was successful
Lint and Build Checks / Lint, Test, and Build (push) Failing after 345h51m17s
feat(styles): add browser scss builder system
2026-06-25 09:46:09 -05:00

646 lines
23 KiB
JSON

{
"schemaVersion": "1.0.0",
"project": {
"name": "blb-throne-of-the-bone-king",
"displayName": "Bone Lord Bob - Throne of the Bone King",
"purpose": "Landscape-first game shell with shared React Native UI across browser, Electron, and future native mobile targets.",
"root": ".",
"model": "single-repo",
"repo": {
"gitea": "http://100.79.253.19:3000/jacob-mathison/blb-throne-of-the-bone-king",
"slug": "jacob-mathison/blb-throne-of-the-bone-king",
"defaultBranch": "main"
},
"universe": "Bone Lord Bob (BLB) - Mathison Projects Inc.",
"status": "early-development",
"summary": "Menu shell with persisted route navigation, settings, policies, changelog, credits, gameplay phase scaffolding, local saves, build metadata display, background music, browser/Electron rendering, and a browser-only socket-gated Toolkit for volatile gameplay/content systems."
},
"principles": [
"Start with llm.txt for human-readable orientation.",
"Use manifest.llm.json for machine-readable routing, commands, targets, and known gaps.",
"Read AGENTS.md for coding-agent operating rules before broad changes.",
"Shared UI under src/ is React Native, not raw HTML.",
"Do not use DOM APIs in shared src/ code; platform shims belong in .web.ts files or src/web/.",
"Metro bundles mobile; Vite bundles web and the Electron renderer.",
"Navigation is Zustand-based; do not add React Navigation unless explicitly requested.",
"Persistence is platform-split via persistStorage.ts for native and persistStorage.web.ts for web/Electron.",
"Toolkit is browser-only, requires Browser resolution, and requires an active Socket.IO connection for entry.",
"Update src/data/toolkit/changelog.json before committing or pushing meaningful deliverables; Husky only updates build metadata.",
"Import app data through src/data/index.ts and keep shared data interfaces in src/data/types/.",
"Commit as Jacob Mathison (jacob@mathisonprojects.com); never commit as an AI identity."
],
"guideFiles": [
{
"path": "llm.txt",
"type": "root-orientation",
"purpose": "First-read guide for project shape, stack, architecture, commands, conventions, and LLM notes.",
"alwaysRead": true
},
{
"path": "manifest.llm.json",
"type": "machine-manifest",
"purpose": "Machine-readable routing manifest: targets, commands, task routes, known gaps, and verification baseline.",
"alwaysRead": true
},
{
"path": "AGENTS.md",
"type": "agent-instructions",
"purpose": "Operational instructions for coding agents: ground rules, structure conventions, and common tasks.",
"alwaysRead": true
},
{
"path": "README.md",
"type": "human-overview",
"purpose": "Human-facing overview for setup, commands, architecture, toolkit behavior, and validation."
}
],
"globalReadOrder": ["llm.txt", "manifest.llm.json", "AGENTS.md", "README.md"],
"globalReadOrderSemantics": "Broad orientation order. Task routers should prefer taskRoutes read arrays to avoid over-reading.",
"documentationFiles": [
{
"path": "llm.txt",
"type": "root-orientation",
"purpose": "Human-readable first-read guide."
},
{
"path": "manifest.llm.json",
"type": "machine-manifest",
"purpose": "Machine-readable project manifest."
},
{
"path": "AGENTS.md",
"type": "agent-instructions",
"purpose": "Agent operating instructions."
},
{
"path": "README.md",
"type": "human-overview",
"purpose": "Human-facing setup and development guide."
},
{
"path": "socket/README.md",
"type": "toolkit-socket-notes",
"purpose": "Socket folder notes."
},
{
"path": "src/data/AGENTS.md",
"type": "data-instructions",
"purpose": "Rules for editable JSON content, Toolkit seed data, and canonical Credits content."
}
],
"targets": [
{
"id": "web",
"label": "Web",
"runtime": "react-native-web in browser",
"bundler": "Vite",
"entry": "index.html -> src/web/main.tsx -> App.tsx",
"devCommand": "npm run web",
"devUrl": "http://127.0.0.1:5173",
"primary": true
},
{
"id": "electron",
"label": "Desktop",
"runtime": "Electron Chromium renderer",
"bundler": "Vite renderer + TypeScript main/preload compile",
"entry": "electron/main.ts loads the Vite dev server in development or dist/renderer/ in production",
"devCommand": "npm run electron:dev",
"buildCommand": "npm run electron:build",
"packageCommand": "npm run electron:package",
"primary": true
},
{
"id": "toolkit-socket",
"label": "Toolkit Socket",
"runtime": "Node + Socket.IO",
"entry": "socket/server.mjs",
"devCommand": "npm run dev:toolkit",
"healthUrl": "http://127.0.0.1:5175/health",
"deployCommand": "npm run deploy:toolkit",
"deployHealthUrl": "http://bone-kingdom.tabitha.tealthrone:5174/health",
"primary": true
},
{
"id": "android",
"label": "Android",
"runtime": "React Native",
"bundler": "Metro",
"entry": "index.js -> App.tsx",
"devCommand": "npm run android",
"status": "native android/ folder is not currently present in this checkout"
},
{
"id": "ios",
"label": "iOS",
"runtime": "React Native",
"bundler": "Metro",
"entry": "index.js -> App.tsx",
"devCommand": "npm run ios",
"status": "native ios/ folder is not currently present in this checkout"
}
],
"stack": [
"React Native 0.85.3",
"React 19.2.3",
"react-native-web ^0.21.2",
"TypeScript ^5.8.3",
"Zustand ^5.0.14",
"@react-native-async-storage/async-storage ^3.1.1",
"Vite ^8.0.16",
"Electron ^42.4.0",
"Socket.IO and socket.io-client ^4.8.3",
"Sass ^1.101.0",
"Jest",
"ESLint + Prettier",
"Husky pre-commit build version bump and validation",
"Node >= 22.12.0"
],
"scripts": {
"dev": "npm run web",
"web": "vite --host 127.0.0.1",
"web:build": "vite build",
"web:preview": "vite preview --host 127.0.0.1",
"dev:toolkit": "node socket/server.mjs",
"dev:all": "concurrently -k -n app,toolkit -c blue,magenta \"npm run dev\" \"npm run dev:toolkit\"",
"dev:clear": "node socket/clear.mjs",
"deploy:frontend-health": "node scripts/deploy/write-frontend-health.mjs",
"deploy:toolkit": "sh scripts/deploy/restart-toolkit-socket.sh",
"electron:dev": "npm run electron:compile && cross-env NODE_ENV=development VITE_DEV_SERVER_URL=http://127.0.0.1:5173 concurrently -k \"vite --host 127.0.0.1\" \"wait-on http://127.0.0.1:5173 && electron .\"",
"electron:build": "npm run web:build && npm run electron:compile",
"electron:compile": "tsc -p tsconfig.electron.json",
"electron:package": "npm run electron:build && electron-builder",
"lint": "eslint .",
"test": "jest",
"validate:commit": "npm run lint && npm run test -- --runInBand && npm run electron:build",
"version:bump-build": "node tools/bump-build-version.mjs"
},
"architecture": {
"rootComponent": "App.tsx",
"componentTree": ["SafeAreaProvider", "GameViewport", "AppNavigator"],
"navigation": {
"type": "zustand-store with animated fade transitions",
"routes": "src/navigation/routes.ts",
"navigator": "src/navigation/AppNavigator.tsx",
"store": "src/state/navigationStore.ts",
"persistKey": "blb-navigation"
},
"state": {
"library": "zustand",
"stores": [
{
"file": "src/state/navigationStore.ts",
"persistKey": "blb-navigation",
"purpose": "Current route and pending route persistence."
},
{
"file": "src/state/gameSettingsStore.ts",
"persistKey": "blb-game-settings",
"purpose": "Resolution, autosave, mute, and audio volume settings."
},
{
"file": "src/state/gameplayStore.ts",
"persistKey": "blb-gameplay",
"purpose": "Active gameplay run, day counter, phase state, and phase navigation."
},
{
"file": "src/state/saveGameStore.ts",
"persistKey": "blb-save-games",
"purpose": "Local save slots for gameplay runs."
},
{
"file": "src/state/toolkitSocketStore.ts",
"purpose": "Toolkit socket connection status."
},
{
"file": "src/state/toolkitContentStore.ts",
"purpose": "Toolkit credits content, revision, load status, and socket refresh/save actions."
}
],
"persistHelper": "src/state/createPersistOptions.ts",
"platformStorage": {
"mobile": "src/state/persistStorage.ts",
"web": "src/state/persistStorage.web.ts"
}
},
"settings": {
"file": "src/settings/gameSettings.ts",
"resolutionIds": [
"browser",
"iphoneMini",
"iphoneDefault",
"androidDefault",
"phoneLarge"
],
"volumeKeys": ["master", "music", "ambience", "speech", "sfx"]
},
"screens": [
"src/screens/HomeScreen.tsx",
"src/screens/GameplayScreen.tsx",
"src/screens/SavesScreen.tsx",
"src/screens/ChangelogScreen.tsx",
"src/screens/SettingsScreen.tsx",
"src/screens/PoliciesScreen.tsx",
"src/screens/ToolkitScreen.tsx",
"src/screens/PageScreen.tsx"
],
"components": [
"src/components/GameViewport.tsx",
"src/components/ScreenLayout.tsx",
"src/components/MenuButton.tsx",
"src/components/BackHomeButton.tsx"
],
"assets": {
"images": "src/assets/images/",
"fonts": "src/assets/fonts/",
"music": "src/assets/music/",
"scss": "src/assets/scss/",
"scssBuilders": [
"src/assets/scss/__variables.scss",
"src/assets/scss/__mixins.scss",
"src/assets/scss/__globals.scss",
"src/assets/scss/__scrollbars.scss",
"src/assets/scss/__typography.scss",
"src/assets/scss/__layout.scss",
"src/assets/scss/__surfaces.scss",
"src/assets/scss/__buttons.scss",
"src/assets/scss/__forms.scss",
"src/assets/scss/__toolkit.scss"
],
"favicon": "src/assets/images/favicon.svg"
},
"data": {
"changelog": {
"json": "src/data/toolkit/changelog.json",
"typedExport": "src/data/index.ts",
"sortOrder": "newest-created-first",
"discipline": "Update before committing or pushing meaningful product, gameplay, Toolkit, content, build, or process changes."
},
"credits": {
"json": "src/data/toolkit/credits.json",
"typedExport": "src/data/index.ts"
},
"legal": {
"json": "src/data/toolkit/legal.json",
"typedExport": "src/data/index.ts"
},
"types": "src/data/types/index.ts",
"toolkitSeedData": {
"directory": "src/data/toolkit/",
"typedExport": "src/data/toolkit/index.ts",
"shape": "wiki-derived starter content for Toolkit planning resources and app content.",
"files": [
"audio.json",
"changelog.json",
"credits.json",
"endings.json",
"factions.json",
"flags.json",
"images.json",
"legal.json",
"lore.json",
"map.json",
"opening.json",
"petitioners.json",
"references.json",
"resources.json",
"rulings.json",
"seed.json",
"story.json"
]
}
},
"audio": {
"hook": "src/hooks/useBackgroundMusic.ts",
"webHook": "src/hooks/useBackgroundMusic.web.ts",
"defaultTrack": "src/assets/music/throne-of-the-bone-king.mp3",
"volumeControls": ["master", "music", "mute"]
},
"toolkit": {
"screen": "src/screens/ToolkitScreen.tsx",
"accessRules": [
"resolution setting must be browser",
"socket status must be connected"
],
"routes": [
"toolkitOpening",
"toolkitPetitioners",
"toolkitRulings",
"toolkitSeed",
"toolkitResources",
"toolkitMap",
"toolkitFactions",
"toolkitFlags",
"toolkitStory",
"toolkitLore",
"toolkitImages",
"toolkitAudio",
"toolkitCredits",
"toolkitEndings",
"toolkitReferences"
],
"contentSync": {
"server": "socket/server.mjs",
"serverHelpers": "socket/contentStore.cjs",
"client": "src/socket/toolkitSocketClient.ts",
"store": "src/state/toolkitContentStore.ts",
"events": [
"toolkit:content:read",
"toolkit:content:save",
"toolkit:content:changed",
"toolkit:content:error"
]
}
},
"webEntry": "src/web/main.tsx",
"electronMain": "electron/main.ts",
"electronPreload": "electron/preload.ts",
"buildOutputs": ["dist/renderer/", "dist/electron/"]
},
"taskRoutes": {
"ui-screen": {
"description": "Add or modify screens, navigation routes, or shared UI components.",
"read": [
"llm.txt",
"manifest.llm.json",
"AGENTS.md",
"src/navigation/routes.ts",
"src/navigation/AppNavigator.tsx",
"<target screen or component>"
],
"update": [
"src/navigation/routes.ts when adding a route",
"src/navigation/AppNavigator.tsx when wiring a route",
"manifest.llm.json when screens, routes, or architecture sections change"
]
},
"state": {
"description": "Zustand stores, persistence, navigation, or game settings.",
"read": [
"llm.txt",
"manifest.llm.json",
"src/state/",
"src/settings/gameSettings.ts",
"src/state/persistStorage.ts",
"src/state/persistStorage.web.ts"
],
"policies": [
"Extend persistStorage.ts and persistStorage.web.ts for platform storage changes.",
"Do not embed DOM or AsyncStorage calls directly in stores.",
"Add merge handling when persisted state shape changes."
],
"update": [
"manifest.llm.json when stores, persist keys, or settings surface change"
]
},
"web-electron": {
"description": "Vite config, web entry, Electron shell, browser assets, SCSS, or platform-specific .web.ts overrides.",
"read": [
"llm.txt",
"manifest.llm.json",
"vite.config.ts",
"index.html",
"src/web/",
"src/assets/",
"electron/",
"tsconfig.electron.json"
],
"policies": [
"DOM APIs are allowed in src/web/ and .web.ts shims only.",
"Electron main/preload compile to dist/electron/.",
"Vite emits renderer assets to dist/renderer/."
],
"verify": ["npm run lint", "npm run web:build", "npm run electron:build"],
"update": [
"manifest.llm.json when targets, build outputs, or dev commands change"
]
},
"toolkit": {
"description": "Toolkit screens, socket-gated browser tooling, JSON content sync, or Toolkit content panels.",
"read": [
"llm.txt",
"manifest.llm.json",
"src/screens/ToolkitScreen.tsx",
"src/navigation/routes.ts",
"src/state/toolkitSocketStore.ts",
"src/state/toolkitContentStore.ts",
"src/socket/toolkitSocketClient.ts",
"socket/"
],
"policies": [
"Keep Toolkit browser-only unless explicitly requested.",
"Keep Toolkit accessible only through Browser resolution and connected socket status.",
"Use src/data JSON as canonical editable content until schemas stabilize.",
"Do not add full CRUD forms unless explicitly requested."
],
"verify": [
"npm run test -- --runInBand",
"npm run dev:toolkit and check /health"
]
},
"data-content": {
"description": "Editable JSON content, typed data exports, and content validation.",
"read": [
"llm.txt",
"manifest.llm.json",
"src/data/AGENTS.md",
"src/data/",
"socket/contentStore.cjs"
],
"policies": [
"Keep JSON valid and typed through src/data exports.",
"Add runtime validation for data imported by stores or socket helpers.",
"Use atomic writes for server-side JSON save behavior.",
"Export app-importable data through src/data/index.ts.",
"Keep Changelog, Credits, and Legal JSON under src/data/toolkit/.",
"Update src/data/toolkit/changelog.json before committing or pushing meaningful deliverables unless explicitly skipped."
],
"verify": ["npm run test -- --runInBand"]
},
"realtime": {
"description": "Socket.IO server/client wiring for Toolkit connection status and content sync.",
"read": [
"llm.txt",
"manifest.llm.json",
"socket/server.mjs",
"socket/contentStore.cjs",
"src/hooks/useToolkitSocketConnection.ts",
"src/socket/toolkitSocketClient.ts",
"src/state/toolkitSocketStore.ts",
"src/state/toolkitContentStore.ts",
"package.json"
],
"policies": [
"Keep socket host/port configurable through environment variables.",
"Broadcast content changes after valid reads or saves.",
"Emit toolkit:content:error for read, parse, validation, or write failures."
],
"verify": [
"npm run test -- --runInBand",
"npm run dev:toolkit and check http://127.0.0.1:5175/health"
]
},
"mobile": {
"description": "React Native mobile target changes, Metro behavior, or native dependency setup.",
"read": [
"llm.txt",
"manifest.llm.json",
"AGENTS.md",
"metro.config.js",
"index.js",
"App.tsx"
],
"policies": [
"Do not modify android/ or ios/ native files unless explicitly requested and those folders exist.",
"Run pod install inside ios/ after native dependency changes when ios/ exists.",
"Keep shared src/ free of browser-only APIs."
]
},
"testing": {
"description": "Jest tests for logic, stores, routes, socket helpers, or screen scaffolding.",
"read": [
"llm.txt",
"manifest.llm.json",
"<target source>",
"<related __tests__ file>"
],
"verify": ["npm run test -- --runInBand"]
},
"docs": {
"description": "README, AGENTS, llm.txt, manifest, docs, or wiki maintenance.",
"read": [
"README.md",
"AGENTS.md",
"llm.txt",
"manifest.llm.json",
"package.json",
"src/navigation/routes.ts"
],
"policies": [
"Keep commit/push workflow guidance aligned across AGENTS.md, README.md, llm.txt, manifest.llm.json, and src/data/AGENTS.md when changelog discipline changes."
],
"verify": [
"node -e \"JSON.parse(require('fs').readFileSync('manifest.llm.json','utf8')); console.log('manifest ok')\"",
"npm run lint"
]
}
},
"rootCommands": [
{
"command": "npm run dev",
"purpose": "Alias for browser development.",
"target": "web"
},
{
"command": "npm run web",
"purpose": "Vite dev server for browser iteration.",
"target": "web"
},
{
"command": "npm run web:build",
"purpose": "Production web build to dist/renderer/.",
"target": "web"
},
{
"command": "npm run web:preview",
"purpose": "Preview production web build.",
"target": "web"
},
{
"command": "npm run dev:toolkit",
"purpose": "Start local Toolkit Socket.IO server.",
"target": "toolkit-socket"
},
{
"command": "npm run dev:all",
"purpose": "Start browser app and Toolkit socket together.",
"target": "web+toolkit-socket"
},
{
"command": "npm run dev:clear",
"purpose": "Stop related local dev processes if a run hangs.",
"target": "local-dev"
},
{
"command": "npm run electron:dev",
"purpose": "Run Vite dev server and Electron concurrently.",
"target": "electron"
},
{
"command": "npm run electron:build",
"purpose": "Build renderer and compile Electron main/preload files.",
"target": "electron"
},
{
"command": "npm run electron:package",
"purpose": "Build and package desktop installer via electron-builder.",
"target": "electron"
},
{
"command": "npm run start",
"purpose": "Start Metro bundler.",
"target": "mobile"
},
{
"command": "npm run android",
"purpose": "Run on Android emulator or device when android/ exists.",
"target": "android"
},
{
"command": "npm run ios",
"purpose": "Run on iOS simulator or device when ios/ exists.",
"target": "ios"
},
{
"command": "npm run lint",
"purpose": "ESLint."
},
{
"command": "npm run test",
"purpose": "Jest test suite."
},
{
"command": "npm run validate:commit",
"purpose": "Pre-commit safety check: lint, Jest, and Electron build."
},
{
"command": "npm run version:bump-build",
"purpose": "Increment the package patch version, update public .env build metadata, and stage package/env metadata before a commit. This does not author changelog content."
}
],
"knownGaps": [
"docs/ is still a placeholder README stub.",
"No JSON Schema validator exists yet for manifest.llm.json.",
"Toolkit content panels use socket-backed structured authoring forms for current JSON fields.",
"Toolkit audio and image resources can upload local files through the Toolkit socket into src/assets uploads folders.",
"The deployed Toolkit socket is expected to run from the shared repo workspace so deployed browser authoring updates development JSON and uploaded assets.",
"Toolkit JSON schemas are first-pass wiki-derived interfaces and should remain flexible while authoring forms stabilize.",
"Native android/ and ios/ folders are not currently present in this checkout.",
"No database exists yet; editable content is intentionally JSON-backed until schemas stabilize."
],
"verificationBaseline": {
"logicOrStoreChanges": ["npm run test -- --runInBand"],
"uiChanges": [
"npm run lint",
"npm run test -- --runInBand",
"npm run web:build"
],
"webElectronChanges": [
"npm run lint",
"npm run test -- --runInBand",
"npm run electron:build"
],
"socketChanges": [
"npm run test -- --runInBand",
"npm run dev:toolkit",
"curl http://127.0.0.1:5175/health",
"curl http://bone-kingdom.tabitha.tealthrone:5174/health"
],
"mobileChanges": ["npm run lint", "npm run test -- --runInBand"],
"docsChanges": [
"node -e \"JSON.parse(require('fs').readFileSync('manifest.llm.json','utf8')); console.log('manifest ok')\"",
"npm run lint"
]
}
}