pelican-engine 0.0.0-stage → 0.3.1

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 (192) hide show
  1. package/AGENTS.md +147 -0
  2. package/LICENSE +22 -0
  3. package/README.md +129 -2
  4. package/distribution.json +197 -0
  5. package/docs/AI-WORKFLOW.md +517 -0
  6. package/docs/ARCHITECTURE.md +268 -0
  7. package/docs/CAPABILITIES.md +264 -0
  8. package/docs/DECISIONS.md +107 -0
  9. package/docs/M3-USAGE.md +192 -0
  10. package/docs/PELICAN-MIGRATION.md +38 -0
  11. package/docs/RENDER-BACKENDS.md +50 -0
  12. package/docs/ROADMAP.md +239 -0
  13. package/docs/THIRD-PARTY-NOTICES.md +151 -0
  14. package/docs/api/REFERENCE.md +1435 -0
  15. package/docs/api/index.json +1139 -0
  16. package/docs/npm/DISTRIBUTION.md +130 -0
  17. package/docs/npm/GAME-AUTHOR.md +147 -0
  18. package/engine.manifest.json +15 -0
  19. package/lib/assets/audio.js +67 -0
  20. package/lib/assets/errors.js +36 -0
  21. package/lib/assets/glb.js +277 -0
  22. package/lib/assets/index.js +53 -0
  23. package/lib/assets/jpeg.js +199 -0
  24. package/lib/assets/model.js +558 -0
  25. package/lib/assets/optimize.js +95 -0
  26. package/lib/assets/texture.js +187 -0
  27. package/lib/compiler/distribution.js +17 -0
  28. package/lib/compiler/extract.js +425 -0
  29. package/lib/compiler/graph.js +366 -0
  30. package/lib/compiler/index.js +574 -0
  31. package/lib/compiler/normalize.js +1194 -0
  32. package/lib/compiler/source-map.js +25 -0
  33. package/lib/compiler/types.js +2 -0
  34. package/lib/compiler/version.js +93 -0
  35. package/lib/experiments/simulation/index.js +2 -0
  36. package/lib/experiments/simulation/math.js +41 -0
  37. package/lib/experiments/simulation/probe.js +215 -0
  38. package/lib/experiments/simulation/scenes.js +192 -0
  39. package/lib/experiments/simulation/solver.js +346 -0
  40. package/lib/experiments/simulation/types.js +1 -0
  41. package/lib/experiments/world/adapters.js +30 -0
  42. package/lib/experiments/world/geometry.js +180 -0
  43. package/lib/experiments/world/index.js +2 -0
  44. package/lib/experiments/world/probe.js +288 -0
  45. package/lib/experiments/world/types.js +1 -0
  46. package/lib/experiments/world/world.js +599 -0
  47. package/lib/navigation/index.js +157 -0
  48. package/lib/physics/index.js +909 -0
  49. package/lib/protocol/index.js +92 -0
  50. package/lib/renderer/acceleration.js +609 -0
  51. package/lib/renderer/browser.js +2015 -0
  52. package/lib/renderer/bsdf.js +260 -0
  53. package/lib/renderer/checkpoint.js +88 -0
  54. package/lib/renderer/compute-executor.js +1034 -0
  55. package/lib/renderer/compute-texture-assets.js +49 -0
  56. package/lib/renderer/compute-view-contract.js +1 -0
  57. package/lib/renderer/denoiser.js +361 -0
  58. package/lib/renderer/dielectric.js +360 -0
  59. package/lib/renderer/embedded-image-pixels.js +368 -0
  60. package/lib/renderer/emissive-lights.js +67 -0
  61. package/lib/renderer/environment-importance.js +55 -0
  62. package/lib/renderer/environment.js +346 -0
  63. package/lib/renderer/gameplay.js +464 -0
  64. package/lib/renderer/geometry.js +103 -0
  65. package/lib/renderer/graph-expressions.js +485 -0
  66. package/lib/renderer/graph-tsl.js +141 -0
  67. package/lib/renderer/graph.js +214 -0
  68. package/lib/renderer/managed-texture-sampling.js +29 -0
  69. package/lib/renderer/material-graphs.js +297 -0
  70. package/lib/renderer/medium.js +348 -0
  71. package/lib/renderer/models.js +1053 -0
  72. package/lib/renderer/motion-shader.js +40 -0
  73. package/lib/renderer/path-shader.js +196 -0
  74. package/lib/renderer/pathtrace.js +324 -0
  75. package/lib/renderer/postprocess-contract.js +1 -0
  76. package/lib/renderer/postprocess.js +494 -0
  77. package/lib/renderer/render-buffers.js +132 -0
  78. package/lib/renderer/render-textures.js +155 -0
  79. package/lib/renderer/startup.js +50 -0
  80. package/lib/renderer/surface-capture.js +199 -0
  81. package/lib/renderer/surface-gpu.js +270 -0
  82. package/lib/renderer/surface-motion.js +84 -0
  83. package/lib/renderer/surface-ray-shader.js +91 -0
  84. package/lib/renderer/surface-shader.js +88 -0
  85. package/lib/renderer/surface-tracer.js +1720 -0
  86. package/lib/renderer/surface.js +1425 -0
  87. package/lib/renderer/temporal-filter.js +512 -0
  88. package/lib/renderer/texture-pixels.js +207 -0
  89. package/lib/renderer/traversal-nodes.js +54 -0
  90. package/lib/renderer/ui.js +446 -0
  91. package/lib/renderer/vertex-bounds.js +127 -0
  92. package/lib/renderer/vertex-contract.js +1 -0
  93. package/lib/renderer/vertex-graphs.js +197 -0
  94. package/lib/renderer/volume-shader.js +50 -0
  95. package/lib/runtime/compute-contract.js +1 -0
  96. package/lib/runtime/compute-service.js +674 -0
  97. package/lib/runtime/contracts.js +1 -0
  98. package/lib/runtime/error.js +37 -0
  99. package/lib/runtime/events.js +189 -0
  100. package/lib/runtime/game-services.js +772 -0
  101. package/lib/runtime/host.js +839 -0
  102. package/lib/runtime/material-parameters.js +145 -0
  103. package/lib/runtime/plugins.js +1 -0
  104. package/lib/runtime/postprocess-contract.js +1 -0
  105. package/lib/runtime/postprocess.js +189 -0
  106. package/lib/runtime/prefabs.js +13 -0
  107. package/lib/runtime/random.js +88 -0
  108. package/lib/runtime/render-buffer-contract.js +1 -0
  109. package/lib/runtime/render-buffers.js +243 -0
  110. package/lib/runtime/render-capabilities.js +17 -0
  111. package/lib/runtime/render-settings.js +249 -0
  112. package/lib/runtime/render-texture-contract.js +1 -0
  113. package/lib/runtime/render-textures.js +271 -0
  114. package/lib/runtime/resources.js +648 -0
  115. package/lib/runtime/scheduler.js +765 -0
  116. package/lib/runtime/storage.js +169 -0
  117. package/lib/runtime/world.js +594 -0
  118. package/lib/schema/index.js +24 -0
  119. package/lib/sdk/graph-values.js +16 -0
  120. package/lib/sdk/index.d.ts +800 -0
  121. package/lib/sdk/index.js +82 -0
  122. package/lib/tools/api-index.js +113 -0
  123. package/lib/tools/browser-session.js +89 -0
  124. package/lib/tools/cli.js +513 -0
  125. package/lib/tools/compress-dist.js +59 -0
  126. package/lib/tools/control-client.js +153 -0
  127. package/lib/tools/control-server.js +633 -0
  128. package/lib/tools/diagnostic-code.js +3 -0
  129. package/lib/tools/doctor.js +496 -0
  130. package/lib/tools/npm/browser-cli.js +6 -0
  131. package/lib/tools/npm/entry.js +40 -0
  132. package/lib/tools/npm/layout.js +195 -0
  133. package/lib/tools/setup.js +153 -0
  134. package/licenses/@dimforge/rapier2d-compat/LICENSE +201 -0
  135. package/licenses/@dimforge/rapier3d-compat/LICENSE +201 -0
  136. package/licenses/@gltf-transform/core/LICENSE.md +21 -0
  137. package/licenses/@gltf-transform/extensions/LICENSE.md +21 -0
  138. package/licenses/@gltf-transform/functions/LICENSE.md +21 -0
  139. package/licenses/@img/colour/LICENSE.md +82 -0
  140. package/licenses/@img/sharp-win32-x64/LICENSE +191 -0
  141. package/licenses/@oxc-project/types/LICENSE +22 -0
  142. package/licenses/@rolldown/pluginutils/LICENSE +21 -0
  143. package/licenses/@tweenjs/tween.js/LICENSE +23 -0
  144. package/licenses/@types/ndarray/LICENSE +21 -0
  145. package/licenses/@types/node/LICENSE +21 -0
  146. package/licenses/@types/stats.js/LICENSE +21 -0
  147. package/licenses/@types/three/@dimforge/rapier3d-compat/LICENSE +201 -0
  148. package/licenses/@types/three/LICENSE +21 -0
  149. package/licenses/@types/webxr/LICENSE +21 -0
  150. package/licenses/@webgpu/types/LICENSE +26 -0
  151. package/licenses/THIRD-PARTY-NOTICES.md +139 -0
  152. package/licenses/cwise-compiler/LICENSE +22 -0
  153. package/licenses/detect-libc/LICENSE +201 -0
  154. package/licenses/esbuild/LICENSE.md +21 -0
  155. package/licenses/fast-png/LICENSE +21 -0
  156. package/licenses/fdir/LICENSE +7 -0
  157. package/licenses/fflate/LICENSE +21 -0
  158. package/licenses/iobuffer/LICENSE +22 -0
  159. package/licenses/iota-array/LICENSE +22 -0
  160. package/licenses/is-buffer/LICENSE +21 -0
  161. package/licenses/ktx-parse/LICENSE +21 -0
  162. package/licenses/lightningcss/LICENSE +373 -0
  163. package/licenses/lightningcss-win32-x64-msvc/LICENSE +373 -0
  164. package/licenses/meshoptimizer/LICENSE.md +21 -0
  165. package/licenses/nanoid/LICENSE +20 -0
  166. package/licenses/ndarray/LICENSE +22 -0
  167. package/licenses/ndarray-lanczos/LICENSE +21 -0
  168. package/licenses/ndarray-ops/LICENSE +22 -0
  169. package/licenses/ndarray-pixels/LICENSE +21 -0
  170. package/licenses/ngraph.path/LICENSE +21 -0
  171. package/licenses/picocolors/LICENSE +15 -0
  172. package/licenses/picomatch/LICENSE +21 -0
  173. package/licenses/playwright/LICENSE +202 -0
  174. package/licenses/playwright/NOTICE +5 -0
  175. package/licenses/playwright-core/LICENSE +202 -0
  176. package/licenses/playwright-core/NOTICE +5 -0
  177. package/licenses/postcss/LICENSE +20 -0
  178. package/licenses/prettier/LICENSE +7 -0
  179. package/licenses/property-graph/LICENSE +21 -0
  180. package/licenses/rolldown/LICENSE +25 -0
  181. package/licenses/semver/LICENSE +15 -0
  182. package/licenses/sharp/LICENSE +191 -0
  183. package/licenses/source-map-js/LICENSE +28 -0
  184. package/licenses/three/LICENSE +21 -0
  185. package/licenses/tinyglobby/LICENSE +21 -0
  186. package/licenses/tsx/LICENSE +21 -0
  187. package/licenses/typescript/LICENSE.txt +55 -0
  188. package/licenses/undici-types/LICENSE +21 -0
  189. package/licenses/uniq/LICENSE +22 -0
  190. package/licenses/vite/LICENSE.md +2084 -0
  191. package/package.json +49 -4
  192. package/web/index.html +34 -0
