@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.
- package/LICENSE +22 -0
- package/README.md +62 -0
- package/cli/add.mjs +197 -0
- package/cli/audio/cc.mjs +128 -0
- package/cli/audio/index.mjs +42 -0
- package/cli/audio/utils.mjs +56 -0
- package/cli/create-caper.mjs +8 -0
- package/cli/create.mjs +351 -0
- package/cli/install-peerdeps.mjs +57 -0
- package/cli/update.mjs +9 -0
- package/cli/utils.mjs +81 -0
- package/cli/vite.mjs +55 -0
- package/cli/voiceover/generateVoiceoverCSV.mjs +158 -0
- package/cli/voiceover/index.mjs +1 -0
- package/cli.mjs +157 -0
- package/client.d.ts +7 -0
- package/config/assetpack.mjs +212 -0
- package/config/tsconfig.base.json +28 -0
- package/config/vite.mjs +2464 -0
- package/extras/css/accessibility.css +9 -0
- package/extras/css/fullscreen.css +28 -0
- package/extras/css/loader.css +67 -0
- package/extras/llms.txt +1602 -0
- package/lib/CaptionsPlugin-Dc8fIrjy.js +277 -0
- package/lib/CaptionsPlugin-Dc8fIrjy.js.map +1 -0
- package/lib/DataAdapter-BY2114sp.js +84 -0
- package/lib/DataAdapter-BY2114sp.js.map +1 -0
- package/lib/DebugRenderer-BJMLILqI.js +1385 -0
- package/lib/DebugRenderer-BJMLILqI.js.map +1 -0
- package/lib/DevToolsPlugin-wQ5rOkn0.js +31 -0
- package/lib/DevToolsPlugin-wQ5rOkn0.js.map +1 -0
- package/lib/GSAPPlugin-DHhSZKv8.js +350 -0
- package/lib/GSAPPlugin-DHhSZKv8.js.map +1 -0
- package/lib/LayoutPlugin-B-DF9SYM.js +1271 -0
- package/lib/LayoutPlugin-B-DF9SYM.js.map +1 -0
- package/lib/SpinePlugin-Dz_3dljz.js +6077 -0
- package/lib/SpinePlugin-Dz_3dljz.js.map +1 -0
- package/lib/StatsPlugin-Cg82JMBD.js +70 -0
- package/lib/StatsPlugin-Cg82JMBD.js.map +1 -0
- package/lib/VoiceOverPlugin-BR3ImT8C.js +114 -0
- package/lib/VoiceOverPlugin-BR3ImT8C.js.map +1 -0
- package/lib/caper.mjs +1233 -0
- package/lib/caper.mjs.map +1 -0
- package/lib/core/Application.d.ts +268 -0
- package/lib/core/Application.d.ts.map +1 -0
- package/lib/core/config.d.ts +39 -0
- package/lib/core/config.d.ts.map +1 -0
- package/lib/core/create.d.ts +41 -0
- package/lib/core/create.d.ts.map +1 -0
- package/lib/core/globals.d.ts +51 -0
- package/lib/core/globals.d.ts.map +1 -0
- package/lib/core/index.d.ts +7 -0
- package/lib/core/index.d.ts.map +1 -0
- package/lib/core/interfaces/IApplication.d.ts +566 -0
- package/lib/core/interfaces/IApplication.d.ts.map +1 -0
- package/lib/core/interfaces/IApplicationOptions.d.ts +65 -0
- package/lib/core/interfaces/IApplicationOptions.d.ts.map +1 -0
- package/lib/core/interfaces/ICoreFunctions.d.ts +49 -0
- package/lib/core/interfaces/ICoreFunctions.d.ts.map +1 -0
- package/lib/core/interfaces/ICoreSignals.d.ts +57 -0
- package/lib/core/interfaces/ICoreSignals.d.ts.map +1 -0
- package/lib/core/interfaces/IStorageCapability.d.ts +20 -0
- package/lib/core/interfaces/IStorageCapability.d.ts.map +1 -0
- package/lib/core/interfaces/IStorageCapability.test.d.ts +2 -0
- package/lib/core/interfaces/IStorageCapability.test.d.ts.map +1 -0
- package/lib/core/interfaces/index.d.ts +7 -0
- package/lib/core/interfaces/index.d.ts.map +1 -0
- package/lib/core/registries.d.ts +8 -0
- package/lib/core/registries.d.ts.map +1 -0
- package/lib/core/types.d.ts +12 -0
- package/lib/core/types.d.ts.map +1 -0
- package/lib/display/AnimatedSprite.d.ts +40 -0
- package/lib/display/AnimatedSprite.d.ts.map +1 -0
- package/lib/display/Camera.d.ts +102 -0
- package/lib/display/Camera.d.ts.map +1 -0
- package/lib/display/Container.d.ts +115 -0
- package/lib/display/Container.d.ts.map +1 -0
- package/lib/display/Entity.d.ts +46 -0
- package/lib/display/Entity.d.ts.map +1 -0
- package/lib/display/ParticleContainer.d.ts +58 -0
- package/lib/display/ParticleContainer.d.ts.map +1 -0
- package/lib/display/Scene.d.ts +250 -0
- package/lib/display/Scene.d.ts.map +1 -0
- package/lib/display/SceneTransition.d.ts +41 -0
- package/lib/display/SceneTransition.d.ts.map +1 -0
- package/lib/display/SpineAnimation.d.ts +76 -0
- package/lib/display/SpineAnimation.d.ts.map +1 -0
- package/lib/display/Svg.d.ts +5 -0
- package/lib/display/Svg.d.ts.map +1 -0
- package/lib/display/index.d.ts +10 -0
- package/lib/display/index.d.ts.map +1 -0
- package/lib/env.d.ts +6 -0
- package/lib/hello.d.ts +2 -0
- package/lib/hello.d.ts.map +1 -0
- package/lib/index.d.ts +15 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/mixins/animated.d.ts +53 -0
- package/lib/mixins/animated.d.ts.map +1 -0
- package/lib/mixins/factory/Factory.d.ts +8 -0
- package/lib/mixins/factory/Factory.d.ts.map +1 -0
- package/lib/mixins/factory/const.d.ts +67 -0
- package/lib/mixins/factory/const.d.ts.map +1 -0
- package/lib/mixins/factory/index.d.ts +8 -0
- package/lib/mixins/factory/index.d.ts.map +1 -0
- package/lib/mixins/factory/methods.d.ts +3 -0
- package/lib/mixins/factory/methods.d.ts.map +1 -0
- package/lib/mixins/factory/props.d.ts +160 -0
- package/lib/mixins/factory/props.d.ts.map +1 -0
- package/lib/mixins/factory/registry.d.ts +27 -0
- package/lib/mixins/factory/registry.d.ts.map +1 -0
- package/lib/mixins/factory/registry.test.d.ts +2 -0
- package/lib/mixins/factory/registry.test.d.ts.map +1 -0
- package/lib/mixins/factory/schema.d.ts +71 -0
- package/lib/mixins/factory/schema.d.ts.map +1 -0
- package/lib/mixins/factory/ui-registry.d.ts +20 -0
- package/lib/mixins/factory/ui-registry.d.ts.map +1 -0
- package/lib/mixins/factory/utils.d.ts +11 -0
- package/lib/mixins/factory/utils.d.ts.map +1 -0
- package/lib/mixins/focus.d.ts +15 -0
- package/lib/mixins/focus.d.ts.map +1 -0
- package/lib/mixins/index.d.ts +6 -0
- package/lib/mixins/index.d.ts.map +1 -0
- package/lib/mixins/interaction.d.ts +20 -0
- package/lib/mixins/interaction.d.ts.map +1 -0
- package/lib/mixins/signals.d.ts +15 -0
- package/lib/mixins/signals.d.ts.map +1 -0
- package/lib/plugins/AssetsPlugin.d.ts +79 -0
- package/lib/plugins/AssetsPlugin.d.ts.map +1 -0
- package/lib/plugins/DataAdapter.d.ts +95 -0
- package/lib/plugins/DataAdapter.d.ts.map +1 -0
- package/lib/plugins/DevToolsPlugin.d.ts +97 -0
- package/lib/plugins/DevToolsPlugin.d.ts.map +1 -0
- package/lib/plugins/FullScreenPlugin.d.ts +240 -0
- package/lib/plugins/FullScreenPlugin.d.ts.map +1 -0
- package/lib/plugins/GSAPPlugin.d.ts +634 -0
- package/lib/plugins/GSAPPlugin.d.ts.map +1 -0
- package/lib/plugins/KeyboardPlugin.d.ts +53 -0
- package/lib/plugins/KeyboardPlugin.d.ts.map +1 -0
- package/lib/plugins/LayoutPlugin.d.ts +100 -0
- package/lib/plugins/LayoutPlugin.d.ts.map +1 -0
- package/lib/plugins/LookupPlugin.d.ts +223 -0
- package/lib/plugins/LookupPlugin.d.ts.map +1 -0
- package/lib/plugins/Plugin.d.ts +132 -0
- package/lib/plugins/Plugin.d.ts.map +1 -0
- package/lib/plugins/Plugin.test.d.ts +2 -0
- package/lib/plugins/Plugin.test.d.ts.map +1 -0
- package/lib/plugins/PopupManagerPlugin.d.ts +108 -0
- package/lib/plugins/PopupManagerPlugin.d.ts.map +1 -0
- package/lib/plugins/ResizerPlugin.d.ts +62 -0
- package/lib/plugins/ResizerPlugin.d.ts.map +1 -0
- package/lib/plugins/SceneManagerPlugin.d.ts +122 -0
- package/lib/plugins/SceneManagerPlugin.d.ts.map +1 -0
- package/lib/plugins/StatsPlugin.d.ts +8 -0
- package/lib/plugins/StatsPlugin.d.ts.map +1 -0
- package/lib/plugins/TimerPlugin.d.ts +401 -0
- package/lib/plugins/TimerPlugin.d.ts.map +1 -0
- package/lib/plugins/WebEventsPlugin.d.ts +60 -0
- package/lib/plugins/WebEventsPlugin.d.ts.map +1 -0
- package/lib/plugins/actions/ActionsPlugin.d.ts +39 -0
- package/lib/plugins/actions/ActionsPlugin.d.ts.map +1 -0
- package/lib/plugins/actions/constants.d.ts +52 -0
- package/lib/plugins/actions/constants.d.ts.map +1 -0
- package/lib/plugins/actions/index.d.ts +5 -0
- package/lib/plugins/actions/index.d.ts.map +1 -0
- package/lib/plugins/actions/methods.d.ts +11 -0
- package/lib/plugins/actions/methods.d.ts.map +1 -0
- package/lib/plugins/actions/types.d.ts +25 -0
- package/lib/plugins/actions/types.d.ts.map +1 -0
- package/lib/plugins/audio/AudioChannel.d.ts +46 -0
- package/lib/plugins/audio/AudioChannel.d.ts.map +1 -0
- package/lib/plugins/audio/AudioChannel.test.d.ts +2 -0
- package/lib/plugins/audio/AudioChannel.test.d.ts.map +1 -0
- package/lib/plugins/audio/AudioInstance.d.ts +79 -0
- package/lib/plugins/audio/AudioInstance.d.ts.map +1 -0
- package/lib/plugins/audio/AudioManagerPlugin.d.ts +323 -0
- package/lib/plugins/audio/AudioManagerPlugin.d.ts.map +1 -0
- package/lib/plugins/audio/VoiceOverPlugin.d.ts +69 -0
- package/lib/plugins/audio/VoiceOverPlugin.d.ts.map +1 -0
- package/lib/plugins/audio/index.d.ts +4 -0
- package/lib/plugins/audio/index.d.ts.map +1 -0
- package/lib/plugins/breakpoints/BreakpointPlugin.d.ts +109 -0
- package/lib/plugins/breakpoints/BreakpointPlugin.d.ts.map +1 -0
- package/lib/plugins/breakpoints/BreakpointPlugin.test.d.ts +2 -0
- package/lib/plugins/breakpoints/BreakpointPlugin.test.d.ts.map +1 -0
- package/lib/plugins/breakpoints/evaluate.d.ts +53 -0
- package/lib/plugins/breakpoints/evaluate.d.ts.map +1 -0
- package/lib/plugins/breakpoints/evaluate.test.d.ts +2 -0
- package/lib/plugins/breakpoints/evaluate.test.d.ts.map +1 -0
- package/lib/plugins/breakpoints/index.d.ts +4 -0
- package/lib/plugins/breakpoints/index.d.ts.map +1 -0
- package/lib/plugins/breakpoints/methods.d.ts +23 -0
- package/lib/plugins/breakpoints/methods.d.ts.map +1 -0
- package/lib/plugins/breakpoints/types.d.ts +70 -0
- package/lib/plugins/breakpoints/types.d.ts.map +1 -0
- package/lib/plugins/captions/CaptionsPlugin.d.ts +150 -0
- package/lib/plugins/captions/CaptionsPlugin.d.ts.map +1 -0
- package/lib/plugins/captions/CaptionsRenderer.d.ts +37 -0
- package/lib/plugins/captions/CaptionsRenderer.d.ts.map +1 -0
- package/lib/plugins/captions/index.d.ts +3 -0
- package/lib/plugins/captions/index.d.ts.map +1 -0
- package/lib/plugins/defaults.d.ts +4 -0
- package/lib/plugins/defaults.d.ts.map +1 -0
- package/lib/plugins/focus/FocusManagerPlugin.d.ts +148 -0
- package/lib/plugins/focus/FocusManagerPlugin.d.ts.map +1 -0
- package/lib/plugins/focus/FocusOutliner.d.ts +32 -0
- package/lib/plugins/focus/FocusOutliner.d.ts.map +1 -0
- package/lib/plugins/focus/index.d.ts +3 -0
- package/lib/plugins/focus/index.d.ts.map +1 -0
- package/lib/plugins/i18nPlugin.d.ts +128 -0
- package/lib/plugins/i18nPlugin.d.ts.map +1 -0
- package/lib/plugins/index.d.ts +18 -0
- package/lib/plugins/index.d.ts.map +1 -0
- package/lib/plugins/input/AbstractControls.d.ts +8 -0
- package/lib/plugins/input/AbstractControls.d.ts.map +1 -0
- package/lib/plugins/input/Controls.d.ts +16 -0
- package/lib/plugins/input/Controls.d.ts.map +1 -0
- package/lib/plugins/input/InputPlugin.d.ts +52 -0
- package/lib/plugins/input/InputPlugin.d.ts.map +1 -0
- package/lib/plugins/input/constants.d.ts +8 -0
- package/lib/plugins/input/constants.d.ts.map +1 -0
- package/lib/plugins/input/index.d.ts +10 -0
- package/lib/plugins/input/index.d.ts.map +1 -0
- package/lib/plugins/input/interfaces.d.ts +30 -0
- package/lib/plugins/input/interfaces.d.ts.map +1 -0
- package/lib/plugins/input/keyboard/KeyboardContols.d.ts +28 -0
- package/lib/plugins/input/keyboard/KeyboardContols.d.ts.map +1 -0
- package/lib/plugins/input/keyboard/index.d.ts +3 -0
- package/lib/plugins/input/keyboard/index.d.ts.map +1 -0
- package/lib/plugins/input/keyboard/interfaces.d.ts +18 -0
- package/lib/plugins/input/keyboard/interfaces.d.ts.map +1 -0
- package/lib/plugins/input/methods.d.ts +4 -0
- package/lib/plugins/input/methods.d.ts.map +1 -0
- package/lib/plugins/input/touch/TouchControls.d.ts +35 -0
- package/lib/plugins/input/touch/TouchControls.d.ts.map +1 -0
- package/lib/plugins/input/touch/constants.d.ts +14 -0
- package/lib/plugins/input/touch/constants.d.ts.map +1 -0
- package/lib/plugins/input/touch/index.d.ts +4 -0
- package/lib/plugins/input/touch/index.d.ts.map +1 -0
- package/lib/plugins/input/touch/interfaces.d.ts +15 -0
- package/lib/plugins/input/touch/interfaces.d.ts.map +1 -0
- package/lib/plugins/input/types.d.ts +32 -0
- package/lib/plugins/input/types.d.ts.map +1 -0
- package/lib/plugins/input/utils.d.ts +23 -0
- package/lib/plugins/input/utils.d.ts.map +1 -0
- package/lib/plugins/spine/SpinePlugin.d.ts +6 -0
- package/lib/plugins/spine/SpinePlugin.d.ts.map +1 -0
- package/lib/plugins/spine/pixi-spine/BatchableSpineSlot.d.ts +31 -0
- package/lib/plugins/spine/pixi-spine/BatchableSpineSlot.d.ts.map +1 -0
- package/lib/plugins/spine/pixi-spine/Spine.d.ts +211 -0
- package/lib/plugins/spine/pixi-spine/Spine.d.ts.map +1 -0
- package/lib/plugins/spine/pixi-spine/SpineDebugRenderer.d.ts +81 -0
- package/lib/plugins/spine/pixi-spine/SpineDebugRenderer.d.ts.map +1 -0
- package/lib/plugins/spine/pixi-spine/SpinePipe.d.ts +21 -0
- package/lib/plugins/spine/pixi-spine/SpinePipe.d.ts.map +1 -0
- package/lib/plugins/spine/pixi-spine/SpineTexture.d.ts +16 -0
- package/lib/plugins/spine/pixi-spine/SpineTexture.d.ts.map +1 -0
- package/lib/plugins/spine/pixi-spine/assets/atlasLoader.d.ts +10 -0
- package/lib/plugins/spine/pixi-spine/assets/atlasLoader.d.ts.map +1 -0
- package/lib/plugins/spine/pixi-spine/assets/skeletonLoader.d.ts +6 -0
- package/lib/plugins/spine/pixi-spine/assets/skeletonLoader.d.ts.map +1 -0
- package/lib/plugins/spine/pixi-spine/darktint/DarkTintBatchGeometry.d.ts +5 -0
- package/lib/plugins/spine/pixi-spine/darktint/DarkTintBatchGeometry.d.ts.map +1 -0
- package/lib/plugins/spine/pixi-spine/darktint/DarkTintBatcher.d.ts +22 -0
- package/lib/plugins/spine/pixi-spine/darktint/DarkTintBatcher.d.ts.map +1 -0
- package/lib/plugins/spine/pixi-spine/darktint/DarkTintShader.d.ts +5 -0
- package/lib/plugins/spine/pixi-spine/darktint/DarkTintShader.d.ts.map +1 -0
- package/lib/plugins/spine/pixi-spine/darktint/darkTintBit.d.ts +51 -0
- package/lib/plugins/spine/pixi-spine/darktint/darkTintBit.d.ts.map +1 -0
- package/lib/plugins/spine/pixi-spine/index.d.ts +9 -0
- package/lib/plugins/spine/pixi-spine/index.d.ts.map +1 -0
- package/lib/plugins/spine/pixi-spine/require-shim.d.ts +34 -0
- package/lib/plugins/spine/pixi-spine/require-shim.d.ts.map +1 -0
- package/lib/registries-CYCaYKZI.js +6885 -0
- package/lib/registries-CYCaYKZI.js.map +1 -0
- package/lib/signals/Signal.d.ts +16 -0
- package/lib/signals/Signal.d.ts.map +1 -0
- package/lib/signals/Signal.test.d.ts +2 -0
- package/lib/signals/Signal.test.d.ts.map +1 -0
- package/lib/signals/index.d.ts +3 -0
- package/lib/signals/index.d.ts.map +1 -0
- package/lib/store/Store.d.ts +56 -0
- package/lib/store/Store.d.ts.map +1 -0
- package/lib/store/Store.test.d.ts +2 -0
- package/lib/store/Store.test.d.ts.map +1 -0
- package/lib/store/index.d.ts +2 -0
- package/lib/store/index.d.ts.map +1 -0
- package/lib/types/framework.d.ts +46 -0
- package/lib/types/gsap.d.ts +23 -0
- package/lib/ui/Button.d.ts +162 -0
- package/lib/ui/Button.d.ts.map +1 -0
- package/lib/ui/FlexContainer.d.ts +109 -0
- package/lib/ui/FlexContainer.d.ts.map +1 -0
- package/lib/ui/Input.d.ts +384 -0
- package/lib/ui/Input.d.ts.map +1 -0
- package/lib/ui/Joystick.d.ts +61 -0
- package/lib/ui/Joystick.d.ts.map +1 -0
- package/lib/ui/Popup.d.ts +109 -0
- package/lib/ui/Popup.d.ts.map +1 -0
- package/lib/ui/Toast.d.ts +131 -0
- package/lib/ui/Toast.d.ts.map +1 -0
- package/lib/ui/Toaster.d.ts +188 -0
- package/lib/ui/Toaster.d.ts.map +1 -0
- package/lib/ui/UICanvas.d.ts +155 -0
- package/lib/ui/UICanvas.d.ts.map +1 -0
- package/lib/ui/index.d.ts +9 -0
- package/lib/ui/index.d.ts.map +1 -0
- package/lib/utils/array.d.ts +11 -0
- package/lib/utils/array.d.ts.map +1 -0
- package/lib/utils/bind.d.ts +21 -0
- package/lib/utils/bind.d.ts.map +1 -0
- package/lib/utils/canvas.d.ts +2 -0
- package/lib/utils/canvas.d.ts.map +1 -0
- package/lib/utils/color.d.ts +66 -0
- package/lib/utils/color.d.ts.map +1 -0
- package/lib/utils/console/Logger.d.ts +15 -0
- package/lib/utils/console/Logger.d.ts.map +1 -0
- package/lib/utils/console/index.d.ts +2 -0
- package/lib/utils/console/index.d.ts.map +1 -0
- package/lib/utils/debug.d.ts +34 -0
- package/lib/utils/debug.d.ts.map +1 -0
- package/lib/utils/define.d.ts +100 -0
- package/lib/utils/define.d.ts.map +1 -0
- package/lib/utils/env.d.ts +4 -0
- package/lib/utils/env.d.ts.map +1 -0
- package/lib/utils/events.d.ts +12 -0
- package/lib/utils/events.d.ts.map +1 -0
- package/lib/utils/framework.d.ts +12 -0
- package/lib/utils/framework.d.ts.map +1 -0
- package/lib/utils/index.d.ts +28 -0
- package/lib/utils/index.d.ts.map +1 -0
- package/lib/utils/map.d.ts +31 -0
- package/lib/utils/map.d.ts.map +1 -0
- package/lib/utils/math.d.ts +15 -0
- package/lib/utils/math.d.ts.map +1 -0
- package/lib/utils/misc.d.ts +13 -0
- package/lib/utils/misc.d.ts.map +1 -0
- package/lib/utils/number.d.ts +2 -0
- package/lib/utils/number.d.ts.map +1 -0
- package/lib/utils/object.d.ts +21 -0
- package/lib/utils/object.d.ts.map +1 -0
- package/lib/utils/padding.d.ts +4 -0
- package/lib/utils/padding.d.ts.map +1 -0
- package/lib/utils/pixi.d.ts +42 -0
- package/lib/utils/pixi.d.ts.map +1 -0
- package/lib/utils/platform.d.ts +20 -0
- package/lib/utils/platform.d.ts.map +1 -0
- package/lib/utils/point.d.ts +66 -0
- package/lib/utils/point.d.ts.map +1 -0
- package/lib/utils/promise/Queue.d.ts +60 -0
- package/lib/utils/promise/Queue.d.ts.map +1 -0
- package/lib/utils/promise/functions.d.ts +14 -0
- package/lib/utils/promise/functions.d.ts.map +1 -0
- package/lib/utils/promise/index.d.ts +3 -0
- package/lib/utils/promise/index.d.ts.map +1 -0
- package/lib/utils/random.d.ts +42 -0
- package/lib/utils/random.d.ts.map +1 -0
- package/lib/utils/rect.d.ts +26 -0
- package/lib/utils/rect.d.ts.map +1 -0
- package/lib/utils/set.d.ts +15 -0
- package/lib/utils/set.d.ts.map +1 -0
- package/lib/utils/string.d.ts +3 -0
- package/lib/utils/string.d.ts.map +1 -0
- package/lib/utils/text.d.ts +3 -0
- package/lib/utils/text.d.ts.map +1 -0
- package/lib/utils/typefilters.d.ts +4 -0
- package/lib/utils/typefilters.d.ts.map +1 -0
- package/lib/utils/types.d.ts +209 -0
- package/lib/utils/types.d.ts.map +1 -0
- package/lib/utils/vite.d.ts +25 -0
- package/lib/utils/vite.d.ts.map +1 -0
- package/lib/utils/web.d.ts +3 -0
- package/lib/utils/web.d.ts.map +1 -0
- package/lib/version.d.ts +3 -0
- package/lib/version.d.ts.map +1 -0
- package/lib/webgl-check.d.ts +2 -0
- package/lib/webgl-check.d.ts.map +1 -0
- package/package.json +138 -0
- package/src/core/Application.ts +1091 -0
- package/src/core/config.ts +168 -0
- package/src/core/create.ts +186 -0
- package/src/core/globals.ts +299 -0
- package/src/core/index.ts +6 -0
- package/src/core/interfaces/IApplication.ts +628 -0
- package/src/core/interfaces/IApplicationOptions.ts +81 -0
- package/src/core/interfaces/ICoreFunctions.ts +86 -0
- package/src/core/interfaces/ICoreSignals.ts +77 -0
- package/src/core/interfaces/IStorageCapability.test.ts +27 -0
- package/src/core/interfaces/IStorageCapability.ts +26 -0
- package/src/core/interfaces/index.ts +6 -0
- package/src/core/registries.ts +7 -0
- package/src/core/types.ts +13 -0
- package/src/display/AnimatedSprite.ts +227 -0
- package/src/display/Camera.ts +371 -0
- package/src/display/Container.ts +240 -0
- package/src/display/Entity.ts +50 -0
- package/src/display/ParticleContainer.ts +107 -0
- package/src/display/Scene.ts +305 -0
- package/src/display/SceneTransition.ts +108 -0
- package/src/display/SpineAnimation.ts +170 -0
- package/src/display/Svg.ts +9 -0
- package/src/display/index.ts +11 -0
- package/src/env.d.ts +6 -0
- package/src/hello.ts +20 -0
- package/src/index.ts +17 -0
- package/src/mixins/animated.ts +340 -0
- package/src/mixins/factory/Factory.ts +24 -0
- package/src/mixins/factory/const.ts +363 -0
- package/src/mixins/factory/index.ts +7 -0
- package/src/mixins/factory/methods.ts +21 -0
- package/src/mixins/factory/props.ts +207 -0
- package/src/mixins/factory/registry.test.ts +83 -0
- package/src/mixins/factory/registry.ts +61 -0
- package/src/mixins/factory/schema.ts +153 -0
- package/src/mixins/factory/ui-registry.ts +54 -0
- package/src/mixins/factory/utils.ts +130 -0
- package/src/mixins/focus.ts +124 -0
- package/src/mixins/index.ts +5 -0
- package/src/mixins/interaction.ts +74 -0
- package/src/mixins/signals.ts +49 -0
- package/src/plugins/AssetsPlugin.ts +407 -0
- package/src/plugins/DataAdapter.ts +259 -0
- package/src/plugins/DevToolsPlugin.ts +103 -0
- package/src/plugins/FullScreenPlugin.ts +359 -0
- package/src/plugins/GSAPPlugin.ts +811 -0
- package/src/plugins/KeyboardPlugin.ts +160 -0
- package/src/plugins/LayoutPlugin.ts +127 -0
- package/src/plugins/LookupPlugin.ts +308 -0
- package/src/plugins/Plugin.test.ts +73 -0
- package/src/plugins/Plugin.ts +200 -0
- package/src/plugins/PopupManagerPlugin.ts +263 -0
- package/src/plugins/ResizerPlugin.ts +220 -0
- package/src/plugins/SceneManagerPlugin.ts +669 -0
- package/src/plugins/StatsPlugin.ts +24 -0
- package/src/plugins/TimerPlugin.ts +841 -0
- package/src/plugins/WebEventsPlugin.ts +132 -0
- package/src/plugins/actions/ActionsPlugin.ts +113 -0
- package/src/plugins/actions/constants.ts +45 -0
- package/src/plugins/actions/index.ts +4 -0
- package/src/plugins/actions/methods.ts +28 -0
- package/src/plugins/actions/types.ts +47 -0
- package/src/plugins/audio/AudioChannel.test.ts +101 -0
- package/src/plugins/audio/AudioChannel.ts +164 -0
- package/src/plugins/audio/AudioInstance.ts +228 -0
- package/src/plugins/audio/AudioManagerPlugin.ts +903 -0
- package/src/plugins/audio/VoiceOverPlugin.ts +354 -0
- package/src/plugins/audio/index.ts +3 -0
- package/src/plugins/breakpoints/BreakpointPlugin.test.ts +228 -0
- package/src/plugins/breakpoints/BreakpointPlugin.ts +293 -0
- package/src/plugins/breakpoints/evaluate.test.ts +239 -0
- package/src/plugins/breakpoints/evaluate.ts +201 -0
- package/src/plugins/breakpoints/index.ts +3 -0
- package/src/plugins/breakpoints/methods.ts +22 -0
- package/src/plugins/breakpoints/types.ts +86 -0
- package/src/plugins/captions/CaptionsPlugin.ts +468 -0
- package/src/plugins/captions/CaptionsRenderer.ts +184 -0
- package/src/plugins/captions/font/Sans.fnt +116 -0
- package/src/plugins/captions/font/Sans.png +0 -0
- package/src/plugins/captions/index.ts +2 -0
- package/src/plugins/defaults.ts +95 -0
- package/src/plugins/focus/FocusManagerPlugin.ts +773 -0
- package/src/plugins/focus/FocusOutliner.ts +111 -0
- package/src/plugins/focus/index.ts +2 -0
- package/src/plugins/i18nPlugin.ts +284 -0
- package/src/plugins/index.ts +17 -0
- package/src/plugins/input/AbstractControls.ts +15 -0
- package/src/plugins/input/Controls.ts +55 -0
- package/src/plugins/input/InputPlugin.ts +168 -0
- package/src/plugins/input/constants.ts +12 -0
- package/src/plugins/input/index.ts +9 -0
- package/src/plugins/input/interfaces.ts +37 -0
- package/src/plugins/input/keyboard/KeyboardContols.ts +182 -0
- package/src/plugins/input/keyboard/index.ts +2 -0
- package/src/plugins/input/keyboard/interfaces.ts +21 -0
- package/src/plugins/input/methods.ts +9 -0
- package/src/plugins/input/touch/TouchControls.ts +237 -0
- package/src/plugins/input/touch/constants.ts +34 -0
- package/src/plugins/input/touch/index.ts +3 -0
- package/src/plugins/input/touch/interfaces.ts +15 -0
- package/src/plugins/input/types.ts +41 -0
- package/src/plugins/input/utils.ts +10 -0
- package/src/plugins/spine/SpinePlugin.ts +14 -0
- package/src/plugins/spine/pixi-spine/BatchableSpineSlot.ts +138 -0
- package/src/plugins/spine/pixi-spine/Spine.ts +897 -0
- package/src/plugins/spine/pixi-spine/SpineDebugRenderer.ts +615 -0
- package/src/plugins/spine/pixi-spine/SpinePipe.ts +197 -0
- package/src/plugins/spine/pixi-spine/SpineTexture.ts +143 -0
- package/src/plugins/spine/pixi-spine/assets/atlasLoader.ts +156 -0
- package/src/plugins/spine/pixi-spine/assets/skeletonLoader.ts +80 -0
- package/src/plugins/spine/pixi-spine/darktint/DarkTintBatchGeometry.ts +92 -0
- package/src/plugins/spine/pixi-spine/darktint/DarkTintBatcher.ts +186 -0
- package/src/plugins/spine/pixi-spine/darktint/DarkTintShader.ts +74 -0
- package/src/plugins/spine/pixi-spine/darktint/darkTintBit.ts +77 -0
- package/src/plugins/spine/pixi-spine/index.ts +43 -0
- package/src/plugins/spine/pixi-spine/require-shim.ts +43 -0
- package/src/signals/Signal.test.ts +54 -0
- package/src/signals/Signal.ts +68 -0
- package/src/signals/index.ts +10 -0
- package/src/store/Store.test.ts +146 -0
- package/src/store/Store.ts +192 -0
- package/src/store/index.ts +1 -0
- package/src/types/framework.d.ts +47 -0
- package/src/types/gsap.d.ts +26 -0
- package/src/ui/Button.ts +454 -0
- package/src/ui/FlexContainer.ts +526 -0
- package/src/ui/Input.ts +1274 -0
- package/src/ui/Joystick.ts +288 -0
- package/src/ui/Popup.ts +242 -0
- package/src/ui/Toast.ts +399 -0
- package/src/ui/Toaster.ts +409 -0
- package/src/ui/UICanvas.ts +812 -0
- package/src/ui/index.ts +8 -0
- package/src/utils/array.ts +24 -0
- package/src/utils/bind.ts +79 -0
- package/src/utils/canvas.ts +26 -0
- package/src/utils/color.ts +126 -0
- package/src/utils/console/Logger.ts +86 -0
- package/src/utils/console/index.ts +1 -0
- package/src/utils/debug.ts +69 -0
- package/src/utils/define.ts +120 -0
- package/src/utils/env.ts +3 -0
- package/src/utils/events.ts +10 -0
- package/src/utils/framework.ts +45 -0
- package/src/utils/index.ts +27 -0
- package/src/utils/map.ts +59 -0
- package/src/utils/math.ts +19 -0
- package/src/utils/misc.ts +45 -0
- package/src/utils/number.ts +3 -0
- package/src/utils/object.ts +43 -0
- package/src/utils/padding.ts +43 -0
- package/src/utils/pixi.ts +116 -0
- package/src/utils/platform.ts +33 -0
- package/src/utils/point.ts +123 -0
- package/src/utils/promise/Queue.ts +125 -0
- package/src/utils/promise/functions.ts +16 -0
- package/src/utils/promise/index.ts +2 -0
- package/src/utils/random.ts +69 -0
- package/src/utils/rect.ts +50 -0
- package/src/utils/set.ts +32 -0
- package/src/utils/string.ts +9 -0
- package/src/utils/text.ts +30 -0
- package/src/utils/typefilters.ts +29 -0
- package/src/utils/types.ts +426 -0
- package/src/utils/vite.ts +41 -0
- package/src/utils/web.ts +7 -0
- package/src/version.ts +3 -0
- package/src/webgl-check.ts +12 -0
- package/templates/app/default/.eslintrc.json +21 -0
- package/templates/app/default/.meta.json +4 -0
- package/templates/app/default/.nvmrc +1 -0
- package/templates/app/default/.prettierrc.json +7 -0
- package/templates/app/default/README.md +8 -0
- package/templates/app/default/assets/audio{m}/music/Cheerful Annoyance.ogg +0 -0
- package/templates/app/default/assets/audio{m}/music/Drumming Sticks.ogg +0 -0
- package/templates/app/default/assets/audio{m}/music/Game Over.ogg +0 -0
- package/templates/app/default/assets/audio{m}/music/Mishief Stroll.ogg +0 -0
- package/templates/app/default/assets/audio{m}/music/Night at the Beach.ogg +0 -0
- package/templates/app/default/assets/audio{m}/sfx/click.ogg +0 -0
- package/templates/app/default/assets/audio{m}/sfx/hover.ogg +0 -0
- package/templates/app/default/assets/required{m}/caper.png +0 -0
- package/templates/app/default/assets/required{m}/fonts{fix}/SpaceGrotesk-Bold{family=Space Grotesk}{wf}.ttf +0 -0
- package/templates/app/default/assets/required{m}/fonts{fix}/SpaceGrotesk-Medium{family=Space Grotesk}{wf}.ttf +0 -0
- package/templates/app/default/assets/required{m}/fonts{fix}/SpaceGrotesk-Regular{family=Space Grotesk}{wf}.ttf +0 -0
- package/templates/app/default/assets/required{m}/fonts{fix}/Syncopate-Bold{family=Syncopate}{wf}.ttf +0 -0
- package/templates/app/default/assets/required{m}/ui{tps}/btn/blue.png +0 -0
- package/templates/app/default/assets/required{m}/ui{tps}/btn/green.png +0 -0
- package/templates/app/default/assets/required{m}/ui{tps}/btn/grey.png +0 -0
- package/templates/app/default/assets/required{m}/ui{tps}/btn/orange.png +0 -0
- package/templates/app/default/assets/required{m}/ui{tps}/btn/purple.png +0 -0
- package/templates/app/default/assets/required{m}/ui{tps}/btn/red.png +0 -0
- package/templates/app/default/assets/required{m}/ui{tps}/btn/yellow.png +0 -0
- package/templates/app/default/assets/required{m}/ui{tps}/btn_a/down.png +0 -0
- package/templates/app/default/assets/required{m}/ui{tps}/btn_a/over.png +0 -0
- package/templates/app/default/assets/required{m}/ui{tps}/btn_a/up.png +0 -0
- package/templates/app/default/assets/required{m}/ui{tps}/btn_b/down.png +0 -0
- package/templates/app/default/assets/required{m}/ui{tps}/btn_b/over.png +0 -0
- package/templates/app/default/assets/required{m}/ui{tps}/btn_b/up.png +0 -0
- package/templates/app/default/assets/required{m}/ui{tps}/joystick/base.png +0 -0
- package/templates/app/default/assets/required{m}/ui{tps}/joystick/handle.png +0 -0
- package/templates/app/default/assets/required{m}/wordmark.svg +1 -0
- package/templates/app/default/assets/spine{m}/spineboy-pro.png +0 -0
- package/templates/app/default/assets/spine{m}/spineboy-pro.skel +0 -0
- package/templates/app/default/assets/spine{m}/spineboy-pro{fix}.atlas +94 -0
- package/templates/app/default/caper.config.ts +60 -0
- package/templates/app/default/index.html +23 -0
- package/templates/app/default/package.template.json +17 -0
- package/templates/app/default/public/favicon.ico +0 -0
- package/templates/app/default/src/__APPLICATION_NAME__.ts +3 -0
- package/templates/app/default/src/main.ts +9 -0
- package/templates/app/default/src/scenes/Base.ts +39 -0
- package/templates/app/default/src/scenes/Game.ts +34 -0
- package/templates/app/default/src/scenes/Splash.ts +70 -0
- package/templates/app/default/src/scenes/Start.ts +90 -0
- package/templates/app/default/src/utils/Constants.ts +3 -0
- package/templates/app/default/tsconfig.json +1 -0
- package/templates/plugin/package.template.json +33 -0
- package/templates/plugin/src/Plugin.template.ts +24 -0
- package/templates/plugin/src/index.template.ts +3 -0
- package/templates/plugin/tsconfig.template.json +43 -0
- package/templates/plugin/vite-env.template.d.ts +16 -0
- package/templates/plugin/vite.config.template.ts +19 -0
package/extras/llms.txt
ADDED
|
@@ -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.
|