@underpostnet/cyberia 3.3.73 → 3.3.77

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 (269) hide show
  1. package/.env.example +17 -5
  2. package/.github/workflows/coverall.cyberia.ci.yml +10 -0
  3. package/.github/workflows/docker-image.cyberia-client.ci.yml +1 -1
  4. package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +1 -1
  5. package/.github/workflows/docker-image.cyberia-server.ci.yml +1 -1
  6. package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +1 -1
  7. package/.github/workflows/docker-image.engine-cyberia.ci.yml +1 -1
  8. package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +1 -1
  9. package/.github/workflows/engine-cyberia.ci.yml +1 -1
  10. package/.github/workflows/publish.cyberia.ci.yml +44 -0
  11. package/AGENTS.md +61 -12
  12. package/CHANGELOG.md +159 -161
  13. package/CLI-HELP.md +20 -13
  14. package/Dockerfile +1 -1
  15. package/Dockerfile.dev +1 -1
  16. package/Dockerfile.test +2 -2
  17. package/README.md +28 -28
  18. package/bin/build.js +96 -21
  19. package/bin/cyberia.js +1247 -1373
  20. package/bin/index.js +1247 -1373
  21. package/compose.env +17 -5
  22. package/conf.js +7 -4
  23. package/deploy/cyberia-client/deploy.sh +10 -11
  24. package/deploy/cyberia-client/package.sh +0 -1
  25. package/deploy/cyberia-client/state.sh +3 -2
  26. package/deploy/cyberia-server/deploy.sh +10 -11
  27. package/deploy/cyberia-server/package.sh +0 -1
  28. package/deploy/cyberia-server/state.sh +3 -2
  29. package/deploy/dd-cyberia/deploy.sh +5 -5
  30. package/deploy/dd-cyberia/init.sh +15 -14
  31. package/deploy/dd-cyberia/package.sh +0 -1
  32. package/deploy/dd-cyberia/state.sh +2 -2
  33. package/deploy/dd-cyberia/sync-deploy.sh +139 -75
  34. package/deploy/lib/config.sh +29 -0
  35. package/deploy/lib/github-actions-logging.sh +92 -76
  36. package/deploy/lib/host.sh +28 -19
  37. package/deploy/lib/state.sh +4 -1
  38. package/deploy/pwa-microservices-template/deploy.sh +10 -8
  39. package/deploy/release/deploy.sh +0 -2
  40. package/deployment.yaml +1 -1
  41. package/docker-compose.yml +23 -17
  42. package/docs/coverage/cyberia/api/cyberia-instance/cyberia-fallback-capture.js.html +1591 -0
  43. package/docs/coverage/cyberia/api/cyberia-instance/index.html +116 -0
  44. package/docs/coverage/cyberia/api/cyberia-server-defaults/cyberia-server-defaults.js.html +4138 -0
  45. package/docs/coverage/cyberia/api/cyberia-server-defaults/index.html +116 -0
  46. package/docs/coverage/cyberia/api/object-layer/index.html +116 -0
  47. package/docs/coverage/cyberia/api/object-layer/object-layer.model.js.html +1393 -0
  48. package/docs/coverage/cyberia/base.css +362 -0
  49. package/docs/coverage/cyberia/block-navigation.js +82 -0
  50. package/docs/coverage/cyberia/favicon.png +0 -0
  51. package/docs/coverage/cyberia/index.html +161 -0
  52. package/docs/coverage/cyberia/prettify.css +101 -0
  53. package/docs/coverage/cyberia/prettify.js +937 -0
  54. package/docs/coverage/cyberia/projects/cyberia/atlas-sprite-sheet-generator.js.html +1315 -0
  55. package/docs/coverage/cyberia/projects/cyberia/index.html +176 -0
  56. package/docs/coverage/cyberia/projects/cyberia/instance-backup.js.html +715 -0
  57. package/docs/coverage/cyberia/projects/cyberia/instance-data.js.html +2182 -0
  58. package/docs/coverage/cyberia/projects/cyberia/shape-generator.js.html +3265 -0
  59. package/docs/coverage/cyberia/projects/cyberia/stat-balance.js.html +328 -0
  60. package/docs/coverage/cyberia/sort-arrow-sprite.png +0 -0
  61. package/docs/coverage/cyberia/sorter.js +205 -0
  62. package/hardhat/package-lock.json +2 -2
  63. package/hardhat/package.json +1 -1
  64. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +1 -1
  65. package/manifests/cronjobs/dd-cron/dd-cron-vultr.yaml +1 -1
  66. package/manifests/deployment/dd-cyberia-development/deployment.yaml +1 -1
  67. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  68. package/manifests/deployment/mongo-express/deployment.yaml +46 -27
  69. package/manifests/deployment/mongo-express/kustomization.yaml +9 -0
  70. package/manifests/deployment/mongo-express/mongo-express-nodeport.yaml +18 -0
  71. package/manifests/deployment/mongo-express/service.yaml +16 -0
  72. package/manifests/deployment/mongo-express-no-auth/disable-mongodb-auth.yaml +16 -0
  73. package/manifests/deployment/mongo-express-no-auth/kustomization.yaml +16 -0
  74. package/package.json +19 -17
  75. package/scripts/test-monitor.sh +3 -3
  76. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.controller.js +14 -9
  77. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.model.js +36 -5
  78. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +5 -0
  79. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +88 -184
  80. package/src/api/cyberia-action/cyberia-action.router.js +2 -2
  81. package/src/api/cyberia-action/cyberia-action.service.js +3 -4
  82. package/src/api/cyberia-audio/cyberia-audio.controller.js +6 -0
  83. package/src/api/cyberia-audio/cyberia-audio.model.js +61 -0
  84. package/src/api/cyberia-audio/cyberia-audio.router.js +21 -0
  85. package/src/api/cyberia-audio/cyberia-audio.service.js +220 -0
  86. package/src/api/cyberia-client-hints/cyberia-client-hints.controller.js +1 -3
  87. package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +10 -19
  88. package/src/api/cyberia-client-hints/cyberia-client-hints.router.js +12 -34
  89. package/src/api/cyberia-client-hints/cyberia-client-hints.service.js +15 -32
  90. package/src/api/cyberia-dialogue/cyberia-dialogue.model.js +1 -1
  91. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +1 -1
  92. package/src/api/cyberia-entity/cyberia-entity.model.js +2 -0
  93. package/src/api/cyberia-entity/cyberia-entity.service.js +1 -1
  94. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +8 -2
  95. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +31 -20
  96. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +16 -1
  97. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +466 -3
  98. package/src/api/cyberia-instance/cyberia-fallback-capture.js +87 -51
  99. package/src/api/cyberia-instance/cyberia-fallback-world.js +21 -40
  100. package/src/api/cyberia-instance/cyberia-instance-boot.service.js +5 -5
  101. package/src/api/cyberia-instance/cyberia-instance-items.js +98 -0
  102. package/src/api/cyberia-instance/cyberia-instance-map.service.js +34 -141
  103. package/src/api/cyberia-instance/cyberia-instance.controller.js +1 -4
  104. package/src/api/cyberia-instance/cyberia-instance.model.js +0 -14
  105. package/src/api/cyberia-instance/cyberia-instance.router.js +3 -16
  106. package/src/api/cyberia-instance/cyberia-instance.service.js +3 -43
  107. package/src/api/cyberia-instance/cyberia-world-generator.js +8 -13
  108. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +49 -75
  109. package/src/api/cyberia-instance-conf/cyberia-instance-conf.service.js +74 -1
  110. package/src/api/cyberia-map/cyberia-map.service.js +6 -2
  111. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.controller.js +31 -0
  112. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.model.js +56 -0
  113. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.router.js +33 -0
  114. package/src/api/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +189 -0
  115. package/src/api/cyberia-quest/cyberia-quest.router.js +3 -3
  116. package/src/api/cyberia-quest/cyberia-quest.service.js +3 -3
  117. package/src/api/cyberia-quest-progress/cyberia-quest-progress.model.js +1 -1
  118. package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +403 -188
  119. package/src/api/cyberia-skill/cyberia-skill.model.js +6 -6
  120. package/src/api/file/file.ref.js +153 -0
  121. package/src/api/file/file.ref.json +11 -2
  122. package/src/api/object-layer/object-layer.model.js +47 -12
  123. package/src/api/object-layer/object-layer.router.js +10 -3
  124. package/src/api/object-layer/object-layer.service.js +113 -120
  125. package/src/cli/app.js +12 -1
  126. package/src/cli/client.js +2 -2
  127. package/src/cli/cluster.js +80 -18
  128. package/src/cli/deploy.js +215 -34
  129. package/src/cli/docker-compose.js +1 -1
  130. package/src/cli/fs-selection.js +115 -0
  131. package/src/cli/fs.js +158 -342
  132. package/src/cli/index.js +22 -10
  133. package/src/cli/release.js +3 -1
  134. package/src/cli/repository.js +35 -9
  135. package/src/cli/run.js +80 -199
  136. package/src/cli/test.js +4 -0
  137. package/src/cli/wireguard.js +32 -31
  138. package/src/client/components/core/Badge.js +0 -1
  139. package/src/client/components/core/CssCore.js +8 -1
  140. package/src/client/components/core/Docs.js +77 -100
  141. package/src/client/components/core/Modal.js +77 -23
  142. package/src/client/components/core/ToolTip.js +15 -0
  143. package/src/client/components/cryptokoyn/AppShellCryptokoyn.js +0 -2
  144. package/src/client/components/cyberia/ActionEngineCyberia.js +12 -36
  145. package/src/client/components/cyberia/EntityEngineCyberia.js +492 -121
  146. package/src/client/components/cyberia/InstanceEngineCyberia.js +129 -160
  147. package/src/client/components/cyberia/InstanceSelectionView.js +7 -1
  148. package/src/client/components/cyberia/MapEngineCyberia.js +175 -69
  149. package/src/client/components/cyberia/ObjectLayerEngine.js +1011 -97
  150. package/src/client/components/cyberia/ObjectLayerEngineModal.js +81 -155
  151. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +113 -98
  152. package/src/client/components/cyberia/SharedDefaultsCyberia.js +215 -56
  153. package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +0 -34
  154. package/src/client/components/cyberia-portal/CssCyberiaPortal.js +1 -1
  155. package/src/client/components/cyberia-portal/MainBodyCyberiaPortal.js +712 -76
  156. package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +0 -4
  157. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +0 -4
  158. package/src/client/components/default/AppShellDefault.js +1 -4
  159. package/src/client/components/itemledger/AppShellItemledger.js +0 -2
  160. package/src/client/components/underpost/AppShellUnderpost.js +1 -1
  161. package/src/client/public/cyberia-docs/ARCHITECTURE.md +15 -15
  162. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +280 -24
  163. package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +51 -29
  164. package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +52 -53
  165. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +16 -11
  166. package/src/client/public/cyberia-docs/CYBERIA.md +28 -28
  167. package/src/client/public/cyberia-docs/ENTITY-PROFILE.md +11 -5
  168. package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
  169. package/src/client/public/cyberia-docs/STATS-PROGRESSION.md +217 -0
  170. package/src/client/public/cyberia-docs/WHITE-PAPER.md +20 -12
  171. package/src/client/services/cyberia-audio/cyberia-audio.service.js +99 -0
  172. package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +38 -0
  173. package/src/client/services/cyberia-instance/cyberia-instance.management.js +5 -4
  174. package/src/client/services/cyberia-instance/cyberia-instance.service.js +0 -40
  175. package/src/client/services/cyberia-map/cyberia-map.management.js +5 -4
  176. package/src/client/services/cyberia-map-audio-conf/cyberia-map-audio-conf.service.js +138 -0
  177. package/src/client/services/object-layer/object-layer.management.js +6 -10
  178. package/src/client/services/object-layer/object-layer.service.js +3 -1
  179. package/src/client/ssr/views/Cyberia404.js +3 -3
  180. package/src/client-builder/client-build-docs.js +52 -52
  181. package/src/client-builder/client-build.js +67 -44
  182. package/src/client-builder/client-bundle.js +347 -0
  183. package/src/db/mongo/MongoExpress.js +187 -0
  184. package/src/grpc/cyberia/grpc-server.js +5 -7
  185. package/src/index.js +1 -1
  186. package/src/projects/cyberia/atlas-sprite-sheet-generator.js +143 -146
  187. package/src/projects/cyberia/atlas-sprite-sheet-store.js +391 -0
  188. package/src/projects/cyberia/besu-genesis-generator.js +5 -14
  189. package/src/projects/cyberia/boot-contract-fixtures.js +32 -0
  190. package/src/projects/cyberia/catalog-cyberia.js +3 -2
  191. package/src/projects/cyberia/gemini-client.js +3 -3
  192. package/src/projects/cyberia/generate-saga.js +4 -11
  193. package/src/projects/cyberia/hot-reload-trigger.js +17 -28
  194. package/src/projects/cyberia/instance-backup.js +210 -0
  195. package/src/projects/cyberia/instance-data.js +177 -257
  196. package/src/projects/cyberia/map-preview-generator.js +32 -68
  197. package/src/projects/cyberia/object-layer.js +152 -319
  198. package/src/projects/cyberia/seed-audio.js +139 -0
  199. package/src/projects/cyberia/semantic-layer-generator-skin.js +2 -8
  200. package/src/projects/cyberia/semantic-layer-generator.js +2 -18
  201. package/src/projects/cyberia/stat-balance.js +81 -0
  202. package/src/projects/cyberia/stat-commands.js +23 -0
  203. package/src/projects/cyberia/stat-contract-generator.js +101 -0
  204. package/src/runtime/cyberia-client/Dockerfile +8 -4
  205. package/src/runtime/cyberia-client/Dockerfile.dev +5 -2
  206. package/src/runtime/cyberia-server/Dockerfile +9 -2
  207. package/src/runtime/cyberia-server/Dockerfile.dev +8 -1
  208. package/src/runtime/engine-cyberia/Dockerfile +1 -1
  209. package/src/runtime/engine-cyberia/Dockerfile.dev +1 -1
  210. package/src/runtime/engine-cyberia/Dockerfile.test +2 -2
  211. package/src/runtime/engine-cyberia/compose.env +17 -5
  212. package/src/runtime/engine-cyberia/docker-compose.yml +23 -17
  213. package/src/server/build/coverage.js +113 -42
  214. package/src/server/build/package.js +55 -12
  215. package/src/server/build/testing.js +59 -9
  216. package/src/server/network/middlewares.js +8 -2
  217. package/src/server/network/underpost-gateway.js +113 -14
  218. package/src/server/ops/logger.js +70 -35
  219. package/src/server/runtime/conf.js +40 -9
  220. package/src/server/runtime/start.js +11 -2
  221. package/src/server/storage/data-query.js +16 -0
  222. package/src/server/storage/downloader.js +62 -14
  223. package/src/server/storage/zip.js +153 -0
  224. package/test/integration/app/cyberia/atlas-sprite-sheet-store.test.js +402 -0
  225. package/test/integration/app/cyberia/atlas-sprite-sheet.test.js +86 -0
  226. package/test/integration/app/cyberia/cyberia-cli-plain-reads.test.js +34 -0
  227. package/test/integration/app/cyberia/cyberia-entity-type-default.test.js +842 -0
  228. package/test/integration/app/cyberia/cyberia-instance-conf-coerce.test.js +53 -0
  229. package/test/integration/app/cyberia/cyberia-instance-conf-defaults.test.js +16 -22
  230. package/test/integration/app/cyberia/cyberia-instance-items.test.js +90 -0
  231. package/test/integration/app/cyberia/cyberia-load.test.js +6 -7
  232. package/test/integration/app/cyberia/cyberia-map-audio-conf.test.js +256 -0
  233. package/test/integration/app/cyberia/cyberia-stats.test.js +150 -0
  234. package/test/integration/app/cyberia/fallback-world-capture.test.js +87 -2
  235. package/test/integration/app/cyberia/object-layer-item-selection.test.js +56 -0
  236. package/test/integration/app/cyberia/object-layer-natural-key.test.js +32 -0
  237. package/test/integration/app/cyberia/seed-audio.test.js +275 -0
  238. package/test/integration/infra/2-network/wireguard-cli.test.js +33 -9
  239. package/test/integration/infra/2-network/wireguard-edge.test.js +58 -18
  240. package/test/integration/infra/3-cluster/mongo-express-deploy.test.js +156 -0
  241. package/test/integration/infra/4-ingress/api-cross-origin.test.js +79 -0
  242. package/test/integration/infra/4-ingress/underpost-ingress.test.js +1 -1
  243. package/test/unit/catalog.test.js +13 -2
  244. package/test/unit/client-build-docs.test.js +97 -70
  245. package/test/unit/client-bundle.test.js +313 -0
  246. package/test/unit/conf-resolution.test.js +58 -7
  247. package/test/unit/coverage-artifact.test.js +120 -29
  248. package/test/unit/cyberia/instance-backup.test.js +183 -0
  249. package/test/unit/cyberia/instance-data.test.js +314 -0
  250. package/test/unit/cyberia/instance-object-layer-items.test.js +46 -0
  251. package/test/unit/cyberia/publish-workflow.test.js +22 -0
  252. package/test/unit/cyberia/stat-balance.test.js +69 -0
  253. package/test/unit/deploy-legacy-gateway-sweep.test.js +63 -0
  254. package/test/unit/deploy-log-table.test.js +76 -5
  255. package/test/unit/downloader-integrity.test.js +98 -0
  256. package/test/unit/file-reference-registry.test.js +141 -0
  257. package/test/unit/fs-storage-paths.test.js +596 -0
  258. package/test/unit/gateway-pod-fetch.test.js +95 -0
  259. package/test/unit/letsencrypt-issuer.test.js +101 -0
  260. package/test/unit/logger-redaction.test.js +29 -0
  261. package/test/unit/package.test.js +70 -16
  262. package/test/unit/prepare-host.test.js +84 -1
  263. package/test/unit/release-bump.test.js +3 -1
  264. package/test/unit/start-options.test.js +12 -0
  265. package/test/unit/test-tiers.test.js +27 -0
  266. package/test/unit/zip-archive.test.js +142 -0
  267. package/vitest.config.js +11 -3
  268. package/src/api/cyberia-instance/cyberia-fallback-default-items.js +0 -63
  269. package/src/client/components/cyberia/FallbackWorldEngineCyberia.js +0 -368
