@caperjs/core 0.1.0

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 (600) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +62 -0
  3. package/cli/add.mjs +197 -0
  4. package/cli/audio/cc.mjs +128 -0
  5. package/cli/audio/index.mjs +42 -0
  6. package/cli/audio/utils.mjs +56 -0
  7. package/cli/create-caper.mjs +8 -0
  8. package/cli/create.mjs +351 -0
  9. package/cli/install-peerdeps.mjs +57 -0
  10. package/cli/update.mjs +9 -0
  11. package/cli/utils.mjs +81 -0
  12. package/cli/vite.mjs +55 -0
  13. package/cli/voiceover/generateVoiceoverCSV.mjs +158 -0
  14. package/cli/voiceover/index.mjs +1 -0
  15. package/cli.mjs +157 -0
  16. package/client.d.ts +7 -0
  17. package/config/assetpack.mjs +212 -0
  18. package/config/tsconfig.base.json +28 -0
  19. package/config/vite.mjs +2464 -0
  20. package/extras/css/accessibility.css +9 -0
  21. package/extras/css/fullscreen.css +28 -0
  22. package/extras/css/loader.css +67 -0
  23. package/extras/llms.txt +1602 -0
  24. package/lib/CaptionsPlugin-Dc8fIrjy.js +277 -0
  25. package/lib/CaptionsPlugin-Dc8fIrjy.js.map +1 -0
  26. package/lib/DataAdapter-BY2114sp.js +84 -0
  27. package/lib/DataAdapter-BY2114sp.js.map +1 -0
  28. package/lib/DebugRenderer-BJMLILqI.js +1385 -0
  29. package/lib/DebugRenderer-BJMLILqI.js.map +1 -0
  30. package/lib/DevToolsPlugin-wQ5rOkn0.js +31 -0
  31. package/lib/DevToolsPlugin-wQ5rOkn0.js.map +1 -0
  32. package/lib/GSAPPlugin-DHhSZKv8.js +350 -0
  33. package/lib/GSAPPlugin-DHhSZKv8.js.map +1 -0
  34. package/lib/LayoutPlugin-B-DF9SYM.js +1271 -0
  35. package/lib/LayoutPlugin-B-DF9SYM.js.map +1 -0
  36. package/lib/SpinePlugin-Dz_3dljz.js +6077 -0
  37. package/lib/SpinePlugin-Dz_3dljz.js.map +1 -0
  38. package/lib/StatsPlugin-Cg82JMBD.js +70 -0
  39. package/lib/StatsPlugin-Cg82JMBD.js.map +1 -0
  40. package/lib/VoiceOverPlugin-BR3ImT8C.js +114 -0
  41. package/lib/VoiceOverPlugin-BR3ImT8C.js.map +1 -0
  42. package/lib/caper.mjs +1233 -0
  43. package/lib/caper.mjs.map +1 -0
  44. package/lib/core/Application.d.ts +268 -0
  45. package/lib/core/Application.d.ts.map +1 -0
  46. package/lib/core/config.d.ts +39 -0
  47. package/lib/core/config.d.ts.map +1 -0
  48. package/lib/core/create.d.ts +41 -0
  49. package/lib/core/create.d.ts.map +1 -0
  50. package/lib/core/globals.d.ts +51 -0
  51. package/lib/core/globals.d.ts.map +1 -0
  52. package/lib/core/index.d.ts +7 -0
  53. package/lib/core/index.d.ts.map +1 -0
  54. package/lib/core/interfaces/IApplication.d.ts +566 -0
  55. package/lib/core/interfaces/IApplication.d.ts.map +1 -0
  56. package/lib/core/interfaces/IApplicationOptions.d.ts +65 -0
  57. package/lib/core/interfaces/IApplicationOptions.d.ts.map +1 -0
  58. package/lib/core/interfaces/ICoreFunctions.d.ts +49 -0
  59. package/lib/core/interfaces/ICoreFunctions.d.ts.map +1 -0
  60. package/lib/core/interfaces/ICoreSignals.d.ts +57 -0
  61. package/lib/core/interfaces/ICoreSignals.d.ts.map +1 -0
  62. package/lib/core/interfaces/IStorageCapability.d.ts +20 -0
  63. package/lib/core/interfaces/IStorageCapability.d.ts.map +1 -0
  64. package/lib/core/interfaces/IStorageCapability.test.d.ts +2 -0
  65. package/lib/core/interfaces/IStorageCapability.test.d.ts.map +1 -0
  66. package/lib/core/interfaces/index.d.ts +7 -0
  67. package/lib/core/interfaces/index.d.ts.map +1 -0
  68. package/lib/core/registries.d.ts +8 -0
  69. package/lib/core/registries.d.ts.map +1 -0
  70. package/lib/core/types.d.ts +12 -0
  71. package/lib/core/types.d.ts.map +1 -0
  72. package/lib/display/AnimatedSprite.d.ts +40 -0
  73. package/lib/display/AnimatedSprite.d.ts.map +1 -0
  74. package/lib/display/Camera.d.ts +102 -0
  75. package/lib/display/Camera.d.ts.map +1 -0
  76. package/lib/display/Container.d.ts +115 -0
  77. package/lib/display/Container.d.ts.map +1 -0
  78. package/lib/display/Entity.d.ts +46 -0
  79. package/lib/display/Entity.d.ts.map +1 -0
  80. package/lib/display/ParticleContainer.d.ts +58 -0
  81. package/lib/display/ParticleContainer.d.ts.map +1 -0
  82. package/lib/display/Scene.d.ts +250 -0
  83. package/lib/display/Scene.d.ts.map +1 -0
  84. package/lib/display/SceneTransition.d.ts +41 -0
  85. package/lib/display/SceneTransition.d.ts.map +1 -0
  86. package/lib/display/SpineAnimation.d.ts +76 -0
  87. package/lib/display/SpineAnimation.d.ts.map +1 -0
  88. package/lib/display/Svg.d.ts +5 -0
  89. package/lib/display/Svg.d.ts.map +1 -0
  90. package/lib/display/index.d.ts +10 -0
  91. package/lib/display/index.d.ts.map +1 -0
  92. package/lib/env.d.ts +6 -0
  93. package/lib/hello.d.ts +2 -0
  94. package/lib/hello.d.ts.map +1 -0
  95. package/lib/index.d.ts +15 -0
  96. package/lib/index.d.ts.map +1 -0
  97. package/lib/mixins/animated.d.ts +53 -0
  98. package/lib/mixins/animated.d.ts.map +1 -0
  99. package/lib/mixins/factory/Factory.d.ts +8 -0
  100. package/lib/mixins/factory/Factory.d.ts.map +1 -0
  101. package/lib/mixins/factory/const.d.ts +67 -0
  102. package/lib/mixins/factory/const.d.ts.map +1 -0
  103. package/lib/mixins/factory/index.d.ts +8 -0
  104. package/lib/mixins/factory/index.d.ts.map +1 -0
  105. package/lib/mixins/factory/methods.d.ts +3 -0
  106. package/lib/mixins/factory/methods.d.ts.map +1 -0
  107. package/lib/mixins/factory/props.d.ts +160 -0
  108. package/lib/mixins/factory/props.d.ts.map +1 -0
  109. package/lib/mixins/factory/registry.d.ts +27 -0
  110. package/lib/mixins/factory/registry.d.ts.map +1 -0
  111. package/lib/mixins/factory/registry.test.d.ts +2 -0
  112. package/lib/mixins/factory/registry.test.d.ts.map +1 -0
  113. package/lib/mixins/factory/schema.d.ts +71 -0
  114. package/lib/mixins/factory/schema.d.ts.map +1 -0
  115. package/lib/mixins/factory/ui-registry.d.ts +20 -0
  116. package/lib/mixins/factory/ui-registry.d.ts.map +1 -0
  117. package/lib/mixins/factory/utils.d.ts +11 -0
  118. package/lib/mixins/factory/utils.d.ts.map +1 -0
  119. package/lib/mixins/focus.d.ts +15 -0
  120. package/lib/mixins/focus.d.ts.map +1 -0
  121. package/lib/mixins/index.d.ts +6 -0
  122. package/lib/mixins/index.d.ts.map +1 -0
  123. package/lib/mixins/interaction.d.ts +20 -0
  124. package/lib/mixins/interaction.d.ts.map +1 -0
  125. package/lib/mixins/signals.d.ts +15 -0
  126. package/lib/mixins/signals.d.ts.map +1 -0
  127. package/lib/plugins/AssetsPlugin.d.ts +79 -0
  128. package/lib/plugins/AssetsPlugin.d.ts.map +1 -0
  129. package/lib/plugins/DataAdapter.d.ts +95 -0
  130. package/lib/plugins/DataAdapter.d.ts.map +1 -0
  131. package/lib/plugins/DevToolsPlugin.d.ts +97 -0
  132. package/lib/plugins/DevToolsPlugin.d.ts.map +1 -0
  133. package/lib/plugins/FullScreenPlugin.d.ts +240 -0
  134. package/lib/plugins/FullScreenPlugin.d.ts.map +1 -0
  135. package/lib/plugins/GSAPPlugin.d.ts +634 -0
  136. package/lib/plugins/GSAPPlugin.d.ts.map +1 -0
  137. package/lib/plugins/KeyboardPlugin.d.ts +53 -0
  138. package/lib/plugins/KeyboardPlugin.d.ts.map +1 -0
  139. package/lib/plugins/LayoutPlugin.d.ts +100 -0
  140. package/lib/plugins/LayoutPlugin.d.ts.map +1 -0
  141. package/lib/plugins/LookupPlugin.d.ts +223 -0
  142. package/lib/plugins/LookupPlugin.d.ts.map +1 -0
  143. package/lib/plugins/Plugin.d.ts +132 -0
  144. package/lib/plugins/Plugin.d.ts.map +1 -0
  145. package/lib/plugins/Plugin.test.d.ts +2 -0
  146. package/lib/plugins/Plugin.test.d.ts.map +1 -0
  147. package/lib/plugins/PopupManagerPlugin.d.ts +108 -0
  148. package/lib/plugins/PopupManagerPlugin.d.ts.map +1 -0
  149. package/lib/plugins/ResizerPlugin.d.ts +62 -0
  150. package/lib/plugins/ResizerPlugin.d.ts.map +1 -0
  151. package/lib/plugins/SceneManagerPlugin.d.ts +122 -0
  152. package/lib/plugins/SceneManagerPlugin.d.ts.map +1 -0
  153. package/lib/plugins/StatsPlugin.d.ts +8 -0
  154. package/lib/plugins/StatsPlugin.d.ts.map +1 -0
  155. package/lib/plugins/TimerPlugin.d.ts +401 -0
  156. package/lib/plugins/TimerPlugin.d.ts.map +1 -0
  157. package/lib/plugins/WebEventsPlugin.d.ts +60 -0
  158. package/lib/plugins/WebEventsPlugin.d.ts.map +1 -0
  159. package/lib/plugins/actions/ActionsPlugin.d.ts +39 -0
  160. package/lib/plugins/actions/ActionsPlugin.d.ts.map +1 -0
  161. package/lib/plugins/actions/constants.d.ts +52 -0
  162. package/lib/plugins/actions/constants.d.ts.map +1 -0
  163. package/lib/plugins/actions/index.d.ts +5 -0
  164. package/lib/plugins/actions/index.d.ts.map +1 -0
  165. package/lib/plugins/actions/methods.d.ts +11 -0
  166. package/lib/plugins/actions/methods.d.ts.map +1 -0
  167. package/lib/plugins/actions/types.d.ts +25 -0
  168. package/lib/plugins/actions/types.d.ts.map +1 -0
  169. package/lib/plugins/audio/AudioChannel.d.ts +46 -0
  170. package/lib/plugins/audio/AudioChannel.d.ts.map +1 -0
  171. package/lib/plugins/audio/AudioChannel.test.d.ts +2 -0
  172. package/lib/plugins/audio/AudioChannel.test.d.ts.map +1 -0
  173. package/lib/plugins/audio/AudioInstance.d.ts +79 -0
  174. package/lib/plugins/audio/AudioInstance.d.ts.map +1 -0
  175. package/lib/plugins/audio/AudioManagerPlugin.d.ts +323 -0
  176. package/lib/plugins/audio/AudioManagerPlugin.d.ts.map +1 -0
  177. package/lib/plugins/audio/VoiceOverPlugin.d.ts +69 -0
  178. package/lib/plugins/audio/VoiceOverPlugin.d.ts.map +1 -0
  179. package/lib/plugins/audio/index.d.ts +4 -0
  180. package/lib/plugins/audio/index.d.ts.map +1 -0
  181. package/lib/plugins/breakpoints/BreakpointPlugin.d.ts +109 -0
  182. package/lib/plugins/breakpoints/BreakpointPlugin.d.ts.map +1 -0
  183. package/lib/plugins/breakpoints/BreakpointPlugin.test.d.ts +2 -0
  184. package/lib/plugins/breakpoints/BreakpointPlugin.test.d.ts.map +1 -0
  185. package/lib/plugins/breakpoints/evaluate.d.ts +53 -0
  186. package/lib/plugins/breakpoints/evaluate.d.ts.map +1 -0
  187. package/lib/plugins/breakpoints/evaluate.test.d.ts +2 -0
  188. package/lib/plugins/breakpoints/evaluate.test.d.ts.map +1 -0
  189. package/lib/plugins/breakpoints/index.d.ts +4 -0
  190. package/lib/plugins/breakpoints/index.d.ts.map +1 -0
  191. package/lib/plugins/breakpoints/methods.d.ts +23 -0
  192. package/lib/plugins/breakpoints/methods.d.ts.map +1 -0
  193. package/lib/plugins/breakpoints/types.d.ts +70 -0
  194. package/lib/plugins/breakpoints/types.d.ts.map +1 -0
  195. package/lib/plugins/captions/CaptionsPlugin.d.ts +150 -0
  196. package/lib/plugins/captions/CaptionsPlugin.d.ts.map +1 -0
  197. package/lib/plugins/captions/CaptionsRenderer.d.ts +37 -0
  198. package/lib/plugins/captions/CaptionsRenderer.d.ts.map +1 -0
  199. package/lib/plugins/captions/index.d.ts +3 -0
  200. package/lib/plugins/captions/index.d.ts.map +1 -0
  201. package/lib/plugins/defaults.d.ts +4 -0
  202. package/lib/plugins/defaults.d.ts.map +1 -0
  203. package/lib/plugins/focus/FocusManagerPlugin.d.ts +148 -0
  204. package/lib/plugins/focus/FocusManagerPlugin.d.ts.map +1 -0
  205. package/lib/plugins/focus/FocusOutliner.d.ts +32 -0
  206. package/lib/plugins/focus/FocusOutliner.d.ts.map +1 -0
  207. package/lib/plugins/focus/index.d.ts +3 -0
  208. package/lib/plugins/focus/index.d.ts.map +1 -0
  209. package/lib/plugins/i18nPlugin.d.ts +128 -0
  210. package/lib/plugins/i18nPlugin.d.ts.map +1 -0
  211. package/lib/plugins/index.d.ts +18 -0
  212. package/lib/plugins/index.d.ts.map +1 -0
  213. package/lib/plugins/input/AbstractControls.d.ts +8 -0
  214. package/lib/plugins/input/AbstractControls.d.ts.map +1 -0
  215. package/lib/plugins/input/Controls.d.ts +16 -0
  216. package/lib/plugins/input/Controls.d.ts.map +1 -0
  217. package/lib/plugins/input/InputPlugin.d.ts +52 -0
  218. package/lib/plugins/input/InputPlugin.d.ts.map +1 -0
  219. package/lib/plugins/input/constants.d.ts +8 -0
  220. package/lib/plugins/input/constants.d.ts.map +1 -0
  221. package/lib/plugins/input/index.d.ts +10 -0
  222. package/lib/plugins/input/index.d.ts.map +1 -0
  223. package/lib/plugins/input/interfaces.d.ts +30 -0
  224. package/lib/plugins/input/interfaces.d.ts.map +1 -0
  225. package/lib/plugins/input/keyboard/KeyboardContols.d.ts +28 -0
  226. package/lib/plugins/input/keyboard/KeyboardContols.d.ts.map +1 -0
  227. package/lib/plugins/input/keyboard/index.d.ts +3 -0
  228. package/lib/plugins/input/keyboard/index.d.ts.map +1 -0
  229. package/lib/plugins/input/keyboard/interfaces.d.ts +18 -0
  230. package/lib/plugins/input/keyboard/interfaces.d.ts.map +1 -0
  231. package/lib/plugins/input/methods.d.ts +4 -0
  232. package/lib/plugins/input/methods.d.ts.map +1 -0
  233. package/lib/plugins/input/touch/TouchControls.d.ts +35 -0
  234. package/lib/plugins/input/touch/TouchControls.d.ts.map +1 -0
  235. package/lib/plugins/input/touch/constants.d.ts +14 -0
  236. package/lib/plugins/input/touch/constants.d.ts.map +1 -0
  237. package/lib/plugins/input/touch/index.d.ts +4 -0
  238. package/lib/plugins/input/touch/index.d.ts.map +1 -0
  239. package/lib/plugins/input/touch/interfaces.d.ts +15 -0
  240. package/lib/plugins/input/touch/interfaces.d.ts.map +1 -0
  241. package/lib/plugins/input/types.d.ts +32 -0
  242. package/lib/plugins/input/types.d.ts.map +1 -0
  243. package/lib/plugins/input/utils.d.ts +23 -0
  244. package/lib/plugins/input/utils.d.ts.map +1 -0
  245. package/lib/plugins/spine/SpinePlugin.d.ts +6 -0
  246. package/lib/plugins/spine/SpinePlugin.d.ts.map +1 -0
  247. package/lib/plugins/spine/pixi-spine/BatchableSpineSlot.d.ts +31 -0
  248. package/lib/plugins/spine/pixi-spine/BatchableSpineSlot.d.ts.map +1 -0
  249. package/lib/plugins/spine/pixi-spine/Spine.d.ts +211 -0
  250. package/lib/plugins/spine/pixi-spine/Spine.d.ts.map +1 -0
  251. package/lib/plugins/spine/pixi-spine/SpineDebugRenderer.d.ts +81 -0
  252. package/lib/plugins/spine/pixi-spine/SpineDebugRenderer.d.ts.map +1 -0
  253. package/lib/plugins/spine/pixi-spine/SpinePipe.d.ts +21 -0
  254. package/lib/plugins/spine/pixi-spine/SpinePipe.d.ts.map +1 -0
  255. package/lib/plugins/spine/pixi-spine/SpineTexture.d.ts +16 -0
  256. package/lib/plugins/spine/pixi-spine/SpineTexture.d.ts.map +1 -0
  257. package/lib/plugins/spine/pixi-spine/assets/atlasLoader.d.ts +10 -0
  258. package/lib/plugins/spine/pixi-spine/assets/atlasLoader.d.ts.map +1 -0
  259. package/lib/plugins/spine/pixi-spine/assets/skeletonLoader.d.ts +6 -0
  260. package/lib/plugins/spine/pixi-spine/assets/skeletonLoader.d.ts.map +1 -0
  261. package/lib/plugins/spine/pixi-spine/darktint/DarkTintBatchGeometry.d.ts +5 -0
  262. package/lib/plugins/spine/pixi-spine/darktint/DarkTintBatchGeometry.d.ts.map +1 -0
  263. package/lib/plugins/spine/pixi-spine/darktint/DarkTintBatcher.d.ts +22 -0
  264. package/lib/plugins/spine/pixi-spine/darktint/DarkTintBatcher.d.ts.map +1 -0
  265. package/lib/plugins/spine/pixi-spine/darktint/DarkTintShader.d.ts +5 -0
  266. package/lib/plugins/spine/pixi-spine/darktint/DarkTintShader.d.ts.map +1 -0
  267. package/lib/plugins/spine/pixi-spine/darktint/darkTintBit.d.ts +51 -0
  268. package/lib/plugins/spine/pixi-spine/darktint/darkTintBit.d.ts.map +1 -0
  269. package/lib/plugins/spine/pixi-spine/index.d.ts +9 -0
  270. package/lib/plugins/spine/pixi-spine/index.d.ts.map +1 -0
  271. package/lib/plugins/spine/pixi-spine/require-shim.d.ts +34 -0
  272. package/lib/plugins/spine/pixi-spine/require-shim.d.ts.map +1 -0
  273. package/lib/registries-CYCaYKZI.js +6885 -0
  274. package/lib/registries-CYCaYKZI.js.map +1 -0
  275. package/lib/signals/Signal.d.ts +16 -0
  276. package/lib/signals/Signal.d.ts.map +1 -0
  277. package/lib/signals/Signal.test.d.ts +2 -0
  278. package/lib/signals/Signal.test.d.ts.map +1 -0
  279. package/lib/signals/index.d.ts +3 -0
  280. package/lib/signals/index.d.ts.map +1 -0
  281. package/lib/store/Store.d.ts +56 -0
  282. package/lib/store/Store.d.ts.map +1 -0
  283. package/lib/store/Store.test.d.ts +2 -0
  284. package/lib/store/Store.test.d.ts.map +1 -0
  285. package/lib/store/index.d.ts +2 -0
  286. package/lib/store/index.d.ts.map +1 -0
  287. package/lib/types/framework.d.ts +46 -0
  288. package/lib/types/gsap.d.ts +23 -0
  289. package/lib/ui/Button.d.ts +162 -0
  290. package/lib/ui/Button.d.ts.map +1 -0
  291. package/lib/ui/FlexContainer.d.ts +109 -0
  292. package/lib/ui/FlexContainer.d.ts.map +1 -0
  293. package/lib/ui/Input.d.ts +384 -0
  294. package/lib/ui/Input.d.ts.map +1 -0
  295. package/lib/ui/Joystick.d.ts +61 -0
  296. package/lib/ui/Joystick.d.ts.map +1 -0
  297. package/lib/ui/Popup.d.ts +109 -0
  298. package/lib/ui/Popup.d.ts.map +1 -0
  299. package/lib/ui/Toast.d.ts +131 -0
  300. package/lib/ui/Toast.d.ts.map +1 -0
  301. package/lib/ui/Toaster.d.ts +188 -0
  302. package/lib/ui/Toaster.d.ts.map +1 -0
  303. package/lib/ui/UICanvas.d.ts +155 -0
  304. package/lib/ui/UICanvas.d.ts.map +1 -0
  305. package/lib/ui/index.d.ts +9 -0
  306. package/lib/ui/index.d.ts.map +1 -0
  307. package/lib/utils/array.d.ts +11 -0
  308. package/lib/utils/array.d.ts.map +1 -0
  309. package/lib/utils/bind.d.ts +21 -0
  310. package/lib/utils/bind.d.ts.map +1 -0
  311. package/lib/utils/canvas.d.ts +2 -0
  312. package/lib/utils/canvas.d.ts.map +1 -0
  313. package/lib/utils/color.d.ts +66 -0
  314. package/lib/utils/color.d.ts.map +1 -0
  315. package/lib/utils/console/Logger.d.ts +15 -0
  316. package/lib/utils/console/Logger.d.ts.map +1 -0
  317. package/lib/utils/console/index.d.ts +2 -0
  318. package/lib/utils/console/index.d.ts.map +1 -0
  319. package/lib/utils/debug.d.ts +34 -0
  320. package/lib/utils/debug.d.ts.map +1 -0
  321. package/lib/utils/define.d.ts +100 -0
  322. package/lib/utils/define.d.ts.map +1 -0
  323. package/lib/utils/env.d.ts +4 -0
  324. package/lib/utils/env.d.ts.map +1 -0
  325. package/lib/utils/events.d.ts +12 -0
  326. package/lib/utils/events.d.ts.map +1 -0
  327. package/lib/utils/framework.d.ts +12 -0
  328. package/lib/utils/framework.d.ts.map +1 -0
  329. package/lib/utils/index.d.ts +28 -0
  330. package/lib/utils/index.d.ts.map +1 -0
  331. package/lib/utils/map.d.ts +31 -0
  332. package/lib/utils/map.d.ts.map +1 -0
  333. package/lib/utils/math.d.ts +15 -0
  334. package/lib/utils/math.d.ts.map +1 -0
  335. package/lib/utils/misc.d.ts +13 -0
  336. package/lib/utils/misc.d.ts.map +1 -0
  337. package/lib/utils/number.d.ts +2 -0
  338. package/lib/utils/number.d.ts.map +1 -0
  339. package/lib/utils/object.d.ts +21 -0
  340. package/lib/utils/object.d.ts.map +1 -0
  341. package/lib/utils/padding.d.ts +4 -0
  342. package/lib/utils/padding.d.ts.map +1 -0
  343. package/lib/utils/pixi.d.ts +42 -0
  344. package/lib/utils/pixi.d.ts.map +1 -0
  345. package/lib/utils/platform.d.ts +20 -0
  346. package/lib/utils/platform.d.ts.map +1 -0
  347. package/lib/utils/point.d.ts +66 -0
  348. package/lib/utils/point.d.ts.map +1 -0
  349. package/lib/utils/promise/Queue.d.ts +60 -0
  350. package/lib/utils/promise/Queue.d.ts.map +1 -0
  351. package/lib/utils/promise/functions.d.ts +14 -0
  352. package/lib/utils/promise/functions.d.ts.map +1 -0
  353. package/lib/utils/promise/index.d.ts +3 -0
  354. package/lib/utils/promise/index.d.ts.map +1 -0
  355. package/lib/utils/random.d.ts +42 -0
  356. package/lib/utils/random.d.ts.map +1 -0
  357. package/lib/utils/rect.d.ts +26 -0
  358. package/lib/utils/rect.d.ts.map +1 -0
  359. package/lib/utils/set.d.ts +15 -0
  360. package/lib/utils/set.d.ts.map +1 -0
  361. package/lib/utils/string.d.ts +3 -0
  362. package/lib/utils/string.d.ts.map +1 -0
  363. package/lib/utils/text.d.ts +3 -0
  364. package/lib/utils/text.d.ts.map +1 -0
  365. package/lib/utils/typefilters.d.ts +4 -0
  366. package/lib/utils/typefilters.d.ts.map +1 -0
  367. package/lib/utils/types.d.ts +209 -0
  368. package/lib/utils/types.d.ts.map +1 -0
  369. package/lib/utils/vite.d.ts +25 -0
  370. package/lib/utils/vite.d.ts.map +1 -0
  371. package/lib/utils/web.d.ts +3 -0
  372. package/lib/utils/web.d.ts.map +1 -0
  373. package/lib/version.d.ts +3 -0
  374. package/lib/version.d.ts.map +1 -0
  375. package/lib/webgl-check.d.ts +2 -0
  376. package/lib/webgl-check.d.ts.map +1 -0
  377. package/package.json +138 -0
  378. package/src/core/Application.ts +1091 -0
  379. package/src/core/config.ts +168 -0
  380. package/src/core/create.ts +186 -0
  381. package/src/core/globals.ts +299 -0
  382. package/src/core/index.ts +6 -0
  383. package/src/core/interfaces/IApplication.ts +628 -0
  384. package/src/core/interfaces/IApplicationOptions.ts +81 -0
  385. package/src/core/interfaces/ICoreFunctions.ts +86 -0
  386. package/src/core/interfaces/ICoreSignals.ts +77 -0
  387. package/src/core/interfaces/IStorageCapability.test.ts +27 -0
  388. package/src/core/interfaces/IStorageCapability.ts +26 -0
  389. package/src/core/interfaces/index.ts +6 -0
  390. package/src/core/registries.ts +7 -0
  391. package/src/core/types.ts +13 -0
  392. package/src/display/AnimatedSprite.ts +227 -0
  393. package/src/display/Camera.ts +371 -0
  394. package/src/display/Container.ts +240 -0
  395. package/src/display/Entity.ts +50 -0
  396. package/src/display/ParticleContainer.ts +107 -0
  397. package/src/display/Scene.ts +305 -0
  398. package/src/display/SceneTransition.ts +108 -0
  399. package/src/display/SpineAnimation.ts +170 -0
  400. package/src/display/Svg.ts +9 -0
  401. package/src/display/index.ts +11 -0
  402. package/src/env.d.ts +6 -0
  403. package/src/hello.ts +20 -0
  404. package/src/index.ts +17 -0
  405. package/src/mixins/animated.ts +340 -0
  406. package/src/mixins/factory/Factory.ts +24 -0
  407. package/src/mixins/factory/const.ts +363 -0
  408. package/src/mixins/factory/index.ts +7 -0
  409. package/src/mixins/factory/methods.ts +21 -0
  410. package/src/mixins/factory/props.ts +207 -0
  411. package/src/mixins/factory/registry.test.ts +83 -0
  412. package/src/mixins/factory/registry.ts +61 -0
  413. package/src/mixins/factory/schema.ts +153 -0
  414. package/src/mixins/factory/ui-registry.ts +54 -0
  415. package/src/mixins/factory/utils.ts +130 -0
  416. package/src/mixins/focus.ts +124 -0
  417. package/src/mixins/index.ts +5 -0
  418. package/src/mixins/interaction.ts +74 -0
  419. package/src/mixins/signals.ts +49 -0
  420. package/src/plugins/AssetsPlugin.ts +407 -0
  421. package/src/plugins/DataAdapter.ts +259 -0
  422. package/src/plugins/DevToolsPlugin.ts +103 -0
  423. package/src/plugins/FullScreenPlugin.ts +359 -0
  424. package/src/plugins/GSAPPlugin.ts +811 -0
  425. package/src/plugins/KeyboardPlugin.ts +160 -0
  426. package/src/plugins/LayoutPlugin.ts +127 -0
  427. package/src/plugins/LookupPlugin.ts +308 -0
  428. package/src/plugins/Plugin.test.ts +73 -0
  429. package/src/plugins/Plugin.ts +200 -0
  430. package/src/plugins/PopupManagerPlugin.ts +263 -0
  431. package/src/plugins/ResizerPlugin.ts +220 -0
  432. package/src/plugins/SceneManagerPlugin.ts +669 -0
  433. package/src/plugins/StatsPlugin.ts +24 -0
  434. package/src/plugins/TimerPlugin.ts +841 -0
  435. package/src/plugins/WebEventsPlugin.ts +132 -0
  436. package/src/plugins/actions/ActionsPlugin.ts +113 -0
  437. package/src/plugins/actions/constants.ts +45 -0
  438. package/src/plugins/actions/index.ts +4 -0
  439. package/src/plugins/actions/methods.ts +28 -0
  440. package/src/plugins/actions/types.ts +47 -0
  441. package/src/plugins/audio/AudioChannel.test.ts +101 -0
  442. package/src/plugins/audio/AudioChannel.ts +164 -0
  443. package/src/plugins/audio/AudioInstance.ts +228 -0
  444. package/src/plugins/audio/AudioManagerPlugin.ts +903 -0
  445. package/src/plugins/audio/VoiceOverPlugin.ts +354 -0
  446. package/src/plugins/audio/index.ts +3 -0
  447. package/src/plugins/breakpoints/BreakpointPlugin.test.ts +228 -0
  448. package/src/plugins/breakpoints/BreakpointPlugin.ts +293 -0
  449. package/src/plugins/breakpoints/evaluate.test.ts +239 -0
  450. package/src/plugins/breakpoints/evaluate.ts +201 -0
  451. package/src/plugins/breakpoints/index.ts +3 -0
  452. package/src/plugins/breakpoints/methods.ts +22 -0
  453. package/src/plugins/breakpoints/types.ts +86 -0
  454. package/src/plugins/captions/CaptionsPlugin.ts +468 -0
  455. package/src/plugins/captions/CaptionsRenderer.ts +184 -0
  456. package/src/plugins/captions/font/Sans.fnt +116 -0
  457. package/src/plugins/captions/font/Sans.png +0 -0
  458. package/src/plugins/captions/index.ts +2 -0
  459. package/src/plugins/defaults.ts +95 -0
  460. package/src/plugins/focus/FocusManagerPlugin.ts +773 -0
  461. package/src/plugins/focus/FocusOutliner.ts +111 -0
  462. package/src/plugins/focus/index.ts +2 -0
  463. package/src/plugins/i18nPlugin.ts +284 -0
  464. package/src/plugins/index.ts +17 -0
  465. package/src/plugins/input/AbstractControls.ts +15 -0
  466. package/src/plugins/input/Controls.ts +55 -0
  467. package/src/plugins/input/InputPlugin.ts +168 -0
  468. package/src/plugins/input/constants.ts +12 -0
  469. package/src/plugins/input/index.ts +9 -0
  470. package/src/plugins/input/interfaces.ts +37 -0
  471. package/src/plugins/input/keyboard/KeyboardContols.ts +182 -0
  472. package/src/plugins/input/keyboard/index.ts +2 -0
  473. package/src/plugins/input/keyboard/interfaces.ts +21 -0
  474. package/src/plugins/input/methods.ts +9 -0
  475. package/src/plugins/input/touch/TouchControls.ts +237 -0
  476. package/src/plugins/input/touch/constants.ts +34 -0
  477. package/src/plugins/input/touch/index.ts +3 -0
  478. package/src/plugins/input/touch/interfaces.ts +15 -0
  479. package/src/plugins/input/types.ts +41 -0
  480. package/src/plugins/input/utils.ts +10 -0
  481. package/src/plugins/spine/SpinePlugin.ts +14 -0
  482. package/src/plugins/spine/pixi-spine/BatchableSpineSlot.ts +138 -0
  483. package/src/plugins/spine/pixi-spine/Spine.ts +897 -0
  484. package/src/plugins/spine/pixi-spine/SpineDebugRenderer.ts +615 -0
  485. package/src/plugins/spine/pixi-spine/SpinePipe.ts +197 -0
  486. package/src/plugins/spine/pixi-spine/SpineTexture.ts +143 -0
  487. package/src/plugins/spine/pixi-spine/assets/atlasLoader.ts +156 -0
  488. package/src/plugins/spine/pixi-spine/assets/skeletonLoader.ts +80 -0
  489. package/src/plugins/spine/pixi-spine/darktint/DarkTintBatchGeometry.ts +92 -0
  490. package/src/plugins/spine/pixi-spine/darktint/DarkTintBatcher.ts +186 -0
  491. package/src/plugins/spine/pixi-spine/darktint/DarkTintShader.ts +74 -0
  492. package/src/plugins/spine/pixi-spine/darktint/darkTintBit.ts +77 -0
  493. package/src/plugins/spine/pixi-spine/index.ts +43 -0
  494. package/src/plugins/spine/pixi-spine/require-shim.ts +43 -0
  495. package/src/signals/Signal.test.ts +54 -0
  496. package/src/signals/Signal.ts +68 -0
  497. package/src/signals/index.ts +10 -0
  498. package/src/store/Store.test.ts +146 -0
  499. package/src/store/Store.ts +192 -0
  500. package/src/store/index.ts +1 -0
  501. package/src/types/framework.d.ts +47 -0
  502. package/src/types/gsap.d.ts +26 -0
  503. package/src/ui/Button.ts +454 -0
  504. package/src/ui/FlexContainer.ts +526 -0
  505. package/src/ui/Input.ts +1274 -0
  506. package/src/ui/Joystick.ts +288 -0
  507. package/src/ui/Popup.ts +242 -0
  508. package/src/ui/Toast.ts +399 -0
  509. package/src/ui/Toaster.ts +409 -0
  510. package/src/ui/UICanvas.ts +812 -0
  511. package/src/ui/index.ts +8 -0
  512. package/src/utils/array.ts +24 -0
  513. package/src/utils/bind.ts +79 -0
  514. package/src/utils/canvas.ts +26 -0
  515. package/src/utils/color.ts +126 -0
  516. package/src/utils/console/Logger.ts +86 -0
  517. package/src/utils/console/index.ts +1 -0
  518. package/src/utils/debug.ts +69 -0
  519. package/src/utils/define.ts +120 -0
  520. package/src/utils/env.ts +3 -0
  521. package/src/utils/events.ts +10 -0
  522. package/src/utils/framework.ts +45 -0
  523. package/src/utils/index.ts +27 -0
  524. package/src/utils/map.ts +59 -0
  525. package/src/utils/math.ts +19 -0
  526. package/src/utils/misc.ts +45 -0
  527. package/src/utils/number.ts +3 -0
  528. package/src/utils/object.ts +43 -0
  529. package/src/utils/padding.ts +43 -0
  530. package/src/utils/pixi.ts +116 -0
  531. package/src/utils/platform.ts +33 -0
  532. package/src/utils/point.ts +123 -0
  533. package/src/utils/promise/Queue.ts +125 -0
  534. package/src/utils/promise/functions.ts +16 -0
  535. package/src/utils/promise/index.ts +2 -0
  536. package/src/utils/random.ts +69 -0
  537. package/src/utils/rect.ts +50 -0
  538. package/src/utils/set.ts +32 -0
  539. package/src/utils/string.ts +9 -0
  540. package/src/utils/text.ts +30 -0
  541. package/src/utils/typefilters.ts +29 -0
  542. package/src/utils/types.ts +426 -0
  543. package/src/utils/vite.ts +41 -0
  544. package/src/utils/web.ts +7 -0
  545. package/src/version.ts +3 -0
  546. package/src/webgl-check.ts +12 -0
  547. package/templates/app/default/.eslintrc.json +21 -0
  548. package/templates/app/default/.meta.json +4 -0
  549. package/templates/app/default/.nvmrc +1 -0
  550. package/templates/app/default/.prettierrc.json +7 -0
  551. package/templates/app/default/README.md +8 -0
  552. package/templates/app/default/assets/audio{m}/music/Cheerful Annoyance.ogg +0 -0
  553. package/templates/app/default/assets/audio{m}/music/Drumming Sticks.ogg +0 -0
  554. package/templates/app/default/assets/audio{m}/music/Game Over.ogg +0 -0
  555. package/templates/app/default/assets/audio{m}/music/Mishief Stroll.ogg +0 -0
  556. package/templates/app/default/assets/audio{m}/music/Night at the Beach.ogg +0 -0
  557. package/templates/app/default/assets/audio{m}/sfx/click.ogg +0 -0
  558. package/templates/app/default/assets/audio{m}/sfx/hover.ogg +0 -0
  559. package/templates/app/default/assets/required{m}/caper.png +0 -0
  560. package/templates/app/default/assets/required{m}/fonts{fix}/SpaceGrotesk-Bold{family=Space Grotesk}{wf}.ttf +0 -0
  561. package/templates/app/default/assets/required{m}/fonts{fix}/SpaceGrotesk-Medium{family=Space Grotesk}{wf}.ttf +0 -0
  562. package/templates/app/default/assets/required{m}/fonts{fix}/SpaceGrotesk-Regular{family=Space Grotesk}{wf}.ttf +0 -0
  563. package/templates/app/default/assets/required{m}/fonts{fix}/Syncopate-Bold{family=Syncopate}{wf}.ttf +0 -0
  564. package/templates/app/default/assets/required{m}/ui{tps}/btn/blue.png +0 -0
  565. package/templates/app/default/assets/required{m}/ui{tps}/btn/green.png +0 -0
  566. package/templates/app/default/assets/required{m}/ui{tps}/btn/grey.png +0 -0
  567. package/templates/app/default/assets/required{m}/ui{tps}/btn/orange.png +0 -0
  568. package/templates/app/default/assets/required{m}/ui{tps}/btn/purple.png +0 -0
  569. package/templates/app/default/assets/required{m}/ui{tps}/btn/red.png +0 -0
  570. package/templates/app/default/assets/required{m}/ui{tps}/btn/yellow.png +0 -0
  571. package/templates/app/default/assets/required{m}/ui{tps}/btn_a/down.png +0 -0
  572. package/templates/app/default/assets/required{m}/ui{tps}/btn_a/over.png +0 -0
  573. package/templates/app/default/assets/required{m}/ui{tps}/btn_a/up.png +0 -0
  574. package/templates/app/default/assets/required{m}/ui{tps}/btn_b/down.png +0 -0
  575. package/templates/app/default/assets/required{m}/ui{tps}/btn_b/over.png +0 -0
  576. package/templates/app/default/assets/required{m}/ui{tps}/btn_b/up.png +0 -0
  577. package/templates/app/default/assets/required{m}/ui{tps}/joystick/base.png +0 -0
  578. package/templates/app/default/assets/required{m}/ui{tps}/joystick/handle.png +0 -0
  579. package/templates/app/default/assets/required{m}/wordmark.svg +1 -0
  580. package/templates/app/default/assets/spine{m}/spineboy-pro.png +0 -0
  581. package/templates/app/default/assets/spine{m}/spineboy-pro.skel +0 -0
  582. package/templates/app/default/assets/spine{m}/spineboy-pro{fix}.atlas +94 -0
  583. package/templates/app/default/caper.config.ts +60 -0
  584. package/templates/app/default/index.html +23 -0
  585. package/templates/app/default/package.template.json +17 -0
  586. package/templates/app/default/public/favicon.ico +0 -0
  587. package/templates/app/default/src/__APPLICATION_NAME__.ts +3 -0
  588. package/templates/app/default/src/main.ts +9 -0
  589. package/templates/app/default/src/scenes/Base.ts +39 -0
  590. package/templates/app/default/src/scenes/Game.ts +34 -0
  591. package/templates/app/default/src/scenes/Splash.ts +70 -0
  592. package/templates/app/default/src/scenes/Start.ts +90 -0
  593. package/templates/app/default/src/utils/Constants.ts +3 -0
  594. package/templates/app/default/tsconfig.json +1 -0
  595. package/templates/plugin/package.template.json +33 -0
  596. package/templates/plugin/src/Plugin.template.ts +24 -0
  597. package/templates/plugin/src/index.template.ts +3 -0
  598. package/templates/plugin/tsconfig.template.json +43 -0
  599. package/templates/plugin/vite-env.template.d.ts +16 -0
  600. package/templates/plugin/vite.config.template.ts +19 -0
