@inneranimalmedia/agentsam-sdk 2.6.7 → 2.6.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) hide show
  1. package/README.md +37 -0
  2. package/docs/REPO_FILE_MAP.txt +132 -0
  3. package/migrations/d1/0018_goap_control_plane_remaster.sql +40 -0
  4. package/migrations/d1/0019_agentsam_agent_run_plan_todo.sql +14 -0
  5. package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +20 -9
  6. package/migrations/runtime/0002_goap_blackboard_v1.sql +15 -0
  7. package/migrations/runtime/0004_agent_run_plan_linkage.sql +8 -0
  8. package/native/agentsam-machine/cli/Cargo.toml +8 -1
  9. package/native/agentsam-machine/cli/README.md +21 -0
  10. package/native/agentsam-machine/core/Cargo.toml +7 -0
  11. package/native/agentsam-machine/core/README.md +14 -0
  12. package/native/agentsam-machine/core/build.rs +33 -0
  13. package/native/agentsam-machine/core/contracts/source-types.v1.json +353 -0
  14. package/native/agentsam-machine/core/src/lib.rs +6 -0
  15. package/native/agentsam-machine/core/src/source_types.rs +2 -2
  16. package/package.json +16 -6
  17. package/packages/agentsam-errors/package.json +1 -1
  18. package/packages/agentsam-errors/src/index.js +1 -0
  19. package/packages/agentsam-errors/src/tool.js +56 -0
  20. package/packages/agentsam-errors/test/tool.test.mjs +58 -0
  21. package/packages/agentsam-goap/README.md +52 -0
  22. package/packages/agentsam-goap/package.json +37 -0
  23. package/packages/agentsam-goap/src/adapters/d1-sqlite.js +570 -0
  24. package/packages/agentsam-goap/src/adapters/memory.js +199 -0
  25. package/packages/agentsam-goap/src/contracts.js +226 -0
  26. package/packages/agentsam-goap/src/control-plane.js +112 -0
  27. package/packages/agentsam-goap/src/errors.js +157 -0
  28. package/packages/agentsam-goap/src/index.js +5 -0
  29. package/packages/agentsam-goap/src/world.js +202 -0
  30. package/packages/agentsam-goap/test/goap-control-plane.test.mjs +245 -0
  31. package/packages/agentsam-goap/test/world.test.mjs +79 -0
  32. package/packages/agentsam-nav/dist/Nav.d.ts +43 -0
  33. package/packages/agentsam-nav/dist/NavCollapsible.d.ts +10 -0
  34. package/packages/agentsam-nav/dist/NavContent.d.ts +2 -0
  35. package/packages/agentsam-nav/dist/NavFooter.d.ts +2 -0
  36. package/packages/agentsam-nav/dist/NavGroup.d.ts +3 -0
  37. package/packages/agentsam-nav/dist/NavHeader.d.ts +2 -0
  38. package/packages/agentsam-nav/dist/NavMenu.d.ts +22 -0
  39. package/packages/agentsam-nav/dist/NavProvider.d.ts +35 -0
  40. package/packages/agentsam-nav/dist/NavTrigger.d.ts +2 -0
  41. package/packages/agentsam-nav/dist/Surfaces.d.ts +41 -0
  42. package/packages/agentsam-nav/dist/browser.d.ts +11 -0
  43. package/packages/agentsam-nav/dist/browser.global.js +135 -0
  44. package/packages/agentsam-nav/dist/browser.js +7290 -0
  45. package/packages/agentsam-nav/dist/contracts.d.ts +76 -0
  46. package/packages/agentsam-nav/dist/index.d.ts +11 -0
  47. package/packages/agentsam-nav/dist/index.js +7291 -0
  48. package/packages/agentsam-nav/dist/legacy.css +83 -0
  49. package/packages/agentsam-nav/dist/shell.css +113 -0
  50. package/packages/agentsam-nav/dist/theme.css +113 -0
  51. package/packages/agentsam-nav/dist/utils.d.ts +1 -0
  52. package/packages/agentsam-repository/src/goap.js +13 -14
  53. package/packages/agentsam-repository/src/goap.js.bak-20260922011251 +670 -0
  54. package/packages/agentsam-repository/src/tickets.js +15 -22
  55. package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +19 -8
  56. package/packages/connectors/cloudflare/package.json +3 -1
  57. package/packages/identity/tests/lane1-packed-consumer.test.mjs +1 -1
  58. package/python/agentsam_sdk/repository/intelligence/discovery.py +27 -2
  59. package/python/agentsam_sdk/repository/intelligence/git.py +4 -0
  60. package/python/tests/test_repository_intelligence.py +30 -0
  61. package/src/cli/command-catalog.js +2 -1
  62. package/src/cli.js +10 -1
  63. package/src/commands/goap-world.js +134 -0
  64. package/src/commands/goap.js +11 -4
  65. package/src/commands/machine-binary.js +33 -27
  66. package/src/commands/machine-runtime.js +266 -0
  67. package/src/commands/machine.js +122 -51
  68. package/src/commands/package.js +530 -0
  69. package/src/commands/plan-ledger.js +370 -0
  70. package/src/commands/plan.js +183 -0
  71. package/src/commands/skill.js +78 -17
  72. package/src/knowledge/source.js +1 -1
  73. package/src/lib/slash-commands.js +1 -1
  74. package/src/local/runtime-store.js +24 -2
  75. package/src/local/sqlite.js +17 -0
  76. package/src/sam/operations/package-audit.js +41 -0
  77. package/src/sam/seed.js +2 -0
  78. package/skills/grok-auth/SKILL.md +0 -110
  79. package/skills/grok-auth/agentsam.skill.json +0 -25
  80. package/skills/grok-auth/references/grok-identity.md +0 -64
  81. package/skills/grok-auth/references/per-user-data.md +0 -49
  82. package/skills/grok-auth/references/prewired-and-env.md +0 -54
  83. package/skills/grok-auth/references/session-ui.md +0 -133
  84. package/skills/grok-auth/references/sign-in-methods.md +0 -55
  85. package/skills/grok-auth/references/wiring.md +0 -71
  86. package/skills/grok-building-games/SKILL.md +0 -213
  87. package/skills/grok-building-games/agentsam.skill.json +0 -25
  88. package/skills/grok-building-games/references/3d-libs.md +0 -64
  89. package/skills/grok-building-games/references/ai-pathfinding.md +0 -122
  90. package/skills/grok-building-games/references/audio.md +0 -129
  91. package/skills/grok-building-games/references/babylon.md +0 -202
  92. package/skills/grok-building-games/references/collision-physics.md +0 -122
  93. package/skills/grok-building-games/references/ecs-architecture.md +0 -111
  94. package/skills/grok-building-games/references/game-feel-juice.md +0 -110
  95. package/skills/grok-building-games/references/genres/board-card-chess.md +0 -89
  96. package/skills/grok-building-games/references/genres/endless-runner.md +0 -83
  97. package/skills/grok-building-games/references/genres/fps.md +0 -105
  98. package/skills/grok-building-games/references/genres/platformer-2d.md +0 -97
  99. package/skills/grok-building-games/references/genres/puzzle-match3-tetris.md +0 -131
  100. package/skills/grok-building-games/references/genres/racing-kart.md +0 -106
  101. package/skills/grok-building-games/references/genres/topdown-twin-stick.md +0 -97
  102. package/skills/grok-building-games/references/genres/tower-defense.md +0 -84
  103. package/skills/grok-building-games/references/genres/voxel-minecraft.md +0 -89
  104. package/skills/grok-building-games/references/input.md +0 -139
  105. package/skills/grok-building-games/references/phaser.md +0 -277
  106. package/skills/grok-building-games/references/procedural-generation.md +0 -141
  107. package/skills/grok-building-games/references/save-persistence.md +0 -108
  108. package/skills/grok-building-games/references/threejs-foundational.md +0 -148
  109. package/skills/grok-controls/SKILL.md +0 -274
  110. package/skills/grok-controls/agentsam.skill.json +0 -25
  111. package/skills/grok-design-ui/SKILL.md +0 -122
  112. package/skills/grok-design-ui/agentsam.skill.json +0 -25
  113. package/skills/grok-design-ui/references/animations.md +0 -379
  114. package/skills/grok-design-ui/references/performance.md +0 -88
  115. package/skills/grok-design-ui/references/refined-ui.md +0 -384
  116. package/skills/grok-design-ui/references/surfaces.md +0 -247
  117. package/skills/grok-design-ui/references/typography.md +0 -123
  118. package/skills/grok-game-animation-frames/SKILL.md +0 -84
  119. package/skills/grok-game-animation-frames/agentsam.skill.json +0 -25
  120. package/skills/grok-game-asset-core/SKILL.md +0 -69
  121. package/skills/grok-game-asset-core/agentsam.skill.json +0 -25
  122. package/skills/grok-game-character-consistency/SKILL.md +0 -69
  123. package/skills/grok-game-character-consistency/agentsam.skill.json +0 -25
  124. package/skills/grok-game-tilesets/SKILL.md +0 -65
  125. package/skills/grok-game-tilesets/agentsam.skill.json +0 -25
  126. package/skills/grok-game-ui-icons/SKILL.md +0 -56
  127. package/skills/grok-game-ui-icons/agentsam.skill.json +0 -25
  128. package/skills/grok-generate2dmap/LICENSE +0 -21
  129. package/skills/grok-generate2dmap/SKILL.md +0 -120
  130. package/skills/grok-generate2dmap/SOURCE.md +0 -6
  131. package/skills/grok-generate2dmap/agentsam.skill.json +0 -25
  132. package/skills/grok-generate2dmap/references/deliverables.md +0 -101
  133. package/skills/grok-generate2dmap/references/layered-map-contract.md +0 -209
  134. package/skills/grok-generate2dmap/references/map-strategies.md +0 -341
  135. package/skills/grok-generate2dmap/references/object-production-gate.md +0 -24
  136. package/skills/grok-generate2dmap/references/pipeline.md +0 -149
  137. package/skills/grok-generate2dmap/references/prop-pack-contract.md +0 -174
  138. package/skills/grok-generate2dmap/references/side-scroll-stages.md +0 -29
  139. package/skills/grok-generate2dmap/scripts/compose_layered_preview.py +0 -157
  140. package/skills/grok-generate2dmap/scripts/extract_prop_pack.py +0 -369
  141. package/skills/grok-generate2dsprite/LICENSE +0 -21
  142. package/skills/grok-generate2dsprite/SKILL.md +0 -313
  143. package/skills/grok-generate2dsprite/SOURCE.md +0 -6
  144. package/skills/grok-generate2dsprite/agentsam.skill.json +0 -25
  145. package/skills/grok-generate2dsprite/references/modes.md +0 -124
  146. package/skills/grok-generate2dsprite/references/prompt-rules.md +0 -315
  147. package/skills/grok-generate2dsprite/scripts/generate2dsprite.py +0 -1031
  148. package/skills/grok-generate2dsprite/scripts/make_layout_guide.py +0 -109
  149. package/skills/grok-imagine/SKILL.md +0 -201
  150. package/skills/grok-imagine/agentsam.skill.json +0 -25
  151. package/skills/grok-multiplayer-p2p/SKILL.md +0 -111
  152. package/skills/grok-multiplayer-p2p/agentsam.skill.json +0 -25
  153. package/skills/grok-multiplayer-p2p/references/react-binding.md +0 -144
  154. package/skills/grok-multiplayer-p2p/references/signaling-relay.md +0 -269
  155. package/skills/grok-neon/SKILL.md +0 -157
  156. package/skills/grok-neon/agentsam.skill.json +0 -25
  157. package/skills/grok-og/SKILL.md +0 -102
  158. package/skills/grok-og/agentsam.skill.json +0 -25
  159. package/skills/grok-og/references/brand-pass.md +0 -53
  160. package/skills/grok-og/references/custom-card.md +0 -107
  161. package/skills/grok-og/references/favicon-and-icons.md +0 -48
  162. package/skills/grok-og/references/og-type-contract.md +0 -18
  163. package/skills/grok-og/references/placeholder-card.md +0 -21
  164. package/skills/grok-og/references/x-banner.md +0 -41
  165. package/skills/grok-threejs/SKILL.md +0 -67
  166. package/skills/grok-threejs/agentsam.skill.json +0 -25
  167. package/skills/grok-threejs/references/llms-full.txt +0 -2780
  168. package/skills/grok-video2dsprite/LICENSE +0 -21
  169. package/skills/grok-video2dsprite/SKILL.md +0 -236
  170. package/skills/grok-video2dsprite/SOURCE.md +0 -6
  171. package/skills/grok-video2dsprite/agentsam.skill.json +0 -25
  172. package/skills/grok-video2dsprite/references/pipeline.md +0 -90
  173. package/skills/grok-video2dsprite/references/prompt-rules.md +0 -63
  174. package/skills/grok-video2dsprite/scripts/video2dsprite.py +0 -490
  175. package/skills/grok-xai-api/SKILL.md +0 -152
  176. package/skills/grok-xai-api/agentsam.skill.json +0 -25
  177. package/test/account-session.test.mjs +0 -101
  178. package/test/agent-capabilities.test.mjs +0 -67
  179. package/test/app-authority-context.test.mjs +0 -32
  180. package/test/app-building-skills.test.mjs +0 -61
  181. package/test/apps-scaffold-contract.test.mjs +0 -115
  182. package/test/blender-cad.test.mjs +0 -146
  183. package/test/cad-docker.test.mjs +0 -96
  184. package/test/capabilities.test.mjs +0 -133
  185. package/test/cli/api-key-env-whoami.test.mjs +0 -129
  186. package/test/cli/catalog-authority.test.mjs +0 -64
  187. package/test/cli/codebaseindex-plan-ux.test.mjs +0 -37
  188. package/test/cli/eval-live.test.mjs +0 -219
  189. package/test/cli/go.test.mjs +0 -128
  190. package/test/cli/local-vault-and-provider-setup.test.mjs +0 -268
  191. package/test/cli/machine-command.test.mjs +0 -34
  192. package/test/cli/mcp-client.test.mjs +0 -256
  193. package/test/cli/preferences-runtime.test.mjs +0 -11
  194. package/test/cli/runtime-persist.test.mjs +0 -56
  195. package/test/cli/runtime-ui.test.mjs +0 -141
  196. package/test/cli/rust-command.test.mjs +0 -21
  197. package/test/cli/skill-npm-and-env.test.mjs +0 -52
  198. package/test/cli/status-actions.test.mjs +0 -88
  199. package/test/cli/wireframes-go-registry.test.mjs +0 -139
  200. package/test/cli-preferences.test.mjs +0 -46
  201. package/test/cloudflare-connector.test.mjs +0 -93
  202. package/test/cloudflare-runtime.test.mjs +0 -82
  203. package/test/context.test.mjs +0 -159
  204. package/test/credentials-audit.test.mjs +0 -113
  205. package/test/deploy-health-scan.test.mjs +0 -95
  206. package/test/deploy-receipt.test.mjs +0 -91
  207. package/test/dockerize.test.mjs +0 -93
  208. package/test/error-diagnostics.test.mjs +0 -124
  209. package/test/eval-context.test.mjs +0 -37
  210. package/test/execution-approvals.test.mjs +0 -27
  211. package/test/fixtures/cad/courtyard-house.json +0 -208
  212. package/test/fixtures/knowledge-rpc-worker.mjs +0 -16
  213. package/test/fixtures/project-authority/customer-app/.agentsam/app.json +0 -5
  214. package/test/fixtures/project-authority/customer-app/apps/my-product/index.ts +0 -1
  215. package/test/fixtures/project-authority/customer-app/wrangler.toml +0 -17
  216. package/test/gcloud-auth.test.mjs +0 -111
  217. package/test/go/build-source-identity.test.mjs +0 -31
  218. package/test/go/cloudflare-probe.test.mjs +0 -317
  219. package/test/go/distribution.test.mjs +0 -28
  220. package/test/google-cloud-connection.test.mjs +0 -83
  221. package/test/google-cloud-inventory.test.mjs +0 -64
  222. package/test/indexing-provider.test.mjs +0 -29
  223. package/test/init-options.test.mjs +0 -35
  224. package/test/integration/ai-access-onboarding.test.mjs +0 -47
  225. package/test/integration/app-command.test.mjs +0 -85
  226. package/test/integration/autorag-project-authority.integration.test.mjs +0 -51
  227. package/test/integration/autorag-runtime-discovery.test.mjs +0 -107
  228. package/test/integration/cad-discovery.test.mjs +0 -158
  229. package/test/integration/cad-docker-executor.test.mjs +0 -249
  230. package/test/integration/cad-execution.test.mjs +0 -184
  231. package/test/integration/cad-project-app.test.mjs +0 -31
  232. package/test/integration/cad-project-d1.test.mjs +0 -25
  233. package/test/integration/cad-project-native.test.mjs +0 -24
  234. package/test/integration/cad-project-workflow.test.mjs +0 -9
  235. package/test/integration/cad-project.test.mjs +0 -85
  236. package/test/integration/cli-help.test.mjs +0 -41
  237. package/test/integration/cms-app-scaffold.test.mjs +0 -77
  238. package/test/integration/cms-site-tenancy-contract.test.mjs +0 -268
  239. package/test/integration/codebaseindex-ingest.test.mjs +0 -255
  240. package/test/integration/core-client.integration.test.mjs +0 -55
  241. package/test/integration/database-hosted-honesty.test.mjs +0 -49
  242. package/test/integration/desktop-keychain-boundary.test.mjs +0 -45
  243. package/test/integration/error-runtime-rpc.test.mjs +0 -71
  244. package/test/integration/features-resolve.test.mjs +0 -147
  245. package/test/integration/hosted-work-host-authority.test.mjs +0 -47
  246. package/test/integration/icon-registry.test.mjs +0 -67
  247. package/test/integration/ingest-discover-models.test.mjs +0 -30
  248. package/test/integration/inspect-path-cli.test.mjs +0 -46
  249. package/test/integration/install-script.test.mjs +0 -110
  250. package/test/integration/inventory-core.test.mjs +0 -53
  251. package/test/integration/inventory-eligibility.test.mjs +0 -59
  252. package/test/integration/inventory-evidence.test.mjs +0 -125
  253. package/test/integration/knowledge-rpc.test.mjs +0 -112
  254. package/test/integration/local-fs.test.mjs +0 -113
  255. package/test/integration/local-provider-bridge.test.mjs +0 -65
  256. package/test/integration/local-studio-settings-production.test.mjs +0 -40
  257. package/test/integration/lockfile-sync.test.mjs +0 -26
  258. package/test/integration/merkle-cli.test.mjs +0 -61
  259. package/test/integration/merkle-persistence-identity.test.mjs +0 -48
  260. package/test/integration/plugins-cloudflare.integration.test.mjs +0 -28
  261. package/test/integration/provider-env-cli.test.mjs +0 -60
  262. package/test/integration/provider-factory.test.mjs +0 -197
  263. package/test/integration/repository-company-graph.test.mjs +0 -90
  264. package/test/integration/runtime-migrations.test.mjs +0 -87
  265. package/test/integration/runtime-status.integration.test.mjs +0 -227
  266. package/test/integration/sam-activity-recovery.test.mjs +0 -147
  267. package/test/integration/sam-decision.test.mjs +0 -584
  268. package/test/integration/sam-kernel.test.mjs +0 -99
  269. package/test/integration/sam-planning-astar.test.mjs +0 -279
  270. package/test/integration/scaffold-cloudflare.test.mjs +0 -46
  271. package/test/integration/skill-runtime.test.mjs +0 -240
  272. package/test/integration/storage-architecture.test.mjs +0 -154
  273. package/test/integration/store-discovery.test.mjs +0 -44
  274. package/test/integration/studio-fs-pty-e2e.test.mjs +0 -294
  275. package/test/integration/terminal-exec.integration.test.mjs +0 -86
  276. package/test/integration/theme-package-registry.test.mjs +0 -31
  277. package/test/integration/tool-runtime.test.mjs +0 -124
  278. package/test/integration/tool-schema.test.mjs +0 -59
  279. package/test/jr-dev-skill.test.mjs +0 -26
  280. package/test/knowledge-context-pack.test.mjs +0 -19
  281. package/test/knowledge-postgres.test.mjs +0 -40
  282. package/test/knowledge-service.test.mjs +0 -110
  283. package/test/knowledge.test.mjs +0 -206
  284. package/test/live/terminal-transport.live.test.mjs +0 -24
  285. package/test/local-sessions.test.mjs +0 -57
  286. package/test/local-studio-deploy.test.mjs +0 -83
  287. package/test/loopback-oauth.test.mjs +0 -53
  288. package/test/merkle-render.test.mjs +0 -31
  289. package/test/mini.test.mjs +0 -140
  290. package/test/model-catalog.test.mjs +0 -70
  291. package/test/models.test.mjs +0 -309
  292. package/test/npm10-lock.test.mjs +0 -29
  293. package/test/ollama.test.mjs +0 -137
  294. package/test/open-url.test.mjs +0 -64
  295. package/test/openai-responses.test.mjs +0 -155
  296. package/test/portable-context.test.mjs +0 -94
  297. package/test/project-config.test.mjs +0 -81
  298. package/test/project-rules.test.mjs +0 -44
  299. package/test/provider-credentials.test.mjs +0 -106
  300. package/test/rehydrate.test.mjs +0 -25
  301. package/test/release-hygiene.test.mjs +0 -42
  302. package/test/repository-snapshot-view.test.mjs +0 -112
  303. package/test/responses-runner.test.mjs +0 -465
  304. package/test/runtime-activity.test.mjs +0 -98
  305. package/test/sdk-worker-contract.test.mjs +0 -72
  306. package/test/security.test.mjs +0 -266
  307. package/test/setup-planner.test.mjs +0 -74
  308. package/test/setup-runtime.test.mjs +0 -51
  309. package/test/shell.test.mjs +0 -281
  310. package/test/skills.test.mjs +0 -22
  311. package/test/smoke.mjs +0 -122
  312. package/test/telemetry.test.mjs +0 -79
  313. package/test/terminal/local-pty.mock.test.mjs +0 -153
  314. package/test/terminal-machine-identity.test.mjs +0 -88
  315. package/test/theme-portability.test.mjs +0 -14
  316. package/test/tools-search.test.mjs +0 -73
  317. package/test/unit/website-assets-bindings.test.mjs +0 -60
  318. package/test/whoami-resume.test.mjs +0 -157
