嵌入式物联网智能硬件机器人硬件开发前端AI 应用【免费下载链接】stack-chanA JavaScript-driven M5Stack-embedded super-kawaii robot.项目地址https://gitcode.com/gh_mirrors/sta/stack-chan点击查看免费下载本示例位于 firmware/mods/examples/stackchan_minigames演示了 Stack-chan 固件上最典型的 mini-app 打包方式把两个各自独立的游戏正本mini_app_sample与stackchan_catch通过compose.mjs合成进一个 import 白名单兼容的miniapp.ts最终以一个 archive 向迷你应用启动器注册两款游戏。读完本文你将掌握 mini-app 外部归档的格式约束、合成脚本的底层原理、manifest.json的资源打包规则以及从合成、格式化、构建到测试的完整命令链路。一、示例定位一个 archive、两个游戏、一个 Gallery 包Stack-chan 的迷你游戏集是一个“打包”型示例1 个 mini-app archive向迷你应用列表注册 2 个游戏 JUMPsample.stackchan-jump点击屏幕让 Stack-chan 跳跃躲避不断逼近的障碍物的横版动作游戏 CATCHsample.stackchan-catch左右 3 条车道中移动接住普通道具、避开炸弹的 Game Watch 风格接物游戏。该示例的特殊之处在于它并不维护两份游戏代码。文档明确指出执行的“正本”是已有的两个独立示例 ——mini_app_sampleJUMP 游戏与stackchan_catchCATCH 游戏各游戏的规则与绘制方式以它们各自的 README 为准。stackchan_minigames目录只负责通过compose.mjs把两份源码合成为符合外部 mini-app import 限制的单一miniapp.ts。在分发层面这一组合还作为一个整体发布到 MOD Galleryweb/mod-gallery/samples/stackchan-minigames/stackchan-mod.json定义了sample.stackchan-minigames包version1.0.0名称「 ミニゲーム集」entrypoints为[miniapp]targets覆盖m5stackchan-cores3与simulator随包附带一个已构建的stackchan-minigames.xsa归档。二、先理解运行环境mini-app 的画面所有权与 import 白名单要理解为什么需要compose.mjs做“合成”需要先了解 Stack-chan 的 mini-app 运行模型详见 firmware/docs/mini-apps_ja.md画面所有权迷你应用会临时替换普通的脸部画面但AppBar 始终由宿主拥有mini-app 只能获得去掉高度 44 px 之后的320 x 196区域mini-app 根容器进入clip: true的 viewport普通绘制不会溢出到 AppBar。界面层次Application → 迷你应用 viewporttop: 44, clip: true→ 迷你应用返回的 Piu Container其上还有宿主拥有的 AppBar、Overlay、Drawer。迷你应用不会嵌套自己的Application。外部归档格式外部迷你应用必须从 archive 的miniapp模块default export 一个定义数组类型为MiniAppDefinition包含id、title、create()。外部 archive只能 importminiapp、piu/MC、piu/Timeline且piu/MC只开放除Application之外的绘制 API。包含边界containment宿主用 Moddable 的Compartment限制外部 mini-app 的 global 与 import只额外传入读取该 archive 内部资源的archive对象Modules、网络、设备 I/O、宿主的Application均不交给外部代码。但文档明确警告这不是针对不可信代码的完整沙箱——因为 Compartment 内创建的原生 Piu 对象会挂进宿主的显示树Piu 的 constructor/prototype 与宿主共享当前 API 无法证明不会经父子引用、事件分发或 prototype 修改波及宿主。因此目前只应安装受信任的迷你应用。正是在这个“import 受限、信任边界明确”的框架下compose.mjs的职责变得清晰把两份源码中不符合约束的import语句剥离并把它们包装为闭包合并到一个模块里使最终产物只依赖被允许的miniapp/piu/MC。三、两款游戏的玩法与手感参数3.1 JUMP单一 Port 上的跑酷JUMP 用 Piu 的单个Port绘制整个游戏区域玩家32×32 的stack-chan.png精灵固定横坐标PLAYER_X 48只做垂直运动。核心手感参数集中在合成产物 firmware/mods/examples/stackchan_minigames/miniapp.ts 顶部参数值含义FRAME_INTERVAL_MS40帧间隔即port.interval约 25 FPSSPRITE_SIZE32玩家精灵尺寸GROUND_BOTTOM18地面距 Port 底部的高度决定#groundYINITIAL_SPEED/MAX_SPEED4/8障碍物左移初速与上限JUMP_VELOCITY/GRAVITY-11/1跳跃初速向上为负与重力加速度障碍物有 5 种组合通过OBSTACLE_HEIGHTS28/36/44/32/40、OBSTACLE_WIDTHS14/18/16/20/14、OBSTACLE_GAPS88/120/104/144/112循环生成#spawnIndex每生成一个障碍物自增并取模保证形态循环。游戏规则与实现细节点击onTouchBegan触发跳跃#onGround为 false 时二次点击无效空中仍保持跳跃状态碰撞导致#gameOver后再点一次即#reset重开。每越过一个障碍物得分 1并刷新速度speed Math.min(MAX_SPEED, INITIAL_SPEED (score 2))即每 4 分提速 1最高 8。碰撞检测#collides()在玩家包围盒横向缩进 6/-5、纵向 4/-2与障碍物包围盒之间做 AABB 相交判定障碍物顶边为groundY - obstacleHeight。性能取向onTimeChanged中只对旧/新位置的玩家与障碍物包围盒做局部port.invalidate()而不是全屏重绘。这是有意为之——文档mini_app_sample README_ja说明这是为了“不堆叠大量 Piu 对象降低嵌入式目标的显示树与重绘负担”。计分用 5×3 点阵字模绘制DIGIT_MASKS存 0–9 的 15 位掩码并以score % 1000显示三位数。3.2 CATCH离散状态的三车道接物CATCH 是一个“离散状态”游戏落物不连续移动而是沿 5 个固定台阶DROP_Y [31, 50, 69, 88, 107]按 tick 跳变形成 Game Watch 式残像。核心状态与规则车道与玩家3 条车道中心LANE_CENTERS [52, 160, 268]玩家 48×48movePlayer()把位置钳制在 0–2触摸左 1/3 左移、右 1/3 右移、中间 1/3 在标题/结束画面用于开始或重试。道具四类screw螺丝、m5stack、bubble气泡为得分道具bomb为炸弹。接住普通道具 1 分漏接落到本车道没接住或接到炸弹 1 missmiss 累计 3 次进入gameover。避开炸弹不加分。三档速度STEP_DELAYS定义了每档在每个台阶的停留 tick ——fast: [1,1,1,1,1]、steady: [1,1,2,1,1]、slow: [2,2,2,2,1]由于各档总时长不同后发的 fast 落物可能先于先发的 slow 落物着地。落地间隔约束MIN_LANDING_GAP_TICKS 3canSpawnDrop()会检查新落物落地 tick 与lastLandingTick以及场上每个活动落物的落地 tick 之差确保任意两次落地之间至少间隔 3 tick避免出现“无解”局面。连续补位流不按“波次”排队而是场上活动落物 2 个时立即用DROP_SEQUENCE12 项循环序列补充保证屏幕上常驻 1–2 个落物。难度递增increaseDifficulty()每得 5 分把tickInterval从初始600 ms下调50 ms下限250 msINITIAL_TICK_INTERVAL_MS600、MIN_TICK_INTERVAL_MS250、SPEED_UP_EVERY_SCORE5、SPEED_UP_STEP_MS50。显示风格LCD 米色背景#d8deb7配合浅色幽灵标记#b7be99车道分隔线、落物轨迹点、非活动态的控制区与深色活动元素#343a31刻意用“固定姿势瞬间切换”替代连续动画重现 Game Watch 的残像观感。底部LEFT / START / RIGHT控件以浓淡区分当前可用的触摸区。四、compose.mjs合成脚本的工作原理合成脚本 compose.mjs 全流程如下node mods/examples/stackchan_minigames/compose.mjs1. 声明两个正本来源sources数组通过import.meta.url相对定位到../mini_app_sample/miniapp.ts与../stackchan_catch/miniapp.ts分别命名为jump与catch。2. 计算来源哈希把两个源文件内容以\0拼接后做 SHA-256得到sourceHash写入生成文件头注释用于追溯合成产物的来源版本。3. 模块体改写moduleBody逐行过滤掉以import开头的行——这是满足外部 mini-app import 白名单的关键一步把export type|interface|function|class开头的行替换为去掉export的声明把export default替换为return因为整个模块体将被包进 IIFE。4. 闭包包装indent 模板拼接每个模块体统一缩进两格后包成const jumpDefinitions (() { ... })() const catchDefinitions (() { ... })()5. 合并导出最后生成const definitions: readonly MiniAppDefinition[] Object.freeze([...jumpDefinitions, ...catchDefinitions]) export default definitions即两个来源各自导出的定义数组被展开合并为一个数组——这正是外部归档要求的miniapp模块 default export 形式。6.--check模式若以node compose.mjs --check运行脚本不会写文件而是比对现有miniapp.ts与预期输出不一致即抛错miniapp.ts is stale; run compose.mjs。这一模式被测试链路用来防止合成产物过期详见第六节。五、manifest.json 与资源打包规则合成后的 manifest.json 结构如下{ include: [ $(MODDABLE)/examples/manifest_mod.json, $(MODDABLE)/examples/manifest_typings.json, ../../../host/app/manifest_typings.json ], modules: { miniapp: ./miniapp }, resources: { *: [./assets/stack-chan], *-mask: [ ./assets/player-left, ./assets/player-center, ./assets/player-right, ./assets/screw, ./assets/m5stack, ./assets/bubble, ./assets/bomb, ./assets/miss ] } }要点include沿用了mini_app_sample的 manifest 模式manifest_mod.jsonmanifest_typings.json 宿主app/manifest_typings.json提供 TypeScript 能力类型如MiniAppDefinition与 Moddable 模块说明符modules.miniapp指向合成产物./miniapp这是整个 archive 的唯一代码入口resources使用了两类键*只收录 JUMP 的stack-chan.png该资源不带 mask 处理而*-mask收录 CATCH 的 8 张单色 alpha 掩码图player-left/center/right、screw、m5stack、bubble、bomb、miss与 CATCH 绘制代码中drawTexture(texture, COLOR_INK, ...)的染色用法一致。六、完整构建链路合成 → 格式化 → 构建原文档给出的命令须在firmware/目录下依次执行node mods/examples/stackchan_minigames/compose.mjs npm exec biome format --write mods/examples/stackchan_minigames/miniapp.ts npm run mod:build -- mods/examples/stackchan_minigames/manifest.json --moderelease第一步重新合成miniapp.ts每次修改正本源码后都必须重新执行第二步用项目统一的 biome 格式化器对生成文件做格式化firmware/下的biome.json定义了项目的格式规则第三步npm run mod:build实际转发到 scripts/firmware.mjs 的mod:build子命令按manifest.json与--moderelease产出 release 归档。此外从firmware/目录也可以直接安装/运行单个 MODnpm run mod -- mods/examples/stackchan_minigames/manifest.json七、自动化验证合成产物与 Gallery 包的一致性该示例带有一套完整的测试支撑1. 合成产物自身测试——__tests__/definitions/stackchan-minigames.test.js通过manifest.test.jsonincludemanifest_base、manifest_piu、示例 manifest 与host/modules/testing/manifest.json加载miniapp模块并断言equal(definitions.length, 2, one archive should register two mini games) equal(definitions[0].id, sample.stackchan-jump, the first game should be Stack-chan JUMP) equal(definitions[1].id, sample.stackchan-catch, the second game should be Stack-chan CATCH)即一个 archive 恰好注册两个定义且顺序为 JUMP 在前、CATCH 在后——这与合成脚本中sources数组的顺序严格对应。2. Gallery 包与固件示例的字节级一致性—— web/mod-gallery/mod-definition.test.mjs 中专门有一条测试“Stack-chan 迷你游戏集 Gallery 包与 Firmware 示例公开相同的运行源码”逐字节比对web/mod-gallery/samples/stackchan-minigames/miniapp/与firmware/mods/examples/stackchan_minigames/下的 13 个文件manifest.json、miniapp.ts、两份 README、LICENSE.mouse-follower以及全部 9 张精灵资源防止 Gallery 分发包与固件示例发生漂移。Gallery 包的 README 进一步说明stackchan-minigames.xsa面向 XS 17.8.2、以 Moddable SDK 9.5.0 按 M5StackChan CoreS3 配置构建同一归档也支持 Web 模拟器运行。八、运行时行为计时器、退出方式与仅触摸交互原文档明确了两个值得注意的运行时约定计时器生命周期每个游戏的Port通过 Behavior 的onDisplaying设置port.interval并port.start()在onUndisplaying中port.stop()——即当 Port 不再显示时游戏计时器随之停止JUMP 的StackchanJumpBehavior与 CATCH 的StackchanCatchBehavior均如此实现。这避免了 mini-app 被切走时后台继续空转。退出方式结束游戏使用宿主拥有的 AppBar 左上角“返回”按钮launcher 与执行画面中该按钮常驻。外部 mini-app API不暴露设备物理按键能力因此 JUMP 与 CATCH 都没有绑定 Core2/CoreS3 的实体按钮操作完全依赖屏幕触摸——这也与 firmware/docs/mini-apps_ja.md 中“当前外部迷你应用只接收触摸事件、不提供宿主按键能力”的说明一致。九、精灵出典与许可证原文档明确标注了资源出处JUMP 的assets/stack-chan.png基于 meganetaaan/mouse-follower 仓库中的 Stack-chan 精灵commit3258fc6dpackages/mouse-follower/assets/stack-chan.png制作——原 sprite 的绿色背景被转换为透明非背景像素未改动见 mini_app_sample 文档CATCH 的三种玩家姿势player-left/center/right.png以同一图片为设计参考配合现有道具 sprite sheet 作为风格参考生成并压缩为单色 alpha 掩码分发条件遵循随附的 LICENSE.mouse-followerMIT LicenseCopyright (c) meganetaaan。Gallery 包stackchan-mod.json中的license字段写作Apache-2.0 AND MIT对应仓库整体许可与 sprite 来源许可的组合。十、相关源码与文档导航主题路径合成脚本正本声明、import 剥离、闭包合并、--checkfirmware/mods/examples/stackchan_minigames/compose.mjs合成产物完整游戏逻辑firmware/mods/examples/stackchan_minigames/miniapp.ts归档清单与资源打包firmware/mods/examples/stackchan_minigames/manifest.jsonJUMP 正本含 README_ja、manifestfirmware/mods/examples/mini_app_sample/CATCH 正本含玩法细节 READMEfirmware/mods/examples/stackchan_catch/mini-app 框架文档画面所有权、外部归档格式、containment 边界firmware/docs/mini-apps_ja.mdMOD 与示例总览mod:build/npm run mod用法firmware/mods/README.mdGallery 分发包定义目标机、artifact、许可证web/mod-gallery/samples/stackchan-minigames/stackchan-mod.json一致性回归测试合成产物断言、Gallery 字节级比对firmware/mods/examples/stackchan_minigames/tests/definitions/stackchan-minigames.test.js、web/mod-gallery/mod-definition.test.mjs小结stackchan_minigames是 Stack-chan 生态中一个“小而完整”的工程范本它示范了在不维护重复代码的前提下如何用合成脚本把多个独立 mini-app 正本收敛为一个符合外部归档约束的模块、并以一个 archive 注册多个游戏。对希望开发或打包 Stack-chan mini-app 的开发者来说本文梳理的合成机制、资源清单规则、构建与回归测试链路均可直接迁移到自己的项目上。赞分享嵌入式物联网智能硬件机器人硬件开发前端AI 应用【免费下载链接】stack-chanA JavaScript-driven M5Stack-embedded super-kawaii robot.项目地址https://gitcode.com/gh_mirrors/sta/stack-chan点击查看免费下载相关推荐Stack-chan 迷你游戏集 stackchan_minigames用 compose.mjs 把 JUMP 与 CATCH 合成为一个 mini-app 归档Stack chan 迷你游戏集 stackchan_minigames用 compose.mjs 把 JUMP 与 CATCH 合成为一个 mini app嵌入式物联网智能硬件机器人硬件开发前端AI 应用基于 Piu Port 的离散状态迷你游戏Stack-chan CATCH 实战拆解基于 Piu Port 的离散状态迷你游戏Stack chan CATCH 实战拆解 Stack chan CATCH 是 Stack chan 固件仓库中一嵌入式物联网智能硬件机器人硬件开发前端AI 应用Stack-chan ミニアプリ入门用单个 Piu Port 实现「 JUMP」跳跃游戏Stack chan ミニアプリ入门用单个 Piu Port 实现「 JUMP」跳跃游戏 本篇指南围绕 Stack chan 固件仓库中的迷你应嵌入式物联网智能硬件机器人硬件开发前端AI 应用上一篇彻底解耦DVA状态管理3个测试陷阱与模型注入实战指南下一篇如何快速实现umi与Clerk集成身份验证与用户管理完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考