@@ -0,0 +1,1602 @@
1
+ # Caper — llms.txt
2
+
3
+ **What Caper is.** An opinionated HTML game framework built on **PixiJS v8**. Ships
4
+ as `@caperjs/core` plus a set of `@caperjs/plugin-*` packages. Scene-oriented
5
+ architecture, plugin dependency ordering, typed-signal wiring, a factory surface
6
+ on every `Container`, build-time auto-discovery of scenes/plugins/popups/entities,
7
+ and generated TypeScript types for app IDs and assets. Caper is a personal fork
8
+ of `dill-pixel` by Relish Studios.
9
+
10
+ **Package version:** `@caperjs/core@6.2.2` · **Peer deps:** `pixi.js@8.x`, `@pixi/sound@^6`, `gsap@^3.13`.
11
+
12
+ **File citations in this guide** point at the `@caperjs/core` package source
13
+ (paths relative to this file, e.g. `../src/core/Application.ts`) — those ship
14
+ with the npm package and resolve wherever the agent is reading from. Code
15
+ snippets are self-contained; you shouldn't need to fetch anything external to
16
+ produce working code.
17
+
18
+ **External references worth fetching when deeper context is needed:**
19
+ - `pixijs.com/llms.txt` — PixiJS v8 API reference
20
+ - `@caperjs/core` README on npm — package overview
21
+
22
+ ---
23
+
24
+ ## Table of contents
25
+
26
+ 1. [Rules of engagement](#1-rules-of-engagement) — read this first
27
+ 2. [Project layout & scaffolding CLI](#2-project-layout--scaffolding-cli)
28
+ 3. [Bootstrap: `create()` + entry](#3-bootstrap-create--entry)
29
+ 4. [`defineConfig` & companion helpers](#4-defineconfig--companion-helpers)
30
+ 5. [Scene lifecycle](#5-scene-lifecycle)
31
+ 6. [Factory methods: `add.*` / `make.*`](#6-factory-methods-add--make)
32
+ 7. [UI primitives](#7-ui-primitives)
33
+ 8. [Built-in plugins (on `app`)](#8-built-in-plugins-on-app)
34
+ 9. [Plugin authoring](#9-plugin-authoring)
35
+ 10. [Display objects beyond UI](#10-display-objects-beyond-ui)
36
+ 11. [Assets & AssetPack](#11-assets--assetpack)
37
+ 12. [Signals, Store, mixins](#12-signals-store-mixins)
38
+ 13. [First-party plugins (`@caperjs/plugin-*`)](#13-first-party-plugins-caperplugin-)
39
+ 14. [Generated types & virtual modules](#14-generated-types--virtual-modules)
40
+ 15. [Common recipes](#15-common-recipes)
41
+ 16. [Gotchas & verification loop](#16-gotchas--verification-loop)
42
+ 17. [API reference index](#17-api-reference-index)
43
+
44
+ ---
45
+
46
+ ## 1. Rules of engagement
47
+
48
+ These six rules are the difference between idiomatic Caper code and code the
49
+ human will rewrite. **Apply every one.** They're ordered by how often agents
50
+ violate them.
51
+
52
+ ### 1.1 `caper.config.ts` is the single source of truth
53
+
54
+ Plugins listed in `caper.config.ts`'s `plugins: [...]` array are
55
+ **authoritative**. The framework does NOT auto-register transitive dependencies. If plugin A `requires: ['b']`, both A **and** B must
56
+ appear in `plugins: [...]`. Bootstrap throws with an actionable message if a
57
+ required plugin is missing — it does not silently add B.
58
+
59
+ ```ts
60
+ // ✅ correct — both listed explicitly
61
+ plugins: ['google-analytics', 'firebase']
62
+
63
+ // ❌ wrong — relying on transitive registration
64
+ plugins: ['plugin-that-requires-firebase'] // bootstrap will throw
65
+ ```
66
+
67
+ Corollary: if you want to disable a plugin, remove it from `plugins: []`. Don't
68
+ add an `enabled: false` flag, don't comment-and-uncomment, don't set `autoLoad:
69
+ false` (that defers loading, it doesn't unregister). Explicit beats clever.
70
+
71
+ ### 1.2 Fail loud, never silent
72
+
73
+ When the framework — or any plugin you write — hits a misconfiguration, missing
74
+ dependency, missing asset, or other dev-error condition, **throw with a message
75
+ that says what to change and where**. Do not fall back to defaults, do not
76
+ return `null`, do not swallow exceptions.
77
+
78
+ ```ts
79
+ // ❌ wrong — silent fallback, user has no idea anything went wrong
80
+ try { texture = Assets.get('hero'); } catch { texture = Texture.WHITE; }
81
+
82
+ // ✅ correct — tell the user exactly what's broken and how to fix it
83
+ const texture = Assets.get('hero');
84
+ if (!texture) {
85
+ throw new Error(
86
+ `Missing texture 'hero'. Add it to an asset bundle and preload it via ` +
87
+ `caper.config.ts > assets.preload.bundles, or declare it on the scene via ` +
88
+ `export const assets: SceneAssets = { preload: { bundles: ['hero'] } }`,
89
+ );
90
+ }
91
+ ```
92
+
93
+ Corollary: don't add `try { ... } catch { return null }` blocks to make symptoms
94
+ go away. Diagnose the upstream cause.
95
+
96
+ ### 1.3 Metadata goes on `defineX` wrappers, not class statics
97
+
98
+ Scene, plugin, popup, and entity metadata is read by the Vite plugin at build
99
+ time via AST walk of `src/scenes/`, `src/plugins/`, `src/popups/`, `src/entities/`.
100
+ The walker reads `export const <name> = defineX({...})`. It does **not** read
101
+ class statics, decorators, or runtime registration. See
102
+ [src/utils/define.ts](../src/utils/define.ts) —
103
+ `defineScene`, `definePlugin`, `definePopup`, `defineEntity`, `defineUI` are all
104
+ identity functions whose value is type inference + AST discoverability.
105
+
106
+ ```ts
107
+ // ✅ correct — AST walker picks this up; types flow through
108
+ export const scene = defineScene({ id: 'menu', dynamic: true });
109
+ export default class MenuScene extends Scene { /* ... */ }
110
+
111
+ // ❌ wrong — static ignored by discovery; type narrowing broken
112
+ export default class MenuScene extends Scene {
113
+ static id = 'menu';
114
+ }
115
+ ```
116
+
117
+ Do **not** propose TypeScript decorators, a runtime `register()` call, or
118
+ reflection — the architecture explicitly rules them out.
119
+
120
+ ### 1.4 `add.*` / `make.*` over raw `new Pixi…()`
121
+
122
+ Every `Container` subclass in Caper (`Scene`, `Entity`, `Popup`, `FlexContainer`,
123
+ user subclasses) has the Factory mixin. Always use `this.add.*` to parent to
124
+ `this`, or `this.make.*` to build detached. The factory wires position / scale /
125
+ pivot / anchor, asset-name resolution, layout props, and signals — raw `new
126
+ Sprite()` skips all of that.
127
+
128
+ ```ts
129
+ // ✅ correct
130
+ this.hero = this.add.sprite({ asset: 'hero', anchor: 0.5, x: 100 });
131
+
132
+ // ❌ wrong — no asset resolution, no layout integration, no factory behavior
133
+ this.hero = new Sprite(Texture.from('hero.png'));
134
+ this.addChild(this.hero);
135
+ this.hero.anchor.set(0.5);
136
+ this.hero.position.set(100, 0);
137
+ ```
138
+
139
+ Full factory catalog: §6. Extending with custom factories: §6 end.
140
+
141
+ ### 1.5 `caper add` before hand-authoring
142
+
143
+ When scaffolding a new scene / plugin / popup / entity, always start from the
144
+ CLI. The templates drop the file in the right directory, include the `defineX`
145
+ wrapper, and wire the import shape the discovery walker expects.
146
+
147
+ ```bash
148
+ caper add scene LevelOne # → src/scenes/LevelOne.ts
149
+ caper add plugin Analytics # → src/plugins/AnalyticsPlugin.ts
150
+ caper add popup Confirm # → src/popups/ConfirmPopup.ts
151
+ caper add entity Enemy # → src/entities/Enemy.ts
152
+ ```
153
+
154
+ Only hand-author when the template genuinely doesn't match — e.g. a subclass of
155
+ an existing scene that's not itself discoverable.
156
+
157
+ ### 1.6 Verify in the running app, not in isolation
158
+
159
+ Caper changes are verified by running the app in a browser, not by unit tests
160
+ alone. The framework's own type-check + test suite (`pnpm --filter @caperjs/core
161
+ test`) catches a lot, but UI/scene/asset behavior only shows up live.
162
+
163
+ After any non-trivial change:
164
+
165
+ 1. Type-check the app (`pnpm types` or `tsc`).
166
+ 2. Build cleanly (`caper build` or the app's `build` script).
167
+ 3. **Ask the human to run `caper dev`** and eyeball the affected scene/feature.
168
+
169
+ Do **not** start `caper dev` yourself — it runs forever and will block. Ask the
170
+ user to verify visually and report back.
171
+
172
+ ---
173
+
174
+ ## 2. Project layout & scaffolding CLI
175
+
176
+ ### 2.1 Canonical layout (per app)
177
+
178
+ The Vite plugin's discovery paths are hard-coded — don't invent alternative
179
+ directories.
180
+
181
+ ```
182
+ my-app/
183
+ ├── src/
184
+ │ ├── main.ts # optional post-boot hook: main(app) export
185
+ │ ├── MyApplication.ts # optional Application subclass
186
+ │ ├── scenes/ # AST-discovered; each file: defineScene + default class
187
+ │ ├── plugins/ # AST-discovered; each file: definePlugin + default class
188
+ │ ├── popups/ # AST-discovered; each file: definePopup + default class
189
+ │ ├── entities/ # AST-discovered; each file: defineEntity + default class
190
+ │ ├── ui/ # user UI components (not discovered)
191
+ │ ├── locales/ # i18n key maps, one file per locale
192
+ │ ├── types/ # generated: caper-app.d.ts, caper-assets.d.ts
193
+ │ ├── utils/ # user helpers, Constants.ts, Easing.ts, etc.
194
+ │ └── theme.ts # user color / token constants
195
+ ├── assets/ # AssetPack raw inputs (folders = bundle IDs)
196
+ ├── public/ # static passthroughs
197
+ ├── caper.config.ts # app config — source of truth (§4)
198
+ ├── vite.config.mjs # usually minimal; just path aliases
199
+ ├── tsconfig.json # extends @caperjs/core/config/tsconfig
200
+ ├── index.html # Vite entry
201
+ └── package.json
202
+ ```
203
+
204
+ ### 2.2 CLI — `caper <subcommand>`
205
+
206
+ Installed via `@caperjs/core` package. Binary at [cli.mjs](../cli.mjs). All
207
+ subcommands run from the app root.
208
+
209
+ | Command | Purpose |
210
+ | --- | --- |
211
+ | `caper create [path] [--use-pnpm\|--use-yarn]` | Interactive scaffolder for a new Caper app. Also exposed as `create-caper`. |
212
+ | `caper add scene \| plugin \| popup \| entity <Name> [--dir path]` | **Primary scaffolding entry.** Emits `src/<kind>s/<Name>.ts` with `defineX` wrapper + default class + the correct import shape. |
213
+ | `caper dev` (alias `caper start`) | Start Vite dev server with Caper plugin pre-wired. |
214
+ | `caper build` | Production build. |
215
+ | `caper preview` | Build then preview locally. |
216
+ | `caper update` | Update Caper to latest. |
217
+ | `caper install` | Install peer deps (rarely needed; normally automatic). |
218
+ | `caper vo generate [inputDir] [outputDir]` | Voiceover CSV generation from locales. Defaults: `./src/locales` → `./src/assets/audio/vo/csv`. |
219
+ | `caper audio compress [audioDir]` | Compress audio files. |
220
+ | `caper audio captions [csvDir] [outputDir]` | Generate `cc.json` closed-captions from CSV. |
221
+
222
+ **Name normalization.** `caper add` accepts any case and produces PascalCase
223
+ class name + kebab-case id. `caper add scene "My Cool Scene"` → class `MyCoolScene`,
224
+ id `my-cool-scene`.
225
+
226
+ **File is auto-discovered** on the next Vite reload. No edit to `caper.config.ts`
227
+ required (plugins are the one exception — see §1.1).
228
+
229
+ ### 2.3 Typical app-level scripts
230
+
231
+ ```jsonc
232
+ {
233
+ "dev": "pnpm clean && caper dev",
234
+ "build": "pnpm clean && caper build",
235
+ "preview": "pnpm clean && caper preview",
236
+ "types": "tsc",
237
+ "clean": "rimraf dist .assetpack .cache",
238
+ "lint": "eslint \"src/**/*.ts\""
239
+ }
240
+ ```
241
+
242
+ The `clean` step is important — AssetPack caches aggressively under
243
+ `.assetpack/` and stale caches cause confusing asset/name mismatches.
244
+
245
+ **Source references:** [cli.mjs](../cli.mjs), [cli/add.mjs](../cli/add.mjs),
246
+ [cli/create.mjs](../cli/create.mjs), [templates/](../templates/).
247
+
248
+ ---
249
+
250
+ ## 3. Bootstrap: `create()` + entry
251
+
252
+ ### 3.1 Entry HTML + `index.html`
253
+
254
+ Standard Vite entry. The Caper Vite plugin injects the config.
255
+
256
+ ### 3.2 `main.ts` — optional post-boot hook
257
+
258
+ Default-export an `async function main(app)` that runs after the app boots. Used
259
+ for user-level UI that spans scenes, e.g. a sidebar / overlay. If you don't
260
+ need one, omit the file.
261
+
262
+ ```ts
263
+ // src/main.ts
264
+ import type { MyApplication } from '@/MyApplication';
265
+ import { Sidebar } from '@/ui/sidebar';
266
+
267
+ export default async function main(app: MyApplication) {
268
+ new Sidebar(app).mount();
269
+ }
270
+ ```
271
+
272
+ The framework calls `create()` for you — **you don't call it yourself** in an
273
+ app using the Caper Vite plugin. `create()` is exported for programmatic /
274
+ testing use.
275
+
276
+ ### 3.3 `create(config?, domElement?, speak?)`
277
+
278
+ Signature (from [src/core/create.ts](../src/core/create.ts)):
279
+
280
+ ```ts
281
+ function create(
282
+ config?: Partial<AppConfig>,
283
+ domElement?: string | HTMLElement | Window,
284
+ speak?: boolean,
285
+ ): Promise<App>
286
+ ```
287
+
288
+ - `config` — merged over discovered `caper.config.ts`.
289
+ - `domElement` — string ID, element, or Window. If ID, a container is created.
290
+ - `speak` — voiceover initialization flag.
291
+
292
+ ### 3.4 Custom `Application` subclass
293
+
294
+ Provide a class in `config.application` to add typed getters for plugins, a
295
+ `setup()` hook, and convenience methods on `app`. Pattern:
296
+
297
+ ```ts
298
+ import { Application, PopupId } from '@caperjs/core';
299
+ import { IFirebasePlugin } from '@caperjs/plugin-firebase';
300
+
301
+ export class MyApplication extends Application {
302
+ get firebase(): IFirebasePlugin {
303
+ return this.getPlugin('firebase') as unknown as IFirebasePlugin;
304
+ }
305
+
306
+ setup() {
307
+ // Register cross-scene action handlers here
308
+ this.actions('toggle_pause').connect(detail => this.togglePause(detail.data), 'highest');
309
+ this.actions('show_popup').connect(detail => this.popups.showPopup(detail.data.id as PopupId, detail.data));
310
+ }
311
+ }
312
+ ```
313
+
314
+ Then in `caper.config.ts`:
315
+
316
+ ```ts
317
+ export default defineConfig({
318
+ application: KitchenSinkApplication,
319
+ // ...
320
+ });
321
+ ```
322
+
323
+ ---
324
+
325
+ ## 4. `defineConfig` & companion helpers
326
+
327
+ Everything the Vite AST walker reads. All of them are identity functions
328
+ (`config => config`) whose real job is type inference + static discoverability.
329
+ See [src/utils/define.ts](../src/utils/define.ts) and
330
+ [src/core/config.ts](../src/core/config.ts).
331
+
332
+ ### 4.1 `defineConfig(config)` — app config
333
+
334
+ Returns the config object unchanged. Use it as the **default export** of
335
+ `caper.config.ts`. Every top-level key listed in §4.3.
336
+
337
+ ### 4.2 Per-file wrappers
338
+
339
+ | Helper | File location | Purpose |
340
+ | --- | --- | --- |
341
+ | `defineScene({ id, active?, dynamic?, assets?, plugins?, debug? })` | `src/scenes/<X>.ts` | Scene metadata |
342
+ | `definePlugin({ id, active?, dynamic?, requires? })` | `src/plugins/<X>.ts` | Plugin metadata |
343
+ | `definePopup({ id, active?, dynamic? })` | `src/popups/<X>.ts` | Popup metadata |
344
+ | `defineEntity({ id, active?, dynamic? })` | `src/entities/<X>.ts` | Entity metadata |
345
+ | `defineUI({ id, active?, dynamic? })` | `src/ui/<X>.ts` | UI component metadata (optional; for `this.add.ui(id)`) |
346
+
347
+ Shared fields:
348
+ - `id` — required, lowercase kebab or snake. Must be unique across its kind.
349
+ - `active` — default `true`. Set `false` to hide without deleting the file.
350
+ - `dynamic` — whether to code-split: `defineScene` defaults `true`,
351
+ `definePlugin`/`definePopup`/`defineEntity` default `false`.
352
+ - `requires` (plugin only) — array of plugin IDs; topologically sorted at boot.
353
+
354
+ Canonical scene file shape:
355
+
356
+ ```ts
357
+ // src/scenes/Menu.ts
358
+ import { defineScene, Scene } from '@caperjs/core';
359
+
360
+ export const scene = defineScene({
361
+ id: 'menu',
362
+ debug: { label: 'Main Menu', group: 'Menus' },
363
+ });
364
+
365
+ export default class MenuScene extends Scene {
366
+ async initialize() { /* ... */ }
367
+ }
368
+ ```
369
+
370
+ ### 4.3 Action / input helpers
371
+
372
+ Four cooperating helpers, all imported from `@caperjs/core`:
373
+
374
+ ```ts
375
+ const contexts = defineContexts(['default', 'game', 'menu', 'popup']);
376
+
377
+ const actions = defineActions(contexts, {
378
+ jump: { context: ['game'] },
379
+ close: { context: ['menu', 'popup'] },
380
+ show_popup: { context: '*' }, // any context
381
+ });
382
+
383
+ const buttons = defineButtons(['A', 'B']); // physical button IDs
384
+
385
+ const controls = defineControls(actions, buttons, {
386
+ keyboard: {
387
+ down: { jump: ['Space', 'W'], move_left: ['ArrowLeft', 'A'] },
388
+ up: { close: 'Escape' },
389
+ },
390
+ touch: { down: { jump: 'A' }, joystick: { move_left: ['left'] } },
391
+ });
392
+ ```
393
+
394
+ Typo protection is compile-time: `actions` keys are constrained to the union
395
+ `contexts[number]`, `controls` keys are constrained to `keyof actions`.
396
+
397
+ Wire them in the main config:
398
+
399
+ ```ts
400
+ export default defineConfig({
401
+ actions,
402
+ input: { controls },
403
+ /* ... */
404
+ });
405
+ ```
406
+
407
+ Read actions from code via `app.actions('jump').connect(detail => { ... })`.
408
+
409
+ ### 4.4 `defineData(schema)` — typed persistent store
410
+
411
+ ```ts
412
+ export const dataSchema = defineData({
413
+ score: 0 satisfies number,
414
+ playerName: '' satisfies string,
415
+ unlocked: [] as string[],
416
+ settings: { sfx: true, music: 1.0 },
417
+ });
418
+ ```
419
+
420
+ Then `app.data.set('score', 100)` / `app.data.get('score')` are fully typed.
421
+
422
+ ### 4.5 Full `AppConfig` key table
423
+
424
+ Every allowed key in `caper.config.ts`. Defer shape details to
425
+ [src/core/interfaces/IApplicationOptions.ts](../src/core/interfaces/IApplicationOptions.ts).
426
+
427
+ | Key | Purpose |
428
+ | --- | --- |
429
+ | `id: string` | Required. Unique app ID. |
430
+ | `application?: typeof Application` | Custom Application subclass. |
431
+ | `defaultScene?: string` | Scene ID to load first. Typed via `AppScenes` union. |
432
+ | `sceneTransition?: typeof SceneTransition` | Transition animation class. |
433
+ | `defaultSceneLoadMethod?: LoadSceneMethod` | `'immediate' \| 'exitEnter' \| 'enterExit' \| 'enterBehind' \| 'transitionExitEnter' \| 'exitTransitionEnter'` |
434
+ | `sceneGroupOrder?: string[]` | Order for the debug scene picker. |
435
+ | `useSpine?: boolean` | Enable Spine 2D integration. |
436
+ | `useLayout?: boolean` | Enable `@pixi/layout` (Yoga flexbox). Required for FlexContainer. |
437
+ | `useVoiceover?: boolean` | Enable VO + captions subsystem. |
438
+ | `useStore?: boolean` | Enable reactive store. |
439
+ | `useHash?: boolean` | Use URL hash for scene nav (deep links). |
440
+ | `showSceneDebugMenu?: boolean` | Dev-only in-app scene picker. |
441
+ | `showStats?: boolean` | Show PixiJS stats overlay. |
442
+ | `defaultTextStyle?: Partial<TextStyle>` | Global text defaults. |
443
+ | `defaultDropShadow?: TextDropShadow` | Global drop shadow defaults. |
444
+ | `gsap?: Partial<GSAPPluginOptions>` | GSAP config + custom eases. |
445
+ | `data?: Partial<IDataAdapterOptions>` | `{ initial, backupKeys }` for the store. |
446
+ | `actions?: ActionMap` | Registered actions (from `defineActions`). |
447
+ | `input?: { controls }` | Input bindings (from `defineControls`). |
448
+ | `focus?: { outliner? }` | Focus subsystem (keyboard/gamepad nav). |
449
+ | `assets?: AssetLoadingOptions` | `{ preload: { bundles }, background: { bundles } }` |
450
+ | `plugins?: PluginConfig[]` | **Source of truth for which plugins run.** |
451
+ | `i18n?: i18nOptions` | Locales + file map. |
452
+ | `captions?: CaptionsOptions` | Closed-captions config. |
453
+ | `resizer?: ResizerPluginOptions` | `{ minWidth, minHeight, letterbox, center }` viewport shape. |
454
+ | `resizeToContainer?: boolean` | Auto-fit canvas to the mount element. |
455
+ | `autoDensity?: boolean` | PixiJS DPI handling. |
456
+ | `resolution?: number` | DPI scale factor. |
457
+ | `splash?: SplashOptions` | Splash screen config. |
458
+ | `logger?: LoggerMode` | Verbosity. |
459
+
460
+ Plus all standard PixiJS `ApplicationOptions` (`antialias`, `width`, `height`, etc.).
461
+
462
+ **Scene/plugin/popup/entity registrations are NOT in this table** — they're
463
+ discovered from disk. Plugins list above is the one exception.
464
+
465
+ ### 4.6 `plugins: [...]` tuple forms
466
+
467
+ ```ts
468
+ plugins: [
469
+ 'my-local-plugin', // string ID only — loads with default options
470
+ 'google-analytics',
471
+ ['crunch', { autoLoad: false }], // tuple: defer initialization
472
+ ['rive', { autoLoad: false }],
473
+ ['rollbar', { options: { isDev: true } }], // tuple: pass options
474
+ 'firebase',
475
+ ]
476
+ ```
477
+
478
+ `autoLoad: false` defers `initialize()` until you call
479
+ `app.loadPlugin('rive')`. Options are passed to the plugin's `initialize()`.
480
+
481
+ **Source references:** [src/utils/define.ts](../src/utils/define.ts),
482
+ [src/core/config.ts](../src/core/config.ts),
483
+ [src/core/interfaces/IApplicationOptions.ts](../src/core/interfaces/IApplicationOptions.ts).
484
+
485
+ ---
486
+
487
+ ## 5. Scene lifecycle
488
+
489
+ ### 5.1 Class shape
490
+
491
+ ```ts
492
+ export class Scene<Props = void> extends Container implements IScene {
493
+ public readonly id: string;
494
+ public props: Props; // set before initialize() runs
495
+ public autoUnloadAssets: boolean = false;
496
+ public assets: SceneAssets;
497
+
498
+ async preloadAssets(): Promise<void> // load scene-specific bundles
499
+ async initialize(): Promise<void> // build display tree
500
+ enter(fromScene?): Promise<any> // animate in
501
+ async start(): Promise<void> // gameplay hook
502
+ update(ticker): void // per-frame (inherited from Container)
503
+ exit(toScene?): Promise<any> // animate out
504
+ destroy(options): void // cleanup
505
+ }
506
+ ```
507
+
508
+ Signatures in [src/display/Scene.ts](../src/display/Scene.ts).
509
+
510
+ ### 5.2 Lifecycle order
511
+
512
+ 1. `preloadAssets()` — assets declared on the scene are loaded here.
513
+ 2. `initialize(props)` — display tree constructed; `this.props` is populated.
514
+ 3. `enter(fromScene)` — entry animation; awaited before next hook.
515
+ 4. `start()` — ready to play.
516
+ 5. `update(ticker)` — every frame.
517
+ 6. `exit(toScene)` — exit animation; awaited before unload.
518
+ 7. `destroy()` — resources freed. `WithSignals` auto-disconnects connections.
519
+
520
+ **`this.props` is populated before `initialize()` runs**, by the
521
+ SceneManagerPlugin after construction. Safe to read from any lifecycle hook.
522
+
523
+ ### 5.3 Declaring scene assets
524
+
525
+ Module-level export on the scene file:
526
+
527
+ ```ts
528
+ // src/scenes/Level.ts
529
+ import { defineScene, Scene, SceneAssets } from '@caperjs/core';
530
+
531
+ export const scene = defineScene({ id: 'level' });
532
+
533
+ export const assets: SceneAssets = {
534
+ preload: { bundles: ['level-1'] },
535
+ background: { bundles: ['level-1-optional'] },
536
+ autoUnload: true, // unload when leaving the scene
537
+ };
538
+
539
+ export default class LevelScene extends Scene { /* ... */ }
540
+ ```
541
+
542
+ Bundle IDs come from folder names under `assets/` (see §11). Bundles that
543
+ don't exist fail build-time validation with a warning.
544
+
545
+ ### 5.4 Declaring required plugins
546
+
547
+ ```ts
548
+ export const plugins: ScenePlugins = ['rive', 'crunch'];
549
+ ```
550
+
551
+ These plugins must be present in `caper.config.ts plugins: []`; they'll be
552
+ loaded before this scene enters. Typos fail at compile time via the
553
+ `AppTypeOverrides['Plugins']` union.
554
+
555
+ ### 5.5 Typed scene props
556
+
557
+ ```ts
558
+ class LevelScene extends Scene<{ levelId: number; difficulty: 'easy' | 'hard' }> {
559
+ async start() {
560
+ const { levelId } = this.props; // typed
561
+ }
562
+ }
563
+ ```
564
+
565
+ Load it typed:
566
+
567
+ ```ts
568
+ app.scenes.load('level', { levelId: 3, difficulty: 'easy' });
569
+ ```
570
+
571
+ ### 5.6 Switching scenes
572
+
573
+ `app.scenes.load(id, props?)` from `SceneManagerPlugin`. Transition shape
574
+ controlled by the config's `defaultSceneLoadMethod` (one of: `immediate`,
575
+ `exitEnter`, `enterExit`, `enterBehind`, `transitionExitEnter`,
576
+ `exitTransitionEnter`) or by providing an explicit method argument.
577
+
578
+ Scene-change signals:
579
+ - `app.scenes.onSceneChangeStart.connect(scene => { ... })`
580
+ - `app.scenes.onSceneChangeComplete.connect(scene => { ... })`
581
+
582
+ ### 5.7 `SceneTransition`
583
+
584
+ Provide a class extending `SceneTransition` for the config's `sceneTransition`
585
+ key. It's a full-screen container that overlays between scenes:
586
+
587
+ ```ts
588
+ // src/scenes/Transition.ts
589
+ import { SceneTransition } from '@caperjs/core';
590
+ import { gsap } from 'gsap';
591
+
592
+ export class Transition extends SceneTransition {
593
+ private _cover: Graphics;
594
+
595
+ initialize() {
596
+ this._cover = this.add.graphics();
597
+ this._cover.rect(0, 0, this.app.size.width, this.app.size.height).fill(0x000000);
598
+ this._cover.alpha = 0;
599
+ }
600
+
601
+ async enter() {
602
+ await gsap.to(this._cover, { alpha: 1, duration: 0.3 });
603
+ }
604
+
605
+ async exit() {
606
+ await gsap.to(this._cover, { alpha: 0, duration: 0.3 });
607
+ }
608
+ }
609
+ ```
610
+
611
+ Splash screen hide-when: `splash: { hideWhen: 'firstSceneEnter' | 'requiredAssetsLoaded' }`.
612
+
613
+ **Source references:** [src/display/Scene.ts](../src/display/Scene.ts),
614
+ [src/display/SceneTransition.ts](../src/display/SceneTransition.ts),
615
+ [src/plugins/SceneManagerPlugin.ts](../src/plugins/SceneManagerPlugin.ts).
616
+
617
+ ---
618
+
619
+ ## 6. Factory methods: `add.*` / `make.*`
620
+
621
+ Every `Container` subclass in Caper has both `add` and `make`:
622
+ - `this.add.sprite({...})` — creates the object **and** addChilds it to `this`.
623
+ - `this.make.sprite({...})` — creates and returns detached.
624
+
625
+ Definition in [src/mixins/factory/const.ts](../src/mixins/factory/const.ts)
626
+ (`defaultFactoryMethods`), props in
627
+ [src/mixins/factory/props.ts](../src/mixins/factory/props.ts). Wrapped by
628
+ `Factory()` mixin in [src/mixins/factory/Factory.ts](../src/mixins/factory/Factory.ts).
629
+
630
+ ### 6.1 Full catalog
631
+
632
+ | Method | Shape / notable keys |
633
+ | --- | --- |
634
+ | `existing(entity, props?)` | Wrap an already-instantiated object with position/scale/pivot/anchor resolution. Use for 3rd-party or hand-constructed instances. |
635
+ | `container(props?)` | `ContainerProps`. A `@caperjs/core` Container (Animated + WithSignals + Factory). |
636
+ | `particleContainer(props?)` | `ParticleContainerProps`. |
637
+ | `sprite(props?)` | `{ asset, sheet, anchor, x, y, scale, alpha, label, layout, ... }`. `asset` is a string ID from the asset manifest — **not** a raw Texture. |
638
+ | `tilingSprite(props?)` | Same as sprite + tiling. |
639
+ | `animatedSprite(props?)` | `{ sheet, animations, animation, autoPlay, autoUpdate, animationSpeed, ... }`. |
640
+ | `graphics(props?)` | Empty Graphics; draw on it afterwards. |
641
+ | `svg({ ctx, ... })` | Pixi Graphics from SVG context. `ctx` required. |
642
+ | `text(props?)` | `{ text, style: { fontFamily, fontSize, fill, ... }, anchor, roundPixels, layout, ... }`. Text style is **flattened** at the top level (no nested `{ style: {} }` required). |
643
+ | `htmlText(props?)` | Same shape as `text`, uses Pixi `HTMLText`. Note: only sees fonts loaded via `loadWebFont` — not CSS @font-face. |
644
+ | `bitmapText(props?)` | Same as `text`; no `resolution`. |
645
+ | `button(props)` | See §7.2. `textures.default` required. |
646
+ | `flexContainer(props?)` | See §7.1. Yoga flexbox. |
647
+ | `uiCanvas(props?)` | See §7.5. Root UI layer. |
648
+ | `spine(props?)` | `{ data: 'spine/foo', autoUpdate, animationName, loop, trackIndex }`. `data` is the asset name without extension; skeleton + atlas auto-resolved. |
649
+ | `spineAnimation<Names>(props?)` | Wrapper with typed animation-name generic. |
650
+ | `popup(...)` | Popup construction (normally use `app.popups.show(id)` instead). |
651
+ | `particles(props?)` | Particle emitter. |
652
+ | `toaster(config?, defaultToastConfig?)` | Toast notification container. |
653
+ | `entity(id, props?)` | Construct from discovered entity registry. `id` narrowed to `AppEntities`. |
654
+ | `ui(id, props?)` | Construct from discovered UI registry. |
655
+
656
+ ### 6.2 Common props (applied across the catalog)
657
+
658
+ Most methods auto-resolve these from a single props object:
659
+
660
+ ```ts
661
+ {
662
+ x, y, position, // PositionProps
663
+ scale, scaleX, scaleY, // ScaleProps
664
+ pivot, // PivotProps
665
+ anchor, // (sprite-like only)
666
+ label, alpha, visible, eventMode, // AbstractProps / VisibilityProps
667
+ layout: { ... }, // LayoutProps — @pixi/layout keys
668
+ }
669
+ ```
670
+
671
+ ### 6.3 Canonical snippet
672
+
673
+ Composition of a title + body inside a vertically-centered flex container:
674
+
675
+ ```ts
676
+ this.container = this.add.flexContainer({
677
+ bindToAppSize: true,
678
+ layout: { flexDirection: 'column', alignItems: 'center', gap: 5 },
679
+ });
680
+
681
+ this.mascot = this.add.sprite({
682
+ asset: 'logo', // name from the asset manifest
683
+ anchor: 0.5,
684
+ scale: 0.35,
685
+ y: -150,
686
+ });
687
+
688
+ this.container.add.text({
689
+ text: 'GAME TITLE',
690
+ style: { fontFamily: 'MyFont', fontSize: 42, fill: 0xffffff },
691
+ layout: { marginTop: 100 },
692
+ });
693
+ ```
694
+
695
+ ### 6.4 Extending the factory
696
+
697
+ Add project-specific factories via `Factory(extensions)`:
698
+
699
+ ```ts
700
+ class MyContainer extends Factory({ customBadge: (props) => new Badge(props) }) {}
701
+ const c = new MyContainer();
702
+ c.add.customBadge({ /* ... */ });
703
+ ```
704
+
705
+ **Source references:** [src/mixins/factory/const.ts](../src/mixins/factory/const.ts),
706
+ [src/mixins/factory/props.ts](../src/mixins/factory/props.ts),
707
+ [src/mixins/factory/Factory.ts](../src/mixins/factory/Factory.ts).
708
+
709
+ ---
710
+
711
+ ## 7. UI primitives
712
+
713
+ All under [src/ui/](../src/ui/). Instantiate via `this.add.*` whenever
714
+ possible — raw `new FlexContainer(...)` works but misses the parenting +
715
+ factory resolution.
716
+
717
+ ### 7.1 `FlexContainer` — Yoga flexbox
718
+
719
+ Backed by `@pixi/layout`. Requires `useLayout: true` in config. Signature at
720
+ [src/ui/FlexContainer.ts](../src/ui/FlexContainer.ts).
721
+
722
+ ```ts
723
+ this.add.flexContainer({
724
+ bindTo?: ContainerLike, // bind size to another container
725
+ bindToAppSize?: boolean, // bind to app viewport
726
+ autoLayoutChildren?: boolean, // default true — marks children as leaves
727
+ layout?: {
728
+ flexDirection?: 'row' | 'column' | 'row-reverse' | 'column-reverse',
729
+ justifyContent?: 'center' | 'space-between' | 'space-around' | 'space-evenly' | 'flex-start' | 'flex-end',
730
+ alignItems?: 'center' | 'flex-start' | 'flex-end' | 'stretch' | 'baseline',
731
+ flexWrap?: 'wrap' | 'nowrap' | 'wrap-reverse',
732
+ gap?: number,
733
+ padding?: number, paddingTop?: number, paddingRight?: number, /* ... */
734
+ margin?: number, marginTop?: number, /* ... */
735
+ width?: SizeNumber, // number | 'auto' | 'intrinsic'
736
+ height?: SizeNumber,
737
+ },
738
+ debug?: boolean, // debug overlay
739
+ });
740
+ ```
741
+
742
+ Child layout metadata goes on the child's `layout` prop — `this.container.add.text({ layout: { flexGrow: 1 } })`.
743
+
744
+ ### 7.2 `Button` — interactive state machine
745
+
746
+ [src/ui/Button.ts](../src/ui/Button.ts). Four texture states
747
+ (`default`, `hover`, `active`, `disabled`), four sound slots (`hover`, `out`,
748
+ `down`, `click`), action dispatch, keyboard/focus integration.
749
+
750
+ ```ts
751
+ this.add.button({
752
+ id: 'play',
753
+ textures: {
754
+ default: 'button/default',
755
+ hover: 'button/hover',
756
+ active: 'button/active',
757
+ disabled: 'button/disabled',
758
+ },
759
+ sounds: { click: 'click', hover: 'hover' },
760
+ action: { id: 'start_game', data: { level: 1 } }, // dispatches via app.actions
761
+ label: { text: 'Play', style: { fontSize: 24 } }, // optional child text
762
+ anchor: 0.5,
763
+ });
764
+ ```
765
+
766
+ Signals on the button: `onDown`, `onUp`, `onOver`, `onOut`, `onClick`,
767
+ `onEnabled`, `onDisabled`, `onKeyboardEvent`, `onDestroy`.
768
+
769
+ ### 7.3 `Popup` — focus-aware modal
770
+
771
+ [src/ui/Popup.ts](../src/ui/Popup.ts). Extends `Container`,
772
+ implements `IPopup<T>`. Pushed/popped by the PopupManager, participates in
773
+ the focus stack and action context.
774
+
775
+ ```ts
776
+ // src/popups/Confirm.ts
777
+ import { Container, definePopup, IPopup, Popup } from '@caperjs/core';
778
+
779
+ export const popup = definePopup({ id: 'confirm', active: true });
780
+
781
+ export default class ConfirmPopup extends Popup<{ title: string; onOk: () => void }> implements IPopup {
782
+ initialize() {
783
+ // access this.config.data.title (typed via generic)
784
+ // access this.backing (backdrop), this.view (content)
785
+ }
786
+ async show() { /* entrance animation */ }
787
+ async hide() { /* exit animation */ }
788
+ }
789
+ ```
790
+
791
+ Show from anywhere:
792
+
793
+ ```ts
794
+ app.popups.showPopup('confirm', { data: { title: 'Delete save?', onOk: doDelete } });
795
+ app.popups.hidePopup('confirm');
796
+ ```
797
+
798
+ ### 7.4 `Toast` / `Toaster`
799
+
800
+ Programmatic toast notifications. Build a `Toaster` via `this.add.toaster()`
801
+ then push toasts to it. Also available as `app.popups.toast(...)`.
802
+
803
+ ### 7.5 `UICanvas` — HUD root layer
804
+
805
+ A FlexContainer preset for app-size-bound HUDs. Use as the root of in-game UI.
806
+
807
+ ### 7.6 `Joystick` — virtual stick
808
+
809
+ For touch input. Wires into the `controls.touch.joystick` bindings set via
810
+ `defineControls`.
811
+
812
+ ### 7.7 `Input` — text input
813
+
814
+ Pixi-native text input primitive. Limited (no browser IME) — acceptable for
815
+ game HUDs, not rich text forms.
816
+
817
+ **Source references:** [src/ui/FlexContainer.ts](../src/ui/FlexContainer.ts),
818
+ [src/ui/Button.ts](../src/ui/Button.ts),
819
+ [src/ui/Popup.ts](../src/ui/Popup.ts),
820
+ [src/ui/Toast.ts](../src/ui/Toast.ts),
821
+ [src/ui/Toaster.ts](../src/ui/Toaster.ts),
822
+ [src/ui/UICanvas.ts](../src/ui/UICanvas.ts),
823
+ [src/ui/Joystick.ts](../src/ui/Joystick.ts),
824
+ [src/ui/Input.ts](../src/ui/Input.ts).
825
+
826
+ ---
827
+
828
+ ## 8. Built-in plugins (on `app`)
829
+
830
+ Registered by default — **do not** list them in `plugins: [...]`. Source:
831
+ [src/plugins/defaults.ts](../src/plugins/defaults.ts).
832
+
833
+ | ID | `app.X` | Primary methods |
834
+ | --- | --- | --- |
835
+ | `lookup` | `app.lookup` | `add(id, obj)`, `get(id)`, `remove(id)` — id-based game-object registry. |
836
+ | `webEvents` | `app.webEvents` | `onResize`, `onVisibilityChange`, `onBlur`, `onFocus` signals. |
837
+ | `fullscreen` | `app.fullscreen` | `toggle()`, `enter()`, `exit()`, `isActive`. |
838
+ | `resizer` | `app.resizer` | `onResize` signal + `size`, driven by `config.resizer`. |
839
+ | `assets` | `app.assets` | `loadAssets(list)`, `loadBundles(ids)`, `loadSceneAssets(scene)`, `unloadSceneAssets(scene)`. Signals: `onLoadStart`, `onLoadProgress`, `onLoadComplete`, required / background variants. |
840
+ | `scenes` | `app.scenes` | `load(id, props)`, `onSceneChangeStart`, `onSceneChangeComplete`, `current`. |
841
+ | `actions` | `app.actions(id)` | Returns the action's signal. `.connect(cb, order?)`. |
842
+ | `input` | `app.input` | Pointer / gamepad / touch state. |
843
+ | `keyboard` | `app.keyboard` | Raw keyboard listener. Normally use `actions` instead. |
844
+ | `focus` | `app.focus` | `add(entity, layerId, active)`, `addFocusLayer(id)`, `removeFocusLayer(id)`, `setFocusLayer(id)`. Outliner provided via `config.focus.outliner`. |
845
+ | `popups` | `app.popups` | `showPopup(id, config?)`, `hidePopup(id)`, `toast(config)`. |
846
+ | `audio` | `app.audio` | `play(id, opts)`, `stop`, `pause`, groups (`music`, `sfx`, `vo`). |
847
+ | `i18n` | `app.i18n` | `t(key, params?)`, `setLocale(id)`, `currentLocale`. Keys typed via `AppLocaleKeys`. |
848
+ | `timers` | `app.timers` | `delay(ms)`, `every(ms, cb)`, scene-scoped via `WithSignals`. |
849
+
850
+ Access any plugin by ID: `app.getPlugin('firebase')`. Typed via
851
+ `AppTypeOverrides['Plugins']` — typos fail at compile time.
852
+
853
+ **Source references:** [src/plugins/defaults.ts](../src/plugins/defaults.ts)
854
+ for the full list, individual plugin sources under [src/plugins/](../src/plugins/).
855
+
856
+ ---
857
+
858
+ ## 9. Plugin authoring
859
+
860
+ Sources: [src/plugins/Plugin.ts](../src/plugins/Plugin.ts), template at
861
+ [cli/add.mjs](../cli/add.mjs).
862
+
863
+ ### 9.1 Scaffolding
864
+
865
+ Preferred: `caper add plugin <Name>` — drops a file with the right shape for a
866
+ **local** plugin under `src/plugins/`. For a new **publishable** plugin
867
+ package, in the Caper monorepo run `pnpm plugin:create` which scaffolds a
868
+ full `packages/plugin-<name>/` workspace package.
869
+
870
+ ### 9.2 Anatomy
871
+
872
+ ```ts
873
+ // src/plugins/MyPlugin.ts
874
+ import { definePlugin, IApplication, Plugin } from '@caperjs/core';
875
+
876
+ export const plugin = definePlugin({
877
+ id: 'my-plugin',
878
+ active: true,
879
+ // requires: ['firebase'], // optional dependency ordering
880
+ });
881
+
882
+ export type MyPluginOptions = { verbose?: boolean };
883
+
884
+ export default class MyPlugin extends Plugin<MyPluginOptions> {
885
+ public readonly id = plugin.id;
886
+ protected _options: MyPluginOptions = {};
887
+
888
+ async initialize(options: Partial<MyPluginOptions> = {}, app: IApplication): Promise<void> {
889
+ this._options = { ...this._options, ...options };
890
+ // set up state, register signal connections, etc.
891
+ }
892
+
893
+ async postInitialize(app: IApplication): Promise<void> {
894
+ // All other plugins have initialized. Safe to look up siblings:
895
+ // const firebase = app.getPlugin('firebase');
896
+ }
897
+
898
+ destroy(): void {
899
+ super.destroy();
900
+ }
901
+ }
902
+ ```
903
+
904
+ ### 9.3 Lifecycle
905
+
906
+ 1. Constructor — no `app` yet.
907
+ 2. `initialize(options, app)` — ordered by `requires` (topological sort). Required
908
+ deps are guaranteed initialized first.
909
+ 3. `postInitialize(app)` — every plugin's `initialize` has resolved.
910
+ 4. (use) — signal handlers fire, methods called.
911
+ 5. `destroy()` — signal connections auto-disconnect via `WithSignals`.
912
+
913
+ ### 9.4 `requires: [...]` rules
914
+
915
+ - Listed dep IDs must exist in `caper.config.ts plugins: []` (see §1.1). Bootstrap
916
+ throws with an actionable error if not.
917
+ - Cycles fail bootstrap with the cycle path printed.
918
+ - Build-time validation also warns at `caper dev`/`build` time.
919
+
920
+ ### 9.5 Exposing API
921
+
922
+ ```ts
923
+ export default class MyPlugin extends Plugin {
924
+ public readonly id = 'my-plugin';
925
+
926
+ public readonly onSomething = new Signal<(x: number) => void>();
927
+
928
+ // Public methods are accessible via:
929
+ // app.getPlugin('my-plugin').doThing()
930
+ // — or, if you publish core functions:
931
+ protected getCoreFunctions(): string[] { return ['doThing']; }
932
+ protected getCoreSignals(): string[] { return ['onSomething']; }
933
+
934
+ doThing() { /* ... */ }
935
+ }
936
+ ```
937
+
938
+ ### 9.6 Storage adapters
939
+
940
+ A plugin that implements `IStorageCapability` (has `save(key, data)` and
941
+ `load(key)` methods) is **automatically** picked up by `app.store`. No separate
942
+ registration. The first-party `@caperjs/plugin-firebase` package is the reference
943
+ implementation. See §12.2.
944
+
945
+ ### 9.7 Fail-loud in `initialize`
946
+
947
+ Throw with actionable messages. Bootstrap catches plugin init errors and routes
948
+ through a `pluginError` signal — but only so a later plugin doesn't block the
949
+ whole boot; it doesn't hide anything from the user.
950
+
951
+ **Source references:** [src/plugins/Plugin.ts](../src/plugins/Plugin.ts),
952
+ [src/plugins/defaults.ts](../src/plugins/defaults.ts),
953
+ [src/core/registries.ts](../src/core/registries.ts).
954
+
955
+ ---
956
+
957
+ ## 10. Display objects beyond UI
958
+
959
+ Under [src/display/](../src/display/).
960
+
961
+ | Class | Purpose |
962
+ | --- | --- |
963
+ | `Container` | Base container. Mixes in `Animated` + `WithSignals` + `Factory`. Has `addColoredBackground(color, alpha)`, `onDestroy` signal, `autoResize` / `autoUpdate` / `priority` options. |
964
+ | `Entity` | Extends `Container`. Use for game objects discovered under `src/entities/`. Paired with `defineEntity({ id })`. |
965
+ | `Scene` | Extends `Container`. See §5. |
966
+ | `SceneTransition` | Full-screen entry/exit animation container. |
967
+ | `AnimatedSprite` | Caper wrapper over PixiJS AnimatedSprite — accepts `{ sheet, animations, animation, autoPlay, autoUpdate, animationSpeed }`. |
968
+ | `SpineAnimation<Names>` | Typed Spine wrapper. Animation-name union via generic. |
969
+ | `ParticleContainer` | Pixi ParticleContainer with Caper factory/resolve semantics. |
970
+ | `Svg` | Graphics from SVG context. |
971
+ | `Camera` | Camera controller for following/constraining entities. |
972
+
973
+ ### 10.1 Entity example
974
+
975
+ ```ts
976
+ // src/entities/Hero.ts
977
+ import type { Spine } from '@caperjs/core';
978
+ import { Container, defineEntity, Interactive } from '@caperjs/core';
979
+ import { Rectangle } from 'pixi.js';
980
+
981
+ export const entity = defineEntity({ id: 'hero', active: true });
982
+
983
+ export class Hero extends Interactive(Container) {
984
+ private _spine: Spine;
985
+
986
+ constructor() {
987
+ super();
988
+ this._spine = this.add.spine({ data: 'spine/hero', autoUpdate: true, loop: true });
989
+ }
990
+
991
+ added() {
992
+ this.eventMode = 'static';
993
+ this.cursor = 'pointer';
994
+ this.hitArea = new Rectangle(-350, -500, 500, 500);
995
+ this.onInteraction('pointerdown').connect(() => this._next());
996
+ }
997
+
998
+ _next() { /* cycle animation */ }
999
+ }
1000
+
1001
+ export default Hero;
1002
+ ```
1003
+
1004
+ Use from a scene:
1005
+
1006
+ ```ts
1007
+ this.hero = this.add.entity('hero'); // typed via AppEntities union
1008
+ ```
1009
+
1010
+ **Source references:** [src/display/Container.ts](../src/display/Container.ts),
1011
+ [src/display/Entity.ts](../src/display/Entity.ts),
1012
+ [src/display/SpineAnimation.ts](../src/display/SpineAnimation.ts),
1013
+ [src/display/AnimatedSprite.ts](../src/display/AnimatedSprite.ts),
1014
+ [src/display/Camera.ts](../src/display/Camera.ts),
1015
+ [src/display/ParticleContainer.ts](../src/display/ParticleContainer.ts),
1016
+ [src/display/Svg.ts](../src/display/Svg.ts).
1017
+
1018
+ ---
1019
+
1020
+ ## 11. Assets & AssetPack
1021
+
1022
+ AssetPack is a build-time asset compiler that generates `assets.json` + optimized
1023
+ outputs from an `assets/` folder. Caper's Vite plugin wires it automatically.
1024
+
1025
+ ### 11.1 Folder → bundle mapping
1026
+
1027
+ A folder under `assets/` **is** a bundle. Bundle IDs are the folder names.
1028
+ The `{m}` suffix means multi-resolution (AssetPack auto-generates 1x, 2x, etc.).
1029
+
1030
+ ```
1031
+ assets/
1032
+ splash{m}/ → bundle 'splash'
1033
+ required{m}/ → bundle 'required'
1034
+ game{m}/ → bundle 'game'
1035
+ audio{m}/ → bundle 'audio'
1036
+ spine{m}/ → bundle 'spine'
1037
+ kenney{m}/ → bundle 'kenney'
1038
+ ```
1039
+
1040
+ Preload / background wiring in `caper.config.ts`:
1041
+
1042
+ ```ts
1043
+ assets: {
1044
+ preload: { bundles: ['splash', 'required', 'game'] }, // gated before first scene
1045
+ background: { bundles: ['audio', 'spine'] }, // loaded concurrently post-boot
1046
+ }
1047
+ ```
1048
+
1049
+ Scene-specific assets declared at module level — see §5.3.
1050
+
1051
+ ### 11.2 AssetPack filename tag reference
1052
+
1053
+ Tags appear inside `{...}` in source filenames. AssetPack extracts them pre-build.
1054
+
1055
+ | Tag | Effect |
1056
+ | --- | --- |
1057
+ | `{family=Name}` | Web-font family name. **Must be whitespace-free.** See §16.1. |
1058
+ | `{weight=bold}` | Font weight. Caper's `fontWeights` pipe converts this to the `weights: ['bold']` array PixiJS `loadWebFont` expects. |
1059
+ | `{resolution=2x}` / `{m}` | Multi-resolution variant. `{m}` on a folder auto-detects 1x/2x. |
1060
+ | `{wf}` | Mark this file as a web font. |
1061
+ | `{fix}` | Fix alpha pre-multiplication. |
1062
+ | `{nc}` | No cache bust in production (use sparingly). |
1063
+ | `{spine}` | Mark as Spine bundle. |
1064
+ | `{rive}` | Mark as Rive bundle. |
1065
+
1066
+ Example:
1067
+
1068
+ ```
1069
+ assets/fonts{fix}/SpaceGrotesk-Bold{family=SpaceGrotesk}{weight=bold}{wf}.ttf
1070
+ ↑ file ↑ strict: no whitespace ↑ pipe converts
1071
+ ```
1072
+
1073
+ ### 11.3 Framework AssetPack config
1074
+
1075
+ Default pipes at [config/assetpack.mjs](../config/assetpack.mjs). Includes
1076
+ compression, spritesheets, webfonts, audio, Spine, Rive, and the custom
1077
+ **`fontWeights`** pipe that runs before the webfont pipe to convert
1078
+ `{weight=X}` to `weights: [X]` for PixiJS.
1079
+
1080
+ ### 11.4 Per-app override: `.assetpack.mjs`
1081
+
1082
+ If `.assetpack.mjs` exists at the app root, Caper's framework config loads it
1083
+ via `import()` and merges it in. Only needed when injecting custom pipes.
1084
+
1085
+ ### 11.5 Loading from code
1086
+
1087
+ ```ts
1088
+ // Individual assets
1089
+ await app.assets.loadAssets(['hero', 'enemy']);
1090
+
1091
+ // Whole bundle
1092
+ await app.assets.loadBundles('level-1');
1093
+
1094
+ // Progress signals
1095
+ app.assets.onLoadProgress.connect(p => console.log(`${p * 100}%`));
1096
+ app.assets.onLoadComplete.connect(() => { /* ready */ });
1097
+ ```
1098
+
1099
+ Asset names in `this.add.sprite({ asset: 'hero' })` are resolved against the
1100
+ manifest. Unknown names fail at runtime with a named error.
1101
+
1102
+ **Source references:** [config/assetpack.mjs](../config/assetpack.mjs),
1103
+ [src/plugins/AssetsPlugin.ts](../src/plugins/AssetsPlugin.ts).
1104
+
1105
+ ---
1106
+
1107
+ ## 12. Signals, Store, mixins
1108
+
1109
+ ### 12.1 Signals (typed, priority-ordered)
1110
+
1111
+ Based on `typed-signals`. See [src/signals/Signal.ts](../src/signals/Signal.ts).
1112
+
1113
+ ```ts
1114
+ import { Signal, SignalConnections } from '@caperjs/core';
1115
+
1116
+ const onPowerup = new Signal<(kind: 'life' | 'coin', n: number) => void>();
1117
+
1118
+ const c = onPowerup.connect((kind, n) => { /* ... */ });
1119
+ onPowerup.connectOnce(cb);
1120
+ onPowerup.connectNTimes(cb, 3);
1121
+
1122
+ // Emit
1123
+ onPowerup.emit('life', 1);
1124
+
1125
+ // Priorities (higher = earlier): 'highest' | 'higher' | 'high' | 'normal' | 'low' | 'lower' | 'lowest' | number
1126
+ onPowerup.connect(cb, 'highest');
1127
+ ```
1128
+
1129
+ `WithSignals` mixin (applied to Container/Scene/Entity/Plugin) auto-disconnects
1130
+ all connections on `destroy()`. Use `addSignalConnection(conn)` to register a
1131
+ connection for auto-cleanup.
1132
+
1133
+ Common framework signals:
1134
+ - `app.onResize`, `app.webEvents.onVisibilityChange`
1135
+ - `app.scenes.onSceneChangeStart`, `onSceneChangeComplete`
1136
+ - `app.assets.onLoadStart`, `onLoadProgress`, `onLoadComplete`
1137
+ - `scene.onDestroy`, `button.onClick`, `popup.onHide`
1138
+
1139
+ ### 12.2 Store (uniform storage-adapter facade)
1140
+
1141
+ See [src/store/Store.ts](../src/store/Store.ts).
1142
+
1143
+ ```ts
1144
+ // Save to the firebase adapter
1145
+ await app.store.save('firebase', 'playerData', { score: 100 });
1146
+
1147
+ // Load
1148
+ const data = await app.store.load('firebase', 'playerData');
1149
+
1150
+ // Save to all storage-capable plugins
1151
+ await app.store.save('*', 'playerData', data);
1152
+
1153
+ // Type-safe adapter lookup
1154
+ const firebase = app.store.getAdapter<IFirebasePlugin>('firebase');
1155
+
1156
+ // Error signal
1157
+ app.store.onError.connect(({ adapterId, operation, key, error }) => { /* ... */ });
1158
+ ```
1159
+
1160
+ Adapters = any plugin implementing `IStorageCapability`. Discovered
1161
+ automatically; no separate registration.
1162
+
1163
+ ### 12.3 Mixins
1164
+
1165
+ All under [src/mixins/](../src/mixins/). Composable via function calls:
1166
+
1167
+ ```ts
1168
+ class MyThing extends Focusable(Interactive(Container)) {}
1169
+ ```
1170
+
1171
+ | Mixin | Adds |
1172
+ | --- | --- |
1173
+ | `Animated` | GSAP-driven `animate(props)`, `animateFrom`, `animateFromTo`, `animateSequence`, `shake(config?)`, `pulse(config?)`, `bob(config?)`. Signals `onAnimationStart/Update/Complete`. `pauseAnimations()`, `resumeAnimations()`. |
1174
+ | `WithSignals` | `signalConnections` collection; `addSignalConnection(c)`; auto-disconnect on `destroy()`. Use `connectAction(...)` for action-scoped connections. |
1175
+ | `Factory(extensions?)` | `this.add.*` / `this.make.*`. See §6. |
1176
+ | `Interactive` | Pointer-event signals: `onInteraction('pointerdown' | 'pointerup' | 'pointerover' | 'pointerout' | 'pointerupoutside' | 'pointermove').connect(cb)`. |
1177
+ | `Focusable` | Participates in keyboard/gamepad focus stack. Works with `app.focus`. |
1178
+
1179
+ **Source references:** [src/signals/Signal.ts](../src/signals/Signal.ts),
1180
+ [src/store/Store.ts](../src/store/Store.ts),
1181
+ [src/mixins/animated.ts](../src/mixins/animated.ts),
1182
+ [src/mixins/signals.ts](../src/mixins/signals.ts),
1183
+ [src/mixins/interaction.ts](../src/mixins/interaction.ts),
1184
+ [src/mixins/focus.ts](../src/mixins/focus.ts).
1185
+
1186
+ ---
1187
+
1188
+ ## 13. First-party plugins (`@caperjs/plugin-*`)
1189
+
1190
+ Each is a separate npm package. Install → list in `plugins: [...]` → use via
1191
+ `app.getPlugin(id)` or a typed getter on a custom `Application` subclass.
1192
+
1193
+ | Package | ID | Purpose |
1194
+ | --- | --- | --- |
1195
+ | `@caperjs/plugin-firebase` | `firebase` | Firebase Firestore save/load. Implements `IStorageCapability` → auto-registered with `app.store`. |
1196
+ | `@caperjs/plugin-rive` | `rive` | Rive animation runtime. `RiveEntity` for scene-level use. |
1197
+ | `@caperjs/plugin-colyseus` | `colyseus` | Colyseus multiplayer rooms. |
1198
+ | `@caperjs/plugin-google-analytics` | `google-analytics` | GA event tracking. Generic `IGoogleAnalyticsPlugin<Events>` for typed events. |
1199
+ | `@caperjs/plugin-crunch` | `crunch` | Crunch 2D rigid-body physics. |
1200
+ | `@caperjs/plugin-rollbar` | `rollbar` | Rollbar error tracking. |
1201
+
1202
+ Install via pnpm/npm, then register in `caper.config.ts plugins: [...]`.
1203
+ Deep API lives in each plugin's own README on npm.
1204
+
1205
+ Canonical registration shape:
1206
+
1207
+ ```ts
1208
+ plugins: [
1209
+ 'google-analytics',
1210
+ ['crunch', { autoLoad: false }],
1211
+ ['rive', { autoLoad: false }],
1212
+ ['rollbar', { options: { isDev: import.meta.env.MODE === 'development' } }],
1213
+ 'firebase',
1214
+ ]
1215
+ ```
1216
+
1217
+ ---
1218
+
1219
+ ## 14. Generated types & virtual modules
1220
+
1221
+ The Vite plugin ([config/vite.mjs](../config/vite.mjs)) generates types on every
1222
+ dev reload. **Do not hand-edit them** — delete stale copies after renames and let
1223
+ the next build regen.
1224
+
1225
+ ### 14.1 `src/types/caper-app.d.ts`
1226
+
1227
+ Augments `AppTypeOverrides` with unions derived from disk:
1228
+
1229
+ | Type | Derived from |
1230
+ | --- | --- |
1231
+ | `AppScenes` | `src/scenes/*` `defineScene.id` values |
1232
+ | `AppPlugins` | `src/plugins/*` `definePlugin.id` ∪ discovered `@caperjs/plugin-*` |
1233
+ | `AppPopups` | `src/popups/*` `definePopup.id` |
1234
+ | `AppEntities` | `src/entities/*` `defineEntity.id` |
1235
+ | `AppActions` | keys of `defineActions` in `caper.config.ts` |
1236
+ | `AppContexts` | `defineContexts` array |
1237
+ | `AppData` | `defineData` schema shape |
1238
+ | `AppLocaleKeys` | union of keys across locale files |
1239
+ | `AppSceneClasses` | `{ 'scene-id': typeof import('./scenes/X').default }` |
1240
+
1241
+ These narrow runtime APIs:
1242
+
1243
+ ```ts
1244
+ app.scenes.load('unknown-scene'); // ← compile error
1245
+ app.getPlugin('typo'); // ← compile error
1246
+ app.popups.showPopup('confirm'); // ← typed
1247
+ app.i18n.t('home.title'); // ← typed
1248
+ ```
1249
+
1250
+ ### 14.2 `src/types/caper-assets.d.ts`
1251
+
1252
+ Generated from AssetPack's `assets.json`:
1253
+
1254
+ ```ts
1255
+ type AssetTextures = 'caper' | 'hero' | 'button/default' | /* ... */ ;
1256
+ type AssetTexturesIn<'game'> = /* textures in the 'game' bundle only */ ;
1257
+ type AssetAudio = 'music/main' | 'sfx/jump' | /* ... */ ;
1258
+ type AssetSpine = 'spine/spineboy-pro' | /* ... */ ;
1259
+ ```
1260
+
1261
+ `this.add.sprite({ asset: 'caper' })` narrows `asset` against `AssetTextures`.
1262
+
1263
+ ### 14.3 Virtual modules
1264
+
1265
+ Provided by the Caper Vite plugin. You rarely import them directly — they're
1266
+ implementation of the auto-wiring. Know they exist for debugging.
1267
+
1268
+ | Module | Contents |
1269
+ | --- | --- |
1270
+ | `virtual:caper-config` | The resolved config. |
1271
+ | `virtual:caper-scenes` | Map of scene ID → `() => import('./scenes/X.ts')`. |
1272
+ | `virtual:caper-plugins` | Map of plugin ID → constructor or dynamic import. |
1273
+ | `virtual:caper-popups` | Map of popup ID → constructor. |
1274
+ | `virtual:caper-entities` | Map of entity ID → constructor. |
1275
+ | `virtual:caper-assets` | Inlined asset manifest for dev. |
1276
+
1277
+ ### 14.4 Regenerating
1278
+
1279
+ Types regen on dev-server restart. After renaming a scene / plugin / popup /
1280
+ entity: delete the stale `caper-app.d.ts` / `caper-assets.d.ts`, then
1281
+ `caper dev` — they're re-emitted from scratch.
1282
+
1283
+ **Source references:** [config/vite.mjs](../config/vite.mjs).
1284
+
1285
+ ---
1286
+
1287
+ ## 15. Common recipes
1288
+
1289
+ Recipes are intentionally short — they point at the section with the full
1290
+ shape. Each one starts with `caper add` when applicable.
1291
+
1292
+ ### 15.1 Add a scene
1293
+
1294
+ ```bash
1295
+ caper add scene Level
1296
+ ```
1297
+
1298
+ Edit `src/scenes/Level.ts`:
1299
+
1300
+ ```ts
1301
+ export const scene = defineScene({ id: 'level' });
1302
+ export const assets: SceneAssets = { preload: { bundles: ['level'] } };
1303
+
1304
+ export default class LevelScene extends Scene<{ id: number }> {
1305
+ async initialize() {
1306
+ const { id } = this.props;
1307
+ this.add.text({ text: `Level ${id}`, anchor: 0.5 });
1308
+ }
1309
+ }
1310
+ ```
1311
+
1312
+ Load it: `app.scenes.load('level', { id: 1 })`. Details: §5.
1313
+
1314
+ ### 15.2 Switch scene with typed props
1315
+
1316
+ Declare `Scene<Props>` generic, then `app.scenes.load(id, props)` is fully typed.
1317
+ Details: §5.5.
1318
+
1319
+ ### 15.3 Add a popup
1320
+
1321
+ ```bash
1322
+ caper add popup Confirm
1323
+ ```
1324
+
1325
+ Show: `app.popups.showPopup('confirm', { data: { title: 'Sure?' } })`. Details: §7.3.
1326
+
1327
+ ### 15.4 Add an entity
1328
+
1329
+ ```bash
1330
+ caper add entity Enemy
1331
+ ```
1332
+
1333
+ Use from a scene: `this.enemy = this.add.entity('enemy')`. Details: §10.
1334
+
1335
+ ### 15.5 Add a local plugin
1336
+
1337
+ ```bash
1338
+ caper add plugin Analytics
1339
+ ```
1340
+
1341
+ Add to `caper.config.ts plugins: ['analytics', ...]`. Details: §9.
1342
+
1343
+ For a new publishable plugin: `pnpm plugin:create`.
1344
+
1345
+ ### 15.6 Add an asset bundle
1346
+
1347
+ 1. Create `assets/<bundle>{m}/` and drop files into it.
1348
+ 2. Add to `caper.config.ts assets.preload.bundles` (or `background.bundles`).
1349
+ 3. Restart dev server so AssetPack re-runs and types regen.
1350
+ 4. Reference files via `this.add.sprite({ asset: '<path>' })` — names flow from
1351
+ the generated `AssetTextures` union.
1352
+
1353
+ Details: §11.
1354
+
1355
+ ### 15.7 Scene-scoped assets
1356
+
1357
+ Module-level `export const assets: SceneAssets = { preload: { bundles: [...] }, autoUnload: true }`.
1358
+ Details: §5.3.
1359
+
1360
+ ### 15.8 Register an action + keybinding
1361
+
1362
+ ```ts
1363
+ // caper.config.ts
1364
+ const actions = defineActions(contexts, { jump: { context: ['game'] } });
1365
+ const controls = defineControls(actions, buttons, {
1366
+ keyboard: { down: { jump: 'Space' } },
1367
+ });
1368
+ ```
1369
+
1370
+ Listen in a scene:
1371
+
1372
+ ```ts
1373
+ this.addSignalConnection(
1374
+ this.app.actions('jump').connect(() => this.player.jump()),
1375
+ );
1376
+ ```
1377
+
1378
+ Details: §4.3.
1379
+
1380
+ ### 15.9 Show a toast
1381
+
1382
+ ```ts
1383
+ app.popups.toast({ message: 'Saved', duration: 2 });
1384
+ ```
1385
+
1386
+ Or attach a scene-local `Toaster` via `this.add.toaster({...})`.
1387
+
1388
+ ### 15.10 Persist data
1389
+
1390
+ ```ts
1391
+ // caper.config.ts
1392
+ export const dataSchema = defineData({ score: 0 });
1393
+
1394
+ // anywhere
1395
+ app.data.set('score', 100);
1396
+ const s = app.data.get('score'); // typed: number
1397
+
1398
+ // persist to firebase
1399
+ await app.store.save('firebase', 'playerData', app.data.toJSON());
1400
+ ```
1401
+
1402
+ Details: §4.4, §12.2.
1403
+
1404
+ ### 15.11 Use i18n
1405
+
1406
+ ```ts
1407
+ // src/locales/en.ts
1408
+ export default { 'home.title': 'Welcome', 'play': 'Play' };
1409
+
1410
+ // usage
1411
+ this.add.text({ text: app.i18n.t('home.title') });
1412
+ await app.i18n.setLocale('fr');
1413
+ ```
1414
+
1415
+ Locale files declared in `caper.config.ts i18n.files`.
1416
+
1417
+ ### 15.12 Add a Spine entity
1418
+
1419
+ ```bash
1420
+ caper add entity Hero
1421
+ ```
1422
+
1423
+ ```ts
1424
+ this._spine = this.add.spine({
1425
+ data: 'spine/hero', // resolves spine/hero.json + spine/hero.atlas
1426
+ autoUpdate: true,
1427
+ animationName: 'idle',
1428
+ loop: true,
1429
+ });
1430
+ ```
1431
+
1432
+ Details: §6.1 (`spine`), §10.
1433
+
1434
+ ### 15.13 FlexContainer-based HUD
1435
+
1436
+ ```ts
1437
+ const hud = this.add.uiCanvas({ /* app-sized */ });
1438
+
1439
+ const topBar = hud.add.flexContainer({
1440
+ layout: {
1441
+ width: 'intrinsic', height: 60,
1442
+ flexDirection: 'row', justifyContent: 'space-between', padding: 12,
1443
+ },
1444
+ });
1445
+
1446
+ topBar.add.text({ text: `Score: ${score}`, style: { fontSize: 20 } });
1447
+ topBar.add.button({ textures: { default: 'button/pause' }, action: { id: 'toggle_pause' } });
1448
+ ```
1449
+
1450
+ Details: §7.1, §7.5.
1451
+
1452
+ ### 15.14 Consume firebase
1453
+
1454
+ ```ts
1455
+ // in a scene
1456
+ const firebase = this.app.getPlugin('firebase');
1457
+ await firebase.save('save-slot-1', { score: 100 });
1458
+ const data = await firebase.load('save-slot-1');
1459
+ ```
1460
+
1461
+ Via store facade (works with any storage adapter):
1462
+
1463
+ ```ts
1464
+ await this.app.store.save('firebase', 'save-slot-1', { score: 100 });
1465
+ ```
1466
+
1467
+ ---
1468
+
1469
+ ## 16. Gotchas & verification loop
1470
+
1471
+ ### 16.1 AssetPack font family tags must be whitespace-free
1472
+
1473
+ AssetPack strips whitespace from `{tag=value}` filename tags before parsing.
1474
+ `{family=Space Grotesk}` silently becomes `{family=SpaceGrotesk}`. Worse: if
1475
+ you **don't** add a family tag at all, AssetPack falls back to the filename
1476
+ stem — so `SpaceGrotesk-Bold{wf}.ttf` registers as family
1477
+ `"SpaceGrotesk-Bold"` and each weight becomes its own family.
1478
+
1479
+ Rule: pick a single-word family name up front. Use it verbatim in all three
1480
+ places:
1481
+ 1. The `{family=...}` tag in the source font filename
1482
+ 2. The CSS `@font-face { font-family: '...' }` declaration
1483
+ 3. The `FONT_*` constant in `src/utils/Constants.ts`
1484
+
1485
+ After renaming source font files, delete `.assetpack/` so AssetPack
1486
+ re-processes.
1487
+
1488
+ ### 16.2 Verify in the running app
1489
+
1490
+ Type-check and build don't catch UI/scene/asset regressions. After changes:
1491
+
1492
+ ```bash
1493
+ pnpm types # or tsc — compiles clean
1494
+ pnpm build # or caper build — builds clean
1495
+ # then ask the human to run `pnpm dev` (or `caper dev`) and report visually
1496
+ ```
1497
+
1498
+ Do not start the dev server yourself — it runs forever and blocks.
1499
+
1500
+ ### 16.3 Regenerate types after renames
1501
+
1502
+ After renaming a scene/plugin/popup/entity, delete
1503
+ `src/types/caper-app.d.ts` and `src/types/caper-assets.d.ts` (they're
1504
+ generated), then run `pnpm dev`. Old IDs stuck in the union cause weird
1505
+ downstream type errors.
1506
+
1507
+ ### 16.4 Fail loud in plugins (see §1.2)
1508
+
1509
+ A plugin that silently falls back to default options when its config is bad
1510
+ hides the bug. Throw with "set `options.X` in `caper.config.ts plugins[]`".
1511
+
1512
+ ### 16.5 `plugins[]` is explicit (see §1.1)
1513
+
1514
+ If plugin A `requires: ['b']`, list both in `plugins: []`. Never assume
1515
+ transitive registration.
1516
+
1517
+ ### 16.6 Prefer `caper add` over hand-authoring
1518
+
1519
+ Hand-authored files often miss the `defineX` wrapper and land outside the
1520
+ discovery directory. Both cause the file to be silently ignored — no error,
1521
+ just doesn't work. Start from the CLI.
1522
+
1523
+ ### 16.7 Don't commit `.vscode/settings.json`
1524
+
1525
+ Personal editor config. Must stay unstaged.
1526
+
1527
+ ### 16.8 Conventional Commits
1528
+
1529
+ This repo uses `@commitlint/config-conventional`. Prefix every commit with
1530
+ `feat:`, `fix:`, `chore:`, `refactor:`, etc. release-please parses these for
1531
+ changelogs + version bumps.
1532
+
1533
+ ### 16.9 Bust `.assetpack/`, `dist/`, `.cache/` on weirdness
1534
+
1535
+ `pnpm clean` in an app clears them. AssetPack caches aggressively; a stale
1536
+ cache produces confusing texture/name mismatches.
1537
+
1538
+ ---
1539
+
1540
+ ## 17. API reference index
1541
+
1542
+ Flat jump table. Name → section → one-line.
1543
+
1544
+ | Name | § | One-line |
1545
+ | --- | --- | --- |
1546
+ | `Application` | §3.4 | Base app class; subclass for typed plugin getters. |
1547
+ | `AnimatedSprite` | §6.1, §10 | Pixi AnimatedSprite wrapper (`animations`, `animation`, `autoPlay`). |
1548
+ | `Button` | §7.2 | Four-state interactive button with sounds + actions. |
1549
+ | `Camera` | §10 | Camera controller for scene-level follow/constrain. |
1550
+ | `Container` | §6, §10 | Caper base container (Animated + WithSignals + Factory). |
1551
+ | `create(config, el?, speak?)` | §3.3 | Programmatic app bootstrap. |
1552
+ | `defineActions(contexts, map)` | §4.3 | Typed action registry. |
1553
+ | `defineButtons(ids)` | §4.3 | Physical button IDs. |
1554
+ | `defineConfig(config)` | §4.1 | `caper.config.ts` default export. |
1555
+ | `defineContexts(ids)` | §4.3 | Action contexts. |
1556
+ | `defineControls(actions, buttons, map)` | §4.3 | Key/touch/gamepad bindings. |
1557
+ | `defineData(schema)` | §4.4 | Typed store schema. |
1558
+ | `defineEntity({id, ...})` | §4.2, §10 | Entity discovery. |
1559
+ | `definePlugin({id, requires?, ...})` | §4.2, §9 | Plugin discovery + deps. |
1560
+ | `definePopup({id, ...})` | §4.2, §7.3 | Popup discovery. |
1561
+ | `defineScene({id, ...})` | §4.2, §5 | Scene discovery. |
1562
+ | `defineUI({id, ...})` | §4.2 | UI component discovery. |
1563
+ | `Entity` | §10 | Game-object base; paired with `defineEntity`. |
1564
+ | `FlexContainer` | §7.1 | Yoga flexbox container. |
1565
+ | `Focusable` (mixin) | §12.3 | Keyboard/gamepad focus. |
1566
+ | `Interactive` (mixin) | §12.3 | Pointer-event signals. |
1567
+ | `Joystick` | §7.6 | Virtual touch stick. |
1568
+ | `Plugin<Options>` | §9 | Base plugin class. |
1569
+ | `Popup<T>` | §7.3 | Focus-aware modal; paired with `definePopup`. |
1570
+ | `Scene<Props>` | §5 | Scene base; paired with `defineScene`. |
1571
+ | `SceneTransition` | §5.7 | Full-screen entry/exit animation. |
1572
+ | `Signal<T>` | §12.1 | Typed signal with priority ordering. |
1573
+ | `SpineAnimation<Names>` | §6.1, §10 | Typed Spine wrapper. |
1574
+ | `Store` | §12.2 | Unified storage-adapter facade. |
1575
+ | `Toast` / `Toaster` | §7.4 | Toast notifications. |
1576
+ | `UICanvas` | §7.5 | HUD root layer. |
1577
+ | `app.actions(id)` | §8 | Returns the action's signal. |
1578
+ | `app.assets.loadBundles(ids)` | §8, §11.5 | Load named bundles. |
1579
+ | `app.assets.loadSceneAssets(scene)` | §8 | Load a scene's declared bundles. |
1580
+ | `app.audio.play(id, opts)` | §8 | Play a sound by manifest ID. |
1581
+ | `app.data.get(key)` / `.set(key, v)` | §4.4, §15.10 | Typed store access. |
1582
+ | `app.focus.addFocusLayer(id)` | §8 | New focus layer. |
1583
+ | `app.fullscreen.toggle()` | §8 | Request fullscreen. |
1584
+ | `app.getPlugin<T>(id)` | §8 | Typed plugin lookup. |
1585
+ | `app.i18n.t(key, params?)` | §8 | Translate. |
1586
+ | `app.i18n.setLocale(id)` | §8 | Switch locale. |
1587
+ | `app.lookup.add/get/remove(id)` | §8 | Object ID registry. |
1588
+ | `app.popups.showPopup(id, config?)` | §7.3, §8 | Show a popup. |
1589
+ | `app.popups.toast(config)` | §7.4, §8 | Push a toast. |
1590
+ | `app.resizer.size` | §8 | Current viewport. |
1591
+ | `app.scenes.load(id, props?)` | §5.6, §8 | Switch scenes. |
1592
+ | `app.store.save(adapter, key, data)` | §12.2 | Persist via storage adapter. |
1593
+ | `app.store.load(adapter, key)` | §12.2 | Read via storage adapter. |
1594
+ | `app.timers.delay(ms)` | §8 | Scene-scoped timer. |
1595
+ | `Animated.animate(props)` | §12.3 | GSAP tween. |
1596
+ | `Animated.shake()` / `.pulse()` / `.bob()` | §12.3 | Preset animations. |
1597
+ | `this.add.*` / `this.make.*` | §6 | Factory methods on any Container subclass. |
1598
+
1599
+ ---
1600
+
1601
+ **Last updated:** `@caperjs/core@6.2.2` (PixiJS 8.x). When in doubt, read the
1602
+ cited framework source file — signatures and defaults are authoritative there.