@@ -1,277 +0,0 @@
1
- # Phaser 3 / 4 — Deep Engine Guide (scenes, physics, scale, tilemaps, pooling, architecture)
2
-
3
- Phaser is the default choice for **2D browser games**. This file goes deep on the parts that actually break in generated games. It assumes the general loop/mobile/perf rules in `threejs-foundational.md` and does **not** repeat them.
4
-
5
- > **Version note (verified):** Phaser **3** is the mature, ubiquitous line (3.90+). Phaser **4** shipped in 2025 with a rewritten WebGL renderer (internally "Beam") and optional **WebGPU** path, plus the core split into modular packages. Phaser 4 is *intentionally near-API-compatible with Phaser 3* — the Scene lifecycle, Arcade/Matter physics, Scale Manager, Loader and GameObject APIs described here carry over. Prefer Phaser 3 (3.90.x) for maximum stability/plugin compatibility today; use Phaser 4 when you want the faster renderer/WebGPU and can tolerate a younger ecosystem. When unsure, target v3 API surface — it runs on both.
6
-
7
- ---
8
-
9
- ## 1. Scene model — the thing to get right first
10
-
11
- A Phaser game is a **stack of Scenes**, each an almost self-contained world (own display list, cameras, input, tweens, physics, clock). The `Phaser.Game` instance owns only truly global systems: **Renderer, Animation Manager, global Cache, Registry (global DataManager), Input Manager, Scene Manager, Sound Manager, TimeStep**. Everything else (`this.add`, `this.tweens`, `this.physics`, `this.input`, `this.cameras`) is **per-scene**. A tween created in Scene A is unrelated to one in Scene B.
12
-
13
- ### Lifecycle callbacks (exact order)
14
-
15
- ```js
16
- class GameScene extends Phaser.Scene {
17
- constructor() { super('game'); } // unique string key
18
- init(data) {} // (1) reset per-run state HERE, receives data from start/launch
19
- preload() {} // (2) queue asset loads only
20
- create(data) {} // (3) build objects; assets from preload are now ready
21
- update(time, delta){} // (4) every tick while RUNNING (delta in ms)
22
- }
23
- ```
24
-
25
- Status flow: `PENDING → INIT (booted) → START → LOADING → CREATING → RUNNING`. `RUNNING` can go to `PAUSED` (renders, no update) or `SLEEPING` (no update, no render), then back. `stop()` → `SHUTDOWN` (can restart). `remove()` → `DESTROYED` (gone).
26
-
27
- ### The scene stack pattern (best-practice architecture)
28
-
29
- Run **multiple scenes at once**, layered bottom→top by config order:
30
-
31
- - **Boot** — load the tiny assets needed for the loading screen (bar image, logo); set Scale/registry defaults; `this.scene.start('preload')`.
32
- - **Preload** — load everything with a visible progress bar (`this.load.on('progress', v => …)`), then `start('menu')`.
33
- - **Menu / Title** — UI, start button.
34
- - **Game** — actual gameplay.
35
- - **UI / HUD** — run **in parallel** over Game via `this.scene.launch('ui')`; keeps HUD stable while Game restarts. Communicate via events/registry, never direct references.
36
- - **Pause / GameOver** — overlay scenes launched over Game.
37
-
38
- ### Scene control verbs (get these exactly right — a top bug source)
39
-
40
- | Method | Effect on target | Effect on caller |
41
- |---|---|---|
42
- | `start('k')` | **stops** then starts k | **stops** caller |
43
- | `launch('k')` | starts k (parallel) | caller keeps running |
44
- | `switch('k')` | starts or **wakes** k | **sleeps** caller |
45
- | `run('k')` | resume if paused / wake if sleeping / restart if running / else start | caller keeps running |
46
- | `pause`/`resume` | freeze update, keep render | — |
47
- | `sleep`/`wake` | freeze update + render | — |
48
- | `stop` | shutdown | — |
49
-
50
- Rules of thumb: gameplay you replay from scratch → **start/stop** or **sleep/wake**; a modal (pause menu, shop) over live gameplay → **pause/resume** or **launch** an overlay; menus you revisit → **sleep/wake** is easier to reason about than start/stop.
51
-
52
- ### The #1 Phaser correctness bug: state not reset on restart
53
-
54
- Scenes are **booted once, started many times**. Module-level or constructor-set flags persist across restarts.
55
-
56
- ```js
57
- // BROKEN: gameOver stays true after restart → instant game over
58
- class S extends Phaser.Scene { constructor(){ super('s'); this.gameOver = false; } }
59
-
60
- // CORRECT: reset run state in init()
61
- class S extends Phaser.Scene {
62
- constructor(){ super('s'); }
63
- init(){ this.gameOver = false; this.score = 0; } // runs on every start
64
- }
65
- ```
66
-
67
- Related: arrays of destroyed game objects survive restart. **Clean up on SHUTDOWN**:
68
- ```js
69
- this.events.once('shutdown', () => { this.enemies.length = 0; });
70
- ```
71
-
72
- ### Cleanup rule
73
-
74
- On `shutdown`, Phaser auto-destroys the scene's display list, tweens, timers and input. But **external references, global timers, DOM listeners, EventEmitter subscriptions on cross-scene emitters, and pooled arrays are yours to clear**. A destroyed GameObject still registered on an emitter is a classic crash. Always `this.events.once('shutdown', cleanup)`.
75
-
76
- ---
77
-
78
- ## 2. Physics: Arcade vs Matter (choose deliberately)
79
-
80
- Phaser ships two physics systems. **Pick Arcade unless you specifically need Matter** — mixing/over-choosing is a common performance and complexity mistake.
81
-
82
- ### Arcade Physics — AABB, fast, for platformers/shooters/arcade
83
-
84
- - **Only axis-aligned bounding boxes (rectangles) and circles.** No rotation of bodies, no slopes, no polygons. Extremely fast; handles thousands of bodies.
85
- - Two body types: **Dynamic** (`this.physics.add.sprite`) responds to velocity/gravity/collisions; **Static** (`this.physics.add.staticGroup`) never moves (platforms, walls) and is cheaper.
86
- - Core calls: `body.setVelocity(x,y)`, `setGravityY`, `setBounce`, `setCollideWorldBounds(true)`, `setImmovable(true)`, `setAllowGravity(false)`.
87
- - **Collide vs Overlap:**
88
- - `this.physics.add.collider(a, b, cb)` — separates bodies (they block each other), optional callback.
89
- - `this.physics.add.overlap(a, b, cb)` — detects overlap without separation (pickups, hitboxes, triggers).
90
- - Both accept Groups, arrays, or single objects; add a `processCallback` (4th arg) to conditionally allow/deny a collision.
91
- - Config: `physics: { default: 'arcade', arcade: { gravity: { y: 300 }, debug: true } }`. Turn on `debug` while building — it draws body outlines and velocity vectors and reveals 90% of "collision doesn't work" issues.
92
- - Set body size explicitly for non-rectangular sprites: `sprite.body.setSize(w,h).setOffset(x,y)` or `setCircle(r)`.
93
- - **Fast small objects tunnel through thin walls** (AABB, discrete step). Mitigate: thicker colliders, cap max velocity, or set world bounds; Arcade has limited continuous collision.
94
-
95
- ### Matter.js — full rigid-body, for physics-toys/ragdolls/complex shapes
96
-
97
- - Real rigid-body dynamics: rotation, arbitrary convex/compound polygons, constraints/joints, springs, restitution, friction, sleeping bodies.
98
- - Use when the *physics itself is the game* (Angry-Birds-like, stacking, contraptions, vehicles) or you need realistic collisions/rotation.
99
- - Config: `physics: { default: 'matter', matter: { gravity: { y: 1 }, debug: true } }`.
100
- - `this.matter.add.sprite(x,y,key,null,{ shape:'circle', restitution:0.6 })`. Use collision events: `this.matter.world.on('collisionstart', (e)=>{ for (const p of e.pairs){…} })`, plus **collision filters/categories** for what hits what.
101
- - Heavier than Arcade; watch body counts on mobile. Enable body sleeping for idle stacks.
102
-
103
- **Decision:** platformer, top-down shooter, endless runner, breakout, most casual games → **Arcade**. Physics sandbox, realistic stacking/rotation, joints → **Matter**. Don't reach for Matter just for "better collisions" — 90% of 2D games are Arcade games.
104
-
105
- ---
106
-
107
- ## 3. Scale Manager — responsive/mobile without stretching
108
-
109
- Set once in game config. The two modes that matter:
110
-
111
- ```js
112
- scale: {
113
- mode: Phaser.Scale.FIT, // letterbox: keep aspect, fit inside parent
114
- autoCenter: Phaser.Scale.CENTER_BOTH,
115
- width: 800, height: 600, // your fixed design resolution
116
- parent: 'game',
117
- // min/max clamp the FIT scaling:
118
- min: { width: 400, height: 300 }, max: { width: 1600, height: 1200 }
119
- }
120
- ```
121
-
122
- - **`FIT`** — canvas scales to fit the parent preserving aspect ratio; letterbox bars appear. Your game logic runs at a **fixed design resolution** (800×600 here) — simplest and most predictable. Best default for most games.
123
- - **`RESIZE`** — canvas always matches parent size; **no fixed resolution**, game world dimensions change. You must handle the `resize` event and reposition/relayout UI yourself (`this.scale.on('resize', (gameSize)=>{…})`). Use for games that should truly fill the screen (strategy, infinite canvas) where you can reflow layout.
124
- - `ENVELOP` — cover the parent (may crop). `WIDTH_CONTROLS_HEIGHT` / `HEIGHT_CONTROLS_WIDTH` — lock one axis.
125
- - `NONE` — fixed, no scaling.
126
-
127
- **Orientation:** listen `this.scale.on('orientationchange', o => …)` or check `this.scale.isPortrait`. For a landscape-only game, show a "rotate your device" overlay in portrait rather than fighting the layout. Combine with `viewport` meta + `touch-action: none` (see three.js file §7).
128
-
129
- **Retina/DPR:** Phaser respects `resolution`/DPR via the renderer; for pixel-art keep `pixelArt: true` (sets nearest-neighbor + disables antialias) and `roundPixels: true` to avoid sub-pixel shimmer. Rendering at a modest internal resolution and letting FIT upscale is a legit perf win on mobile.
130
-
131
- ---
132
-
133
- ## 4. Sprites, atlases & animations
134
-
135
- - **Always pack sprites into a texture atlas** (TexturePacker → JSON Hash/Array, or free tools). One atlas = one texture bind = fewer draw calls and no seams. `this.load.atlas('sheet','sheet.png','sheet.json')`, then `this.add.sprite(x,y,'sheet','frameName')`.
136
- - Uniform grid frames → `this.load.spritesheet('run','run.png',{ frameWidth:32, frameHeight:32 })`.
137
- - Animations are **global** (stored on the Animation Manager), defined once, reused by any sprite in any scene:
138
- ```js
139
- this.anims.create({ key:'run', frames:this.anims.generateFrameNames('sheet',{prefix:'run_',start:0,end:7,zeroPad:2}), frameRate:12, repeat:-1 });
140
- sprite.play('run');
141
- ```
142
- - Batching: sprites sharing the **same texture** batch into few draw calls. Interleaving textures (sprite from atlas A, then B, then A) breaks the batch. Group same-texture sprites and set depth thoughtfully.
143
- - Bitmap fonts (`load.bitmapFont`) render far cheaper than lots of dynamic `Text` objects (each `Text` is its own canvas texture — expensive to update every frame). For frequently-changing text prefer bitmap fonts or update sparingly.
144
-
145
- ---
146
-
147
- ## 5. Tilemaps
148
-
149
- For levels, use **Tiled** (`.tmx`/exported JSON) rather than hand-placing sprites.
150
-
151
- ```js
152
- // preload
153
- this.load.image('tiles','tileset.png');
154
- this.load.tilemapTiledJSON('map','level1.json');
155
- // create
156
- const map = this.make.tilemap({ key:'map' });
157
- const tileset = map.addTilesetImage('tilesetNameInTiled','tiles');
158
- const ground = map.createLayer('Ground', tileset, 0, 0);
159
- ground.setCollisionByProperty({ collides:true }); // set per-tile in Tiled
160
- this.physics.add.collider(player, ground);
161
- // object layer for spawns/enemies:
162
- const objs = map.getObjectLayer('Objects').objects;
163
- ```
164
-
165
- - **Static layers** (`createLayer`) are fast (culled, batched). Dynamic tile edits use the same layer API (`putTileAt`, `removeTileAt`) — layers are dynamic in current Phaser.
166
- - Set collision by **property** or by tile index/array; visualize with `layer.renderDebug(graphics)`.
167
- - Cull off-screen tiles automatically via the camera; keep tile layers reasonably sized, split huge worlds into chunks.
168
- - Use **object layers** for spawn points, triggers, and entity placement instead of hardcoding coordinates.
169
-
170
- ---
171
-
172
- ## 6. Object pooling with Groups (the mobile perf lever)
173
-
174
- Creating/destroying bullets, enemies, particles every frame thrashes GC and stutters. **Pool them.**
175
-
176
- ```js
177
- this.bullets = this.physics.add.group({
178
- classType: Bullet, maxSize: 64, runChildUpdate: true
179
- });
180
- // fire:
181
- const b = this.bullets.get(x, y); // reuse dead one or make new (up to maxSize)
182
- if (!b) return; // pool exhausted → skip
183
- b.enableBody(true, x, y, true, true); // reactivate + show
184
- // on expire/off-screen: DON'T destroy — recycle:
185
- b.disableBody(true, true); // deactivate + hide, returns to pool
186
- ```
187
-
188
- - `get()` returns an **inactive** member (recycled) or creates a new one until `maxSize`; returns `null` when full — always null-check.
189
- - `killAndHide(child)` / `disableBody(true,true)` recycles; avoid `destroy()` for pooled objects.
190
- - `runChildUpdate:true` calls each active child's `preUpdate`/`update` — put per-object logic in the class.
191
- - Only iterate **active** members: `this.bullets.getChildren()` and skip `!child.active`, or use `group.getMatching('active', true)`.
192
- - Reuse tween/particle emitters too; destroy emitters and tweens on `SHUTDOWN`.
193
-
194
- ---
195
-
196
- ## 7. Input
197
-
198
- - Keyboard: `this.cursors = this.input.keyboard.createCursorKeys()` (arrows + space/shift), or `this.keys = this.input.keyboard.addKeys('W,A,S,D')`. **Read state in `update` via `.isDown`**; use `Phaser.Input.Keyboard.JustDown(key)` for single-press actions. Don't drive movement off `keydown` events.
199
- - Pointer/touch: `this.input.on('pointerdown', p => …)`; enable object interaction with `sprite.setInteractive()` then `sprite.on('pointerdown', …)`. Set explicit hit areas for irregular sprites.
200
- - Unify keyboard + touch + **Gamepad API** (`this.input.gamepad`) into one input-state object your `update` reads, so control code doesn't branch per device.
201
- - Drag: `this.input.setDraggable(sprite)` + `'drag'` event. For virtual joysticks on mobile, integrate nipplejs or the rex virtual joystick plugin and feed normalized -1..1 into your input state.
202
-
203
- ---
204
-
205
- ## 8. Cameras & tweens
206
-
207
- - Each scene has a main camera (`this.cameras.main`). Follow the player: `camera.startFollow(player, true, 0.08, 0.08)` (lerp for smooth follow), set `camera.setBounds(0,0,mapW,mapH)` and `setZoom()`. `setDeadzone()` avoids jitter around the player.
208
- - Effects for free polish: `camera.shake(200, 0.01)`, `camera.flash()`, `camera.fade()`. Multiple cameras enable split-screen / minimaps (`camera.ignore(objects)` to exclude).
209
- - Tweens for juice: `this.tweens.add({ targets:sprite, scale:1.2, yoyo:true, duration:120, ease:'Sine.easeInOut' })`. **Always destroy long-lived/looping tweens on SHUTDOWN** or they reference dead objects.
210
-
211
- ---
212
-
213
- ## 9. Cross-scene communication (avoid spaghetti)
214
-
215
- - **Registry** (global DataManager): `this.registry.set('score', 0)` / `get` — shared across all scenes; emits `changedata` events.
216
- - **Scene events / a shared EventEmitter** ("EventsCenter"): create one `new Phaser.Events.EventEmitter()` in a module, import into scenes, emit/subscribe. Lets the UI scene react to Game scene events with **zero direct coupling**. Always `off()` listeners on shutdown.
217
- - `this.scene.get('ui').events.emit(...)` works but couples scenes — prefer the shared emitter/registry.
218
- - Pass one-shot data via `this.scene.start('game', { level: 3 })` → arrives in `init(data)` / `create(data)`.
219
-
220
- ---
221
-
222
- ## 10. Performance checklist (Phaser-specific)
223
-
224
- - **Object pooling** for anything spawned repeatedly (bullets, enemies, particles, floating text).
225
- - **Texture atlases** everywhere; group same-texture draws to keep batches intact.
226
- - Turn **off physics debug** in production; only add bodies to objects that need them.
227
- - Process **only active** objects; set `sprite.active=false`/`visible=false` for off-screen entities instead of updating them.
228
- - Prefer **static** physics bodies / static tile layers for non-moving geometry.
229
- - Minimize per-frame `Text` updates and `Graphics` re-draws (redrawing a Graphics every frame is expensive) — cache to a texture (`generateTexture`) or use bitmap fonts.
230
- - Avoid per-frame allocations in `update`; reuse vectors/objects.
231
- - Destroy tweens, timers (`this.time` events), and particle emitters on `SHUTDOWN`; clear pooled arrays.
232
- - Lazy-load per-level assets in that level's preload; unload with `this.textures.remove` / `this.cache` when leaving big levels.
233
- - Smaller canvas + FIT upscale on low-end mobile; consider `Phaser.CANVAS` fallback only if WebGL is unavailable (WebGL is default and much faster).
234
- - Profile with the browser FPS meter and `game.loop.actualFps`; Phaser 4's WebGPU path reduces CPU draw-call overhead further.
235
-
236
- ---
237
-
238
- ## 11. Common Phaser pitfalls (checklist)
239
-
240
- - Run-state not reset in `init()` → instant game-over / carried-over score after restart.
241
- - Not cleaning arrays/emitter listeners on `shutdown` → crashes on destroyed objects after restart.
242
- - Using `this.scene.start` when you meant `launch` (start stops the caller — kills your HUD).
243
- - Movement/animation not scaled by `delta` (Phaser `update(time, delta)` gives delta in **milliseconds**).
244
- - Physics body doesn't match sprite art → set `body.setSize/offset`; wrong/no collider group; forgetting `setCollideWorldBounds`.
245
- - Fast objects tunneling through thin walls in Arcade → thicker walls / velocity cap.
246
- - Text objects updated every frame tanking FPS → bitmap fonts / update on change only.
247
- - Creating instead of pooling bullets/enemies → GC stutter on mobile.
248
- - `RESIZE` scale mode without repositioning UI → misaligned HUD; use `FIT` unless you handle `resize`.
249
- - Loading assets in `create` instead of `preload` → assets not ready / race conditions.
250
- - Mixing Matter + Arcade needlessly, or choosing Matter when Arcade suffices → perf and complexity cost.
251
-
252
- ---
253
-
254
- ## Defaults to apply
255
-
256
- - **Default to Phaser (v3 API) for any 2D game**; scaffold the **Boot → Preload(progress bar) → Menu → Game → parallel UI → Pause/GameOver** scene stack automatically.
257
- - **Always put per-run state reset in `init()`** and register a `this.events.once('shutdown', cleanup)` in every gameplay scene — this alone eliminates the most common generated-game bug (broken restart).
258
- - **Choose Arcade physics by default; only emit Matter when the physics is the game.** Encode the decision table above in the builder's engine-selection step.
259
- - **Emit object pools (Groups with `maxSize` + recycle via `disableBody`) for bullets/enemies/particles** rather than create/destroy, and **texture atlases** for all sprites.
260
- - Use **`Scale.FIT` + fixed design resolution + `CENTER_BOTH`** as the responsive default; add a rotate-device overlay for orientation-locked games.
261
- - Load levels from **Tiled JSON tilemaps** with collision-by-property and object layers for spawns, instead of hardcoded coordinates.
262
- - Decouple scenes via a **shared EventEmitter + Registry**, never direct scene references.
263
- - Turn **physics `debug` on during generation/testing, off in the shipped build.**
264
-
265
- ---
266
-
267
- ## Sources
268
- - Phaser official docs — Scenes (lifecycle, systems, control methods, restart pitfalls): https://docs.phaser.io/phaser/concepts/scenes
269
- - Phaser docs — Arcade Physics: https://docs.phaser.io/phaser/concepts/physics/arcade ; Matter Physics: https://docs.phaser.io/phaser/concepts/physics/matter
270
- - Phaser docs — Scale Manager: https://docs.phaser.io/phaser/concepts/scale-manager
271
- - Phaser docs — Tilemaps: https://docs.phaser.io/phaser/concepts/tilemaps ; Loader: https://docs.phaser.io/phaser/concepts/loader
272
- - Phaser docs — Groups & object pooling: https://docs.phaser.io/phaser/concepts/gameobjects/group ; Animations: https://docs.phaser.io/phaser/concepts/animations
273
- - Phaser docs — Input (keyboard/pointer/gamepad): https://docs.phaser.io/phaser/concepts/input
274
- - Phaser 4 announcement / release: https://phaser.io/news (Phaser 4 + Beam renderer / WebGPU) and https://github.com/phaserjs/phaser/releases
275
- - API reference: https://newdocs.phaser.io/docs/latest
276
- - franzeus.medium.com — "How I optimized my Phaser 3 action game" (pooling, atlases, active-only processing)
277
- - joshmorony.com — Phaser scaling / responsive guides
@@ -1,141 +0,0 @@
1
- # Procedural Generation (seeded RNG, noise, dungeons/mazes/terrain, wave function collapse)
2
-
3
- Consolidated from Red Blob Games, the simplex-noise library, and WFC primary sources (see Sources). Focus: what an AI builder needs to generate **varied but reproducible** worlds without the classic bugs — non-deterministic output, disconnected dungeons, blobby/banded terrain.
4
-
5
- ---
6
-
7
- ## 1. Seeded RNG is the foundation — never use bare `Math.random()`
8
-
9
- `Math.random()` is **not seedable**, so you can't reproduce a level, share a seed, debug a bad map, or sync generation across clients in multiplayer. **Always drive procedural generation from a seeded PRNG.**
10
-
11
- **mulberry32** — the go-to small, fast, good-quality 32-bit seeded PRNG:
12
- ```js
13
- function mulberry32(seed) {
14
- return function () {
15
- let t = (seed += 0x6D2B79F5);
16
- t = Math.imul(t ^ (t >>> 15), t | 1);
17
- t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
18
- return ((t ^ (t >>> 14)) >>> 0) / 4294967296; // [0,1)
19
- };
20
- }
21
- const rng = mulberry32(12345); // same seed → identical sequence forever
22
- ```
23
-
24
- Rules:
25
- - **Hash string seeds to an int first** (e.g. `xmur3`) so `"cave-42"` maps to a stable number.
26
- - **Use separate RNG streams for independent systems** (terrain vs loot vs enemy placement) so changing one doesn't reshuffle the others (`mulberry32(seed)`, `mulberry32(seed ^ 0x9e3779b9)`, …).
27
- - Add helpers: `randRange(a,b)=a+rng()*(b-a)`, `randInt`, `pick(arr)`, `shuffle` (Fisher–Yates using `rng`).
28
- - For **networked/deterministic** generation, both sides must run the *same* PRNG and consume it in the *same order* (deterministic multiplayer is out of scope on this deploy target). Order-of-consumption bugs are the #1 desync source.
29
- - Alternatives: `alea`, PCG. mulberry32 is plenty for games.
30
-
31
- ---
32
-
33
- ## 2. Noise: value / Perlin / simplex (for terrain, textures, organic fields)
34
-
35
- Random-per-cell is white noise (harsh, uncorrelated). **Coherent noise** produces smooth, natural-looking fields where nearby points are similar.
36
-
37
- - **Value noise** — cheap, interpolate random lattice values. OK for simple stuff.
38
- - **Perlin noise** — classic gradient noise; can show axis-aligned artifacts.
39
- - **Simplex / OpenSimplex** — fewer directional artifacts, scales better to higher dimensions; preferred default. Use the **`simplex-noise` npm package**.
40
- - **v4 API changed:** no more `new SimplexNoise()`. Use factory functions and pass your seeded PRNG:
41
- ```js
42
- import { createNoise2D } from 'simplex-noise';
43
- const noise2D = createNoise2D(mulberry32(12345)); // returns ~[-1, 1]
44
- const v = noise2D(x * 0.01, y * 0.01); // scale coords = "frequency"
45
- ```
46
- (Also `createNoise3D`/`createNoise4D`; passing a PRNG makes output reproducible — without one it uses `Math.random()` = non-reproducible.)
47
-
48
- **Key techniques (from Red Blob Games "Making maps with noise"):**
49
- - **Frequency:** multiply input coords by a scale; small scale = large smooth features.
50
- - **Octaves / fBm:** sum several noise layers at increasing frequency and decreasing amplitude (`amplitude *= persistence(≈0.5)`, `frequency *= lacunarity(≈2)`) for natural detail.
51
- - **Normalize** noise from [−1,1] to [0,1] before thresholding.
52
- - **Redistribution:** `elev = Math.pow(elev, k)` to bias toward valleys/plains vs peaks.
53
- - **Island mask:** multiply by a radial falloff so edges are water.
54
- - **Biomes:** sample **two independent noise fields** (elevation + moisture) and look up a Whittaker-style biome table — don't derive moisture from elevation (they'd correlate and look wrong).
55
-
56
- ---
57
-
58
- ## 3. Dungeon / room generation
59
-
60
- Common approaches, pick per game:
61
- - **Rooms + corridors (BSP or random placement):** place non-overlapping rooms, then connect. BSP recursively splits space and puts a room in each leaf; connect sibling leaves → guaranteed structure. Random placement: drop rooms, reject overlaps, connect with L-shaped/A* corridors.
62
- - **Cellular automata caves:** fill grid randomly (~45% wall), run several smoothing passes (`cell = neighbors≥5 ? wall : floor`) → organic caverns. Then **flood-fill and keep only the largest connected region** (or carve tunnels to connect regions).
63
- - **Drunkard's walk / random walk:** carve floors along a random walk for winding caves.
64
-
65
- **Critical rule: guarantee connectivity.** After generation, **flood-fill from the entrance and verify every important tile (exit, key rooms, loot) is reachable.** Discard/regenerate or carve connectors otherwise. "Unreachable exit / locked-in player" is the #1 procgen bug. Also validate: min room count, spawn ≠ exit, no soft-locks.
66
-
67
- ---
68
-
69
- ## 4. Maze generation
70
-
71
- - Grid where each cell has walls; carve passages.
72
- - **Recursive backtracker (randomized DFS):** deep, winding mazes with long corridors — most common.
73
- - **Randomized Prim's / Kruskal's:** more uniform, bushier mazes.
74
- - All produce a "perfect maze" (exactly one path between any two cells). Add **loops** by knocking out extra walls if you want multiple routes.
75
- - Use your seeded `rng` for neighbor choice so the maze is reproducible.
76
-
77
- ---
78
-
79
- ## 5. Terrain generation
80
-
81
- - **Heightmap from fBm simplex** (see §2): sample noise per cell → elevation → color/mesh. Threshold into water/sand/grass/rock/snow bands.
82
- - **Domain warping** (offset sample coords by another noise) for more natural, less "blobby" coastlines.
83
- - For 3D: feed the heightmap into a plane geometry's vertex Y (Three.js `PlaneGeometry` + displace vertices) and `computeVertexNormals()`; consider chunking + LOD for large worlds.
84
- - Keep generation **deterministic per chunk**: derive each chunk's local seed from `(worldSeed, chunkX, chunkY)` so infinite/streamed worlds are stable and reproducible.
85
-
86
- ---
87
-
88
- ## 6. Wave Function Collapse (WFC) basics
89
-
90
- WFC is a constraint-solver that generates output where every local neighborhood matches examples/adjacency rules — great for tile maps, textures, and levels that must "fit together."
91
-
92
- Algorithm (overlapping or simple-tiled):
93
- 1. Every cell starts in **superposition** (all tiles possible).
94
- 2. **Observe:** pick the lowest-entropy cell (fewest remaining options) and **collapse** it to one tile (weighted-random).
95
- 3. **Propagate:** remove now-impossible neighbors' options based on adjacency rules; repeat until stable.
96
- 4. Loop until all cells collapsed, or **backtrack/restart on contradiction** (a cell with zero options).
97
-
98
- Rules & gotchas:
99
- - Adjacency rules come from a sample image (overlapping model) or hand-authored tile edges (simple-tiled model).
100
- - **Contradictions happen** — implement restart or backtracking; without it, generation hangs/throws.
101
- - Weight tiles for aesthetics; use noise (from §2) to bias regional weights for large-scale structure, then WFC for coherent local detail.
102
- - For JS: **mxgmn/WaveFunctionCollapse** (original), Boris the Brave's write-up + **DeBroglie**, or ndarray-based JS ports.
103
-
104
- > Note: Red Blob Games does **not** have a WFC tutorial (a common false citation). Cite Maxim Gumin's repo and Boris the Brave instead. Red Blob Games *is* the canonical source for **noise maps** and **A\*/grids**.
105
-
106
- ---
107
-
108
- ## 7. Bug-prevention checklist
109
- - **`Math.random()` for generation** → non-reproducible, unshareable, undebuggable, desyncs multiplayer; use a seeded PRNG.
110
- - **String seed used directly** → NaN/garbage; hash to int (xmur3) first.
111
- - **Shared single RNG stream across systems** → tweaking one system reshuffles all; use separate streams.
112
- - **No connectivity check** → unreachable exits / trapped player; flood-fill validate & regenerate.
113
- - **Forgetting to seed simplex-noise (v4)** → falls back to `Math.random()`, non-reproducible; pass your PRNG to `createNoise2D`.
114
- - **Single-octave noise** → smooth but featureless; add fBm octaves.
115
- - **Deriving moisture from elevation** → correlated, unrealistic biomes; use independent noise fields.
116
- - **WFC with no contradiction handling** → infinite loop / crash; add restart/backtrack.
117
- - **Per-frame regeneration or huge synchronous gen** → jank; generate in chunks / a web worker / on level load.
118
- - **Non-deterministic chunk seeds** → seams/flicker in streamed worlds; derive chunk seed from `(worldSeed, cx, cy)`.
119
-
120
- ---
121
-
122
- ## Defaults to apply
123
- - **Every generated procgen game gets a visible/optional seed** driven by **mulberry32** (with xmur3 for string seeds), plus `randRange/randInt/pick/shuffle` helpers and **separate RNG streams** per system. Reproducibility is free QA, shareable content, and multiplayer-safe.
124
- - **Terrain/organic → seeded `simplex-noise` v4 (`createNoise2D(rng)`) with fBm octaves + redistribution + island mask + independent elevation/moisture** per Red Blob Games.
125
- - **Dungeons → rooms+corridors or cellular-automata caves, ALWAYS followed by a flood-fill connectivity guarantee** (regenerate on failure). Ship this validation step by default — it prevents the worst procgen bug.
126
- - **Offer WFC** for tile-based levels/textures (with contradiction restart), optionally seeded by noise for macro structure. Do heavy generation in a worker/on load, not per frame.
127
-
128
- ---
129
-
130
- ## Sources
131
- - Red Blob Games — Making maps with noise functions: https://www.redblobgames.com/maps/terrain-from-noise/
132
- - Red Blob Games — Noise (value/Perlin/simplex intro): https://www.redblobgames.com/articles/noise/introduction.html
133
- - Red Blob Games — Procedural map/dungeon & grids index: https://www.redblobgames.com/
134
- - simplex-noise (npm, v4 `createNoise2D` API): https://www.npmjs.com/package/simplex-noise , https://github.com/jwagner/simplex-noise.js
135
- - mulberry32 / xmur3 seeded PRNGs (bryc's gist): https://github.com/bryc/code/blob/master/jshash/PRNGs.md
136
- - Stefan Gustavson — Simplex noise demystified (PDF): https://weber.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf
137
- - Ken Perlin — Improving Noise (SIGGRAPH 2002): https://mrl.cs.nyu.edu/~perlin/paper445.pdf
138
- - Cellular-automata cave generation (RogueBasin): https://www.roguebasin.com/index.php/Cellular_Automata_Method_for_Generating_Random_Cave-Like_Levels
139
- - BSP dungeon generation (RogueBasin): https://www.roguebasin.com/index.php/Basic_BSP_Dungeon_generation
140
- - Maze generation algorithms — Jamis Buck ("Buckblog") & "Mazes for Programmers": https://weblog.jamisbuck.org/2011/2/7/maze-generation-algorithm-recap
141
- - Wave Function Collapse — Maxim Gumin (original): https://github.com/mxgmn/WaveFunctionCollapse ; Boris the Brave, "WFC explained": https://www.boristhebrave.com/2020/04/13/wave-function-collapse-explained/
@@ -1,108 +0,0 @@
1
- # Save & Persistence for Browser Games (localStorage vs IndexedDB, versioned saves, serialization, autosave)
2
-
3
- Consolidated from MDN storage docs and the `idb` library (see Sources). Focus: what an AI builder needs so saves **survive updates, don't corrupt, and don't block the frame** — the usual bugs are lost progress on a schema change, quota errors, and jank from synchronous writes.
4
-
5
- ---
6
-
7
- ## 1. Pick the right storage
8
-
9
- **`localStorage`** — simple key/value, **synchronous, string-only, ~5MB** per origin.
10
- - Good for: small settings, high scores, current-level, a single small save blob, key bindings, volume.
11
- - **Synchronous = it blocks the main thread.** Fine for occasional small writes; **do NOT write large/frequent blobs to it every frame** (causes hitches). Values must be strings → `JSON.stringify`/`parse`.
12
- - `sessionStorage` = same API but cleared when the tab closes (use for transient state only).
13
-
14
- **IndexedDB** — **asynchronous**, transactional, large (hundreds of MB to GB, quota-based), stores **structured data** (objects, arrays, `Blob`, `ArrayBuffer`, typed arrays via the structured clone algorithm — no manual JSON needed).
15
- - Good for: big/complex saves, multiple save slots, replays, generated assets/level caches, offline data.
16
- - The raw API is verbose/callbacky — **use the `idb` wrapper** (Jake Archibald) for a clean promise-based API. Don't hand-roll raw IndexedDB.
17
-
18
- **Rule of thumb:** settings/scores/small single save → `localStorage`; anything large, multi-slot, binary, or frequently written → **IndexedDB (via `idb`)**. Cookies are the wrong tool for game saves (tiny, sent on every request).
19
-
20
- **Cache API / service worker** is for caching the *game itself* (assets, offline PWA), not for player save data.
21
-
22
- ---
23
-
24
- ## 2. ALWAYS version your saves (the #1 lost-progress bug)
25
-
26
- Your save schema *will* change between game versions. If you `JSON.parse` an old save into new code with no version handling, you get crashes or silent corruption and angry players who lost progress.
27
-
28
- **Rule: every save carries a `version` number, and you write migration steps between versions.**
29
- ```js
30
- const SAVE_VERSION = 3;
31
- function migrate(save) {
32
- let s = { ...save };
33
- if (s.version === 1) { s.coins = s.gold ?? 0; delete s.gold; s.version = 2; }
34
- if (s.version === 2) { s.settings = { ...defaults.settings, ...s.settings }; s.version = 3; }
35
- return s; // now at SAVE_VERSION
36
- }
37
- function loadSave(raw) {
38
- let save = raw ?? structuredClone(defaultSave);
39
- if (save.version !== SAVE_VERSION) save = migrate(save);
40
- return save;
41
- }
42
- ```
43
- - Migrations run **in sequence** (v1→v2→v3) so any old save upgrades.
44
- - IndexedDB has its own **schema versioning** via the `open(name, version)` + `onupgradeneeded`/`idb`'s `upgrade` callback — use it to create/alter object stores. That's separate from your *data* version above; you often want both.
45
- - **New fields:** merge over defaults (`{ ...defaults, ...loaded }`) so older saves gain new keys with sane values instead of `undefined`.
46
- - Keep a **backup of the previous save** before overwriting, so a failed migration/corruption is recoverable.
47
-
48
- ---
49
-
50
- ## 3. Serialization: what to save
51
-
52
- - **Save state, not behavior.** Serialize plain data (positions, inventory, flags, RNG seed + counters). Never try to serialize class instances/functions/DOM/engine objects directly.
53
- - **Save the seed + progress**, not the whole generated world, for procgen games — regenerate deterministically on load (see procgen skill). Massively smaller and robust.
54
- - Use `structuredClone` / IndexedDB for objects with `Map`/`Set`/`Date`/typed arrays; **plain `JSON` drops those** (Map→`{}`, Date→string, `undefined`/functions omitted, `NaN`/`Infinity`→`null`). If using JSON, convert them explicitly.
55
- - **Wrap every load in try/catch.** Corrupt/partial JSON must fall back to defaults, not white-screen the game.
56
- - Consider a **checksum** or at least shape-validation of loaded data before trusting it. For competitive/leaderboard games remember client saves are trivially editable — validate server-side, don't trust local high scores.
57
-
58
- ---
59
-
60
- ## 4. Autosave (do it safely)
61
-
62
- - **Autosave on meaningful events** (level complete, checkpoint, item gained) and on a throttled timer — not every frame.
63
- - **Debounce/throttle writes** (e.g. at most once every few seconds) to avoid thrashing storage and causing jank; coalesce rapid changes.
64
- - **Save on `visibilitychange` (hidden) and `pagehide`/`beforeunload`** — mobile browsers kill backgrounded tabs without firing `beforeunload` reliably, so `visibilitychange → hidden` is the most reliable "player is leaving" signal. Do a final synchronous-ish flush there (localStorage) or a queued IndexedDB write.
65
- - **Write atomically:** for IndexedDB use a transaction; for localStorage, build the full string then set it once (a half-written multi-key save = corruption). Keep the previous save until the new one is confirmed.
66
- - Give visible feedback ("Saved") and expose manual save/load + multiple slots where appropriate.
67
-
68
- ---
69
-
70
- ## 5. Quota, availability & privacy gotchas
71
- - **Storage can throw or be disabled:** private/incognito mode, quota exceeded (`QuotaExceededError`), or blocked third-party storage. **Feature-detect and wrap in try/catch**; degrade gracefully (in-memory only) rather than crashing.
72
- - **Eviction:** browsers can clear storage under pressure ("best-effort" default). For important saves, request **`navigator.storage.persist()`** to reduce eviction risk, and check `navigator.storage.estimate()` for usage/quota.
73
- - Storage is **per-origin**; a domain change loses saves. iOS Safari has historically been aggressive about clearing storage from rarely-visited sites — don't treat browser storage as permanent; offer export/import (download/upload a save file) for anything precious, and cloud save for accounts.
74
- - **`localStorage` blocks the main thread** — keep values small; move big/async work to IndexedDB.
75
-
76
- ---
77
-
78
- ## 6. Bug-prevention checklist
79
- - **No version field** → old saves crash new builds / silent data loss; version + sequential migrations.
80
- - **Parsing without try/catch** → corrupt save white-screens the game; fall back to defaults.
81
- - **Merging loaded save without defaults** → new fields are `undefined`; spread over defaults.
82
- - **JSON round-trip of Map/Set/Date/typed arrays** → data silently lost; use structuredClone/IndexedDB or convert explicitly.
83
- - **Frequent/large `localStorage.setItem`** → main-thread hitches; throttle + use IndexedDB for big data.
84
- - **No save on tab hide** → mobile players lose progress; save on `visibilitychange`/`pagehide`.
85
- - **Non-atomic multi-key writes** → partial/corrupt saves; write one blob / use a transaction, keep a backup.
86
- - **Assuming storage always works** → crashes in private mode / over quota; feature-detect + try/catch + graceful degrade.
87
- - **Trusting local high scores** → trivially cheatable; validate server-side for leaderboards.
88
- - **Saving the whole procgen world** → bloated saves; save seed + progress and regenerate.
89
-
90
- ---
91
-
92
- ## Defaults to apply
93
- - **Ship a tiny save module by default:** `save(state)` / `load()` with a **`version` field + sequential `migrate()`**, **try/catch → defaults**, and **merge-over-defaults**. This single pattern prevents the most damaging bug (progress lost on update).
94
- - **Storage routing rule baked in:** settings/scores/small save → `localStorage`; large/multi-slot/binary/frequent → **IndexedDB via `idb`**.
95
- - **Autosave defaults:** save on checkpoints + throttled timer + **`visibilitychange`/`pagehide`**, written atomically with a retained backup.
96
- - **Persist the seed, not the world** for procgen; offer **export/import** for precious saves and request `storage.persist()`. Never trust local scores for leaderboards.
97
-
98
- ---
99
-
100
- ## Sources
101
- - MDN — Web Storage API (`localStorage`/`sessionStorage`): https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API
102
- - MDN — IndexedDB API + Using IndexedDB (versioning/`onupgradeneeded`): https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API , https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB
103
- - MDN — Structured clone algorithm (what serializes): https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm ; `structuredClone()`: https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
104
- - MDN — Storage quotas & eviction / `navigator.storage`: https://developer.mozilla.org/en-US/docs/Web/API/Storage_API/Storage_quotas_and_eviction_criteria , https://developer.mozilla.org/en-US/docs/Web/API/StorageManager/persist
105
- - MDN — `Document.visibilitychange` / Page Visibility API: https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
106
- - `idb` (promise-based IndexedDB wrapper, Jake Archibald): https://github.com/jakearchibald/idb
107
- - web.dev — "Storage for the web" (choosing storage): https://web.dev/articles/storage-for-the-web
108
- - localForage (localStorage-like API over IndexedDB): https://github.com/localForage/localForage