@@ -56,10 +56,6 @@ class RouterCyberiaPortal {
56
56
  title: 'cyberia-entity-engine',
57
57
  render: () => s(`.main-btn-cyberia-entity-engine`).click(),
58
58
  },
59
- '/fallback-world-engine': {
60
- title: 'fallback-world-engine',
61
- render: () => s(`.main-btn-fallback-world-engine`).click(),
62
- },
63
59
  '/instance-selection': {
64
60
  title: 'instance-selection',
65
61
  render: () => s(`.main-btn-instance-selection`).click(),
@@ -30,10 +30,6 @@ class TranslateCyberiaPortal {
30
30
  en: 'Cyberia Entity Engine',
31
31
  es: 'Cyberia Entity Engine',
32
32
  };
33
- Translate.Data['fallback-world-engine'] = {
34
- en: 'Fallback World Engine',
35
- es: 'Fallback World Engine',
36
- };
37
33
  Translate.Data['instance-selection'] = {
38
34
  en: 'Select World',
39
35
  es: 'Seleccionar Mundo',
@@ -31,8 +31,6 @@ class AppShellDefault {
31
31
  const RouterInstance = RouterDefault.instance();
32
32
 
33
33
  const { barConfig } = await Themes[Css.currentTheme]();
34
-
35
- const badgeNotificationMenuStyle = { top: '-33px', left: '24px' };
36
34
  const barMode = undefined; // 'top-bottom-bar';
37
35
  await Modal.instance({
38
36
  id: 'modal-menu',
@@ -197,8 +195,7 @@ class AppShellDefault {
197
195
  ${await Badge.instance({
198
196
  id: 'main-btn-chat',
199
197
  type: 'circle-red',
200
- style: badgeNotificationMenuStyle,
201
- classList: 'hide',
198
+ classList: 'hide badge-notification-menu',
202
199
  })}`,
203
200
  attrs: `data-id="chat"`,
204
201
  tabHref: `${getProxyPath()}chat`,
@@ -27,8 +27,6 @@ class AppShellItemledger {
27
27
  const RouterInstance = RouterItemledger.instance();
28
28
 
29
29
  const { barConfig } = await Themes[Css.currentTheme]();
30
-
31
- const badgeNotificationMenuStyle = { top: '-33px', left: '24px' };
32
30
  const barMode = undefined; // 'top-bottom-bar';
33
31
  await Modal.instance({
34
32
  id: 'modal-menu',
@@ -227,7 +227,7 @@ class AppShellUnderpost {
227
227
  titleRender: () => {
228
228
  return '';
229
229
  },
230
- mode: 'slide-menu',
230
+ mode: 'slide-menu-right',
231
231
  RouterInstance,
232
232
  searchCustomImgClass: 'underpost-menu-icon',
233
233
  htmlMainBody: async () => {
@@ -9,8 +9,8 @@ Underpost Platform provides the toolchain, deployment surface, PWA delivery, and
9
9
  ## Process model
10
10
 
11
11
  ```
12
- ┌─────────────────────────────────────────────────────────────────────────┐
13
- │ UNDERPOST PLATFORM (infra · toolchain · deploy · PWA/Workbox)
12
+ ┌──────────────────────────────────────────────────────────────────────────┐
13
+ │ UNDERPOST PLATFORM (infra · toolchain · deploy · PWA/Workbox)
14
14
  │ │
15
15
  │ ┌─────────────────────┐ │
16
16
  │ │ Persistent backend │ ← Cyberia content authority + asset backend │
@@ -38,9 +38,9 @@ Underpost Platform provides the toolchain, deployment surface, PWA delivery, and
38
38
  │ └─────────────────────┘ │
39
39
  │ │ │
40
40
  │ │ REST (atlas frames, asset metadata, client hints, │
41
- │ │ instance-map static presence + capability activity)
41
+ │ │ instance-map static presence + capability activity)
42
42
  │ └──→ engine-cyberia │
43
- └─────────────────────────────────────────────────────────────────────────┘
43
+ └──────────────────────────────────────────────────────────────────────────┘
44
44
  ```
45
45
 
46
46
  Three processes, strict role separation. The ecosystem is fully operational only when all three are running and healthy at the same time.
@@ -62,7 +62,7 @@ What it owns:
62
62
  - gRPC `CyberiaDataService` for world load and content streaming.
63
63
  - REST boot fallback (`/api/cyberia-instance/boot/*`): the same world-load / hot-reload payloads as the gRPC service, served over REST for deploys where the engine gRPC server is not enabled.
64
64
  - REST APIs for assets and the optional client-hints overrides.
65
- - Instance Map REST (`/api/cyberia-instance/instance-map/:code/{static,dynamic}`): static map topology plus authored presence POIs, `sumStatsLimit`-capped baseline ObjectLayer stat sums, and capability membership; the dynamic response supplies only per-player capability activity. Never live positions or simulation stats — those stay client-side.
65
+ - Instance Map REST (`/api/cyberia-instance/instance-map/:code/{static,dynamic}`): static map topology plus authored presence POIs, and capability membership; the dynamic response supplies only per-player capability activity. Never live positions or simulation stats — those stay client-side.
66
66
  - Static content distribution + Cloudinary-backed asset flow.
67
67
  - Editor and CLI integration for content workflows.
68
68
 
@@ -125,7 +125,7 @@ The three processes are supervised independently. Each service owns its own moni
125
125
 
126
126
  Dependency between services is handled by supervision and reconnect loops:
127
127
 
128
- - `cyberia-server` dials `engine-cyberia` gRPC at boot; on dial or load failure it retries over the REST boot fallback (`ENGINE_API_BASE_URL`, `/api/cyberia-instance/boot/*`) and exits only when both transports fail rather than fabricate a world. On reconnect, it reloads world configuration.
128
+ - `cyberia-server` dials `engine-cyberia` gRPC at boot; on dial or load failure it retries over the REST boot fallback (`--data-server-url`, `/api/cyberia-instance/boot/*`) and exits only when both transports fail rather than fabricate a world. On reconnect, it reloads world configuration.
129
129
  - `cyberia-client` reconnects to `cyberia-server` over WebSocket and re-fetches content from `engine-cyberia` over REST independently.
130
130
  - If any one of the three services goes unhealthy, the game moves to standby until all three recover.
131
131
 
@@ -238,18 +238,18 @@ WS frame (binary) → decode → typed InputCommand{kind, clientTick, sequen
238
238
 
239
239
  `InputCommand.Sequence` is monotonic per client. Every snapshot carries two acknowledgements of it, and they are not interchangeable:
240
240
 
241
- | Field | Meaning | Client use |
242
- | --------- | ------------------------------------------------------------- | -------------------------------------------------------------------------------- |
243
- | `ack` | Highest sequence **received** for this player. | Retires commands from the prediction buffer. |
244
- | `moveAck` | Highest `PlayerAction` sequence that **re-planned movement**. | Gates adoption of the authoritative `targetPos` / `path`. |
241
+ | Field | Meaning | Client use |
242
+ | --------- | ------------------------------------------------------------- | --------------------------------------------------------- |
243
+ | `ack` | Highest sequence **received** for this player. | Retires commands from the prediction buffer. |
244
+ | `moveAck` | Highest `PlayerAction` sequence that **re-planned movement**. | Gates adoption of the authoritative `targetPos` / `path`. |
245
245
 
246
- **Movement re-plans once per player per tick, and nothing else throttles it.** Handlers record the tap's destination; `phaseInput` runs one A* per player after the queue is drained. Taps that land in the same tick describe the same instant, so only the newest is planned — the rest were superseded before they could mean anything. That coalescing is the only bound on pathfinder cost.
246
+ **Movement re-plans once per player per tick, and nothing else throttles it.** Handlers record the tap's destination; `phaseInput` runs one A\* per player after the queue is drained. Taps that land in the same tick describe the same instant, so only the newest is planned — the rest were superseded before they could mean anything. That coalescing is the only bound on pathfinder cost.
247
247
 
248
248
  This is why the two acknowledgements diverge: a superseded tap is acked on arrival and never planned, so `self.path` and `self.targetPos` can still describe an earlier command. A client that adopted the route on `ack` alone would turn back toward the abandoned target — worst during rapid changes of direction, where it reads as input lag and as a walk that sets off the wrong way.
249
249
 
250
250
  Skills are not coalesced: they fire on every accepted tap, so the uplink carries every tap and the inbound rate limiter (`DefaultMessageRate`, 30/s) is what bounds the stream.
251
251
 
252
- The client predicts every tap immediately and never waits on a cadence. `self.actionCooldownMs` is the skill-trigger period only; keyboard steering paces its *refresh* by it, while a change of heading emits at once.
252
+ The client predicts every tap immediately and never waits on a cadence. `self.actionCooldownMs` is the skill-trigger period only; keyboard steering paces its _refresh_ by it, while a change of heading emits at once.
253
253
 
254
254
  ---
255
255
 
@@ -284,8 +284,8 @@ Every Cyberia document uses the same terms. Aliases are not permitted.
284
284
  | **tick rate** | Simulation Hz on `cyberia-server`. |
285
285
  | **snapshot** | AOI-filtered world view at one tick for one player. |
286
286
  | **prediction** | Optimistic local apply of input commands to the predicted self entity. |
287
- | **reconciliation** | Correct prediction by the error measured at one tick: authoritative position minus the position predicted for that tick. Input is a destination, not a per-tick impulse, so the client keeps walking toward the `targetPos` that `moveAck` confirms, rather than replaying a command log. |
288
- | **move coalescing** | One movement re-plan per player per tick, from the newest tap of that tick. The only bound on pathfinder cost, and the reason `moveAck` trails `ack`. |
287
+ | **reconciliation** | Correct prediction by the error measured at one tick: authoritative position minus the position predicted for that tick. Input is a destination, not a per-tick impulse, so the client keeps walking toward the `targetPos` that `moveAck` confirms, rather than replaying a command log. |
288
+ | **move coalescing** | One movement re-plan per player per tick, from the newest tap of that tick. The only bound on pathfinder cost, and the reason `moveAck` trails `ack`. |
289
289
  | **display smoothing** | Per-render-frame exponential lerp from the discrete predicted self position to a continuous on-screen position. Decouples the visible main player from sim-tick boundaries. |
290
290
  | **interpolation** | Render-time smoothing of remote entities, sampled from snapshot history. |
291
291
  | **authoritative server** | `cyberia-server`. Sole authority on world state. |
@@ -295,7 +295,7 @@ Every Cyberia document uses the same terms. Aliases are not permitted.
295
295
  | **presentation metadata** | Render-only data. Client-owned. |
296
296
  | **input command** | Typed client→server frame with kind, clientTick, sequence, payload. |
297
297
  | **AOI** | Area of interest — the spatial filter that defines which entities a given player receives. |
298
- | **Instance Map** | Client strategic overlay of packed map tiles and authored presence POIs. The static REST response supplies topology, presence, baseline ObjectLayer stat sums, and capability membership; the dynamic response supplies per-player capability activity. Live player presence and stats remain client-side. |
298
+ | **Instance Map** | Client strategic overlay of packed map tiles and authored presence POIs. The static REST response supplies topology, presence, and capability membership; the dynamic response supplies per-player capability activity. Live player presence and stats remain client-side. |
299
299
  | **replication** | Production and delivery of snapshots from server to clients. |
300
300
  | **simulation phase** | A named step inside one simulation tick. |
301
301
  | **healthy** | All three Cyberia services up and connected; game is playable. |
@@ -35,28 +35,38 @@ Import PNG assets, generate procedural layers, build atlas sprite sheets, push t
35
35
  cyberia ol [item-id] [options]
36
36
  ```
37
37
 
38
- | Option | Description |
39
- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------ |
40
- | `--import` | Import specific item-id(s), comma-separated, from the asset directory |
41
- | `--import-types [types]` | Batch import by type (e.g. `skin,floors`) or `all` |
42
- | `--generate` | Generate procedural layers from a semantic item-id (e.g. `floor-desert`) |
43
- | `--count <n>` / `--density <0..1>` | Shape count multiplier (default `3`) / density (default `0.5`) |
44
- | `--seed <seed>` | Deterministic seed for `--generate` (e.g. `fx-42`) |
45
- | `--frame-index <n>` / `--frame-count <n>` | Start frame (default `0`) / frame count (default `1`) |
46
- | `--to-atlas-sprite-sheet [dim]` | Build a consolidated atlas PNG for the item |
47
- | `--show-frame [dir_frame]` | View one frame (e.g. `08_0`; default `08_0`) |
48
- | `--show-atlas-sprite-sheet` | Display the atlas PNG for the item |
49
- | `--drop` | Drop existing data before importing (or standalone) |
50
- | `--client-public` / `--git-clean` | With `--drop`: also remove static asset folders / run clean |
51
- | `--env-path <path>` · `--mongo-host <host>` · `--dev` · `--storage-file-path <path>` | env / DB / dev / filter overrides |
38
+ | Option | Description |
39
+ | ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- |
40
+ | `--import` | Import specific item-id(s), comma-separated; needs one source below |
41
+ | `--instance <code>` | Source `--import` from that instance backup under `engine-private` |
42
+ | `--from-directory` | Source `--import` / `--import-types` from the asset directory |
43
+ | `--import-types [types]` | Batch import by type (e.g. `skin,floors`) or `all`; needs `--from-directory` |
44
+ | `--generate` | Generate procedural layers from a semantic item-id (e.g. `floor-desert`) |
45
+ | `--count <n>` / `--density <0..1>` | Shape count multiplier (default `3`) / density (default `0.5`) |
46
+ | `--seed <seed>` | Deterministic seed for `--generate` (e.g. `fx-42`) |
47
+ | `--frame-index <n>` / `--frame-count <n>` | Start frame (default `0`) / frame count (default `1`) |
48
+ | `--to-atlas-sprite-sheet [dim]` | Rebuild both atlas renders for the selected items |
49
+ | `--minify` | Refresh the minified render and the idle still; `--instance` narrows it |
50
+ | `--upscale <px-factor>` | Pixels per cell of the human-resolution render; alone, rebuilds it |
51
+ | `--normalize-stats` | Clamp the stats of every layer the action writes to its item type's bounds |
52
+ | `--random-stats` | Regenerate the stats of every layer the action writes at random |
53
+ | `--min-stat <n>` / `--max-stat <n>` | Narrow the range the two flags above may leave (default `-100`/`100`) |
54
+ | `--show-frame [dir_frame]` | View one frame (e.g. `08_0`; default `08_0`) |
55
+ | `--show-atlas-sprite-sheet` | Display the atlas PNG for the item |
56
+ | `--drop` | Drop existing data before importing (or standalone) |
57
+ | `--client-public` / `--git-clean` | With `--drop`: also remove static asset folders / run clean |
58
+ | `--env-path <path>` · `--mongo-host <host>` · `--dev` | env / DB / dev overrides |
52
59
 
53
60
  ```bash
54
- # Import specific items
55
- cyberia ol hatchet,sword --import --env-path ./engine-private/conf/dd-cyberia/.env.development
61
+ # Restore specific items from an instance backup: the backup is the authority for the item
62
+ cyberia ol hatchet,sword --instance FOREST --import
56
63
 
57
- # Batch import by type, or everything
58
- cyberia ol --import-types skin,floors
59
- cyberia ol --import-types all
64
+ # Import specific items from the asset directory
65
+ cyberia ol hatchet,sword --from-directory --import --env-path ./engine-private/conf/dd-cyberia/.env.development
66
+
67
+ # Batch import by type, or everything, from the asset directory
68
+ cyberia ol --from-directory --import-types skin,floors
69
+ cyberia ol --from-directory --import-types all
60
70
 
61
71
  # Procedural generation
62
72
  cyberia ol floor-desert --generate --seed fx-42
@@ -66,16 +76,29 @@ cyberia ol floor-grass --generate --frame-count 4 --count 5 --density 0.7
66
76
  cyberia ol hatchet --to-atlas-sprite-sheet
67
77
  cyberia ol hatchet --show-frame 08_0
68
78
 
79
+ # Rebuild both atlas renders. The scope is an item-id, an instance, or everything.
80
+ cyberia ol hatchet --to-atlas-sprite-sheet --upscale 40
81
+ cyberia ol --instance TEST --upscale 20
82
+ cyberia ol --to-atlas-sprite-sheet
83
+
84
+ # Refresh the minified render the client downloads and the idle still every preview shows
85
+ cyberia ol hatchet --minify
86
+ cyberia ol --minify --instance FOREST
87
+
88
+ # Balance stats on every layer an action writes
89
+ cyberia ol --minify --instance FOREST --normalize-stats
90
+ cyberia ol hatchet --from-directory --import --random-stats --normalize-stats --max-stat 10
91
+
69
92
  # Drop + re-import a single item, including static folders
70
- cyberia ol hatchet --drop --client-public --import
93
+ cyberia ol hatchet --drop --client-public --from-directory --import
71
94
  ```
72
95
 
73
96
  ---
74
97
 
75
98
  ## `cyberia instance` — instance data
76
99
 
77
- Export / import / drop a game instance and its related maps, entities, actions, quests, and object
78
- layers in MongoDB.
100
+ Export / import / drop a game instance and its related maps, entities, actions, quests, object
101
+ layers and map audio in MongoDB.
79
102
 
80
103
  ```bash
81
104
  cyberia instance [instance-code] [options]
@@ -87,6 +110,7 @@ cyberia instance [instance-code] [options]
87
110
  | `--import [path]` | Import from a backup directory (upsert, preserves UUIDs) |
88
111
  | `--conf` | With `--export`/`--import`: only `cyberia-instance.json` + `-conf.json` |
89
112
  | `--drop` | Drop all documents associated with the instance code |
113
+ | `--sync-entities` | Sync the conf's entity-type default references and skill config |
90
114
  | `--export-current-fallbackworld` | Capture the in-memory procedural fallback world, then export it |
91
115
  | `--keep-fallback-codes` | Capture using the raw `fallback-map-*` / canonical action-quest codes |
92
116
  | `--fallback-url <url>` | Capture the world a running engine serves instead of regenerating it |
@@ -98,6 +122,102 @@ cyberia instance FOREST --import ./backups/FOREST
98
122
  cyberia instance FOREST --drop
99
123
  ```
100
124
 
125
+ A backup carries audio too. `cyberia-map-audio-confs/<map-code>.json` holds each map's bindings —
126
+ that configuration belongs to the map, so it travels with the instance and `--drop` removes it with
127
+ the map. The assets those bindings name travel as copies in `cyberia-audio/<code>.json` with their
128
+ WAV beside them in `files/`, because a `CyberiaAudio` document is global: the import upserts it by
129
+ code and leaves other instances' bindings alone, and `--drop` never removes one. A binding whose
130
+ asset is missing is kept as written — the code is the whole reference, so importing the asset later
131
+ is all it takes to make it play.
132
+
133
+ A backup also carries the entity-type defaults the instance's conf **references**, under
134
+ `cyberia-entity-type-defaults/<_id>.json`. `CyberiaInstanceConf.entityDefaults` holds
135
+ `CyberiaEntityTypeDefault` ids, never copies of the documents, and both directions travel by that
136
+ id: the export writes exactly the referenced documents, and the import restores them under their
137
+ original `_id` so the references keep resolving.
138
+
139
+ `--sync-entities` builds those references from the world's own content: a default belongs to the
140
+ instance when all of its `liveItemIds` appear together on some entity the maps place — the same
141
+ subset containment the runtime resolves an entity with. It is additive and idempotent, so a
142
+ hand-linked default that no map places (a player or coin default) is kept, and re-running links
143
+ nothing new. A match another instance already references is **reported, not adopted**: two worlds
144
+ built on the same art hold documents with identical live item ids, so matching alone cannot tell
145
+ them apart, and claiming one stays a deliberate act in the Entity engine.
146
+
147
+ Skills are **derived, never stored**. The `cyberia-skill` collection is deployment-wide and owns
148
+ the definitions; an instance runs the ones whose `triggerItemId` is an item id its own content
149
+ names. That content is four things and no more: what its maps place, what its entity-type defaults
150
+ wire, what its vendor and assembler catalogs trade, and what its quests ask for or pay out. The
151
+ canonical `ENTITY_TYPE_DEFAULTS` count alongside the instance's own, so a world referencing no
152
+ player default still holds `atlas_pistol_mk2` and keeps its projectile skill rather than being
153
+ disarmed.
154
+
155
+ That last source is why `hatchet` belongs to a world whose maps place no hatchet: a quest objective
156
+ or a shop shelf names one, so a player there can come to hold it and fire it. `--sync-entities`
157
+ reports the resolved list, the export writes exactly those documents to
158
+ `cyberia-skills/`, and the boot payload sends exactly those to the simulation — one rule, so the
159
+ three can no longer disagree. Nothing is written to the instance conf, which carries no
160
+ `skillConfig` field: a stored list was a second answer to the same question, and it was the one
161
+ that went stale.
162
+
163
+ The Instance engine has the same action as a button, syncing against the map codes currently
164
+ selected.
165
+
166
+ ```bash
167
+ cyberia instance FOREST --sync-entities --dev
168
+ ```
169
+
170
+ A reference cannot outlive its document. Deleting an entity-type default unlinks it from every
171
+ conf first, and both `--export` and `--import` compact the instance's references — dropping any
172
+ whose document is gone — so a backup never carries a dangling id and restoring one never recreates
173
+ it. Saving a default in the Entity engine compacts the collection too. What is exported is
174
+ therefore exactly what resolves.
175
+
176
+ That reference is what scopes a default to a world. Membership used to be inferred by matching item
177
+ ids, and two instances built on the same art therefore matched each other: exporting one dragged in
178
+ the other's wiring, and importing it overwrote the original by an `(entityType, liveItemIds)`
179
+ "natural key". An id names one document, so neither is possible. A backup written before the change
180
+ still embeds the documents in its conf; importing it converts them to references against the
181
+ documents in that same backup, creating any it cannot find.
182
+
183
+ An instance that references nothing is complete, not empty: it runs on the canonical
184
+ `ENTITY_TYPE_DEFAULTS`, and referenced documents override only the entity types they cover.
185
+
186
+ Those documents are also where a world's starting inventory comes from, and an entity has exactly
187
+ one. It carries the **union** of every id its default names — `liveItemIds`, `deadItemIds`,
188
+ `dropItemIds` and the inventory-only `inventoryItemsIds` — deduplicated. Nothing stores which slots
189
+ are worn: the three lifecycle lists are discriminators, and the runtime activates the ones the
190
+ context calls for, which is why the whole union is seeded (the server activates a slot that is
191
+ already there rather than appending one). Spawn state is alive, so the live ids are the active
192
+ ones; everything else is carried empty, a coin balance included.
193
+
194
+ `overrideItemsIdsState` is the one adjustment to that derivation, per id: `active` forces the spawn
195
+ state — a skin the equipment rules would otherwise leave inactive — `quantity` sizes a stack,
196
+ which is how a drop bundle declares how many tokens it scatters, and `dropChance` (0–1) says how
197
+ often the id actually scatters when the entity dies. It never adds an id; the union decides
198
+ membership, an override only what a member starts as.
199
+
200
+ `dropChance` is meaningful only for an id the build carries in `dropItemIds`; on any other row it is
201
+ inert, and the resolver reports 1 there so the simulation reads one field and never a missing one.
202
+ Saying nothing means 1, which is what every world did before the field existed, and each drop id is
203
+ rolled independently — a build can pair a common drop with a rare one and have both decided on their
204
+ own. A deliberate 0 survives, because the wire field is explicitly optional: absent and zero are
205
+ different answers.
206
+
207
+ `inventoryItemsIds` is therefore only for what no lifecycle state ever activates. The instance holds
208
+ no item list of its own: it names entity-type defaults, and the items follow from them, so there is
209
+ exactly one place to read or change a starting kit.
210
+
211
+ To point a world at the seeded collection, name it:
212
+
213
+ ```bash
214
+ cyberia run-workflow seed-entities --instance FOREST --dev
215
+ ```
216
+
217
+ `seed-entities` upserts `ENTITY_TYPE_DEFAULTS` into the collection; `--instance` then makes that
218
+ instance's conf reference exactly those documents, replacing whatever it referenced before, so
219
+ re-running converges rather than accumulating.
220
+
101
221
  ### Capturing the procedural fallback world
102
222
 
103
223
  The fallback world is never persisted: every engine process rebuilds it from the code defaults at
@@ -105,7 +225,9 @@ boot and serves it whenever a requested instance is absent. `--export-current-fa
105
225
  that in-memory world into MongoDB under a real instance code — maps and portal topology, the
106
226
  instance conf, and the content collections the fallback path serves from code rather than the DB
107
227
  (skills, entity-type defaults, dialogues, actions, quests) — and then exports it like any other
108
- instance.
228
+ instance. It writes each captured map's audio configuration too, under the captured map code,
229
+ binding only the codes an imported `CyberiaAudio` actually carries and reporting the rest: the
230
+ client asks for audio by map code, so a namespaced capture would otherwise play nothing.
109
231
 
110
232
  ```bash
111
233
  # Freeze the current fallback world as PROC-1 and back it up
@@ -119,7 +241,7 @@ Map, action and quest codes are namespaced under the instance code (`fallback-ma
119
241
  `PROC-1-map-0`) so successive captures never overwrite each other; `--keep-fallback-codes` writes
120
242
  the canonical codes verbatim instead. Sprites are the one thing a capture cannot synthesise: when a
121
243
  referenced item id has no `ObjectLayer` document the command aborts and names the ids to import with
122
- `cyberia ol <ids> --import`. Staged fallback default items live only in the serving engine process,
244
+ `cyberia ol <ids> --from-directory --import`. Staged fallback default items live only in the serving engine process,
123
245
  so pass `--fallback-url http://localhost:4001` to capture a live world rather than regenerating it.
124
246
 
125
247
  ---
@@ -148,6 +270,140 @@ cyberia client-hints cyberia-main --export ./client-hints-cyberia-main.json
148
270
 
149
271
  ---
150
272
 
273
+ ## `cyberia audio` — audio assets and map audio
274
+
275
+ Imports recorded [`cyberia-audio`](https://github.com/underpostnet/cyberia-audio) assets into MongoDB and binds
276
+ them to a map. Every recording is a pair — `<name>.wav` and its `<name>.json` manifest — and the pair is the unit
277
+ of import: a WAV with no manifest beside it is skipped. Produce the pair with `cyberia-audio sfx coin` or
278
+ `cyberia-audio music combat`.
279
+
280
+ ```bash
281
+ cyberia audio [audio-code] [options]
282
+ ```
283
+
284
+ | Option | Description |
285
+ | ----------------------------------------------------- | -------------------------------------------------------------------- |
286
+ | `--import` | Import WAV + manifest pairs; all of them when no code is given |
287
+ | `--records-path <path>` | Records directory to import from (default `./cyberia-audio/records`) |
288
+ | `--map <map-code>` | Target `cyberia-map` code to read or configure |
289
+ | `--set-default-music <audio-code>` | Default background music for `--map` |
290
+ | `--set-event <logic-event-id:audio-code>` | Bind an asset to a logic event (e.g. `combat`, `shoot`); repeatable |
291
+ | `--env-path <path>` · `--mongo-host <host>` · `--dev` | env / DB / dev overrides |
292
+
293
+ ```bash
294
+ # Import every recorded asset, or a single one
295
+ cyberia audio --import
296
+ cyberia audio combat --import
297
+
298
+ # Configure a map, then read back what it resolved to
299
+ cyberia audio --map FOREST --set-default-music exploration \
300
+ --set-event projectile:shoot --set-event coin_drop_or_transaction:coin
301
+ cyberia audio --map FOREST
302
+ ```
303
+
304
+ An asset is identified by its `code` alone — `cyberia-audio` stores what a sound _is_ (`code`, `fileId`,
305
+ `manifest`) and never what it is for. `manifest.bus` is the `src/audio-module/<bus-id>/` directory the module
306
+ was authored in — the asset's natural route, recorded as provenance; a map binding decides where it actually
307
+ plays. Configuration lands in `cyberia-map-audio-conf`, one document per map code,
308
+ holding `defaultMusic`, a single `events` list and volume/loop/crossfade `settings`. Each binding is the same
309
+ pattern the skill model uses — a semantic `logicEventId` resolving to an `audioCode`:
310
+
311
+ ```js
312
+ { logicEventId: 'combat', audioCode: 'combat', settings: { bus: 'music', loop: true, crossfadeMs: 800 } }
313
+ { logicEventId: 'hit', audioCode: 'hit' }
314
+ ```
315
+
316
+ `bus` is one vocabulary with one spelling — `music` and `sfx`, declared once in
317
+ `SharedDefaultsCyberia.AUDIO_BUSES`. The same two ids name the `cyberia-audio/src/audio-module/<bus-id>/`
318
+ directory an asset is authored in, the argument `cyberia-audio <bus-id> <id>` dispatches on, the `bus` a
319
+ recorded manifest carries, and the route a binding's `settings.bus` selects.
320
+
321
+ The event vocabulary is centralized the same way: `SharedDefaultsCyberia.AUDIO_LOGIC_IDS` declares the
322
+ events a binding may answer and the bus each one naturally routes to, `cyberia-server-defaults` holds the seed's
323
+ bank (`DEFAULT_AUDIO_BANK`) and its bindings (`DEFAULT_AUDIO_BINDINGS`, expanded by `buildAudioEventBindings`),
324
+ and `cyberia-client/src/audio/audio_events.h` holds the same ids for the emitting side. A binding naming an
325
+ unknown event, or an asset the bank does not carry, throws at import rather than playing silence.
326
+
327
+ The fallback bank binds `projectile`, `coin_drop_or_transaction`, `drop`, `item-pickup`, `victory`, `level-up`,
328
+ `death`, `heal`, `hit`, `portal`, `ui-click` and `footsteps` as one-shots, and `combat`, `boss`, `portal-cooldown` and
329
+ `craft` as music. `victory` is a cue rather than a bed: completing a quest is an event, and holding the
330
+ bus for it would take the map's music away for the length of a flourish. `hit` follows the server's damage events, so it sounds for any entity in view rather than
331
+ only for the player; `level-up` and `death` arrive as server `audio_event` broadcasts, so a level gained or a defeat sounds for every viewer in reach; `ui-click` follows a tap the interface accepted.
332
+
333
+ `item-pickup` fires where every route into the inventory bar converges — world loot flying in, a quest
334
+ reward, a purchase, an assembly output — so one emission covers them all. It is deliberately plainer than
335
+ `coin`, which stays the reward gesture reserved for currency.
336
+
337
+ `craft` is a held bed rather than a cue, the same shape as `portal-cooldown`: it takes over the map's music
338
+ for exactly as long as a recipe's assembly bar charges, loops seamlessly while the player waits, and releases
339
+ back to the map on completion. Both holds are arbitrated in `audio_context.c`, which is also what makes them
340
+ outlive a combat exchange instead of being cut by it — the modal owns the bar and only reports whether one is
341
+ running.
342
+
343
+ Two cues are about the crowd rather than about one event, because sounding them per entity buries the bus.
344
+ `heal` is a milestone: regeneration ticks constantly and in small amounts, so it sounds only when an entity's
345
+ life crosses back above zero, 25%, 50% or 75%, once per snapshot however many entities crossed. `footsteps`
346
+ is a cadence: one gait cycle repeats for as long as anything with feet is walking in view, at one rate for the
347
+ whole scene rather than one per walker.
348
+
349
+ Portal audio follows the authoritative teleport charge, never the map code: `onPortal` holds `portal-cooldown` as
350
+ a bed for as long as the charge runs, and completing it fires the `portal` one-shot while the departing map's
351
+ bindings are still resident. An intra-map portal moves the player without changing maps, so watching the map code
352
+ was silent for exactly that case; stepping off the pad drops the bed without sounding the jump.
353
+
354
+ Whether a binding behaves as a bed, a one-shot or a transition follows from the logic event that fires it and the
355
+ settings it carries, not from a classification stored twice. The code is checked against the imported assets, so
356
+ an unimported one is rejected rather than stored as a dangling name. Bindings merge by `logicEventId`: naming an
357
+ event replaces that binding and leaves the others in place. `--map` on its own prints the current configuration
358
+ and writes nothing.
359
+
360
+ The fallback seed is the exception, and deliberately so: it states a map's complete binding set, so re-running it
361
+ converges. A binding whose logic event the bank no longer declares — a renamed cue, for instance — is dropped and
362
+ logged, instead of surviving as a name the client would keep asking the engine to resolve.
363
+
364
+ `settings.bus` selects `music` or `sfx` on the binding. It does not classify the asset.
365
+ Omitted settings inherit client or map defaults. Supported overrides include volume, loop, crossfadeMs, pitch, pan, and priority.
366
+ Set music event routing through the map configuration API or the fallback seed workflow.
367
+ Changing only an event's audio code preserves its existing settings.
368
+
369
+ Record and seed the complete fallback bank from the engine repository root:
370
+
371
+ ```bash
372
+ cyberia run-workflow seed-audio --records-only
373
+ cyberia run-workflow seed-audio --dev --mongo-host 127.0.0.1
374
+ cyberia run-workflow seed-audio --instance my-instance --dev --mongo-host 127.0.0.1
375
+ ```
376
+
377
+ The first command records thirteen WAV and manifest pairs and touches no database.
378
+ The second also upserts generic File references, CyberiaAudio metadata, and audio configuration for the fallback maps.
379
+ The third configures one instance's maps instead: `--instance <instance-code>` reads that instance's own
380
+ `cyberiaMapCodes` and scores every one of them with the same bank, bindings and default bed the fallback world
381
+ uses, so a world built on that topology sounds the way the fallback world does. Every map falls back to the
382
+ `exploration` bed; what makes a place sound different is the event that fires there. The instance must exist and
383
+ declare at least one map, or the run fails without writing anything.
384
+
385
+ Every form states each map's whole configuration, so re-running converges rather than accumulating: a bed is
386
+ reassigned and a binding the bank no longer declares is dropped.
387
+ It reuses the existing engine environment resolution. Full seeding requires that deployment configuration and MongoDB.
388
+ Use `--records-path` to select the output directory.
389
+ An asset's generic File `_id` is derived from its code and the bytes themselves, so re-importing an unchanged
390
+ bank rewrites nothing, and a changed render lands on a new `fileId` while the blob it replaced is deleted in the
391
+ same step. That is what keeps the client honest: it fetches a WAV as `/api/file/blob/<fileId>` and caches it, so
392
+ new bytes under a reused id would go on playing the old sound. `cyberia-audio.fileId` is registered in
393
+ `src/api/file/file.ref.json`, which is the list `underpost db clean-fs` treats as the complete set of File
394
+ references — a blob no registered field points at is deleted by that sweep. Deleting an asset, through the API or
395
+ by restoring an instance over it, deletes its blob with it. Interrupted imports can be rerun safely.
396
+
397
+ Recording produces nothing for the client to ship: `cyberia-client` bundles no WAV and fetches every asset from
398
+ engine-cyberia by code, so an asset is reachable only once it is seeded.
399
+
400
+ The client resolves `logicEventId → audioCode → fileId → /api/file/blob/:fileId` and caches decoded WAVs.
401
+ Fallback maps use exploration, combat, boss, and exploration music in order.
402
+ Missing remote content uses the generated local bank. Unknown effects become silence.
403
+ Regenerate the local bank before building the client after changing audio content.
404
+
405
+ ---
406
+
151
407
  ## `cyberia chain` — Besu + ObjectLayerToken
152
408
 
153
409
  Hyperledger Besu IBFT2 network and ERC-1155 `ObjectLayerToken` (CKY) lifecycle.