@@ -0,0 +1,130 @@
1
+ # Pelican Engine npm development distribution
2
+
3
+ The installed package is `pelican-engine`. Its root export is the same compiled
4
+ public SDK used by repository games, not a wrapper or a separate SDK. The package
5
+ also provides the `pelican` executable. This is an M3 development distribution,
6
+ not accepted M3 hardware evidence or a complete engine release.
7
+
8
+ ## Windows project workflow
9
+
10
+ Use Node 24 and npm in an empty project directory. The explicit prefix keeps npm
11
+ in this directory even when a parent directory is also an npm project:
12
+
13
+ ```powershell
14
+ npm --prefix . i -D pelican-engine
15
+ npx pelican dev
16
+ ```
17
+
18
+ The first installed `dev` creates the minimal `game.ts`, `pelican.project.json`
19
+ version lock, and game-author `AGENTS.md` when the directory contains only npm
20
+ installation metadata. An existing game or manifest is used as supplied; other
21
+ project files or author instructions prevent automatic scaffolding. Files are
22
+ never overwritten. Stop dev with Ctrl+C, then use the same local CLI:
23
+
24
+ ```powershell
25
+ npx --no-install pelican api
26
+ npx --no-install pelican setup --install-browser
27
+ npx --no-install pelican check
28
+ npx --no-install pelican dev --port 4173
29
+ npx --no-install pelican capture --port 4174 --output capture.png
30
+ npx --no-install pelican build
31
+ ```
32
+
33
+ For an exact-version install use `npm --prefix . i -D --save-exact pelican-engine@0.3.1`,
34
+ or substitute the local `pelican-engine-0.3.1.tgz` tarball before registry
35
+ publication. `pelican create --template minimal` remains available explicitly.
36
+
37
+ Without `--prefix .`, npm may select an ancestor `package.json` or `node_modules`
38
+ as the install root and modify that parent. The shorter `npm i -D pelican-engine`
39
+ works when npm selects the intended directory; verify `npm prefix` before using
40
+ it. The smoke harness uses an explicit prefix and does not require `npm init`.
41
+
42
+ `create --template minimal` uses the same primitive starter in npm and repository
43
+ workflows. npm defaults to `minimal` and reports the selected template; repository
44
+ default `m2` is preserved with its historical sample assets. Samples are not engine
45
+ capabilities. Identical authored game/asset inputs use the same API/compiler/runtime
46
+ in either channel. npm does not bundle the `m2` sample or any sample/game assets.
47
+
48
+ `create` writes `game.ts`, `AGENTS.md` and an exact `pelican.project.json` lock in the current
49
+ directory. Existing project files are never overwritten. Author TypeScript with
50
+ named imports from `pelican-engine` and project-local imports only. The compiler
51
+ reports `TC_PUBLIC_API` for renderer, Three.js, TSL, physics, Node and internal
52
+ package imports, including type-only and unused imports. Package subpaths are not
53
+ public exports. Project lock mismatches report `TC_ENGINE_VERSION_MISMATCH`;
54
+ mixed package/API versions report `TC_ENGINE_SDK_VERSION`. Reinstall a matching
55
+ exact version, or migrate through the public API before explicitly changing a lock.
56
+
57
+ After npm dependencies and Playwright Chromium have been installed, authoring,
58
+ API inspection, checks, builds, dev/control commands and capture need no network
59
+ service. `setup --offline` never installs dependencies or downloads a browser in
60
+ an installed package. Keep the game package-lock for repeatable future installs;
61
+ an offline _reinstall_ additionally requires the npm cache or a dependency mirror.
62
+ `TC_DISTRIBUTION_DEPENDENCY_MISSING` and
63
+ `TC_DISTRIBUTION_DEPENDENCY_VERSION` identify broken tool dependencies.
64
+
65
+ Serve the generated `dist/` directory over HTTP(S), including its `generated/`
66
+ files, license files, notices and compression manifests. No Node process, engine
67
+ repository, SDK installation, external AI service or development control server
68
+ is needed by players. Use `build --base /game/` for a nested deployment URL.
69
+ Capture requires installed Chromium and actual supported graphics capability.
70
+ No software renderer result establishes hardware acceptance.
71
+
72
+ ## AI entry points
73
+
74
+ Read the game-author `AGENTS.md`, `docs/npm/GAME-AUTHOR.md`, `docs/CAPABILITIES.md` and
75
+ `docs/api/REFERENCE.md` inside `node_modules/pelican-engine`. The machine-readable
76
+ API is `docs/api/index.json`, also discoverable through `pelican api`.
77
+ `lib/sdk/index.d.ts` is the authoritative installed declaration surface.
78
+ `docs/PELICAN-MIGRATION.md` explains current names and historical provenance.
79
+ Repository paths and release instructions in copied documents are historical
80
+ context; the installed workflow above replaces source-checkout commands.
81
+ The JSON CLI protocol and dev control operations are shared with the repository.
82
+
83
+ ## Maintainer validation and publishing
84
+
85
+ ```powershell
86
+ npm run distribution:test
87
+ npm run distribution:pack
88
+ npm run distribution:smoke
89
+ npm run distribution:smoke -- --gpu
90
+ ```
91
+
92
+ Build output is regenerated from current sources into ignored
93
+ `.pelican/npm/package/`; tarballs and smoke reports go in `.pelican/npm/artifacts/`.
94
+ Neither staging nor tarballs are inside the deployable game `dist/`.
95
+ Pack that staging directory, not the private repository root. Compiled relative
96
+ imports use `lib/` modules and `.js`, never the TypeScript source layout. The
97
+ tarball allowlist excludes source maps, evidence, examples and game assets;
98
+ SDK declarations, engine runtime code, MIT, copied AI docs, and dependency
99
+ license texts are included. `distribution.json` records version and file hashes.
100
+ Dependencies are normal pinned npm dependencies, not vendored engine sources.
101
+
102
+ The npm workflow runs only for a published GitHub milestone release. Its gate
103
+ requires tag/version/SDK/manifest identity and the existing milestone acceptance
104
+ and source-fingerprint checks. An ordinary push or CPU-green build cannot publish.
105
+ M3 is deliberately blocked until its release profile and real acceptance exist.
106
+ The default smoke install uses npm cache only; `--online-install` allows network
107
+ for initial dependency installation, then runs every operation offline with a
108
+ disabled registry. CI uses this flag because `npm ci` alone need not populate
109
+ registry metadata for a fresh external install. `--gpu` additionally measures
110
+ the installed WebGPU backend, renders path/hybrid/raster, checks a nonblank canvas,
111
+ captures through both CLI routes, verifies WebGL2 fallback rejection, and loads
112
+ the nested-base static build without a development hook. It is not M3 acceptance.
113
+
114
+ The single unscoped package is `pelican-engine`, its only public import is
115
+ `pelican-engine`, and its executable is `pelican`. The GitHub target is
116
+ `danchar12138/pelican-engine`; main completed the public repository rename and
117
+ verified the updated origin. No new organization is required. The authorized
118
+ npm Automation Token was authenticated as `danchar12138`, and main confirmed
119
+ the repository Actions secret `NPM_TOKEN` is configured. `npm view pelican-engine`
120
+ returned `E404` before publication. The package remains unpublished pending
121
+ genuine M3 acceptance; this is not an authentication or organization blocker.
122
+ `setup-node` configures the registry;
123
+ only the final publication step receives `NODE_AUTH_TOKEN`. A missing secret
124
+ fails with `TC_NPM_AUTH_MISSING`, without printing the value. The token must have
125
+ permission to publish the fixed unscoped package. No OIDC/trusted-publisher setup
126
+ or provenance flag is required by this workflow. Prereleases use `next`; stable
127
+ versions use `latest`. These credentials do not bypass milestone acceptance.
128
+ No token value is stored in source, documentation, or probe output. No publication
129
+ is performed by this packaging task. See
130
+ `tools/npm/publish-gate.ts` in the source distribution.
@@ -0,0 +1,147 @@
1
+ # Pelican Engine Game Author
2
+
3
+ Your workspace is the game project. Use the public `pelican-engine` API and local
4
+ game modules. Do not modify engine internals or `node_modules`, import Three.js,
5
+ TSL, GPU devices, physics-library objects, compiler internals or Node APIs into
6
+ game code. Engine research, hardware acceptance, evidence and publishing tasks
7
+ are not part of game authoring.
8
+
9
+ Read the API reference at `docs/api/REFERENCE.md` and machine-readable symbols at
10
+ `docs/api/index.json` under the engine/package directory. Installed declarations
11
+ are `lib/sdk/index.d.ts`. `pelican api` discovers the index;
12
+ `pelican api --symbol defineGame` returns exact, case-sensitive public signatures
13
+ as JSON in both source and npm distributions. `pelican help`
14
+ lists the JSON CLI protocol. `docs/CAPABILITIES.md` records implemented scope and
15
+ limitations. The longer `docs/AI-WORKFLOW.md` is shared design context, not an
16
+ instruction to run source-only engine acceptance tasks.
17
+
18
+ The shared `docs/M3-USAGE.md` describes the current rendering and compute
19
+ contracts. Its `examples/`, engine `packages/`, and `npm run probe:*` references
20
+ are maintainer references available only in a source checkout; the npm package
21
+ intentionally contains no example projects, game assets, or engine source. Use
22
+ the same public declarations in your own game project and validate them with the
23
+ installed `pelican` commands. Do not try to import an internal compiled module.
24
+
25
+ Models using `KHR_animation_pointer` animation channels are currently rejected
26
+ with `TC_MODEL_EXTENSION_UNSUPPORTED`; pointer-driven material animation is not
27
+ implemented. A merely declared optional extension without such a channel does
28
+ not cause this runtime rejection.
29
+
30
+ ## Standalone Rendering Recipe
31
+
32
+ The following complete asset-free `game.ts` works with either distribution and
33
+ exercises the public opaque-IOR and specular material controls:
34
+
35
+ <!-- standalone-render-recipe:start -->
36
+ ```ts
37
+ import { defineGame, defineMaterial, defineScene } from "pelican-engine";
38
+
39
+ const material = defineMaterial({
40
+ id: "paint",
41
+ color: "#303030",
42
+ roughness: 0.35,
43
+ metalness: 0,
44
+ ior: 1.5,
45
+ specularIntensity: 0.7,
46
+ specularColor: "#ffb080",
47
+ });
48
+
49
+ export default defineGame({
50
+ id: "render-recipe",
51
+ scene: defineScene({
52
+ id: "main",
53
+ camera: { position: [0, 1, 5], target: [0, 0, 0], fov: 45 },
54
+ environment: { background: "#17212a", ambientIntensity: 0.4 },
55
+ entities: [
56
+ { id: "object", mesh: { geometry: { kind: "box" }, material } },
57
+ { id: "light", transform: { position: [2, 4, 5] },
58
+ light: { kind: "directional", intensity: 3 } },
59
+ ],
60
+ }),
61
+ });
62
+ ```
63
+ <!-- standalone-render-recipe:end -->
64
+
65
+ Use `npx --no-install pelican check` and `npx --no-install pelican dev` in an
66
+ installed project, then `npx --no-install pelican build`. A repository-based
67
+ project uses the same source and equivalent engine CLI commands listed below.
68
+ Imported opaque GLB materials support `KHR_materials_specular` intensity and
69
+ color textures with `TEXCOORD_0`. Positive transmission combined with specular
70
+ textures or non-default specular remains unsupported. The tracer rejects PNG
71
+ color maps with ICC profiles. Low-bit-depth grayscale and indexed Adam7 PNGs
72
+ are decoded with explicit pass/filter validation. For 16-bit PNG,
73
+ supported color chunks are gAMA 45455 or 100000, standard sRGB cHRM, sRGB
74
+ intent 0, and cICP [1,13,0,1]; other values are diagnosed. Use supported PNG
75
+ or JPEG and retain diagnostics rather than silently changing material semantics.
76
+
77
+ Audio voices returned by `ctx.audio.play(soundId, options)` can be paused and
78
+ resumed with `ctx.audio.pause(voice)` and `ctx.audio.resume(voice)`. Both are
79
+ idempotent; a valid unknown voice is a no-op. Playback position follows fixed
80
+ simulation ticks, including while browser audio is locked. Paused time does not
81
+ advance the voice. Snapshots restore playback intent and logical position, not
82
+ the browser's internal audio processing state.
83
+
84
+ Declare `audioBuses: [{ id: "music", volume: 0.5 }]` in `defineGame`, route a
85
+ sound with `sounds: [{ id: "theme", asset: musicAsset, bus: "music" }]`, and
86
+ change its bus using `ctx.audio.busVolume("music", 0.25)`. A `play` call can
87
+ override the sound's bus with `{ bus: "music" }`. Bus, voice and master gains
88
+ multiply; `ctx.audio.volume` controls master gain. Unknown buses and gains
89
+ outside 0–1 return diagnostics. Games with no buses keep their existing routing.
90
+
91
+ Use `ctx.audio.fadeBus("music", 0, 1.5)` for a fixed-tick linear fade in
92
+ seconds. A new fade or `busVolume` replaces the previous fade. `play` accepts
93
+ an optional integer `priority` from 0 to 255; when the voice limit is full, a
94
+ new voice only replaces the earliest voice with a strictly lower priority.
95
+ Invalid priority or a non-winning full voice returns a stable diagnostic.
96
+
97
+ For orthogonal grid routing, game systems may call `ctx.navigation.createGrid`
98
+ with `{ id, owner, width, height }`, then `setBlocked(id, { x, y }, true)` and
99
+ `findPath(id, start, end)`. Paths contain both endpoints; `destroyGrid` and
100
+ `destroyOwner` release grids. The default 65,536-cell `searchCellBudget` limits
101
+ distinct cells considered per query; set it explicitly when needed. Budget
102
+ exhaustion returns `TC_NAVIGATION_CAPACITY`, not an unreachable result. Owners
103
+ are explicit strings, not entities. This is a development-stage grid service,
104
+ not continuous-world, flying or underwater navigation.
105
+
106
+ Keyboard bindings use the browser's `KeyboardEvent.key` values, not physical
107
+ `KeyboardEvent.code` values. For example, use `input: { up: ["w", "W", "ArrowUp"],
108
+ restart: ["r", "R"] }`, not `"KeyW"` or `"KeyR"`. Letter case depends on the
109
+ actual keyboard event; Space is `" "`. Actions are read inside systems through
110
+ `ctx.input.held`, `pressed`, `released`, or `axis`. Always exercise real keyboard
111
+ input in the browser; a mocked system test does not establish browser bindings.
112
+
113
+ ## Work Loop
114
+
115
+ 1. Inspect `pelican.project.json`, `game.ts`, asset declarations and the public API.
116
+ 2. Make small game-only edits. Keep the exact engine version lock.
117
+ 3. Run `pelican check`, then `pelican dev` and exercise actual gameplay.
118
+ 4. Use `inspect`, `input`, `step`, `pause`, `resume`, `snapshot`, `restore`,
119
+ `record`, `replay`, `status`, `cancel` and `reset-session` against the dev port.
120
+ 5. Run `capture --live` against the dev port or a standalone `capture`, inspect
121
+ the actual screenshot, and preserve explicit failures rather than claiming success.
122
+ 6. Run `build` and serve `dist/` over HTTP(S). Keep notices and license files.
123
+
124
+ Installed package commands use `npx --no-install pelican <command>` from the game
125
+ directory. Repository commands use `node --import tsx <engine>/tools/cli.ts
126
+ <command> --project <game-directory>` with the same operations and protocol.
127
+ Both `create` commands generate a project `AGENTS.md` pointing to these same docs.
128
+ In a new installed workspace, `npm --prefix . i -D pelican-engine` followed by
129
+ `npx pelican dev` automatically creates that same minimal starter when no project
130
+ files exist. Existing games, manifests and author instructions are preserved.
131
+ The explicit prefix prevents npm from choosing a parent project when one exists.
132
+
133
+ Dependencies and Chromium must be installed before offline work. Once prepared,
134
+ checks/builds/dev/capture use local files and loopback only. `setup --offline`
135
+ never downloads a missing browser. In npm projects use `setup --install-browser`
136
+ once while online. No Git checkout, account, external AI service or source tree
137
+ is required to author an installed game.
138
+
139
+ Do not assume all render modes are supported. Use `engine.render.capabilities()`
140
+ to inspect the actual backend. WebGL2 fallback does not silently implement
141
+ compute-dependent path/hybrid features. Observe structured diagnostics and keep
142
+ the prior valid state on rejected operations. Hardware acceptance is separate
143
+ from a successful software-rendered or CPU-only run.
144
+
145
+ For project-version mismatches, migrate via public API, then explicitly update
146
+ the lock. For package integrity/dependency errors, reinstall one exact package
147
+ version. Never work around a diagnostic by importing an internal dependency.
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "pelican-engine",
3
+ "version": "0.3.1",
4
+ "milestone": "M3",
5
+ "stage": "advanced-rendering-development",
6
+ "license": "MIT",
7
+ "protocolVersion": "0.1.0",
8
+ "agentEntry": "AGENTS.md",
9
+ "developmentPlatform": "windows",
10
+ "renderer": "webgpu-with-webgl2-fallback",
11
+ "publicApi": "lib/sdk/index.d.ts",
12
+ "workflow": "docs/npm/GAME-AUTHOR.md",
13
+ "releasePolicy": "docs/npm/DISTRIBUTION.md",
14
+ "releaseScope": "dynamic-raytracing"
15
+ }
@@ -0,0 +1,67 @@
1
+ import path from "node:path";
2
+ export function inspectWAV(data, ctx) {
3
+ if (data.toString("latin1", 0, 4) !== "RIFF") {
4
+ const magic = data.toString("latin1", 0, 4);
5
+ if (path.extname(ctx.file).toLowerCase() === ".wav" &&
6
+ !["RF64", "RIFX"].includes(magic))
7
+ ctx.invalid("WAV/header", "Missing or damaged RIFF header.");
8
+ ctx.unsupported("audio/format", "Only little-endian RIFF/WAVE PCM and IEEE float audio are implemented.");
9
+ }
10
+ ctx.check(data.length >= 12 && data.toString("latin1", 8, 12) === "WAVE", "WAV/header", "Missing or truncated WAVE header.");
11
+ ctx.check(data.readUInt32LE(4) + 8 === data.length, "WAV/length", "RIFF length does not match the file.");
12
+ let offset = 12;
13
+ let format;
14
+ let samples;
15
+ let factFrames;
16
+ while (offset < data.length) {
17
+ ctx.check(offset + 8 <= data.length, "WAV/chunk", "Truncated chunk header.");
18
+ const id = data.toString("latin1", offset, offset + 4), size = data.readUInt32LE(offset + 4);
19
+ const end = offset + 8 + size, padded = end + (size % 2);
20
+ ctx.check(padded <= data.length, `WAV/${id}`, "Chunk exceeds RIFF boundary or is missing padding.");
21
+ const chunk = data.subarray(offset + 8, end);
22
+ if (id === "fmt ") {
23
+ ctx.check(!format && !samples && size >= 16, "WAV/fmt", "Missing, duplicate, misplaced or truncated format chunk.");
24
+ const encoding = chunk.readUInt16LE(0), channels = chunk.readUInt16LE(2), sampleRate = chunk.readUInt32LE(4);
25
+ const byteRate = chunk.readUInt32LE(8), blockAlign = chunk.readUInt16LE(12), bitsPerSample = chunk.readUInt16LE(14);
26
+ if (![1, 3].includes(encoding))
27
+ ctx.unsupported("WAV/encoding", `WAVE format tag ${encoding} is not implemented (PCM=1, float=3).`);
28
+ ctx.check(size === 16 || (size >= 18 && chunk.readUInt16LE(16) === size - 18), "WAV/fmt", "Invalid format extension length.");
29
+ ctx.check(channels > 0 &&
30
+ sampleRate > 0 &&
31
+ (encoding === 1 ? [8, 16, 24, 32] : [32, 64]).includes(bitsPerSample), "WAV/fmt", "Invalid channels, sample rate or sample size.");
32
+ ctx.check(blockAlign === (channels * bitsPerSample) / 8 &&
33
+ byteRate === sampleRate * blockAlign, "WAV/fmt", "Inconsistent block alignment or byte rate.");
34
+ format = { encoding, channels, sampleRate, bitsPerSample, blockAlign };
35
+ }
36
+ else if (id === "fact") {
37
+ ctx.check(factFrames === undefined && size >= 4, "WAV/fact", "Duplicate or truncated fact chunk.");
38
+ factFrames = chunk.readUInt32LE(0);
39
+ }
40
+ else if (id === "data") {
41
+ ctx.check(format && !samples, "WAV/data", "Missing format chunk or duplicate data chunk.");
42
+ ctx.check(size > 0 && size % format.blockAlign === 0, "WAV/data", "Empty or incomplete sample frame.");
43
+ samples = chunk;
44
+ }
45
+ offset = padded;
46
+ }
47
+ ctx.check(format && samples, "WAV/chunks", "Both fmt and data chunks are required.");
48
+ if (format.encoding === 3) {
49
+ const step = format.bitsPerSample / 8;
50
+ for (let i = 0; i < samples.length; i += step)
51
+ ctx.check(Number.isFinite(step === 4 ? samples.readFloatLE(i) : samples.readDoubleLE(i)), "WAV/data", "Non-finite floating point sample.");
52
+ }
53
+ const frameCount = samples.length / format.blockAlign;
54
+ ctx.check(format.encoding !== 3 || factFrames !== undefined, "WAV/fact", "IEEE float WAVE requires a fact sample count.");
55
+ if (factFrames !== undefined)
56
+ ctx.check(factFrames === frameCount, "WAV/fact", "Fact sample count does not match data frames.");
57
+ return {
58
+ format: "wav",
59
+ encoding: format.encoding === 1 ? "pcm" : "ieee-float",
60
+ channels: format.channels,
61
+ sampleRate: format.sampleRate,
62
+ bitsPerSample: format.bitsPerSample,
63
+ frameCount,
64
+ duration: frameCount / format.sampleRate,
65
+ dataBytes: samples.length,
66
+ };
67
+ }
@@ -0,0 +1,36 @@
1
+ export class AssetInspectionError extends Error {
2
+ code;
3
+ file;
4
+ resource;
5
+ suggestion;
6
+ constructor(code, file, resource, detail, suggestion) {
7
+ super(`${code}: ${file} [${resource}]: ${detail} ${suggestion}`);
8
+ this.code = code;
9
+ this.file = file;
10
+ this.resource = resource;
11
+ this.suggestion = suggestion;
12
+ this.name = "AssetInspectionError";
13
+ }
14
+ }
15
+ export class InspectionContext {
16
+ file;
17
+ constructor(file) {
18
+ this.file = file;
19
+ }
20
+ invalid(resource, detail) {
21
+ throw new AssetInspectionError("TC_ASSET_INVALID", this.file, resource, detail, "Repair or re-export the source asset and inspect it again.");
22
+ }
23
+ unsupported(resource, detail) {
24
+ throw new AssetInspectionError("TC_ASSET_UNSUPPORTED", this.file, resource, detail, "Convert to a supported self-contained format; see packages/assets/README.md.");
25
+ }
26
+ check(condition, resource, detail) {
27
+ if (!condition)
28
+ this.invalid(resource, detail);
29
+ }
30
+ integer(value, resource, min = 0, max = Number.MAX_SAFE_INTEGER) {
31
+ this.check(Number.isSafeInteger(value) &&
32
+ Number(value) >= min &&
33
+ Number(value) <= max, resource, `Expected an integer in [${min}, ${max}].`);
34
+ return value;
35
+ }
36
+ }