@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.
- package/README.md +37 -0
- package/docs/REPO_FILE_MAP.txt +132 -0
- package/migrations/d1/0018_goap_control_plane_remaster.sql +40 -0
- package/migrations/d1/0019_agentsam_agent_run_plan_todo.sql +14 -0
- package/migrations/d1/README_PORTABLE_CONTROL_PLANE.md +20 -9
- package/migrations/runtime/0002_goap_blackboard_v1.sql +15 -0
- package/migrations/runtime/0004_agent_run_plan_linkage.sql +8 -0
- package/native/agentsam-machine/cli/Cargo.toml +8 -1
- package/native/agentsam-machine/cli/README.md +21 -0
- package/native/agentsam-machine/core/Cargo.toml +7 -0
- package/native/agentsam-machine/core/README.md +14 -0
- package/native/agentsam-machine/core/build.rs +33 -0
- package/native/agentsam-machine/core/contracts/source-types.v1.json +353 -0
- package/native/agentsam-machine/core/src/lib.rs +6 -0
- package/native/agentsam-machine/core/src/source_types.rs +2 -2
- package/package.json +16 -6
- package/packages/agentsam-errors/package.json +1 -1
- package/packages/agentsam-errors/src/index.js +1 -0
- package/packages/agentsam-errors/src/tool.js +56 -0
- package/packages/agentsam-errors/test/tool.test.mjs +58 -0
- package/packages/agentsam-goap/README.md +52 -0
- package/packages/agentsam-goap/package.json +37 -0
- package/packages/agentsam-goap/src/adapters/d1-sqlite.js +570 -0
- package/packages/agentsam-goap/src/adapters/memory.js +199 -0
- package/packages/agentsam-goap/src/contracts.js +226 -0
- package/packages/agentsam-goap/src/control-plane.js +112 -0
- package/packages/agentsam-goap/src/errors.js +157 -0
- package/packages/agentsam-goap/src/index.js +5 -0
- package/packages/agentsam-goap/src/world.js +202 -0
- package/packages/agentsam-goap/test/goap-control-plane.test.mjs +245 -0
- package/packages/agentsam-goap/test/world.test.mjs +79 -0
- package/packages/agentsam-nav/dist/Nav.d.ts +43 -0
- package/packages/agentsam-nav/dist/NavCollapsible.d.ts +10 -0
- package/packages/agentsam-nav/dist/NavContent.d.ts +2 -0
- package/packages/agentsam-nav/dist/NavFooter.d.ts +2 -0
- package/packages/agentsam-nav/dist/NavGroup.d.ts +3 -0
- package/packages/agentsam-nav/dist/NavHeader.d.ts +2 -0
- package/packages/agentsam-nav/dist/NavMenu.d.ts +22 -0
- package/packages/agentsam-nav/dist/NavProvider.d.ts +35 -0
- package/packages/agentsam-nav/dist/NavTrigger.d.ts +2 -0
- package/packages/agentsam-nav/dist/Surfaces.d.ts +41 -0
- package/packages/agentsam-nav/dist/browser.d.ts +11 -0
- package/packages/agentsam-nav/dist/browser.global.js +135 -0
- package/packages/agentsam-nav/dist/browser.js +7290 -0
- package/packages/agentsam-nav/dist/contracts.d.ts +76 -0
- package/packages/agentsam-nav/dist/index.d.ts +11 -0
- package/packages/agentsam-nav/dist/index.js +7291 -0
- package/packages/agentsam-nav/dist/legacy.css +83 -0
- package/packages/agentsam-nav/dist/shell.css +113 -0
- package/packages/agentsam-nav/dist/theme.css +113 -0
- package/packages/agentsam-nav/dist/utils.d.ts +1 -0
- package/packages/agentsam-repository/src/goap.js +13 -14
- package/packages/agentsam-repository/src/goap.js.bak-20260922011251 +670 -0
- package/packages/agentsam-repository/src/tickets.js +15 -22
- package/packages/agentsam-repository/test/goap-tickets-workspace-state.test.mjs +19 -8
- package/packages/connectors/cloudflare/package.json +3 -1
- package/packages/identity/tests/lane1-packed-consumer.test.mjs +1 -1
- package/python/agentsam_sdk/repository/intelligence/discovery.py +27 -2
- package/python/agentsam_sdk/repository/intelligence/git.py +4 -0
- package/python/tests/test_repository_intelligence.py +30 -0
- package/src/cli/command-catalog.js +2 -1
- package/src/cli.js +10 -1
- package/src/commands/goap-world.js +134 -0
- package/src/commands/goap.js +11 -4
- package/src/commands/machine-binary.js +33 -27
- package/src/commands/machine-runtime.js +266 -0
- package/src/commands/machine.js +122 -51
- package/src/commands/package.js +530 -0
- package/src/commands/plan-ledger.js +370 -0
- package/src/commands/plan.js +183 -0
- package/src/commands/skill.js +78 -17
- package/src/knowledge/source.js +1 -1
- package/src/lib/slash-commands.js +1 -1
- package/src/local/runtime-store.js +24 -2
- package/src/local/sqlite.js +17 -0
- package/src/sam/operations/package-audit.js +41 -0
- package/src/sam/seed.js +2 -0
- package/skills/grok-auth/SKILL.md +0 -110
- package/skills/grok-auth/agentsam.skill.json +0 -25
- package/skills/grok-auth/references/grok-identity.md +0 -64
- package/skills/grok-auth/references/per-user-data.md +0 -49
- package/skills/grok-auth/references/prewired-and-env.md +0 -54
- package/skills/grok-auth/references/session-ui.md +0 -133
- package/skills/grok-auth/references/sign-in-methods.md +0 -55
- package/skills/grok-auth/references/wiring.md +0 -71
- package/skills/grok-building-games/SKILL.md +0 -213
- package/skills/grok-building-games/agentsam.skill.json +0 -25
- package/skills/grok-building-games/references/3d-libs.md +0 -64
- package/skills/grok-building-games/references/ai-pathfinding.md +0 -122
- package/skills/grok-building-games/references/audio.md +0 -129
- package/skills/grok-building-games/references/babylon.md +0 -202
- package/skills/grok-building-games/references/collision-physics.md +0 -122
- package/skills/grok-building-games/references/ecs-architecture.md +0 -111
- package/skills/grok-building-games/references/game-feel-juice.md +0 -110
- package/skills/grok-building-games/references/genres/board-card-chess.md +0 -89
- package/skills/grok-building-games/references/genres/endless-runner.md +0 -83
- package/skills/grok-building-games/references/genres/fps.md +0 -105
- package/skills/grok-building-games/references/genres/platformer-2d.md +0 -97
- package/skills/grok-building-games/references/genres/puzzle-match3-tetris.md +0 -131
- package/skills/grok-building-games/references/genres/racing-kart.md +0 -106
- package/skills/grok-building-games/references/genres/topdown-twin-stick.md +0 -97
- package/skills/grok-building-games/references/genres/tower-defense.md +0 -84
- package/skills/grok-building-games/references/genres/voxel-minecraft.md +0 -89
- package/skills/grok-building-games/references/input.md +0 -139
- package/skills/grok-building-games/references/phaser.md +0 -277
- package/skills/grok-building-games/references/procedural-generation.md +0 -141
- package/skills/grok-building-games/references/save-persistence.md +0 -108
- package/skills/grok-building-games/references/threejs-foundational.md +0 -148
- package/skills/grok-controls/SKILL.md +0 -274
- package/skills/grok-controls/agentsam.skill.json +0 -25
- package/skills/grok-design-ui/SKILL.md +0 -122
- package/skills/grok-design-ui/agentsam.skill.json +0 -25
- package/skills/grok-design-ui/references/animations.md +0 -379
- package/skills/grok-design-ui/references/performance.md +0 -88
- package/skills/grok-design-ui/references/refined-ui.md +0 -384
- package/skills/grok-design-ui/references/surfaces.md +0 -247
- package/skills/grok-design-ui/references/typography.md +0 -123
- package/skills/grok-game-animation-frames/SKILL.md +0 -84
- package/skills/grok-game-animation-frames/agentsam.skill.json +0 -25
- package/skills/grok-game-asset-core/SKILL.md +0 -69
- package/skills/grok-game-asset-core/agentsam.skill.json +0 -25
- package/skills/grok-game-character-consistency/SKILL.md +0 -69
- package/skills/grok-game-character-consistency/agentsam.skill.json +0 -25
- package/skills/grok-game-tilesets/SKILL.md +0 -65
- package/skills/grok-game-tilesets/agentsam.skill.json +0 -25
- package/skills/grok-game-ui-icons/SKILL.md +0 -56
- package/skills/grok-game-ui-icons/agentsam.skill.json +0 -25
- package/skills/grok-generate2dmap/LICENSE +0 -21
- package/skills/grok-generate2dmap/SKILL.md +0 -120
- package/skills/grok-generate2dmap/SOURCE.md +0 -6
- package/skills/grok-generate2dmap/agentsam.skill.json +0 -25
- package/skills/grok-generate2dmap/references/deliverables.md +0 -101
- package/skills/grok-generate2dmap/references/layered-map-contract.md +0 -209
- package/skills/grok-generate2dmap/references/map-strategies.md +0 -341
- package/skills/grok-generate2dmap/references/object-production-gate.md +0 -24
- package/skills/grok-generate2dmap/references/pipeline.md +0 -149
- package/skills/grok-generate2dmap/references/prop-pack-contract.md +0 -174
- package/skills/grok-generate2dmap/references/side-scroll-stages.md +0 -29
- package/skills/grok-generate2dmap/scripts/compose_layered_preview.py +0 -157
- package/skills/grok-generate2dmap/scripts/extract_prop_pack.py +0 -369
- package/skills/grok-generate2dsprite/LICENSE +0 -21
- package/skills/grok-generate2dsprite/SKILL.md +0 -313
- package/skills/grok-generate2dsprite/SOURCE.md +0 -6
- package/skills/grok-generate2dsprite/agentsam.skill.json +0 -25
- package/skills/grok-generate2dsprite/references/modes.md +0 -124
- package/skills/grok-generate2dsprite/references/prompt-rules.md +0 -315
- package/skills/grok-generate2dsprite/scripts/generate2dsprite.py +0 -1031
- package/skills/grok-generate2dsprite/scripts/make_layout_guide.py +0 -109
- package/skills/grok-imagine/SKILL.md +0 -201
- package/skills/grok-imagine/agentsam.skill.json +0 -25
- package/skills/grok-multiplayer-p2p/SKILL.md +0 -111
- package/skills/grok-multiplayer-p2p/agentsam.skill.json +0 -25
- package/skills/grok-multiplayer-p2p/references/react-binding.md +0 -144
- package/skills/grok-multiplayer-p2p/references/signaling-relay.md +0 -269
- package/skills/grok-neon/SKILL.md +0 -157
- package/skills/grok-neon/agentsam.skill.json +0 -25
- package/skills/grok-og/SKILL.md +0 -102
- package/skills/grok-og/agentsam.skill.json +0 -25
- package/skills/grok-og/references/brand-pass.md +0 -53
- package/skills/grok-og/references/custom-card.md +0 -107
- package/skills/grok-og/references/favicon-and-icons.md +0 -48
- package/skills/grok-og/references/og-type-contract.md +0 -18
- package/skills/grok-og/references/placeholder-card.md +0 -21
- package/skills/grok-og/references/x-banner.md +0 -41
- package/skills/grok-threejs/SKILL.md +0 -67
- package/skills/grok-threejs/agentsam.skill.json +0 -25
- package/skills/grok-threejs/references/llms-full.txt +0 -2780
- package/skills/grok-video2dsprite/LICENSE +0 -21
- package/skills/grok-video2dsprite/SKILL.md +0 -236
- package/skills/grok-video2dsprite/SOURCE.md +0 -6
- package/skills/grok-video2dsprite/agentsam.skill.json +0 -25
- package/skills/grok-video2dsprite/references/pipeline.md +0 -90
- package/skills/grok-video2dsprite/references/prompt-rules.md +0 -63
- package/skills/grok-video2dsprite/scripts/video2dsprite.py +0 -490
- package/skills/grok-xai-api/SKILL.md +0 -152
- package/skills/grok-xai-api/agentsam.skill.json +0 -25
- package/test/account-session.test.mjs +0 -101
- package/test/agent-capabilities.test.mjs +0 -67
- package/test/app-authority-context.test.mjs +0 -32
- package/test/app-building-skills.test.mjs +0 -61
- package/test/apps-scaffold-contract.test.mjs +0 -115
- package/test/blender-cad.test.mjs +0 -146
- package/test/cad-docker.test.mjs +0 -96
- package/test/capabilities.test.mjs +0 -133
- package/test/cli/api-key-env-whoami.test.mjs +0 -129
- package/test/cli/catalog-authority.test.mjs +0 -64
- package/test/cli/codebaseindex-plan-ux.test.mjs +0 -37
- package/test/cli/eval-live.test.mjs +0 -219
- package/test/cli/go.test.mjs +0 -128
- package/test/cli/local-vault-and-provider-setup.test.mjs +0 -268
- package/test/cli/machine-command.test.mjs +0 -34
- package/test/cli/mcp-client.test.mjs +0 -256
- package/test/cli/preferences-runtime.test.mjs +0 -11
- package/test/cli/runtime-persist.test.mjs +0 -56
- package/test/cli/runtime-ui.test.mjs +0 -141
- package/test/cli/rust-command.test.mjs +0 -21
- package/test/cli/skill-npm-and-env.test.mjs +0 -52
- package/test/cli/status-actions.test.mjs +0 -88
- package/test/cli/wireframes-go-registry.test.mjs +0 -139
- package/test/cli-preferences.test.mjs +0 -46
- package/test/cloudflare-connector.test.mjs +0 -93
- package/test/cloudflare-runtime.test.mjs +0 -82
- package/test/context.test.mjs +0 -159
- package/test/credentials-audit.test.mjs +0 -113
- package/test/deploy-health-scan.test.mjs +0 -95
- package/test/deploy-receipt.test.mjs +0 -91
- package/test/dockerize.test.mjs +0 -93
- package/test/error-diagnostics.test.mjs +0 -124
- package/test/eval-context.test.mjs +0 -37
- package/test/execution-approvals.test.mjs +0 -27
- package/test/fixtures/cad/courtyard-house.json +0 -208
- package/test/fixtures/knowledge-rpc-worker.mjs +0 -16
- package/test/fixtures/project-authority/customer-app/.agentsam/app.json +0 -5
- package/test/fixtures/project-authority/customer-app/apps/my-product/index.ts +0 -1
- package/test/fixtures/project-authority/customer-app/wrangler.toml +0 -17
- package/test/gcloud-auth.test.mjs +0 -111
- package/test/go/build-source-identity.test.mjs +0 -31
- package/test/go/cloudflare-probe.test.mjs +0 -317
- package/test/go/distribution.test.mjs +0 -28
- package/test/google-cloud-connection.test.mjs +0 -83
- package/test/google-cloud-inventory.test.mjs +0 -64
- package/test/indexing-provider.test.mjs +0 -29
- package/test/init-options.test.mjs +0 -35
- package/test/integration/ai-access-onboarding.test.mjs +0 -47
- package/test/integration/app-command.test.mjs +0 -85
- package/test/integration/autorag-project-authority.integration.test.mjs +0 -51
- package/test/integration/autorag-runtime-discovery.test.mjs +0 -107
- package/test/integration/cad-discovery.test.mjs +0 -158
- package/test/integration/cad-docker-executor.test.mjs +0 -249
- package/test/integration/cad-execution.test.mjs +0 -184
- package/test/integration/cad-project-app.test.mjs +0 -31
- package/test/integration/cad-project-d1.test.mjs +0 -25
- package/test/integration/cad-project-native.test.mjs +0 -24
- package/test/integration/cad-project-workflow.test.mjs +0 -9
- package/test/integration/cad-project.test.mjs +0 -85
- package/test/integration/cli-help.test.mjs +0 -41
- package/test/integration/cms-app-scaffold.test.mjs +0 -77
- package/test/integration/cms-site-tenancy-contract.test.mjs +0 -268
- package/test/integration/codebaseindex-ingest.test.mjs +0 -255
- package/test/integration/core-client.integration.test.mjs +0 -55
- package/test/integration/database-hosted-honesty.test.mjs +0 -49
- package/test/integration/desktop-keychain-boundary.test.mjs +0 -45
- package/test/integration/error-runtime-rpc.test.mjs +0 -71
- package/test/integration/features-resolve.test.mjs +0 -147
- package/test/integration/hosted-work-host-authority.test.mjs +0 -47
- package/test/integration/icon-registry.test.mjs +0 -67
- package/test/integration/ingest-discover-models.test.mjs +0 -30
- package/test/integration/inspect-path-cli.test.mjs +0 -46
- package/test/integration/install-script.test.mjs +0 -110
- package/test/integration/inventory-core.test.mjs +0 -53
- package/test/integration/inventory-eligibility.test.mjs +0 -59
- package/test/integration/inventory-evidence.test.mjs +0 -125
- package/test/integration/knowledge-rpc.test.mjs +0 -112
- package/test/integration/local-fs.test.mjs +0 -113
- package/test/integration/local-provider-bridge.test.mjs +0 -65
- package/test/integration/local-studio-settings-production.test.mjs +0 -40
- package/test/integration/lockfile-sync.test.mjs +0 -26
- package/test/integration/merkle-cli.test.mjs +0 -61
- package/test/integration/merkle-persistence-identity.test.mjs +0 -48
- package/test/integration/plugins-cloudflare.integration.test.mjs +0 -28
- package/test/integration/provider-env-cli.test.mjs +0 -60
- package/test/integration/provider-factory.test.mjs +0 -197
- package/test/integration/repository-company-graph.test.mjs +0 -90
- package/test/integration/runtime-migrations.test.mjs +0 -87
- package/test/integration/runtime-status.integration.test.mjs +0 -227
- package/test/integration/sam-activity-recovery.test.mjs +0 -147
- package/test/integration/sam-decision.test.mjs +0 -584
- package/test/integration/sam-kernel.test.mjs +0 -99
- package/test/integration/sam-planning-astar.test.mjs +0 -279
- package/test/integration/scaffold-cloudflare.test.mjs +0 -46
- package/test/integration/skill-runtime.test.mjs +0 -240
- package/test/integration/storage-architecture.test.mjs +0 -154
- package/test/integration/store-discovery.test.mjs +0 -44
- package/test/integration/studio-fs-pty-e2e.test.mjs +0 -294
- package/test/integration/terminal-exec.integration.test.mjs +0 -86
- package/test/integration/theme-package-registry.test.mjs +0 -31
- package/test/integration/tool-runtime.test.mjs +0 -124
- package/test/integration/tool-schema.test.mjs +0 -59
- package/test/jr-dev-skill.test.mjs +0 -26
- package/test/knowledge-context-pack.test.mjs +0 -19
- package/test/knowledge-postgres.test.mjs +0 -40
- package/test/knowledge-service.test.mjs +0 -110
- package/test/knowledge.test.mjs +0 -206
- package/test/live/terminal-transport.live.test.mjs +0 -24
- package/test/local-sessions.test.mjs +0 -57
- package/test/local-studio-deploy.test.mjs +0 -83
- package/test/loopback-oauth.test.mjs +0 -53
- package/test/merkle-render.test.mjs +0 -31
- package/test/mini.test.mjs +0 -140
- package/test/model-catalog.test.mjs +0 -70
- package/test/models.test.mjs +0 -309
- package/test/npm10-lock.test.mjs +0 -29
- package/test/ollama.test.mjs +0 -137
- package/test/open-url.test.mjs +0 -64
- package/test/openai-responses.test.mjs +0 -155
- package/test/portable-context.test.mjs +0 -94
- package/test/project-config.test.mjs +0 -81
- package/test/project-rules.test.mjs +0 -44
- package/test/provider-credentials.test.mjs +0 -106
- package/test/rehydrate.test.mjs +0 -25
- package/test/release-hygiene.test.mjs +0 -42
- package/test/repository-snapshot-view.test.mjs +0 -112
- package/test/responses-runner.test.mjs +0 -465
- package/test/runtime-activity.test.mjs +0 -98
- package/test/sdk-worker-contract.test.mjs +0 -72
- package/test/security.test.mjs +0 -266
- package/test/setup-planner.test.mjs +0 -74
- package/test/setup-runtime.test.mjs +0 -51
- package/test/shell.test.mjs +0 -281
- package/test/skills.test.mjs +0 -22
- package/test/smoke.mjs +0 -122
- package/test/telemetry.test.mjs +0 -79
- package/test/terminal/local-pty.mock.test.mjs +0 -153
- package/test/terminal-machine-identity.test.mjs +0 -88
- package/test/theme-portability.test.mjs +0 -14
- package/test/tools-search.test.mjs +0 -73
- package/test/unit/website-assets-bindings.test.mjs +0 -60
- package/test/whoami-resume.test.mjs +0 -157
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# Wiring the routes (do this once)
|
|
2
|
-
|
|
3
|
-
**Live-preview popup is PRE-WIRED — do not create it.**
|
|
4
|
-
`signIn` opens `/auth/popup`; the template Vite plugin
|
|
5
|
-
(`authPopupPlugin` in `vite.config.ts`) serves it via `popup.server.ts`.
|
|
6
|
-
**Never** add `src/routes/auth/popup.tsx` (or any React page / client OAuth at
|
|
7
|
-
that path). Doing so loads the full app shell in the popup ("the app opened
|
|
8
|
-
instead of Google") — that is always wrong.
|
|
9
|
-
|
|
10
|
-
**1. Mount Better Auth** — create the catch-all API route (this is what makes
|
|
11
|
-
`/api/auth/*` work; the broker's OAuth callback lands here):
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
// src/routes/api/auth/$.ts
|
|
15
|
-
import { createFileRoute } from "@tanstack/react-router";
|
|
16
|
-
import { auth } from "@/lib/auth/server";
|
|
17
|
-
|
|
18
|
-
export const Route = createFileRoute("/api/auth/$")({
|
|
19
|
-
server: {
|
|
20
|
-
handlers: {
|
|
21
|
-
GET: ({ request }) => auth.handler(request),
|
|
22
|
-
POST: ({ request }) => auth.handler(request),
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
**2. Add a sign-in page** — buttons that kick off the broker flow. Import from
|
|
29
|
-
`@/lib/auth/client`. With the flag on, `authEnabled` is true in preview and
|
|
30
|
-
deployed, so the buttons show and work in the live preview; the `else` branch
|
|
31
|
-
shows while auth is still disabled (`VITE_AUTH_ENABLED=false`):
|
|
32
|
-
|
|
33
|
-
```tsx
|
|
34
|
-
// src/routes/login.tsx
|
|
35
|
-
import { createFileRoute } from "@tanstack/react-router";
|
|
36
|
-
import { GROK_PROVIDERS, authEnabled, signIn } from "@/lib/auth/client";
|
|
37
|
-
|
|
38
|
-
export const Route = createFileRoute("/login")({ component: Login });
|
|
39
|
-
|
|
40
|
-
function Login() {
|
|
41
|
-
return (
|
|
42
|
-
<main className="grid min-h-screen place-items-center p-6">
|
|
43
|
-
<div className="w-full max-w-sm space-y-3">
|
|
44
|
-
<h1 className="text-xl font-semibold">Sign in</h1>
|
|
45
|
-
{authEnabled ? (
|
|
46
|
-
GROK_PROVIDERS.map((p) => (
|
|
47
|
-
<button
|
|
48
|
-
key={p.providerId}
|
|
49
|
-
type="button"
|
|
50
|
-
onClick={() => signIn(p.providerId, { callbackURL: "/" })}
|
|
51
|
-
className="w-full cursor-pointer rounded-md border border-neutral-300 px-4 py-2 hover:bg-neutral-100 dark:border-neutral-700 dark:hover:bg-neutral-900"
|
|
52
|
-
>
|
|
53
|
-
Continue with {p.label}
|
|
54
|
-
</button>
|
|
55
|
-
))
|
|
56
|
-
) : (
|
|
57
|
-
<p className="text-sm text-neutral-500">Sign-in is disabled.</p>
|
|
58
|
-
)}
|
|
59
|
-
</div>
|
|
60
|
-
</main>
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
`RedirectToSignIn` sends signed-out users to `/login` by default (override with
|
|
66
|
-
`<RedirectToSignIn to="/somewhere" />`). Style the page however you like — see
|
|
67
|
-
the `design-ui` skill.
|
|
68
|
-
|
|
69
|
-
That's it — call `signIn(providerId)` from your sign-in buttons. The popup,
|
|
70
|
-
bearer-token hand-off, and request attachment are all inside `src/lib/auth` +
|
|
71
|
-
the Vite plugin; leave them alone.
|
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: building-games
|
|
3
|
-
description: >
|
|
4
|
-
Build browser games and interactive/canvas/3D experiences in this TanStack
|
|
5
|
-
Start + React app. Use for any game, simulation, or WebGL/Canvas experience —
|
|
6
|
-
2D or 3D, single-player. Covers the game loop & timing, 3D orientation/camera
|
|
7
|
-
conventions, collision, performance, assets, audio, save, game feel, and
|
|
8
|
-
per-genre playbooks. For WASD / vehicle / flight **input signs and inverted
|
|
9
|
-
A/D**, open the **`controls`** skill — do not rely on this file or racing-kart
|
|
10
|
-
alone. Triggers on "game", "minecraft", "fps", "platformer", "racing",
|
|
11
|
-
"tetris", "snake", "shooter", "3d", "three.js", "canvas", "voxel", "physics".
|
|
12
|
-
metadata:
|
|
13
|
-
short-description: "Browser games: loop, 3D orientation, camera, perf, assets, genres"
|
|
14
|
-
user-invocable: false
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
# Building Games
|
|
18
|
-
|
|
19
|
-
Build a **playable, correct** browser game — not a static screenshot. A game is
|
|
20
|
-
just a React route with a `<canvas>` (or `<Canvas>` for R3F) plus DOM overlay UI.
|
|
21
|
-
Style the overlay (start screen, HUD, menus) with the **`design-ui`** skill; this
|
|
22
|
-
skill owns the gameplay loop and world.
|
|
23
|
-
|
|
24
|
-
**Controls / inverted A/D:** open **`.grok/skills/controls/SKILL.md`** **before**
|
|
25
|
-
writing WASD, steering, or flight input. Vehicle/flight demos often ship with
|
|
26
|
-
A/D flipped if you only read this file or a single genre playbook.
|
|
27
|
-
|
|
28
|
-
**Scope note — single-player, bots, or small P2P co-op:**
|
|
29
|
-
- Ship **single-player** or **single-player + AI/bots** by default.
|
|
30
|
-
- **2–8 player co-op / casual realtime** (shared cursors, party games, casual
|
|
31
|
-
action among friends) is supported — use the **`multiplayer-p2p` skill**
|
|
32
|
-
(WebRTC mesh, signaled at `/api/rtc`). Read its trust model first.
|
|
33
|
-
- P2P is the only supported multiplayer right now. Do not half-build sockets
|
|
34
|
-
that can’t connect.
|
|
35
|
-
|
|
36
|
-
**References (load on demand):**
|
|
37
|
-
- **`controls` skill** (`../controls/`) — **required** for movement/steer/flight:
|
|
38
|
-
player-visible A/D, inverted-steer anti-pattern, flight ailerons, mandatory
|
|
39
|
-
self-test + `window.__controlsTest`. Not optional for vehicles/planes.
|
|
40
|
-
- `references/threejs-foundational.md` — the deep 3D/loop/perf reference. Read for 3D.
|
|
41
|
-
- `references/3d-libs.md` — three.js + @react-three/fiber + drei + rapier usage.
|
|
42
|
-
- **`threejs` skill** (`../threejs/`) — official full Three.js + TSL API dump
|
|
43
|
-
(`llms-full.txt`). Load for advanced materials/shaders/WebGPU/loaders; not for
|
|
44
|
-
simple 2D canvas games.
|
|
45
|
-
- `references/babylon.md` — Babylon.js, the batteries-included 3D engine alternative.
|
|
46
|
-
- `references/phaser.md` — Phaser 3, the default engine for 2D games.
|
|
47
|
-
- `references/ecs-architecture.md` — entity-component-system structure for larger games.
|
|
48
|
-
- `references/genres/*.md` — per-genre playbooks (fps, platformer-2d, racing-kart,
|
|
49
|
-
puzzle-match3-tetris, voxel-minecraft, endless-runner, topdown-twin-stick,
|
|
50
|
-
tower-defense, board-card-chess). Genre files **do not** replace **`controls`**.
|
|
51
|
-
- `references/game-feel-juice.md`, `input.md`, `audio.md`, `collision-physics.md`,
|
|
52
|
-
`save-persistence.md`, `procedural-generation.md`, `ai-pathfinding.md`.
|
|
53
|
-
- **`game-asset-core`** (+ `game-animation-frames` / `game-tilesets` /
|
|
54
|
-
`game-character-consistency` / `game-ui-icons`) — engine-ready 2D art defaults
|
|
55
|
-
and verification when generating sprites, sheets, tiles, or UI (see §6).
|
|
56
|
-
|
|
57
|
-
Pick the specific genre/topic reference for the build; this file is the universal
|
|
58
|
-
core for loop/world. **Input signs → `controls`.** **2D game art → `game-asset-core`.**
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
## 1. Game loop & timing (the #1 correctness issue)
|
|
63
|
-
|
|
64
|
-
- Drive the loop with the engine's RAF loop (`renderer.setAnimationLoop`, R3F
|
|
65
|
-
`useFrame`, or `requestAnimationFrame` for 2D canvas). **Never** `setInterval`/
|
|
66
|
-
`setTimeout`/`Date.now()` for game timing.
|
|
67
|
-
- **Scale ALL movement/animation by delta time** (seconds) so speed is frame-rate
|
|
68
|
-
independent (60Hz vs 144Hz). Compute delta **once per frame** and reuse it.
|
|
69
|
-
- three.js: use `THREE.Timer` (not `Clock` — `Clock.getDelta()` returns ~0 on a
|
|
70
|
-
second call in the same frame, a classic freeze bug).
|
|
71
|
-
- **Cap delta** (`min(delta, 0.1)`) so a backgrounded tab doesn't teleport things.
|
|
72
|
-
- **Fixed timestep for physics/gameplay:** accumulate delta and step simulation at
|
|
73
|
-
a fixed rate (e.g. 1/60) while rendering at display rate — prevents tunneling and
|
|
74
|
-
non-determinism.
|
|
75
|
-
|
|
76
|
-
## 2. Controls (delegate to the `controls` skill)
|
|
77
|
-
|
|
78
|
-
**Open `.grok/skills/controls/SKILL.md` before implementing any WASD / steer /
|
|
79
|
-
flight code.** That skill is the source of truth for:
|
|
80
|
-
|
|
81
|
-
- Player-visible **A = left / D = right** (chase cam, while moving forward)
|
|
82
|
-
- Why **`KeyA → steer−` + `yaw += steer * +rate` inverts** (most common bug)
|
|
83
|
-
- Vehicle vs FPS (strafe ≠ steer), fixed-wing ailerons, heli/drone notes
|
|
84
|
-
- Mandatory self-test + `window.__controlsTest` probe
|
|
85
|
-
|
|
86
|
-
Do **not** treat `genres/racing-kart.md` as the only place steer signs live —
|
|
87
|
-
planes, jetskis, and mechs never open it.
|
|
88
|
-
|
|
89
|
-
**Short reminder (full detail in `controls`):**
|
|
90
|
-
|
|
91
|
-
```
|
|
92
|
-
// Vehicle yaw body (chase cam): A must increase yaw with this basis
|
|
93
|
-
forward = (-sin(yaw), 0, -cos(yaw))
|
|
94
|
-
// KeyA → steer = +1; yaw += steer * turnRate * speedFactor * dt
|
|
95
|
-
// WRONG (ships inverted): KeyA → steer = -1; yaw += steer * turnRate * dt
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
- **Pointer lock:** mouse-look only — implement WASD yourself; click-to-play
|
|
99
|
-
overlay; dismiss on lock.
|
|
100
|
-
- Track keys with held state + **dt**; unify devices via `references/input.md`.
|
|
101
|
-
- **Finish:** run the `controls` skill checklist. Screenshot-only is insufficient
|
|
102
|
-
for vehicles/flight.
|
|
103
|
-
|
|
104
|
-
## 3. 3D orientation & world objects (the "sideways/backwards" bugs)
|
|
105
|
-
|
|
106
|
-
- three.js is **right-handed, +Y up**: +X right, +Y up, +Z toward viewer. **Meshes
|
|
107
|
-
face +Z; cameras look −Z** (the classic "camera backwards" gotcha).
|
|
108
|
-
- Primitives like `Cone`/`Cylinder` point **+Y** by default → rotate to align a
|
|
109
|
-
tip with forward (`geo.rotateX(Math.PI/2)`).
|
|
110
|
-
- **Orienting a mesh to face `forward`** (meshes face **+Z**): simplest correct way
|
|
111
|
-
is `mesh.lookAt(mesh.position.clone().add(forward))`. To build the basis by hand,
|
|
112
|
-
set the **+Z column to `forward`** and choose the x-axis that keeps it a *proper*
|
|
113
|
-
right-handed rotation (`det = +1`):
|
|
114
|
-
`xAxis = normalize(cross(up, forward))`, then `makeBasis(xAxis, up, forward)`.
|
|
115
|
-
Note this is `cross(up, forward)` — **not** the movement `right = cross(forward, up)`
|
|
116
|
-
from §2. Targeting +Z (instead of a camera's −Z) flips the x-axis sign so that
|
|
117
|
-
`xAxis × up = forward`; the frame stays right-handed (no mirroring). Do **not** use
|
|
118
|
-
`makeBasis(xAxis, up, -forward)` for a mesh — that targets −forward (the *camera*
|
|
119
|
-
convention) so the mesh faces **backwards**.
|
|
120
|
-
- **Orienting a camera** to look along `forward` (cameras look **−Z**): set the +Z
|
|
121
|
-
column to `-forward` — `xAxis = normalize(cross(forward, up))`, then
|
|
122
|
-
`makeBasis(xAxis, up, -forward)` (or just `camera.lookAt(target)`).
|
|
123
|
-
- Keep a consistent world `up` so objects stay upright; only rotate flat primitives
|
|
124
|
-
to stand up.
|
|
125
|
-
- Verify glTF import orientation; debug with `AxesHelper`/`ArrowHelper`. Upright
|
|
126
|
-
self-test: characters stand on the ground plane, not lying/sunk.
|
|
127
|
-
|
|
128
|
-
## 4. Camera must agree with movement
|
|
129
|
-
|
|
130
|
-
- Keep a **dedicated `moveForward`/`moveRight`** for movement, computed once and
|
|
131
|
-
never mutated by camera code (aliasing a shared temp vector makes camera and
|
|
132
|
-
movement disagree — a real repro bug).
|
|
133
|
-
- Third-person follow: `desired = playerPos + up*height + moveForward*(-followDist)`;
|
|
134
|
-
lerp the camera toward it (use exp-based smoothing, delta-scaled), `lookAt(player)`.
|
|
135
|
-
- Isolate-the-layer debug order: (1) keys register → (2) movement signs correct →
|
|
136
|
-
(3) camera agrees. Fix in that order.
|
|
137
|
-
|
|
138
|
-
## 5. Performance
|
|
139
|
-
|
|
140
|
-
- **Minimize draw calls** (`renderer.info.render.calls`, target <100): share
|
|
141
|
-
materials, `InstancedMesh`/`BatchedMesh` for repeated objects, atlases.
|
|
142
|
-
- **Dispose GPU resources yourself** (`geometry/material/texture.dispose()`) on
|
|
143
|
-
level change — three.js does not GC them. **Pool** bullets/enemies/particles.
|
|
144
|
-
- No per-frame allocations (reuse temp vectors). Compress textures; LOD for distance.
|
|
145
|
-
|
|
146
|
-
## 6. Assets (avoid the generated-photo trap)
|
|
147
|
-
|
|
148
|
-
- **Interactive 3D elements** (weapon viewmodels, characters, props, projectiles)
|
|
149
|
-
→ build from **3D geometry / glTF**, not a generated image. A flat photorealistic
|
|
150
|
-
JPG of a gun-in-hands used as an FPS viewmodel looks wrong, can't animate, and
|
|
151
|
-
(JPG has **no alpha**) renders as a black box. Parent a real 3D viewmodel to the
|
|
152
|
-
camera as an overlay render layer.
|
|
153
|
-
- Reserve image generation for **flat 2D** assets only (textures, sky/menu
|
|
154
|
-
backgrounds, 2D sprites, UI art). **Never** use a generated photo as a 3D mesh,
|
|
155
|
-
viewmodel, or character substitute — build those in 3D geometry / glTF.
|
|
156
|
-
Set `crossOrigin="anonymous"` on images drawn to canvas/textures.
|
|
157
|
-
See the **`imagine`** skill (2D only — image tools cannot produce real 3D).
|
|
158
|
-
- **Engine-ready game art doctrine** → open **`game-asset-core`**
|
|
159
|
-
(`../game-asset-core/`) for defaults + blind verify + retry discipline, then the
|
|
160
|
-
matching specialist: **`game-animation-frames`** (loop / motion laws),
|
|
161
|
-
**`game-tilesets`**, **`game-character-consistency`**, **`game-ui-icons`**.
|
|
162
|
-
These are **QC/doctrine**, not the export pipeline. Do not ship stick-figure
|
|
163
|
-
placeholders when real art is expected.
|
|
164
|
-
- **2D game sprites / animation sheets** → run **`generate2dsprite`**
|
|
165
|
-
(`.grok/skills/generate2dsprite/SKILL.md`): solid **`#FF00FF`** magenta
|
|
166
|
-
`imagine_text_to_image` sheets + chroma postprocess scripts (magenta is required for the
|
|
167
|
-
processor). Wire transparent PNGs/GIFs into Canvas/Phaser. Still apply
|
|
168
|
-
**`game-asset-core`** (+ animation/character specialists when relevant).
|
|
169
|
-
- **2D maps / levels / prop packs** → open **`generate2dmap`**
|
|
170
|
-
(`.grok/skills/generate2dmap/SKILL.md`). Prefer foundation-only base + separate
|
|
171
|
-
props/collision for playable maps. Browser default: `raw_canvas` / Phaser.
|
|
172
|
-
Tileable ground/walls → also **`game-tilesets`** for 2×2 seam checks.
|
|
173
|
-
- **Optional denser locomotion** → run **`video2dsprite`** (Grok
|
|
174
|
-
`imagine_image_to_video` + sandbox scripts; magenta base). Prefer `generate2dsprite`
|
|
175
|
-
for crisp production heroes. Use **`game-animation-frames`** for loop/flip-test
|
|
176
|
-
laws; prefer **`video2dsprite`** over ad-hoc ffmpeg-only harvest in this
|
|
177
|
-
sandbox.
|
|
178
|
-
|
|
179
|
-
## 7. Audio, save, feel
|
|
180
|
-
- **Audio**: unlock `AudioContext` on the first user gesture (tap-to-start) or iOS
|
|
181
|
-
is silent; re-resume on `visibilitychange`. (`references/audio.md`)
|
|
182
|
-
- **Save**: `localStorage`/IndexedDB with a `version` field + migrations.
|
|
183
|
-
- **Juice**: screen shake, hit-stop, eased tweens, particles — cheap, huge
|
|
184
|
-
perceived-quality lift. Keep presentation separate from simulation.
|
|
185
|
-
|
|
186
|
-
## 8. Mobile
|
|
187
|
-
- Distinguish canvas buffer size from CSS size; respect `devicePixelRatio`.
|
|
188
|
-
- `touch-action: none`, letterbox-fit to a base resolution, handle orientation.
|
|
189
|
-
- Touch controls (virtual joystick + action buttons), ≥44px targets.
|
|
190
|
-
|
|
191
|
-
---
|
|
192
|
-
|
|
193
|
-
## Stack / engine choice
|
|
194
|
-
- **3D → three.js**, ideally via **@react-three/fiber + drei** (fits the React
|
|
195
|
-
app; drei gives pointer-lock/controls/loaders) + **@react-three/rapier** for
|
|
196
|
-
physics/character controllers. See `references/3d-libs.md`.
|
|
197
|
-
- **2D →** native Canvas 2D is enough for snake/tetris/flappy/platformer; reach for
|
|
198
|
-
Phaser only when the genre needs it.
|
|
199
|
-
- These game deps are **not preinstalled** — `npm install` them (and make sure they
|
|
200
|
-
land in `package.json` so the Vercel build has them).
|
|
201
|
-
|
|
202
|
-
## Finish criteria (before "done")
|
|
203
|
-
- Loads with **no console errors**; visible gameplay (not a blank canvas).
|
|
204
|
-
- **`controls` skill self-test passed** (A = left / D = right from chase cam
|
|
205
|
-
while moving forward; flip one sign if inverted). Not screenshot-only.
|
|
206
|
-
- 3D upright & camera-agrees self-tests pass (§3, §4).
|
|
207
|
-
- Runs on mobile viewport with touch controls.
|
|
208
|
-
- Production build (`npm run build`) renders the built output, not just dev.
|
|
209
|
-
- **Share / X card:** open the **`og`** skill — custom `public/og.jpg` **and**
|
|
210
|
-
`"type": "x:game"` in `src/lib/og/site.json`. X uses `og:type="x:game"`
|
|
211
|
-
to present the unfurl as a game card; do not use `twitter:card` or invent
|
|
212
|
-
`x:type` for this. `browser-smoke` / `brand-check` warn when canvas apps omit
|
|
213
|
-
the `site.json` field.
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"schema": "agentsam.skill.v1",
|
|
3
|
-
"id": "grok-building-games",
|
|
4
|
-
"name": "Grok \u00b7 building-games",
|
|
5
|
-
"description": "Browser games: loop, 3D orientation, camera, perf, assets, genres",
|
|
6
|
-
"icon": "skill",
|
|
7
|
-
"slash": {
|
|
8
|
-
"suggested": "/grok-building-games"
|
|
9
|
-
},
|
|
10
|
-
"instructions": {
|
|
11
|
-
"source": "local_file",
|
|
12
|
-
"ref": "SKILL.md"
|
|
13
|
-
},
|
|
14
|
-
"execution": {
|
|
15
|
-
"mode": "turn",
|
|
16
|
-
"tools": [],
|
|
17
|
-
"operations": [],
|
|
18
|
-
"capabilities": []
|
|
19
|
-
},
|
|
20
|
-
"provenance": {
|
|
21
|
-
"source": "apps/local-studio/.grok/skills",
|
|
22
|
-
"vendor": "grok",
|
|
23
|
-
"status": "imported"
|
|
24
|
-
}
|
|
25
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# 3D libraries for this stack (three.js + React Three Fiber + drei + rapier)
|
|
2
|
-
|
|
3
|
-
The app is React/TanStack. The idiomatic way to do 3D here is **React Three
|
|
4
|
-
Fiber (R3F)** — write three.js as React components inside a `<Canvas>` on a
|
|
5
|
-
route. It deploys like any other page.
|
|
6
|
-
|
|
7
|
-
> These are **not preinstalled**. Install and confirm they land in `package.json`:
|
|
8
|
-
> `npm i three @react-three/fiber @react-three/drei @react-three/rapier`
|
|
9
|
-
> (+ `npm i -D @types/three`). If the deploy build has no three, the game is blank.
|
|
10
|
-
|
|
11
|
-
## When to use what
|
|
12
|
-
- **three.js** — the engine. Raw three is fine for a self-contained canvas; prefer
|
|
13
|
-
R3F when the game has React UI/state around it.
|
|
14
|
-
- **@react-three/fiber** — renders three as React; `useFrame((state, delta) => …)`
|
|
15
|
-
is your game loop (delta is seconds — scale movement by it, see SKILL §1).
|
|
16
|
-
- **@react-three/drei** — helpers so you don't hand-roll bug-prone code:
|
|
17
|
-
`<PointerLockControls/>`, `useKeyboardControls`, `<OrbitControls/>`,
|
|
18
|
-
`useGLTF`, `<Environment/>`, `<Instances/>`, `<Stats/>`.
|
|
19
|
-
- **@react-three/rapier** — physics + **character controller** (capsule +
|
|
20
|
-
autostep + snap-to-ground). Use for FPS/platformer movement and collisions
|
|
21
|
-
instead of hand-rolled raycasts. `<Physics>`, `<RigidBody>`, `useRapier`.
|
|
22
|
-
|
|
23
|
-
## Minimal R3F shape
|
|
24
|
-
```tsx
|
|
25
|
-
import { Canvas, useFrame } from "@react-three/fiber";
|
|
26
|
-
import { PointerLockControls, useKeyboardControls } from "@react-three/drei";
|
|
27
|
-
|
|
28
|
-
function Player() {
|
|
29
|
-
useFrame((_, delta) => {
|
|
30
|
-
const d = Math.min(delta, 0.1); // cap delta (SKILL §1)
|
|
31
|
-
// move with a dedicated moveForward/moveRight basis (SKILL §2/§4)
|
|
32
|
-
});
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export default function Game() {
|
|
37
|
-
return (
|
|
38
|
-
<Canvas camera={{ position: [0, 1.7, 5], fov: 75 }} shadows dpr={[1, 2]}>
|
|
39
|
-
{/* scene */}
|
|
40
|
-
<PointerLockControls /> {/* mouse-look ONLY — implement WASD yourself */}
|
|
41
|
-
<Player />
|
|
42
|
-
</Canvas>
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Gotchas (map to the SKILL universals)
|
|
48
|
-
- **Controls:** drei `PointerLockControls` is mouse-look only — WASD is yours
|
|
49
|
-
(SKILL §2). Gate `.lock()` behind a "click to play" overlay and dismiss it on lock.
|
|
50
|
-
- **Orientation:** meshes face +Z, camera looks −Z; right-handed +Y up (SKILL §3).
|
|
51
|
-
- **Delta:** `useFrame` delta is seconds; cap it; fixed-step physics via rapier's
|
|
52
|
-
own stepping. Don't read `THREE.Clock.getDelta()` twice a frame.
|
|
53
|
-
- **Perf:** `<Instances>`/`InstancedMesh` for repeats; dispose on unmount (R3F
|
|
54
|
-
auto-disposes objects it created, but not manual textures/loaders — dispose those).
|
|
55
|
-
Set `dpr={[1, 2]}` to cap retina cost.
|
|
56
|
-
- **Mobile:** R3F sets pixel ratio via `dpr`; still add touch controls + `touch-action:none`.
|
|
57
|
-
|
|
58
|
-
## Alternatives
|
|
59
|
-
- **Babylon.js** (`references/babylon.md`) — batteries-included 3D (Havok physics,
|
|
60
|
-
inspector, SceneOptimizer). Viable if you want an all-in-one engine, but it's a
|
|
61
|
-
separate paradigm from React; default to three/R3F for consistency with the app.
|
|
62
|
-
|
|
63
|
-
Sources: R3F docs (https://r3f.docs.pmnd.rs), drei (https://github.com/pmndrs/drei),
|
|
64
|
-
react-three-rapier (https://github.com/pmndrs/react-three-rapier), three.js docs.
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
# Game AI & Pathfinding (A* on grids, steering, FSM, behavior trees, navmesh)
|
|
2
|
-
|
|
3
|
-
Consolidated from Red Blob Games (the canonical A*/grid reference), Craig Reynolds' steering work, and Game AI Pro / behavior-tree canon (see Sources). Focus: what an AI builder needs so enemies/agents **move sensibly and don't jitter, get stuck, or tank the frame rate.**
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 1. Pathfinding: A* on a grid (the default)
|
|
8
|
-
|
|
9
|
-
**A\*** finds the shortest path by expanding the node that minimizes `f = g + h`, where `g` = cost so far and `h` = heuristic estimate to goal. It's Dijkstra + a goal-directed heuristic.
|
|
10
|
-
|
|
11
|
-
Rules:
|
|
12
|
-
- **Heuristic must be admissible** (never overestimate true cost) or A* may return a non-optimal path.
|
|
13
|
-
- **4-directional grid → Manhattan distance** `|dx|+|dy|`.
|
|
14
|
-
- **8-directional grid → octile/Chebyshev distance** (diagonal cost ≈ 1.414). Using Manhattan on an 8-dir grid overestimates → wrong paths; using Euclidean on a 4-dir grid underestimates → slow.
|
|
15
|
-
- **Use a binary heap / priority queue** for the open set. A linear scan of the open set is the #1 A* perf bug — turns O(E log V) into O(V²) and stutters on big maps.
|
|
16
|
-
- **Track a closed set / best-g per node** so you don't reprocess nodes; update `g` if a cheaper path to a node is found.
|
|
17
|
-
- **Weighted tiles:** give terrain costs (mud=5, road=1) via `g`; A* naturally routes around expensive terrain.
|
|
18
|
-
- **Diagonal corner-cutting:** forbid diagonal moves that clip through two wall corners, or agents visually cut through walls.
|
|
19
|
-
- **Reconstruct the path** by following `cameFrom` parents from goal back to start, then reverse.
|
|
20
|
-
|
|
21
|
-
Related tools (Red Blob Games):
|
|
22
|
-
- **Breadth-First Search / Dijkstra maps ("flow fields"):** when *many* agents chase *one* goal (tower defense, RTS), compute one BFS/Dijkstra field from the goal and have every agent follow the gradient — far cheaper than one A* per agent.
|
|
23
|
-
- **Greedy Best-First** is faster but not optimal; A* is the balanced default.
|
|
24
|
-
- **JPS (Jump Point Search)** optimizes A* on uniform-cost grids.
|
|
25
|
-
|
|
26
|
-
Libraries: **PathFinding.js** (grid A*/JPS/BFS, easy), or roll your own for control.
|
|
27
|
-
|
|
28
|
-
**Path-following gotchas:** smooth the raw grid path (string-pulling / line-of-sight simplification) so agents don't zig-zag along cell centers; recompute paths sparingly (on target move / periodically, not every frame); handle "no path exists" explicitly.
|
|
29
|
-
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
## 2. Steering behaviors (smooth local movement)
|
|
33
|
-
|
|
34
|
-
A* gives *where* to go; **steering** (Craig Reynolds) makes agents *move there naturally* by accumulating steering forces on velocity:
|
|
35
|
-
- **Seek / Arrive** — move toward a target; Arrive decelerates within a slowing radius (prevents overshoot/orbit).
|
|
36
|
-
- **Flee / Evade** — away from a threat.
|
|
37
|
-
- **Pursuit** — seek the target's *predicted future* position.
|
|
38
|
-
- **Wander** — smooth random roaming (jitter a point on a circle ahead), not teleporting random targets.
|
|
39
|
-
- **Obstacle avoidance** — steer around obstacles detected by a look-ahead feeler.
|
|
40
|
-
- **Separation / Alignment / Cohesion** = **Flocking (boids)** for crowds/schools/swarms.
|
|
41
|
-
- **Path following** — follow a computed A* path smoothly rather than snapping cell-to-cell.
|
|
42
|
-
|
|
43
|
-
Rules: **combine forces** (weighted sum or priority), **clamp to max force and max speed**, apply with **delta time**. Steering handles the smooth "how"; A*/flow fields handle the strategic "where." Use both together — A* alone looks robotic; steering alone gets stuck on walls.
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## 3. Finite State Machines (FSM) — decision-making for simple agents
|
|
48
|
-
|
|
49
|
-
- Agent is in exactly one **state** (Idle, Patrol, Chase, Attack, Flee); **transitions** fire on conditions (saw player → Chase; lost player → Patrol; low HP → Flee).
|
|
50
|
-
- Each state has `enter()`, `update(dt)`, `exit()`. Keep transition logic centralized/table-driven.
|
|
51
|
-
- Great for enemies with a handful of behaviors. **Downside:** transitions explode combinatorially (n states → up to n² transitions) — becomes spaghetti past ~6–8 states.
|
|
52
|
-
- **Hierarchical FSMs** (states containing sub-states) tame some of that.
|
|
53
|
-
|
|
54
|
-
---
|
|
55
|
-
|
|
56
|
-
## 4. Behavior Trees (BT) — scalable decision-making
|
|
57
|
-
|
|
58
|
-
When FSMs get unwieldy, use a **behavior tree**: a tree of nodes evaluated each tick, each returning **Success / Failure / Running**.
|
|
59
|
-
- **Composites:** **Sequence** (run children in order, fail-fast — "AND"), **Selector/Fallback** (try children until one succeeds — "OR"), **Parallel**.
|
|
60
|
-
- **Decorators:** Inverter, Repeat, Cooldown, Succeeder, condition guards.
|
|
61
|
-
- **Leaves:** Actions (MoveTo, Attack, Reload) and Conditions (IsPlayerVisible, HasAmmo).
|
|
62
|
-
- **`Running` is the key concept:** long actions (walking a path) return `Running` and resume next tick — don't block.
|
|
63
|
-
- Far more **modular/reusable/authorable** than FSMs; the industry standard for complex NPCs. Consider a lib (behaviortree.js) or a small hand-rolled implementation.
|
|
64
|
-
- **Utility AI / GOAP** are alternatives for emergent/goal-driven behavior at higher complexity.
|
|
65
|
-
|
|
66
|
-
**Rule:** simple enemies → FSM; complex/multi-goal NPCs → behavior tree. Don't build a BT framework for a single 3-state slime.
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
## 5. Navmesh basics (3D / open spaces)
|
|
71
|
-
|
|
72
|
-
- Grids are natural for tile games; for **open 3D/continuous** worlds, a **navigation mesh** (convex polygons covering walkable surfaces) is more efficient and gives smoother paths than a dense grid.
|
|
73
|
-
- Run A* over the polygon graph (portal edges), then **string-pull ("funnel algorithm")** through polygon portals for a smooth, natural path.
|
|
74
|
-
- In JS: **recast-navigation-js** (WASM port of industry-standard Recast/Detour) bakes navmeshes from level geometry and provides crowd/agent avoidance; three-pathfinding for a simpler Three.js navmesh follower.
|
|
75
|
-
- Navmeshes handle multi-level geometry (ramps, bridges) that flat grids can't; support off-mesh links (jumps, ladders).
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
## 6. Performance & correctness rules
|
|
80
|
-
- **Don't A* every agent every frame.** Cache paths; recompute on target movement or a throttled interval; **time-slice** pathfinding across frames or use a **web worker** for big searches so the main thread doesn't hitch.
|
|
81
|
-
- **Flow field / Dijkstra map** when many agents share one goal — one computation for all.
|
|
82
|
-
- **Binary heap** open set, **typed arrays** for large grids, reuse buffers (no per-search allocation churn).
|
|
83
|
-
- **Run AI on a fixed timestep** (decoupled from render) for determinism/netcode; often at a lower rate than render (e.g. 10–20Hz for decisions) with steering interpolating between.
|
|
84
|
-
- **Stagger** AI updates across agents (LOD-AI): distant/off-screen agents think less often.
|
|
85
|
-
- Handle **dynamic obstacles**: mark blocked cells / re-path when the map changes; use local steering avoidance for moving agents.
|
|
86
|
-
|
|
87
|
-
---
|
|
88
|
-
|
|
89
|
-
## 7. Bug-prevention checklist
|
|
90
|
-
- **Non-admissible heuristic** (Euclidean on 4-dir, Manhattan on 8-dir) → non-optimal or slow paths; match heuristic to movement.
|
|
91
|
-
- **Linear open-set scan** → severe stutter on big maps; use a binary heap.
|
|
92
|
-
- **A* per agent per frame** → frame drops; cache/throttle/flow-field/worker.
|
|
93
|
-
- **Following raw grid path** → robotic zig-zag; smooth/string-pull and add steering.
|
|
94
|
-
- **No Arrive/slowing radius** → agents overshoot and orbit the target.
|
|
95
|
-
- **Corner-cutting diagonals** → agents clip through wall corners; forbid unsafe diagonals.
|
|
96
|
-
- **FSM sprawl** → unmaintainable transitions; switch to a behavior tree.
|
|
97
|
-
- **Blocking actions in a BT** → tree stalls; return `Running` for long actions.
|
|
98
|
-
- **Ignoring "no path"** → crashes/agents freeze; handle unreachable goals explicitly.
|
|
99
|
-
- **Not re-pathing on map change** → agents walk into new walls; invalidate cached paths.
|
|
100
|
-
- **AI tied to render frame rate** → non-deterministic/uneven; fixed timestep, staggered.
|
|
101
|
-
|
|
102
|
-
---
|
|
103
|
-
|
|
104
|
-
## Defaults to apply
|
|
105
|
-
- **Default AI stack:** **A\* on a grid** (binary-heap open set, movement-matched heuristic, weighted tiles) for "where," **steering behaviors** (seek/arrive/avoid/separation) for smooth "how," and an **FSM for simple enemies / behavior tree for complex NPCs** for "what to do."
|
|
106
|
-
- **Use flow fields (BFS/Dijkstra map) when many agents chase one target** (tower defense/RTS) — big perf win over per-agent A*.
|
|
107
|
-
- **For 3D/open worlds, generate navmeshes via recast-navigation-js**; smooth paths with the funnel algorithm.
|
|
108
|
-
- **Bake in the perf guardrails**: cache paths, throttle/time-slice/worker pathfinding, run AI on a fixed lower-rate tick with steering interpolation, and stagger distant agents. Always handle "no path found."
|
|
109
|
-
|
|
110
|
-
---
|
|
111
|
-
|
|
112
|
-
## Sources
|
|
113
|
-
- Red Blob Games — Introduction to A* (canonical, interactive): https://www.redblobgames.com/pathfinding/a-star/introduction.html ; A* Implementation Guide: https://www.redblobgames.com/pathfinding/a-star/implementation.html
|
|
114
|
-
- Red Blob Games — Grids/heuristics & "Pathfinding for Tower Defense" (flow fields): https://www.redblobgames.com/pathfinding/tower-defense/ ; grid pathfinding tricks: https://www.redblobgames.com/pathfinding/grids/algorithms.html
|
|
115
|
-
- Craig Reynolds — "Steering Behaviors For Autonomous Characters": https://www.red3d.com/cwr/steer/ ; Boids: https://www.red3d.com/cwr/boids/
|
|
116
|
-
- Amit Patel / Red Blob — heuristics guide: https://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html
|
|
117
|
-
- PathFinding.js (grid A*/JPS/BFS): https://github.com/qiao/PathFinding.js
|
|
118
|
-
- Jump Point Search (Harabor & Grastien): https://harablog.wordpress.com/2011/09/07/jump-point-search/
|
|
119
|
-
- Behavior Trees — Chris Simpson, "Behavior trees for AI: How they work": https://www.gamedeveloper.com/programming/behavior-trees-for-ai-how-they-work ; behaviortree.js: https://github.com/Calamari/BehaviorTree.js
|
|
120
|
-
- Game Programming Patterns — State (FSM): https://gameprogrammingpatterns.com/state.html
|
|
121
|
-
- Recast/Detour navmesh: https://github.com/recastnavigation/recastnavigation ; recast-navigation-js: https://github.com/isaac-mason/recast-navigation-js ; three-pathfinding: https://github.com/donmccurdy/three-pathfinding
|
|
122
|
-
- GOAP (Jeff Orkin, F.E.A.R.): https://alumni.media.mit.edu/~jorkin/goap.html
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
# Game Audio in the Browser (Web Audio API, mobile unlock, Howler.js, gain buses, spatial, latency)
|
|
2
|
-
|
|
3
|
-
Consolidated from MDN Web Audio docs and Howler.js docs (see Sources). Focus: what an AI builder needs so audio **actually plays on mobile, stays low-latency, and mixes cleanly** — the #1 audio bug in browser games is "no sound on iOS."
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 1. The autoplay unlock — the single most important rule
|
|
8
|
-
|
|
9
|
-
Browsers block audio until the user interacts with the page. An `AudioContext` created on page load starts in the **`"suspended"`** state and will silently play nothing until resumed.
|
|
10
|
-
|
|
11
|
-
**Rule: create/resume the AudioContext (or unlock your audio lib) from inside the FIRST real user gesture** (`click`/`touchend`/`keydown`), and call `resume()` **synchronously** in that handler's call stack (iOS Safari is strict — an `await` before `resume()` can break the gesture chain).
|
|
12
|
-
|
|
13
|
-
```js
|
|
14
|
-
let audioCtx;
|
|
15
|
-
function unlockAudio() {
|
|
16
|
-
if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
|
17
|
-
if (audioCtx.state === 'suspended') audioCtx.resume(); // call synchronously in the gesture
|
|
18
|
-
}
|
|
19
|
-
// Attach once; remove after first success. `pointerdown`/`touchend`/`keydown` all count.
|
|
20
|
-
window.addEventListener('pointerdown', unlockAudio, { once: true });
|
|
21
|
-
window.addEventListener('keydown', unlockAudio, { once: true });
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
- Show a "tap to start" / "click to play" screen so the first gesture reliably unlocks audio (and any pointer lock / fullscreen you need). Games should not expect audio before the player clicks in.
|
|
25
|
-
- Also **resume on `visibilitychange`/focus** — contexts can get re-suspended when a tab is backgrounded on mobile.
|
|
26
|
-
- Listen to the `statechange` event if you need to reflect mute/paused UI.
|
|
27
|
-
|
|
28
|
-
---
|
|
29
|
-
|
|
30
|
-
## 2. Web Audio API vs `<audio>` vs Howler
|
|
31
|
-
|
|
32
|
-
- **Don't use `<audio>` / `Audio()` elements for game SFX.** They have high latency, limited simultaneous playback, and inconsistent mobile behavior. Fine for background music streaming only.
|
|
33
|
-
- **Web Audio API** is the correct foundation: decode once into an `AudioBuffer`, then fire many low-latency, overlapping `AudioBufferSourceNode`s. Gives you precise scheduling, gain buses, and spatialization.
|
|
34
|
-
- **Howler.js** is the recommended default library — it wraps Web Audio (with `<audio>` fallback), auto-handles the **mobile unlock**, sprite support, fades, spatial audio, and pooling. Use it unless you specifically need raw Web Audio control. (Note: `AudioBufferSourceNode` is one-shot — you create a new source per play; that's normal and cheap. Howler manages this for you.)
|
|
35
|
-
|
|
36
|
-
**Preload & decode up front:** `fetch → arrayBuffer → audioCtx.decodeAudioData` during a loading screen. Decoding on first play causes an audible hitch.
|
|
37
|
-
|
|
38
|
-
---
|
|
39
|
-
|
|
40
|
-
## 3. Gain buses (music / SFX / master) — do this from the start
|
|
41
|
-
|
|
42
|
-
Route everything through a small mixer graph so you can control category volumes and a master mute:
|
|
43
|
-
|
|
44
|
-
```
|
|
45
|
-
source → (per-sound gain) → sfxBus ─┐
|
|
46
|
-
music → musicGain ────────────────┼→ masterGain → audioCtx.destination
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
```js
|
|
50
|
-
const master = audioCtx.createGain();
|
|
51
|
-
const musicBus = audioCtx.createGain();
|
|
52
|
-
const sfxBus = audioCtx.createGain();
|
|
53
|
-
musicBus.connect(master); sfxBus.connect(master); master.connect(audioCtx.destination);
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
- Set volumes with **`gain.setTargetAtTime(value, audioCtx.currentTime, 0.02)`** or `setValueAtTime`, **not** a raw `gain.value =` mid-play — abrupt jumps cause clicks/pops. Ramp fades over ~10–50ms.
|
|
57
|
-
- Perceived loudness is logarithmic: map a 0–1 slider to gain with a curve (e.g. `gain = slider²`) so sliders feel linear.
|
|
58
|
-
- Howler equivalent: per-sound `volume`, category via `Howler` groups / separate `Howl` instances, and `Howler.volume()` for master.
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
## 4. Latency (keep audio tight)
|
|
63
|
-
|
|
64
|
-
- Prefer **Web Audio buffer sources** over `<audio>` for anything reactive — element playback latency ruins hit feedback.
|
|
65
|
-
- Optionally construct the context with **`{ latencyHint: 'interactive' }`** (default) for lowest latency; use `'playback'` only for pure music.
|
|
66
|
-
- **Reuse decoded buffers**; never `decodeAudioData` in the gameplay hot path.
|
|
67
|
-
- Schedule to `audioCtx.currentTime` for sample-accurate timing (e.g. rhythm games): `source.start(when)`. Don't rely on `setTimeout` for musical timing — use the Web Audio clock ("A Tale of Two Clocks").
|
|
68
|
-
- Avoid creating hundreds of nodes per frame; cap concurrent voices and stop/disconnect finished sources (set `source.onended` to disconnect) to avoid graph buildup.
|
|
69
|
-
|
|
70
|
-
---
|
|
71
|
-
|
|
72
|
-
## 5. Variation & layering (feel)
|
|
73
|
-
|
|
74
|
-
- **Pitch-randomize** repeated SFX so footsteps/gunfire don't sound robotic: set `source.playbackRate.value = 1 + (Math.random()*2-1)*0.1` (Howler: `rate`). Randomize volume slightly too.
|
|
75
|
-
- **Layer** a sound from multiple samples (thump + body + transient) — see `game-feel-juice.md`.
|
|
76
|
-
- **Round-robin / random pick** from a few variants of the same sound.
|
|
77
|
-
- Use **audio sprites** (one file, offset+duration segments) to cut HTTP requests and decode overhead — Howler supports `sprite` natively.
|
|
78
|
-
|
|
79
|
-
---
|
|
80
|
-
|
|
81
|
-
## 6. Spatial / positional audio (for 3D or top-down games)
|
|
82
|
-
|
|
83
|
-
- **`PannerNode`** positions a source in 3D relative to `audioCtx.listener`. Connect `source → panner → bus`. Update `panner.positionX/Y/Z` and `listener.positionX/Y/Z` (+ listener `forward`/`up`) each frame to match camera/player.
|
|
84
|
-
- `panningModel`: `'HRTF'` (realistic, headphone-friendly, costlier) or `'equalpower'` (cheap stereo). `distanceModel`: `'inverse'`/`'linear'`/`'exponential'` with `refDistance`, `maxDistance`, `rolloffFactor` for falloff.
|
|
85
|
-
- For simple **2D stereo pan** (left/right by screen x), a `StereoPannerNode` (pan −1..1) is cheaper and sufficient — don't reach for HRTF in a 2D game.
|
|
86
|
-
- Howler exposes `pos()`, `orientation()`, and `pannerAttr()` for this.
|
|
87
|
-
- Update positions in the render loop; set the position AudioParams via `.value` (or `setValueAtTime`) to avoid zipper noise on fast movement.
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
## 7. Formats & assets
|
|
92
|
-
- Use **compressed formats**: `.webm`/`.ogg` (Opus/Vorbis) with an `.mp3`/`.m4a` fallback for Safari. Howler takes an array of sources and picks a supported one.
|
|
93
|
-
- Keep SFX short and mono (mono halves size and works with panners); keep music stereo but compressed.
|
|
94
|
-
- Watch total download; long music tracks can stream via `html5: true` in Howler (uses `<audio>`, saves memory, slightly higher latency — fine for music).
|
|
95
|
-
|
|
96
|
-
---
|
|
97
|
-
|
|
98
|
-
## 8. Bug-prevention checklist
|
|
99
|
-
- **No sound on mobile/iOS** → didn't resume `AudioContext` synchronously inside a user gesture; add a tap-to-start unlock.
|
|
100
|
-
- **Silence after backgrounding tab** → context re-suspended; resume on `visibilitychange`/focus.
|
|
101
|
-
- **Clicks/pops on volume change or start/stop** → setting `gain.value` abruptly; ramp with `setTargetAtTime` and fade in/out a few ms.
|
|
102
|
-
- **Laggy hit sounds** → using `<audio>` elements; use Web Audio buffer sources.
|
|
103
|
-
- **Hitch on first play of a sound** → decoding at play time; preload + `decodeAudioData` during loading.
|
|
104
|
-
- **Robotic repeated sounds** → no pitch/volume variation; randomize `playbackRate`.
|
|
105
|
-
- **Growing memory / stuck voices** → not disconnecting finished sources or capping concurrent voices.
|
|
106
|
-
- **Works in Chrome, silent in Safari** → format not supported (provide ogg/opus **and** mp3/m4a) or async break before `resume()`.
|
|
107
|
-
- **No volume controls** → always expose master/music/sfx sliders + mute (accessibility + player expectation).
|
|
108
|
-
|
|
109
|
-
---
|
|
110
|
-
|
|
111
|
-
## Defaults to apply
|
|
112
|
-
- **Default to Howler.js** for generated games (handles unlock, sprites, fades, spatial, pooling) — fall back to raw Web Audio only when we need custom DSP/scheduling.
|
|
113
|
-
- **Always wire the mixer graph**: master + music + sfx gain buses with sliders and a mute, from the first commit. Map sliders through a `x²` curve.
|
|
114
|
-
- **Always add a "tap to start" gate** that unlocks audio (and pointer lock/fullscreen) on the first gesture, and re-resume on visibility change — kills the #1 "no audio on mobile" bug.
|
|
115
|
-
- **Preload + decode on the loading screen**, reuse buffers, pitch-randomize repeated SFX, ramp all gain changes. Provide ogg/opus + mp3 fallbacks.
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
## Sources
|
|
120
|
-
- MDN — Web Audio API Best Practices (autoplay, gesture, gain, controls): https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Best_practices
|
|
121
|
-
- MDN — `AudioContext.resume()`: https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/resume
|
|
122
|
-
- MDN — `BaseAudioContext.decodeAudioData()`: https://developer.mozilla.org/en-US/docs/Web/API/BaseAudioContext/decodeAudioData
|
|
123
|
-
- MDN — `GainNode` / `AudioParam.setTargetAtTime`: https://developer.mozilla.org/en-US/docs/Web/API/GainNode , https://developer.mozilla.org/en-US/docs/Web/API/AudioParam/setTargetAtTime
|
|
124
|
-
- MDN — `PannerNode` + Web audio spatialization basics: https://developer.mozilla.org/en-US/docs/Web/API/PannerNode , https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Web_audio_spatialization_basics
|
|
125
|
-
- MDN — `StereoPannerNode`: https://developer.mozilla.org/en-US/docs/Web/API/StereoPannerNode
|
|
126
|
-
- MDN — Autoplay guide for media & Web Audio: https://developer.mozilla.org/en-US/docs/Web/Media/Autoplay_guide
|
|
127
|
-
- Chris Wilson — "A Tale of Two Clocks" (Web Audio scheduling): https://web.dev/articles/audio-scheduling
|
|
128
|
-
- Howler.js — docs & repo: https://howlerjs.com/ , https://github.com/goldfire/howler.js
|
|
129
|
-
- Chrome autoplay policy for Web Audio: https://developer.chrome.com/blog/autoplay/#webaudio
|