@playcraft/skills 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +333 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/skills.loader.d.ts +31 -0
- package/dist/src/skills.loader.d.ts.map +1 -0
- package/dist/src/skills.loader.js +200 -0
- package/dist/src/skills.loader.js.map +1 -0
- package/dist/src/skills.types.d.ts +44 -0
- package/dist/src/skills.types.d.ts.map +1 -0
- package/dist/src/skills.types.js +9 -0
- package/dist/src/skills.types.js.map +1 -0
- package/package.json +35 -0
- package/skills/2048_core.aigameplay/SKILL.md +123 -0
- package/skills/2048_core.aigameplay/manifest.json +159 -0
- package/skills/2048_core.aigameplay/ref/pgs-schema.json +194 -0
- package/skills/2048_core.aigameplay/ref/reducer.template.ts +189 -0
- package/skills/SKILL.md +46 -0
- package/skills/ad_compliance_rules.aiconfig/SKILL.md +85 -0
- package/skills/ad_compliance_rules.aiconfig/manifest.json +60 -0
- package/skills/agent_remix_orchestrator.aicomponent/SKILL.md +257 -0
- package/skills/agent_remix_orchestrator.aicomponent/manifest.json +12 -0
- package/skills/app_metadata.aiconfig/SKILL.md +53 -0
- package/skills/app_metadata.aiconfig/manifest.json +32 -0
- package/skills/appear_sfx.aiaudio/SKILL.md +59 -0
- package/skills/appear_sfx.aiaudio/manifest.json +45 -0
- package/skills/appear_sfx.aiaudio/ref/appear.mp3 +0 -0
- package/skills/arrow_move_error_sfx.aiaudio/SKILL.md +59 -0
- package/skills/arrow_move_error_sfx.aiaudio/manifest.json +45 -0
- package/skills/arrow_move_error_sfx.aiaudio/ref/arrow_move_error.mp3 +0 -0
- package/skills/arrow_path_data_format.aicomponent/SKILL.md +152 -0
- package/skills/arrow_path_data_format.aicomponent/manifest.json +57 -0
- package/skills/arrow_path_data_format.aicomponent/ref/LevelParser.ts +188 -0
- package/skills/arrow_path_data_format.aicomponent/ref/LevelTypes.ts +131 -0
- package/skills/arrow_pick_match_rules.aigameplay/SKILL.md +117 -0
- package/skills/arrow_pick_match_rules.aigameplay/manifest.json +105 -0
- package/skills/arrow_pick_match_rules.aigameplay/ref/pgs-schema.json +180 -0
- package/skills/asset_pipeline_scripts.aicomponent/SKILL.md +117 -0
- package/skills/asset_pipeline_scripts.aicomponent/manifest.json +17 -0
- package/skills/asset_pipeline_scripts.aicomponent/ref/gen-sprite.sh +105 -0
- package/skills/ball_sort.aigameplay/SKILL.md +109 -0
- package/skills/ball_sort.aigameplay/manifest.json +155 -0
- package/skills/ball_sort.aigameplay/ref/pgs-schema.json +192 -0
- package/skills/ball_sort.aigameplay/ref/reducer.template.ts +156 -0
- package/skills/basketball_shot.aigameplay/SKILL.md +94 -0
- package/skills/basketball_shot.aigameplay/manifest.json +150 -0
- package/skills/basketball_shot.aigameplay/ref/pgs-schema.json +229 -0
- package/skills/basketball_shot.aigameplay/ref/reducer.template.ts +189 -0
- package/skills/bg_music.aiaudio/SKILL.md +61 -0
- package/skills/bg_music.aiaudio/manifest.json +48 -0
- package/skills/bg_music.aiaudio/ref/bg.mp3 +0 -0
- package/skills/big_watermelon.aigameplay/SKILL.md +94 -0
- package/skills/big_watermelon.aigameplay/manifest.json +155 -0
- package/skills/big_watermelon.aigameplay/ref/pgs-schema.json +191 -0
- package/skills/big_watermelon.aigameplay/ref/reducer.template.ts +202 -0
- package/skills/block_puzzle.aigameplay/SKILL.md +121 -0
- package/skills/block_puzzle.aigameplay/manifest.json +154 -0
- package/skills/block_puzzle.aigameplay/ref/pgs-schema.json +170 -0
- package/skills/block_puzzle.aigameplay/ref/reducer.template.ts +182 -0
- package/skills/board_entity_sprite.aiimage/SKILL.md +255 -0
- package/skills/board_entity_sprite.aiimage/manifest.json +153 -0
- package/skills/board_entity_sprite.aiimage/ref/ProceduralCar.ts +357 -0
- package/skills/board_entity_sprite.aiimage/ref/car.png +0 -0
- package/skills/board_entity_sprite.aiimage/ref/car.webp +0 -0
- package/skills/bottom_ui_bar.aicomponent/SKILL.md +50 -0
- package/skills/bottom_ui_bar.aicomponent/manifest.json +31 -0
- package/skills/bottom_ui_bar.aicomponent/ref/GameBottomUI.ts +27 -0
- package/skills/bubble_shooter.aigameplay/SKILL.md +129 -0
- package/skills/bubble_shooter.aigameplay/manifest.json +181 -0
- package/skills/bubble_shooter.aigameplay/ref/pgs-schema.json +226 -0
- package/skills/bubble_shooter.aigameplay/ref/reducer.template.ts +228 -0
- package/skills/button_click_sfx.aiaudio/SKILL.md +59 -0
- package/skills/button_click_sfx.aiaudio/manifest.json +45 -0
- package/skills/button_click_sfx.aiaudio/ref/button_click.mp3 +0 -0
- package/skills/calm_piano.aiaudio/SKILL.md +68 -0
- package/skills/calm_piano.aiaudio/manifest.json +50 -0
- package/skills/camera_controller_3d.aicomponent/SKILL.md +100 -0
- package/skills/camera_controller_3d.aicomponent/manifest.json +52 -0
- package/skills/camera_controller_3d.aicomponent/ref/CameraController.ts +199 -0
- package/skills/camera_controller_3d.aicomponent/ref/OrbitControlsAdapter.ts +152 -0
- package/skills/candy_tile.aiimage/SKILL.md +62 -0
- package/skills/candy_tile.aiimage/manifest.json +49 -0
- package/skills/car_parking.aigameplay/SKILL.md +105 -0
- package/skills/car_parking.aigameplay/manifest.json +164 -0
- package/skills/car_parking.aigameplay/ref/pgs-schema.json +163 -0
- package/skills/car_parking.aigameplay/ref/reducer.template.ts +166 -0
- package/skills/castle.aiimage/SKILL.md +64 -0
- package/skills/castle.aiimage/manifest.json +48 -0
- package/skills/cheerful_ukulele.aiaudio/SKILL.md +72 -0
- package/skills/cheerful_ukulele.aiaudio/manifest.json +50 -0
- package/skills/click_sfx.aiaudio/SKILL.md +59 -0
- package/skills/click_sfx.aiaudio/manifest.json +45 -0
- package/skills/click_sfx.aiaudio/ref/click.mp3 +0 -0
- package/skills/combo_display.aicomponent/SKILL.md +45 -0
- package/skills/combo_display.aicomponent/manifest.json +31 -0
- package/skills/combo_display.aicomponent/ref/ComboManager.ts +362 -0
- package/skills/combo_display.aicomponent/ref/ComboSmallUI.ts +232 -0
- package/skills/combo_praise_text.aicomponent/SKILL.md +56 -0
- package/skills/combo_praise_text.aicomponent/manifest.json +34 -0
- package/skills/combo_praise_text.aicomponent/ref/ComboManager.ts +362 -0
- package/skills/countdown_timer.aicomponent/SKILL.md +44 -0
- package/skills/countdown_timer.aicomponent/manifest.json +35 -0
- package/skills/countdown_timer.aicomponent/ref/CountdownDisplay.ts +213 -0
- package/skills/cta_platform_config.aiconfig/SKILL.md +72 -0
- package/skills/cta_platform_config.aiconfig/manifest.json +56 -0
- package/skills/debug_overlay.aicomponent/SKILL.md +75 -0
- package/skills/debug_overlay.aicomponent/manifest.json +17 -0
- package/skills/debug_overlay.aicomponent/ref/DebugOverlay.ts +144 -0
- package/skills/desert.aiimage/SKILL.md +63 -0
- package/skills/desert.aiimage/manifest.json +49 -0
- package/skills/difficulty_curve_designer.aiconfig/SKILL.md +68 -0
- package/skills/difficulty_curve_designer.aiconfig/manifest.json +36 -0
- package/skills/digit_renderer.aicomponent/SKILL.md +43 -0
- package/skills/digit_renderer.aicomponent/manifest.json +25 -0
- package/skills/digit_renderer.aicomponent/ref/DigitRenderer.ts +237 -0
- package/skills/download_button.aicomponent/SKILL.md +44 -0
- package/skills/download_button.aicomponent/manifest.json +25 -0
- package/skills/download_button.aicomponent/ref/DownloadButton.ts +137 -0
- package/skills/draw_line_puzzle.aigameplay/SKILL.md +84 -0
- package/skills/draw_line_puzzle.aigameplay/manifest.json +152 -0
- package/skills/draw_line_puzzle.aigameplay/ref/pgs-schema.json +189 -0
- package/skills/draw_line_puzzle.aigameplay/ref/reducer.template.ts +194 -0
- package/skills/easy_to_hard.aiconfig/SKILL.md +52 -0
- package/skills/easy_to_hard.aiconfig/manifest.json +33 -0
- package/skills/eight_ball_pool.aigameplay/SKILL.md +104 -0
- package/skills/eight_ball_pool.aigameplay/manifest.json +152 -0
- package/skills/eight_ball_pool.aigameplay/ref/pgs-schema.json +205 -0
- package/skills/eight_ball_pool.aigameplay/ref/reducer.template.ts +198 -0
- package/skills/energetic_electronic.aiaudio/SKILL.md +69 -0
- package/skills/energetic_electronic.aiaudio/manifest.json +51 -0
- package/skills/fail_sfx.aiaudio/SKILL.md +59 -0
- package/skills/fail_sfx.aiaudio/manifest.json +44 -0
- package/skills/fail_sfx.aiaudio/ref/fail.mp3 +0 -0
- package/skills/figer_icon.aiimage/SKILL.md +58 -0
- package/skills/figer_icon.aiimage/manifest.json +48 -0
- package/skills/figer_icon.aiimage/ref/figer.png +0 -0
- package/skills/figer_icon.aiimage/ref/figer.webp +0 -0
- package/skills/forest.aiimage/SKILL.md +74 -0
- package/skills/forest.aiimage/manifest.json +48 -0
- package/skills/fruit_tile.aiimage/SKILL.md +68 -0
- package/skills/fruit_tile.aiimage/manifest.json +48 -0
- package/skills/game_over_panel.aicomponent/SKILL.md +47 -0
- package/skills/game_over_panel.aicomponent/manifest.json +61 -0
- package/skills/game_over_panel.aicomponent/ref/GameOverPanel.ts +74 -0
- package/skills/game_scene.aicomponent/SKILL.md +57 -0
- package/skills/game_scene.aicomponent/manifest.json +36 -0
- package/skills/game_scene.aicomponent/ref/Game.ts +748 -0
- package/skills/gameplay_balance_check.aivalidator/SKILL.md +69 -0
- package/skills/gameplay_balance_check.aivalidator/manifest.json +21 -0
- package/skills/gameplay_unit_test.aivalidator/SKILL.md +89 -0
- package/skills/gameplay_unit_test.aivalidator/manifest.json +17 -0
- package/skills/gameplay_unit_test.aivalidator/ref/gameplay.test.ts +202 -0
- package/skills/gameplay_unit_test.aivalidator/ref/vitest.config.ts +13 -0
- package/skills/grid_board_layout.aicomponent/SKILL.md +85 -0
- package/skills/grid_board_layout.aicomponent/manifest.json +69 -0
- package/skills/grid_board_layout.aicomponent/ref/BoardLayout.ts +416 -0
- package/skills/grid_board_layout.aicomponent/ref/BoardLayout3D.ts +125 -0
- package/skills/grid_board_layout.aicomponent/ref/BoardLayoutMath.ts +85 -0
- package/skills/grid_board_layout.aicomponent/ref/BoardRenderer3D.ts +298 -0
- package/skills/heart_lives.aicomponent/SKILL.md +42 -0
- package/skills/heart_lives.aicomponent/manifest.json +25 -0
- package/skills/heart_lives.aicomponent/ref/HeartDisplay.ts +96 -0
- package/skills/idle-breathe.aicomponent/SKILL.md +27 -0
- package/skills/idle-breathe.aicomponent/manifest.json +20 -0
- package/skills/idle-breathe.aicomponent/ref/phaser.js +25 -0
- package/skills/idle-breathe.aicomponent/ref/playcanvas.js +29 -0
- package/skills/jewel_tile.aiimage/SKILL.md +63 -0
- package/skills/jewel_tile.aiimage/manifest.json +49 -0
- package/skills/knife_hit.aigameplay/SKILL.md +103 -0
- package/skills/knife_hit.aigameplay/manifest.json +151 -0
- package/skills/knife_hit.aigameplay/ref/pgs-schema.json +202 -0
- package/skills/knife_hit.aigameplay/ref/reducer.template.ts +196 -0
- package/skills/left_right_parkour.aigameplay/SKILL.md +120 -0
- package/skills/left_right_parkour.aigameplay/manifest.json +165 -0
- package/skills/left_right_parkour.aigameplay/ref/pgs-schema.json +200 -0
- package/skills/left_right_parkour.aigameplay/ref/reducer.template.ts +194 -0
- package/skills/level_data_pack.aiconfig/SKILL.md +64 -0
- package/skills/level_data_pack.aiconfig/manifest.json +37 -0
- package/skills/level_data_validator.aivalidator/SKILL.md +85 -0
- package/skills/level_data_validator.aivalidator/manifest.json +17 -0
- package/skills/level_data_validator.aivalidator/ref/LevelValidator.ts +113 -0
- package/skills/level_lifecycle.aicomponent/SKILL.md +81 -0
- package/skills/level_lifecycle.aicomponent/manifest.json +87 -0
- package/skills/level_lifecycle.aicomponent/ref/LevelLifecycle.ts +235 -0
- package/skills/level_solvability_validator.aivalidator/SKILL.md +74 -0
- package/skills/level_solvability_validator.aivalidator/manifest.json +23 -0
- package/skills/level_solvability_validator.aivalidator/ref/LevelValidator.ts +186 -0
- package/skills/level_state.aicomponent/SKILL.md +55 -0
- package/skills/level_state.aicomponent/manifest.json +34 -0
- package/skills/level_state.aicomponent/ref/LevelDataManager.ts +26 -0
- package/skills/level_state.aicomponent/ref/LevelManager.ts +26 -0
- package/skills/loading_screen.aicomponent/SKILL.md +57 -0
- package/skills/loading_screen.aicomponent/manifest.json +43 -0
- package/skills/loading_screen.aicomponent/ref/LoadingUI.ts +339 -0
- package/skills/lose_result_panel.aiimage/SKILL.md +58 -0
- package/skills/lose_result_panel.aiimage/manifest.json +47 -0
- package/skills/lose_result_panel.aiimage/ref/lose.png +0 -0
- package/skills/lose_result_panel.aiimage/ref/lose.webp +0 -0
- package/skills/lose_sfx.aiaudio/SKILL.md +59 -0
- package/skills/lose_sfx.aiaudio/manifest.json +45 -0
- package/skills/lose_sfx.aiaudio/ref/lose.mp3 +0 -0
- package/skills/match-pop.aicomponent/SKILL.md +29 -0
- package/skills/match-pop.aicomponent/manifest.json +19 -0
- package/skills/match-pop.aicomponent/ref/phaser.js +30 -0
- package/skills/match-pop.aicomponent/ref/playcanvas.js +22 -0
- package/skills/match3_core.aigameplay/SKILL.md +125 -0
- package/skills/match3_core.aigameplay/manifest.json +107 -0
- package/skills/match3_core.aigameplay/ref/pgs-schema.json +154 -0
- package/skills/match3_core.aigameplay/ref/reducer.template.ts +191 -0
- package/skills/match_engine.aicomponent/SKILL.md +84 -0
- package/skills/match_engine.aicomponent/manifest.json +23 -0
- package/skills/match_engine.aicomponent/ref/MatchEngine.ts +75 -0
- package/skills/memory_match.aigameplay/SKILL.md +111 -0
- package/skills/memory_match.aigameplay/manifest.json +164 -0
- package/skills/memory_match.aigameplay/ref/pgs-schema.json +190 -0
- package/skills/memory_match.aigameplay/ref/reducer.template.ts +162 -0
- package/skills/merge_core.aigameplay/SKILL.md +112 -0
- package/skills/merge_core.aigameplay/manifest.json +154 -0
- package/skills/merge_core.aigameplay/ref/pgs-schema.json +202 -0
- package/skills/merge_core.aigameplay/ref/reducer.template.ts +179 -0
- package/skills/mistake_sfx.aiaudio/SKILL.md +59 -0
- package/skills/mistake_sfx.aiaudio/manifest.json +45 -0
- package/skills/mistake_sfx.aiaudio/ref/mistake.mp3 +0 -0
- package/skills/nomove_hint_overlay.aiimage/SKILL.md +58 -0
- package/skills/nomove_hint_overlay.aiimage/manifest.json +48 -0
- package/skills/nomove_hint_overlay.aiimage/ref/nomove_hint.png +0 -0
- package/skills/nomove_hint_overlay.aiimage/ref/nomove_hint.webp +0 -0
- package/skills/normal_dot.aiimage/SKILL.md +58 -0
- package/skills/normal_dot.aiimage/manifest.json +46 -0
- package/skills/normal_dot.aiimage/ref/normal_dot.png +0 -0
- package/skills/normal_dot.aiimage/ref/normal_dot.webp +0 -0
- package/skills/ocean.aiimage/SKILL.md +71 -0
- package/skills/ocean.aiimage/manifest.json +49 -0
- package/skills/particle-confetti.aicomponent/SKILL.md +32 -0
- package/skills/particle-confetti.aicomponent/manifest.json +21 -0
- package/skills/particle-confetti.aicomponent/ref/html5-spritesheet.js +17 -0
- package/skills/particle-confetti.aicomponent/ref/phaser.js +38 -0
- package/skills/particle-explosion.aicomponent/SKILL.md +37 -0
- package/skills/particle-explosion.aicomponent/manifest.json +24 -0
- package/skills/particle-explosion.aicomponent/ref/html5-spritesheet.js +40 -0
- package/skills/particle-explosion.aicomponent/ref/phaser.js +46 -0
- package/skills/particle-explosion.aicomponent/ref/playcanvas.js +33 -0
- package/skills/particle-trail.aicomponent/SKILL.md +25 -0
- package/skills/particle-trail.aicomponent/manifest.json +22 -0
- package/skills/particle-trail.aicomponent/ref/phaser.js +31 -0
- package/skills/path_animation.aicomponent/SKILL.md +82 -0
- package/skills/path_animation.aicomponent/manifest.json +77 -0
- package/skills/path_animation.aicomponent/ref/AnimationManager.ts +694 -0
- package/skills/path_animation.aicomponent/ref/AnimationManager3D.ts +317 -0
- package/skills/path_elimination_rules.aigameplay/SKILL.md +88 -0
- package/skills/path_elimination_rules.aigameplay/manifest.json +119 -0
- package/skills/path_elimination_rules.aigameplay/ref/pgs-schema.json +227 -0
- package/skills/path_input_handler.aicomponent/SKILL.md +87 -0
- package/skills/path_input_handler.aicomponent/manifest.json +97 -0
- package/skills/path_input_handler.aicomponent/ref/InputHandler.ts +714 -0
- package/skills/path_input_handler.aicomponent/ref/InputHandler3D.ts +204 -0
- package/skills/path_renderer.aicomponent/SKILL.md +101 -0
- package/skills/path_renderer.aicomponent/manifest.json +69 -0
- package/skills/path_renderer.aicomponent/ref/PathRenderer.ts +509 -0
- package/skills/path_renderer.aicomponent/ref/PathRenderer3D.ts +176 -0
- package/skills/path_renderer.aicomponent/ref/PathRenderers.ts +640 -0
- package/skills/phaser.aicomponent/SKILL.md +315 -0
- package/skills/phaser.aicomponent/manifest.json +156 -0
- package/skills/phaser.aicomponent/ref/BootScene.ts +29 -0
- package/skills/phaser.aicomponent/ref/GameConfig.ts +29 -0
- package/skills/phaser.aicomponent/ref/GameScene.ts +88 -0
- package/skills/phaser.aicomponent/ref/PreloaderScene.ts +78 -0
- package/skills/phaser.aicomponent/ref/SceneKeys.ts +7 -0
- package/skills/phaser.aicomponent/ref/SoundUtils.ts +21 -0
- package/skills/phaser.aicomponent/ref/UiLayout.ts +74 -0
- package/skills/phaser.aicomponent/ref/globals.d.ts +52 -0
- package/skills/phaser.aicomponent/ref/index.css +40 -0
- package/skills/phaser.aicomponent/ref/index.html +14 -0
- package/skills/phaser.aicomponent/ref/index.ts +48 -0
- package/skills/phaser.aicomponent/ref/main.ts +16 -0
- package/skills/phaser.aicomponent/ref/package.json +22 -0
- package/skills/phaser.aicomponent/ref/tsconfig.json +25 -0
- package/skills/phaser.aicomponent/ref/webpack.config.js +57 -0
- package/skills/phaser_scene_lifecycle.aicomponent/SKILL.md +63 -0
- package/skills/phaser_scene_lifecycle.aicomponent/manifest.json +33 -0
- package/skills/pick_and_match_rules.aigameplay/SKILL.md +113 -0
- package/skills/pick_and_match_rules.aigameplay/manifest.json +121 -0
- package/skills/pick_and_match_rules.aigameplay/ref/pgs-schema.json +354 -0
- package/skills/pin_pull.aigameplay/SKILL.md +110 -0
- package/skills/pin_pull.aigameplay/manifest.json +164 -0
- package/skills/pin_pull.aigameplay/ref/pgs-schema.json +201 -0
- package/skills/pin_pull.aigameplay/ref/reducer.template.ts +216 -0
- package/skills/playable_app_logo.aiimage/SKILL.md +58 -0
- package/skills/playable_app_logo.aiimage/manifest.json +47 -0
- package/skills/playable_app_logo.aiimage/ref/logo.png +0 -0
- package/skills/playable_app_logo.aiimage/ref/logo.webp +0 -0
- package/skills/playable_end_screen_layout.aicomponent/SKILL.md +75 -0
- package/skills/playable_end_screen_layout.aicomponent/manifest.json +24 -0
- package/skills/playable_guidance_layer.aicomponent/SKILL.md +89 -0
- package/skills/playable_guidance_layer.aicomponent/manifest.json +24 -0
- package/skills/playable_hud_layout.aicomponent/SKILL.md +96 -0
- package/skills/playable_hud_layout.aicomponent/manifest.json +24 -0
- package/skills/playable_scripts_build.aicomponent/SKILL.md +69 -0
- package/skills/playable_scripts_build.aicomponent/manifest.json +53 -0
- package/skills/playable_scripts_build.aicomponent/ref/builds.config.js +257 -0
- package/skills/playcraft-3d-flip-sprite/SKILL.md +336 -0
- package/skills/playcraft-3d-flip-sprite/renderer/flatten_glb.mjs +62 -0
- package/skills/playcraft-3d-flip-sprite/renderer/render.mjs +325 -0
- package/skills/playcraft-3d-flip-sprite/renderer/render_single.mjs +138 -0
- package/skills/playcraft-asset-management/SKILL.md +73 -0
- package/skills/playcraft-audio-generation/SKILL.md +126 -0
- package/skills/playcraft-build/SKILL.md +44 -0
- package/skills/playcraft-code-editor/SKILL.md +71 -0
- package/skills/playcraft-create-remix/SKILL.md +62 -0
- package/skills/playcraft-deploy/SKILL.md +59 -0
- package/skills/playcraft-image-generation/SKILL.md +148 -0
- package/skills/playcraft-image-processing/SKILL.md +216 -0
- package/skills/playcraft-platform-intro/SKILL.md +41 -0
- package/skills/playcraft-prefab/SKILL.md +98 -0
- package/skills/playcraft-project-management/SKILL.md +57 -0
- package/skills/playcraft-remix-workflow/SKILL.md +119 -0
- package/skills/playcraft-remix-workflow/references/xplatform.schema.json5 +31 -0
- package/skills/playcraft-save/SKILL.md +46 -0
- package/skills/playcraft-skill-recommender/SKILL.md +152 -0
- package/skills/playcraft-sprite-generation/SKILL.md +534 -0
- package/skills/playcraft-sprite-remix/SKILL.md +155 -0
- package/skills/playcraft-sprite-sheet/SKILL.md +97 -0
- package/skills/playtest_report.aivalidator/SKILL.md +103 -0
- package/skills/playtest_report.aivalidator/manifest.json +21 -0
- package/skills/preloader_scene.aicomponent/SKILL.md +58 -0
- package/skills/preloader_scene.aicomponent/manifest.json +43 -0
- package/skills/preloader_scene.aicomponent/ref/Preloader.ts +339 -0
- package/skills/progress_bar.aicomponent/SKILL.md +38 -0
- package/skills/progress_bar.aicomponent/manifest.json +25 -0
- package/skills/progress_bar.aicomponent/ref/ProgressDisplay.ts +140 -0
- package/skills/references/xplatform.schema.json5 +31 -0
- package/skills/responsive_2d_layout.aicomponent/SKILL.md +161 -0
- package/skills/responsive_2d_layout.aicomponent/manifest.json +43 -0
- package/skills/responsive_2d_layout.aicomponent/ref/UiLayout.ts +56 -0
- package/skills/run_context_state.aicomponent/SKILL.md +54 -0
- package/skills/run_context_state.aicomponent/manifest.json +40 -0
- package/skills/run_context_state.aicomponent/ref/RunContextRuntime.ts +30 -0
- package/skills/score-fly.aicomponent/SKILL.md +31 -0
- package/skills/score-fly.aicomponent/manifest.json +21 -0
- package/skills/score-fly.aicomponent/ref/phaser.js +26 -0
- package/skills/score-fly.aicomponent/ref/playcanvas.js +28 -0
- package/skills/score_goal.aiconfig/SKILL.md +46 -0
- package/skills/score_goal.aiconfig/manifest.json +33 -0
- package/skills/screen-flash.aicomponent/SKILL.md +30 -0
- package/skills/screen-flash.aicomponent/manifest.json +20 -0
- package/skills/screen-flash.aicomponent/ref/phaser.js +48 -0
- package/skills/screen-shake.aicomponent/SKILL.md +30 -0
- package/skills/screen-shake.aicomponent/manifest.json +19 -0
- package/skills/screen-shake.aicomponent/ref/phaser.js +23 -0
- package/skills/screen-shake.aicomponent/ref/playcanvas.js +44 -0
- package/skills/screw_puzzle.aigameplay/SKILL.md +116 -0
- package/skills/screw_puzzle.aigameplay/manifest.json +164 -0
- package/skills/screw_puzzle.aigameplay/ref/pgs-schema.json +235 -0
- package/skills/screw_puzzle.aigameplay/ref/reducer.template.ts +213 -0
- package/skills/settings_state.aicomponent/SKILL.md +61 -0
- package/skills/settings_state.aicomponent/manifest.json +33 -0
- package/skills/settings_state.aicomponent/ref/SettingsManager.ts +130 -0
- package/skills/slide_out_to_tray_animation.aicomponent/SKILL.md +64 -0
- package/skills/slide_out_to_tray_animation.aicomponent/manifest.json +58 -0
- package/skills/slide_out_to_tray_animation.aicomponent/ref/AnimationManager.ts +164 -0
- package/skills/slide_out_to_tray_animation.aicomponent/ref/AnimationManager3D.ts +198 -0
- package/skills/slide_out_to_tray_animation.aicomponent/ref/BezierUtils.ts +59 -0
- package/skills/slot_machine.aigameplay/SKILL.md +119 -0
- package/skills/slot_machine.aigameplay/manifest.json +166 -0
- package/skills/slot_machine.aigameplay/ref/pgs-schema.json +212 -0
- package/skills/slot_machine.aigameplay/ref/reducer.template.ts +212 -0
- package/skills/sniper_shot.aigameplay/SKILL.md +84 -0
- package/skills/sniper_shot.aigameplay/manifest.json +153 -0
- package/skills/sniper_shot.aigameplay/ref/pgs-schema.json +211 -0
- package/skills/sniper_shot.aigameplay/ref/reducer.template.ts +211 -0
- package/skills/solitaire.aigameplay/SKILL.md +101 -0
- package/skills/solitaire.aigameplay/manifest.json +151 -0
- package/skills/solitaire.aigameplay/ref/pgs-schema.json +200 -0
- package/skills/solitaire.aigameplay/ref/reducer.template.ts +176 -0
- package/skills/sound-effects/SKILL.md +46 -0
- package/skills/sound_utils.aicomponent/SKILL.md +52 -0
- package/skills/sound_utils.aicomponent/manifest.json +30 -0
- package/skills/sound_utils.aicomponent/ref/SoundUtils.ts +29 -0
- package/skills/sprite-animation-2d.aicomponent/SKILL.md +45 -0
- package/skills/sprite-animation-2d.aicomponent/manifest.json +28 -0
- package/skills/sprite-animation-2d.aicomponent/ref/html5.js +83 -0
- package/skills/sprite-animation-2d.aicomponent/ref/phaser.js +38 -0
- package/skills/sprite-animation-2d.aicomponent/ref/playcanvas.js +67 -0
- package/skills/sprite_entity_renderer.aicomponent/SKILL.md +148 -0
- package/skills/sprite_entity_renderer.aicomponent/manifest.json +17 -0
- package/skills/sprite_entity_renderer.aicomponent/ref/SpriteEntityRenderer.ts +126 -0
- package/skills/success_sfx.aiaudio/SKILL.md +59 -0
- package/skills/success_sfx.aiaudio/manifest.json +45 -0
- package/skills/success_sfx.aiaudio/ref/success.mp3 +0 -0
- package/skills/tap_blast.aigameplay/SKILL.md +116 -0
- package/skills/tap_blast.aigameplay/manifest.json +153 -0
- package/skills/tap_blast.aigameplay/ref/pgs-schema.json +208 -0
- package/skills/tap_blast.aigameplay/ref/reducer.template.ts +202 -0
- package/skills/theme_state.aicomponent/SKILL.md +53 -0
- package/skills/theme_state.aicomponent/manifest.json +33 -0
- package/skills/theme_state.aicomponent/ref/ThemeManager.ts +174 -0
- package/skills/theme_switcher_build.aicomponent/SKILL.md +62 -0
- package/skills/theme_switcher_build.aicomponent/manifest.json +38 -0
- package/skills/theme_switcher_build.aicomponent/ref/theme-index.ts +8 -0
- package/skills/theme_variant.aiconfig/SKILL.md +78 -0
- package/skills/theme_variant.aiconfig/manifest.json +39 -0
- package/skills/theme_variant.aiconfig/ref/ExampleTheme/index.ts +16 -0
- package/skills/theme_variant.aiconfig/ref/ExampleTheme/levelEasy.json +141 -0
- package/skills/threejs.aicomponent/SKILL.md +422 -0
- package/skills/threejs.aicomponent/manifest.json +166 -0
- package/skills/threejs.aicomponent/ref/AssetLoader.ts +158 -0
- package/skills/threejs.aicomponent/ref/BaseScene.ts +88 -0
- package/skills/threejs.aicomponent/ref/GameConfig.ts +47 -0
- package/skills/threejs.aicomponent/ref/MainScene.ts +170 -0
- package/skills/threejs.aicomponent/ref/PreloaderScene.ts +93 -0
- package/skills/threejs.aicomponent/ref/SceneKeys.ts +6 -0
- package/skills/threejs.aicomponent/ref/SceneManager.ts +69 -0
- package/skills/threejs.aicomponent/ref/ViewportManager.ts +62 -0
- package/skills/threejs.aicomponent/ref/globals.d.ts +74 -0
- package/skills/threejs.aicomponent/ref/index.css +80 -0
- package/skills/threejs.aicomponent/ref/index.html +20 -0
- package/skills/threejs.aicomponent/ref/index.ts +117 -0
- package/skills/threejs.aicomponent/ref/main.ts +10 -0
- package/skills/threejs.aicomponent/ref/package.json +23 -0
- package/skills/threejs.aicomponent/ref/tsconfig.json +24 -0
- package/skills/threejs.aicomponent/ref/webpack.config.js +61 -0
- package/skills/time_clear_goal.aiconfig/SKILL.md +46 -0
- package/skills/time_clear_goal.aiconfig/manifest.json +32 -0
- package/skills/time_icon.aiimage/SKILL.md +58 -0
- package/skills/time_icon.aiimage/manifest.json +47 -0
- package/skills/time_icon.aiimage/ref/time.png +0 -0
- package/skills/time_icon.aiimage/ref/time.webp +0 -0
- package/skills/top_ui_bar.aicomponent/SKILL.md +45 -0
- package/skills/top_ui_bar.aicomponent/manifest.json +27 -0
- package/skills/top_ui_bar.aicomponent/ref/GameTopUI.ts +229 -0
- package/skills/tower_defence.aigameplay/SKILL.md +117 -0
- package/skills/tower_defence.aigameplay/manifest.json +175 -0
- package/skills/tower_defence.aigameplay/ref/pgs-schema.json +247 -0
- package/skills/tower_defence.aigameplay/ref/reducer.template.ts +239 -0
- package/skills/tray_container.aicomponent/SKILL.md +143 -0
- package/skills/tray_container.aicomponent/manifest.json +58 -0
- package/skills/tray_container.aicomponent/ref/TrayRenderer.ts +155 -0
- package/skills/tray_container.aicomponent/ref/TrayRenderer3D.ts +281 -0
- package/skills/tray_container.aicomponent/ref/TrayRendererHtmlOverlay.ts +228 -0
- package/skills/tutorial_overlay.aicomponent/SKILL.md +46 -0
- package/skills/tutorial_overlay.aicomponent/manifest.json +34 -0
- package/skills/tutorial_overlay.aicomponent/ref/TutorialManager.ts +367 -0
- package/skills/tween-animation-2d.aicomponent/SKILL.md +35 -0
- package/skills/tween-animation-2d.aicomponent/manifest.json +28 -0
- package/skills/tween-animation-2d.aicomponent/ref/phaser.js +49 -0
- package/skills/tween-animation-2d.aicomponent/ref/playcanvas.js +36 -0
- package/skills/typescript_module_patterns.aicomponent/SKILL.md +209 -0
- package/skills/typescript_module_patterns.aicomponent/manifest.json +28 -0
- package/skills/typescript_module_patterns.aicomponent/ref/globals.d.ts +31 -0
- package/skills/ui-transition.aicomponent/SKILL.md +33 -0
- package/skills/ui-transition.aicomponent/manifest.json +19 -0
- package/skills/ui-transition.aicomponent/ref/phaser.js +45 -0
- package/skills/ux_flow_spec.aiconfig/SKILL.md +82 -0
- package/skills/ux_flow_spec.aiconfig/manifest.json +39 -0
- package/skills/wave_difficulty.aiconfig/SKILL.md +46 -0
- package/skills/wave_difficulty.aiconfig/manifest.json +33 -0
- package/skills/webpack_build.aicomponent/SKILL.md +204 -0
- package/skills/webpack_build.aicomponent/manifest.json +29 -0
- package/skills/webpack_build.aicomponent/ref/package.json +16 -0
- package/skills/webpack_build.aicomponent/ref/webpack.config.js +53 -0
- package/skills/win_anim_sfx.aiaudio/SKILL.md +59 -0
- package/skills/win_anim_sfx.aiaudio/manifest.json +46 -0
- package/skills/win_anim_sfx.aiaudio/ref/win_anim.mp3 +0 -0
- package/skills/win_dot.aiimage/SKILL.md +58 -0
- package/skills/win_dot.aiimage/manifest.json +47 -0
- package/skills/win_dot.aiimage/ref/win_dot.png +0 -0
- package/skills/win_dot.aiimage/ref/win_dot.webp +0 -0
- package/skills/win_result_panel.aiimage/SKILL.md +58 -0
- package/skills/win_result_panel.aiimage/manifest.json +47 -0
- package/skills/win_result_panel.aiimage/ref/win.png +0 -0
- package/skills/win_result_panel.aiimage/ref/win.webp +0 -0
- package/skills/word_connect.aigameplay/SKILL.md +86 -0
- package/skills/word_connect.aigameplay/manifest.json +154 -0
- package/skills/word_connect.aigameplay/ref/pgs-schema.json +212 -0
- package/skills/word_connect.aigameplay/ref/reducer.template.ts +186 -0
- package/src/index.ts +10 -0
- package/src/skills.loader.ts +225 -0
- package/src/skills.types.ts +42 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import { GLTFLoader, type GLTF } from "three/addons/loaders/GLTFLoader.js";
|
|
3
|
+
|
|
4
|
+
export type TextureEntry = { key: string; url: string };
|
|
5
|
+
export type ModelEntry = { key: string; url: string };
|
|
6
|
+
export type AudioEntry = { key: string; url: string };
|
|
7
|
+
export type CubeTextureEntry = { key: string; urls: [string, string, string, string, string, string] };
|
|
8
|
+
|
|
9
|
+
export type AssetManifest = {
|
|
10
|
+
textures?: TextureEntry[];
|
|
11
|
+
models?: ModelEntry[];
|
|
12
|
+
audio?: AudioEntry[];
|
|
13
|
+
cubeTextures?: CubeTextureEntry[];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type LoadedAssets = {
|
|
17
|
+
textures: Map<string, THREE.Texture>;
|
|
18
|
+
models: Map<string, GLTF>;
|
|
19
|
+
audio: Map<string, AudioBuffer>;
|
|
20
|
+
cubeTextures: Map<string, THREE.CubeTexture>;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type ProgressCallback = (progress: number) => void;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 统一资源加载器。
|
|
27
|
+
*
|
|
28
|
+
* 支持 Texture / GLTF 模型 / 音频 / CubeTexture 批量加载,
|
|
29
|
+
* 提供 0~1 的进度回调。加载结果按 key 存入 Map,方便后续使用。
|
|
30
|
+
*
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const loader = new AssetLoader();
|
|
33
|
+
* await loader.loadAll({
|
|
34
|
+
* textures: [{ key: "logo", url: logoUrl }],
|
|
35
|
+
* models: [{ key: "char", url: charUrl }],
|
|
36
|
+
* }, (p) => console.log(`${(p*100).toFixed(0)}%`));
|
|
37
|
+
*
|
|
38
|
+
* const tex = loader.getTexture("logo");
|
|
39
|
+
* const gltf = loader.getModel("char");
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export class AssetLoader {
|
|
43
|
+
private assets: LoadedAssets = {
|
|
44
|
+
textures: new Map(),
|
|
45
|
+
models: new Map(),
|
|
46
|
+
audio: new Map(),
|
|
47
|
+
cubeTextures: new Map(),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
private textureLoader = new THREE.TextureLoader();
|
|
51
|
+
private gltfLoader = new GLTFLoader();
|
|
52
|
+
private cubeTextureLoader = new THREE.CubeTextureLoader();
|
|
53
|
+
private audioContext: AudioContext | null = null;
|
|
54
|
+
|
|
55
|
+
async loadAll(manifest: AssetManifest, onProgress?: ProgressCallback): Promise<LoadedAssets> {
|
|
56
|
+
const tasks: (() => Promise<void>)[] = [];
|
|
57
|
+
|
|
58
|
+
for (const entry of manifest.textures ?? []) {
|
|
59
|
+
tasks.push(() => this.loadTexture(entry));
|
|
60
|
+
}
|
|
61
|
+
for (const entry of manifest.models ?? []) {
|
|
62
|
+
tasks.push(() => this.loadModel(entry));
|
|
63
|
+
}
|
|
64
|
+
for (const entry of manifest.audio ?? []) {
|
|
65
|
+
tasks.push(() => this.loadAudio(entry));
|
|
66
|
+
}
|
|
67
|
+
for (const entry of manifest.cubeTextures ?? []) {
|
|
68
|
+
tasks.push(() => this.loadCubeTexture(entry));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (tasks.length === 0) {
|
|
72
|
+
onProgress?.(1);
|
|
73
|
+
return this.assets;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let done = 0;
|
|
77
|
+
const total = tasks.length;
|
|
78
|
+
|
|
79
|
+
await Promise.all(
|
|
80
|
+
tasks.map(async (task) => {
|
|
81
|
+
await task();
|
|
82
|
+
done++;
|
|
83
|
+
onProgress?.(done / total);
|
|
84
|
+
}),
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
return this.assets;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
getTexture(key: string): THREE.Texture | undefined {
|
|
91
|
+
return this.assets.textures.get(key);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
getModel(key: string): GLTF | undefined {
|
|
95
|
+
return this.assets.models.get(key);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
getAudioBuffer(key: string): AudioBuffer | undefined {
|
|
99
|
+
return this.assets.audio.get(key);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
getCubeTexture(key: string): THREE.CubeTexture | undefined {
|
|
103
|
+
return this.assets.cubeTextures.get(key);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private loadTexture(entry: TextureEntry): Promise<void> {
|
|
107
|
+
return new Promise((resolve, reject) => {
|
|
108
|
+
this.textureLoader.load(
|
|
109
|
+
entry.url,
|
|
110
|
+
(tex) => {
|
|
111
|
+
tex.colorSpace = THREE.SRGBColorSpace;
|
|
112
|
+
this.assets.textures.set(entry.key, tex);
|
|
113
|
+
resolve();
|
|
114
|
+
},
|
|
115
|
+
undefined,
|
|
116
|
+
reject,
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private loadModel(entry: ModelEntry): Promise<void> {
|
|
122
|
+
return new Promise((resolve, reject) => {
|
|
123
|
+
this.gltfLoader.load(
|
|
124
|
+
entry.url,
|
|
125
|
+
(gltf) => {
|
|
126
|
+
this.assets.models.set(entry.key, gltf);
|
|
127
|
+
resolve();
|
|
128
|
+
},
|
|
129
|
+
undefined,
|
|
130
|
+
reject,
|
|
131
|
+
);
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private async loadAudio(entry: AudioEntry): Promise<void> {
|
|
136
|
+
if (!this.audioContext) {
|
|
137
|
+
this.audioContext = new AudioContext();
|
|
138
|
+
}
|
|
139
|
+
const response = await fetch(entry.url);
|
|
140
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
141
|
+
const audioBuffer = await this.audioContext.decodeAudioData(arrayBuffer);
|
|
142
|
+
this.assets.audio.set(entry.key, audioBuffer);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private loadCubeTexture(entry: CubeTextureEntry): Promise<void> {
|
|
146
|
+
return new Promise((resolve, reject) => {
|
|
147
|
+
this.cubeTextureLoader.load(
|
|
148
|
+
entry.urls,
|
|
149
|
+
(tex) => {
|
|
150
|
+
this.assets.cubeTextures.set(entry.key, tex);
|
|
151
|
+
resolve();
|
|
152
|
+
},
|
|
153
|
+
undefined,
|
|
154
|
+
reject,
|
|
155
|
+
);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import type { SceneKey } from "../SceneKeys";
|
|
3
|
+
|
|
4
|
+
export type SceneTransitionFn = (targetKey: SceneKey) => void;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 所有场景的基类,提供统一的生命周期接口。
|
|
8
|
+
*
|
|
9
|
+
* 生命周期:
|
|
10
|
+
* init() → 首次进入时调用,初始化 Three.js 对象
|
|
11
|
+
* enter() → 每次切到此场景时调用(含首次)
|
|
12
|
+
* update(dt, elapsed) → 每帧调用
|
|
13
|
+
* exit() → 离开此场景时调用
|
|
14
|
+
* dispose() → 销毁场景资源
|
|
15
|
+
*/
|
|
16
|
+
export abstract class BaseScene {
|
|
17
|
+
readonly key: SceneKey;
|
|
18
|
+
readonly scene: THREE.Scene;
|
|
19
|
+
|
|
20
|
+
protected _camera: THREE.PerspectiveCamera | null = null;
|
|
21
|
+
protected _initialized = false;
|
|
22
|
+
protected _goToScene: SceneTransitionFn = () => {};
|
|
23
|
+
|
|
24
|
+
constructor(key: SceneKey) {
|
|
25
|
+
this.key = key;
|
|
26
|
+
this.scene = new THREE.Scene();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get camera(): THREE.PerspectiveCamera | null {
|
|
30
|
+
return this._camera;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** SceneManager 注入,子类不要覆盖 */
|
|
34
|
+
_bind(goToScene: SceneTransitionFn): void {
|
|
35
|
+
this._goToScene = goToScene;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** 首次进入时由 SceneManager 调用 */
|
|
39
|
+
init(camera: THREE.PerspectiveCamera): void {
|
|
40
|
+
this._camera = camera;
|
|
41
|
+
this._initialized = true;
|
|
42
|
+
this.onInit();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** 每次切入场景时调用 */
|
|
46
|
+
enter(): void {
|
|
47
|
+
this.onEnter();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** 每帧由 SceneManager 调用,dt 单位秒 */
|
|
51
|
+
update(dt: number, elapsed: number): void {
|
|
52
|
+
this.onUpdate(dt, elapsed);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** 离开场景时调用 */
|
|
56
|
+
exit(): void {
|
|
57
|
+
this.onExit();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** 销毁场景,释放 GPU 资源 */
|
|
61
|
+
dispose(): void {
|
|
62
|
+
this.onDispose();
|
|
63
|
+
this.scene.traverse((obj) => {
|
|
64
|
+
if (obj instanceof THREE.Mesh) {
|
|
65
|
+
obj.geometry?.dispose();
|
|
66
|
+
const materials = Array.isArray(obj.material) ? obj.material : [obj.material];
|
|
67
|
+
for (const mat of materials) {
|
|
68
|
+
if (mat && typeof mat.dispose === "function") {
|
|
69
|
+
mat.dispose();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
this.scene.clear();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
protected goToScene(key: SceneKey): void {
|
|
78
|
+
this._goToScene(key);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ─── 子类覆盖 ───
|
|
82
|
+
|
|
83
|
+
protected onInit(): void {}
|
|
84
|
+
protected onEnter(): void {}
|
|
85
|
+
protected onUpdate(_dt: number, _elapsed: number): void {}
|
|
86
|
+
protected onExit(): void {}
|
|
87
|
+
protected onDispose(): void {}
|
|
88
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 游戏全局配置(通用基础版)。
|
|
3
|
+
*
|
|
4
|
+
* 具体游戏的业务常量(关卡参数、物理系数等)应在各自模块中声明,
|
|
5
|
+
* 不要污染此文件。
|
|
6
|
+
*/
|
|
7
|
+
export const GameConfig = {
|
|
8
|
+
// ─── 渲染 ───
|
|
9
|
+
antialias: true,
|
|
10
|
+
shadows: true,
|
|
11
|
+
toneMapping: "ACESFilmic" as "ACESFilmic" | "Linear" | "Reinhard" | "Cineon",
|
|
12
|
+
toneMappingExposure: 1.0,
|
|
13
|
+
maxPixelRatio: 2,
|
|
14
|
+
|
|
15
|
+
// ─── 相机 ───
|
|
16
|
+
camera: {
|
|
17
|
+
fov: 60,
|
|
18
|
+
near: 0.1,
|
|
19
|
+
far: 1000,
|
|
20
|
+
position: { x: 0, y: 3, z: 5 } as { x: number; y: number; z: number },
|
|
21
|
+
lookAt: { x: 0, y: 0, z: 0 } as { x: number; y: number; z: number },
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
// ─── 灯光 ───
|
|
25
|
+
lighting: {
|
|
26
|
+
ambientColor: 0x404040,
|
|
27
|
+
ambientIntensity: 1.0,
|
|
28
|
+
directionalColor: 0xffffff,
|
|
29
|
+
directionalIntensity: 1.5,
|
|
30
|
+
directionalPosition: { x: 5, y: 8, z: 5 } as { x: number; y: number; z: number },
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
// ─── 场景 ───
|
|
34
|
+
clearColor: 0x1a1a2e,
|
|
35
|
+
debugScene: "main" as "preloader" | "main",
|
|
36
|
+
|
|
37
|
+
// ─── 调试 ───
|
|
38
|
+
showFps: false,
|
|
39
|
+
showGrid: true,
|
|
40
|
+
enableOrbitControls: true,
|
|
41
|
+
|
|
42
|
+
// ─── 音频 ───
|
|
43
|
+
settings: {
|
|
44
|
+
musicOn: true,
|
|
45
|
+
soundOn: true,
|
|
46
|
+
},
|
|
47
|
+
};
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
|
3
|
+
import { BaseScene } from "./BaseScene";
|
|
4
|
+
import { SceneKeys } from "../SceneKeys";
|
|
5
|
+
import { GameConfig } from "../GameConfig";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 主游戏场景(空白骨架)。
|
|
9
|
+
*
|
|
10
|
+
* 执行脚手架后,此场景显示旋转的 Torus Knot + 网格 + 坐标轴,
|
|
11
|
+
* 作为开发起点。替换 onInit() / onUpdate() 中的内容即可开始编写游戏逻辑。
|
|
12
|
+
*/
|
|
13
|
+
export class MainScene extends BaseScene {
|
|
14
|
+
private controls: OrbitControls | null = null;
|
|
15
|
+
private torusKnot: THREE.Mesh | null = null;
|
|
16
|
+
private fpsDiv: HTMLDivElement | null = null;
|
|
17
|
+
private frameCount = 0;
|
|
18
|
+
private fpsTime = 0;
|
|
19
|
+
|
|
20
|
+
constructor() {
|
|
21
|
+
super(SceneKeys.Main);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
protected onEnter(): void {
|
|
25
|
+
const overlay = document.getElementById("loading-overlay");
|
|
26
|
+
if (overlay) overlay.classList.add("hidden");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
protected onInit(): void {
|
|
30
|
+
if (!this._camera) return;
|
|
31
|
+
|
|
32
|
+
// ─── 背景 ───
|
|
33
|
+
this.scene.background = new THREE.Color(GameConfig.clearColor);
|
|
34
|
+
this.scene.fog = new THREE.Fog(GameConfig.clearColor, 20, 80);
|
|
35
|
+
|
|
36
|
+
// ─── 灯光 ───
|
|
37
|
+
const { lighting } = GameConfig;
|
|
38
|
+
|
|
39
|
+
const ambient = new THREE.AmbientLight(lighting.ambientColor, lighting.ambientIntensity);
|
|
40
|
+
this.scene.add(ambient);
|
|
41
|
+
|
|
42
|
+
const dirLight = new THREE.DirectionalLight(lighting.directionalColor, lighting.directionalIntensity);
|
|
43
|
+
dirLight.position.set(
|
|
44
|
+
lighting.directionalPosition.x,
|
|
45
|
+
lighting.directionalPosition.y,
|
|
46
|
+
lighting.directionalPosition.z,
|
|
47
|
+
);
|
|
48
|
+
dirLight.castShadow = GameConfig.shadows;
|
|
49
|
+
if (dirLight.shadow) {
|
|
50
|
+
dirLight.shadow.mapSize.setScalar(1024);
|
|
51
|
+
dirLight.shadow.camera.near = 0.5;
|
|
52
|
+
dirLight.shadow.camera.far = 50;
|
|
53
|
+
const s = 10;
|
|
54
|
+
dirLight.shadow.camera.left = -s;
|
|
55
|
+
dirLight.shadow.camera.right = s;
|
|
56
|
+
dirLight.shadow.camera.top = s;
|
|
57
|
+
dirLight.shadow.camera.bottom = -s;
|
|
58
|
+
}
|
|
59
|
+
this.scene.add(dirLight);
|
|
60
|
+
|
|
61
|
+
// ─── 地面 ───
|
|
62
|
+
const groundGeo = new THREE.PlaneGeometry(30, 30);
|
|
63
|
+
const groundMat = new THREE.MeshStandardMaterial({
|
|
64
|
+
color: 0x222244,
|
|
65
|
+
roughness: 0.9,
|
|
66
|
+
metalness: 0.1,
|
|
67
|
+
});
|
|
68
|
+
const ground = new THREE.Mesh(groundGeo, groundMat);
|
|
69
|
+
ground.rotation.x = -Math.PI / 2;
|
|
70
|
+
ground.receiveShadow = true;
|
|
71
|
+
this.scene.add(ground);
|
|
72
|
+
|
|
73
|
+
// ─── 参考网格 + 坐标轴 ───
|
|
74
|
+
if (GameConfig.showGrid) {
|
|
75
|
+
const grid = new THREE.GridHelper(20, 20, 0x444466, 0x333355);
|
|
76
|
+
grid.position.y = 0.01;
|
|
77
|
+
this.scene.add(grid);
|
|
78
|
+
|
|
79
|
+
const axes = new THREE.AxesHelper(3);
|
|
80
|
+
axes.position.y = 0.02;
|
|
81
|
+
this.scene.add(axes);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ─── Hello Three.js — 旋转 Torus Knot ───
|
|
85
|
+
const geometry = new THREE.TorusKnotGeometry(0.8, 0.3, 128, 32);
|
|
86
|
+
const material = new THREE.MeshStandardMaterial({
|
|
87
|
+
color: 0x4488ff,
|
|
88
|
+
roughness: 0.3,
|
|
89
|
+
metalness: 0.6,
|
|
90
|
+
});
|
|
91
|
+
this.torusKnot = new THREE.Mesh(geometry, material);
|
|
92
|
+
this.torusKnot.position.y = 1.5;
|
|
93
|
+
this.torusKnot.castShadow = true;
|
|
94
|
+
this.scene.add(this.torusKnot);
|
|
95
|
+
|
|
96
|
+
// ─── "Hello Three.js!" 文字精灵 ───
|
|
97
|
+
const canvas = document.createElement("canvas");
|
|
98
|
+
canvas.width = 512;
|
|
99
|
+
canvas.height = 128;
|
|
100
|
+
const ctx = canvas.getContext("2d")!;
|
|
101
|
+
ctx.fillStyle = "transparent";
|
|
102
|
+
ctx.fillRect(0, 0, 512, 128);
|
|
103
|
+
ctx.font = "bold 48px Arial, sans-serif";
|
|
104
|
+
ctx.fillStyle = "#ffffff";
|
|
105
|
+
ctx.textAlign = "center";
|
|
106
|
+
ctx.textBaseline = "middle";
|
|
107
|
+
ctx.fillText("Hello Three.js!", 256, 64);
|
|
108
|
+
|
|
109
|
+
const spriteTex = new THREE.CanvasTexture(canvas);
|
|
110
|
+
const spriteMat = new THREE.SpriteMaterial({ map: spriteTex, transparent: true });
|
|
111
|
+
const sprite = new THREE.Sprite(spriteMat);
|
|
112
|
+
sprite.position.set(0, 3.2, 0);
|
|
113
|
+
sprite.scale.set(4, 1, 1);
|
|
114
|
+
this.scene.add(sprite);
|
|
115
|
+
|
|
116
|
+
// ─── OrbitControls ───
|
|
117
|
+
if (GameConfig.enableOrbitControls) {
|
|
118
|
+
const rendererDom = document.querySelector("#game-container canvas");
|
|
119
|
+
if (rendererDom) {
|
|
120
|
+
this.controls = new OrbitControls(this._camera, rendererDom as HTMLElement);
|
|
121
|
+
this.controls.enableDamping = true;
|
|
122
|
+
this.controls.dampingFactor = 0.08;
|
|
123
|
+
this.controls.target.set(0, 1, 0);
|
|
124
|
+
this.controls.update();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ─── FPS 显示 ───
|
|
129
|
+
if (GameConfig.showFps) {
|
|
130
|
+
this.fpsDiv = document.createElement("div");
|
|
131
|
+
Object.assign(this.fpsDiv.style, {
|
|
132
|
+
position: "fixed",
|
|
133
|
+
top: "8px",
|
|
134
|
+
left: "8px",
|
|
135
|
+
padding: "2px 6px",
|
|
136
|
+
background: "rgba(0,0,0,0.5)",
|
|
137
|
+
color: "#0c0",
|
|
138
|
+
fontSize: "12px",
|
|
139
|
+
fontFamily: "monospace",
|
|
140
|
+
zIndex: "9999",
|
|
141
|
+
pointerEvents: "none",
|
|
142
|
+
});
|
|
143
|
+
document.body.appendChild(this.fpsDiv);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
protected onUpdate(dt: number, elapsed: number): void {
|
|
148
|
+
if (this.torusKnot) {
|
|
149
|
+
this.torusKnot.rotation.y = elapsed * 0.5;
|
|
150
|
+
this.torusKnot.rotation.x = elapsed * 0.3;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
this.controls?.update();
|
|
154
|
+
|
|
155
|
+
if (this.fpsDiv) {
|
|
156
|
+
this.frameCount++;
|
|
157
|
+
this.fpsTime += dt;
|
|
158
|
+
if (this.fpsTime >= 0.5) {
|
|
159
|
+
this.fpsDiv.textContent = `FPS: ${Math.round(this.frameCount / this.fpsTime)}`;
|
|
160
|
+
this.frameCount = 0;
|
|
161
|
+
this.fpsTime = 0;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
protected onDispose(): void {
|
|
167
|
+
this.controls?.dispose();
|
|
168
|
+
this.fpsDiv?.remove();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { BaseScene } from "./BaseScene";
|
|
2
|
+
import { SceneKeys } from "../SceneKeys";
|
|
3
|
+
import { AssetLoader, type AssetManifest } from "../utils/AssetLoader";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 预加载场景。
|
|
7
|
+
*
|
|
8
|
+
* 使用 HTML overlay 显示加载进度(CSS 动画,无需 Three.js 渲染)。
|
|
9
|
+
* 加载完成后自动切换到 Main 场景。
|
|
10
|
+
*
|
|
11
|
+
* 要加载资源,在 getManifest() 中返回资源清单即可。
|
|
12
|
+
*/
|
|
13
|
+
export class PreloaderScene extends BaseScene {
|
|
14
|
+
private loader = new AssetLoader();
|
|
15
|
+
|
|
16
|
+
constructor() {
|
|
17
|
+
super(SceneKeys.Preloader);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
protected onEnter(): void {
|
|
21
|
+
this.showOverlay();
|
|
22
|
+
this.startLoading();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 定义资源清单。按需添加资源条目。
|
|
27
|
+
*
|
|
28
|
+
* 示例:
|
|
29
|
+
* ```typescript
|
|
30
|
+
* import logoTexture from "assets/images/logo.webp";
|
|
31
|
+
* import modelFile from "assets/models/character.glb";
|
|
32
|
+
*
|
|
33
|
+
* return {
|
|
34
|
+
* textures: [{ key: "logo", url: logoTexture }],
|
|
35
|
+
* models: [{ key: "character", url: modelFile }],
|
|
36
|
+
* };
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
protected getManifest(): AssetManifest {
|
|
40
|
+
return {};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private async startLoading(): Promise<void> {
|
|
44
|
+
const manifest = this.getManifest();
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
await this.loader.loadAll(manifest, (progress) => {
|
|
48
|
+
this.updateProgress(progress);
|
|
49
|
+
});
|
|
50
|
+
} catch (err) {
|
|
51
|
+
console.error("[PreloaderScene] Loading failed:", err);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
this.updateProgress(1);
|
|
55
|
+
this.setLoadingText("Ready");
|
|
56
|
+
|
|
57
|
+
await this.delay(300);
|
|
58
|
+
this.hideOverlay();
|
|
59
|
+
this.goToScene(SceneKeys.Main);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private showOverlay(): void {
|
|
63
|
+
const overlay = document.getElementById("loading-overlay");
|
|
64
|
+
if (overlay) {
|
|
65
|
+
overlay.classList.remove("hidden");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private hideOverlay(): void {
|
|
70
|
+
const overlay = document.getElementById("loading-overlay");
|
|
71
|
+
if (overlay) {
|
|
72
|
+
overlay.classList.add("hidden");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private updateProgress(value: number): void {
|
|
77
|
+
const bar = document.getElementById("loading-bar");
|
|
78
|
+
if (bar) {
|
|
79
|
+
bar.style.width = `${Math.round(value * 100)}%`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private setLoadingText(text: string): void {
|
|
84
|
+
const el = document.getElementById("loading-text");
|
|
85
|
+
if (el) {
|
|
86
|
+
el.textContent = text;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private delay(ms: number): Promise<void> {
|
|
91
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import { BaseScene } from "./scenes/BaseScene";
|
|
3
|
+
import type { SceneKey } from "./SceneKeys";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 场景生命周期管理器。
|
|
7
|
+
*
|
|
8
|
+
* 管理多个 BaseScene 实例的注册、切换和更新。
|
|
9
|
+
* 同一时刻只有一个活跃场景,切换时自动调用 exit/enter。
|
|
10
|
+
*/
|
|
11
|
+
export class SceneManager {
|
|
12
|
+
private scenes = new Map<SceneKey, BaseScene>();
|
|
13
|
+
private _activeScene: BaseScene | null = null;
|
|
14
|
+
private _camera: THREE.PerspectiveCamera;
|
|
15
|
+
|
|
16
|
+
constructor(camera: THREE.PerspectiveCamera) {
|
|
17
|
+
this._camera = camera;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get activeScene(): BaseScene | null {
|
|
21
|
+
return this._activeScene;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get activeThreeScene(): THREE.Scene | null {
|
|
25
|
+
return this._activeScene?.scene ?? null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
register(...scenes: BaseScene[]): void {
|
|
29
|
+
for (const s of scenes) {
|
|
30
|
+
s._bind((key) => this.switchTo(key));
|
|
31
|
+
this.scenes.set(s.key, s);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
switchTo(key: SceneKey): void {
|
|
36
|
+
const next = this.scenes.get(key);
|
|
37
|
+
if (!next) {
|
|
38
|
+
console.warn(`[SceneManager] Scene "${key}" not registered`);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (this._activeScene) {
|
|
43
|
+
this._activeScene.exit();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (!next["_initialized"]) {
|
|
47
|
+
next.init(this._camera);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
next.enter();
|
|
51
|
+
this._activeScene = next;
|
|
52
|
+
|
|
53
|
+
if (typeof __DEV__ !== "undefined" && __DEV__) {
|
|
54
|
+
console.log(`[SceneManager] → ${key}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
update(dt: number, elapsed: number): void {
|
|
59
|
+
this._activeScene?.update(dt, elapsed);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
dispose(): void {
|
|
63
|
+
for (const s of this.scenes.values()) {
|
|
64
|
+
s.dispose();
|
|
65
|
+
}
|
|
66
|
+
this.scenes.clear();
|
|
67
|
+
this._activeScene = null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 响应式视口管理器。
|
|
5
|
+
*
|
|
6
|
+
* 监听 container resize(通过 ResizeObserver),自动更新:
|
|
7
|
+
* - renderer 尺寸与像素比
|
|
8
|
+
* - camera 宽高比
|
|
9
|
+
*
|
|
10
|
+
* 比 Phaser 的 reload 方案更高效,无需刷新页面。
|
|
11
|
+
*/
|
|
12
|
+
export class ViewportManager {
|
|
13
|
+
private renderer: THREE.WebGLRenderer;
|
|
14
|
+
private camera: THREE.PerspectiveCamera;
|
|
15
|
+
private container: HTMLElement;
|
|
16
|
+
private observer: ResizeObserver | null = null;
|
|
17
|
+
private maxPixelRatio: number;
|
|
18
|
+
|
|
19
|
+
constructor(
|
|
20
|
+
renderer: THREE.WebGLRenderer,
|
|
21
|
+
camera: THREE.PerspectiveCamera,
|
|
22
|
+
container: HTMLElement,
|
|
23
|
+
maxPixelRatio = 2,
|
|
24
|
+
) {
|
|
25
|
+
this.renderer = renderer;
|
|
26
|
+
this.camera = camera;
|
|
27
|
+
this.container = container;
|
|
28
|
+
this.maxPixelRatio = maxPixelRatio;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
enable(): void {
|
|
32
|
+
this.observer = new ResizeObserver(() => this.handleResize());
|
|
33
|
+
this.observer.observe(this.container);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
disable(): void {
|
|
37
|
+
this.observer?.disconnect();
|
|
38
|
+
this.observer = null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** 手动触发一次 resize 计算 */
|
|
42
|
+
refresh(): void {
|
|
43
|
+
this.handleResize();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
getSize(): { width: number; height: number; aspect: number } {
|
|
47
|
+
const width = this.container.clientWidth;
|
|
48
|
+
const height = this.container.clientHeight;
|
|
49
|
+
return { width, height, aspect: width / height };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private handleResize(): void {
|
|
53
|
+
const { width, height, aspect } = this.getSize();
|
|
54
|
+
if (width === 0 || height === 0) return;
|
|
55
|
+
|
|
56
|
+
this.camera.aspect = aspect;
|
|
57
|
+
this.camera.updateProjectionMatrix();
|
|
58
|
+
|
|
59
|
+
this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, this.maxPixelRatio));
|
|
60
|
+
this.renderer.setSize(width, height);
|
|
61
|
+
}
|
|
62
|
+
}
|