@funpixel/tools 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2414) hide show
  1. package/LICENSE +115 -0
  2. package/NOTICE +28 -0
  3. package/README.md +110 -2
  4. package/bench/LICENSE +674 -0
  5. package/bench/README.md +10 -0
  6. package/bench/entrypoint.py +94 -0
  7. package/bench/handlers/__init__.py +53 -0
  8. package/bench/handlers/apply_skin.py +192 -0
  9. package/bench/handlers/apply_texture.py +195 -0
  10. package/bench/handlers/audit_clips.py +351 -0
  11. package/bench/handlers/author_clips.py +297 -0
  12. package/bench/handlers/author_motion.py +298 -0
  13. package/bench/handlers/bake_emissive.py +136 -0
  14. package/bench/handlers/build_level.py +395 -0
  15. package/bench/handlers/decimate.py +220 -0
  16. package/bench/handlers/fit_rig.py +273 -0
  17. package/bench/handlers/fracture.py +233 -0
  18. package/bench/handlers/humanoid.py +119 -0
  19. package/bench/handlers/inspect.py +212 -0
  20. package/bench/handlers/level_check.py +68 -0
  21. package/bench/handlers/level_geo.py +150 -0
  22. package/bench/handlers/level_proof.py +117 -0
  23. package/bench/handlers/level_props.py +135 -0
  24. package/bench/handlers/lod.py +83 -0
  25. package/bench/handlers/merge_clips.py +122 -0
  26. package/bench/handlers/mirror_limb.py +336 -0
  27. package/bench/handlers/motion_specs.json +11 -0
  28. package/bench/handlers/normalize_materials.py +182 -0
  29. package/bench/handlers/normalize_transform.py +174 -0
  30. package/bench/handlers/prune_clips.py +141 -0
  31. package/bench/handlers/raster.py +98 -0
  32. package/bench/handlers/render.py +239 -0
  33. package/bench/handlers/render_views.py +101 -0
  34. package/bench/handlers/retarget_clips.py +185 -0
  35. package/bench/handlers/scene.py +311 -0
  36. package/bench/handlers/sheet.py +118 -0
  37. package/bench/handlers/texels.py +176 -0
  38. package/bench/handlers/views.py +232 -0
  39. package/dist/api/generated/openapi.js +1 -0
  40. package/dist/api/http.js +71 -0
  41. package/dist/api/jobs.js +94 -0
  42. package/dist/assets/bakeoff.js +61 -0
  43. package/dist/assets/counts.js +60 -0
  44. package/dist/assets/gen.js +230 -0
  45. package/dist/assets/lock.js +77 -0
  46. package/dist/assets/manifest.js +236 -0
  47. package/dist/assets/palette-fit.js +99 -0
  48. package/dist/assets/pixelart.js +192 -0
  49. package/dist/assets/pixels.js +131 -0
  50. package/dist/assets/plan.js +169 -0
  51. package/dist/assets/process.js +209 -0
  52. package/dist/assets/script.js +194 -0
  53. package/dist/assets/steps.js +294 -0
  54. package/dist/bin.js +8 -0
  55. package/dist/board/board.js +99 -0
  56. package/dist/cast/library.js +102 -0
  57. package/dist/cast/measure.js +222 -0
  58. package/dist/cli.js +2917 -0
  59. package/dist/clip/clip.js +83 -0
  60. package/dist/commands/account.js +158 -0
  61. package/dist/commands/assets-pixels.js +106 -0
  62. package/dist/commands/assets.js +473 -0
  63. package/dist/commands/beats.js +77 -0
  64. package/dist/commands/board.js +162 -0
  65. package/dist/commands/boxes.js +89 -0
  66. package/dist/commands/capture-all.js +92 -0
  67. package/dist/commands/cast.js +84 -0
  68. package/dist/commands/character.js +58 -0
  69. package/dist/commands/check.js +404 -0
  70. package/dist/commands/clip.js +112 -0
  71. package/dist/commands/compare-takes.js +204 -0
  72. package/dist/commands/compare-target.js +149 -0
  73. package/dist/commands/compare.js +117 -0
  74. package/dist/commands/compose-variations.js +202 -0
  75. package/dist/commands/compose.js +163 -0
  76. package/dist/commands/cut.js +13 -0
  77. package/dist/commands/decide.js +90 -0
  78. package/dist/commands/depth.js +171 -0
  79. package/dist/commands/dev.js +138 -0
  80. package/dist/commands/directions.js +106 -0
  81. package/dist/commands/doctor.js +281 -0
  82. package/dist/commands/export.js +88 -0
  83. package/dist/commands/feedback.js +496 -0
  84. package/dist/commands/feel.js +144 -0
  85. package/dist/commands/fidelity.js +95 -0
  86. package/dist/commands/find.js +116 -0
  87. package/dist/commands/firstlook.js +138 -0
  88. package/dist/commands/flow.js +600 -0
  89. package/dist/commands/framing.js +53 -0
  90. package/dist/commands/gdd.js +227 -0
  91. package/dist/commands/gen.js +512 -0
  92. package/dist/commands/greenlight.js +148 -0
  93. package/dist/commands/hook.js +171 -0
  94. package/dist/commands/init.js +234 -0
  95. package/dist/commands/inspect.js +161 -0
  96. package/dist/commands/job.js +41 -0
  97. package/dist/commands/jobs.js +87 -0
  98. package/dist/commands/journal.js +58 -0
  99. package/dist/commands/journey.js +228 -0
  100. package/dist/commands/judge.js +191 -0
  101. package/dist/commands/lanes.js +571 -0
  102. package/dist/commands/lessons.js +74 -0
  103. package/dist/commands/life.js +134 -0
  104. package/dist/commands/login.js +134 -0
  105. package/dist/commands/look-3d.js +105 -0
  106. package/dist/commands/look-fit.js +116 -0
  107. package/dist/commands/look-hud.js +180 -0
  108. package/dist/commands/look-read.js +162 -0
  109. package/dist/commands/look-sheet.js +152 -0
  110. package/dist/commands/look-theme.js +136 -0
  111. package/dist/commands/look.js +373 -0
  112. package/dist/commands/loop.js +112 -0
  113. package/dist/commands/loudness.js +69 -0
  114. package/dist/commands/mobile-qa.js +119 -0
  115. package/dist/commands/model.js +256 -0
  116. package/dist/commands/models.js +93 -0
  117. package/dist/commands/motion.js +305 -0
  118. package/dist/commands/next.js +72 -0
  119. package/dist/commands/note.js +294 -0
  120. package/dist/commands/optimize.js +212 -0
  121. package/dist/commands/owner.js +109 -0
  122. package/dist/commands/pack.js +66 -0
  123. package/dist/commands/parts.js +635 -0
  124. package/dist/commands/phone.js +398 -0
  125. package/dist/commands/pick.js +146 -0
  126. package/dist/commands/pitch.js +205 -0
  127. package/dist/commands/places.js +89 -0
  128. package/dist/commands/play.js +368 -0
  129. package/dist/commands/playable.js +51 -0
  130. package/dist/commands/playtest.js +262 -0
  131. package/dist/commands/profile.js +292 -0
  132. package/dist/commands/progress.js +537 -0
  133. package/dist/commands/publish.js +165 -0
  134. package/dist/commands/reach.js +72 -0
  135. package/dist/commands/reel.js +177 -0
  136. package/dist/commands/review.js +112 -0
  137. package/dist/commands/rooms.js +180 -0
  138. package/dist/commands/schema.js +29 -0
  139. package/dist/commands/score.js +326 -0
  140. package/dist/commands/serve.js +67 -0
  141. package/dist/commands/setup.js +254 -0
  142. package/dist/commands/sim.js +179 -0
  143. package/dist/commands/simulator.js +154 -0
  144. package/dist/commands/smoke-build.js +305 -0
  145. package/dist/commands/smoke.js +37 -0
  146. package/dist/commands/spec.js +114 -0
  147. package/dist/commands/store.js +154 -0
  148. package/dist/commands/test.js +104 -0
  149. package/dist/commands/trailer.js +255 -0
  150. package/dist/commands/unity-editor.js +322 -0
  151. package/dist/commands/unity-player.js +672 -0
  152. package/dist/commands/unity.js +198 -0
  153. package/dist/commands/upgrade.js +186 -0
  154. package/dist/commands/variety.js +108 -0
  155. package/dist/commands/verify.js +293 -0
  156. package/dist/commands/walk.js +449 -0
  157. package/dist/commands/widen.js +133 -0
  158. package/dist/commands/world.js +175 -0
  159. package/dist/commands/wow.js +143 -0
  160. package/dist/commands/zero.js +71 -0
  161. package/dist/compose/adsheet.js +61 -0
  162. package/dist/compose/contract.js +248 -0
  163. package/dist/compose/facts.js +81 -0
  164. package/dist/compose/hyperframes.js +102 -0
  165. package/dist/compose/page.js +216 -0
  166. package/dist/compose/probe.js +160 -0
  167. package/dist/compose/run.js +170 -0
  168. package/dist/compose/sheet.js +92 -0
  169. package/dist/compose/starters.js +247 -0
  170. package/dist/compose/variations.js +203 -0
  171. package/dist/criteria.js +35 -0
  172. package/dist/depth/experience.js +61 -0
  173. package/dist/depth/fill.js +102 -0
  174. package/dist/depth/inventory.js +161 -0
  175. package/dist/depth/pacing.js +173 -0
  176. package/dist/depth/story.js +97 -0
  177. package/dist/dev/devtools.js +119 -0
  178. package/dist/dev/hold.js +46 -0
  179. package/dist/dev/lan.js +15 -0
  180. package/dist/dev/open.js +30 -0
  181. package/dist/dev/qr.js +124 -0
  182. package/dist/devtools/LICENSES/pixi.js.LICENSE +21 -0
  183. package/dist/devtools/LICENSES/preact.LICENSE +21 -0
  184. package/dist/devtools/LICENSES/source-map-js.LICENSE +28 -0
  185. package/dist/devtools/LICENSES/three.LICENSE +21 -0
  186. package/dist/devtools/inspector/funpixel-inspector.pixi.min.js +1 -0
  187. package/dist/devtools/inspector/funpixel-inspector.threejs.min.js +1 -0
  188. package/dist/devtools/inspector/hooked-engines/pixi.min.js +8 -0
  189. package/dist/devtools/inspector/hooked-engines/preact.min.js +1 -0
  190. package/dist/devtools/inspector/hooked-engines/threejs.min.js +12 -0
  191. package/dist/devtools/kapture/funpixel-kapture.min.js +1 -0
  192. package/dist/devtools/profiler/funpixel-profiler.pixi.min.js +1 -0
  193. package/dist/devtools/profiler/funpixel-profiler.threejs.min.js +1 -0
  194. package/dist/direct/moves.js +234 -0
  195. package/dist/direct/read.js +59 -0
  196. package/dist/direct/round.js +80 -0
  197. package/dist/doctor/host.js +245 -0
  198. package/dist/doctor/unity-checks.js +380 -0
  199. package/dist/doctor/unity-history.js +589 -0
  200. package/dist/doctor/unity-host.js +160 -0
  201. package/dist/doctor/unity-import-rules.js +874 -0
  202. package/dist/doctor/unity-meta.js +225 -0
  203. package/dist/doctor/unity-project.js +297 -0
  204. package/dist/doctor/unity.js +171 -0
  205. package/dist/export/export.js +165 -0
  206. package/dist/export/metadata.js +25 -0
  207. package/dist/export/runtime.js +119 -0
  208. package/dist/export/scan.js +78 -0
  209. package/dist/export/select.js +193 -0
  210. package/dist/export/strip.js +42 -0
  211. package/dist/feedback/ab.js +55 -0
  212. package/dist/feedback/auto.js +44 -0
  213. package/dist/feedback/learn.js +255 -0
  214. package/dist/feedback/measure.js +49 -0
  215. package/dist/feedback/page.js +66 -0
  216. package/dist/feel/feedback.js +85 -0
  217. package/dist/feel/judge.js +420 -0
  218. package/dist/feel/run.js +185 -0
  219. package/dist/feel/spec.js +124 -0
  220. package/dist/feel/sweep.js +156 -0
  221. package/dist/fidelity/consistency.js +205 -0
  222. package/dist/fidelity/match.js +675 -0
  223. package/dist/fidelity/run.js +107 -0
  224. package/dist/find/keywords.js +97 -0
  225. package/dist/find/names.js +45 -0
  226. package/dist/find/route.js +59 -0
  227. package/dist/firstlook/quality.js +261 -0
  228. package/dist/firstlook/render.js +111 -0
  229. package/dist/firstlook/set.js +218 -0
  230. package/dist/flow/flow.js +455 -0
  231. package/dist/flow/look.js +139 -0
  232. package/dist/frame/behaviour.js +53 -0
  233. package/dist/frame/clock.js +117 -0
  234. package/dist/frame/contract.js +111 -0
  235. package/dist/frame/genre.js +65 -0
  236. package/dist/frame/idle.js +58 -0
  237. package/dist/frame/opening.js +171 -0
  238. package/dist/frames/loop.js +52 -0
  239. package/dist/frames/sheet.js +69 -0
  240. package/dist/gdd/book.js +483 -0
  241. package/dist/gdd/chapters.js +71 -0
  242. package/dist/gdd/design.js +135 -0
  243. package/dist/gdd/doc.js +32 -0
  244. package/dist/gdd/levelmap.js +428 -0
  245. package/dist/gdd/measures.js +477 -0
  246. package/dist/gdd/page.js +111 -0
  247. package/dist/gdd/rubric.js +250 -0
  248. package/dist/gdd/size.js +83 -0
  249. package/dist/gdd/tiers.js +148 -0
  250. package/dist/gdd/world.js +98 -0
  251. package/dist/gdd/worth.js +507 -0
  252. package/dist/gen/kinds.js +451 -0
  253. package/dist/gen/local/doctor.js +25 -0
  254. package/dist/gen/local/index.js +3 -0
  255. package/dist/gen/local/kokoro.js +334 -0
  256. package/dist/gen/local/master.js +248 -0
  257. package/dist/gen/local/provider.js +65 -0
  258. package/dist/gen/local/voice-rules.js +156 -0
  259. package/dist/gen/models.generated.js +469 -0
  260. package/dist/gen/models.js +53 -0
  261. package/dist/gen/prompt-lint.js +35 -0
  262. package/dist/gen/record.js +73 -0
  263. package/dist/gen/save.js +101 -0
  264. package/dist/gen/title.js +55 -0
  265. package/dist/gen/unity.js +334 -0
  266. package/dist/goals/goals.js +204 -0
  267. package/dist/goals/run.js +90 -0
  268. package/dist/greenlight/ambition.js +42 -0
  269. package/dist/greenlight/bible.js +138 -0
  270. package/dist/greenlight/lock.js +48 -0
  271. package/dist/greenlight/match.js +19 -0
  272. package/dist/greenlight/md.js +82 -0
  273. package/dist/greenlight/page.js +100 -0
  274. package/dist/greenlight/pitches.js +66 -0
  275. package/dist/greenlight/worth.js +90 -0
  276. package/dist/guidance.js +24 -0
  277. package/dist/init/bare.js +114 -0
  278. package/dist/init/git.js +56 -0
  279. package/dist/init/starter.js +166 -0
  280. package/dist/init/starters.js +179 -0
  281. package/dist/inspect/describe.js +125 -0
  282. package/dist/inspect/devserver.js +40 -0
  283. package/dist/journey/diff.js +74 -0
  284. package/dist/journey/from-round.js +44 -0
  285. package/dist/journey/record.js +76 -0
  286. package/dist/journey/run.js +139 -0
  287. package/dist/journey/script.js +223 -0
  288. package/dist/judge/common.js +60 -0
  289. package/dist/judge/identity.js +68 -0
  290. package/dist/judge/sources.js +37 -0
  291. package/dist/judge/structure.js +59 -0
  292. package/dist/keys/device.js +145 -0
  293. package/dist/keys/store.js +167 -0
  294. package/dist/lanes/fence.js +108 -0
  295. package/dist/lanes/gate.js +123 -0
  296. package/dist/lanes/lanes.js +355 -0
  297. package/dist/lanes/union.js +62 -0
  298. package/dist/lanes/where.js +49 -0
  299. package/dist/lessons/motifs.js +97 -0
  300. package/dist/lessons/store.js +56 -0
  301. package/dist/look/anim.js +206 -0
  302. package/dist/look/boxes.js +209 -0
  303. package/dist/look/dressing.js +24 -0
  304. package/dist/look/feedback.js +50 -0
  305. package/dist/look/fit.js +123 -0
  306. package/dist/look/held.js +92 -0
  307. package/dist/look/hook.js +169 -0
  308. package/dist/look/hud.js +189 -0
  309. package/dist/look/image-io.js +50 -0
  310. package/dist/look/life.js +96 -0
  311. package/dist/look/light.js +42 -0
  312. package/dist/look/look.js +85 -0
  313. package/dist/look/loops.js +108 -0
  314. package/dist/look/made-of.js +242 -0
  315. package/dist/look/moments.js +32 -0
  316. package/dist/look/motion.js +44 -0
  317. package/dist/look/phone-play.js +142 -0
  318. package/dist/look/player.js +32 -0
  319. package/dist/look/png.js +117 -0
  320. package/dist/look/readability.js +100 -0
  321. package/dist/look/roles.js +109 -0
  322. package/dist/look/sheet.js +104 -0
  323. package/dist/look/theme.js +278 -0
  324. package/dist/look/touch.js +129 -0
  325. package/dist/look/ui-style.js +102 -0
  326. package/dist/machine/procs.js +117 -0
  327. package/dist/managed.js +15 -0
  328. package/dist/mcp/hosted.js +174 -0
  329. package/dist/mcp/models.generated.js +538 -0
  330. package/dist/mcp/models.js +35 -0
  331. package/dist/mcp/server.js +330 -0
  332. package/dist/memory/decisions.js +138 -0
  333. package/dist/memory/journal.js +108 -0
  334. package/dist/model/bench.js +83 -0
  335. package/dist/model/blender.js +106 -0
  336. package/dist/model/clips.js +34 -0
  337. package/dist/model/finalize.js +33 -0
  338. package/dist/motion/checks.js +173 -0
  339. package/dist/motion/contract.js +177 -0
  340. package/dist/motion/encode.js +37 -0
  341. package/dist/motion/render.js +167 -0
  342. package/dist/motion/starter.js +54 -0
  343. package/dist/optimize/check.js +29 -0
  344. package/dist/optimize/helper.js +80 -0
  345. package/dist/owner/bar.js +285 -0
  346. package/dist/owner/match.js +105 -0
  347. package/dist/pack/build.js +97 -0
  348. package/dist/pack/deps.js +28 -0
  349. package/dist/pack/leaks.js +77 -0
  350. package/dist/pack/limits.js +51 -0
  351. package/dist/pack/report.js +35 -0
  352. package/dist/phone/baguette.js +139 -0
  353. package/dist/phone/listen.js +65 -0
  354. package/dist/pipeline/pipeline.js +929 -0
  355. package/dist/plan/actions.js +18 -0
  356. package/dist/plan/notes.js +15 -0
  357. package/dist/play/clock.js +40 -0
  358. package/dist/play/condition.js +45 -0
  359. package/dist/play/frames.js +60 -0
  360. package/dist/play/input.js +118 -0
  361. package/dist/play/pointer.js +21 -0
  362. package/dist/play/report.js +124 -0
  363. package/dist/play/server.js +274 -0
  364. package/dist/play/session.js +231 -0
  365. package/dist/play/steps.js +192 -0
  366. package/dist/playable/build.js +90 -0
  367. package/dist/playable/cta.js +88 -0
  368. package/dist/playable/networks.js +33 -0
  369. package/dist/playable/scan.js +46 -0
  370. package/dist/playtest/after-round.js +60 -0
  371. package/dist/playtest/assemble.js +168 -0
  372. package/dist/playtest/experience-run.js +69 -0
  373. package/dist/playtest/experience.js +77 -0
  374. package/dist/playtest/facts.js +90 -0
  375. package/dist/playtest/fidelity.js +179 -0
  376. package/dist/playtest/history.js +115 -0
  377. package/dist/playtest/hits.js +48 -0
  378. package/dist/playtest/hosted.js +98 -0
  379. package/dist/playtest/keep.js +110 -0
  380. package/dist/playtest/ledger.js +77 -0
  381. package/dist/playtest/length.js +113 -0
  382. package/dist/playtest/measure.js +181 -0
  383. package/dist/playtest/mobile-qa.js +391 -0
  384. package/dist/playtest/mockups.js +198 -0
  385. package/dist/playtest/moments.js +28 -0
  386. package/dist/playtest/prepare.js +162 -0
  387. package/dist/playtest/rank.js +184 -0
  388. package/dist/playtest/report.js +209 -0
  389. package/dist/playtest/route.js +139 -0
  390. package/dist/playtest/seats.js +128 -0
  391. package/dist/playtest/sheet.js +38 -0
  392. package/dist/playtest/stop.js +54 -0
  393. package/dist/playtest/stuck.js +47 -0
  394. package/dist/production/contract.js +61 -0
  395. package/dist/production/mirror.js +96 -0
  396. package/dist/production/tier.js +66 -0
  397. package/dist/profile/compare.js +171 -0
  398. package/dist/progress/answers.js +35 -0
  399. package/dist/progress/holds.js +106 -0
  400. package/dist/progress/notify.js +25 -0
  401. package/dist/progress/progress.js +300 -0
  402. package/dist/publish/build.js +54 -0
  403. package/dist/publish/folder.js +106 -0
  404. package/dist/publish/funpixel.js +96 -0
  405. package/dist/publish/hosts.js +48 -0
  406. package/dist/reach/envelope.js +111 -0
  407. package/dist/reach/load.js +84 -0
  408. package/dist/reach/side.js +320 -0
  409. package/dist/reach/spec3d.js +338 -0
  410. package/dist/reach/tiles.js +163 -0
  411. package/dist/reel/encode.js +34 -0
  412. package/dist/reel/tour.js +81 -0
  413. package/dist/relay/bots.js +62 -0
  414. package/dist/relay/bridge.js +54 -0
  415. package/dist/relay/local.js +82 -0
  416. package/dist/relay/redis.js +40 -0
  417. package/dist/review/audio.js +72 -0
  418. package/dist/review/ledger.js +60 -0
  419. package/dist/review/media.js +114 -0
  420. package/dist/review/model.js +348 -0
  421. package/dist/review/picture.js +113 -0
  422. package/dist/review/specs.js +134 -0
  423. package/dist/review/video.js +248 -0
  424. package/dist/schema/game.js +308 -0
  425. package/dist/score/comfort.js +79 -0
  426. package/dist/score/light.js +62 -0
  427. package/dist/score/measure.js +386 -0
  428. package/dist/score/vision.js +59 -0
  429. package/dist/serve/webgl.js +415 -0
  430. package/dist/setup/lsp.js +42 -0
  431. package/dist/sim/curve.js +122 -0
  432. package/dist/sim/judge.js +240 -0
  433. package/dist/sim/skeleton.js +65 -0
  434. package/dist/simulator/lease.js +159 -0
  435. package/dist/simulator/orient.js +57 -0
  436. package/dist/simulator/screen.js +113 -0
  437. package/dist/simulator/simctl.js +79 -0
  438. package/dist/smoke/art.js +20 -0
  439. package/dist/smoke/checks.js +165 -0
  440. package/dist/smoke/logic.js +73 -0
  441. package/dist/smoke/orphans.js +78 -0
  442. package/dist/smoke/palette.js +16 -0
  443. package/dist/smoke/sources.js +36 -0
  444. package/dist/sound/beats.js +95 -0
  445. package/dist/sound/loudness.js +94 -0
  446. package/dist/spec/extract.js +123 -0
  447. package/dist/spec/lint.js +261 -0
  448. package/dist/spec/presets.js +30 -0
  449. package/dist/spec/rooms.js +188 -0
  450. package/dist/spec/scaffold.js +457 -0
  451. package/dist/spec/sections.js +16 -0
  452. package/dist/spec/tunables.js +74 -0
  453. package/dist/stage/harnessignore.js +90 -0
  454. package/dist/stage/stage.js +57 -0
  455. package/dist/stage/tar.js +41 -0
  456. package/dist/status/board.js +172 -0
  457. package/dist/status/file.js +112 -0
  458. package/dist/status/inbox.js +55 -0
  459. package/dist/status/status.js +311 -0
  460. package/dist/store/answers.js +47 -0
  461. package/dist/store/doctor.js +120 -0
  462. package/dist/store/images.js +65 -0
  463. package/dist/store/init.js +101 -0
  464. package/dist/store/lint.js +392 -0
  465. package/dist/store/plan.js +133 -0
  466. package/dist/store/sdks.js +107 -0
  467. package/dist/studio/forks.js +93 -0
  468. package/dist/studio/pitch.js +294 -0
  469. package/dist/studio/widen.js +212 -0
  470. package/dist/suite/node-run.js +81 -0
  471. package/dist/suite/test-types.js +71 -0
  472. package/dist/trailer/assemble.js +90 -0
  473. package/dist/trailer/beats.js +74 -0
  474. package/dist/trailer/cards.js +77 -0
  475. package/dist/trailer/cues.js +78 -0
  476. package/dist/trailer/cut.js +49 -0
  477. package/dist/trailer/find.js +33 -0
  478. package/dist/trailer/mix.js +109 -0
  479. package/dist/trailer/placement.js +30 -0
  480. package/dist/types.js +1 -0
  481. package/dist/ui.js +79 -0
  482. package/dist/unity/bridge.js +251 -0
  483. package/dist/unity/disk.js +666 -0
  484. package/dist/unity/editor.js +471 -0
  485. package/dist/unity/gc.js +140 -0
  486. package/dist/unity/mcp-stdio.js +141 -0
  487. package/dist/unity/probe/budgets.js +84 -0
  488. package/dist/unity/probe/client.js +93 -0
  489. package/dist/unity/probe/install.js +118 -0
  490. package/dist/unity/probe/player.js +255 -0
  491. package/dist/unity/probe/report.js +102 -0
  492. package/dist/unity/probe/script.js +225 -0
  493. package/dist/unity/queue.js +353 -0
  494. package/dist/unity/run.js +172 -0
  495. package/dist/update.js +111 -0
  496. package/dist/variety/compare.js +104 -0
  497. package/dist/variety/places.js +109 -0
  498. package/dist/variety/profile.js +127 -0
  499. package/dist/vendor/verify/README.md +19 -0
  500. package/dist/vendor/verify/package.json +14 -0
  501. package/dist/vendor/verify/src/index.d.ts +105 -0
  502. package/dist/vendor/verify/src/index.js +78 -0
  503. package/dist/vendor/verify/src/init/preview_shim.js +63 -0
  504. package/dist/vendor/verify/src/page/actors.js +258 -0
  505. package/dist/vendor/verify/src/page/audio.js +106 -0
  506. package/dist/vendor/verify/src/page/audio_cues.js +141 -0
  507. package/dist/vendor/verify/src/page/audio_files.js +56 -0
  508. package/dist/vendor/verify/src/page/bot_sweep.js +72 -0
  509. package/dist/vendor/verify/src/page/capture_view.js +164 -0
  510. package/dist/vendor/verify/src/page/context_loss_listener.js +23 -0
  511. package/dist/vendor/verify/src/page/dressing.js +106 -0
  512. package/dist/vendor/verify/src/page/enter_view.js +33 -0
  513. package/dist/vendor/verify/src/page/feel.js +126 -0
  514. package/dist/vendor/verify/src/page/feel_sweep.js +75 -0
  515. package/dist/vendor/verify/src/page/first_paint.js +54 -0
  516. package/dist/vendor/verify/src/page/fonts.js +50 -0
  517. package/dist/vendor/verify/src/page/frame_honesty.js +44 -0
  518. package/dist/vendor/verify/src/page/front_door.js +197 -0
  519. package/dist/vendor/verify/src/page/grounding.js +448 -0
  520. package/dist/vendor/verify/src/page/hooks.js +74 -0
  521. package/dist/vendor/verify/src/page/hud.js +261 -0
  522. package/dist/vendor/verify/src/page/inventory.js +15 -0
  523. package/dist/vendor/verify/src/page/layout.js +378 -0
  524. package/dist/vendor/verify/src/page/levels.js +40 -0
  525. package/dist/vendor/verify/src/page/life.js +123 -0
  526. package/dist/vendor/verify/src/page/life_anim.js +501 -0
  527. package/dist/vendor/verify/src/page/made_of.js +83 -0
  528. package/dist/vendor/verify/src/page/mechanic_check.js +272 -0
  529. package/dist/vendor/verify/src/page/moments.js +36 -0
  530. package/dist/vendor/verify/src/page/motion.js +139 -0
  531. package/dist/vendor/verify/src/page/perf.js +255 -0
  532. package/dist/vendor/verify/src/page/phone_check.js +229 -0
  533. package/dist/vendor/verify/src/page/play.js +117 -0
  534. package/dist/vendor/verify/src/page/play_act.js +164 -0
  535. package/dist/vendor/verify/src/page/preview.js +33 -0
  536. package/dist/vendor/verify/src/page/recorder.js +54 -0
  537. package/dist/vendor/verify/src/page/render_health.js +83 -0
  538. package/dist/vendor/verify/src/page/renderer.js +75 -0
  539. package/dist/vendor/verify/src/page/scene.js +222 -0
  540. package/dist/vendor/verify/src/page/self_test.js +25 -0
  541. package/dist/vendor/verify/src/page/step_clock.js +247 -0
  542. package/dist/vendor/verify/src/page/surfaces.js +261 -0
  543. package/dist/vendor/verify/src/page/world_actors.js +264 -0
  544. package/dist/verify/browser.js +245 -0
  545. package/dist/verify/console.js +34 -0
  546. package/dist/verify/fingerprint.js +72 -0
  547. package/dist/verify/gpu.js +33 -0
  548. package/dist/verify/health.js +172 -0
  549. package/dist/verify/hooks.js +34 -0
  550. package/dist/verify/judge.js +303 -0
  551. package/dist/verify/players.js +123 -0
  552. package/dist/verify/probe.js +236 -0
  553. package/dist/verify/reads.js +32 -0
  554. package/dist/verify/run.js +56 -0
  555. package/dist/verify/serve.js +36 -0
  556. package/dist/walk/film.js +37 -0
  557. package/dist/walk/judge.js +287 -0
  558. package/dist/walk/routes.js +199 -0
  559. package/dist/walk/world.js +292 -0
  560. package/dist/world/brief.js +86 -0
  561. package/dist/world/check.js +254 -0
  562. package/dist/world/forge.js +542 -0
  563. package/dist/world/format.js +40 -0
  564. package/dist/world/variety.js +59 -0
  565. package/dist/wow/catalogue.js +86 -0
  566. package/dist/wow/picks.js +74 -0
  567. package/package.json +51 -4
  568. package/panel/asset-identity.md +61 -0
  569. package/panel/asset-structure.md +55 -0
  570. package/panel/blockers.md +47 -0
  571. package/panel/brief.md +89 -0
  572. package/panel/clip.md +54 -0
  573. package/panel/experience-personas.json +4 -0
  574. package/panel/experience.md +96 -0
  575. package/panel/fidelity-ui.md +74 -0
  576. package/panel/fidelity.md +83 -0
  577. package/panel/greenlight-pitch.md +69 -0
  578. package/panel/greenlight.md +87 -0
  579. package/panel/mobile-qa.md +128 -0
  580. package/panel/personas.json +6 -0
  581. package/panel/reference-match.md +12 -0
  582. package/panel/versus.md +31 -0
  583. package/plugins/.agents/plugins/marketplace.json +18 -0
  584. package/plugins/.claude-plugin/marketplace.json +17 -0
  585. package/plugins/.cursor-plugin/marketplace.json +13 -0
  586. package/plugins/LICENSE +115 -0
  587. package/plugins/README.md +16 -0
  588. package/plugins/THIRD_PARTY_NOTICES.md +75 -0
  589. package/plugins/claude/.claude-plugin/plugin.json +19 -0
  590. package/plugins/claude/.mcp.json +10 -0
  591. package/plugins/claude/LICENSE +115 -0
  592. package/plugins/claude/README.md +14 -0
  593. package/plugins/claude/THIRD_PARTY_NOTICES.md +75 -0
  594. package/plugins/claude/agents/art-director.md +54 -0
  595. package/plugins/claude/agents/audio-director.md +51 -0
  596. package/plugins/claude/agents/critic.md +113 -0
  597. package/plugins/claude/agents/lane.md +38 -0
  598. package/plugins/claude/agents/level-designer.md +45 -0
  599. package/plugins/claude/agents/mobile-qa.md +71 -0
  600. package/plugins/claude/agents/player.md +144 -0
  601. package/plugins/claude/agents/qa-lead.md +52 -0
  602. package/plugins/claude/commands/first-look.md +59 -0
  603. package/plugins/claude/commands/flow.md +50 -0
  604. package/plugins/claude/commands/lanes.md +38 -0
  605. package/plugins/claude/commands/mobile-qa.md +28 -0
  606. package/plugins/claude/commands/new.md +94 -0
  607. package/plugins/claude/commands/playtest.md +66 -0
  608. package/plugins/claude/commands/publish.md +23 -0
  609. package/plugins/claude/commands/smoke-build.md +25 -0
  610. package/plugins/claude/commands/verify.md +20 -0
  611. package/plugins/claude/hooks/brief.md +135 -0
  612. package/plugins/claude/hooks/critic-receipts.mjs +86 -0
  613. package/plugins/claude/hooks/durable.mjs +56 -0
  614. package/plugins/claude/hooks/fence.mjs +30 -0
  615. package/plugins/claude/hooks/floors.mjs +181 -0
  616. package/plugins/claude/hooks/flow.mjs +154 -0
  617. package/plugins/claude/hooks/front-door.mjs +68 -0
  618. package/plugins/claude/hooks/guidance.json +3 -0
  619. package/plugins/claude/hooks/hints.mjs +183 -0
  620. package/plugins/claude/hooks/hooks.json +62 -0
  621. package/plugins/claude/hooks/lib.mjs +362 -0
  622. package/plugins/claude/hooks/memory.mjs +92 -0
  623. package/plugins/claude/hooks/mobile-qa.mjs +43 -0
  624. package/plugins/claude/hooks/note.mjs +63 -0
  625. package/plugins/claude/hooks/nudge.mjs +98 -0
  626. package/plugins/claude/hooks/pipeline.mjs +207 -0
  627. package/plugins/claude/hooks/prompt.mjs +51 -0
  628. package/plugins/claude/hooks/quality.mjs +310 -0
  629. package/plugins/claude/hooks/reach.mjs +93 -0
  630. package/plugins/claude/hooks/scope.mjs +44 -0
  631. package/plugins/claude/hooks/session-log.mjs +101 -0
  632. package/plugins/claude/hooks/session-start.mjs +194 -0
  633. package/plugins/claude/hooks/skill-names.json +19 -0
  634. package/plugins/claude/hooks/stop-gate.mjs +303 -0
  635. package/plugins/claude/hooks/vendor/direct/round.mjs +81 -0
  636. package/plugins/claude/hooks/vendor/find/names.mjs +46 -0
  637. package/plugins/claude/hooks/vendor/firstlook/set.mjs +219 -0
  638. package/plugins/claude/hooks/vendor/flow/flow.mjs +456 -0
  639. package/plugins/claude/hooks/vendor/flow/look.mjs +140 -0
  640. package/plugins/claude/hooks/vendor/gdd/book.mjs +484 -0
  641. package/plugins/claude/hooks/vendor/gdd/chapters.mjs +72 -0
  642. package/plugins/claude/hooks/vendor/gdd/doc.mjs +33 -0
  643. package/plugins/claude/hooks/vendor/gdd/levelmap.mjs +429 -0
  644. package/plugins/claude/hooks/vendor/gdd/rubric.mjs +251 -0
  645. package/plugins/claude/hooks/vendor/gdd/worth.mjs +508 -0
  646. package/plugins/claude/hooks/vendor/lanes/fence.mjs +109 -0
  647. package/plugins/claude/hooks/vendor/lanes/lanes.mjs +356 -0
  648. package/plugins/claude/hooks/vendor/lanes/union.mjs +63 -0
  649. package/plugins/claude/hooks/vendor/lessons/motifs.mjs +98 -0
  650. package/plugins/claude/hooks/vendor/lessons/store.mjs +57 -0
  651. package/plugins/claude/hooks/vendor/look/made-of.mjs +243 -0
  652. package/plugins/claude/hooks/vendor/look/roles.mjs +110 -0
  653. package/plugins/claude/hooks/vendor/memory/decisions.mjs +139 -0
  654. package/plugins/claude/hooks/vendor/memory/journal.mjs +109 -0
  655. package/plugins/claude/hooks/vendor/owner/bar.mjs +286 -0
  656. package/plugins/claude/hooks/vendor/pipeline/pipeline.mjs +930 -0
  657. package/plugins/claude/hooks/vendor/playtest/keep.mjs +111 -0
  658. package/plugins/claude/hooks/vendor/playtest/stuck.mjs +48 -0
  659. package/plugins/claude/hooks/vendor/progress/holds.mjs +107 -0
  660. package/plugins/claude/hooks/vendor/progress/progress.mjs +301 -0
  661. package/plugins/claude/hooks/vendor/sim/judge.mjs +241 -0
  662. package/plugins/claude/hooks/vendor/spec/rooms.mjs +189 -0
  663. package/plugins/claude/hooks/vendor/spec/tunables.mjs +75 -0
  664. package/plugins/claude/hooks/vendor/stage/harnessignore.mjs +91 -0
  665. package/plugins/claude/hooks/vendor/stage/stage.mjs +58 -0
  666. package/plugins/claude/hooks/vendor/status/board.mjs +173 -0
  667. package/plugins/claude/hooks/vendor/status/file.mjs +113 -0
  668. package/plugins/claude/hooks/vendor/studio/forks.mjs +94 -0
  669. package/plugins/claude/hooks/vendor/studio/pitch.mjs +295 -0
  670. package/plugins/claude/hooks/vendor/verify/fingerprint.mjs +73 -0
  671. package/plugins/claude/hooks/vendor/verify/reads.mjs +33 -0
  672. package/plugins/claude/hooks/vendor/wow/picks.mjs +75 -0
  673. package/plugins/claude/skills/3d/SKILL.md +89 -0
  674. package/plugins/claude/skills/3d/references/bake-off.md +48 -0
  675. package/plugins/claude/skills/3d/references/bench.md +103 -0
  676. package/plugins/claude/skills/3d/references/budgets.md +48 -0
  677. package/plugins/claude/skills/3d/references/characters.md +67 -0
  678. package/plugins/claude/skills/3d/references/concept-image.md +47 -0
  679. package/plugins/claude/skills/3d/references/engine-targets.md +31 -0
  680. package/plugins/claude/skills/3d/references/hero-route.md +104 -0
  681. package/plugins/claude/skills/3d/references/level-spec.md +109 -0
  682. package/plugins/claude/skills/3d/references/levels.md +84 -0
  683. package/plugins/claude/skills/3d/references/light-and-places.md +141 -0
  684. package/plugins/claude/skills/3d/references/models.md +111 -0
  685. package/plugins/claude/skills/3d/references/painted-target.md +184 -0
  686. package/plugins/claude/skills/3d/references/reading.md +41 -0
  687. package/plugins/claude/skills/3d/references/skin.md +85 -0
  688. package/plugins/claude/skills/3d/references/skyboxes.md +65 -0
  689. package/plugins/claude/skills/3d/references/textures.md +71 -0
  690. package/plugins/claude/skills/3d/references/three-loading.md +199 -0
  691. package/plugins/claude/skills/3d/references/unity.md +78 -0
  692. package/plugins/claude/skills/art/SKILL.md +104 -0
  693. package/plugins/claude/skills/art/references/2d-assets.md +108 -0
  694. package/plugins/claude/skills/art/references/animation.md +126 -0
  695. package/plugins/claude/skills/art/references/cast.md +73 -0
  696. package/plugins/claude/skills/art/references/characters.md +49 -0
  697. package/plugins/claude/skills/art/references/cost.md +107 -0
  698. package/plugins/claude/skills/art/references/effects.md +85 -0
  699. package/plugins/claude/skills/art/references/frames.md +87 -0
  700. package/plugins/claude/skills/art/references/judging-frames.md +64 -0
  701. package/plugins/claude/skills/art/references/look.md +102 -0
  702. package/plugins/claude/skills/art/references/measure.md +119 -0
  703. package/plugins/claude/skills/art/references/pipeline.md +185 -0
  704. package/plugins/claude/skills/art/references/pixi.md +277 -0
  705. package/plugins/claude/skills/art/references/planes.md +27 -0
  706. package/plugins/claude/skills/art/references/prompts.md +171 -0
  707. package/plugins/claude/skills/art/references/sheets.md +141 -0
  708. package/plugins/claude/skills/art/references/style-file.md +39 -0
  709. package/plugins/claude/skills/art/references/three.md +232 -0
  710. package/plugins/claude/skills/art/references/ui.md +163 -0
  711. package/plugins/claude/skills/art/references/unity.md +78 -0
  712. package/plugins/claude/skills/art/references/wiring.md +41 -0
  713. package/plugins/claude/skills/audio/SKILL.md +92 -0
  714. package/plugins/claude/skills/audio/references/adaptive-music.md +204 -0
  715. package/plugins/claude/skills/audio/references/engine.md +78 -0
  716. package/plugins/claude/skills/audio/references/measure.md +101 -0
  717. package/plugins/claude/skills/audio/references/unity.md +74 -0
  718. package/plugins/claude/skills/feedback/SKILL.md +120 -0
  719. package/plugins/claude/skills/feedback/references/memory.md +99 -0
  720. package/plugins/claude/skills/game-feel/SKILL.md +104 -0
  721. package/plugins/claude/skills/game-feel/references/contact.md +110 -0
  722. package/plugins/claude/skills/game-feel/references/measure.md +125 -0
  723. package/plugins/claude/skills/game-feel/references/motion.md +134 -0
  724. package/plugins/claude/skills/game-feel/references/payoffs.md +35 -0
  725. package/plugins/claude/skills/game-feel/references/recipes.md +107 -0
  726. package/plugins/claude/skills/game-feel/references/unity.md +73 -0
  727. package/plugins/claude/skills/game-logic/SKILL.md +113 -0
  728. package/plugins/claude/skills/game-logic/references/balance.md +88 -0
  729. package/plugins/claude/skills/game-logic/references/content-at-scale.md +147 -0
  730. package/plugins/claude/skills/game-logic/references/depth.md +89 -0
  731. package/plugins/claude/skills/game-logic/references/escalation.md +41 -0
  732. package/plugins/claude/skills/game-logic/references/levels.md +61 -0
  733. package/plugins/claude/skills/game-logic/references/probes.md +122 -0
  734. package/plugins/claude/skills/game-logic/references/unity.md +108 -0
  735. package/plugins/claude/skills/game-spine/SKILL.md +118 -0
  736. package/plugins/claude/skills/game-spine/references/camera.md +94 -0
  737. package/plugins/claude/skills/game-spine/references/multiplayer.md +101 -0
  738. package/plugins/claude/skills/game-spine/references/patterns.md +103 -0
  739. package/plugins/claude/skills/game-spine/references/performance.md +96 -0
  740. package/plugins/claude/skills/game-spine/references/pixi.md +26 -0
  741. package/plugins/claude/skills/game-spine/references/replay.md +102 -0
  742. package/plugins/claude/skills/game-spine/references/room-api.md +63 -0
  743. package/plugins/claude/skills/game-spine/references/room-modes.md +40 -0
  744. package/plugins/claude/skills/game-spine/references/sdk.md +114 -0
  745. package/plugins/claude/skills/game-spine/references/three.md +62 -0
  746. package/plugins/claude/skills/gdd/SKILL.md +116 -0
  747. package/plugins/claude/skills/gdd/references/as-built.md +40 -0
  748. package/plugins/claude/skills/gdd/references/design-measures.md +24 -0
  749. package/plugins/claude/skills/gdd/references/design-note.md +88 -0
  750. package/plugins/claude/skills/gdd/references/experience.md +92 -0
  751. package/plugins/claude/skills/gdd/references/first-look.md +226 -0
  752. package/plugins/claude/skills/gdd/references/floors.md +62 -0
  753. package/plugins/claude/skills/gdd/references/frame.md +75 -0
  754. package/plugins/claude/skills/gdd/references/gameplay-contract.md +81 -0
  755. package/plugins/claude/skills/gdd/references/gdd-template.md +417 -0
  756. package/plugins/claude/skills/gdd/references/genre-card.md +109 -0
  757. package/plugins/claude/skills/gdd/references/genre-platformer.md +159 -0
  758. package/plugins/claude/skills/gdd/references/genre-puzzle.md +145 -0
  759. package/plugins/claude/skills/gdd/references/genre-racing.md +137 -0
  760. package/plugins/claude/skills/gdd/references/genre-rpg.md +125 -0
  761. package/plugins/claude/skills/gdd/references/genre-shooter.md +128 -0
  762. package/plugins/claude/skills/gdd/references/genre-simulation.md +112 -0
  763. package/plugins/claude/skills/gdd/references/genre-strategy.md +116 -0
  764. package/plugins/claude/skills/gdd/references/genre-survival.md +122 -0
  765. package/plugins/claude/skills/gdd/references/in-the-loop.md +106 -0
  766. package/plugins/claude/skills/gdd/references/invent-first.md +131 -0
  767. package/plugins/claude/skills/gdd/references/level-and-fun.md +112 -0
  768. package/plugins/claude/skills/gdd/references/pages.md +47 -0
  769. package/plugins/claude/skills/gdd/references/plan-at-size.md +140 -0
  770. package/plugins/claude/skills/gdd/references/production-tiers.md +117 -0
  771. package/plugins/claude/skills/gdd/references/sections.md +148 -0
  772. package/plugins/claude/skills/gdd/references/spec-folder.md +131 -0
  773. package/plugins/claude/skills/gdd/references/start.md +110 -0
  774. package/plugins/claude/skills/gdd/references/starters.md +175 -0
  775. package/plugins/claude/skills/gdd/references/the-path.md +133 -0
  776. package/plugins/claude/skills/gdd/references/track.md +29 -0
  777. package/plugins/claude/skills/gdd/references/world-and-identity.md +165 -0
  778. package/plugins/claude/skills/gdd/references/worth.md +74 -0
  779. package/plugins/claude/skills/mobile-ui/SKILL.md +107 -0
  780. package/plugins/claude/skills/mobile-ui/references/contrast.md +123 -0
  781. package/plugins/claude/skills/mobile-ui/references/hud-and-title.md +108 -0
  782. package/plugins/claude/skills/mobile-ui/references/hud-genres.md +124 -0
  783. package/plugins/claude/skills/mobile-ui/references/phone-check.md +156 -0
  784. package/plugins/claude/skills/mobile-ui/references/recipes.md +279 -0
  785. package/plugins/claude/skills/mobile-ui/references/restyle-ui.md +229 -0
  786. package/plugins/claude/skills/mobile-ui/references/unity.md +61 -0
  787. package/plugins/claude/skills/publishing/SKILL.md +109 -0
  788. package/plugins/claude/skills/publishing/references/compose.md +113 -0
  789. package/plugins/claude/skills/publishing/references/motion.md +120 -0
  790. package/plugins/claude/skills/publishing/references/networks.md +75 -0
  791. package/plugins/claude/skills/publishing/references/other-hosts.md +65 -0
  792. package/plugins/claude/skills/publishing/references/playable-ad.md +90 -0
  793. package/plugins/claude/skills/publishing/references/server-build.md +85 -0
  794. package/plugins/claude/skills/publishing/references/store-shots.md +85 -0
  795. package/plugins/claude/skills/publishing/references/trailer.md +55 -0
  796. package/plugins/claude/skills/publishing/references/what-ships.md +30 -0
  797. package/plugins/claude/skills/store/SKILL.md +81 -0
  798. package/plugins/claude/skills/store/references/app-store.md +73 -0
  799. package/plugins/claude/skills/store/references/google-play.md +141 -0
  800. package/plugins/claude/skills/store/references/ios-release.md +63 -0
  801. package/plugins/claude/skills/store/references/money.md +66 -0
  802. package/plugins/claude/skills/store/references/purchases-and-review.md +74 -0
  803. package/plugins/claude/skills/store/references/readiness-page.md +24 -0
  804. package/plugins/claude/skills/store/references/readiness.md +107 -0
  805. package/plugins/claude/skills/store/references/steam.md +38 -0
  806. package/plugins/claude/skills/store/references/unity-store.md +55 -0
  807. package/plugins/claude/skills/store/references/web-portals.md +43 -0
  808. package/plugins/claude/skills/unity-game/SKILL.md +103 -0
  809. package/plugins/claude/skills/unity-game/references/agent-ops.md +54 -0
  810. package/plugins/claude/skills/unity-game/references/fixes.md +40 -0
  811. package/plugins/claude/skills/unity-game/references/from-a-web-game.md +108 -0
  812. package/plugins/claude/skills/unity-game/references/handing-off.md +42 -0
  813. package/plugins/claude/skills/unity-game/references/performance.md +59 -0
  814. package/plugins/claude/skills/unity-game/references/probe.md +80 -0
  815. package/plugins/claude/skills/unity-game/references/shared-mac.md +121 -0
  816. package/plugins/claude/skills/unity-game/references/traps.md +108 -0
  817. package/plugins/claude/skills/verifying/SKILL.md +109 -0
  818. package/plugins/claude/skills/verifying/references/actors.md +94 -0
  819. package/plugins/claude/skills/verifying/references/bar.md +62 -0
  820. package/plugins/claude/skills/verifying/references/checks.md +69 -0
  821. package/plugins/claude/skills/verifying/references/experience.md +67 -0
  822. package/plugins/claude/skills/verifying/references/eyes.md +54 -0
  823. package/plugins/claude/skills/verifying/references/fidelity.md +126 -0
  824. package/plugins/claude/skills/verifying/references/hit-bar.md +31 -0
  825. package/plugins/claude/skills/verifying/references/journeys.md +77 -0
  826. package/plugins/claude/skills/verifying/references/mobile-qa.md +123 -0
  827. package/plugins/claude/skills/verifying/references/playtest.md +161 -0
  828. package/plugins/claude/skills/verifying/references/review.md +105 -0
  829. package/plugins/claude/skills/verifying/references/rubric.md +67 -0
  830. package/plugins/claude/skills/verifying/references/scenes.md +49 -0
  831. package/plugins/claude/skills/verifying/references/unity.md +60 -0
  832. package/plugins/claude/skills/world-and-story/SKILL.md +99 -0
  833. package/plugins/claude/skills/world-and-story/references/atmosphere.md +208 -0
  834. package/plugins/claude/skills/world-and-story/references/forged-world.md +79 -0
  835. package/plugins/claude/skills/world-and-story/references/living-world.md +237 -0
  836. package/plugins/claude/skills/world-and-story/references/opening-and-chapters.md +215 -0
  837. package/plugins/claude/skills/world-and-story/references/shelf.md +80 -0
  838. package/plugins/claude/skills/world-and-story/references/story-at-size.md +159 -0
  839. package/plugins/claude/skills/world-and-story/references/voice.md +175 -0
  840. package/plugins/claude/skills/world-and-story/references/world-kit.md +154 -0
  841. package/plugins/codex/.codex-plugin/plugin.json +27 -0
  842. package/plugins/codex/.mcp.json +7 -0
  843. package/plugins/codex/AGENTS.md +135 -0
  844. package/plugins/codex/LICENSE +115 -0
  845. package/plugins/codex/README.md +17 -0
  846. package/plugins/codex/THIRD_PARTY_NOTICES.md +75 -0
  847. package/plugins/codex/hooks/brief.md +135 -0
  848. package/plugins/codex/hooks/codex-critic.mjs +15 -0
  849. package/plugins/codex/hooks/critic-receipts.mjs +86 -0
  850. package/plugins/codex/hooks/durable.mjs +56 -0
  851. package/plugins/codex/hooks/fence.mjs +30 -0
  852. package/plugins/codex/hooks/floors.mjs +181 -0
  853. package/plugins/codex/hooks/flow.mjs +154 -0
  854. package/plugins/codex/hooks/front-door.mjs +68 -0
  855. package/plugins/codex/hooks/guidance.json +3 -0
  856. package/plugins/codex/hooks/hints.mjs +183 -0
  857. package/plugins/codex/hooks/hooks.json +59 -0
  858. package/plugins/codex/hooks/host.md +54 -0
  859. package/plugins/codex/hooks/lib.mjs +362 -0
  860. package/plugins/codex/hooks/memory.mjs +92 -0
  861. package/plugins/codex/hooks/mobile-qa.mjs +43 -0
  862. package/plugins/codex/hooks/note.mjs +63 -0
  863. package/plugins/codex/hooks/nudge.mjs +98 -0
  864. package/plugins/codex/hooks/pipeline.mjs +207 -0
  865. package/plugins/codex/hooks/prompt.mjs +51 -0
  866. package/plugins/codex/hooks/quality.mjs +310 -0
  867. package/plugins/codex/hooks/reach.mjs +93 -0
  868. package/plugins/codex/hooks/scope.mjs +44 -0
  869. package/plugins/codex/hooks/session-log.mjs +101 -0
  870. package/plugins/codex/hooks/session-start.mjs +194 -0
  871. package/plugins/codex/hooks/stop-gate.mjs +303 -0
  872. package/plugins/codex/hooks/vendor/direct/round.mjs +81 -0
  873. package/plugins/codex/hooks/vendor/find/names.mjs +46 -0
  874. package/plugins/codex/hooks/vendor/firstlook/set.mjs +219 -0
  875. package/plugins/codex/hooks/vendor/flow/flow.mjs +456 -0
  876. package/plugins/codex/hooks/vendor/flow/look.mjs +140 -0
  877. package/plugins/codex/hooks/vendor/gdd/book.mjs +484 -0
  878. package/plugins/codex/hooks/vendor/gdd/chapters.mjs +72 -0
  879. package/plugins/codex/hooks/vendor/gdd/doc.mjs +33 -0
  880. package/plugins/codex/hooks/vendor/gdd/levelmap.mjs +429 -0
  881. package/plugins/codex/hooks/vendor/gdd/rubric.mjs +251 -0
  882. package/plugins/codex/hooks/vendor/gdd/worth.mjs +508 -0
  883. package/plugins/codex/hooks/vendor/lanes/fence.mjs +109 -0
  884. package/plugins/codex/hooks/vendor/lanes/lanes.mjs +356 -0
  885. package/plugins/codex/hooks/vendor/lanes/union.mjs +63 -0
  886. package/plugins/codex/hooks/vendor/lessons/motifs.mjs +98 -0
  887. package/plugins/codex/hooks/vendor/lessons/store.mjs +57 -0
  888. package/plugins/codex/hooks/vendor/look/made-of.mjs +243 -0
  889. package/plugins/codex/hooks/vendor/look/roles.mjs +110 -0
  890. package/plugins/codex/hooks/vendor/memory/decisions.mjs +139 -0
  891. package/plugins/codex/hooks/vendor/memory/journal.mjs +109 -0
  892. package/plugins/codex/hooks/vendor/owner/bar.mjs +286 -0
  893. package/plugins/codex/hooks/vendor/pipeline/pipeline.mjs +930 -0
  894. package/plugins/codex/hooks/vendor/playtest/keep.mjs +111 -0
  895. package/plugins/codex/hooks/vendor/playtest/stuck.mjs +48 -0
  896. package/plugins/codex/hooks/vendor/progress/holds.mjs +107 -0
  897. package/plugins/codex/hooks/vendor/progress/progress.mjs +301 -0
  898. package/plugins/codex/hooks/vendor/sim/judge.mjs +241 -0
  899. package/plugins/codex/hooks/vendor/spec/rooms.mjs +189 -0
  900. package/plugins/codex/hooks/vendor/spec/tunables.mjs +75 -0
  901. package/plugins/codex/hooks/vendor/stage/harnessignore.mjs +91 -0
  902. package/plugins/codex/hooks/vendor/stage/stage.mjs +58 -0
  903. package/plugins/codex/hooks/vendor/status/board.mjs +173 -0
  904. package/plugins/codex/hooks/vendor/status/file.mjs +113 -0
  905. package/plugins/codex/hooks/vendor/studio/forks.mjs +94 -0
  906. package/plugins/codex/hooks/vendor/studio/pitch.mjs +295 -0
  907. package/plugins/codex/hooks/vendor/verify/fingerprint.mjs +73 -0
  908. package/plugins/codex/hooks/vendor/verify/reads.mjs +33 -0
  909. package/plugins/codex/hooks/vendor/wow/picks.mjs +75 -0
  910. package/plugins/codex/mcp.json +9 -0
  911. package/plugins/codex/plugin.json +26 -0
  912. package/plugins/codex/skills/fp-art-director/SKILL.md +58 -0
  913. package/plugins/codex/skills/fp-art-director/agents/openai.yaml +12 -0
  914. package/plugins/codex/skills/fp-art-director/references/codex.md +54 -0
  915. package/plugins/codex/skills/fp-audio-director/SKILL.md +55 -0
  916. package/plugins/codex/skills/fp-audio-director/agents/openai.yaml +12 -0
  917. package/plugins/codex/skills/fp-audio-director/references/codex.md +54 -0
  918. package/plugins/codex/skills/fp-critic/SKILL.md +117 -0
  919. package/plugins/codex/skills/fp-critic/agents/openai.yaml +12 -0
  920. package/plugins/codex/skills/fp-critic/references/codex.md +54 -0
  921. package/plugins/codex/skills/fp-first-look/SKILL.md +59 -0
  922. package/plugins/codex/skills/fp-first-look/agents/openai.yaml +12 -0
  923. package/plugins/codex/skills/fp-flow/SKILL.md +50 -0
  924. package/plugins/codex/skills/fp-flow/agents/openai.yaml +12 -0
  925. package/plugins/codex/skills/fp-lane/SKILL.md +41 -0
  926. package/plugins/codex/skills/fp-lane/agents/openai.yaml +12 -0
  927. package/plugins/codex/skills/fp-lane/references/codex.md +54 -0
  928. package/plugins/codex/skills/fp-lanes/SKILL.md +38 -0
  929. package/plugins/codex/skills/fp-lanes/agents/openai.yaml +12 -0
  930. package/plugins/codex/skills/fp-level-designer/SKILL.md +49 -0
  931. package/plugins/codex/skills/fp-level-designer/agents/openai.yaml +12 -0
  932. package/plugins/codex/skills/fp-level-designer/references/codex.md +54 -0
  933. package/plugins/codex/skills/fp-mobile-qa/SKILL.md +28 -0
  934. package/plugins/codex/skills/fp-mobile-qa/agents/openai.yaml +12 -0
  935. package/plugins/codex/skills/fp-mobile-qa-seat/SKILL.md +74 -0
  936. package/plugins/codex/skills/fp-mobile-qa-seat/agents/openai.yaml +12 -0
  937. package/plugins/codex/skills/fp-mobile-qa-seat/references/codex.md +54 -0
  938. package/plugins/codex/skills/fp-new/SKILL.md +94 -0
  939. package/plugins/codex/skills/fp-new/agents/openai.yaml +12 -0
  940. package/plugins/codex/skills/fp-player/SKILL.md +147 -0
  941. package/plugins/codex/skills/fp-player/agents/openai.yaml +12 -0
  942. package/plugins/codex/skills/fp-player/references/codex.md +54 -0
  943. package/plugins/codex/skills/fp-playtest/SKILL.md +66 -0
  944. package/plugins/codex/skills/fp-playtest/agents/openai.yaml +12 -0
  945. package/plugins/codex/skills/fp-publish/SKILL.md +23 -0
  946. package/plugins/codex/skills/fp-publish/agents/openai.yaml +12 -0
  947. package/plugins/codex/skills/fp-qa-lead/SKILL.md +56 -0
  948. package/plugins/codex/skills/fp-qa-lead/agents/openai.yaml +12 -0
  949. package/plugins/codex/skills/fp-qa-lead/references/codex.md +54 -0
  950. package/plugins/codex/skills/fp-smoke-build/SKILL.md +25 -0
  951. package/plugins/codex/skills/fp-smoke-build/agents/openai.yaml +12 -0
  952. package/plugins/codex/skills/fp-studio/SKILL.md +59 -0
  953. package/plugins/codex/skills/fp-studio/agents/openai.yaml +12 -0
  954. package/plugins/codex/skills/fp-verify/SKILL.md +20 -0
  955. package/plugins/codex/skills/fp-verify/agents/openai.yaml +12 -0
  956. package/plugins/codex/skills/funpixel-3d/SKILL.md +89 -0
  957. package/plugins/codex/skills/funpixel-3d/agents/openai.yaml +12 -0
  958. package/plugins/codex/skills/funpixel-3d/references/bake-off.md +48 -0
  959. package/plugins/codex/skills/funpixel-3d/references/bench.md +103 -0
  960. package/plugins/codex/skills/funpixel-3d/references/budgets.md +48 -0
  961. package/plugins/codex/skills/funpixel-3d/references/characters.md +67 -0
  962. package/plugins/codex/skills/funpixel-3d/references/concept-image.md +47 -0
  963. package/plugins/codex/skills/funpixel-3d/references/engine-targets.md +31 -0
  964. package/plugins/codex/skills/funpixel-3d/references/hero-route.md +104 -0
  965. package/plugins/codex/skills/funpixel-3d/references/level-spec.md +109 -0
  966. package/plugins/codex/skills/funpixel-3d/references/levels.md +84 -0
  967. package/plugins/codex/skills/funpixel-3d/references/light-and-places.md +141 -0
  968. package/plugins/codex/skills/funpixel-3d/references/models.md +111 -0
  969. package/plugins/codex/skills/funpixel-3d/references/painted-target.md +184 -0
  970. package/plugins/codex/skills/funpixel-3d/references/reading.md +41 -0
  971. package/plugins/codex/skills/funpixel-3d/references/skin.md +85 -0
  972. package/plugins/codex/skills/funpixel-3d/references/skyboxes.md +65 -0
  973. package/plugins/codex/skills/funpixel-3d/references/textures.md +71 -0
  974. package/plugins/codex/skills/funpixel-3d/references/three-loading.md +199 -0
  975. package/plugins/codex/skills/funpixel-3d/references/unity.md +78 -0
  976. package/plugins/codex/skills/funpixel-art/SKILL.md +104 -0
  977. package/plugins/codex/skills/funpixel-art/agents/openai.yaml +12 -0
  978. package/plugins/codex/skills/funpixel-art/references/2d-assets.md +108 -0
  979. package/plugins/codex/skills/funpixel-art/references/animation.md +126 -0
  980. package/plugins/codex/skills/funpixel-art/references/cast.md +73 -0
  981. package/plugins/codex/skills/funpixel-art/references/characters.md +49 -0
  982. package/plugins/codex/skills/funpixel-art/references/cost.md +107 -0
  983. package/plugins/codex/skills/funpixel-art/references/effects.md +85 -0
  984. package/plugins/codex/skills/funpixel-art/references/frames.md +87 -0
  985. package/plugins/codex/skills/funpixel-art/references/judging-frames.md +64 -0
  986. package/plugins/codex/skills/funpixel-art/references/look.md +102 -0
  987. package/plugins/codex/skills/funpixel-art/references/measure.md +119 -0
  988. package/plugins/codex/skills/funpixel-art/references/pipeline.md +185 -0
  989. package/plugins/codex/skills/funpixel-art/references/pixi.md +277 -0
  990. package/plugins/codex/skills/funpixel-art/references/planes.md +27 -0
  991. package/plugins/codex/skills/funpixel-art/references/prompts.md +171 -0
  992. package/plugins/codex/skills/funpixel-art/references/sheets.md +141 -0
  993. package/plugins/codex/skills/funpixel-art/references/style-file.md +39 -0
  994. package/plugins/codex/skills/funpixel-art/references/three.md +232 -0
  995. package/plugins/codex/skills/funpixel-art/references/ui.md +163 -0
  996. package/plugins/codex/skills/funpixel-art/references/unity.md +78 -0
  997. package/plugins/codex/skills/funpixel-art/references/wiring.md +41 -0
  998. package/plugins/codex/skills/funpixel-audio/SKILL.md +92 -0
  999. package/plugins/codex/skills/funpixel-audio/agents/openai.yaml +12 -0
  1000. package/plugins/codex/skills/funpixel-audio/references/adaptive-music.md +204 -0
  1001. package/plugins/codex/skills/funpixel-audio/references/engine.md +78 -0
  1002. package/plugins/codex/skills/funpixel-audio/references/measure.md +101 -0
  1003. package/plugins/codex/skills/funpixel-audio/references/unity.md +74 -0
  1004. package/plugins/codex/skills/funpixel-feedback/SKILL.md +120 -0
  1005. package/plugins/codex/skills/funpixel-feedback/agents/openai.yaml +12 -0
  1006. package/plugins/codex/skills/funpixel-feedback/references/memory.md +99 -0
  1007. package/plugins/codex/skills/funpixel-game-feel/SKILL.md +104 -0
  1008. package/plugins/codex/skills/funpixel-game-feel/agents/openai.yaml +12 -0
  1009. package/plugins/codex/skills/funpixel-game-feel/references/contact.md +110 -0
  1010. package/plugins/codex/skills/funpixel-game-feel/references/measure.md +125 -0
  1011. package/plugins/codex/skills/funpixel-game-feel/references/motion.md +134 -0
  1012. package/plugins/codex/skills/funpixel-game-feel/references/payoffs.md +35 -0
  1013. package/plugins/codex/skills/funpixel-game-feel/references/recipes.md +107 -0
  1014. package/plugins/codex/skills/funpixel-game-feel/references/unity.md +73 -0
  1015. package/plugins/codex/skills/funpixel-game-logic/SKILL.md +113 -0
  1016. package/plugins/codex/skills/funpixel-game-logic/agents/openai.yaml +12 -0
  1017. package/plugins/codex/skills/funpixel-game-logic/references/balance.md +88 -0
  1018. package/plugins/codex/skills/funpixel-game-logic/references/content-at-scale.md +147 -0
  1019. package/plugins/codex/skills/funpixel-game-logic/references/depth.md +89 -0
  1020. package/plugins/codex/skills/funpixel-game-logic/references/escalation.md +41 -0
  1021. package/plugins/codex/skills/funpixel-game-logic/references/levels.md +61 -0
  1022. package/plugins/codex/skills/funpixel-game-logic/references/probes.md +122 -0
  1023. package/plugins/codex/skills/funpixel-game-logic/references/unity.md +108 -0
  1024. package/plugins/codex/skills/funpixel-game-spine/SKILL.md +118 -0
  1025. package/plugins/codex/skills/funpixel-game-spine/agents/openai.yaml +12 -0
  1026. package/plugins/codex/skills/funpixel-game-spine/references/camera.md +94 -0
  1027. package/plugins/codex/skills/funpixel-game-spine/references/multiplayer.md +101 -0
  1028. package/plugins/codex/skills/funpixel-game-spine/references/patterns.md +103 -0
  1029. package/plugins/codex/skills/funpixel-game-spine/references/performance.md +96 -0
  1030. package/plugins/codex/skills/funpixel-game-spine/references/pixi.md +26 -0
  1031. package/plugins/codex/skills/funpixel-game-spine/references/replay.md +102 -0
  1032. package/plugins/codex/skills/funpixel-game-spine/references/room-api.md +63 -0
  1033. package/plugins/codex/skills/funpixel-game-spine/references/room-modes.md +40 -0
  1034. package/plugins/codex/skills/funpixel-game-spine/references/sdk.md +114 -0
  1035. package/plugins/codex/skills/funpixel-game-spine/references/three.md +62 -0
  1036. package/plugins/codex/skills/funpixel-gdd/SKILL.md +116 -0
  1037. package/plugins/codex/skills/funpixel-gdd/agents/openai.yaml +12 -0
  1038. package/plugins/codex/skills/funpixel-gdd/references/as-built.md +40 -0
  1039. package/plugins/codex/skills/funpixel-gdd/references/design-measures.md +24 -0
  1040. package/plugins/codex/skills/funpixel-gdd/references/design-note.md +88 -0
  1041. package/plugins/codex/skills/funpixel-gdd/references/experience.md +92 -0
  1042. package/plugins/codex/skills/funpixel-gdd/references/first-look.md +226 -0
  1043. package/plugins/codex/skills/funpixel-gdd/references/floors.md +62 -0
  1044. package/plugins/codex/skills/funpixel-gdd/references/frame.md +75 -0
  1045. package/plugins/codex/skills/funpixel-gdd/references/gameplay-contract.md +81 -0
  1046. package/plugins/codex/skills/funpixel-gdd/references/gdd-template.md +417 -0
  1047. package/plugins/codex/skills/funpixel-gdd/references/genre-card.md +109 -0
  1048. package/plugins/codex/skills/funpixel-gdd/references/genre-platformer.md +159 -0
  1049. package/plugins/codex/skills/funpixel-gdd/references/genre-puzzle.md +145 -0
  1050. package/plugins/codex/skills/funpixel-gdd/references/genre-racing.md +137 -0
  1051. package/plugins/codex/skills/funpixel-gdd/references/genre-rpg.md +125 -0
  1052. package/plugins/codex/skills/funpixel-gdd/references/genre-shooter.md +128 -0
  1053. package/plugins/codex/skills/funpixel-gdd/references/genre-simulation.md +112 -0
  1054. package/plugins/codex/skills/funpixel-gdd/references/genre-strategy.md +116 -0
  1055. package/plugins/codex/skills/funpixel-gdd/references/genre-survival.md +122 -0
  1056. package/plugins/codex/skills/funpixel-gdd/references/in-the-loop.md +106 -0
  1057. package/plugins/codex/skills/funpixel-gdd/references/invent-first.md +131 -0
  1058. package/plugins/codex/skills/funpixel-gdd/references/level-and-fun.md +112 -0
  1059. package/plugins/codex/skills/funpixel-gdd/references/pages.md +47 -0
  1060. package/plugins/codex/skills/funpixel-gdd/references/plan-at-size.md +140 -0
  1061. package/plugins/codex/skills/funpixel-gdd/references/production-tiers.md +117 -0
  1062. package/plugins/codex/skills/funpixel-gdd/references/sections.md +148 -0
  1063. package/plugins/codex/skills/funpixel-gdd/references/spec-folder.md +131 -0
  1064. package/plugins/codex/skills/funpixel-gdd/references/start.md +110 -0
  1065. package/plugins/codex/skills/funpixel-gdd/references/starters.md +175 -0
  1066. package/plugins/codex/skills/funpixel-gdd/references/the-path.md +133 -0
  1067. package/plugins/codex/skills/funpixel-gdd/references/track.md +29 -0
  1068. package/plugins/codex/skills/funpixel-gdd/references/world-and-identity.md +165 -0
  1069. package/plugins/codex/skills/funpixel-gdd/references/worth.md +74 -0
  1070. package/plugins/codex/skills/funpixel-mobile-ui/SKILL.md +107 -0
  1071. package/plugins/codex/skills/funpixel-mobile-ui/agents/openai.yaml +12 -0
  1072. package/plugins/codex/skills/funpixel-mobile-ui/references/contrast.md +123 -0
  1073. package/plugins/codex/skills/funpixel-mobile-ui/references/hud-and-title.md +108 -0
  1074. package/plugins/codex/skills/funpixel-mobile-ui/references/hud-genres.md +124 -0
  1075. package/plugins/codex/skills/funpixel-mobile-ui/references/phone-check.md +156 -0
  1076. package/plugins/codex/skills/funpixel-mobile-ui/references/recipes.md +279 -0
  1077. package/plugins/codex/skills/funpixel-mobile-ui/references/restyle-ui.md +229 -0
  1078. package/plugins/codex/skills/funpixel-mobile-ui/references/unity.md +61 -0
  1079. package/plugins/codex/skills/funpixel-publish/SKILL.md +109 -0
  1080. package/plugins/codex/skills/funpixel-publish/agents/openai.yaml +12 -0
  1081. package/plugins/codex/skills/funpixel-publish/references/compose.md +113 -0
  1082. package/plugins/codex/skills/funpixel-publish/references/motion.md +120 -0
  1083. package/plugins/codex/skills/funpixel-publish/references/networks.md +75 -0
  1084. package/plugins/codex/skills/funpixel-publish/references/other-hosts.md +65 -0
  1085. package/plugins/codex/skills/funpixel-publish/references/playable-ad.md +90 -0
  1086. package/plugins/codex/skills/funpixel-publish/references/server-build.md +85 -0
  1087. package/plugins/codex/skills/funpixel-publish/references/store-shots.md +85 -0
  1088. package/plugins/codex/skills/funpixel-publish/references/trailer.md +55 -0
  1089. package/plugins/codex/skills/funpixel-publish/references/what-ships.md +30 -0
  1090. package/plugins/codex/skills/funpixel-store/SKILL.md +81 -0
  1091. package/plugins/codex/skills/funpixel-store/agents/openai.yaml +12 -0
  1092. package/plugins/codex/skills/funpixel-store/references/app-store.md +73 -0
  1093. package/plugins/codex/skills/funpixel-store/references/google-play.md +141 -0
  1094. package/plugins/codex/skills/funpixel-store/references/ios-release.md +63 -0
  1095. package/plugins/codex/skills/funpixel-store/references/money.md +66 -0
  1096. package/plugins/codex/skills/funpixel-store/references/purchases-and-review.md +74 -0
  1097. package/plugins/codex/skills/funpixel-store/references/readiness-page.md +24 -0
  1098. package/plugins/codex/skills/funpixel-store/references/readiness.md +107 -0
  1099. package/plugins/codex/skills/funpixel-store/references/steam.md +38 -0
  1100. package/plugins/codex/skills/funpixel-store/references/unity-store.md +55 -0
  1101. package/plugins/codex/skills/funpixel-store/references/web-portals.md +43 -0
  1102. package/plugins/codex/skills/funpixel-unity-game/SKILL.md +103 -0
  1103. package/plugins/codex/skills/funpixel-unity-game/agents/openai.yaml +12 -0
  1104. package/plugins/codex/skills/funpixel-unity-game/references/agent-ops.md +54 -0
  1105. package/plugins/codex/skills/funpixel-unity-game/references/fixes.md +40 -0
  1106. package/plugins/codex/skills/funpixel-unity-game/references/from-a-web-game.md +108 -0
  1107. package/plugins/codex/skills/funpixel-unity-game/references/handing-off.md +42 -0
  1108. package/plugins/codex/skills/funpixel-unity-game/references/performance.md +59 -0
  1109. package/plugins/codex/skills/funpixel-unity-game/references/probe.md +80 -0
  1110. package/plugins/codex/skills/funpixel-unity-game/references/shared-mac.md +121 -0
  1111. package/plugins/codex/skills/funpixel-unity-game/references/traps.md +108 -0
  1112. package/plugins/codex/skills/funpixel-verify/SKILL.md +109 -0
  1113. package/plugins/codex/skills/funpixel-verify/agents/openai.yaml +12 -0
  1114. package/plugins/codex/skills/funpixel-verify/references/actors.md +94 -0
  1115. package/plugins/codex/skills/funpixel-verify/references/bar.md +62 -0
  1116. package/plugins/codex/skills/funpixel-verify/references/checks.md +69 -0
  1117. package/plugins/codex/skills/funpixel-verify/references/experience.md +67 -0
  1118. package/plugins/codex/skills/funpixel-verify/references/eyes.md +54 -0
  1119. package/plugins/codex/skills/funpixel-verify/references/fidelity.md +126 -0
  1120. package/plugins/codex/skills/funpixel-verify/references/hit-bar.md +31 -0
  1121. package/plugins/codex/skills/funpixel-verify/references/journeys.md +77 -0
  1122. package/plugins/codex/skills/funpixel-verify/references/mobile-qa.md +123 -0
  1123. package/plugins/codex/skills/funpixel-verify/references/playtest.md +161 -0
  1124. package/plugins/codex/skills/funpixel-verify/references/review.md +105 -0
  1125. package/plugins/codex/skills/funpixel-verify/references/rubric.md +67 -0
  1126. package/plugins/codex/skills/funpixel-verify/references/scenes.md +49 -0
  1127. package/plugins/codex/skills/funpixel-verify/references/unity.md +60 -0
  1128. package/plugins/codex/skills/funpixel-world-and-story/SKILL.md +99 -0
  1129. package/plugins/codex/skills/funpixel-world-and-story/agents/openai.yaml +12 -0
  1130. package/plugins/codex/skills/funpixel-world-and-story/references/atmosphere.md +208 -0
  1131. package/plugins/codex/skills/funpixel-world-and-story/references/forged-world.md +79 -0
  1132. package/plugins/codex/skills/funpixel-world-and-story/references/living-world.md +237 -0
  1133. package/plugins/codex/skills/funpixel-world-and-story/references/opening-and-chapters.md +215 -0
  1134. package/plugins/codex/skills/funpixel-world-and-story/references/shelf.md +80 -0
  1135. package/plugins/codex/skills/funpixel-world-and-story/references/story-at-size.md +159 -0
  1136. package/plugins/codex/skills/funpixel-world-and-story/references/voice.md +175 -0
  1137. package/plugins/codex/skills/funpixel-world-and-story/references/world-kit.md +154 -0
  1138. package/plugins/cursor/.cursor-plugin/plugin.json +26 -0
  1139. package/plugins/cursor/LICENSE +115 -0
  1140. package/plugins/cursor/README.md +13 -0
  1141. package/plugins/cursor/THIRD_PARTY_NOTICES.md +75 -0
  1142. package/plugins/cursor/agents/art-director.md +54 -0
  1143. package/plugins/cursor/agents/audio-director.md +51 -0
  1144. package/plugins/cursor/agents/critic.md +113 -0
  1145. package/plugins/cursor/agents/lane.md +37 -0
  1146. package/plugins/cursor/agents/level-designer.md +45 -0
  1147. package/plugins/cursor/agents/mobile-qa.md +70 -0
  1148. package/plugins/cursor/agents/player.md +143 -0
  1149. package/plugins/cursor/agents/qa-lead.md +52 -0
  1150. package/plugins/cursor/commands/first-look.md +59 -0
  1151. package/plugins/cursor/commands/flow.md +50 -0
  1152. package/plugins/cursor/commands/lanes.md +38 -0
  1153. package/plugins/cursor/commands/mobile-qa.md +28 -0
  1154. package/plugins/cursor/commands/new.md +94 -0
  1155. package/plugins/cursor/commands/playtest.md +66 -0
  1156. package/plugins/cursor/commands/publish.md +23 -0
  1157. package/plugins/cursor/commands/smoke-build.md +25 -0
  1158. package/plugins/cursor/commands/verify.md +20 -0
  1159. package/plugins/cursor/hooks/brief.md +135 -0
  1160. package/plugins/cursor/hooks/critic-receipts.mjs +86 -0
  1161. package/plugins/cursor/hooks/durable.mjs +56 -0
  1162. package/plugins/cursor/hooks/fence.mjs +30 -0
  1163. package/plugins/cursor/hooks/floors.mjs +181 -0
  1164. package/plugins/cursor/hooks/flow.mjs +154 -0
  1165. package/plugins/cursor/hooks/front-door.mjs +68 -0
  1166. package/plugins/cursor/hooks/guidance.json +3 -0
  1167. package/plugins/cursor/hooks/hints.mjs +183 -0
  1168. package/plugins/cursor/hooks/hooks.json +26 -0
  1169. package/plugins/cursor/hooks/lib.mjs +362 -0
  1170. package/plugins/cursor/hooks/memory.mjs +92 -0
  1171. package/plugins/cursor/hooks/mobile-qa.mjs +43 -0
  1172. package/plugins/cursor/hooks/note.mjs +63 -0
  1173. package/plugins/cursor/hooks/nudge.mjs +98 -0
  1174. package/plugins/cursor/hooks/pipeline.mjs +207 -0
  1175. package/plugins/cursor/hooks/prompt.mjs +51 -0
  1176. package/plugins/cursor/hooks/quality.mjs +310 -0
  1177. package/plugins/cursor/hooks/reach.mjs +93 -0
  1178. package/plugins/cursor/hooks/scope.mjs +44 -0
  1179. package/plugins/cursor/hooks/session-log.mjs +101 -0
  1180. package/plugins/cursor/hooks/session-start.mjs +194 -0
  1181. package/plugins/cursor/hooks/stop-gate.mjs +303 -0
  1182. package/plugins/cursor/hooks/vendor/direct/round.mjs +81 -0
  1183. package/plugins/cursor/hooks/vendor/find/names.mjs +46 -0
  1184. package/plugins/cursor/hooks/vendor/firstlook/set.mjs +219 -0
  1185. package/plugins/cursor/hooks/vendor/flow/flow.mjs +456 -0
  1186. package/plugins/cursor/hooks/vendor/flow/look.mjs +140 -0
  1187. package/plugins/cursor/hooks/vendor/gdd/book.mjs +484 -0
  1188. package/plugins/cursor/hooks/vendor/gdd/chapters.mjs +72 -0
  1189. package/plugins/cursor/hooks/vendor/gdd/doc.mjs +33 -0
  1190. package/plugins/cursor/hooks/vendor/gdd/levelmap.mjs +429 -0
  1191. package/plugins/cursor/hooks/vendor/gdd/rubric.mjs +251 -0
  1192. package/plugins/cursor/hooks/vendor/gdd/worth.mjs +508 -0
  1193. package/plugins/cursor/hooks/vendor/lanes/fence.mjs +109 -0
  1194. package/plugins/cursor/hooks/vendor/lanes/lanes.mjs +356 -0
  1195. package/plugins/cursor/hooks/vendor/lanes/union.mjs +63 -0
  1196. package/plugins/cursor/hooks/vendor/lessons/motifs.mjs +98 -0
  1197. package/plugins/cursor/hooks/vendor/lessons/store.mjs +57 -0
  1198. package/plugins/cursor/hooks/vendor/look/made-of.mjs +243 -0
  1199. package/plugins/cursor/hooks/vendor/look/roles.mjs +110 -0
  1200. package/plugins/cursor/hooks/vendor/memory/decisions.mjs +139 -0
  1201. package/plugins/cursor/hooks/vendor/memory/journal.mjs +109 -0
  1202. package/plugins/cursor/hooks/vendor/owner/bar.mjs +286 -0
  1203. package/plugins/cursor/hooks/vendor/pipeline/pipeline.mjs +930 -0
  1204. package/plugins/cursor/hooks/vendor/playtest/keep.mjs +111 -0
  1205. package/plugins/cursor/hooks/vendor/playtest/stuck.mjs +48 -0
  1206. package/plugins/cursor/hooks/vendor/progress/holds.mjs +107 -0
  1207. package/plugins/cursor/hooks/vendor/progress/progress.mjs +301 -0
  1208. package/plugins/cursor/hooks/vendor/sim/judge.mjs +241 -0
  1209. package/plugins/cursor/hooks/vendor/spec/rooms.mjs +189 -0
  1210. package/plugins/cursor/hooks/vendor/spec/tunables.mjs +75 -0
  1211. package/plugins/cursor/hooks/vendor/stage/harnessignore.mjs +91 -0
  1212. package/plugins/cursor/hooks/vendor/stage/stage.mjs +58 -0
  1213. package/plugins/cursor/hooks/vendor/status/board.mjs +173 -0
  1214. package/plugins/cursor/hooks/vendor/status/file.mjs +113 -0
  1215. package/plugins/cursor/hooks/vendor/studio/forks.mjs +94 -0
  1216. package/plugins/cursor/hooks/vendor/studio/pitch.mjs +295 -0
  1217. package/plugins/cursor/hooks/vendor/verify/fingerprint.mjs +73 -0
  1218. package/plugins/cursor/hooks/vendor/verify/reads.mjs +33 -0
  1219. package/plugins/cursor/hooks/vendor/wow/picks.mjs +75 -0
  1220. package/plugins/cursor/mcp.json +10 -0
  1221. package/plugins/cursor/rules/funpixel-brief.mdc +141 -0
  1222. package/plugins/cursor/skills/funpixel-3d/SKILL.md +89 -0
  1223. package/plugins/cursor/skills/funpixel-3d/references/bake-off.md +48 -0
  1224. package/plugins/cursor/skills/funpixel-3d/references/bench.md +103 -0
  1225. package/plugins/cursor/skills/funpixel-3d/references/budgets.md +48 -0
  1226. package/plugins/cursor/skills/funpixel-3d/references/characters.md +67 -0
  1227. package/plugins/cursor/skills/funpixel-3d/references/concept-image.md +47 -0
  1228. package/plugins/cursor/skills/funpixel-3d/references/engine-targets.md +31 -0
  1229. package/plugins/cursor/skills/funpixel-3d/references/hero-route.md +104 -0
  1230. package/plugins/cursor/skills/funpixel-3d/references/level-spec.md +109 -0
  1231. package/plugins/cursor/skills/funpixel-3d/references/levels.md +84 -0
  1232. package/plugins/cursor/skills/funpixel-3d/references/light-and-places.md +141 -0
  1233. package/plugins/cursor/skills/funpixel-3d/references/models.md +111 -0
  1234. package/plugins/cursor/skills/funpixel-3d/references/painted-target.md +184 -0
  1235. package/plugins/cursor/skills/funpixel-3d/references/reading.md +41 -0
  1236. package/plugins/cursor/skills/funpixel-3d/references/skin.md +85 -0
  1237. package/plugins/cursor/skills/funpixel-3d/references/skyboxes.md +65 -0
  1238. package/plugins/cursor/skills/funpixel-3d/references/textures.md +71 -0
  1239. package/plugins/cursor/skills/funpixel-3d/references/three-loading.md +199 -0
  1240. package/plugins/cursor/skills/funpixel-3d/references/unity.md +78 -0
  1241. package/plugins/cursor/skills/funpixel-art/SKILL.md +104 -0
  1242. package/plugins/cursor/skills/funpixel-art/references/2d-assets.md +108 -0
  1243. package/plugins/cursor/skills/funpixel-art/references/animation.md +126 -0
  1244. package/plugins/cursor/skills/funpixel-art/references/cast.md +73 -0
  1245. package/plugins/cursor/skills/funpixel-art/references/characters.md +49 -0
  1246. package/plugins/cursor/skills/funpixel-art/references/cost.md +107 -0
  1247. package/plugins/cursor/skills/funpixel-art/references/effects.md +85 -0
  1248. package/plugins/cursor/skills/funpixel-art/references/frames.md +87 -0
  1249. package/plugins/cursor/skills/funpixel-art/references/judging-frames.md +64 -0
  1250. package/plugins/cursor/skills/funpixel-art/references/look.md +102 -0
  1251. package/plugins/cursor/skills/funpixel-art/references/measure.md +119 -0
  1252. package/plugins/cursor/skills/funpixel-art/references/pipeline.md +185 -0
  1253. package/plugins/cursor/skills/funpixel-art/references/pixi.md +277 -0
  1254. package/plugins/cursor/skills/funpixel-art/references/planes.md +27 -0
  1255. package/plugins/cursor/skills/funpixel-art/references/prompts.md +171 -0
  1256. package/plugins/cursor/skills/funpixel-art/references/sheets.md +141 -0
  1257. package/plugins/cursor/skills/funpixel-art/references/style-file.md +39 -0
  1258. package/plugins/cursor/skills/funpixel-art/references/three.md +232 -0
  1259. package/plugins/cursor/skills/funpixel-art/references/ui.md +163 -0
  1260. package/plugins/cursor/skills/funpixel-art/references/unity.md +78 -0
  1261. package/plugins/cursor/skills/funpixel-art/references/wiring.md +41 -0
  1262. package/plugins/cursor/skills/funpixel-audio/SKILL.md +92 -0
  1263. package/plugins/cursor/skills/funpixel-audio/references/adaptive-music.md +204 -0
  1264. package/plugins/cursor/skills/funpixel-audio/references/engine.md +78 -0
  1265. package/plugins/cursor/skills/funpixel-audio/references/measure.md +101 -0
  1266. package/plugins/cursor/skills/funpixel-audio/references/unity.md +74 -0
  1267. package/plugins/cursor/skills/funpixel-feedback/SKILL.md +120 -0
  1268. package/plugins/cursor/skills/funpixel-feedback/references/memory.md +99 -0
  1269. package/plugins/cursor/skills/funpixel-game-feel/SKILL.md +104 -0
  1270. package/plugins/cursor/skills/funpixel-game-feel/references/contact.md +110 -0
  1271. package/plugins/cursor/skills/funpixel-game-feel/references/measure.md +125 -0
  1272. package/plugins/cursor/skills/funpixel-game-feel/references/motion.md +134 -0
  1273. package/plugins/cursor/skills/funpixel-game-feel/references/payoffs.md +35 -0
  1274. package/plugins/cursor/skills/funpixel-game-feel/references/recipes.md +107 -0
  1275. package/plugins/cursor/skills/funpixel-game-feel/references/unity.md +73 -0
  1276. package/plugins/cursor/skills/funpixel-game-logic/SKILL.md +113 -0
  1277. package/plugins/cursor/skills/funpixel-game-logic/references/balance.md +88 -0
  1278. package/plugins/cursor/skills/funpixel-game-logic/references/content-at-scale.md +147 -0
  1279. package/plugins/cursor/skills/funpixel-game-logic/references/depth.md +89 -0
  1280. package/plugins/cursor/skills/funpixel-game-logic/references/escalation.md +41 -0
  1281. package/plugins/cursor/skills/funpixel-game-logic/references/levels.md +61 -0
  1282. package/plugins/cursor/skills/funpixel-game-logic/references/probes.md +122 -0
  1283. package/plugins/cursor/skills/funpixel-game-logic/references/unity.md +108 -0
  1284. package/plugins/cursor/skills/funpixel-game-spine/SKILL.md +118 -0
  1285. package/plugins/cursor/skills/funpixel-game-spine/references/camera.md +94 -0
  1286. package/plugins/cursor/skills/funpixel-game-spine/references/multiplayer.md +101 -0
  1287. package/plugins/cursor/skills/funpixel-game-spine/references/patterns.md +103 -0
  1288. package/plugins/cursor/skills/funpixel-game-spine/references/performance.md +96 -0
  1289. package/plugins/cursor/skills/funpixel-game-spine/references/pixi.md +26 -0
  1290. package/plugins/cursor/skills/funpixel-game-spine/references/replay.md +102 -0
  1291. package/plugins/cursor/skills/funpixel-game-spine/references/room-api.md +63 -0
  1292. package/plugins/cursor/skills/funpixel-game-spine/references/room-modes.md +40 -0
  1293. package/plugins/cursor/skills/funpixel-game-spine/references/sdk.md +114 -0
  1294. package/plugins/cursor/skills/funpixel-game-spine/references/three.md +62 -0
  1295. package/plugins/cursor/skills/funpixel-gdd/SKILL.md +116 -0
  1296. package/plugins/cursor/skills/funpixel-gdd/references/as-built.md +40 -0
  1297. package/plugins/cursor/skills/funpixel-gdd/references/design-measures.md +24 -0
  1298. package/plugins/cursor/skills/funpixel-gdd/references/design-note.md +88 -0
  1299. package/plugins/cursor/skills/funpixel-gdd/references/experience.md +92 -0
  1300. package/plugins/cursor/skills/funpixel-gdd/references/first-look.md +226 -0
  1301. package/plugins/cursor/skills/funpixel-gdd/references/floors.md +62 -0
  1302. package/plugins/cursor/skills/funpixel-gdd/references/frame.md +75 -0
  1303. package/plugins/cursor/skills/funpixel-gdd/references/gameplay-contract.md +81 -0
  1304. package/plugins/cursor/skills/funpixel-gdd/references/gdd-template.md +417 -0
  1305. package/plugins/cursor/skills/funpixel-gdd/references/genre-card.md +109 -0
  1306. package/plugins/cursor/skills/funpixel-gdd/references/genre-platformer.md +159 -0
  1307. package/plugins/cursor/skills/funpixel-gdd/references/genre-puzzle.md +145 -0
  1308. package/plugins/cursor/skills/funpixel-gdd/references/genre-racing.md +137 -0
  1309. package/plugins/cursor/skills/funpixel-gdd/references/genre-rpg.md +125 -0
  1310. package/plugins/cursor/skills/funpixel-gdd/references/genre-shooter.md +128 -0
  1311. package/plugins/cursor/skills/funpixel-gdd/references/genre-simulation.md +112 -0
  1312. package/plugins/cursor/skills/funpixel-gdd/references/genre-strategy.md +116 -0
  1313. package/plugins/cursor/skills/funpixel-gdd/references/genre-survival.md +122 -0
  1314. package/plugins/cursor/skills/funpixel-gdd/references/in-the-loop.md +106 -0
  1315. package/plugins/cursor/skills/funpixel-gdd/references/invent-first.md +131 -0
  1316. package/plugins/cursor/skills/funpixel-gdd/references/level-and-fun.md +112 -0
  1317. package/plugins/cursor/skills/funpixel-gdd/references/pages.md +47 -0
  1318. package/plugins/cursor/skills/funpixel-gdd/references/plan-at-size.md +140 -0
  1319. package/plugins/cursor/skills/funpixel-gdd/references/production-tiers.md +117 -0
  1320. package/plugins/cursor/skills/funpixel-gdd/references/sections.md +148 -0
  1321. package/plugins/cursor/skills/funpixel-gdd/references/spec-folder.md +131 -0
  1322. package/plugins/cursor/skills/funpixel-gdd/references/start.md +110 -0
  1323. package/plugins/cursor/skills/funpixel-gdd/references/starters.md +175 -0
  1324. package/plugins/cursor/skills/funpixel-gdd/references/the-path.md +133 -0
  1325. package/plugins/cursor/skills/funpixel-gdd/references/track.md +29 -0
  1326. package/plugins/cursor/skills/funpixel-gdd/references/world-and-identity.md +165 -0
  1327. package/plugins/cursor/skills/funpixel-gdd/references/worth.md +74 -0
  1328. package/plugins/cursor/skills/funpixel-mobile-ui/SKILL.md +107 -0
  1329. package/plugins/cursor/skills/funpixel-mobile-ui/references/contrast.md +123 -0
  1330. package/plugins/cursor/skills/funpixel-mobile-ui/references/hud-and-title.md +108 -0
  1331. package/plugins/cursor/skills/funpixel-mobile-ui/references/hud-genres.md +124 -0
  1332. package/plugins/cursor/skills/funpixel-mobile-ui/references/phone-check.md +156 -0
  1333. package/plugins/cursor/skills/funpixel-mobile-ui/references/recipes.md +279 -0
  1334. package/plugins/cursor/skills/funpixel-mobile-ui/references/restyle-ui.md +229 -0
  1335. package/plugins/cursor/skills/funpixel-mobile-ui/references/unity.md +61 -0
  1336. package/plugins/cursor/skills/funpixel-publish/SKILL.md +109 -0
  1337. package/plugins/cursor/skills/funpixel-publish/references/compose.md +113 -0
  1338. package/plugins/cursor/skills/funpixel-publish/references/motion.md +120 -0
  1339. package/plugins/cursor/skills/funpixel-publish/references/networks.md +75 -0
  1340. package/plugins/cursor/skills/funpixel-publish/references/other-hosts.md +65 -0
  1341. package/plugins/cursor/skills/funpixel-publish/references/playable-ad.md +90 -0
  1342. package/plugins/cursor/skills/funpixel-publish/references/server-build.md +85 -0
  1343. package/plugins/cursor/skills/funpixel-publish/references/store-shots.md +85 -0
  1344. package/plugins/cursor/skills/funpixel-publish/references/trailer.md +55 -0
  1345. package/plugins/cursor/skills/funpixel-publish/references/what-ships.md +30 -0
  1346. package/plugins/cursor/skills/funpixel-store/SKILL.md +81 -0
  1347. package/plugins/cursor/skills/funpixel-store/references/app-store.md +73 -0
  1348. package/plugins/cursor/skills/funpixel-store/references/google-play.md +141 -0
  1349. package/plugins/cursor/skills/funpixel-store/references/ios-release.md +63 -0
  1350. package/plugins/cursor/skills/funpixel-store/references/money.md +66 -0
  1351. package/plugins/cursor/skills/funpixel-store/references/purchases-and-review.md +74 -0
  1352. package/plugins/cursor/skills/funpixel-store/references/readiness-page.md +24 -0
  1353. package/plugins/cursor/skills/funpixel-store/references/readiness.md +107 -0
  1354. package/plugins/cursor/skills/funpixel-store/references/steam.md +38 -0
  1355. package/plugins/cursor/skills/funpixel-store/references/unity-store.md +55 -0
  1356. package/plugins/cursor/skills/funpixel-store/references/web-portals.md +43 -0
  1357. package/plugins/cursor/skills/funpixel-unity-game/SKILL.md +103 -0
  1358. package/plugins/cursor/skills/funpixel-unity-game/references/agent-ops.md +54 -0
  1359. package/plugins/cursor/skills/funpixel-unity-game/references/fixes.md +40 -0
  1360. package/plugins/cursor/skills/funpixel-unity-game/references/from-a-web-game.md +108 -0
  1361. package/plugins/cursor/skills/funpixel-unity-game/references/handing-off.md +42 -0
  1362. package/plugins/cursor/skills/funpixel-unity-game/references/performance.md +59 -0
  1363. package/plugins/cursor/skills/funpixel-unity-game/references/probe.md +80 -0
  1364. package/plugins/cursor/skills/funpixel-unity-game/references/shared-mac.md +121 -0
  1365. package/plugins/cursor/skills/funpixel-unity-game/references/traps.md +108 -0
  1366. package/plugins/cursor/skills/funpixel-verify/SKILL.md +109 -0
  1367. package/plugins/cursor/skills/funpixel-verify/references/actors.md +94 -0
  1368. package/plugins/cursor/skills/funpixel-verify/references/bar.md +62 -0
  1369. package/plugins/cursor/skills/funpixel-verify/references/checks.md +69 -0
  1370. package/plugins/cursor/skills/funpixel-verify/references/experience.md +67 -0
  1371. package/plugins/cursor/skills/funpixel-verify/references/eyes.md +54 -0
  1372. package/plugins/cursor/skills/funpixel-verify/references/fidelity.md +126 -0
  1373. package/plugins/cursor/skills/funpixel-verify/references/hit-bar.md +31 -0
  1374. package/plugins/cursor/skills/funpixel-verify/references/journeys.md +77 -0
  1375. package/plugins/cursor/skills/funpixel-verify/references/mobile-qa.md +123 -0
  1376. package/plugins/cursor/skills/funpixel-verify/references/playtest.md +161 -0
  1377. package/plugins/cursor/skills/funpixel-verify/references/review.md +105 -0
  1378. package/plugins/cursor/skills/funpixel-verify/references/rubric.md +67 -0
  1379. package/plugins/cursor/skills/funpixel-verify/references/scenes.md +49 -0
  1380. package/plugins/cursor/skills/funpixel-verify/references/unity.md +60 -0
  1381. package/plugins/cursor/skills/funpixel-world-and-story/SKILL.md +99 -0
  1382. package/plugins/cursor/skills/funpixel-world-and-story/references/atmosphere.md +208 -0
  1383. package/plugins/cursor/skills/funpixel-world-and-story/references/forged-world.md +79 -0
  1384. package/plugins/cursor/skills/funpixel-world-and-story/references/living-world.md +237 -0
  1385. package/plugins/cursor/skills/funpixel-world-and-story/references/opening-and-chapters.md +215 -0
  1386. package/plugins/cursor/skills/funpixel-world-and-story/references/shelf.md +80 -0
  1387. package/plugins/cursor/skills/funpixel-world-and-story/references/story-at-size.md +159 -0
  1388. package/plugins/cursor/skills/funpixel-world-and-story/references/voice.md +175 -0
  1389. package/plugins/cursor/skills/funpixel-world-and-story/references/world-kit.md +154 -0
  1390. package/plugins/kiro/AGENTS.md +135 -0
  1391. package/plugins/kiro/LICENSE +115 -0
  1392. package/plugins/kiro/README.md +17 -0
  1393. package/plugins/kiro/THIRD_PARTY_NOTICES.md +75 -0
  1394. package/plugins/kiro/agent.template.json +45 -0
  1395. package/plugins/kiro/hooks/brief.md +135 -0
  1396. package/plugins/kiro/hooks/critic-receipts.mjs +86 -0
  1397. package/plugins/kiro/hooks/durable.mjs +56 -0
  1398. package/plugins/kiro/hooks/fence.mjs +30 -0
  1399. package/plugins/kiro/hooks/floors.mjs +181 -0
  1400. package/plugins/kiro/hooks/flow.mjs +154 -0
  1401. package/plugins/kiro/hooks/front-door.mjs +68 -0
  1402. package/plugins/kiro/hooks/guidance.json +3 -0
  1403. package/plugins/kiro/hooks/hints.mjs +183 -0
  1404. package/plugins/kiro/hooks/host.md +43 -0
  1405. package/plugins/kiro/hooks/kiro-prompt.mjs +26 -0
  1406. package/plugins/kiro/hooks/lib.mjs +362 -0
  1407. package/plugins/kiro/hooks/memory.mjs +92 -0
  1408. package/plugins/kiro/hooks/mobile-qa.mjs +43 -0
  1409. package/plugins/kiro/hooks/note.mjs +63 -0
  1410. package/plugins/kiro/hooks/nudge.mjs +98 -0
  1411. package/plugins/kiro/hooks/pipeline.mjs +207 -0
  1412. package/plugins/kiro/hooks/prompt.mjs +51 -0
  1413. package/plugins/kiro/hooks/quality.mjs +310 -0
  1414. package/plugins/kiro/hooks/reach.mjs +93 -0
  1415. package/plugins/kiro/hooks/scope.mjs +44 -0
  1416. package/plugins/kiro/hooks/session-log.mjs +101 -0
  1417. package/plugins/kiro/hooks/session-start.mjs +194 -0
  1418. package/plugins/kiro/hooks/stop-gate.mjs +303 -0
  1419. package/plugins/kiro/hooks/vendor/direct/round.mjs +81 -0
  1420. package/plugins/kiro/hooks/vendor/find/names.mjs +46 -0
  1421. package/plugins/kiro/hooks/vendor/firstlook/set.mjs +219 -0
  1422. package/plugins/kiro/hooks/vendor/flow/flow.mjs +456 -0
  1423. package/plugins/kiro/hooks/vendor/flow/look.mjs +140 -0
  1424. package/plugins/kiro/hooks/vendor/gdd/book.mjs +484 -0
  1425. package/plugins/kiro/hooks/vendor/gdd/chapters.mjs +72 -0
  1426. package/plugins/kiro/hooks/vendor/gdd/doc.mjs +33 -0
  1427. package/plugins/kiro/hooks/vendor/gdd/levelmap.mjs +429 -0
  1428. package/plugins/kiro/hooks/vendor/gdd/rubric.mjs +251 -0
  1429. package/plugins/kiro/hooks/vendor/gdd/worth.mjs +508 -0
  1430. package/plugins/kiro/hooks/vendor/lanes/fence.mjs +109 -0
  1431. package/plugins/kiro/hooks/vendor/lanes/lanes.mjs +356 -0
  1432. package/plugins/kiro/hooks/vendor/lanes/union.mjs +63 -0
  1433. package/plugins/kiro/hooks/vendor/lessons/motifs.mjs +98 -0
  1434. package/plugins/kiro/hooks/vendor/lessons/store.mjs +57 -0
  1435. package/plugins/kiro/hooks/vendor/look/made-of.mjs +243 -0
  1436. package/plugins/kiro/hooks/vendor/look/roles.mjs +110 -0
  1437. package/plugins/kiro/hooks/vendor/memory/decisions.mjs +139 -0
  1438. package/plugins/kiro/hooks/vendor/memory/journal.mjs +109 -0
  1439. package/plugins/kiro/hooks/vendor/owner/bar.mjs +286 -0
  1440. package/plugins/kiro/hooks/vendor/pipeline/pipeline.mjs +930 -0
  1441. package/plugins/kiro/hooks/vendor/playtest/keep.mjs +111 -0
  1442. package/plugins/kiro/hooks/vendor/playtest/stuck.mjs +48 -0
  1443. package/plugins/kiro/hooks/vendor/progress/holds.mjs +107 -0
  1444. package/plugins/kiro/hooks/vendor/progress/progress.mjs +301 -0
  1445. package/plugins/kiro/hooks/vendor/sim/judge.mjs +241 -0
  1446. package/plugins/kiro/hooks/vendor/spec/rooms.mjs +189 -0
  1447. package/plugins/kiro/hooks/vendor/spec/tunables.mjs +75 -0
  1448. package/plugins/kiro/hooks/vendor/stage/harnessignore.mjs +91 -0
  1449. package/plugins/kiro/hooks/vendor/stage/stage.mjs +58 -0
  1450. package/plugins/kiro/hooks/vendor/status/board.mjs +173 -0
  1451. package/plugins/kiro/hooks/vendor/status/file.mjs +113 -0
  1452. package/plugins/kiro/hooks/vendor/studio/forks.mjs +94 -0
  1453. package/plugins/kiro/hooks/vendor/studio/pitch.mjs +295 -0
  1454. package/plugins/kiro/hooks/vendor/verify/fingerprint.mjs +73 -0
  1455. package/plugins/kiro/hooks/vendor/verify/reads.mjs +33 -0
  1456. package/plugins/kiro/hooks/vendor/wow/picks.mjs +75 -0
  1457. package/plugins/kiro/install.mjs +37 -0
  1458. package/plugins/kiro/skills/fp-art-director/SKILL.md +58 -0
  1459. package/plugins/kiro/skills/fp-art-director/references/kiro.md +43 -0
  1460. package/plugins/kiro/skills/fp-audio-director/SKILL.md +55 -0
  1461. package/plugins/kiro/skills/fp-audio-director/references/kiro.md +43 -0
  1462. package/plugins/kiro/skills/fp-critic/SKILL.md +117 -0
  1463. package/plugins/kiro/skills/fp-critic/references/kiro.md +43 -0
  1464. package/plugins/kiro/skills/fp-first-look/SKILL.md +61 -0
  1465. package/plugins/kiro/skills/fp-flow/SKILL.md +52 -0
  1466. package/plugins/kiro/skills/fp-lane/SKILL.md +41 -0
  1467. package/plugins/kiro/skills/fp-lane/references/kiro.md +43 -0
  1468. package/plugins/kiro/skills/fp-lanes/SKILL.md +40 -0
  1469. package/plugins/kiro/skills/fp-level-designer/SKILL.md +49 -0
  1470. package/plugins/kiro/skills/fp-level-designer/references/kiro.md +43 -0
  1471. package/plugins/kiro/skills/fp-mobile-qa/SKILL.md +30 -0
  1472. package/plugins/kiro/skills/fp-mobile-qa-seat/SKILL.md +74 -0
  1473. package/plugins/kiro/skills/fp-mobile-qa-seat/references/kiro.md +43 -0
  1474. package/plugins/kiro/skills/fp-new/SKILL.md +96 -0
  1475. package/plugins/kiro/skills/fp-player/SKILL.md +147 -0
  1476. package/plugins/kiro/skills/fp-player/references/kiro.md +43 -0
  1477. package/plugins/kiro/skills/fp-playtest/SKILL.md +68 -0
  1478. package/plugins/kiro/skills/fp-publish/SKILL.md +25 -0
  1479. package/plugins/kiro/skills/fp-qa-lead/SKILL.md +56 -0
  1480. package/plugins/kiro/skills/fp-qa-lead/references/kiro.md +43 -0
  1481. package/plugins/kiro/skills/fp-smoke-build/SKILL.md +27 -0
  1482. package/plugins/kiro/skills/fp-studio/SKILL.md +48 -0
  1483. package/plugins/kiro/skills/fp-verify/SKILL.md +22 -0
  1484. package/plugins/kiro/skills/funpixel-3d/SKILL.md +89 -0
  1485. package/plugins/kiro/skills/funpixel-3d/references/bake-off.md +48 -0
  1486. package/plugins/kiro/skills/funpixel-3d/references/bench.md +103 -0
  1487. package/plugins/kiro/skills/funpixel-3d/references/budgets.md +48 -0
  1488. package/plugins/kiro/skills/funpixel-3d/references/characters.md +67 -0
  1489. package/plugins/kiro/skills/funpixel-3d/references/concept-image.md +47 -0
  1490. package/plugins/kiro/skills/funpixel-3d/references/engine-targets.md +31 -0
  1491. package/plugins/kiro/skills/funpixel-3d/references/hero-route.md +104 -0
  1492. package/plugins/kiro/skills/funpixel-3d/references/level-spec.md +109 -0
  1493. package/plugins/kiro/skills/funpixel-3d/references/levels.md +84 -0
  1494. package/plugins/kiro/skills/funpixel-3d/references/light-and-places.md +141 -0
  1495. package/plugins/kiro/skills/funpixel-3d/references/models.md +111 -0
  1496. package/plugins/kiro/skills/funpixel-3d/references/painted-target.md +184 -0
  1497. package/plugins/kiro/skills/funpixel-3d/references/reading.md +41 -0
  1498. package/plugins/kiro/skills/funpixel-3d/references/skin.md +85 -0
  1499. package/plugins/kiro/skills/funpixel-3d/references/skyboxes.md +65 -0
  1500. package/plugins/kiro/skills/funpixel-3d/references/textures.md +71 -0
  1501. package/plugins/kiro/skills/funpixel-3d/references/three-loading.md +199 -0
  1502. package/plugins/kiro/skills/funpixel-3d/references/unity.md +78 -0
  1503. package/plugins/kiro/skills/funpixel-art/SKILL.md +104 -0
  1504. package/plugins/kiro/skills/funpixel-art/references/2d-assets.md +108 -0
  1505. package/plugins/kiro/skills/funpixel-art/references/animation.md +126 -0
  1506. package/plugins/kiro/skills/funpixel-art/references/cast.md +73 -0
  1507. package/plugins/kiro/skills/funpixel-art/references/characters.md +49 -0
  1508. package/plugins/kiro/skills/funpixel-art/references/cost.md +107 -0
  1509. package/plugins/kiro/skills/funpixel-art/references/effects.md +85 -0
  1510. package/plugins/kiro/skills/funpixel-art/references/frames.md +87 -0
  1511. package/plugins/kiro/skills/funpixel-art/references/judging-frames.md +64 -0
  1512. package/plugins/kiro/skills/funpixel-art/references/look.md +102 -0
  1513. package/plugins/kiro/skills/funpixel-art/references/measure.md +119 -0
  1514. package/plugins/kiro/skills/funpixel-art/references/pipeline.md +185 -0
  1515. package/plugins/kiro/skills/funpixel-art/references/pixi.md +277 -0
  1516. package/plugins/kiro/skills/funpixel-art/references/planes.md +27 -0
  1517. package/plugins/kiro/skills/funpixel-art/references/prompts.md +171 -0
  1518. package/plugins/kiro/skills/funpixel-art/references/sheets.md +141 -0
  1519. package/plugins/kiro/skills/funpixel-art/references/style-file.md +39 -0
  1520. package/plugins/kiro/skills/funpixel-art/references/three.md +232 -0
  1521. package/plugins/kiro/skills/funpixel-art/references/ui.md +163 -0
  1522. package/plugins/kiro/skills/funpixel-art/references/unity.md +78 -0
  1523. package/plugins/kiro/skills/funpixel-art/references/wiring.md +41 -0
  1524. package/plugins/kiro/skills/funpixel-audio/SKILL.md +92 -0
  1525. package/plugins/kiro/skills/funpixel-audio/references/adaptive-music.md +204 -0
  1526. package/plugins/kiro/skills/funpixel-audio/references/engine.md +78 -0
  1527. package/plugins/kiro/skills/funpixel-audio/references/measure.md +101 -0
  1528. package/plugins/kiro/skills/funpixel-audio/references/unity.md +74 -0
  1529. package/plugins/kiro/skills/funpixel-feedback/SKILL.md +120 -0
  1530. package/plugins/kiro/skills/funpixel-feedback/references/memory.md +99 -0
  1531. package/plugins/kiro/skills/funpixel-game-feel/SKILL.md +104 -0
  1532. package/plugins/kiro/skills/funpixel-game-feel/references/contact.md +110 -0
  1533. package/plugins/kiro/skills/funpixel-game-feel/references/measure.md +125 -0
  1534. package/plugins/kiro/skills/funpixel-game-feel/references/motion.md +134 -0
  1535. package/plugins/kiro/skills/funpixel-game-feel/references/payoffs.md +35 -0
  1536. package/plugins/kiro/skills/funpixel-game-feel/references/recipes.md +107 -0
  1537. package/plugins/kiro/skills/funpixel-game-feel/references/unity.md +73 -0
  1538. package/plugins/kiro/skills/funpixel-game-logic/SKILL.md +113 -0
  1539. package/plugins/kiro/skills/funpixel-game-logic/references/balance.md +88 -0
  1540. package/plugins/kiro/skills/funpixel-game-logic/references/content-at-scale.md +147 -0
  1541. package/plugins/kiro/skills/funpixel-game-logic/references/depth.md +89 -0
  1542. package/plugins/kiro/skills/funpixel-game-logic/references/escalation.md +41 -0
  1543. package/plugins/kiro/skills/funpixel-game-logic/references/levels.md +61 -0
  1544. package/plugins/kiro/skills/funpixel-game-logic/references/probes.md +122 -0
  1545. package/plugins/kiro/skills/funpixel-game-logic/references/unity.md +108 -0
  1546. package/plugins/kiro/skills/funpixel-game-spine/SKILL.md +118 -0
  1547. package/plugins/kiro/skills/funpixel-game-spine/references/camera.md +94 -0
  1548. package/plugins/kiro/skills/funpixel-game-spine/references/multiplayer.md +101 -0
  1549. package/plugins/kiro/skills/funpixel-game-spine/references/patterns.md +103 -0
  1550. package/plugins/kiro/skills/funpixel-game-spine/references/performance.md +96 -0
  1551. package/plugins/kiro/skills/funpixel-game-spine/references/pixi.md +26 -0
  1552. package/plugins/kiro/skills/funpixel-game-spine/references/replay.md +102 -0
  1553. package/plugins/kiro/skills/funpixel-game-spine/references/room-api.md +63 -0
  1554. package/plugins/kiro/skills/funpixel-game-spine/references/room-modes.md +40 -0
  1555. package/plugins/kiro/skills/funpixel-game-spine/references/sdk.md +114 -0
  1556. package/plugins/kiro/skills/funpixel-game-spine/references/three.md +62 -0
  1557. package/plugins/kiro/skills/funpixel-gdd/SKILL.md +116 -0
  1558. package/plugins/kiro/skills/funpixel-gdd/references/as-built.md +40 -0
  1559. package/plugins/kiro/skills/funpixel-gdd/references/design-measures.md +24 -0
  1560. package/plugins/kiro/skills/funpixel-gdd/references/design-note.md +88 -0
  1561. package/plugins/kiro/skills/funpixel-gdd/references/experience.md +92 -0
  1562. package/plugins/kiro/skills/funpixel-gdd/references/first-look.md +226 -0
  1563. package/plugins/kiro/skills/funpixel-gdd/references/floors.md +62 -0
  1564. package/plugins/kiro/skills/funpixel-gdd/references/frame.md +75 -0
  1565. package/plugins/kiro/skills/funpixel-gdd/references/gameplay-contract.md +81 -0
  1566. package/plugins/kiro/skills/funpixel-gdd/references/gdd-template.md +417 -0
  1567. package/plugins/kiro/skills/funpixel-gdd/references/genre-card.md +109 -0
  1568. package/plugins/kiro/skills/funpixel-gdd/references/genre-platformer.md +159 -0
  1569. package/plugins/kiro/skills/funpixel-gdd/references/genre-puzzle.md +145 -0
  1570. package/plugins/kiro/skills/funpixel-gdd/references/genre-racing.md +137 -0
  1571. package/plugins/kiro/skills/funpixel-gdd/references/genre-rpg.md +125 -0
  1572. package/plugins/kiro/skills/funpixel-gdd/references/genre-shooter.md +128 -0
  1573. package/plugins/kiro/skills/funpixel-gdd/references/genre-simulation.md +112 -0
  1574. package/plugins/kiro/skills/funpixel-gdd/references/genre-strategy.md +116 -0
  1575. package/plugins/kiro/skills/funpixel-gdd/references/genre-survival.md +122 -0
  1576. package/plugins/kiro/skills/funpixel-gdd/references/in-the-loop.md +106 -0
  1577. package/plugins/kiro/skills/funpixel-gdd/references/invent-first.md +131 -0
  1578. package/plugins/kiro/skills/funpixel-gdd/references/level-and-fun.md +112 -0
  1579. package/plugins/kiro/skills/funpixel-gdd/references/pages.md +47 -0
  1580. package/plugins/kiro/skills/funpixel-gdd/references/plan-at-size.md +140 -0
  1581. package/plugins/kiro/skills/funpixel-gdd/references/production-tiers.md +117 -0
  1582. package/plugins/kiro/skills/funpixel-gdd/references/sections.md +148 -0
  1583. package/plugins/kiro/skills/funpixel-gdd/references/spec-folder.md +131 -0
  1584. package/plugins/kiro/skills/funpixel-gdd/references/start.md +110 -0
  1585. package/plugins/kiro/skills/funpixel-gdd/references/starters.md +175 -0
  1586. package/plugins/kiro/skills/funpixel-gdd/references/the-path.md +133 -0
  1587. package/plugins/kiro/skills/funpixel-gdd/references/track.md +29 -0
  1588. package/plugins/kiro/skills/funpixel-gdd/references/world-and-identity.md +165 -0
  1589. package/plugins/kiro/skills/funpixel-gdd/references/worth.md +74 -0
  1590. package/plugins/kiro/skills/funpixel-mobile-ui/SKILL.md +107 -0
  1591. package/plugins/kiro/skills/funpixel-mobile-ui/references/contrast.md +123 -0
  1592. package/plugins/kiro/skills/funpixel-mobile-ui/references/hud-and-title.md +108 -0
  1593. package/plugins/kiro/skills/funpixel-mobile-ui/references/hud-genres.md +124 -0
  1594. package/plugins/kiro/skills/funpixel-mobile-ui/references/phone-check.md +156 -0
  1595. package/plugins/kiro/skills/funpixel-mobile-ui/references/recipes.md +279 -0
  1596. package/plugins/kiro/skills/funpixel-mobile-ui/references/restyle-ui.md +229 -0
  1597. package/plugins/kiro/skills/funpixel-mobile-ui/references/unity.md +61 -0
  1598. package/plugins/kiro/skills/funpixel-publish/SKILL.md +109 -0
  1599. package/plugins/kiro/skills/funpixel-publish/references/compose.md +113 -0
  1600. package/plugins/kiro/skills/funpixel-publish/references/motion.md +120 -0
  1601. package/plugins/kiro/skills/funpixel-publish/references/networks.md +75 -0
  1602. package/plugins/kiro/skills/funpixel-publish/references/other-hosts.md +65 -0
  1603. package/plugins/kiro/skills/funpixel-publish/references/playable-ad.md +90 -0
  1604. package/plugins/kiro/skills/funpixel-publish/references/server-build.md +85 -0
  1605. package/plugins/kiro/skills/funpixel-publish/references/store-shots.md +85 -0
  1606. package/plugins/kiro/skills/funpixel-publish/references/trailer.md +55 -0
  1607. package/plugins/kiro/skills/funpixel-publish/references/what-ships.md +30 -0
  1608. package/plugins/kiro/skills/funpixel-store/SKILL.md +81 -0
  1609. package/plugins/kiro/skills/funpixel-store/references/app-store.md +73 -0
  1610. package/plugins/kiro/skills/funpixel-store/references/google-play.md +141 -0
  1611. package/plugins/kiro/skills/funpixel-store/references/ios-release.md +63 -0
  1612. package/plugins/kiro/skills/funpixel-store/references/money.md +66 -0
  1613. package/plugins/kiro/skills/funpixel-store/references/purchases-and-review.md +74 -0
  1614. package/plugins/kiro/skills/funpixel-store/references/readiness-page.md +24 -0
  1615. package/plugins/kiro/skills/funpixel-store/references/readiness.md +107 -0
  1616. package/plugins/kiro/skills/funpixel-store/references/steam.md +38 -0
  1617. package/plugins/kiro/skills/funpixel-store/references/unity-store.md +55 -0
  1618. package/plugins/kiro/skills/funpixel-store/references/web-portals.md +43 -0
  1619. package/plugins/kiro/skills/funpixel-unity-game/SKILL.md +103 -0
  1620. package/plugins/kiro/skills/funpixel-unity-game/references/agent-ops.md +54 -0
  1621. package/plugins/kiro/skills/funpixel-unity-game/references/fixes.md +40 -0
  1622. package/plugins/kiro/skills/funpixel-unity-game/references/from-a-web-game.md +108 -0
  1623. package/plugins/kiro/skills/funpixel-unity-game/references/handing-off.md +42 -0
  1624. package/plugins/kiro/skills/funpixel-unity-game/references/performance.md +59 -0
  1625. package/plugins/kiro/skills/funpixel-unity-game/references/probe.md +80 -0
  1626. package/plugins/kiro/skills/funpixel-unity-game/references/shared-mac.md +121 -0
  1627. package/plugins/kiro/skills/funpixel-unity-game/references/traps.md +108 -0
  1628. package/plugins/kiro/skills/funpixel-verify/SKILL.md +109 -0
  1629. package/plugins/kiro/skills/funpixel-verify/references/actors.md +94 -0
  1630. package/plugins/kiro/skills/funpixel-verify/references/bar.md +62 -0
  1631. package/plugins/kiro/skills/funpixel-verify/references/checks.md +69 -0
  1632. package/plugins/kiro/skills/funpixel-verify/references/experience.md +67 -0
  1633. package/plugins/kiro/skills/funpixel-verify/references/eyes.md +54 -0
  1634. package/plugins/kiro/skills/funpixel-verify/references/fidelity.md +126 -0
  1635. package/plugins/kiro/skills/funpixel-verify/references/hit-bar.md +31 -0
  1636. package/plugins/kiro/skills/funpixel-verify/references/journeys.md +77 -0
  1637. package/plugins/kiro/skills/funpixel-verify/references/mobile-qa.md +123 -0
  1638. package/plugins/kiro/skills/funpixel-verify/references/playtest.md +161 -0
  1639. package/plugins/kiro/skills/funpixel-verify/references/review.md +105 -0
  1640. package/plugins/kiro/skills/funpixel-verify/references/rubric.md +67 -0
  1641. package/plugins/kiro/skills/funpixel-verify/references/scenes.md +49 -0
  1642. package/plugins/kiro/skills/funpixel-verify/references/unity.md +60 -0
  1643. package/plugins/kiro/skills/funpixel-world-and-story/SKILL.md +99 -0
  1644. package/plugins/kiro/skills/funpixel-world-and-story/references/atmosphere.md +208 -0
  1645. package/plugins/kiro/skills/funpixel-world-and-story/references/forged-world.md +79 -0
  1646. package/plugins/kiro/skills/funpixel-world-and-story/references/living-world.md +237 -0
  1647. package/plugins/kiro/skills/funpixel-world-and-story/references/opening-and-chapters.md +215 -0
  1648. package/plugins/kiro/skills/funpixel-world-and-story/references/shelf.md +80 -0
  1649. package/plugins/kiro/skills/funpixel-world-and-story/references/story-at-size.md +159 -0
  1650. package/plugins/kiro/skills/funpixel-world-and-story/references/voice.md +175 -0
  1651. package/plugins/kiro/skills/funpixel-world-and-story/references/world-kit.md +154 -0
  1652. package/plugins/robin/LICENSE +115 -0
  1653. package/plugins/robin/README.md +27 -0
  1654. package/plugins/robin/THIRD_PARTY_NOTICES.md +75 -0
  1655. package/plugins/robin/claude/.claude-plugin/plugin.json +19 -0
  1656. package/plugins/robin/claude/.mcp.json +10 -0
  1657. package/plugins/robin/claude/LICENSE +115 -0
  1658. package/plugins/robin/claude/README.md +14 -0
  1659. package/plugins/robin/claude/THIRD_PARTY_NOTICES.md +75 -0
  1660. package/plugins/robin/claude/agents/art-director.md +54 -0
  1661. package/plugins/robin/claude/agents/audio-director.md +51 -0
  1662. package/plugins/robin/claude/agents/critic.md +113 -0
  1663. package/plugins/robin/claude/agents/lane.md +38 -0
  1664. package/plugins/robin/claude/agents/level-designer.md +45 -0
  1665. package/plugins/robin/claude/agents/mobile-qa.md +71 -0
  1666. package/plugins/robin/claude/agents/player.md +144 -0
  1667. package/plugins/robin/claude/agents/qa-lead.md +52 -0
  1668. package/plugins/robin/claude/commands/first-look.md +59 -0
  1669. package/plugins/robin/claude/commands/flow.md +50 -0
  1670. package/plugins/robin/claude/commands/lanes.md +38 -0
  1671. package/plugins/robin/claude/commands/mobile-qa.md +28 -0
  1672. package/plugins/robin/claude/commands/new.md +94 -0
  1673. package/plugins/robin/claude/commands/playtest.md +66 -0
  1674. package/plugins/robin/claude/commands/publish.md +23 -0
  1675. package/plugins/robin/claude/commands/smoke-build.md +25 -0
  1676. package/plugins/robin/claude/commands/verify.md +20 -0
  1677. package/plugins/robin/claude/hooks/brief.md +135 -0
  1678. package/plugins/robin/claude/hooks/critic-receipts.mjs +86 -0
  1679. package/plugins/robin/claude/hooks/durable.mjs +56 -0
  1680. package/plugins/robin/claude/hooks/fence.mjs +30 -0
  1681. package/plugins/robin/claude/hooks/floors.mjs +181 -0
  1682. package/plugins/robin/claude/hooks/flow.mjs +154 -0
  1683. package/plugins/robin/claude/hooks/front-door.mjs +68 -0
  1684. package/plugins/robin/claude/hooks/guidance.json +3 -0
  1685. package/plugins/robin/claude/hooks/hints.mjs +183 -0
  1686. package/plugins/robin/claude/hooks/hooks.json +62 -0
  1687. package/plugins/robin/claude/hooks/lib.mjs +362 -0
  1688. package/plugins/robin/claude/hooks/memory.mjs +92 -0
  1689. package/plugins/robin/claude/hooks/mobile-qa.mjs +43 -0
  1690. package/plugins/robin/claude/hooks/note.mjs +63 -0
  1691. package/plugins/robin/claude/hooks/nudge.mjs +98 -0
  1692. package/plugins/robin/claude/hooks/pipeline.mjs +207 -0
  1693. package/plugins/robin/claude/hooks/prompt.mjs +51 -0
  1694. package/plugins/robin/claude/hooks/quality.mjs +310 -0
  1695. package/plugins/robin/claude/hooks/reach.mjs +93 -0
  1696. package/plugins/robin/claude/hooks/scope.mjs +44 -0
  1697. package/plugins/robin/claude/hooks/session-log.mjs +101 -0
  1698. package/plugins/robin/claude/hooks/session-start.mjs +194 -0
  1699. package/plugins/robin/claude/hooks/skill-names.json +19 -0
  1700. package/plugins/robin/claude/hooks/stop-gate.mjs +303 -0
  1701. package/plugins/robin/claude/hooks/vendor/direct/round.mjs +81 -0
  1702. package/plugins/robin/claude/hooks/vendor/find/names.mjs +46 -0
  1703. package/plugins/robin/claude/hooks/vendor/firstlook/set.mjs +219 -0
  1704. package/plugins/robin/claude/hooks/vendor/flow/flow.mjs +456 -0
  1705. package/plugins/robin/claude/hooks/vendor/flow/look.mjs +140 -0
  1706. package/plugins/robin/claude/hooks/vendor/gdd/book.mjs +484 -0
  1707. package/plugins/robin/claude/hooks/vendor/gdd/chapters.mjs +72 -0
  1708. package/plugins/robin/claude/hooks/vendor/gdd/doc.mjs +33 -0
  1709. package/plugins/robin/claude/hooks/vendor/gdd/levelmap.mjs +429 -0
  1710. package/plugins/robin/claude/hooks/vendor/gdd/rubric.mjs +251 -0
  1711. package/plugins/robin/claude/hooks/vendor/gdd/worth.mjs +508 -0
  1712. package/plugins/robin/claude/hooks/vendor/lanes/fence.mjs +109 -0
  1713. package/plugins/robin/claude/hooks/vendor/lanes/lanes.mjs +356 -0
  1714. package/plugins/robin/claude/hooks/vendor/lanes/union.mjs +63 -0
  1715. package/plugins/robin/claude/hooks/vendor/lessons/motifs.mjs +98 -0
  1716. package/plugins/robin/claude/hooks/vendor/lessons/store.mjs +57 -0
  1717. package/plugins/robin/claude/hooks/vendor/look/made-of.mjs +243 -0
  1718. package/plugins/robin/claude/hooks/vendor/look/roles.mjs +110 -0
  1719. package/plugins/robin/claude/hooks/vendor/memory/decisions.mjs +139 -0
  1720. package/plugins/robin/claude/hooks/vendor/memory/journal.mjs +109 -0
  1721. package/plugins/robin/claude/hooks/vendor/owner/bar.mjs +286 -0
  1722. package/plugins/robin/claude/hooks/vendor/pipeline/pipeline.mjs +930 -0
  1723. package/plugins/robin/claude/hooks/vendor/playtest/keep.mjs +111 -0
  1724. package/plugins/robin/claude/hooks/vendor/playtest/stuck.mjs +48 -0
  1725. package/plugins/robin/claude/hooks/vendor/progress/holds.mjs +107 -0
  1726. package/plugins/robin/claude/hooks/vendor/progress/progress.mjs +301 -0
  1727. package/plugins/robin/claude/hooks/vendor/sim/judge.mjs +241 -0
  1728. package/plugins/robin/claude/hooks/vendor/spec/rooms.mjs +189 -0
  1729. package/plugins/robin/claude/hooks/vendor/spec/tunables.mjs +75 -0
  1730. package/plugins/robin/claude/hooks/vendor/stage/harnessignore.mjs +91 -0
  1731. package/plugins/robin/claude/hooks/vendor/stage/stage.mjs +58 -0
  1732. package/plugins/robin/claude/hooks/vendor/status/board.mjs +173 -0
  1733. package/plugins/robin/claude/hooks/vendor/status/file.mjs +113 -0
  1734. package/plugins/robin/claude/hooks/vendor/studio/forks.mjs +94 -0
  1735. package/plugins/robin/claude/hooks/vendor/studio/pitch.mjs +295 -0
  1736. package/plugins/robin/claude/hooks/vendor/verify/fingerprint.mjs +73 -0
  1737. package/plugins/robin/claude/hooks/vendor/verify/reads.mjs +33 -0
  1738. package/plugins/robin/claude/hooks/vendor/wow/picks.mjs +75 -0
  1739. package/plugins/robin/claude/skills/3d/SKILL.md +89 -0
  1740. package/plugins/robin/claude/skills/3d/references/bake-off.md +48 -0
  1741. package/plugins/robin/claude/skills/3d/references/bench.md +103 -0
  1742. package/plugins/robin/claude/skills/3d/references/budgets.md +48 -0
  1743. package/plugins/robin/claude/skills/3d/references/characters.md +67 -0
  1744. package/plugins/robin/claude/skills/3d/references/concept-image.md +47 -0
  1745. package/plugins/robin/claude/skills/3d/references/engine-targets.md +31 -0
  1746. package/plugins/robin/claude/skills/3d/references/hero-route.md +104 -0
  1747. package/plugins/robin/claude/skills/3d/references/level-spec.md +109 -0
  1748. package/plugins/robin/claude/skills/3d/references/levels.md +84 -0
  1749. package/plugins/robin/claude/skills/3d/references/light-and-places.md +141 -0
  1750. package/plugins/robin/claude/skills/3d/references/models.md +111 -0
  1751. package/plugins/robin/claude/skills/3d/references/painted-target.md +184 -0
  1752. package/plugins/robin/claude/skills/3d/references/reading.md +41 -0
  1753. package/plugins/robin/claude/skills/3d/references/skin.md +85 -0
  1754. package/plugins/robin/claude/skills/3d/references/skyboxes.md +65 -0
  1755. package/plugins/robin/claude/skills/3d/references/textures.md +71 -0
  1756. package/plugins/robin/claude/skills/3d/references/three-loading.md +199 -0
  1757. package/plugins/robin/claude/skills/3d/references/unity.md +78 -0
  1758. package/plugins/robin/claude/skills/art/SKILL.md +104 -0
  1759. package/plugins/robin/claude/skills/art/references/2d-assets.md +108 -0
  1760. package/plugins/robin/claude/skills/art/references/animation.md +126 -0
  1761. package/plugins/robin/claude/skills/art/references/cast.md +73 -0
  1762. package/plugins/robin/claude/skills/art/references/characters.md +49 -0
  1763. package/plugins/robin/claude/skills/art/references/cost.md +107 -0
  1764. package/plugins/robin/claude/skills/art/references/effects.md +85 -0
  1765. package/plugins/robin/claude/skills/art/references/frames.md +87 -0
  1766. package/plugins/robin/claude/skills/art/references/judging-frames.md +64 -0
  1767. package/plugins/robin/claude/skills/art/references/look.md +102 -0
  1768. package/plugins/robin/claude/skills/art/references/measure.md +119 -0
  1769. package/plugins/robin/claude/skills/art/references/pipeline.md +185 -0
  1770. package/plugins/robin/claude/skills/art/references/pixi.md +277 -0
  1771. package/plugins/robin/claude/skills/art/references/planes.md +27 -0
  1772. package/plugins/robin/claude/skills/art/references/prompts.md +171 -0
  1773. package/plugins/robin/claude/skills/art/references/sheets.md +141 -0
  1774. package/plugins/robin/claude/skills/art/references/style-file.md +39 -0
  1775. package/plugins/robin/claude/skills/art/references/three.md +232 -0
  1776. package/plugins/robin/claude/skills/art/references/ui.md +163 -0
  1777. package/plugins/robin/claude/skills/art/references/unity.md +78 -0
  1778. package/plugins/robin/claude/skills/art/references/wiring.md +41 -0
  1779. package/plugins/robin/claude/skills/audio/SKILL.md +92 -0
  1780. package/plugins/robin/claude/skills/audio/references/adaptive-music.md +204 -0
  1781. package/plugins/robin/claude/skills/audio/references/engine.md +78 -0
  1782. package/plugins/robin/claude/skills/audio/references/measure.md +101 -0
  1783. package/plugins/robin/claude/skills/audio/references/unity.md +74 -0
  1784. package/plugins/robin/claude/skills/feedback/SKILL.md +120 -0
  1785. package/plugins/robin/claude/skills/feedback/references/memory.md +99 -0
  1786. package/plugins/robin/claude/skills/game-feel/SKILL.md +104 -0
  1787. package/plugins/robin/claude/skills/game-feel/references/contact.md +110 -0
  1788. package/plugins/robin/claude/skills/game-feel/references/measure.md +125 -0
  1789. package/plugins/robin/claude/skills/game-feel/references/motion.md +134 -0
  1790. package/plugins/robin/claude/skills/game-feel/references/payoffs.md +35 -0
  1791. package/plugins/robin/claude/skills/game-feel/references/recipes.md +107 -0
  1792. package/plugins/robin/claude/skills/game-feel/references/unity.md +73 -0
  1793. package/plugins/robin/claude/skills/game-logic/SKILL.md +113 -0
  1794. package/plugins/robin/claude/skills/game-logic/references/balance.md +88 -0
  1795. package/plugins/robin/claude/skills/game-logic/references/content-at-scale.md +147 -0
  1796. package/plugins/robin/claude/skills/game-logic/references/depth.md +89 -0
  1797. package/plugins/robin/claude/skills/game-logic/references/escalation.md +41 -0
  1798. package/plugins/robin/claude/skills/game-logic/references/levels.md +61 -0
  1799. package/plugins/robin/claude/skills/game-logic/references/probes.md +122 -0
  1800. package/plugins/robin/claude/skills/game-logic/references/unity.md +108 -0
  1801. package/plugins/robin/claude/skills/game-spine/SKILL.md +118 -0
  1802. package/plugins/robin/claude/skills/game-spine/references/camera.md +94 -0
  1803. package/plugins/robin/claude/skills/game-spine/references/multiplayer.md +101 -0
  1804. package/plugins/robin/claude/skills/game-spine/references/patterns.md +103 -0
  1805. package/plugins/robin/claude/skills/game-spine/references/performance.md +96 -0
  1806. package/plugins/robin/claude/skills/game-spine/references/pixi.md +26 -0
  1807. package/plugins/robin/claude/skills/game-spine/references/replay.md +102 -0
  1808. package/plugins/robin/claude/skills/game-spine/references/room-api.md +63 -0
  1809. package/plugins/robin/claude/skills/game-spine/references/room-modes.md +40 -0
  1810. package/plugins/robin/claude/skills/game-spine/references/sdk.md +114 -0
  1811. package/plugins/robin/claude/skills/game-spine/references/three.md +62 -0
  1812. package/plugins/robin/claude/skills/gdd/SKILL.md +116 -0
  1813. package/plugins/robin/claude/skills/gdd/references/as-built.md +40 -0
  1814. package/plugins/robin/claude/skills/gdd/references/design-measures.md +24 -0
  1815. package/plugins/robin/claude/skills/gdd/references/design-note.md +88 -0
  1816. package/plugins/robin/claude/skills/gdd/references/experience.md +92 -0
  1817. package/plugins/robin/claude/skills/gdd/references/first-look.md +226 -0
  1818. package/plugins/robin/claude/skills/gdd/references/floors.md +62 -0
  1819. package/plugins/robin/claude/skills/gdd/references/frame.md +75 -0
  1820. package/plugins/robin/claude/skills/gdd/references/gameplay-contract.md +81 -0
  1821. package/plugins/robin/claude/skills/gdd/references/gdd-template.md +417 -0
  1822. package/plugins/robin/claude/skills/gdd/references/genre-card.md +109 -0
  1823. package/plugins/robin/claude/skills/gdd/references/genre-platformer.md +159 -0
  1824. package/plugins/robin/claude/skills/gdd/references/genre-puzzle.md +145 -0
  1825. package/plugins/robin/claude/skills/gdd/references/genre-racing.md +137 -0
  1826. package/plugins/robin/claude/skills/gdd/references/genre-rpg.md +125 -0
  1827. package/plugins/robin/claude/skills/gdd/references/genre-shooter.md +128 -0
  1828. package/plugins/robin/claude/skills/gdd/references/genre-simulation.md +112 -0
  1829. package/plugins/robin/claude/skills/gdd/references/genre-strategy.md +116 -0
  1830. package/plugins/robin/claude/skills/gdd/references/genre-survival.md +122 -0
  1831. package/plugins/robin/claude/skills/gdd/references/in-the-loop.md +106 -0
  1832. package/plugins/robin/claude/skills/gdd/references/invent-first.md +131 -0
  1833. package/plugins/robin/claude/skills/gdd/references/level-and-fun.md +112 -0
  1834. package/plugins/robin/claude/skills/gdd/references/pages.md +47 -0
  1835. package/plugins/robin/claude/skills/gdd/references/plan-at-size.md +140 -0
  1836. package/plugins/robin/claude/skills/gdd/references/production-tiers.md +117 -0
  1837. package/plugins/robin/claude/skills/gdd/references/sections.md +148 -0
  1838. package/plugins/robin/claude/skills/gdd/references/spec-folder.md +131 -0
  1839. package/plugins/robin/claude/skills/gdd/references/start.md +110 -0
  1840. package/plugins/robin/claude/skills/gdd/references/starters.md +175 -0
  1841. package/plugins/robin/claude/skills/gdd/references/the-path.md +133 -0
  1842. package/plugins/robin/claude/skills/gdd/references/track.md +29 -0
  1843. package/plugins/robin/claude/skills/gdd/references/world-and-identity.md +165 -0
  1844. package/plugins/robin/claude/skills/gdd/references/worth.md +74 -0
  1845. package/plugins/robin/claude/skills/mobile-ui/SKILL.md +107 -0
  1846. package/plugins/robin/claude/skills/mobile-ui/references/contrast.md +123 -0
  1847. package/plugins/robin/claude/skills/mobile-ui/references/hud-and-title.md +108 -0
  1848. package/plugins/robin/claude/skills/mobile-ui/references/hud-genres.md +124 -0
  1849. package/plugins/robin/claude/skills/mobile-ui/references/phone-check.md +156 -0
  1850. package/plugins/robin/claude/skills/mobile-ui/references/recipes.md +279 -0
  1851. package/plugins/robin/claude/skills/mobile-ui/references/restyle-ui.md +229 -0
  1852. package/plugins/robin/claude/skills/mobile-ui/references/unity.md +61 -0
  1853. package/plugins/robin/claude/skills/publishing/SKILL.md +109 -0
  1854. package/plugins/robin/claude/skills/publishing/references/compose.md +113 -0
  1855. package/plugins/robin/claude/skills/publishing/references/motion.md +120 -0
  1856. package/plugins/robin/claude/skills/publishing/references/networks.md +75 -0
  1857. package/plugins/robin/claude/skills/publishing/references/other-hosts.md +65 -0
  1858. package/plugins/robin/claude/skills/publishing/references/playable-ad.md +90 -0
  1859. package/plugins/robin/claude/skills/publishing/references/server-build.md +85 -0
  1860. package/plugins/robin/claude/skills/publishing/references/store-shots.md +85 -0
  1861. package/plugins/robin/claude/skills/publishing/references/trailer.md +55 -0
  1862. package/plugins/robin/claude/skills/publishing/references/what-ships.md +30 -0
  1863. package/plugins/robin/claude/skills/store/SKILL.md +81 -0
  1864. package/plugins/robin/claude/skills/store/references/app-store.md +73 -0
  1865. package/plugins/robin/claude/skills/store/references/google-play.md +141 -0
  1866. package/plugins/robin/claude/skills/store/references/ios-release.md +63 -0
  1867. package/plugins/robin/claude/skills/store/references/money.md +66 -0
  1868. package/plugins/robin/claude/skills/store/references/purchases-and-review.md +74 -0
  1869. package/plugins/robin/claude/skills/store/references/readiness-page.md +24 -0
  1870. package/plugins/robin/claude/skills/store/references/readiness.md +107 -0
  1871. package/plugins/robin/claude/skills/store/references/steam.md +38 -0
  1872. package/plugins/robin/claude/skills/store/references/unity-store.md +55 -0
  1873. package/plugins/robin/claude/skills/store/references/web-portals.md +43 -0
  1874. package/plugins/robin/claude/skills/unity-game/SKILL.md +103 -0
  1875. package/plugins/robin/claude/skills/unity-game/references/agent-ops.md +54 -0
  1876. package/plugins/robin/claude/skills/unity-game/references/fixes.md +40 -0
  1877. package/plugins/robin/claude/skills/unity-game/references/from-a-web-game.md +108 -0
  1878. package/plugins/robin/claude/skills/unity-game/references/handing-off.md +42 -0
  1879. package/plugins/robin/claude/skills/unity-game/references/performance.md +59 -0
  1880. package/plugins/robin/claude/skills/unity-game/references/probe.md +80 -0
  1881. package/plugins/robin/claude/skills/unity-game/references/shared-mac.md +121 -0
  1882. package/plugins/robin/claude/skills/unity-game/references/traps.md +108 -0
  1883. package/plugins/robin/claude/skills/verifying/SKILL.md +109 -0
  1884. package/plugins/robin/claude/skills/verifying/references/actors.md +94 -0
  1885. package/plugins/robin/claude/skills/verifying/references/bar.md +62 -0
  1886. package/plugins/robin/claude/skills/verifying/references/checks.md +69 -0
  1887. package/plugins/robin/claude/skills/verifying/references/experience.md +67 -0
  1888. package/plugins/robin/claude/skills/verifying/references/eyes.md +54 -0
  1889. package/plugins/robin/claude/skills/verifying/references/fidelity.md +126 -0
  1890. package/plugins/robin/claude/skills/verifying/references/hit-bar.md +31 -0
  1891. package/plugins/robin/claude/skills/verifying/references/journeys.md +77 -0
  1892. package/plugins/robin/claude/skills/verifying/references/mobile-qa.md +123 -0
  1893. package/plugins/robin/claude/skills/verifying/references/playtest.md +161 -0
  1894. package/plugins/robin/claude/skills/verifying/references/review.md +105 -0
  1895. package/plugins/robin/claude/skills/verifying/references/rubric.md +67 -0
  1896. package/plugins/robin/claude/skills/verifying/references/scenes.md +49 -0
  1897. package/plugins/robin/claude/skills/verifying/references/unity.md +60 -0
  1898. package/plugins/robin/claude/skills/world-and-story/SKILL.md +99 -0
  1899. package/plugins/robin/claude/skills/world-and-story/references/atmosphere.md +208 -0
  1900. package/plugins/robin/claude/skills/world-and-story/references/forged-world.md +79 -0
  1901. package/plugins/robin/claude/skills/world-and-story/references/living-world.md +237 -0
  1902. package/plugins/robin/claude/skills/world-and-story/references/opening-and-chapters.md +215 -0
  1903. package/plugins/robin/claude/skills/world-and-story/references/shelf.md +80 -0
  1904. package/plugins/robin/claude/skills/world-and-story/references/story-at-size.md +159 -0
  1905. package/plugins/robin/claude/skills/world-and-story/references/voice.md +175 -0
  1906. package/plugins/robin/claude/skills/world-and-story/references/world-kit.md +154 -0
  1907. package/plugins/robin/mcp-servers.json +25 -0
  1908. package/plugins/robin/plugin.json +20 -0
  1909. package/plugins/robin/skills/fp-first-look/SKILL.md +59 -0
  1910. package/plugins/robin/skills/fp-flow/SKILL.md +50 -0
  1911. package/plugins/robin/skills/fp-lanes/SKILL.md +38 -0
  1912. package/plugins/robin/skills/fp-mobile-qa/SKILL.md +28 -0
  1913. package/plugins/robin/skills/fp-new/SKILL.md +94 -0
  1914. package/plugins/robin/skills/fp-playtest/SKILL.md +66 -0
  1915. package/plugins/robin/skills/fp-publish/SKILL.md +23 -0
  1916. package/plugins/robin/skills/fp-smoke-build/SKILL.md +25 -0
  1917. package/plugins/robin/skills/fp-verify/SKILL.md +20 -0
  1918. package/plugins/robin/skills/funpixel-3d/SKILL.md +89 -0
  1919. package/plugins/robin/skills/funpixel-3d/references/bake-off.md +48 -0
  1920. package/plugins/robin/skills/funpixel-3d/references/bench.md +103 -0
  1921. package/plugins/robin/skills/funpixel-3d/references/budgets.md +48 -0
  1922. package/plugins/robin/skills/funpixel-3d/references/characters.md +67 -0
  1923. package/plugins/robin/skills/funpixel-3d/references/concept-image.md +47 -0
  1924. package/plugins/robin/skills/funpixel-3d/references/engine-targets.md +31 -0
  1925. package/plugins/robin/skills/funpixel-3d/references/hero-route.md +104 -0
  1926. package/plugins/robin/skills/funpixel-3d/references/level-spec.md +109 -0
  1927. package/plugins/robin/skills/funpixel-3d/references/levels.md +84 -0
  1928. package/plugins/robin/skills/funpixel-3d/references/light-and-places.md +141 -0
  1929. package/plugins/robin/skills/funpixel-3d/references/models.md +111 -0
  1930. package/plugins/robin/skills/funpixel-3d/references/painted-target.md +184 -0
  1931. package/plugins/robin/skills/funpixel-3d/references/reading.md +41 -0
  1932. package/plugins/robin/skills/funpixel-3d/references/skin.md +85 -0
  1933. package/plugins/robin/skills/funpixel-3d/references/skyboxes.md +65 -0
  1934. package/plugins/robin/skills/funpixel-3d/references/textures.md +71 -0
  1935. package/plugins/robin/skills/funpixel-3d/references/three-loading.md +199 -0
  1936. package/plugins/robin/skills/funpixel-3d/references/unity.md +78 -0
  1937. package/plugins/robin/skills/funpixel-art/SKILL.md +104 -0
  1938. package/plugins/robin/skills/funpixel-art/references/2d-assets.md +108 -0
  1939. package/plugins/robin/skills/funpixel-art/references/animation.md +126 -0
  1940. package/plugins/robin/skills/funpixel-art/references/cast.md +73 -0
  1941. package/plugins/robin/skills/funpixel-art/references/characters.md +49 -0
  1942. package/plugins/robin/skills/funpixel-art/references/cost.md +107 -0
  1943. package/plugins/robin/skills/funpixel-art/references/effects.md +85 -0
  1944. package/plugins/robin/skills/funpixel-art/references/frames.md +87 -0
  1945. package/plugins/robin/skills/funpixel-art/references/judging-frames.md +64 -0
  1946. package/plugins/robin/skills/funpixel-art/references/look.md +102 -0
  1947. package/plugins/robin/skills/funpixel-art/references/measure.md +119 -0
  1948. package/plugins/robin/skills/funpixel-art/references/pipeline.md +185 -0
  1949. package/plugins/robin/skills/funpixel-art/references/pixi.md +277 -0
  1950. package/plugins/robin/skills/funpixel-art/references/planes.md +27 -0
  1951. package/plugins/robin/skills/funpixel-art/references/prompts.md +171 -0
  1952. package/plugins/robin/skills/funpixel-art/references/sheets.md +141 -0
  1953. package/plugins/robin/skills/funpixel-art/references/style-file.md +39 -0
  1954. package/plugins/robin/skills/funpixel-art/references/three.md +232 -0
  1955. package/plugins/robin/skills/funpixel-art/references/ui.md +163 -0
  1956. package/plugins/robin/skills/funpixel-art/references/unity.md +78 -0
  1957. package/plugins/robin/skills/funpixel-art/references/wiring.md +41 -0
  1958. package/plugins/robin/skills/funpixel-audio/SKILL.md +92 -0
  1959. package/plugins/robin/skills/funpixel-audio/references/adaptive-music.md +204 -0
  1960. package/plugins/robin/skills/funpixel-audio/references/engine.md +78 -0
  1961. package/plugins/robin/skills/funpixel-audio/references/measure.md +101 -0
  1962. package/plugins/robin/skills/funpixel-audio/references/unity.md +74 -0
  1963. package/plugins/robin/skills/funpixel-brief/SKILL.md +163 -0
  1964. package/plugins/robin/skills/funpixel-feedback/SKILL.md +120 -0
  1965. package/plugins/robin/skills/funpixel-feedback/references/memory.md +99 -0
  1966. package/plugins/robin/skills/funpixel-game-feel/SKILL.md +104 -0
  1967. package/plugins/robin/skills/funpixel-game-feel/references/contact.md +110 -0
  1968. package/plugins/robin/skills/funpixel-game-feel/references/measure.md +125 -0
  1969. package/plugins/robin/skills/funpixel-game-feel/references/motion.md +134 -0
  1970. package/plugins/robin/skills/funpixel-game-feel/references/payoffs.md +35 -0
  1971. package/plugins/robin/skills/funpixel-game-feel/references/recipes.md +107 -0
  1972. package/plugins/robin/skills/funpixel-game-feel/references/unity.md +73 -0
  1973. package/plugins/robin/skills/funpixel-game-logic/SKILL.md +113 -0
  1974. package/plugins/robin/skills/funpixel-game-logic/references/balance.md +88 -0
  1975. package/plugins/robin/skills/funpixel-game-logic/references/content-at-scale.md +147 -0
  1976. package/plugins/robin/skills/funpixel-game-logic/references/depth.md +89 -0
  1977. package/plugins/robin/skills/funpixel-game-logic/references/escalation.md +41 -0
  1978. package/plugins/robin/skills/funpixel-game-logic/references/levels.md +61 -0
  1979. package/plugins/robin/skills/funpixel-game-logic/references/probes.md +122 -0
  1980. package/plugins/robin/skills/funpixel-game-logic/references/unity.md +108 -0
  1981. package/plugins/robin/skills/funpixel-game-spine/SKILL.md +118 -0
  1982. package/plugins/robin/skills/funpixel-game-spine/references/camera.md +94 -0
  1983. package/plugins/robin/skills/funpixel-game-spine/references/multiplayer.md +101 -0
  1984. package/plugins/robin/skills/funpixel-game-spine/references/patterns.md +103 -0
  1985. package/plugins/robin/skills/funpixel-game-spine/references/performance.md +96 -0
  1986. package/plugins/robin/skills/funpixel-game-spine/references/pixi.md +26 -0
  1987. package/plugins/robin/skills/funpixel-game-spine/references/replay.md +102 -0
  1988. package/plugins/robin/skills/funpixel-game-spine/references/room-api.md +63 -0
  1989. package/plugins/robin/skills/funpixel-game-spine/references/room-modes.md +40 -0
  1990. package/plugins/robin/skills/funpixel-game-spine/references/sdk.md +114 -0
  1991. package/plugins/robin/skills/funpixel-game-spine/references/three.md +62 -0
  1992. package/plugins/robin/skills/funpixel-gdd/SKILL.md +116 -0
  1993. package/plugins/robin/skills/funpixel-gdd/references/as-built.md +40 -0
  1994. package/plugins/robin/skills/funpixel-gdd/references/design-measures.md +24 -0
  1995. package/plugins/robin/skills/funpixel-gdd/references/design-note.md +88 -0
  1996. package/plugins/robin/skills/funpixel-gdd/references/experience.md +92 -0
  1997. package/plugins/robin/skills/funpixel-gdd/references/first-look.md +226 -0
  1998. package/plugins/robin/skills/funpixel-gdd/references/floors.md +62 -0
  1999. package/plugins/robin/skills/funpixel-gdd/references/frame.md +75 -0
  2000. package/plugins/robin/skills/funpixel-gdd/references/gameplay-contract.md +81 -0
  2001. package/plugins/robin/skills/funpixel-gdd/references/gdd-template.md +417 -0
  2002. package/plugins/robin/skills/funpixel-gdd/references/genre-card.md +109 -0
  2003. package/plugins/robin/skills/funpixel-gdd/references/genre-platformer.md +159 -0
  2004. package/plugins/robin/skills/funpixel-gdd/references/genre-puzzle.md +145 -0
  2005. package/plugins/robin/skills/funpixel-gdd/references/genre-racing.md +137 -0
  2006. package/plugins/robin/skills/funpixel-gdd/references/genre-rpg.md +125 -0
  2007. package/plugins/robin/skills/funpixel-gdd/references/genre-shooter.md +128 -0
  2008. package/plugins/robin/skills/funpixel-gdd/references/genre-simulation.md +112 -0
  2009. package/plugins/robin/skills/funpixel-gdd/references/genre-strategy.md +116 -0
  2010. package/plugins/robin/skills/funpixel-gdd/references/genre-survival.md +122 -0
  2011. package/plugins/robin/skills/funpixel-gdd/references/in-the-loop.md +106 -0
  2012. package/plugins/robin/skills/funpixel-gdd/references/invent-first.md +131 -0
  2013. package/plugins/robin/skills/funpixel-gdd/references/level-and-fun.md +112 -0
  2014. package/plugins/robin/skills/funpixel-gdd/references/pages.md +47 -0
  2015. package/plugins/robin/skills/funpixel-gdd/references/plan-at-size.md +140 -0
  2016. package/plugins/robin/skills/funpixel-gdd/references/production-tiers.md +117 -0
  2017. package/plugins/robin/skills/funpixel-gdd/references/sections.md +148 -0
  2018. package/plugins/robin/skills/funpixel-gdd/references/spec-folder.md +131 -0
  2019. package/plugins/robin/skills/funpixel-gdd/references/start.md +110 -0
  2020. package/plugins/robin/skills/funpixel-gdd/references/starters.md +175 -0
  2021. package/plugins/robin/skills/funpixel-gdd/references/the-path.md +133 -0
  2022. package/plugins/robin/skills/funpixel-gdd/references/track.md +29 -0
  2023. package/plugins/robin/skills/funpixel-gdd/references/world-and-identity.md +165 -0
  2024. package/plugins/robin/skills/funpixel-gdd/references/worth.md +74 -0
  2025. package/plugins/robin/skills/funpixel-mobile-ui/SKILL.md +107 -0
  2026. package/plugins/robin/skills/funpixel-mobile-ui/references/contrast.md +123 -0
  2027. package/plugins/robin/skills/funpixel-mobile-ui/references/hud-and-title.md +108 -0
  2028. package/plugins/robin/skills/funpixel-mobile-ui/references/hud-genres.md +124 -0
  2029. package/plugins/robin/skills/funpixel-mobile-ui/references/phone-check.md +156 -0
  2030. package/plugins/robin/skills/funpixel-mobile-ui/references/recipes.md +279 -0
  2031. package/plugins/robin/skills/funpixel-mobile-ui/references/restyle-ui.md +229 -0
  2032. package/plugins/robin/skills/funpixel-mobile-ui/references/unity.md +61 -0
  2033. package/plugins/robin/skills/funpixel-publish/SKILL.md +109 -0
  2034. package/plugins/robin/skills/funpixel-publish/references/compose.md +113 -0
  2035. package/plugins/robin/skills/funpixel-publish/references/motion.md +120 -0
  2036. package/plugins/robin/skills/funpixel-publish/references/networks.md +75 -0
  2037. package/plugins/robin/skills/funpixel-publish/references/other-hosts.md +65 -0
  2038. package/plugins/robin/skills/funpixel-publish/references/playable-ad.md +90 -0
  2039. package/plugins/robin/skills/funpixel-publish/references/server-build.md +85 -0
  2040. package/plugins/robin/skills/funpixel-publish/references/store-shots.md +85 -0
  2041. package/plugins/robin/skills/funpixel-publish/references/trailer.md +55 -0
  2042. package/plugins/robin/skills/funpixel-publish/references/what-ships.md +30 -0
  2043. package/plugins/robin/skills/funpixel-store/SKILL.md +81 -0
  2044. package/plugins/robin/skills/funpixel-store/references/app-store.md +73 -0
  2045. package/plugins/robin/skills/funpixel-store/references/google-play.md +141 -0
  2046. package/plugins/robin/skills/funpixel-store/references/ios-release.md +63 -0
  2047. package/plugins/robin/skills/funpixel-store/references/money.md +66 -0
  2048. package/plugins/robin/skills/funpixel-store/references/purchases-and-review.md +74 -0
  2049. package/plugins/robin/skills/funpixel-store/references/readiness-page.md +24 -0
  2050. package/plugins/robin/skills/funpixel-store/references/readiness.md +107 -0
  2051. package/plugins/robin/skills/funpixel-store/references/steam.md +38 -0
  2052. package/plugins/robin/skills/funpixel-store/references/unity-store.md +55 -0
  2053. package/plugins/robin/skills/funpixel-store/references/web-portals.md +43 -0
  2054. package/plugins/robin/skills/funpixel-unity-game/SKILL.md +103 -0
  2055. package/plugins/robin/skills/funpixel-unity-game/references/agent-ops.md +54 -0
  2056. package/plugins/robin/skills/funpixel-unity-game/references/fixes.md +40 -0
  2057. package/plugins/robin/skills/funpixel-unity-game/references/from-a-web-game.md +108 -0
  2058. package/plugins/robin/skills/funpixel-unity-game/references/handing-off.md +42 -0
  2059. package/plugins/robin/skills/funpixel-unity-game/references/performance.md +59 -0
  2060. package/plugins/robin/skills/funpixel-unity-game/references/probe.md +80 -0
  2061. package/plugins/robin/skills/funpixel-unity-game/references/shared-mac.md +121 -0
  2062. package/plugins/robin/skills/funpixel-unity-game/references/traps.md +108 -0
  2063. package/plugins/robin/skills/funpixel-verify/SKILL.md +109 -0
  2064. package/plugins/robin/skills/funpixel-verify/references/actors.md +94 -0
  2065. package/plugins/robin/skills/funpixel-verify/references/bar.md +62 -0
  2066. package/plugins/robin/skills/funpixel-verify/references/checks.md +69 -0
  2067. package/plugins/robin/skills/funpixel-verify/references/experience.md +67 -0
  2068. package/plugins/robin/skills/funpixel-verify/references/eyes.md +54 -0
  2069. package/plugins/robin/skills/funpixel-verify/references/fidelity.md +126 -0
  2070. package/plugins/robin/skills/funpixel-verify/references/hit-bar.md +31 -0
  2071. package/plugins/robin/skills/funpixel-verify/references/journeys.md +77 -0
  2072. package/plugins/robin/skills/funpixel-verify/references/mobile-qa.md +123 -0
  2073. package/plugins/robin/skills/funpixel-verify/references/playtest.md +161 -0
  2074. package/plugins/robin/skills/funpixel-verify/references/review.md +105 -0
  2075. package/plugins/robin/skills/funpixel-verify/references/rubric.md +67 -0
  2076. package/plugins/robin/skills/funpixel-verify/references/scenes.md +49 -0
  2077. package/plugins/robin/skills/funpixel-verify/references/unity.md +60 -0
  2078. package/plugins/robin/skills/funpixel-world-and-story/SKILL.md +99 -0
  2079. package/plugins/robin/skills/funpixel-world-and-story/references/atmosphere.md +208 -0
  2080. package/plugins/robin/skills/funpixel-world-and-story/references/forged-world.md +79 -0
  2081. package/plugins/robin/skills/funpixel-world-and-story/references/living-world.md +237 -0
  2082. package/plugins/robin/skills/funpixel-world-and-story/references/opening-and-chapters.md +215 -0
  2083. package/plugins/robin/skills/funpixel-world-and-story/references/shelf.md +80 -0
  2084. package/plugins/robin/skills/funpixel-world-and-story/references/story-at-size.md +159 -0
  2085. package/plugins/robin/skills/funpixel-world-and-story/references/voice.md +175 -0
  2086. package/plugins/robin/skills/funpixel-world-and-story/references/world-kit.md +154 -0
  2087. package/templates/common/.agents/skills/funpixel-3d/SKILL.md +89 -0
  2088. package/templates/common/.agents/skills/funpixel-3d/references/bake-off.md +48 -0
  2089. package/templates/common/.agents/skills/funpixel-3d/references/bench.md +103 -0
  2090. package/templates/common/.agents/skills/funpixel-3d/references/budgets.md +48 -0
  2091. package/templates/common/.agents/skills/funpixel-3d/references/characters.md +67 -0
  2092. package/templates/common/.agents/skills/funpixel-3d/references/concept-image.md +47 -0
  2093. package/templates/common/.agents/skills/funpixel-3d/references/engine-targets.md +31 -0
  2094. package/templates/common/.agents/skills/funpixel-3d/references/hero-route.md +104 -0
  2095. package/templates/common/.agents/skills/funpixel-3d/references/level-spec.md +109 -0
  2096. package/templates/common/.agents/skills/funpixel-3d/references/levels.md +84 -0
  2097. package/templates/common/.agents/skills/funpixel-3d/references/light-and-places.md +141 -0
  2098. package/templates/common/.agents/skills/funpixel-3d/references/models.md +111 -0
  2099. package/templates/common/.agents/skills/funpixel-3d/references/painted-target.md +184 -0
  2100. package/templates/common/.agents/skills/funpixel-3d/references/reading.md +41 -0
  2101. package/templates/common/.agents/skills/funpixel-3d/references/skin.md +85 -0
  2102. package/templates/common/.agents/skills/funpixel-3d/references/skyboxes.md +65 -0
  2103. package/templates/common/.agents/skills/funpixel-3d/references/textures.md +71 -0
  2104. package/templates/common/.agents/skills/funpixel-3d/references/three-loading.md +199 -0
  2105. package/templates/common/.agents/skills/funpixel-3d/references/unity.md +78 -0
  2106. package/templates/common/.agents/skills/funpixel-art/SKILL.md +104 -0
  2107. package/templates/common/.agents/skills/funpixel-art/references/2d-assets.md +108 -0
  2108. package/templates/common/.agents/skills/funpixel-art/references/animation.md +126 -0
  2109. package/templates/common/.agents/skills/funpixel-art/references/cast.md +73 -0
  2110. package/templates/common/.agents/skills/funpixel-art/references/characters.md +49 -0
  2111. package/templates/common/.agents/skills/funpixel-art/references/cost.md +107 -0
  2112. package/templates/common/.agents/skills/funpixel-art/references/effects.md +85 -0
  2113. package/templates/common/.agents/skills/funpixel-art/references/frames.md +87 -0
  2114. package/templates/common/.agents/skills/funpixel-art/references/judging-frames.md +64 -0
  2115. package/templates/common/.agents/skills/funpixel-art/references/look.md +102 -0
  2116. package/templates/common/.agents/skills/funpixel-art/references/measure.md +119 -0
  2117. package/templates/common/.agents/skills/funpixel-art/references/pipeline.md +185 -0
  2118. package/templates/common/.agents/skills/funpixel-art/references/pixi.md +277 -0
  2119. package/templates/common/.agents/skills/funpixel-art/references/planes.md +27 -0
  2120. package/templates/common/.agents/skills/funpixel-art/references/prompts.md +171 -0
  2121. package/templates/common/.agents/skills/funpixel-art/references/sheets.md +141 -0
  2122. package/templates/common/.agents/skills/funpixel-art/references/style-file.md +39 -0
  2123. package/templates/common/.agents/skills/funpixel-art/references/three.md +232 -0
  2124. package/templates/common/.agents/skills/funpixel-art/references/ui.md +163 -0
  2125. package/templates/common/.agents/skills/funpixel-art/references/unity.md +78 -0
  2126. package/templates/common/.agents/skills/funpixel-art/references/wiring.md +41 -0
  2127. package/templates/common/.agents/skills/funpixel-audio/SKILL.md +92 -0
  2128. package/templates/common/.agents/skills/funpixel-audio/references/adaptive-music.md +204 -0
  2129. package/templates/common/.agents/skills/funpixel-audio/references/engine.md +78 -0
  2130. package/templates/common/.agents/skills/funpixel-audio/references/measure.md +101 -0
  2131. package/templates/common/.agents/skills/funpixel-audio/references/unity.md +74 -0
  2132. package/templates/common/.agents/skills/funpixel-feedback/SKILL.md +120 -0
  2133. package/templates/common/.agents/skills/funpixel-feedback/references/memory.md +99 -0
  2134. package/templates/common/.agents/skills/funpixel-game-feel/SKILL.md +104 -0
  2135. package/templates/common/.agents/skills/funpixel-game-feel/references/contact.md +110 -0
  2136. package/templates/common/.agents/skills/funpixel-game-feel/references/measure.md +125 -0
  2137. package/templates/common/.agents/skills/funpixel-game-feel/references/motion.md +134 -0
  2138. package/templates/common/.agents/skills/funpixel-game-feel/references/payoffs.md +35 -0
  2139. package/templates/common/.agents/skills/funpixel-game-feel/references/recipes.md +107 -0
  2140. package/templates/common/.agents/skills/funpixel-game-feel/references/unity.md +73 -0
  2141. package/templates/common/.agents/skills/funpixel-game-logic/SKILL.md +113 -0
  2142. package/templates/common/.agents/skills/funpixel-game-logic/references/balance.md +88 -0
  2143. package/templates/common/.agents/skills/funpixel-game-logic/references/content-at-scale.md +147 -0
  2144. package/templates/common/.agents/skills/funpixel-game-logic/references/depth.md +89 -0
  2145. package/templates/common/.agents/skills/funpixel-game-logic/references/escalation.md +41 -0
  2146. package/templates/common/.agents/skills/funpixel-game-logic/references/levels.md +61 -0
  2147. package/templates/common/.agents/skills/funpixel-game-logic/references/probes.md +122 -0
  2148. package/templates/common/.agents/skills/funpixel-game-logic/references/unity.md +108 -0
  2149. package/templates/common/.agents/skills/funpixel-game-spine/SKILL.md +118 -0
  2150. package/templates/common/.agents/skills/funpixel-game-spine/references/camera.md +94 -0
  2151. package/templates/common/.agents/skills/funpixel-game-spine/references/multiplayer.md +101 -0
  2152. package/templates/common/.agents/skills/funpixel-game-spine/references/patterns.md +103 -0
  2153. package/templates/common/.agents/skills/funpixel-game-spine/references/performance.md +96 -0
  2154. package/templates/common/.agents/skills/funpixel-game-spine/references/pixi.md +26 -0
  2155. package/templates/common/.agents/skills/funpixel-game-spine/references/replay.md +102 -0
  2156. package/templates/common/.agents/skills/funpixel-game-spine/references/room-api.md +63 -0
  2157. package/templates/common/.agents/skills/funpixel-game-spine/references/room-modes.md +40 -0
  2158. package/templates/common/.agents/skills/funpixel-game-spine/references/sdk.md +114 -0
  2159. package/templates/common/.agents/skills/funpixel-game-spine/references/three.md +62 -0
  2160. package/templates/common/.agents/skills/funpixel-gdd/SKILL.md +116 -0
  2161. package/templates/common/.agents/skills/funpixel-gdd/references/as-built.md +40 -0
  2162. package/templates/common/.agents/skills/funpixel-gdd/references/design-measures.md +24 -0
  2163. package/templates/common/.agents/skills/funpixel-gdd/references/design-note.md +88 -0
  2164. package/templates/common/.agents/skills/funpixel-gdd/references/experience.md +92 -0
  2165. package/templates/common/.agents/skills/funpixel-gdd/references/first-look.md +226 -0
  2166. package/templates/common/.agents/skills/funpixel-gdd/references/floors.md +62 -0
  2167. package/templates/common/.agents/skills/funpixel-gdd/references/frame.md +75 -0
  2168. package/templates/common/.agents/skills/funpixel-gdd/references/gameplay-contract.md +81 -0
  2169. package/templates/common/.agents/skills/funpixel-gdd/references/gdd-template.md +417 -0
  2170. package/templates/common/.agents/skills/funpixel-gdd/references/genre-card.md +109 -0
  2171. package/templates/common/.agents/skills/funpixel-gdd/references/genre-platformer.md +159 -0
  2172. package/templates/common/.agents/skills/funpixel-gdd/references/genre-puzzle.md +145 -0
  2173. package/templates/common/.agents/skills/funpixel-gdd/references/genre-racing.md +137 -0
  2174. package/templates/common/.agents/skills/funpixel-gdd/references/genre-rpg.md +125 -0
  2175. package/templates/common/.agents/skills/funpixel-gdd/references/genre-shooter.md +128 -0
  2176. package/templates/common/.agents/skills/funpixel-gdd/references/genre-simulation.md +112 -0
  2177. package/templates/common/.agents/skills/funpixel-gdd/references/genre-strategy.md +116 -0
  2178. package/templates/common/.agents/skills/funpixel-gdd/references/genre-survival.md +122 -0
  2179. package/templates/common/.agents/skills/funpixel-gdd/references/in-the-loop.md +106 -0
  2180. package/templates/common/.agents/skills/funpixel-gdd/references/invent-first.md +131 -0
  2181. package/templates/common/.agents/skills/funpixel-gdd/references/level-and-fun.md +112 -0
  2182. package/templates/common/.agents/skills/funpixel-gdd/references/pages.md +47 -0
  2183. package/templates/common/.agents/skills/funpixel-gdd/references/plan-at-size.md +140 -0
  2184. package/templates/common/.agents/skills/funpixel-gdd/references/production-tiers.md +117 -0
  2185. package/templates/common/.agents/skills/funpixel-gdd/references/sections.md +148 -0
  2186. package/templates/common/.agents/skills/funpixel-gdd/references/spec-folder.md +131 -0
  2187. package/templates/common/.agents/skills/funpixel-gdd/references/start.md +110 -0
  2188. package/templates/common/.agents/skills/funpixel-gdd/references/starters.md +175 -0
  2189. package/templates/common/.agents/skills/funpixel-gdd/references/the-path.md +133 -0
  2190. package/templates/common/.agents/skills/funpixel-gdd/references/track.md +29 -0
  2191. package/templates/common/.agents/skills/funpixel-gdd/references/world-and-identity.md +165 -0
  2192. package/templates/common/.agents/skills/funpixel-gdd/references/worth.md +74 -0
  2193. package/templates/common/.agents/skills/funpixel-mobile-ui/SKILL.md +107 -0
  2194. package/templates/common/.agents/skills/funpixel-mobile-ui/references/contrast.md +123 -0
  2195. package/templates/common/.agents/skills/funpixel-mobile-ui/references/hud-and-title.md +108 -0
  2196. package/templates/common/.agents/skills/funpixel-mobile-ui/references/hud-genres.md +124 -0
  2197. package/templates/common/.agents/skills/funpixel-mobile-ui/references/phone-check.md +156 -0
  2198. package/templates/common/.agents/skills/funpixel-mobile-ui/references/recipes.md +279 -0
  2199. package/templates/common/.agents/skills/funpixel-mobile-ui/references/restyle-ui.md +229 -0
  2200. package/templates/common/.agents/skills/funpixel-mobile-ui/references/unity.md +61 -0
  2201. package/templates/common/.agents/skills/funpixel-publish/SKILL.md +109 -0
  2202. package/templates/common/.agents/skills/funpixel-publish/references/compose.md +113 -0
  2203. package/templates/common/.agents/skills/funpixel-publish/references/motion.md +120 -0
  2204. package/templates/common/.agents/skills/funpixel-publish/references/networks.md +75 -0
  2205. package/templates/common/.agents/skills/funpixel-publish/references/other-hosts.md +65 -0
  2206. package/templates/common/.agents/skills/funpixel-publish/references/playable-ad.md +90 -0
  2207. package/templates/common/.agents/skills/funpixel-publish/references/server-build.md +85 -0
  2208. package/templates/common/.agents/skills/funpixel-publish/references/store-shots.md +85 -0
  2209. package/templates/common/.agents/skills/funpixel-publish/references/trailer.md +55 -0
  2210. package/templates/common/.agents/skills/funpixel-publish/references/what-ships.md +30 -0
  2211. package/templates/common/.agents/skills/funpixel-store/SKILL.md +81 -0
  2212. package/templates/common/.agents/skills/funpixel-store/references/app-store.md +73 -0
  2213. package/templates/common/.agents/skills/funpixel-store/references/google-play.md +141 -0
  2214. package/templates/common/.agents/skills/funpixel-store/references/ios-release.md +63 -0
  2215. package/templates/common/.agents/skills/funpixel-store/references/money.md +66 -0
  2216. package/templates/common/.agents/skills/funpixel-store/references/purchases-and-review.md +74 -0
  2217. package/templates/common/.agents/skills/funpixel-store/references/readiness-page.md +24 -0
  2218. package/templates/common/.agents/skills/funpixel-store/references/readiness.md +107 -0
  2219. package/templates/common/.agents/skills/funpixel-store/references/steam.md +38 -0
  2220. package/templates/common/.agents/skills/funpixel-store/references/unity-store.md +55 -0
  2221. package/templates/common/.agents/skills/funpixel-store/references/web-portals.md +43 -0
  2222. package/templates/common/.agents/skills/funpixel-unity-game/SKILL.md +103 -0
  2223. package/templates/common/.agents/skills/funpixel-unity-game/references/agent-ops.md +54 -0
  2224. package/templates/common/.agents/skills/funpixel-unity-game/references/fixes.md +40 -0
  2225. package/templates/common/.agents/skills/funpixel-unity-game/references/from-a-web-game.md +108 -0
  2226. package/templates/common/.agents/skills/funpixel-unity-game/references/handing-off.md +42 -0
  2227. package/templates/common/.agents/skills/funpixel-unity-game/references/performance.md +59 -0
  2228. package/templates/common/.agents/skills/funpixel-unity-game/references/probe.md +80 -0
  2229. package/templates/common/.agents/skills/funpixel-unity-game/references/shared-mac.md +121 -0
  2230. package/templates/common/.agents/skills/funpixel-unity-game/references/traps.md +108 -0
  2231. package/templates/common/.agents/skills/funpixel-verify/SKILL.md +109 -0
  2232. package/templates/common/.agents/skills/funpixel-verify/references/actors.md +94 -0
  2233. package/templates/common/.agents/skills/funpixel-verify/references/bar.md +62 -0
  2234. package/templates/common/.agents/skills/funpixel-verify/references/checks.md +69 -0
  2235. package/templates/common/.agents/skills/funpixel-verify/references/experience.md +67 -0
  2236. package/templates/common/.agents/skills/funpixel-verify/references/eyes.md +54 -0
  2237. package/templates/common/.agents/skills/funpixel-verify/references/fidelity.md +126 -0
  2238. package/templates/common/.agents/skills/funpixel-verify/references/hit-bar.md +31 -0
  2239. package/templates/common/.agents/skills/funpixel-verify/references/journeys.md +77 -0
  2240. package/templates/common/.agents/skills/funpixel-verify/references/mobile-qa.md +123 -0
  2241. package/templates/common/.agents/skills/funpixel-verify/references/playtest.md +161 -0
  2242. package/templates/common/.agents/skills/funpixel-verify/references/review.md +105 -0
  2243. package/templates/common/.agents/skills/funpixel-verify/references/rubric.md +67 -0
  2244. package/templates/common/.agents/skills/funpixel-verify/references/scenes.md +49 -0
  2245. package/templates/common/.agents/skills/funpixel-verify/references/unity.md +60 -0
  2246. package/templates/common/.agents/skills/funpixel-world-and-story/SKILL.md +99 -0
  2247. package/templates/common/.agents/skills/funpixel-world-and-story/references/atmosphere.md +208 -0
  2248. package/templates/common/.agents/skills/funpixel-world-and-story/references/forged-world.md +79 -0
  2249. package/templates/common/.agents/skills/funpixel-world-and-story/references/living-world.md +237 -0
  2250. package/templates/common/.agents/skills/funpixel-world-and-story/references/opening-and-chapters.md +215 -0
  2251. package/templates/common/.agents/skills/funpixel-world-and-story/references/shelf.md +80 -0
  2252. package/templates/common/.agents/skills/funpixel-world-and-story/references/story-at-size.md +159 -0
  2253. package/templates/common/.agents/skills/funpixel-world-and-story/references/voice.md +175 -0
  2254. package/templates/common/.agents/skills/funpixel-world-and-story/references/world-kit.md +154 -0
  2255. package/templates/common/.claude/settings.json +3 -0
  2256. package/templates/common/.harnessignore +28 -0
  2257. package/templates/common/AGENTS.md +135 -0
  2258. package/templates/common/CLAUDE.md +1 -0
  2259. package/templates/common/assets/assets.example.json +9 -0
  2260. package/templates/common/index.html +13 -0
  2261. package/templates/common/src/art/files.mjs +27 -0
  2262. package/templates/common/src/assets.ts +62 -0
  2263. package/templates/common/src/beat.ts +50 -0
  2264. package/templates/common/src/characters.ts +54 -0
  2265. package/templates/common/src/expose.ts +63 -0
  2266. package/templates/common/src/feel.ts +78 -0
  2267. package/templates/common/src/fpx-hooks.ts +46 -0
  2268. package/templates/common/src/frame.ts +63 -0
  2269. package/templates/common/src/grade.ts +47 -0
  2270. package/templates/common/src/hud-kit.css +29 -0
  2271. package/templates/common/src/hud-kit.tsx +85 -0
  2272. package/templates/common/src/hud.tsx +55 -0
  2273. package/templates/common/src/icons.tsx +35 -0
  2274. package/templates/common/src/input.ts +70 -0
  2275. package/templates/common/src/juice.ts +92 -0
  2276. package/templates/common/src/levels.ts +43 -0
  2277. package/templates/common/src/living.ts +91 -0
  2278. package/templates/common/src/look.json +19 -0
  2279. package/templates/common/src/look.ts +54 -0
  2280. package/templates/common/src/main.tsx +31 -0
  2281. package/templates/common/src/markers.ts +60 -0
  2282. package/templates/common/src/motion-sample.ts +71 -0
  2283. package/templates/common/src/motion.ts +92 -0
  2284. package/templates/common/src/pin.ts +32 -0
  2285. package/templates/common/src/platform.ts +67 -0
  2286. package/templates/common/src/pose.ts +22 -0
  2287. package/templates/common/src/probe-human.ts +29 -0
  2288. package/templates/common/src/probe-kit.ts +99 -0
  2289. package/templates/common/src/rules.ts +99 -0
  2290. package/templates/common/src/save.ts +21 -0
  2291. package/templates/common/src/screens.css +34 -0
  2292. package/templates/common/src/screens.tsx +95 -0
  2293. package/templates/common/src/selftests.ts +22 -0
  2294. package/templates/common/src/session.ts +99 -0
  2295. package/templates/common/src/sound.ts +85 -0
  2296. package/templates/common/src/splash-funpixel/OFL.txt +94 -0
  2297. package/templates/common/src/splash-funpixel/card.css +18 -0
  2298. package/templates/common/src/splash-funpixel/card.tsx +22 -0
  2299. package/templates/common/src/splash.css +15 -0
  2300. package/templates/common/src/splash.tsx +86 -0
  2301. package/templates/common/src/store.ts +68 -0
  2302. package/templates/common/src/strike.ts +82 -0
  2303. package/templates/common/src/styles.css +81 -0
  2304. package/templates/common/src/toasts.ts +75 -0
  2305. package/templates/common/src/world.ts +91 -0
  2306. package/templates/common/test/feel.json +36 -0
  2307. package/templates/common/test/platform.test.ts +42 -0
  2308. package/templates/common/test/probes.ts +72 -0
  2309. package/templates/common/test/rules.test.ts +88 -0
  2310. package/templates/common/tsconfig.json +16 -0
  2311. package/templates/common/vite.config.ts +6 -0
  2312. package/templates/pixi/src/character.ts +63 -0
  2313. package/templates/pixi/src/game.ts +99 -0
  2314. package/templates/pixi/src/world-hud.ts +16 -0
  2315. package/templates/spec/common/src/chapters.ts +97 -0
  2316. package/templates/spec/common/src/levels.ts +68 -0
  2317. package/templates/spec/common/src/probe-rooms.ts +63 -0
  2318. package/templates/spec/common/src/room-map.tsx +30 -0
  2319. package/templates/spec/common/src/tune.ts +93 -0
  2320. package/templates/spec/common/test/rooms.test.ts +59 -0
  2321. package/templates/spec/common/test/rooms.ts +53 -0
  2322. package/templates/spec/three-world/test/rooms.ts +54 -0
  2323. package/templates/three/src/character.ts +65 -0
  2324. package/templates/three/src/game.ts +99 -0
  2325. package/templates/three/src/world-hud.ts +22 -0
  2326. package/templates/three-world/src/bot.ts +43 -0
  2327. package/templates/three-world/src/budget.ts +73 -0
  2328. package/templates/three-world/src/camera-rig.ts +99 -0
  2329. package/templates/three-world/src/controls.tsx +49 -0
  2330. package/templates/three-world/src/cutout-atlas.ts +26 -0
  2331. package/templates/three-world/src/cutout-math.ts +47 -0
  2332. package/templates/three-world/src/cutouts.ts +99 -0
  2333. package/templates/three-world/src/dressing-math.ts +98 -0
  2334. package/templates/three-world/src/dressing.ts +84 -0
  2335. package/templates/three-world/src/expose.ts +82 -0
  2336. package/templates/three-world/src/feel.ts +79 -0
  2337. package/templates/three-world/src/game.ts +99 -0
  2338. package/templates/three-world/src/hud.tsx +44 -0
  2339. package/templates/three-world/src/icons.tsx +36 -0
  2340. package/templates/three-world/src/input.ts +73 -0
  2341. package/templates/three-world/src/juice.ts +91 -0
  2342. package/templates/three-world/src/layout.ts +73 -0
  2343. package/templates/three-world/src/light-math.ts +78 -0
  2344. package/templates/three-world/src/light.ts +77 -0
  2345. package/templates/three-world/src/look.json +30 -0
  2346. package/templates/three-world/src/main.tsx +38 -0
  2347. package/templates/three-world/src/models.ts +62 -0
  2348. package/templates/three-world/src/palette.ts +21 -0
  2349. package/templates/three-world/src/places.json +50 -0
  2350. package/templates/three-world/src/places.ts +56 -0
  2351. package/templates/three-world/src/pose.ts +22 -0
  2352. package/templates/three-world/src/post.ts +47 -0
  2353. package/templates/three-world/src/rest-math.ts +29 -0
  2354. package/templates/three-world/src/rules.ts +89 -0
  2355. package/templates/three-world/src/screens.css +45 -0
  2356. package/templates/three-world/src/screens.tsx +96 -0
  2357. package/templates/three-world/src/selftests.ts +25 -0
  2358. package/templates/three-world/src/session.ts +99 -0
  2359. package/templates/three-world/src/shots.ts +59 -0
  2360. package/templates/three-world/src/sky.ts +48 -0
  2361. package/templates/three-world/src/stage.ts +83 -0
  2362. package/templates/three-world/src/styles.css +95 -0
  2363. package/templates/three-world/src/surfaces.ts +55 -0
  2364. package/templates/three-world/src/world.ts +70 -0
  2365. package/templates/three-world/test/feel.json +29 -0
  2366. package/templates/three-world/test/probes.ts +65 -0
  2367. package/templates/three-world/test/resolve.mjs +13 -0
  2368. package/templates/three-world/test/rules.test.ts +81 -0
  2369. package/unity/com.funpixel.probe/Editor/Funpixel.Probe.Editor.asmdef +16 -0
  2370. package/unity/com.funpixel.probe/Editor/Funpixel.Probe.Editor.asmdef.meta +7 -0
  2371. package/unity/com.funpixel.probe/Editor/ProbeBuild.cs +97 -0
  2372. package/unity/com.funpixel.probe/Editor/ProbeBuild.cs.meta +11 -0
  2373. package/unity/com.funpixel.probe/Editor/ReleaseGuard.cs +23 -0
  2374. package/unity/com.funpixel.probe/Editor/ReleaseGuard.cs.meta +11 -0
  2375. package/unity/com.funpixel.probe/Editor.meta +8 -0
  2376. package/unity/com.funpixel.probe/Runtime/Api/Funpixel.Probe.asmdef +14 -0
  2377. package/unity/com.funpixel.probe/Runtime/Api/Funpixel.Probe.asmdef.meta +7 -0
  2378. package/unity/com.funpixel.probe/Runtime/Api/FunpixelProbe.cs +146 -0
  2379. package/unity/com.funpixel.probe/Runtime/Api/FunpixelProbe.cs.meta +11 -0
  2380. package/unity/com.funpixel.probe/Runtime/Api.meta +8 -0
  2381. package/unity/com.funpixel.probe/Runtime/Player/Args.cs +87 -0
  2382. package/unity/com.funpixel.probe/Runtime/Player/Args.cs.meta +11 -0
  2383. package/unity/com.funpixel.probe/Runtime/Player/Boot.cs +67 -0
  2384. package/unity/com.funpixel.probe/Runtime/Player/Boot.cs.meta +11 -0
  2385. package/unity/com.funpixel.probe/Runtime/Player/Bridge.cs +559 -0
  2386. package/unity/com.funpixel.probe/Runtime/Player/Bridge.cs.meta +11 -0
  2387. package/unity/com.funpixel.probe/Runtime/Player/Capture.cs +145 -0
  2388. package/unity/com.funpixel.probe/Runtime/Player/Capture.cs.meta +11 -0
  2389. package/unity/com.funpixel.probe/Runtime/Player/Funpixel.Probe.Player.asmdef +32 -0
  2390. package/unity/com.funpixel.probe/Runtime/Player/Funpixel.Probe.Player.asmdef.meta +7 -0
  2391. package/unity/com.funpixel.probe/Runtime/Player/Inject.cs +127 -0
  2392. package/unity/com.funpixel.probe/Runtime/Player/Inject.cs.meta +11 -0
  2393. package/unity/com.funpixel.probe/Runtime/Player/Json.cs +246 -0
  2394. package/unity/com.funpixel.probe/Runtime/Player/Json.cs.meta +11 -0
  2395. package/unity/com.funpixel.probe/Runtime/Player/Probe.cs +194 -0
  2396. package/unity/com.funpixel.probe/Runtime/Player/Probe.cs.meta +11 -0
  2397. package/unity/com.funpixel.probe/Runtime/Player/Stats.cs +266 -0
  2398. package/unity/com.funpixel.probe/Runtime/Player/Stats.cs.meta +11 -0
  2399. package/unity/com.funpixel.probe/Runtime/Player/UiTargets.cs +134 -0
  2400. package/unity/com.funpixel.probe/Runtime/Player/UiTargets.cs.meta +11 -0
  2401. package/unity/com.funpixel.probe/Runtime/Player.meta +8 -0
  2402. package/unity/com.funpixel.probe/Runtime/link.xml +7 -0
  2403. package/unity/com.funpixel.probe/Runtime/link.xml.meta +7 -0
  2404. package/unity/com.funpixel.probe/Runtime.meta +8 -0
  2405. package/unity/com.funpixel.probe/Tests/Editor/Funpixel.Probe.Tests.asmdef +25 -0
  2406. package/unity/com.funpixel.probe/Tests/Editor/Funpixel.Probe.Tests.asmdef.meta +7 -0
  2407. package/unity/com.funpixel.probe/Tests/Editor/StatsTests.cs +147 -0
  2408. package/unity/com.funpixel.probe/Tests/Editor/StatsTests.cs.meta +11 -0
  2409. package/unity/com.funpixel.probe/Tests/Editor/WireTests.cs +86 -0
  2410. package/unity/com.funpixel.probe/Tests/Editor/WireTests.cs.meta +11 -0
  2411. package/unity/com.funpixel.probe/Tests/Editor.meta +8 -0
  2412. package/unity/com.funpixel.probe/Tests.meta +8 -0
  2413. package/unity/com.funpixel.probe/package.json +14 -0
  2414. package/unity/com.funpixel.probe/package.json.meta +7 -0
package/dist/cli.js ADDED
@@ -0,0 +1,2917 @@
1
+ import { existsSync, realpathSync } from 'node:fs';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { verify, EXIT } from "./commands/verify.js";
4
+ import { init } from "./commands/init.js";
5
+ import { publish, TARGETS } from "./commands/publish.js";
6
+ import { store, STORE_SUBCOMMANDS } from "./commands/store.js";
7
+ import { doctor, doctorHost } from "./commands/doctor.js";
8
+ import { HOSTS } from "./doctor/host.js";
9
+ import { check } from "./commands/check.js";
10
+ import { discardOffers, upgrade, upgradeSelf } from "./commands/upgrade.js";
11
+ import { dev } from "./commands/dev.js";
12
+ import { parseBots } from "./relay/bots.js";
13
+ import { pack } from "./commands/pack.js";
14
+ import { exportCmd } from "./commands/export.js";
15
+ import { smoke } from "./commands/smoke.js";
16
+ import { test } from "./commands/test.js";
17
+ import { sim } from "./commands/sim.js";
18
+ import { isSimVerb, simulator } from "./commands/simulator.js";
19
+ import { unity } from "./commands/unity.js";
20
+ import { unityPlayer } from "./commands/unity-player.js";
21
+ import { unityBridge, unityEditor } from "./commands/unity-editor.js";
22
+ import { depth } from "./commands/depth.js";
23
+ import { reach } from "./commands/reach.js";
24
+ import { world, WORLD_ACTIONS } from "./commands/world.js";
25
+ import { life } from "./commands/life.js";
26
+ import { walk } from "./commands/walk.js";
27
+ import { compareTakes } from "./commands/compare-takes.js";
28
+ import { printFixes, score } from "./commands/score.js";
29
+ import { wow } from "./commands/wow.js";
30
+ import { framing } from "./commands/framing.js";
31
+ import { boxes } from "./commands/boxes.js";
32
+ import { places } from "./commands/places.js";
33
+ import { hook } from "./commands/hook.js";
34
+ import { feel } from "./commands/feel.js";
35
+ import { lookSheet } from "./commands/look-sheet.js";
36
+ import { gdd } from "./commands/gdd.js";
37
+ import { greenlight, GREENLIGHT_SUBCOMMANDS } from "./commands/greenlight.js";
38
+ import { browserLogin, login, logout, whoami } from "./commands/login.js";
39
+ import { budget, usage } from "./commands/account.js";
40
+ import { estimateCommand, gen } from "./commands/gen.js";
41
+ import { models, MODELS_SUBCOMMANDS } from "./commands/models.js";
42
+ import { assets, SUBCOMMANDS as ASSETS_SUBCOMMANDS } from "./commands/assets.js";
43
+ import { cast, CAST_SUBCOMMANDS } from "./commands/cast.js";
44
+ import { character } from "./commands/character.js";
45
+ import { job } from "./commands/job.js";
46
+ import { jobs } from "./commands/jobs.js";
47
+ import { optimize } from "./commands/optimize.js";
48
+ import { playable } from "./commands/playable.js";
49
+ import { reel, REEL_LIMITS } from "./commands/reel.js";
50
+ import { trailer, TRAILER_LIMITS } from "./commands/trailer.js";
51
+ import { formatsFor, SAFE } from "./trailer/placement.js";
52
+ import { model } from "./commands/model.js";
53
+ import { fidelity } from "./commands/fidelity.js";
54
+ import { auditScreens, BURST, capture, scene } from "./commands/look.js";
55
+ import { captureAll } from "./commands/capture-all.js";
56
+ import { compare } from "./commands/compare.js";
57
+ import { compareTarget, pairTargets } from "./commands/compare-target.js";
58
+ import { parts, parseGrid, parseKey } from "./commands/parts.js";
59
+ import { cutDefaults } from "./commands/cut.js";
60
+ import { lookRead } from "./commands/look-read.js";
61
+ import { look3d } from "./commands/look-3d.js";
62
+ import { HUD_SAMPLING, lookHud } from "./commands/look-hud.js";
63
+ import { lookTheme, THEME_SUBCOMMANDS } from "./commands/look-theme.js";
64
+ import { playtest, PLAYTEST_SUBCOMMANDS } from "./commands/playtest.js";
65
+ import { playtestHosted } from "./playtest/hosted.js";
66
+ import { mobileQa } from "./commands/mobile-qa.js";
67
+ import { lookFit } from "./commands/look-fit.js";
68
+ import { journey, JOURNEY_SUBCOMMANDS } from "./commands/journey.js";
69
+ import { profile, PROFILE_LIMITS } from "./commands/profile.js";
70
+ import { inspect } from "./commands/inspect.js";
71
+ import { phone } from "./commands/phone.js";
72
+ import { clip } from "./commands/clip.js";
73
+ import { judge, JUDGE_SUBCOMMANDS } from "./commands/judge.js";
74
+ import { lessons } from "./commands/lessons.js";
75
+ import { variety } from "./commands/variety.js";
76
+ import { pitch, PITCH_SUBCOMMANDS } from "./commands/pitch.js";
77
+ import { widen } from "./commands/widen.js";
78
+ import { loudness } from "./commands/loudness.js";
79
+ import { zero } from "./commands/zero.js";
80
+ import { review } from "./commands/review.js";
81
+ import { motion, MOTION_SUBCOMMANDS } from "./commands/motion.js";
82
+ import { compose, COMPOSE_SUBCOMMANDS } from "./commands/compose.js";
83
+ import { boardRun } from "./status/board.js";
84
+ import { beats } from "./commands/beats.js";
85
+ import { schema } from "./commands/schema.js";
86
+ import { loop, LOOP_LIMITS } from "./commands/loop.js";
87
+ import { directions } from "./commands/directions.js";
88
+ import { board, BOARD_SUBCOMMANDS } from "./commands/board.js";
89
+ import { feedback } from "./commands/feedback.js";
90
+ import { note, NOTE_SUBCOMMANDS } from "./commands/note.js";
91
+ import { owner, OWNER_SUBCOMMANDS } from "./commands/owner.js";
92
+ import { firstlook, FIRSTLOOK_SUBCOMMANDS } from "./commands/firstlook.js";
93
+ import { flow, FLOW_SUBCOMMANDS } from "./commands/flow.js";
94
+ import { spec, SPEC_SUBCOMMANDS } from "./commands/spec.js";
95
+ import { roomsCommand } from "./commands/rooms.js";
96
+ import { lanes, LANES_SUBCOMMANDS } from "./commands/lanes.js";
97
+ import { pick, PICK_SUBCOMMANDS } from "./commands/pick.js";
98
+ import { progress, PROGRESS_SUBCOMMANDS } from "./commands/progress.js";
99
+ import { journal } from "./commands/journal.js";
100
+ import { decide } from "./commands/decide.js";
101
+ import { DEFAULTS as PLAY_DEFAULTS, play, PLAY_SUBCOMMANDS } from "./commands/play.js";
102
+ import { STEP_LIMITS as PLAY_STEP_LIMITS } from "./play/steps.js";
103
+ import { FRONT_DOOR } from "./look/look.js";
104
+ import { GEN_FLAGS } from "./gen/kinds.js";
105
+ import { ENGINES, VIEWPORT_CHOICES } from "./verify/browser.js";
106
+ import { ui } from "./ui.js";
107
+ import { versionLine } from "./update.js";
108
+ export const USAGE = `usage:
109
+ funtools init [dir] [--framework pixi|three-world|three] [--name "Title"] [--idea "one line"] [--bare] [--offline] [--no-git]
110
+ funtools init "<one line: the game you want>" [--framework pixi|three-world|three] [--name "Title"] [--offline] [--no-git]
111
+ funtools dev [dir] [--no-devtools] [--relay [--bots 1-15] [--no-hold]] [--phone [--host address]] [--open]
112
+ funtools serve [dir] [--port 5794] [--host address] [--no-compress]
113
+ funtools open <url|file>
114
+ funtools find "<what you want to do>" [--json]
115
+ funtools mcp
116
+ funtools setup [--host claude|cursor|codex|kiro|robin|all] [--dry-run] [--json]
117
+ funtools doctor [dir] [--add-hooks]
118
+ funtools doctor --host [claude|codex|cursor|kiro] [dir] [--json]
119
+ funtools upgrade [dir] [--discard] | upgrade --self
120
+ funtools smoke [dir] [--json]
121
+ funtools smoke-build <fresh-folder> --plan <folder with design/> [--json]
122
+ funtools test [dir] [--node] [--goals] [--json]
123
+ funtools check [dir] [--viewport desktop|phone|both] [--phone] [--front-door | --click selector] [--no-test] [--no-idle] [--world | --no-world] [--json]
124
+ funtools sim [dir] [--script test/probes.ts] [--timeout 300] [--json]
125
+ funtools sim lease [--device "iPhone 17 Pro"] [--runtime "iOS 26.5"] [--no-boot] [--owner pid] [--json] | sim release <udid> [--force]
126
+ | sim list [--json] | sim gc [--dry-run] [--json]
127
+ | sim shot <udid> [--orientation portrait|landscape|landscape-left|landscape-right] [--app bundle-id] [--out file] [--json]
128
+ | sim tap <udid> x y [--points] [--orientation …] [--app bundle-id] [--tool baguette|idb] [--json]
129
+ funtools unity run [--project dir] [--unity bin] [--log file] [--no-quit] [--max 2] [--stale-minutes 20] [--max-wait minutes] -- <unity args>
130
+ | unity jobs [--json] | unity gc [roots…] [--days 14] [--yes] [--json]
131
+ | unity gc --disk [roots…] [--below 20] [--days 2] [--only worktrees,target,derived-data,unity,scratch,context] [--apply] [--strict] [--json]
132
+ | unity probe [--project dir] [--target mac|sim] [--path script.json] [--seconds N] [--tier phone|tablet|mac] [--budget file|json]
133
+ [--player App.app] [--rebuild] [--no-build] [--port N] [--udid U] [--device name] [--visible] [--sound] [--out file] [--json]
134
+ [--player-args file] [-- <the game's own launch arguments>] (probe, play and capture alike)
135
+ [--strict] (the kit's starting points judge as budgets: a release gate; without it only --budget's numbers fail)
136
+ | unity probe install [--project dir] [--from folder | --git url --ref ref] [--absolute] [--tests] [--force] [--dry-run] | unity probe uninstall
137
+ | unity play start|end|status | play tap x y|<name> | drag x1 y1 x2 y2 [ms] | key <name> | pad <button> | state | ui | views
138
+ | view <name> | scene <name> | shot [--out f.png] | record [--seconds 5] [--out dir] | act "<step>" … | send '<json>' [--points] [--mouse]
139
+ | unity capture --all [--project dir] [--target mac|sim] [--out dir] [--settle-ms 1000] [--dev] [--json]
140
+ | unity bridge status|install|remove [--project dir]
141
+ | unity editor console|compile|play|stop|shot|menu|call|hierarchy|add|save|open|close [--project dir] [--open]
142
+ funtools spec [lint] [dir] [--spec design/spec] [--tier mid|deep] [--json] | spec init [dir] [--tier mid|deep] [--json]
143
+ funtools rooms [dir] [--script test/rooms.ts] [--timeout 300] [--json] | rooms open <room> [dir] [--by owner] ["words"] [--json]
144
+ | rooms plan [dir] [--by owner] [--json]
145
+ funtools depth [dir] [--out dir] [--place field] [--tension field] [--progress field] [--fill] [--json]
146
+ funtools reach [dir] [--level file,…] [--json]
147
+ funtools world forge [--seed N] [--rooms N] [--kind 2d|3d] [--from GDD.md|brief.json] [--variety N] [--force]
148
+ [--dir game] [--json] | world check [--dir game] [--json]
149
+ funtools feel [dir] [--script test/feel.json | --journey name] [--no-sweep] [--engine chromium|webkit] [--json]
150
+ funtools gdd [lint] [dir|file.md] [--sources] [--strict] [--json] | gdd page [dir] [--json]
151
+ funtools greenlight [dir] | greenlight page
152
+ | greenlight lock --version v1.0 [--override "why"] [--dir game] [--json]
153
+ | greenlight worth [dir] [--target <min> --by owner] | greenlight worth choose <option> --why "…"
154
+ funtools verify [dir|url] [--viewport desktop|phone|both] [--watch] [--checks file.json]
155
+ [--manifest funpixel.json] [--no-sweep] [--front-door | --click selector]
156
+ [--engine chromium|webkit] [--json | --report]
157
+ funtools verify [dir] --players 2 [--json]
158
+ funtools capture [dir|url] [--view name | --all] [--verbs a,b] [--hold ms] [--burst frames]
159
+ [--viewport desktop|phone [--orientation portrait|landscape] [--safari]]
160
+ [--front-door | --click selector] [--out file.png] [--engine chromium|webkit]
161
+ [--seed n | --free-running] [--json]
162
+ funtools compare [dir] [--baseline] [--json]
163
+ funtools compare [dir|url] --target picture[,picture…] [--view name[,name…]] [--viewport phone|desktop|both]
164
+ [--fit contain|cover] [--verbs a,b] [--hold ms] [--front-door | --click selector] [--out dir|file.png]
165
+ [--seed n | --free-running] [--json]
166
+ funtools parts <sheet.png|jpg|webp> [--grid CxR | --boxes boxes.json] [--names a,b,c] [--key auto|none|paper|#rrggbb]
167
+ [--pivot bottom|top|center] [--pad 2] [--merge 6] [--clean [--keep-shadows]] [--webp] [--out dir] [--json]
168
+ funtools cut <sheet.png|jpg|webp> [--grid CxR | --boxes boxes.json] [--names a,b,c] [--keep-shadows]
169
+ [--pivot bottom|top|center] [--pad 2] [--merge 6] [--webp] [--out dir] [--json]
170
+ funtools audit-screens [dir|url] [--views a,b] [--viewport desktop|phone [--orientation portrait|landscape]]
171
+ [--front-door | --click selector] [--json]
172
+ funtools scene [dir|url] [--view name] [--verbs a,b] [--hold ms] [--viewport desktop|phone [--orientation portrait|landscape]]
173
+ [--motion] [--front-door | --click selector] [--json]
174
+ funtools hook [dir|url] [--seconds n] [--verbs a,b | --idle] [--viewport desktop|phone [--orientation portrait|landscape]]
175
+ funtools life [dir|url] [--view name] [--moment name] [--viewport desktop|phone [--orientation portrait|landscape]]
176
+ [--front-door | --click selector] [--json]
177
+ funtools walk [dir|url] [--route name,… | --chain a,b] [--seconds n] [--no-film] [--viewport desktop|phone [--orientation portrait|landscape]]
178
+ [--json]
179
+ funtools score [dir|url] [--target picture --view name [--hero id] [--hero-share 0.2] [--capture shot.png]]
180
+ [--viewport desktop|phone] [--no-judge] [--seed n | --free-running] [--json]
181
+ funtools score [dir] --fixes [--json]
182
+ funtools framing [dir|url] [--actors id,…] [--view name] [--viewport desktop|phone] [--json]
183
+ funtools boxes [dir|url] [--view name,…] [--viewport desktop|phone [--orientation portrait|landscape]]
184
+ [--front-door | --click selector] [--json]
185
+ funtools places [dir|url] [--view name,…] [--viewport desktop|phone] [--json]
186
+ funtools compare-takes <takeA> <takeB> [--names A,B] [--route name,…] [--viewport desktop|phone]
187
+ [--seconds n] [--no-score] [--out dir] [--json]
188
+ funtools profile [dir|url] [--views a,b] [--viewport desktop|phone] [--seed n] [--frames 120]
189
+ [--settle ms] [--software] [--throttle 4] [--repeat 3] [--against profile.json]
190
+ [--compare [--budget 18]] [--front-door | --click selector] [--json]
191
+ funtools inspect [dir] [--at x,y | --name label] [--tree] [--url http://localhost:5317] [--view name]
192
+ [--verbs a,b] [--settle ms] [--viewport desktop|phone [--orientation portrait|landscape]]
193
+ [--front-door | --click selector] [--json]
194
+ funtools clip [dir] [--frames dir] [--fps 12] [--seats player,animator] [--json] | clip report [--dir game] [--json]
195
+ funtools judge structure <picture|folder…> [--prompt "what it should be"] [--dir game] [--json]
196
+ funtools judge identity <model.glb | view pictures|folder…> [--concept concept.png] [--medium model|sprites]
197
+ [--dir game] [--json] | judge report [n] [--dir game] [--json]
198
+ funtools phone [dir|url] [--sim "iPhone 17 Pro"|udid] [--orientation portrait|landscape] [--seconds 6]
199
+ [--taps "25%,80% 75%,80%"] [--swipes "right up"] [--keep] [--out dir] [--json]
200
+ funtools look [dir|url|capture.png] --read [--view name] [--viewport desktop|phone] [--hold ms]
201
+ [--player regex] [--threats regex] [--colours player=#hex,threat=#hex]
202
+ [--front-door | --click selector] [--json]
203
+ funtools look [dir|url] --hud [--view name] [--verbs a,b] [--samples 8] [--every ms]
204
+ [--viewport desktop|phone [--orientation portrait|landscape]] [--front-door | --click selector] [--json]
205
+ funtools look [dir|url] --fit [--view name] [--front-door | --click selector] [--json]
206
+ funtools look [dir] --sheet [--sprites dir,file…] [--sizes 24,48,96] [--ground #hex] [--out file.png] [--json]
207
+ funtools look set <token=value …> [--dir game] [--json] | look patch <file.json> [--dir game] [--json] | look report [dir] [--json]
208
+ funtools play [dir|url] [--viewport desktop|phone [--orientation portrait|landscape]] [--rounds 3] [--long minutes] [--engine chromium|webkit] [--json]
209
+ funtools play act [--look] "<step>" … | play look | play note "<what you saw>" | play check <file.json|-> | play report <file.json|->
210
+ | play end | play status (each takes [--round N] [--dir game]: the round play printed;
211
+ needed when two rounds are open in one folder, e.g. a blind pair)
212
+ play report --round N --refile <file> file a corrected report into a closed round (ended or filed); the earlier one is kept
213
+ [--dir game] [--json]
214
+ funtools journey [--dir game] | journey record <name> [--viewport desktop|phone [--orientation portrait|landscape]]
215
+ [--seed n] [--seconds 120] [--force] | journey from-play <round|last> <name> [--seed n] [--force]
216
+ funtools journey replay <name> [--repeat 1-3] [--against run] [--dir game] [--engine chromium|webkit] [--json] | journey diff <name> [a] [b] [--json]
217
+ funtools playtest [dir] [--quick] [--versus <evidence dir>|none] [--no-build] [--long minutes] [--phone [--sim name]] [--hosted [--yes]] [--json]
218
+ funtools playtest experience | report | status [--dir game] [--cost-usd n] [--min-score 6.5] [--json]
219
+ funtools playtest keep [--dir game] [--drop K<n> --by owner "<their words>"] [--json]
220
+ funtools mobile-qa [dir] [--phone [--sim name|udid]] [--no-build] [--json] | mobile-qa report [--dir game] [--json]
221
+ funtools lessons [--genre g] [--dir game] [--json]
222
+ funtools lessons add "<finding>" --fix "<what fixed it>" [--source panel|player|verify|look]
223
+ [--delta 0.4] [--share] [--dir game] [--json]
224
+ funtools lessons motif [--dir game] [--json]
225
+ funtools variety [dir] [--within] [--json]
226
+ funtools wow [dir] [--genre card] [--json] | wow pick <move-id> [--signature] [--expression "…"] [--why "…"] [--check "event name"|"frame view"] [--dir d] | wow check [dir]
227
+ funtools pitch [show|propose|pick|ask|lock] [<choice> <option[,option]>] [--why "…"] [--label "…"] [--picture path]
228
+ [--cost "…"] [--note "the person's words"] [--dir game] [--json]
229
+ funtools pitch widen [--seed N] [--dial tight|open|wide] [--brief "…"] | widen score [--text "…"] | widen keep <card>
230
+ [--dir game] [--json]
231
+ funtools loudness [files or folders…] [--dir game] [--json]
232
+ funtools beats [tracks or folders…] [--meter 4] [--dir game] [--json]
233
+ funtools schema [dir] [--strict] [--json]
234
+ funtools loop <video|frames folder> [--fps 12] [--min 6] [--max 24] [--size 256] [--key auto|none|#rrggbb]
235
+ [--name walk] [--out file.png] [--dir game] [--json]
236
+ funtools directions <render folder> [--dirs 8|4] [--size 128] [--key auto|none|#rrggbb] [--reverse]
237
+ [--name hero] [--out file.png] [--dir game] [--json]
238
+ funtools board [show|search "<words>"|wander <ref>|add <link|file>] [--keep 1,3] [--lends palette,light]
239
+ [--note "…"] [--licence "…"] [--by name] [--title "…"] [--limit 12] [--any-licence]
240
+ [--dir game] [--json]
241
+ funtools journal ["<what you changed>" [--why "<why>"] [--by name] [--files a,b] [--values k=v,k=v]]
242
+ [--dir game] [--json]
243
+ funtools decide ["<choice>" --because "<reason>" [--over "<alternative>"] [--supersedes D3]]
244
+ | decide --from N<n> ["<the decision>"] [--touches look,src/hud.tsx] [--dir game] [--json]
245
+ funtools lanes [status] | lanes plan [--stage s] [--lanes play,look,audio|room-2|rooms] [--cap usd] [--timebox min]
246
+ | lanes brief|start|done|gate|sync|merge <id> | lanes start --all [--by name]
247
+ | lanes checkpoint <id> --line "…" [--shot png] [--cost usd] [--minutes n] [--final]
248
+ | lanes verdict <id> pass|fail --by <seat> ["words"] | lanes report | lanes cap <id> <usd> --by owner
249
+ | lanes drop <id> --by owner [--dir game] [--json]
250
+ funtools pick [list] | pick <topic> <a.png> <b.png> [c.png] [--lane id] [--question "…"]
251
+ | pick choose <topic|Q> <option> --by owner ["words"] [--dir game] [--json]
252
+ funtools status [dir] [--json] (flow's status: where the run is and the one next step)
253
+ funtools zero [dir] [--json] (the zero board: errors, overlaps, seams, frame time, round by round)
254
+ funtools review [file|folder…] [--dir project] [--loop] [--still] [--freeze s] [--triangles n]
255
+ [--size WxH] [--alpha] [--lufs n] [--json] (the zero board for any trade's media)
256
+ funtools flow [dir] | flow start [dir] --idea "<the game in a line>" [--autonomy plan-then-go|ask|go] [--budget <credits>|open|free|code-drawn] [--rounds n]
257
+ [--framework f] [--name t] [--bare] [--offline] [--no-git] | flow ask [dir]
258
+ | flow agree [dir] --by owner ["words"] | flow round [dir] | flow look [dir] | flow drop [dir] --by owner "<the owner's words>" [--json]
259
+ funtools note [list] | note ["<the owner's words>"] | note add "<words>" [--stage <stage>] [--screenshot path] [--by owner|agent] [--hold]
260
+ | note close <N> --evidence <path|sha|test> | note close <N> --by owner --force ["words"] | note verdict <N|stage> accept|reject ["words"]
261
+ [--dir game] [--json]
262
+ funtools owner [list] [dir] | owner add "<line>" [--repo dir] | owner remove <n|id> [--repo dir] | owner seed
263
+ | owner apply <n|id> [--dir game] | owner skip <n|id> ["why"] [--dir game] [--json]
264
+ funtools firstlook [dir] | firstlook skip <item> --by owner "<their words>" | firstlook need <item>
265
+ | firstlook render [dir] [--page design/first-look/draw.html] [--dir game] [--json]
266
+ funtools progress [status] | progress card --line "<what changed>" [--stage s] [--shot path|last] [--clip path]
267
+ [--next "…"] [--spent n] [--evidence verify.json|file] [--decision "a; b"] [--out "a; b"] [--standin "a; b"]
268
+ | progress heartbeat --tried "…" [--shot path|last] [--stage s]
269
+ | progress ask "<question>" --kind taste|spend|scope --options a,b [--default a] [--timeout 10m]
270
+ | progress answer <Q> <option> ["words"] | progress wait [Q] [--for 15m] | progress report
271
+ [--dir game] [--json]
272
+ funtools feedback collect <folder…> [--out report.md] [--propose] [--html page.html] [--json]
273
+ funtools feedback log "<what happened>" [--kind step|test|dead-end|lesson|decision|worked|didnt|owner]
274
+ [--metric name --before n --after n --unit u] [--evidence path] [--film path] [--sha commit]
275
+ [--test name] [--cost-usd n] [--minutes n] [--minutes-lost n] [--tool name] [--stage s]
276
+ [--verdict pick|reject|note] [--screenshot path] [--dir game] [--json]
277
+ funtools feedback ab "<game>" --routes a,b [--overall 7.0,8.0] [--axes "story=7.0/8.7,…"] [--winner b]
278
+ [--judges "3 blind seats"] [--what "…"] [--evidence path] [--dir game] [--json]
279
+ funtools feedback merged [--sha ref] [--dir game] [--json]
280
+ funtools pack [dir] [--dry-run] [--no-build] [--json] [--out file.tar.gz]
281
+ funtools export <dest> [--dir game] [--check] [--no-browser] [--strip-metadata] [--json]
282
+ funtools gen <image|texture|strip|sprite|edit|sheet|sound|music|model3d|skybox|find-material|material|video|
283
+ inspect|optimize-model|fracture|lod|rig|render|finalize|level|skin|retexture|motion|retarget>
284
+ ["prompt"] [options]
285
+ [--out path | --unity <project>]
286
+ [--cast <id>] [--no-wait] [--yes] [--strip-title] [--json]
287
+ funtools character list [--medium 2d|3d] [--body biped|quadruped|flyer] [--json]
288
+ funtools character get <id> [--files a,b] [--out dir] [--json]
289
+ funtools character restyle <id> "the new look" [--game-id id] [--animations idle,walk]
290
+ [--palette #hex,…] [--quality low|medium|high] [--yes] [--json]
291
+ funtools estimate <kind> ["prompt"] [options] [--json]
292
+ funtools models list [--json] | models install <local id> [--force] [--json]
293
+ funtools assets status [--dir game] [--json]
294
+ funtools assets gen [--only a,b] [--family f] [--stale] [--max-credits n] [--batch n] [--dry-run] [--yes]
295
+ [--dir game] [--json]
296
+ funtools assets regen <name> --because "what was wrong" [--dry-run] [--yes] [--dir game] [--json]
297
+ funtools assets process [--only a,b] [--dir game] [--json]
298
+ funtools assets pixels [file.png…] [--snap] [--dir game] [--json]
299
+ funtools assets script [--write] [--from design/GDD.md] [--dir game] [--json]
300
+ funtools assets budget [<credits>] [--by owner] [--dir game] [--json]
301
+ funtools cast add <id> --master <png> --pins "the design in words" [--turnaround <png>] [--name N]
302
+ [--kind character|creature|structure|vehicle|prop] [--features "a;b"] [--may-change "…"]
303
+ [--moves] [--by owner] [--dir game] [--json]
304
+ funtools cast list [--dir game] [--json]
305
+ funtools cast check <id> <picture…> [--mode same|pose] [--dir game] [--json]
306
+ funtools job <id> [--wait] [--out path] [--json]
307
+ funtools jobs [--tool name] [--status queued|running|succeeded|failed|cancelled] [--limit 1-100]
308
+ [--cursor c] [--refusals] [--json]
309
+ funtools optimize [dir] [--check] [--json]
310
+ funtools optimize <compress|pack-atlas|unpack-atlas|pack-strip|optimize-mesh> <path…>
311
+ [--dir game] [--max-size px] [--format keep|png|jpeg] [--quantize]
312
+ [--padding px] [--pot] [--no-trim] [--frame-size px] [--out path]
313
+ [--out-dir dir] [--levels phone,desktop,high] [--class character|prop|set_piece|…]
314
+ [--write] [--json]
315
+ funtools playable [dir] --network applovin|unity|ironsource|mintegral|google|meta|tiktok
316
+ [--no-play] [--json]
317
+ funtools trailer [dir|url] [--seconds 30] [--fps 15] [--formats 16x9,9x16,1x1,4x5 | --for tiktok,feed,store]
318
+ [--viewport desktop|phone]
319
+ [--music file | --no-music] [--no-sfx] [--title "Name"] [--key-art file] [--logo file]
320
+ [--cta "Play free"] [--intro clip.mp4] [--outro clip.mp4] [--out dir] [--json]
321
+ funtools reel [dir|url] [--seconds 12] [--fps 12] [--viewport desktop|phone]
322
+ [--frames-only] [--out file.mp4] [--json]
323
+ funtools motion render <scene.html|folder> [--fps 30|60] [--seconds n | --frames n]
324
+ [--size 1080x1920 | --aspect 9:16|16:9|1:1|4:5] [--out dir] [--webm] [--audio file]
325
+ [--prove] [--seed n] [--json]
326
+ | motion check <render folder|scene> [--prove] [--json] | motion new <name> [--aspect 9:16] [--dir folder]
327
+ funtools compose new <trailer|post|endcard> [dir] [--name n] [--aspect 16:9|9:16|1:1] [--seconds n] [--force] [--json]
328
+ funtools compose <check|render> <composition.html> [--dir game] [--aspect 16:9|9:16|1:1] [--seconds n] [--fps 30]
329
+ [--quality draft|standard|high] [--software] [--out file.mp4] [--json]
330
+ funtools compose variations [design/compose/ads.json] [--dir game] [--max 12] [--dry-run] [--fps 30]
331
+ [--quality draft|standard|high] [--software] [--out dir] [--json]
332
+ funtools model <inspect|render|finalize|skin> <asset-id|model file gen saved> [--frames 1-12]
333
+ [--size px] [--keep-clips Idle,Walk] [--tone #rrggbb] [--out path] [--json]
334
+ funtools model retexture <asset-id|model file> "new look" [--palette #a,#b] [--game-id id]
335
+ [--quality low|medium|high] [--roughness] [--normal] [--out path] [--json]
336
+ funtools model level <spec.json> [--size 256-1024] [--out path] [--json]
337
+ funtools model --local <inspect|normalize|decimate|render|finalize> <model.glb|gltf|fbx>
338
+ [--out path] [--target-triangles n] [--height-m m] [--frames 1-12]
339
+ [--size px] [--keep-clips Idle,Walk] [--json]
340
+ funtools model --local level <spec.json> [--out file.glb] [--size 256-1024] [--json]
341
+ funtools model clips <model.glb|gltf> [--json]
342
+ funtools fidelity <model.glb> name=ref.png [name=ref.png …] [--renders dir] [--out dir] [--size px]
343
+ [--own-axes] [--roll] [--outline] [--quarter-turns] [--same-scale] [--min pct] [--json]
344
+ funtools login [--key fp_live_…|-] [--api <url>] [--scope a,b]
345
+ funtools whoami
346
+ funtools --version | -v | version
347
+ funtools usage [--days 1-92] [--this-key] [--json]
348
+ funtools budget [--json]
349
+ funtools logout
350
+ funtools publish [dir] [--target funpixel|itch|pages|folder] [--yes] [--json]
351
+ funpixel: [--name "Title"] [--game-id id]
352
+ itch: --itch user/game[:channel] pages: [--project name] folder: --out dir
353
+ funtools store init|doctor|lint [dir] [--store play|ios|steam] [--json] | store plan [dir] [--store play|ios] [--json]
354
+
355
+ init write a new game the platform builds as-is, with its agent files; with an
356
+ API key it also mints the game's id on the server (--offline skips that).
357
+ One line (--idea, or a first argument with spaces) picks the closest starter,
358
+ each pick with its reason: the engine (3D words → Three), the genre recipe
359
+ (the GDK's cards), how a phone holds it, a folder and a working title; it seeds
360
+ design/GDD.md with the line as the pitch. Flags and your edits override all of it.
361
+ Into a folder with an owner's design/plan.md: the plan sizes the tier, the planning
362
+ stages it answers start done, nothing in design/ is overwritten. --bare writes the
363
+ spine only (hooks, safe band, platform, save, sound, store, look, probes) and a
364
+ game.ts that opens the engine: no demo round to move aside. The new game is its own
365
+ git repository with a first commit (skipped inside an existing repository;
366
+ --no-git skips it): push it to a remote so it survives this machine
367
+ setup the kit into your agent in one command: the package's plugin builds copied to
368
+ ~/.funpixel/plugins/<version>, then installed into each host found (or the one named): Claude Code
369
+ (its plugin marketplace and install), Cursor (its local plugins folder), Kiro (the installer), and
370
+ the one step Codex and Robin take in their apps. --dry-run says every step and runs none. Never
371
+ writes a key: funtools login is next
372
+ exit 0 set up · 1 a step failed or no host found · 3 error
373
+ mcp funtools as a local MCP server over stdio, for a host with no shell (Robin, a desktop chat app): the
374
+ path as tools (flow, find, flow_start, flow_ask, flow_agree, flow_round, flow_look, check, verify, test, sim, capture,
375
+ compare, score, the asset steps, gen, notes, progress_card, reel, compose_video, ad_variations), dev (starts the preview, returns its
376
+ address), image (a picture into the chat) and run (the rest of the toolbox). Never publish, login or
377
+ logout: the person runs those. Started by the host: command funtools, arguments mcp
378
+ find search the kit for an ask in plain words: the three skills to read and the five commands that fit
379
+ best, each with the words that matched. Read-only and offline
380
+ exit 0 found · 2 nothing matched · 3 error
381
+ serve a Unity WebGL build (a folder with index.html, or a Unity project's Builds/WebGL) on this Mac
382
+ and on a phone on the same Wi-Fi, with its LAN address and a QR code: Brotli files go as
383
+ Brotli only to a browser that accepts it on localhost or https, and as gzip made from the
384
+ same bytes to anything else (a phone on http://<LAN address> refuses Brotli:
385
+ ERR_CONTENT_DECODING_FAILED); .gz as gzip; .wasm as application/wasm, .data as
386
+ application/octet-stream. Plain compressible files (Addressables bundles, .wasm/.json/.data
387
+ with no .br/.gz twin, .js, .css, .html, .svg, .txt, everything in StreamingAssets/aa but
388
+ media) are compressed on the fly as a CDN would, Brotli or gzip by the same rule, so what a
389
+ page fetches here weighs what it would live; never images, audio or video; a Range request
390
+ gets the bytes as stored. --no-compress sends files as stored (the raw weight). Binds every
391
+ interface (--host 127.0.0.1 keeps it on this Mac); runs until Ctrl-C, then says what it sent
392
+ exit 0 stopped · 3 no build there, or the port is taken
393
+ open open a URL or a file (a target frame, a clip) on the owner's screen with the system's opener; a host with
394
+ its own browser (Cursor, Codex) shows it there instead. Nothing opens in CI or with FUNPIXEL_NO_OPEN
395
+ exit 0 opened · 2 nothing opens here · 3 error
396
+ dev the game's Vite dev server, with the platform's inspector and profiler; --open opens the preview
397
+ in the owner's browser, in its own tab, once it is up;
398
+ --relay also runs a local relay: open /__funpixel/play in two tabs to play
399
+ the game's dev room (needs the funpixel-relay binary and a Redis);
400
+ --bots N seats N headless bot players there first, each playing through the
401
+ game's __FPX_VERBS__ (else its __FPX_KEYS__, else taps) until you stop dev;
402
+ a full reload is held while two or more pages are in the room, so a save never
403
+ ends the match being tested (--no-hold sends each at once);
404
+ --phone serves it on this Mac's local-network address and prints a QR code: the
405
+ game on your real phone, rebuilt live (off by default: it exposes the dev server
406
+ to the network; --host 0.0.0.0 binds every interface)
407
+ doctor static checks: will the platform build it, can verify measure it;
408
+ a Unity project gets the Unity pre-flight instead (run it at project start and before
409
+ every build; it reads files, never starts Unity): Git LFS pointer files where binaries
410
+ belong (Assets, Packages, every local file: package, Library/PackageCache) with the
411
+ repository to run \`git lfs pull\` in; activeInputHandler against an iOS or Android
412
+ target; TextMeshPro's Essential Resources; a camera with no AudioListener; banned APIs
413
+ (one table: Shader.WarmupAllShaders on URP, UnityEngine.Input on the Input System
414
+ only, -quit with -runTests…); a Shader.Find nothing references; GLBs glTFast cannot
415
+ decode (meshopt, Basis, WebP); ProjectSettings drifted from the project's own setup
416
+ method; the fixes past builds repeated (48 kHz, Unity audio switched off,
417
+ mipmapped NPOT and uncompressed textures with their MB, .meta files an import rule
418
+ rewrites, a productGUID, metroPackageName or .gitattributes cloned from another project
419
+ on this Mac, which branch and commit each file: shared package compiles, Firebase on the
420
+ Simulator, ungated launch flags, EditorApplication.Exit outside batch mode, the
421
+ netstandard guard, IL2CPP numbers, Simulator UDIDs typed into scripts), each a warn or
422
+ a note with its fix but a build that plays no sound; then this Mac: the Editor and the
423
+ build modules each target needs, with the
424
+ Unity Hub line, and for iOS the distribution certificate, Xcode account and App Store
425
+ Connect key, each present or missing (names only, never a secret);
426
+ --add-hooks writes src/fpx-hooks.ts into a game that has no __FPX_* hooks;
427
+ --host reads the host agent's own permission settings (Claude Code, Codex, Cursor
428
+ CLI, Kiro CLI; detected when no name is given): which commands the kit runs it lets
429
+ through, which shapes (chains, heredocs, loops, python) it may refuse and a plain
430
+ call for each, and the allowlist lines you could add. Reads, never writes; exit 0
431
+ upgrade update the files funtools wrote; never overwrites your changes. --discard: say no to
432
+ the waiting <file>.funtools-new copies (deleted, and not offered again until the kit
433
+ changes that file again). --self: the
434
+ newest funtools on npm and the command that installs it. Once a day funtools
435
+ looks for one in the background and says so after a command (never in CI, with
436
+ --json or off a terminal; FUNTOOLS_NO_UPDATE_CHECK=1 turns it off)
437
+ smoke static checks of what ships (exit 1 = a player will see it)
438
+ smoke-build the 10-minute build before any full build: init --bare, the plan's locked sheets pinned, one
439
+ picture and one 3D model through the hosted tools, placed, captured, the world read, the target
440
+ scored, one card. Pass/fail on a model in the world, the locked look, no primitives, a real card.
441
+ Needs a key and Chromium; costs one picture and one model (.funtools/smoke-build.json)
442
+ test run the game's npm test and record its exit with the build fingerprint
443
+ (.funtools/tests.json); exit 0 pass · 1 fail · 3 no test script. --node runs
444
+ test/**/*.test.ts with this Node directly (no npm, nothing on PATH; imports without
445
+ an extension resolve to .ts), and an npm test that cannot start (exit 126/127) falls
446
+ back to it on its own
447
+ --goals: one bounded player per goal the GDD's behaviour tests state (test/goals/<id>.json,
448
+ written for each goal sentence with none: observe = how met is seen in __FPX_STATE__,
449
+ route = journey steps, caps = steps/seconds/loop): the route replayed in a real browser
450
+ and a seat prompt for a fresh agent (.funtools/goals/<id>/seat.md, its answer read back);
451
+ each goal met · not met · blocked (could not act, or stuck) · not observed, in
452
+ .funtools/goals.json. Never changes the exit code
453
+ check build, the rules suite and verify in one call (the loop's chain, for hosts that
454
+ refuse \`&&\`): a red build stops there; exit 3 a step could not run · 1 one failed ·
455
+ 2 verify observed nothing · 0 all passed. Then notes and warnings that never change
456
+ the exit: the production mirror; the frame contract (needs → systems: a starter part
457
+ you replaced is measured for the basic it carried, e.g. the safe HUD band, a save that
458
+ survives a reload); the look (src/look.json: tokens the game would drop, contrast with
459
+ inks proposed, the page's "[frame] look fallback" lines); the idle run (no input after
460
+ Play for 20 s: time alive, deaths, how it ended, warned under the genre's floor;
461
+ .funtools/idle.json; --no-idle skips it). --phone also verifies on a phone and
462
+ measures the band there (pieces under the notch or home bar, HUD cover of the play).
463
+ The world, for a 3D game or one with __FPX_ACTORS__ (--world forces, --no-world
464
+ skips): boxes (flat boxes near the camera, grounding) and life (animated vs a picture
465
+ slid or bobbed, travel, crowd, flyers), read as the slice gate and its card read them.
466
+ Each step lands in .funtools/check.json as it finishes: a run stopped partway (a
467
+ signal, or killed under load with exit 137) keeps what it measured and says it was
468
+ cut short (at once, or at the next check)
469
+ sim the rules played by bots over seeds (the game's test/probes.ts on src/probe-kit.ts,
470
+ engine-free, free): standing still wins, no skill ceiling (a naive steer-to-target
471
+ player does as well as a sharp one), the taught line loses, the novice floor, a
472
+ never-happens check, play length (a skilled run under 3 min on one screen, 5 with
473
+ levels, or under the design doc's play-length line), a sharp bot that stalls (bot
474
+ broken), the best staged moment, music that follows play. Spread and per-level
475
+ splits, the probe's stderr printed; --timeout stops the probe (default 300 s). A
476
+ mirror: warnings never fail it; records .funtools/sim.json
477
+ exit 0 measured · 2 nothing measured (no probe script) · 3 error
478
+ sim lease|release|list|gc|shot|tap: an iOS Simulator of the agent's own. \`lease\`
479
+ creates a fresh one named ft-lease-<id>, records its owner (the agent's process:
480
+ --owner, FUNTOOLS_OWNER_PID or the host's), boots it headless and prints its udid;
481
+ \`release <udid>\` shuts down and deletes that lease and only a lease (another live
482
+ owner's needs --force); \`list\` shows leases, owners and states; \`gc\` deletes leases
483
+ whose owner is gone (--dry-run lists them), and only ever ft-lease-* devices. \`shot\`
484
+ saves the screen upright in the game's orientation (--orientation, else the app's
485
+ Info.plist: --app or the one app running, else what the lease last used); \`tap\`
486
+ presses (x, y) of that upright picture (pixels; --points), mapped onto the portrait
487
+ digitizer, through baguette or else idb (--tool; simctl cannot tap; on the home
488
+ screen a baguette tap reads as a long press), on a lease only. Never
489
+ quits Simulator.app, never \`simctl shutdown all\`, never touches a device it did not
490
+ create. Records in ~/Library/Caches/funtools/sim-leases
491
+ exit 0 done · 2 not observed (no tap tool) · 3 refused or error
492
+ unity Unity on a Mac several agents share. \`unity run -- <unity args>\`: one batch job through
493
+ the machine-wide queue — one job per Unity project path across every session and
494
+ repo, at most --max Unity batch runs on the Mac (default 2, FUNTOOLS_UNITY_MAX;
495
+ Unity runs no funtools job owns count too). While it waits it prints who holds the
496
+ lock (session, pid, command, since). Liveness is progress: the holder's log grows or
497
+ its processes use CPU; a holder that is gone or makes no progress for
498
+ --stale-minutes (default 20, FUNTOOLS_UNITY_STALE_MINUTES) is reclaimed with a
499
+ message. An Editor with the project open refuses the run (it is never quit for you).
500
+ Adds -batchmode, -quit (not with -runTests or --no-quit), -projectPath (the cwd or
501
+ --project) and a per-job -logFile (Logs/funtools-unity-<when>-<id>.log, or --log);
502
+ the Editor is the project's ProjectVersion.txt one from Unity Hub (--unity,
503
+ UNITY_PATH). Prints the log's errors and passes Unity's exit code through.
504
+ \`unity jobs\`: holders, waiters, slots and outside Unity runs. \`unity gc [roots…]\`:
505
+ Library/, Builds/, Temp/ and Logs/ untouched for --days (default 14) under the roots
506
+ (default the cwd), with sizes; a dry run unless --yes; a project Unity has open, whose
507
+ lock is held or a job waits for, is skipped. Locks in ~/Library/Caches/funtools/unity-locks.
508
+ \`unity gc --disk\`: the whole disk, advice first. Free space against --below GB (default 20),
509
+ then what is safe to reclaim, largest first, each with its size, why and the one command:
510
+ this repo's worktrees already in the current branch, clean, with nobody in them (git
511
+ worktree remove, never --force); cargo target/ (sized by listings and stat, never du;
512
+ reclaim with scripts/target-gc.sh; not measured while cargo runs); Xcode DerivedData and
513
+ agents' *-dd temp folders untouched --days (default 2) with no xcodebuild on them; idle
514
+ Unity folders; .funtools/unity scratch older than --days. ~/Library/Caches, the Trash and
515
+ Docker are sized, never touched. Walks are bounded (≥ means at least) and never follow a
516
+ symlink. A report; --apply deletes only the kinds named with --only (worktrees,
517
+ derived-data, unity, scratch), each re-checked first. Exit 0 above the threshold, 1 below
518
+ (advice; --strict marks it FAIL), 125 refused
519
+ exit Unity's own code · 125 nothing ran (refused, gave up waiting)
520
+ \`unity probe\`: the real player measured (com.funpixel.probe in a development build; add it
521
+ with \`unity probe install\`, which prints the one manifest line). Builds the player through the
522
+ queue or reuses a current one (Builds/FunpixelProbe/), launches it — a Mac player hidden and
523
+ muted (--visible, --sound), a Simulator on a lease of its own (--udid one you leased) — plays
524
+ --path's steps (taps, drags, keys, waits, scenes, segments, shots, expects), measures --seconds,
525
+ and reads frame/main/render/work time p50 p95 p99 max, hitches by frame, draws, SetPass,
526
+ triangles, GC per frame and memory, warm-up/capture/load frames left out. Judged against the
527
+ tier's budgets (--tier phone|tablet|mac, --budget); a hitch whose own work stayed small is
528
+ flagged as the host's. Writes .funtools/unity/probe.json. \`unity play\`: a remote-play
529
+ session (start, then tap/drag/key/pad/state/ui/shot/record, end), in the game's own upright
530
+ pixels (--points). \`unity capture --all\`: one still of each registered view, else each scene,
531
+ from a capture build with no development watermark (--dev: the development player)
532
+ exit probe 0 pass · 1 over budget or a step failed · 2 not observed · 3 error
533
+ \`unity bridge status|install|remove\`: MCP for Unity (CoplayDev/unity-mcp, MIT) in a
534
+ project, pinned to v10.3.0. status reads the manifest, the Editor on the project, whether
535
+ its bridge answers, the queue and uv. install adds com.coplaydev.unity-mcp#v10.3.0 to
536
+ Packages/manifest.json — one line, nothing else, printed — and remove takes it out; both
537
+ refuse while the queue holds the project or a Unity has it open.
538
+ \`unity editor <action>\`: console [--since n|last] [--count 50], compile, play, stop, shot
539
+ [--game|--scene] [--out file], menu "<path>", call <Namespace.Class.Method>, hierarchy
540
+ [--depth 3], add <cube|sphere|capsule|cylinder|plane|quad> [--name] [--at x,y,z], save,
541
+ open, close [--force]. With an Editor on the project whose bridge answers, it goes through
542
+ the pinned server over stdio (uvx), routed by set_active_instance to that Editor's exact
543
+ instance id and checked by its project root before any call — never another Editor. With
544
+ none: compile, call and menu (a [MenuItem] in the project's own scripts) run as a queued
545
+ batch job, console reads the newest funtools log, each said as a fallback; play, stop,
546
+ shot, hierarchy, add and save need an Editor: --open opens one with the bridge on stdio
547
+ for that session (through the queue; pid recorded), --wait seconds for its bridge (300).
548
+ close ends only an Editor funtools opened (its recorded pid, checked as that Editor).
549
+ An Editor someone else opened is never quit, relaunched or closed.
550
+ exit (editor) 0 done · 1 failed · 2 not observed (needs an Editor) · 3 refused or error
551
+ spec the big tier of the plan, as a folder the game loads (design/spec/). \`spec init\` (a game
552
+ past the small tier, or --tier mid|deep; a Unity game gets the folder alone, shaped for
553
+ its Unity project to load, and never the web files) writes the README build contract,
554
+ tunables.json with every named number the code holds (src/tune.ts loads it:
555
+ tune('group.name'), typed, a missing id throws, hot in dev), rules, rooms and chapters
556
+ as data (rooms.json, two
557
+ chapters of three rooms of the starter's round), screens and tutorial, difficulty, and at
558
+ deep the rooms in words, cast, story, audio and juice; scaffold files still as written
559
+ are rewired to read the numbers. \`spec lint\` holds it against itself and the code:
560
+ sections the tier needs, unknown and unused ids, a tunable's number typed into src/,
561
+ rooms without a par or an exit, the pars against the play floor, a room changed before
562
+ it was opened; records .funtools/spec.json (the GDD stage's gate past the small tier)
563
+ exit 0 written / clean · 1 lint warnings · 2 nothing to do · 3 error
564
+ rooms every room of design/spec/rooms.json played in order by bots over 5 seeds (test/rooms.ts
565
+ on src/probe-rooms.ts; a lost round retries from the room's door): a careful player at
566
+ a human rate clears each on every seed within 50% of its par, the sharp bot too, the
567
+ naive and novice players' falls room by room, the pars against the play floor; records
568
+ .funtools/rooms.json (the expand stage's gate). \`rooms open <room>\` is slice first: it
569
+ opens a room for building only once every room before it is open and the one before
570
+ passes (the slice's core test and slice stage too); the owner alone releases one early
571
+ (--by owner, their words kept). \`rooms plan\` records the rooms as planned now (a room
572
+ changed before it was opened was built early): free until the owner agrees the plan
573
+ exit 0 every room passes / opened · 1 a room fails / refused · 2 nothing to play · 3 error
574
+ depth the experience evidence stills cannot give, free: the content inventory (what the
575
+ design declares, what the game ships, what real play reached), the pacing timeline of
576
+ the longest real sessions (blind rounds and journeys on game time: beats, places and
577
+ firsts a minute, the longest flat stretch, tension peaks and releases when the state
578
+ names one), the blind player's come-back answer, the design's experience dimensions,
579
+ the bots' skill spread. Facts X1… for the experience seats, text.md (every sentence a
580
+ player can read), a beat strip; in .funtools/depth/ (--out elsewhere). The story's
581
+ ## Story beats against the beats real play showed (__FPX_STATE__.beat; "Story:
582
+ declined" is a choice) and each content-list row against what play reached; --fill
583
+ writes them into the design document's Reached in play / Seen in play cells. A mirror
584
+ exit 0 measured · 3 error
585
+ reach can the player get there, free and local, no browser: each level kept as data (a tile
586
+ grid, side or top view, or the build_level 3D spec; funpixel.json "reach" names them,
587
+ else design/level.json and design/levels/) is filled from its spawn, and every exit,
588
+ pickup, checkpoint or room nothing reaches is named with the gap in the way: wider or
589
+ higher than the game's own jump (reach.movement: numbers or rule constants), or a wall
590
+ with no way through. Sealed pockets are warned. Records .funtools/reach.json
591
+ exit 0 all reached · 1 one cannot be · 2 not observed (no level data, no spawn, a side
592
+ view with no movement declared) · 3 error
593
+ world a seeded world as data the game loads, free and local: \`forge\` writes
594
+ design/world/world.json — chapters of rooms joined by doors, a critical path from the
595
+ arrival room to the goal room, side rooms, loops and a secret; each room a top-down tile
596
+ grid (2D: wall, floor, hazard, arrival, goal, pickup, door) or a heightfield in its own
597
+ file plus placed props (3D), named places (arrival, goal, reward, vista, landmark), a light
598
+ and fog of its own over the world's, and a budget estimate. Props are the game's own kinds
599
+ (GDD **Kit:** line, or "props" in a JSON brief) or neutral roles (cover, landmark, light,
600
+ dressing, marker); chapter names and landmarks come from ## Places. The same seed and
601
+ brief give the same bytes; the grammar itself is drawn per seed. A file changed by hand is
602
+ kept unless --force. --variety N forges N seeds in memory and scores how far apart they
603
+ are (shapes, layouts, grammar, light, graph), naming near-twins. \`check\` validates it:
604
+ ids, every door on both sides, each room's doors, goal and places reached from its
605
+ arrival (3D: a rise of at most movement.step between cells, solid props closed), every
606
+ room reached through the graph, budgets. The loader: src/world.ts
607
+ exit forge 0 written · 3 error; check 0 pass (warnings too) · 1 fail · 2 no world.json · 3 error
608
+ feel the verbs, tells, deaths and poses as a player meets them: a script plays the real
609
+ controls on the built game (test/feel.json: journey steps plus \`until field=value\` and
610
+ \`retry <step>\`; or --journey <name>) while every frame's __FPX_STATE__ is traced. Reads
611
+ the design's numbers (design/GDD.md "## The numbers", the script's "expect") back with
612
+ the gap: jump height, time in the air, apex hang, top speed and time to it, dash
613
+ distance and time, invulnerable window, cooldown; tell to strike and the defensive
614
+ verb's safe window; the death beat and death to control again; each actor's look in
615
+ each of its states. With "sweeps" in the script, coyote time and the jump buffer from
616
+ timed attempts across runs (a fresh load each; --no-sweep skips). Times are on the
617
+ game's clock when __FPX_STATE__ gives t (seconds), else the page's. A mirror: notes
618
+ never fail it; records .funtools/feel.json
619
+ exit 0 measured · 2 nothing measured (no script, no state) · 3 error
620
+ gdd the GDD lint and design reads for design/GDD.md (else design/README.md), no score
621
+ (completeness is not quality): the invention's six answers (answered or generic; an
622
+ answer is its label's line and the sub-bullets under it), hits per axis with sources,
623
+ named behaviour tests (and how many the test files hold), the studio pitch's locked core, then the sections missing or thin; records
624
+ .funtools/gdd.json with the document's sha256 and lists the live decisions of
625
+ design/decisions.md; \`gdd page\` writes design/GDD.html (the document as a page to read and rate; the
626
+ open questions as owner-decision rows under the board) and design/first-look/index.html.
627
+ Then the design measures, advice with a number and why each, "not given" when the GDD has no
628
+ field for one: elements per hour of first playthrough (warns above about 4; peers 1.4–3), the
629
+ spine (a system serving no clause), sources (a marked claim with no source line; --sources
630
+ lists every one), peers (length and elements per hour, else unknown), length totals (the
631
+ parts' minutes against the stated length) and the Steam two-hour check (the hook inside the
632
+ refund window). --strict makes a measure's warn exit 1 (a CI's choice)
633
+ exit 0 read · 1 a measure warns under --strict · 2 no document (or no first-look folder) · 3 error
634
+ greenlight the plan's lock and its worth read: \`lock --version v1.0\` pins the design, the bible and
635
+ the target frames (\`flow agree --by owner\` runs it); \`page\` writes design/greenlight.html (pitches, bible, decisions, lock); \`worth\`
636
+ sets the plan's own minutes against the owner's target and the genre's best, one verdict, a
637
+ scope question to the owner when it does not fit; .funtools/worth.json
638
+ exit 0 locked or met · 1 held · 2 not observed · 3 error
639
+ verify run the game probe locally and write verify.json
640
+ exit 0 pass · 1 fail · 2 not observed · 3 error
641
+ --front-door presses the title's real start control ([data-fpx-start], or
642
+ --click's selector) instead of entering play through the hooks; a missing or
643
+ dead button fails
644
+ --players 2: two tabs in one room on a local relay — the host acts and the
645
+ guest must see it, a late joiner gets the state, the room survives the host
646
+ leaving (needs the funpixel-relay binary and a Redis)
647
+ --engine webkit (also capture, play, journey, feel) runs Playwright's WebKit,
648
+ Safari's engine without Safari's UI, for a bug only Safari shows; recorded in
649
+ .funtools/verify/webkit.json, never verify.json (publish reads Chromium's).
650
+ Optional: npx playwright install webkit (doctor says so)
651
+ capture one PNG of a named view: entered through __FPX_VIEWS__, --verbs pressed in
652
+ order, held --hold ms (600) and frozen for the shot (default
653
+ .funtools/capture/<view>-<viewport>.png); no --view shoots the page as loaded.
654
+ A signature moment (a view declared moment: true) plays instead: a burst of
655
+ --burst frames (12, ~1.8 s) into <out>.burst/, and the frame showing its
656
+ __FPX_MOMENT__ mark is the shot. A phone is touch, with the Studio's touch
657
+ emulation (?funpixel_touch=1); --safari shrinks it to the page Mobile Safari's bars
658
+ leave (390x684 upright, 724x283 sideways; <view>-phone-safari.png), where a
659
+ height-sized play is narrower than the 390x844 frame shows. --all shoots every declared view at both sizes,
660
+ each to its default path: the set the critic panel and the GDK's Stop gate read.
661
+ Repeatable (8 Oct): the page's clock is held from before the game's first line and
662
+ moved in fixed 1/60 s frames from seed 1 (--seed n; window.__FPX_SEED__, Math.random),
663
+ with no game time passing while the page waits on the network, a decode or a resize,
664
+ so two captures of a view are the same frame. Each shot says how it was framed (held
665
+ clock, seed, frames, the named camera from __FPX_CAMERA__) or that it ran free
666
+ (--free-running: the wall clock, as before), in --json and .funtools/capture/index.json
667
+ exit 0 shot · 2 the view was not entered · 3 error
668
+ compare before and after on the same views: --baseline keeps the current captures (capture
669
+ --all) as the before; after the change and a fresh capture --all, compare writes
670
+ each view's before | after sheet to .funtools/compare/ and names the views that
671
+ did not change, and each pair not framed alike (free-running, another seed, game time
672
+ or camera) as not comparable frame for frame; exit 0 compared · 2 nothing to compare · 3 error
673
+ --target: the game today beside the frame it aims at, at fixed framings (a phone held
674
+ sideways 852x393, desktop 1280x720; --viewport, default both), one strip per view and
675
+ size, "today | target", to design/look/<view>-<viewport>.png (--out: a folder, or one
676
+ file for one strip). One picture serves every --view; or one picture per view, in
677
+ order. The target is shown whole (--fit cover fills and crops). Read the strip for
678
+ mood, light, the hero's size and life. Today's frame is held like capture's (--seed,
679
+ --free-running); exit 0 made · 2 a view not entered · 3 error
680
+ parts cut a generated sheet into pieces: a character into parts or poses, an item sheet
681
+ into items. Background keyed (--key auto: the sheet's alpha, else its flat corner
682
+ colour flooded in from the edges), each piece trimmed with --pad px, written as a
683
+ transparent <name>.png (--webp adds lossless WebP) plus parts.json (box on the sheet,
684
+ size, pivot: bottom-centre for poses, --pivot top for limbs). Pieces: --grid CxR, a
685
+ --boxes file ([{name, x, y, w, h}]), or every separate figure (bits within --merge px
686
+ join); --names in reading order. Default out: <sheet>-parts/ beside the sheet.
687
+ Warns on a background that will not key, a piece cut by the edge, names that do
688
+ not match; exit 0 written · 2 nothing found · 3 error. --key paper keys a painted
689
+ sheet's paper (colour and grain from the whole border, patches between legs too);
690
+ --clean runs cut's clean pass on every piece
691
+ cut parts with a painted sheet's defaults: figures off a cream or plain reference sheet
692
+ (or a generated --transparent image) as clean sprites, local and free. The paper is
693
+ keyed; then per piece: painted ground shadows under the feet go (--keep-shadows keeps
694
+ them), the soft halo goes (alpha thresholded, a 1 px soft rim), the rim takes its
695
+ colour from the inside (no paper bleed), stray islands go, and lines ruled across the
696
+ sheet (a generator's cell grid) go first. Each piece says what was removed; parts.json
697
+ carries the counts. Default out: <sheet>-cut/ beside the sheet. Exit as parts
698
+ audit-screens layout on every declared view (or --views): text under 12 px, hit areas
699
+ under 44 px, HUD pieces over each other, anything cut by the screen edge or
700
+ inside a phone's safe area; developer copy on screen ("will be here", TODO,
701
+ lorem, NaN) is a warning beside the verdict
702
+ exit 0 pass · 1 fail · 2 not observed · 3 error
703
+ A phone is held the way funpixel.json's orientation says; --orientation turns it
704
+ (the other way a player can hold it; export audits both) for capture,
705
+ audit-screens, scene and play: a portrait game held sideways is 844x390,
706
+ shot to <view>-phone-landscape.png, never counted as the game's phone shot
707
+ scene the engine's scene graph (Three, Pixi, Phaser) read in the page: nodes, depth,
708
+ what is switched off or outside the view, textures and a draw-call estimate
709
+ exit 0 read · 2 no scene graph found · 3 error
710
+ --motion samples ~1 s of play: each actor (funpixel.json "actors" player, threats,
711
+ pickups, else the usual names), judged against the Motion column of the design
712
+ note's ## Actors table (moves · animates · still); recorded in .funtools/scene/motion.json
713
+ exit 0 every declared mover moved · 1 one stood still or never changed · 2 not observed
714
+ hook the hook moment: the title, the real Play, then the first minutes of play (--seconds,
715
+ default 180) read at checkpoints: what moves besides the player, how much of each frame
716
+ is flat colour (empty), whether the picture changes, stand-ins the game still names
717
+ (__FPX_STATE__().art.placeholders). A light player taps the middle every 3 s (cards
718
+ between Play and the world are passed); --verbs presses verbs in turn instead, --idle none.
719
+ Frames in .funtools/hook/, record .funtools/hook.json. Warns, never fails
720
+ exit 0 measured · 2 not observed · 3 error
721
+ life is the world alive around the player? ~3 s of the play view (--view, else the view
722
+ marked motion): the pieces that move or change besides the player (crowds of
723
+ instances, particles, lights), whether a looping sound bed started, and for each big
724
+ moment (views marked moment, or --moment) whether anything answered its __FPX_MOMENT__
725
+ mark (a sting, a crowd, pieces or lights) against play before it. The front door
726
+ ([data-fpx-start]) is pressed first, since sound starts on a gesture. Warns, never fails;
727
+ records .funtools/life.json (funpixel-world-and-story, references/atmosphere.md).
728
+ Motion is not animation: people and creatures are judged animated (frames, bones,
729
+ morphs or parts change), SLIDES LIKE A STONE (travel with nothing inside changing),
730
+ RIGID (bob or turn as one picture) or STILL; no idle and reactions near the player
731
+ are counted (@funpixel/verify life_anim.js). Travel is watched ~10 s and labelled so;
732
+ walk.json, when walk ran, decides it. A moment that fires every cue at once (a jump
733
+ through the payoff) is flagged, not counted as an answer
734
+ exit 0 measured · 2 not observed (no scene graph and no sound log) · 3 error
735
+ walk verify the world by playing it: every route in funpixel.json walk.routes (else one
736
+ explore walk) from the TITLE with real keys and clicks, held and steered in real time
737
+ (no view jumps, no verbs), filmed from the play camera (.funtools/walk/<route>.webm,
738
+ MediaRecorder on the canvas). Each tick reads the actors contract (__FPX_ACTORS__,
739
+ HOOKS.md "Actors") and warns on CLIPPING (bodies through props, walls, each other),
740
+ PLACEMENT, FLOATING, SCALE (funpixel.json "scale" in metres; "framing" share of the
741
+ frame), STALLS (presses that change nothing: blocked or a dead end), NO CHALLENGE (no
742
+ stumble, detection, timer or failure fired) and life (slides like a stone, no idle,
743
+ no reaction; a crowd that never travels; the hero's face on a crowd; flyers without a
744
+ flap), LOSS (a run that ends failed, then the game's retry; penalties alone are not a
745
+ loss). A route's "then" (or --chain a,b) walks legs in one page and one film from the
746
+ title (a prologue, then Run 01; a chained leg skips its start steps and plays its
747
+ "continue" steps); framing warns when over 15% of the time is outside the band;
748
+ steer.waypoints (or a path in the state) steers by position when there is no
749
+ lateral field; a leg that arrives in under 3 s is not observed. CROWD: clumps
750
+ (people within 1.5 m with no shared scene: tagged, or inferred when they face each
751
+ other or move together), empty stretches of the path, the count against
752
+ walk.crowd.people. Every 4 s the world itself: BOXES (big meshes that read unfinished,
753
+ the worst frame kept as <route>-boxes.png; BOX FIGURES) and OFF THE GROUND (big props
754
+ and vehicles hovering, over a drop or sunk), as funtools boxes reads one view. The
755
+ contract: skill funpixel-verify,
756
+ references/actors.md. Records .funtools/walk.json. Warns, never fails
757
+ exit 0 walked · 2 not observed (no route reached play, or nothing to read) · 3 error
758
+ score how close a moment is to its target picture, 0-100 on six axes (composition, hero,
759
+ identity, palette and light, density, life) at compare --target's framing: measured
760
+ numbers (palette ΔE, layout and edge similarity, detail share, the hero's height share
761
+ from the actors contract against the target's hero_share, motion over 3 s) plus a blind
762
+ vision judge when OPENROUTER_API_KEY is set (else "not observed"). A loading or splash
763
+ frame is never counted. Every moment in funpixel.json "moments" without --target; the bar
764
+ is "accuracy_min" (default 75, the owner's; "accuracy_stretch" 90 kept). Every moment
765
+ also gets its FIX LIST: the camera the game runs (read in the page: __FPX_CAMERA__, the
766
+ three.js camera or the pixi world) and the numbers that would lay the capture over the
767
+ target ("SHOTS.play.height 4.4 → 6.1, fov 50 → 41"), the light (exposure ×k), colours
768
+ by hex and bare regions to dress. Writes design/look/scores.json and one line per run
769
+ to design/look/score-history.jsonl; \`--fixes\` prints the last run's list without a
770
+ browser. The flow's rounds work down it. The moment is shot on capture's held clock
771
+ (--seed, --free-running), so a round's score before and after a change reads one frame
772
+ and says how it was framed. Warns below the bar. Beside the axes, EYE COMFORT (never in
773
+ the score): each frame's busyness (the mean brightness step between neighbouring pixels,
774
+ on a grey copy 360 px on its short side) and clipped share (luma <= 2 or >= 253) against
775
+ its targets'; a frame over 14, over 1.25x its targets' busiest, or over 6% clipped warns
776
+ (match the targets' quality, not their density) and is stamped on zero's comfort counter
777
+ exit 0 scored · 2 nothing scored · 3 error
778
+ framing where each actor lands on screen at the target framing: its box, its height share
779
+ and whether it is in view, against funpixel.json "framing" ({ "ren": [0.16, 0.22] }),
780
+ so a camera is tuned without rebuild-and-shoot rounds
781
+ exit 0 read · 2 none of the actors found · 3 error
782
+ boxes is the world made, or boxes? Each play view (or --view a,b) is held and its frame
783
+ rastered from the play camera beside a screenshot (@funpixel/verify surfaces.js): big
784
+ meshes that read as unfinished (flat colour on big triangles, few vertices for their
785
+ size, no texture) are named, ranked by area and nearness, beside the most detailed
786
+ structure in the frame (terrain and rock in a faceted style lock are the look, not
787
+ boxes); people and creatures built of a handful of boxes are named at any size (BOX
788
+ FIGURES); the big props and vehicles are read against the nearest surface under where
789
+ they touch down, terrain or a support (a deck, a pad, what people stand on; grounding.js:
790
+ hovering, over a drop, sunk). walk does both along its
791
+ routes. The dressing round the player is counted per 100 m² against the place's
792
+ target (state.world.dressing.target), the road kept clear, the phone's frame budget
793
+ (DRESSING: BARE, ROAD CLUTTERED, OVER THE PHONE BUDGET; dressing.js).
794
+ Writes .funtools/boxes.json and .funtools/boxes/<view>.png. Warns, never fails
795
+ exit 0 read · 2 not observed (no Three scene) · 3 error
796
+ places are the places distinct in play (the Silt bar's S8: ≥ 3)? Each place-<id> view (or
797
+ --view a,b) is entered and shot; each pair compared in colour (ΔE over a 4 × 4 grid)
798
+ and layout (variety's limits) and in the light the game says it runs there
799
+ (state.world.light: preset, exposure, key, fill). Alike in colour and light = one
800
+ place repainted. Writes .funtools/places.json and .funtools/places/<view>.png. Warns
801
+ exit 0 read · 2 not observed (under two place views) · 3 error
802
+ compare-takes two takes of one game (two parallel builds of the same plan), each played from
803
+ the title with walk (its routes, filmed) and scored against its targets with score
804
+ when funpixel.json names moments; a best-of-both table per area (environment,
805
+ dynamics, challenge, accuracy, each moment: which take is ahead and what the mix
806
+ keeps) and a contact sheet (walk frames, frames from the films with ffmpeg, each
807
+ moment beside its target). Writes <out>/takes.json, takes.md, sheet.png (default
808
+ .funtools/takes). A mirror for choosing, never a verdict
809
+ exit 0 compared · 2 nothing measured · 3 error
810
+ profile the numbers behind a frame, per view (default: the gameplay views): frame time
811
+ p50/p95/p99/max and long frames after a warm-up, draw calls and triangles counted at
812
+ the WebGL calls, the scene by kind (Three meshes/instances/lights/shadows, Pixi
813
+ sprites/graphics/text/particles/filters), texture memory estimated, JS heap, what
814
+ the page fetched, dist/ size by kind. Saved to .funtools/profile/<view>-<viewport>.json;
815
+ the next run of the same view and viewport prints the change (--against another
816
+ file). --seed sets window.__FPX_SEED__ before the game runs. --software renders on
817
+ the CPU (SwiftShader), where fill costs a desktop GPU hides behind vsync show as frame
818
+ time; --throttle N slows the page's CPU N times, a stand-in for a phone's JS speed.
819
+ --repeat N samples each view N times and reports the median and the p95 range (a busy
820
+ machine moves single runs a lot). Reports, never judges: neither is a phone, so
821
+ compare runs made the same way. --compare reads the run the way the Studio's profiler
822
+ reads a build against the last one (its percentiles, frame-time buckets, burn rate
823
+ and neutral band): every frame kept, frames over the budget (--budget, default the
824
+ profiler's 18 ms) as a burn rate against a 1% allowance, GPU time a frame when the
825
+ browser offers the timer query (else said, never guessed), stored per view in
826
+ .funtools/profile/history/ and compared only with the last run made the same way
827
+ (seed, viewport, throttle, renderer, frames, budget) — "frame p95 16.9 → 20.9 ms (+4.0
828
+ ms, +24%) regression · draw calls 12 → 72 (+60) regression · burn 0.4× → 5.2×"
829
+ exit 0 measured · 2 nothing measured · 3 error
830
+ inspect what is on screen, asked the way a person clicks in the Studio: the platform's
831
+ inspector in the game's own dev server (as \`dev\` mounts it; --url looks at a running
832
+ \`funtools dev\` instead). --at x,y (CSS px, or 50%,80%) names what is there, HUD first,
833
+ then engine objects topmost first; --name finds objects by label or name; --tree prints
834
+ the scene. Each comes with its state (position, scale, alpha, shown or hidden, its box on
835
+ screen, Three userData) and the source file:line that created it, through the source
836
+ maps. Every runtime error so far is listed at its source line, with __FPX_STATE__().
837
+ Never pauses or selects; reports, never judges
838
+ exit 0 answered · 2 not observed (no inspector, no scene, nothing there) · 3 error
839
+ clip clip critics: how the game FEELS, from strips of consecutive frames of play (what
840
+ stills cannot show). Cuts 12-frame 4 × 3 strips from a reel's frames (default
841
+ .funtools/reel/frames: \`reel --frames-only\` first; its payoff marks centre a strip each)
842
+ into .funtools/clip/<n>/ and writes one prompt per seat (player, animator: feel, juice,
843
+ motion, clarity) for your own agent to run; funtools calls no model. \`clip report\`
844
+ reads the answers back. Separate words (panel/clip.md) from the calibrated still panel
845
+ exit 0 ready or reported · 2 no frames or nothing filed · 3 error
846
+ judge two checks on generated art that an aesthetic score cannot make, each one seat for your
847
+ own agent (funtools calls no model; one seat reads the pictures once). structure: fixed
848
+ yes/no questions with evidence (matched pairs, part counts, attachment, lettering, the
849
+ frame); any no fails, never averaged into a score. identity: a model's rendered views
850
+ (.funtools/renders/<name>/ from \`model render\`; nothing is rendered here) or a sprite set
851
+ against the concept it came from (--concept, else the asset manifest's \`from\`), per
852
+ trait (silhouette, palette, features, proportions) with the worst view; major drift
853
+ fails, minor warns. \`judge report\` reads the answer back; an answer about a picture
854
+ that changed since is not counted
855
+ exit (prepare) 0 ready · 2 no picture/concept/views · 3 error;
856
+ (report) 0 pass · 1 fail · 2 not observed (nothing filed, unanswered, stale) · 3 error
857
+ phone the game in real iPhone Safari (WebKit) through baguette's headless iOS Simulator
858
+ (optional: Apple Silicon + Xcode 26 + \`brew install baguette\`; never installed for you):
859
+ boots an iPhone (--sim), opens the built game in Mobile Safari, closes Safari's first-run
860
+ tip, finds the controls through the accessibility tree (sizes; under 44 pt said), taps the
861
+ start control by name, plays --seconds (--taps presses points, --swipes swipes the play in portrait
862
+ and says which __FPX_STATE__ fields each changed), screenshots each step to
863
+ .funtools/phone/<time>/, and reads the page's own frame intervals, errors, __FPX_STATE__
864
+ and safe-area insets (a folder is served with a reporter; a URL is only looked at). Shuts
865
+ the simulator down after (--keep leaves one it booted running). --orientation landscape
866
+ plays too (taps mapped; screenshots turned upright). WebKit's pacing on the Mac,
867
+ not the phone's speed; one simulator at a time
868
+ exit 0 observed · 2 not observed (no baguette, not a Mac, no iPhone simulator) · 3 error
869
+ look --read: can a player tell themselves and the threats from the ground? The play
870
+ view (\`playing\` when declared) frozen, the player and threat boxes read from
871
+ the engine's scene (names matched by funpixel.json "actors", or --player and
872
+ --threats), each measured against the ring of ground around it: ΔE of the
873
+ figure to its ground, the bar the three bar games all pass. With no boxes, the
874
+ style file's role colours (assets/style.json roles hero, harm) or --colours;
875
+ a PNG on disk is read by colour only
876
+ exit 0 pass · 1 an actor merges with its ground · 2 nothing measured · 3 error
877
+ --hud: the HUD while the game plays (default phone): the play view and each
878
+ moment view sampled --samples times, --every ms apart; cover of the play area,
879
+ text size, contrast against the pixels behind each text, HUD over the player
880
+ or a threat, transient pieces piling up; warnings for a worded message over
881
+ the middle of the play, a text gone before it can be read (0.8 s, ~0.3 s a
882
+ word) and developer copy on screen ("will be here", TODO, NaN). The worst
883
+ sample is saved with the HUD outlined (.funtools/look/hud-<view>-<viewport>.png)
884
+ exit 0 nothing found · 1 a finding · 2 nothing measured · 3 error
885
+ --fit: does it fill the windows people give it? 1700x800, 1280x600, 1024x1024 and
886
+ the phone sideways and upright, each opened fresh: how long it stays one flat
887
+ colour (over 3 s is a finding), then the play view's share of the window, flat
888
+ bars at the edges, content bunched in a corner (.funtools/look/fit-<window>.png)
889
+ exit 0 every window filled · 1 a finding · 2 nothing observed · 3 error
890
+ --sheet: the roster at play size before the game exists: every PNG sprite
891
+ (public/assets/sprites, or --sprites) trimmed, at each --sizes height on a
892
+ neutral band and on the ground (--ground, else assets/style.json roles.ground),
893
+ each measured by --read's ΔE; no build needed (.funtools/look/sheet.png).
894
+ An animation sheet (sheet.json names animations) has each cycle measured:
895
+ distinct poses, and a loop's seam (last → first) against its median step
896
+ exit 0 every sprite reads, no cycle pops or freezes · 1 one merges, pops or
897
+ freezes · 2 no sprite · 3 error
898
+ --3d: what a Three.js game's hero objects are made of. The source the entry
899
+ point reaches: files that build the player, rivals and enemies (primitive
900
+ constructors by kind, hand-built buffers, a model loaded) and the models under
901
+ public/. With a build and a browser (not --static), the running play view adds
902
+ each hero node's meshes, triangles and screen share. Code-built heroes pass only
903
+ as a declared style: funpixel.json "art3d" { "heroes": "procedural", "why",
904
+ "proof": "<frame>" }; stand-ins are named in "art3d.stand_ins"
905
+ (.funtools/look/3d.json)
906
+ exit 0 models, or a declared and proven style · 1 heroes are code · 2 not
907
+ observed · 3 error
908
+ set|patch|report: the HUD and screen look as one value, src/look.json (the UI role
909
+ tokens styles.css reads: bg, ink, plate, plate-ink, accent, font-display …; the
910
+ starter's src/look.ts applies it at load). set token=value and patch file.json
911
+ (a merge patch: null removes a token) validate the merged whole and refuse to write
912
+ on a problem, with the closest token names; every write and report prints the
913
+ contrast of each text/background pair and, for one that fails, the ink that passes
914
+ (a proposal: run the printed \`look set\`). report reads the file as the game does
915
+ (.funtools/look/report.json)
916
+ exit 0 written / clean · 1 refused, or tokens the game would drop · 2 no look · 3 error
917
+ play the blind player's hands and eyes: a round keeps one page of the built game open;
918
+ \`act\` plays a batch of steps (up to 20) as a person would and saves the screen once,
919
+ after the batch (tap X Y · drag X1 Y1 X2 Y2 [ms] · hold X Y ms · hold KEY ms · press
920
+ KEY [n] · wait ms · look DX DY [ms] · view NAME · verb NAME · shot; 0.5 is a fraction of
921
+ the screen, 200 a pixel; up/down/left/right are the arrows; a phone takes touch only;
922
+ "A & B" is one gesture, two thumbs at once). \`hold KEY|X Y until COND [max N]\` and
923
+ \`wait until COND [max N]\` let the game run in real time until a field of
924
+ __FPX_STATE__ says so (screen!=playing, x>120, score>=3) or the screen (\`change\`, or
925
+ \`change X1 Y1 X2 Y2\` for a box) visibly changes, 10 s by default, 30 s at most; the act
926
+ says whether and when, and the log keeps how long it ran. \`look DX DY\` moves the
927
+ mouse with no button down (camera look, under pointer lock too, which play grants as a
928
+ browser does; a drag clicks). \`play look\` (or \`act --look\`) hands back a small frame
929
+ (NNN-look.jpg) and the state as one line, no game time passing, no step spent. A
930
+ helper script the player writes belongs in its round's folder: a command run from one
931
+ elsewhere under the game, or in a temp folder, is refused. The
932
+ game's clock is held between acts; \`report\` files the player's report (start,
933
+ goal, act, end, confusions, each funpixel.json criterion, top 3 defects) with each
934
+ defect's exact repro from the round's log, and closes the round; \`check\` names
935
+ each field a draft gets wrong (defects[0].step: got "9a"; expected …) without
936
+ filing; a refused report is kept as written in round-N/report-unfiled.json, and a
937
+ round that went idle still takes its report. Each round has its own session in
938
+ .funtools/play/round-N/ (two may be open at once, a blind pair in one folder or
939
+ two): later commands find it in --dir, else the game folder at or above the
940
+ current one, and --round N (printed at open) names it when two are open there.
941
+ The player never reads the source. At most --rounds (3) rounds, then the panel.
942
+ --long N: a long session of about N minutes of game time (a bigger step budget),
943
+ ending with the come-back question: "would you come back tomorrow, and why?"
944
+ exit: report 0 a new player gets through · 1 blocked · 3 error; check 0 would file · 3 not
945
+ journey a player's path from the visible start through the real controls, kept as a script
946
+ (test/journeys/<name>.json: play's steps without view/verb jumps, plus
947
+ \`mark NAME field=value score>0 …\` checkpoints) and replayed on the same seed
948
+ (window.__FPX_SEED__) and viewport: at each mark the clock is held, the frame kept
949
+ and __FPX_STATE__ read into counters and judged. \`record\` opens a window you
950
+ play in (your taps, drags and keys become the steps; each screen reached becomes a
951
+ mark); \`from-play\` takes a blind player's round; \`replay\` sets the run beside the
952
+ last one (--repeat 2: two runs of one build, the noise); \`diff\` any two runs.
953
+ Kept apart from __FPX_VIEWS__, the diagnostic scenes: a scene reproduces a state, a
954
+ journey shows a player can reach it. Runs in .funtools/journeys/<name>/<n>/
955
+ replay exit 0 every expectation held · 1 a step or one failed · 2 nothing judged · 3 error
956
+ playtest the creator's mirror between rounds: builds, verifies, captures every view at both
957
+ sizes (moments as strips), audits the phone screens, judges the HUD in play and
958
+ profiles, all free; then writes one prompt per seat for your own agent (the
959
+ calibrated critic panel, 3 seats or 2 with --quick, each re-reading its axes on the
960
+ phone captures; a blind phone player round; a
961
+ head to head against the genre hit when its evidence is on this machine, never
962
+ shipped: --versus <dir> or FUNPIXEL_HITS_DIR/<slug>/). \`report\` ranks 3–4 next
963
+ steps, each with a quote, a frame and a number, and sets this playtest beside the
964
+ last (.funtools/playtest/<n>/report.md). --hosted runs the seats as Tools API jobs
965
+ (review, play) for credits, quoted first. Beside the craft panel: a plan-fidelity seat
966
+ (the GDD's target frames beside the game's frames of the same moments) and, after the
967
+ blind round (a long session, --long 10 by default, 0 for a short one), \`experience\`
968
+ measures depth and writes the experience seats (depth, content, replay, story, world,
969
+ arc, originality). A Mobile QA seat judges whether it is native to a phone (--phone
970
+ runs \`phone\` first, so it sees real Mobile Safari). Nothing is ever applied to the game
971
+ The panel informs and never gates: \`report --min-score 6.5\` exits 1 under the number
972
+ you ask for, and funpixel.json owner_gates.panel_min makes it the owner's hold.
973
+ \`report\` also keeps the do-not-regress list (.funtools/keep.json): up to eight things
974
+ the panel named as working; the next ledger seat judges each held, lost or not
975
+ observed, and a lost one is a regression: the report leads with it and exits 1, and
976
+ the panel stage fails. \`keep\` lists it; only the owner drops an item (--drop K<n> --by owner)
977
+ mobile-qa is the game native to a phone? One seat for your own agent, judged from phone
978
+ evidence: real Mobile Safari (the latest \`phone\` runs; --phone makes them), a WebKit
979
+ phone shot, the Chromium phone frames, audit-screens and look --hud at phone size, key
980
+ parity at phone size and the blind phone round. It judges touch-native controls (a
981
+ button that repeats the play area's gesture, never needed controls), the play area's
982
+ share of the screen, thumb reach, tap targets, chrome during play, safe areas,
983
+ orientation, readability and first touch; high/medium/low with a frame and a number.
984
+ \`report\` ranks the answer. Runs in .funtools/mobile-qa/<n>/; playtest runs the same
985
+ seat. Declare "platform": "phone" in funpixel.json metadata when the phone is primary
986
+ (a key with no touch route is then high); "desktop" opts out. Advisory
987
+ exit 0 prepared/reported · 1 build failed · 2 not a phone game · 3 error
988
+ exit 0 prepared or reported · 1 the build failed · 3 error
989
+ lessons settled findings by genre: after a fix round, \`add\` records what the panel or the
990
+ player named and what fixed it (in .funtools/lessons.jsonl; --share also in
991
+ ~/.funpixel/lessons/ for the next game of the genre on this machine); with no
992
+ \`add\`, the best for the game's genre (the GDK's session start shows the top three)
993
+ and the motifs of the last five other games. \`motif\` records this game's
994
+ look (title, palette roles, motif nouns of the design note) in
995
+ ~/.funpixel/lessons/motifs.jsonl, so the next game avoids it
996
+ variety is this game too close to the other games on this machine (the ones in
997
+ ~/.funpixel/lessons/motifs.jsonl)? Five signals, each three-state: palette distance
998
+ (ΔE), the same core verb family in the same genre, a near-identical title screen
999
+ (edge layout of the latest title capture, so one template in new colours still
1000
+ counts), shared motif nouns, a shared title word, the same signature wow expressed
1001
+ alike (the GDD's ## Wow). Other folders of this same game
1002
+ are skipped. Records this game's verb and title layout for the next one. A mirror:
1003
+ the creator decides what to change. --within compares this game's own place
1004
+ pictures (design/first-look/place-*, or those ## Places names) with each other:
1005
+ colour and shape per pair, so six places that read as one room repainted warn
1006
+ exit 0 nothing too close · 1 something is · 2 nothing to compare · 3 error
1007
+ (--within: 0 compared · 2 under two pictures)
1008
+ wow the genre card's wow catalogue: hit-proven moves in four families (signature, juice,
1009
+ feel, presentation), each with the hit, what to build (numbers where a source gives
1010
+ them) and its check (a probe event the game marks with __FPX_MOMENT__, or a frame of
1011
+ a view). \`wow pick\` records the game's choice in the GDD's ## Wow (one signature, up
1012
+ to three more, each with its expression: what this game makes of the move) and flags
1013
+ a signature another game on this machine already used, expressed alike. \`wow check\`
1014
+ reads each pick's evidence: the event in the last hook read, the view's score
1015
+ exit 0 listed / picked / all seen · 1 a pick's evidence missing · 2 not observed · 3 error
1016
+ pitch the studio pitch: pitch → pick → lock → go hard. Cards (genre and fidelity, depth, the
1017
+ core that burns, story standard, extras with their cost) in design/studio.json;
1018
+ \`propose\` sets the agent's pick with its reason for this game (a new option joins the
1019
+ card with --label/--picture/--cost), \`ask\` puts each card the owner has not settled to
1020
+ them (a taste, spend or scope question in the chat), \`pick\` records a pick (--by owner
1021
+ is the owner's), \`lock\` writes the picks to funpixel.json "studio" (and
1022
+ production.tier from the depth) and the GDD's ## The studio pitch, and exits 1 while a
1023
+ card waits for the owner (unless the owner set autonomy go); \`gdd\` and the
1024
+ session start then read the locked core. Autonomy is never a card: the owner's
1025
+ funpixel.json flow.autonomy. No subcommand: the cards and what the
1026
+ locked layer still asks of the GDD. \`widen\`, before the pick: a seeded, replayable
1027
+ spread (operators × domains × facets, near/middle/far, one labelled wildcard; the seed is
1028
+ printed, --seed replays it) into design/widen.json for the agent to answer; \`widen score\`
1029
+ measures each answer against the generic answer for the brief and what the wow ledgers
1030
+ kept; \`widen keep W2\` records the kept card so the next widen of this brief steers away
1031
+ exit 0 shown or written · 2 no game folder · 3 error
1032
+ loudness every cue against its loudness target with the local ffmpeg (EBU R128): one-shot
1033
+ −16, bed −22, music and voice −18 LUFS ±3, true peak ≤ −1 dBTP, silent takes named.
1034
+ Measures, never changes a file. No paths: the game's sound folders. A bed or
1035
+ music track (what a game loops) also has its join measured: a gap (silence at the
1036
+ ends) or a click (the last sample jumping into the first) warns, and is the zero
1037
+ board's audio seams
1038
+ exit 0 measured · 2 nothing measured (no ffmpeg, no audio) · 3 error
1039
+ beats each music track's beat map written beside it as <track>.beats.json: tempo,
1040
+ first beat, downbeat, every beat time and how clear the pulse is, from the
1041
+ track itself (WAV read directly, others through ffmpeg); a track with no clear
1042
+ pulse says so instead of inventing one. The starter's src/beat.ts reads it
1043
+ (loadBeats, beatAt, nearestBeat, nextBeat) against sound.ts musicTime()
1044
+ exit 0 written · 2 nothing read · 3 error
1045
+ schema the whole game held to one shape: funpixel.json (every key a kit command
1046
+ reads, its type and values) and the plan files beside it (src/look.json,
1047
+ assets/assets.json, design/pipeline.json, design/spec/tunables.json, the
1048
+ forged world), each alone and against the others; an unknown key is a
1049
+ warning with the closest name (--strict: an error, what a writer refuses on)
1050
+ exit 0 no errors · 1 errors · 3 error
1051
+ loop a generated video (gen video, from the accepted sprite) or a folder of frames
1052
+ made into a seamless sprite cycle: sampled at --fps, the --min..--max frame
1053
+ window whose last frame leads back into its first as smoothly as an ordinary
1054
+ step, keyed, every frame cut to one shared box (no jitter), packed as a sheet
1055
+ PNG + spritesheet JSON with the cycle as an animation. Free (ffmpeg for video)
1056
+ exit 0 written (a visible seam warns) · 2 too few frames or no ffmpeg · 3 error
1057
+ directions a model's orbit views (gen render: turn_00.png …) made into an 8-way or 4-way
1058
+ sprite set: angle 0 faces the viewer (S), the rest named going round
1059
+ (--reverse for the other way), keyed off the stage, one shared box, a sheet
1060
+ PNG + JSON with an animation per direction. Repainting each view in the
1061
+ game's style is a paid edit per view: printed, never run
1062
+ exit 0 written · 2 too few views · 3 error
1063
+ board the first look's reference board (design/board/): search open-licence
1064
+ collections (Openverse, free, no key), wander from a kept picture to related
1065
+ ones, or add your own files and links; every kept picture names the one or
1066
+ two things it lends (palette, shape, light, composition, material, motion,
1067
+ mood, type) and its licence. \`show\` writes board.html and fails when a board
1068
+ picture is copied into public/ or assets/: a reference informs, never ships
1069
+ exit 0 · 1 a board picture would ship · 2 nothing found · 3 error
1070
+ zero the zero board (design/status.json \`board\`): the loop's counters as the commands
1071
+ that measured them left them, each with its trend over the last runs and what it
1072
+ is made of — errors (verify's failing gates + distinct page errors, verify and
1073
+ capture --all), overlaps (controls cut or covered, HUD over HUD, under the notch:
1074
+ audit-screens per surface, which check runs), seams (looping sprite cycles that pop,
1075
+ look --sheet; looping music and beds that click or gap at the wrap, loudness) and
1076
+ frame time (profile's worst p95 per viewport, against its budget, 18 ms unless
1077
+ --budget); and comfort (score: moments whose frame is too busy or clipped), which
1078
+ warns and never fails. A counter nothing measured is not observed, never 0. Draw, render,
1079
+ check, fix, repeat until it reads zero. Measures nothing itself. Each counter's parts
1080
+ are shown by trade (the game's own; review's video, audio, model, picture)
1081
+ exit 0 every observed counter zero (frame time within budget) · 1 not · 2 nothing observed · 3 error
1082
+ review the zero board for every trade, not only games: measures media (a film spot, a
1083
+ music single, a podcast, a 3D model, a picture series, a game's assets) with the local
1084
+ ffmpeg and the kit's own readers, stamps each trade's part of errors, overlaps and
1085
+ seams in the project's design/status.json (one with no status gets one holding the
1086
+ board), and prints it. Video: a stream that does not decode, black frames outside the
1087
+ first and last 0.5 s, frozen spans over --freeze (2 s) on a moving cut (--still: a
1088
+ still cut), captions outside the 9:16 / 16:9 / 1:1 safe zone when a .vtt/.srt/
1089
+ .captions.json beside it says where they sit, a loop's last frame into its first
1090
+ (named loop, or --loop), loudness as a note (−14 LUFS web, −23 broadcast). Audio:
1091
+ clipping (true peak over −1 dBTP), silence (a dud, a dropout of 2 s+ inside it), a
1092
+ loop's or bed's join (gap or click), loudness as a note (a game's cue classes, else
1093
+ −14 music, −16 speech; --lufs sets it). 3D (glb/gltf, read here, never the hosted
1094
+ bench): missing or broken textures, open or non-manifold edges (welded by position),
1095
+ NaN positions, triangles over a budget (--triangles, funpixel.json review.triangles,
1096
+ design/specs); Draco/meshopt geometry is not decoded (its edges not observed).
1097
+ Pictures: does not decode, a sprite or cut-out with no alpha (by its name, the asset
1098
+ manifest, a spec, --alpha), a size off its spec (design/specs, --size), off the
1099
+ project's palette (only when it has one), a tile whose edges do not meet. Every
1100
+ counter is three-state: one a file cannot answer is not observed, with why, never
1101
+ 0. The project is the nearest folder with design/ or funpixel.json at or above the
1102
+ path (--dir names it); review keeps .funtools/review.json so one file's re-review
1103
+ replaces only its own counts. Folders skip node_modules, dist, build and raw
1104
+ exit 0 every observed counter zero · 1 one is not · 2 nothing observed (no media, no ffmpeg) · 3 error
1105
+ journal the creator's journal: one line per change a PERSON made (by hand, in the editor, a
1106
+ tuned number), with who and why, in .funtools/journal.jsonl (never ships). The GDK's
1107
+ session start shows the recent ones so the agent keeps them; it also records files
1108
+ that changed while no agent turn ran, marked detected (who and why unknown). Run in
1109
+ an agent's shell the line says via the agent. No text: the entries
1110
+ exit 0 recorded or listed · 2 nothing recorded · 3 error
1111
+ decide the decisions log: one choice against its alternative, with the reason, as D<n> in
1112
+ design/decisions.md (never ships). --supersedes D3 replaces one and keeps both on
1113
+ the record. The GDK's session start lists the live ones; \`gdd\` reads them. No
1114
+ text: the decisions, live first. --from N3: the owner's note becomes a decision citing
1115
+ their words and screenshot, open until a lane builds it (the briefs that touch it carry it)
1116
+ exit 0 recorded or listed · 2 none yet · 3 error
1117
+ lanes a stage split into lanes that run at once, each in its own git checkout (branch lane/<id>):
1118
+ \`plan\` proposes them (play, look, feel, audio, env, room-<id>) and writes each brief (scope,
1119
+ what it owns and stays out of, the owner's open decisions that touch it, the evidence that
1120
+ closes it, a $ cap, a time-box, 45-min checkpoints, how to hand back and report); \`start\`
1121
+ makes the checkout and prints the host call (Claude Code: one Agent call per lane). Paid
1122
+ funtools calls in a lane's checkout are logged against it and refused past its cap. \`done\`
1123
+ runs the gate on the lane's commit (synced, owns, tests, sim, the look floor 75 on its
1124
+ frames, funpixel.json lanes.gates commands such as a spec lint, a checkpoint); a seat that
1125
+ did not build it records \`verdict\`; \`merge\` is refused until the gate, the verifier and
1126
+ the owner's picks pass, then merges --no-ff and writes design/MAKING.md
1127
+ exit 0 done · 1 refused · 2 no lanes · 3 error
1128
+ pick the owner picks by eye between two to four candidate frames, shown in the chat; the choice is recorded
1129
+ with each frame above its button; it never defaults, the lane it names cannot merge until
1130
+ the owner answers, and the choice becomes a decision in design/decisions.md
1131
+ exit 0 done · 1 not the owner's word · 2 no picks · 3 error
1132
+ flow one entry for the whole run: where it is (planning, the plan put to the owner, round N on a
1133
+ stage), the ONE next step with the exact command, and why, recorded in .funtools/flow.json.
1134
+ \`flow start\` makes the game (init) from the brief (its title, kind and size read from the
1135
+ sentence) and asks nothing. The plan is made with the owner in the chat (the GDD skill);
1136
+ \`flow ask\` puts it to them once with its price (the asset script at list price) and what it
1137
+ still owes, as warnings, never a refusal; \`flow agree --by owner "<their words>"\` locks it and
1138
+ the approved price becomes the budget. Then round after round on the build: the look-dev loop
1139
+ (capture, compare --target, fix the biggest difference, play), a card with a frame of the
1140
+ build, the owner's notes picked up; \`flow round\` closes a round only on that evidence. The
1141
+ GDK's Stop keeps the rounds going up to funpixel.json flow.rounds_per_session (default 3), then
1142
+ hands back ("resume with /fp:flow"). \`flow ask\` and the cards carry the kit's own read (score,
1143
+ panel, blind player, world, first look): "Below the bar: …" first, "Not judged yet" when
1144
+ nothing ran. \`flow drop --by owner\` ends the game: notes close as dropped, \`flow\` names no step.
1145
+ After the first playable and every few rounds (funpixel.json flow.look_every, default 3; 0
1146
+ is off) the step is the whole-game look: \`flow look\` writes its brief for a fresh agent
1147
+ (would you ship this today? each defect a severity and an owner) and, once filed, routes
1148
+ each defect to the lane of its kind, the owner or the round. It never vetoes
1149
+ exit 0 a step · 1 the round lacks evidence (or agree without --by owner) · 2 not a game folder · 3 error
1150
+ owner the owner's standing bar, carried to every new game: short lines in ~/.funpixel/owner.md (the
1151
+ person's) and an optional <repo>/.funpixel/owner.md (the team's). \`flow start\` (and each
1152
+ \`flow\`) matches it to the game, never blindly: a line that applies becomes an owner note,
1153
+ open until evidence closes it; one that does not is skipped with a reason the owner reads
1154
+ ("creatures: a one-screen word puzzle has no world"); one the kit cannot tell is kept as
1155
+ applying, with why. design/owner-bar.json keeps the match; apply/skip flip a line.
1156
+ seed writes the owner's requests of 4 Oct
1157
+ exit 0 done · 1 nothing matched · 2 no bar yet · 3 error
1158
+ firstlook the first look's required set, the whole game: key art; every screen (title as the play
1159
+ world, pause, the end; past small settings, results, a level select); the HUD on the phone
1160
+ and the desktop; a frame per place tied to a story beat and a living-world sheet (a world
1161
+ game only); an animation board, a juice board, the sound list, the fun page. Scaled by tier
1162
+ and by the game; the first-look gate and \`flow ask\` wait on it; the owner drops an item with
1163
+ skip --by owner. Shown in the chat, grouped. render: the code-drawn route, the studies the
1164
+ game's own draw code composes on design/first-look/draw.html (window.__FPX_FIRSTLOOK__ resolves
1165
+ to { name: PNG data URL }), served by the game's Vite and written to design/first-look/<name>.png
1166
+ exit 0 complete · 1 items missing · 2 not a game folder · 3 error (render: 0 written · 1 none or
1167
+ a refused one · 2 no headless browser · 3 error)
1168
+ note the owner's notes on the stage they affect, in design/pipeline.json: add (the owner's words,
1169
+ --screenshot as the named before-frame), close with evidence that exists (a file in the
1170
+ game, a commit, a test name in test/; a design note: a commit that changes design/) or
1171
+ on the owner's word (--by owner --force),
1172
+ verdict accept|reject (the owner's: outranks any agent claim; a reject reopens a closed note; on a stage it is that stage's owner gate)
1173
+ exit 0 done · 1 the evidence does not exist · 2 no notes · 3 error
1174
+ progress the run's record, in .funtools/progress.jsonl (read by the next session and the hand-back): a
1175
+ card at each stage move with a frame from the built game (--shot last = the newest capture; a
1176
+ card with no frame or evidence is kept and marked not observed, a design/ picture is marked "a
1177
+ picture, not the build"); a heartbeat when a stage runs long (the third on one gate becomes a
1178
+ stuck card asking skip / cut / keep going); questions only at forks (taste, spend, scope), asked
1179
+ in the chat and answered with \`progress answer\` in the owner's words, with a default that lands
1180
+ after its timeout under autonomy go ("decided without you; reply to reverse"); --spent past the
1181
+ approved budget makes a pause card. Each card picks up the owner's new notes and answers.
1182
+ report is the hand-back from the cards. FUNPIXEL_NOTIFY_URL (ntfy, Slack, Discord) hears only
1183
+ "needs you" and "done"
1184
+ exit 0 done · 2 nothing yet / still open · 3 error
1185
+ feedback what creators said about the kit: \`collect\` reads every .funtools/devlog.jsonl and
1186
+ .funtools/kit-feedback.jsonl under the folders (eval copies of one game count once) and
1187
+ ranks what worked, what hurt and what was missing, by tool, with counts, the games
1188
+ and quotes; lines about the game only are counted, not ranked. Reads, never uploads
1189
+ exit 0 reported · 2 no feedback found · 3 error. \`log\` appends one dev-log line,
1190
+ stamped, to the game's .funtools/devlog.jsonl (no heredoc or >> needed). Beside the kit tools,
1191
+ collect ranks the GAME's practice: the owner first (owner lines and each game's pipeline
1192
+ notes outrank any agent claim), what worked by its measured change (--before/--after, or
1193
+ "34 -> 25.5 ms" in the words; a lesson that says it fixed something counts), each entry's
1194
+ evidence checked to exist (a file, a commit, a test; else unverified), dead ends by the
1195
+ hours they burned, cost and time per game, and A/B records (.funtools/ab.jsonl) as "GDK
1196
+ lost level design by 1.8 in 1 of 2". --propose drafts one kit edit per top recurring lesson;
1197
+ --html writes one page with filters. \`ab\` records an A/B; \`merged\` writes the merge
1198
+ commit as a worked entry with the numbers the tools logged since its merge base (sim,
1199
+ play, hook, life, profile and playtest log theirs as measure lines on their own)
1200
+ character the character library: characters animated already. list shows the shelf
1201
+ (2D sheets with idle, walk, run, jump, attack, hit, death and blink; 3D rigged GLBs
1202
+ with every clip by name on one humanoid rig); get copies one into
1203
+ public/assets/characters/<id>/ for free; restyle gives it your look (--game-id:
1204
+ your style lock) and keeps every motion, priced per frame (--animations: fewer)
1205
+ pack exactly what an upload carries, a leak scan, the server's limits and a
1206
+ build from the staged copy; never uploads (exit 1 = must not be uploaded)
1207
+ export the game as a clean folder of build inputs for another repo: index.html, src/,
1208
+ public/, package.json + lock, tsconfig, vite.config, funpixel.json cut to name,
1209
+ splash, metadata, checks and hooks, a two-line .harnessignore; notes, design,
1210
+ evidence, agent files, tests, scripts and the Funpixel splash card (unless
1211
+ "splash": "funpixel") stay behind. Every source comment is removed (the
1212
+ game's TypeScript parser and printer; CSS too), then the dev folder and the clean
1213
+ folder are both built and the bundles must be byte-identical. Reports leaks
1214
+ (secrets, home paths, tool and provider names), absolute /public URLs in code, a
1215
+ dev .harnessignore that excluded a build input, then runs the clean build: verify
1216
+ at both sizes, audit-screens phone portrait and landscape, and every request the
1217
+ page makes on every view (a 404 = a file the folder lost). Mobile findings (viewport
1218
+ meta, safe area, hover-only UI, keys with no touch route, small text and targets)
1219
+ are the game's to fix and never block. --check reports and writes nothing.
1220
+ --strip-metadata removes text chunks and C2PA content credentials from public
1221
+ PNGs, where a generator writes its own name (the owner's call: off by default)
1222
+ exit 0 clean (written) · 1 a problem, nothing written · 3 error
1223
+ gen generate an asset with the Tools API, follow the job and save the files into
1224
+ the game (default public/assets/images|sprites|sfx|music|models/, the folders
1225
+ the scaffold reads); --cast <id> makes it from that cast member's master (reference 1
1226
+ of a picture with its keep-line, the source of an edit or sheet, the image of a model)
1227
+ and holds the result to it by numbers when it lands (cast check); inspect
1228
+ measures a model you made, optimize-model decimates it to a budget, fracture
1229
+ breaks it into shards, lod makes its
1230
+ levels of detail, rig authors clips onto a bare biped rig (or fits a
1231
+ donor's rig onto a bare mesh) after a free rig check, render photographs it
1232
+ (views round it, a front view, a contact sheet), finalize repairs broken
1233
+ materials, drops clips not kept and renders the proof; pictures go to
1234
+ .funtools/renders/<name>/, never shipped; texture is a seamless tile and strip
1235
+ a scrolling layer (refused, uncharged, if it shows a seam); skybox is a 360°
1236
+ equirect sky; find-material searches Poly Haven's free CC0 library and
1237
+ material copies one asset (HDRI, texture set, glTF model) into
1238
+ public/assets/materials/<name>/, its licence and source recorded; video makes
1239
+ a 5 or 10 s clip (generated, never gameplay: for trailer cards) into .funtools/video/;
1240
+ --camera-move static|pan_left|pan_right|tilt_up|tilt_down|dolly_in|dolly_out|orbit_left|orbit_right|
1241
+ crane_up|handheld, --lens wide|normal|tele|macro, --aperture deep|shallow, --camera-speed slow|normal|fast:
1242
+ camera words the model takes (its own control or a fixed phrase; one it does not take is refused);
1243
+ lipsync --image-asset <portrait> --audio-asset <line.mp3> [--duration <s>] [--resolution 480p|720p] makes
1244
+ the portrait speak the line (up to 60 s, priced per second; the portrait must be your own face or a
1245
+ character you made, never a real person who has not agreed) into .funtools/video/;
1246
+ dialogue <scene.json> speaks a scene (an array of {speaker, text, voice?, tags?, pause_after_ms?,
1247
+ track?}, or {lines, cast?, gap_ms?}; a voice is a preset or a cast voice.json; --gap ms, default 250)
1248
+ into public/assets/voice/<scene>/: dialogue.mp3 (one mixed file), line-NN.mp3, dialogue.json (the
1249
+ timeline: tracks by speaker, each clip's start and length); priced as its lines
1250
+ --model <id> on image, sprite, sound, music, voice, line, dialogue, video, edit-video, lipsync and model3d: a model
1251
+ from the registry (the ids: GET /v1/tools/models, or an unknown one's refusal, which lists
1252
+ them); omitted, our recommended pick runs, with its fallback; named, it runs alone, never swapped.
1253
+ voice, line and dialogue also take --model kokoro-82m: Kokoro on this Mac (Apple Silicon, free, offline, slower,
1254
+ not checked by us; set up once with funtools models install kokoro-82m, else exit 2 naming it)
1255
+ options: image/texture/strip/sprite --size WxH, snapped to the nearest of 1:1 3:2 2:3 4:3 3:4
1256
+ 16:9 9:16 21:9 (1024x1024, 1536x1024 → 3:2, 1024x1536 → 2:3, 1792x1024 → 16:9, 1024x1792 → 9:16;
1257
+ the model picks the pixels for the shape); --quality low|medium|high: an image is
1258
+ 2 · 4 · 12 credits (low · medium, the default · high; a square, the dearest shape;
1259
+ funtools estimate image prints the exact figure before you spend)
1260
+ --target-size px (the file's longest side: the size the game shows it at; scaled down on
1261
+ the server after drawing, never up, so a 60 px sprite does not ship at 1024²),
1262
+ image/strip --transparent; skybox --negative "what not to show";
1263
+ find-material --type hdri|texture|model --limit 1-20;
1264
+ material --type hdri|texture|model (--id id | "keywords") --resolution 1k|2k;
1265
+ sound --duration secs --loop; music --length clip|full --instrumental;
1266
+ model3d --image-url https://… | --image-asset <file|id> [--back-asset --left-asset
1267
+ --right-asset <file|id>: more sides of the subject, so its back is drawn, not invented],
1268
+ --style standard|hero|lowpoly (standard ≈30K triangles; hero is static only: 300K triangles
1269
+ on Meshy 7.1 at 4K geometry, 500K faces on Hunyuan 3.1), --model meshy-7.1|hunyuan-3.1|rodin-2.5
1270
+ (or --engine meshy|hunyuan|rodin, the older name: that engine alone, no fallback; Meshy ships
1271
+ 2048 px maps, Hunyuan 4096 px PNG; rodin, only when named, is Rodin 2.5: static only,
1272
+ hard-surface props, every view in one job, 50K triangles and 2048 px PBR maps, hero 500K with
1273
+ 4096 px maps, lowpoly 8K untextured; its prices are the rodin rows of funtools estimate), --raw (the
1274
+ engine's GLB byte for byte: every triangle, full maps, no optimizer pass, same price),
1275
+ --score name=ref.png,name=ref.png (when it lands: funtools fidelity on it, free; with
1276
+ --unity the engine's GLB is scored before it is split for glTFast),
1277
+ --animations walk,run; inspect --asset id; optimize-model --asset id
1278
+ --budget food|prop|thin_walled|set_piece|character [--device phone|desktop]
1279
+ [--height metres]; fracture --asset id [--pieces 2-32] [--seed n];
1280
+ lod --asset id [--levels 1-4] [--ratio 0.05-0.95] [--min-triangles n];
1281
+ rig --asset id [--clips idle,walk,attack,death | --donor id];
1282
+ render --asset id [--frames 1-12] [--size 64-1024]; finalize --asset id
1283
+ [--keep-clips Idle,Walk]; motion --asset id --motions '[{"kind":"wave"}]' (wave nod hop strike
1284
+ flinch celebrate, dials in tuned ranges) [--base-clip idle]; retarget --asset id
1285
+ (--donor id | --character robot-3d) [--only walk,run]; video --duration 5|10 [--aspect 16:9|9:16|1:1]
1286
+ [--image-asset id | --image-url https://…] (a still to animate)
1287
+ edit "the one change" --asset <file|id> [--mode edit|restyle|pose] [--game-id id]: the
1288
+ same picture changed, a cut-out kept a cut-out (a blink, a hurt face, a second step);
1289
+ sheet ["the character"] [--asset <sprite file|id>] --cycles idle:4,walk:6[@fps]
1290
+ [--view side|front, never from above: edit --mode pose] [--body biped|quadruped|flyer]
1291
+ [--frame-size 64-512] [--game-id id]
1292
+ (blink:1 is the eyes-shut swap; a flyer's walk and run fly): every frame an edit of one
1293
+ base, checked for drift, packed into public/assets/sprites/<name>/sheet.png + sheet.json
1294
+ (Pixi AnimatedSprite: sheet.animations.walk); priced per frame (look --sheet
1295
+ measures its loops). A picture prompt that names the game (funpixel.json name)
1296
+ is warned about: image models letter the name and garble it; --strip-title
1297
+ sends it without the name
1298
+ --unity <project> (a Unity project, or the folder holding its unity/): the files go into
1299
+ its Assets/_Game/Generated/<Images|Sprites|Textures|Materials|Skyboxes|Models|Sfx|Loops|
1300
+ Music|Voice>/ with an import rule (Generated/Editor/FunpixelGenImport.cs) that sets each
1301
+ kind's settings when Unity first imports it: sprites as Sprite, normal maps as NormalMap,
1302
+ ASTC by role, audio by length (SFX mono ADPCM, loops PCM, music Vorbis streaming); no
1303
+ .meta is written (Unity mints its GUID). A model is the engine's own GLB (--raw) split
1304
+ into .gltf + .bin + model__basecolor/__normal/__mr PNGs for glTFast; audio is 48 kHz WAV
1305
+ (ffmpeg). Takes image, sprite, strip, edit, sheet, texture, material, skybox, model3d,
1306
+ sound, music, line
1307
+ exit 2 also covers a key the server refused (unauthorized, insufficient_scope)
1308
+ exit 0 done · 1 the job failed · 2 refused before it ran (confirm with --yes,
1309
+ credits, the key's budget, the plan, rate limits) · 3 error
1310
+ estimate what a gen would cost, in credits, without running it
1311
+ models the generation models gen --model takes, from the registry: per kind our pick first (recommended,
1312
+ what runs when --model is left out), the other hosted models, then any that run on this Mac with
1313
+ whether they are set up here. install sets up a local one: kokoro-82m (a voice, Apple Silicon only)
1314
+ gets its runner with uv tool install (mlx-audio) and its weights into ~/.funpixel/models/ with a
1315
+ progress line. A local model is free and offline, slower and not checked by us; it runs only when
1316
+ named (gen voice|line|dialogue --model kokoro-82m), never in place of ours, and its files are recorded
1317
+ generated_by local:<id>. funtools doctor shows the same in its Local models block
1318
+ exit list 0; install 0 set up · 1 the install failed · 2 refused (a hosted id, needs Apple Silicon,
1319
+ no uv) · 3 error
1320
+ assets an optional pipeline for a game that makes many assets from text: items in
1321
+ assets/assets.json (name, kind image|sprite|sheet|texture|strip|sound|music|model3d,
1322
+ subject, family, role size, draws, atlas, anchors, depth, variants, from, params),
1323
+ each subject composed with assets/style.json (medium, the family's clause, never);
1324
+ .funtools/assets.lock.json records what made each file (request hash, job, asset,
1325
+ credits, sha256, the gate's verdict, the kept draw, earlier versions). status says
1326
+ fresh | stale | missing | rejected | edited per item, orphans and credits spent (free,
1327
+ offline). gen makes only missing and stale items in one generate_batch (--only,
1328
+ --family, --stale narrow it; the server keys each item by its content, so a rerun
1329
+ never pays twice), shows the estimate first, asks above 50 credits (--yes), stops
1330
+ at --max-credits; --dry-run shows every prompt and the estimate and sends nothing.
1331
+ draws: N keeps the first the gate accepts, all in .funtools/assets/draws/<name>/.
1332
+ regen re-makes one item and records --because in the lock and style.json failures.
1333
+ process keys (free key_sprite) and trims cut-outs, shrinks each to its role size,
1334
+ desaturates depth planes, packs atlas groups with the local optimizer and writes
1335
+ src/art/assets.json: relative URLs, anchors, a brightness tint per piece.
1336
+ A game declaring "pixelArt": { "scale": 4, "palette": ["#hex", …] } in funpixel.json
1337
+ has process (and gen) snap each picture to that grid and palette instead (hard
1338
+ alpha, one ink per art pixel, originals kept); pixels measures every PNG under
1339
+ public/assets/ (or the files named) for grid blocks that are not one colour, soft
1340
+ edges and inks off the palette, each three-state; --snap snaps the named files first
1341
+ exit 0 done · 1 something stale, missing or failed · 2 refused (confirm, cap) · 3 error;
1342
+ pixels: 0 on the lane · 1 off it · 2 not observed (no lane declared, nothing drawn)
1343
+ More kinds: pose (an edit of the cast master in the pose its subject names), rig (rig_model →
1344
+ author_motion "motions" → retarget_clips "retarget" on a made model3d, "from"), parts (cut
1345
+ from a "sheet" locally, free); a model3d's draws are a bake-off judged against its master
1346
+ (rendered with your Blender, free); "optimize": {device} runs optimize_model after.
1347
+ A picture of a cast member (its "cast", or a name that starts with the id) is drawn with
1348
+ the master attached first and the card's words in its prompt, then held to the master: a
1349
+ drift gets one targeted edit, then one redraw, then is kept as the best and named
1350
+ (lock: identity); the masters ride the first batch as the game's locked sheets ref-<id>.
1351
+ gen goes in batches of --batch (24), each priced before it is sent, and keeps to the
1352
+ owner's asset budget (assets budget) unless --max-credits says otherwise.
1353
+ script turns the plan's "## Asset script" rows (ID | What | Kind | Count | Cast) into
1354
+ manifest items (--write); budget records the owner's credits for them.
1355
+ cast the cast library: design/cast/<id>/ (master.png, turnaround.png, palette.json, card.json/md).
1356
+ add accepts a master; list names them; check holds pictures to a master by numbers
1357
+ (silhouette, colour, lost main colours): exit 0 on model · 1 drift · 2 not observed · 3 error
1358
+ job a job's status; --wait follows it to the end and saves its files (exit as gen)
1359
+ jobs your account's jobs, newest first, a page at a time; --tool takes a tool
1360
+ or a gen kind; a page with more prints the command for the next
1361
+ page; --refusals tallies, per tool, how often your own jobs were refused and by
1362
+ what (policy, a gate, bad input) over the latest 500: our routes measured, not a ranking
1363
+ optimize the Studio's asset optimizer on local files, offline and free. With no op: what
1364
+ the agent's optimization rule would flag (images of 400 KB or more, 4+ loose
1365
+ sprites); --check exits 1 on that (CI). With an op: a dry run unless --write,
1366
+ which also prints the brief your agent needs to change the loading code.
1367
+ optimize-mesh --levels phone,desktop,high cuts one GLB per device class beside
1368
+ the source (never replacing it) plus name.levels.json for the SDK's loadLevel;
1369
+ --class sets the triangle budget (skinned = character, else prop), --out-dir
1370
+ puts the levels elsewhere (a source kept outside public/). Output is
1371
+ Draco (static) or meshopt (rigged) with KTX2 textures; FUNPIXEL_GLB_KTX2=off
1372
+ keeps PNG/JPEG textures, FUNPIXEL_GLB_COMPRESS=draco|meshopt forces one codec
1373
+ (no uncompressed output yet: a page that cannot run the decoders needs a decode)
1374
+ playable the game as one ad network's playable: one HTML file in dist-playable/ (from
1375
+ playable.html when there is one), weighed against the network's ceiling, searched
1376
+ for anything it would fetch, then played offline on a phone with the network's
1377
+ call to action stubbed — it must fire on the end card, after the reward
1378
+ exit 0 pass · 1 fail · 2 not observed · 3 error
1379
+ trailer a store/social trailer from REAL play: the game filmed as reel films it,
1380
+ cut on the beat of its own music (the bed it loops, public/assets/music/, or
1381
+ --music) with its OWN sound effects where they played in the kept shots
1382
+ (--no-sfx leaves them out; synthesised sounds are listed, never faked), mixed
1383
+ to -16 LUFS / -1.5 dBTP, shots on its __FPX_MOMENT__ payoffs, a title card from its key art
1384
+ (design/key-art.png, or --key-art) and an end card; 16:9 and 9:16 MP4s and
1385
+ trailer.json (every segment's source) in .funtools/trailer/, never shipped.
1386
+ 1:1 and 4:5 too; --for names where it is posted (tiktok, reels, shorts,
1387
+ stories, feed, square, youtube, store, site) and picks the formats; every
1388
+ card and label sits inside that format's clear area (the platform's own
1389
+ header, side rail and caption block never cover it: src/trailer/placement.ts).
1390
+ --intro/--outro add generated clips (gen video) as cards only, each labelled
1391
+ on screen as not gameplay. Needs ffmpeg. exit 0 written · 3 error
1392
+ reel a vertical share video of the game being played: the built game toured
1393
+ through its __FPX_VIEWS__ (title, play, ending) and driven by its own
1394
+ __FPX_VERBS__ (else its __FPX_KEYS__), filmed and cut to a 1080x1920 MP4
1395
+ with ffmpeg (default .funtools/reel/reel.mp4, never shipped); with no
1396
+ ffmpeg on PATH, or --frames-only, the PNG frames are the output
1397
+ motion the Motion bench: title cards, trailer shots, UI motion, logo stings and social loops for
1398
+ any trade (a single's visualiser, a podcast's audiogram, a film's titles, a game's trailer).
1399
+ A scene is a page that draws frame f (CSS, canvas, SVG or GSAP), which may say
1400
+ window.__MOTION__ = { seconds, fps, size, loop } and may draw any frame on demand with
1401
+ window.__MOTION_SEEK__(frame); flags beat it. render serves the scene (its folder as files,
1402
+ or its project's own Vite), opens it headless on the held clock (one frame = 1000/fps ms,
1403
+ Math.random seeded) and shoots every frame to <out>/frames/000001.png…, then encodes
1404
+ motion.mp4 (H.264, yuv420p, faststart; --webm adds VP9; --audio is muxed and fitted to the
1405
+ length) and checks it: safe zone (text and controls inside the format's clear area, uncut)
1406
+ and overlaps (text over text), both by layout.js at the first frame, every 0.5 s and the
1407
+ last; loop seam (a loop's wrap frame against its first); blank frames (nearly one colour,
1408
+ outside the first and last 0.5 s); repeatable (--prove renders twice, every frame's bytes
1409
+ compared). motion.json holds the plan, every frame's hash and the checks; a project's
1410
+ design/status.json gets a motion part on the zero board (errors, overlaps, seams).
1411
+ Default out .funtools/motion/<scene>/ (never shipped). check judges a render folder again
1412
+ (or renders a scene without encoding); new writes <name>/index.html, a starter that passes
1413
+ exit 0 pass · 1 a check failed · 2 not observed (no browser) · 3 error
1414
+ compose HTML-composition video: a trailer, a 9:16 post or a playable ad's end card written as a
1415
+ HyperFrames composition (HTML, timed clips on tracks, GSAP titles, <audio>) with the game itself
1416
+ as a live clip (<iframe data-fpx-game="game/index.html">) that the composition's clock drives on the
1417
+ held clock (inputs on their frames; a game the clock cannot hold is filmed), rendered locally and
1418
+ deterministically by HyperFrames (Apache-2.0, run at its pinned version: headless Chrome seeks each
1419
+ frame, FFmpeg encodes). new writes design/compose/<name>.html from the game's build, key art,
1420
+ captures and sound; check runs the contract, the tools, the game probe and HyperFrames' lint; render
1421
+ writes .funtools/compose/<name>.mp4, <name>.sheet.jpg (12 frames to look at) and <name>.json.
1422
+ variations makes ad cuts from one brief (hooks, each with the capture or view it opens on, calls to
1423
+ action, lengths, aspects, an end card, max): at most max of the cross product, every value in a cut
1424
+ before any pair repeats, each its own composition (design/compose/ads/<id>.html) rendered on one stage;
1425
+ .funtools/compose/ads/<id>/ (mp4, contact sheet, record), index.json and sheet.png (a labelled frame
1426
+ per cut: the person picks which to publish). An end card unlike the playable's own words is a warn
1427
+ line; --dry-run prints the plan and renders nothing.
1428
+ Needs Node 22+, ffmpeg and Playwright's headless Chromium (each missing one is named with its fix).
1429
+ exit 0 pass · 1 the composition or a check failed · 2 not observed · 3 error
1430
+ model the hosted Blender bench on a model a job of yours made, by asset id or by the
1431
+ file gen saved it as — nothing is uploaded; a file you changed since, or one no
1432
+ job made, is for --local. inspect measures it (free); render photographs it
1433
+ (--frames, --size: views round it, a front view, a contact sheet); finalize
1434
+ repairs broken materials, drops clips not in --keep-clips and renders the proof;
1435
+ skin has a vision pass mark the exposed skin and paints it one --tone (reuse the
1436
+ tone across a cast); retexture repaints the model's four sides with the new look
1437
+ (your game's style lock with --game-id) and projects them back onto its textures;
1438
+ level builds a spec (rooms, walls, ramps, props, markers; TOOLS_API.md) into a GLB
1439
+ with colliders and named markers, plus a plan and a corner view.
1440
+ Pictures go to .funtools/renders/<name>/ (never shipped). Exit as gen.
1441
+ --local: the bench's verbs on your own Blender 4.2+ (found in Applications,
1442
+ Program Files or PATH, or FUNPIXEL_BLENDER_BIN): free, nothing is uploaded.
1443
+ inspect describes it; normalize (--height-m) and decimate (--target-triangles,
1444
+ never welds) write <name>.<verb>.glb or --out; render writes its PNGs to
1445
+ .funtools/renders/<name>/ or --out; finalize writes <name>.finalize.glb and
1446
+ its proof pictures; level builds a spec on your Blender, free, into
1447
+ public/assets/models/<name>.glb and .funtools/renders/<name>/. The bench scripts ship with
1448
+ funtools under their own GPL-3.0-or-later licence (FUNPIXEL_BENCH_DIR overrides)
1449
+ exit 0 done · 1 Blender refused the model · 3 setup error
1450
+ clips: the animation clip names in a GLB/glTF, read locally (no Blender, free),
1451
+ and any name inside another (run / run_fast, idle / idle_long, walk / walkback),
1452
+ repeated or missing: a lookup by name can play the wrong clip
1453
+ exit 0 every name apart · 1 a collision · 2 no clips (not observed) · 3 error
1454
+ fidelity how closely a 3D model matches its reference views, 0-100 each (the owner's
1455
+ scorer): silhouette 35%, palette 30% (ΔE), tonal structure 20%, ink lines 15%, each view
1456
+ against its best of the bench's 48 fixed cameras (8 yaws × 3 heights × both ways up),
1457
+ rendered on your own Blender 4.2+ (free) at the references' own size, or --renders <dir>.
1458
+ --own-axes for a model built square to its axes (no PCA), --roll for a deep model squared
1459
+ onto its side, --outline for inked references, --quarter-turns for a figure standing
1460
+ taller than long. It also names references no one object can match (proportions, parts,
1461
+ and --same-scale sizes on one sheet). scores.json + sheets in .funtools/fidelity/<model>/
1462
+ exit 0 scored (all ≥ --min) · 1 a view under --min · 2 nothing scored · 3 error
1463
+ login sign in in a browser (device code) and keep a new API key in the OS credential
1464
+ store; --key stores a key you made in Settings › Developers (--key - reads stdin)
1465
+ --api <url> signs in to another API (a local stack) and remembers it for later runs
1466
+ --scope names the new key's scopes instead of the default set (every scope but
1467
+ community:read and community:write, which a key holds only when asked for), e.g.
1468
+ --scope community:read,community:write for a key that reads and acts in Community
1469
+ whoami the account and key funtools is using
1470
+ usage credits charged by tool and by day, this UTC month or the last --days;
1471
+ --this-key counts only the key funtools is using
1472
+ budget this key's monthly credit cap, what it spent this month, the spend alerts it
1473
+ crossed (50, 80, 100%) and what the wallet holds; the cap is set in
1474
+ Settings › Developers
1475
+ logout remove the stored key
1476
+ publish funpixel (default): upload the staged game as a draft you own (needs a fresh
1477
+ verify.json and an API key). itch / pages / folder: ship dist/ elsewhere — the
1478
+ command is shown, and runs only with --yes or your confirm; logged to
1479
+ .funtools/publish.jsonl
1480
+ store the read-only half of store publishing (Google Play, the App Store, Steam), offline: \`init\` writes
1481
+ store/answers.json from what the game says (funpixel.json's name, the GDD's pitch), every other answer an
1482
+ explicit TODO (ids, prices, the SDK list, ages: the owner's); one SDK list gives both stores' privacy
1483
+ answers. \`doctor\`: what this Mac has for each store (asc and its version, DO_NOT_TRACK, the Play service
1484
+ account key's path in .env — only that the file exists, never its contents —, steamcmd), each line with
1485
+ its next step; never signs in, never calls a network API. \`lint\`: the answers against each store's rules
1486
+ (lengths, other stores' names, art sizes read from the files, the privacy URL, the privacy forms against
1487
+ the SDKs). \`plan\`: the ordered steps, each Script / Console / You as the store-readiness references
1488
+ mark them, what is already true, and a plan hash (answers + art bytes + store); .funtools/store-plan.json.
1489
+ store push and store release are not built yet
1490
+ exit init 0 written · 2 already there; doctor/lint 0 clean · 1 a line failed; lint/plan 2 no answers · 3 error`;
1491
+ export function commandHelp(command) {
1492
+ const [synopsis, described] = USAGE.split('\n\n');
1493
+ const pick = (lines, starts, more) => {
1494
+ const out = [];
1495
+ let on = false;
1496
+ for (const l of lines) {
1497
+ if (starts(l))
1498
+ on = true;
1499
+ else if (!more(l))
1500
+ on = false;
1501
+ if (on)
1502
+ out.push(l);
1503
+ }
1504
+ return out;
1505
+ };
1506
+ const syn = pick(synopsis.split('\n').slice(1), (l) => l.startsWith(` funtools ${command} `) || l === ` funtools ${command}`, (l) => /^ {4,}\S/.test(l) && !l.startsWith(' funtools'));
1507
+ const desc = pick(described.split('\n'), (l) => new RegExp(`^ ${command} +\\S`).test(l), (l) => /^ {11,}\S/.test(l));
1508
+ return ['usage:', ...syn, '', ...desc].join('\n');
1509
+ }
1510
+ const message = (e) => (e instanceof Error ? e.message : String(e));
1511
+ export function parse(rest, spec) {
1512
+ const flags = {};
1513
+ const positionals = [];
1514
+ for (let i = 0; i < rest.length; i++) {
1515
+ const a = rest[i];
1516
+ if (!a.startsWith('--') || a === '-') {
1517
+ positionals.push(a);
1518
+ continue;
1519
+ }
1520
+ if (!Object.hasOwn(spec, a))
1521
+ return `unknown flag: ${a}`;
1522
+ if (!spec[a]) {
1523
+ flags[a] = true;
1524
+ continue;
1525
+ }
1526
+ const v = rest[i + 1];
1527
+ if (v === undefined || (v.startsWith('--') && v !== '-'))
1528
+ return `${a} needs a value`;
1529
+ flags[a] = v;
1530
+ i++;
1531
+ }
1532
+ return { positionals, flags };
1533
+ }
1534
+ const str = (v) => (typeof v === 'string' ? v : undefined);
1535
+ const frontDoorOf = (flags) => str(flags['--click']) ?? (flags['--front-door'] ? FRONT_DOOR : null);
1536
+ function heldOf(flags, u) {
1537
+ const raw = str(flags['--seed']);
1538
+ if (raw !== undefined && !/^-?\d+$/.test(raw)) {
1539
+ u.error(`--seed ${raw}`, '--seed is a whole number (window.__FPX_SEED__ and Math.random play from it)');
1540
+ return null;
1541
+ }
1542
+ if (raw !== undefined && flags['--free-running']) {
1543
+ u.error('--seed goes with the held clock', 'drop --free-running, or --seed');
1544
+ return null;
1545
+ }
1546
+ return { ...(raw !== undefined ? { seed: Number(raw) } : {}), ...(flags['--free-running'] ? { freeRunning: true } : {}) };
1547
+ }
1548
+ function orientationOf(flags, vp, u) {
1549
+ const o = str(flags['--orientation']);
1550
+ if (o === undefined || (vp === 'phone' && (o === 'portrait' || o === 'landscape')))
1551
+ return o;
1552
+ if (o !== 'portrait' && o !== 'landscape')
1553
+ u.error(`unknown orientation: ${o}`, '--orientation is portrait or landscape');
1554
+ else
1555
+ u.error(`--orientation ${o} turns the phone`, 'add --viewport phone');
1556
+ return null;
1557
+ }
1558
+ const GEN_COMMANDS = new Set(['gen', 'character', 'estimate']);
1559
+ const GEN_SPEC = { ...Object.fromEntries(Object.entries(GEN_FLAGS).map(([f, d]) => [f, d.value])), '--json': false, '--score': true };
1560
+ const LOOK_SPEC = { '--viewport': true, '--front-door': false, '--click': true, '--json': false };
1561
+ export const SPECS = {
1562
+ init: { '--framework': true, '--name': true, '--offline': false, '--idea': true, '--bare': false, '--no-git': false },
1563
+ dev: { '--no-devtools': false, '--relay': false, '--bots': true, '--no-hold': false, '--phone': false, '--host': true, '--open': false },
1564
+ open: {},
1565
+ serve: { '--port': true, '--host': true, '--no-compress': false },
1566
+ find: { '--json': false },
1567
+ mcp: {},
1568
+ setup: { '--host': true, '--dry-run': false, '--json': false },
1569
+ doctor: { '--add-hooks': false, '--host': false, '--json': false },
1570
+ upgrade: { '--self': false, '--discard': false },
1571
+ smoke: { '--json': false },
1572
+ 'smoke-build': { '--plan': true, '--json': false },
1573
+ test: { '--node': false, '--goals': false, '--json': false },
1574
+ check: { '--viewport': true, '--phone': false, '--front-door': false, '--click': true, '--no-test': false, '--no-idle': false, '--world': false, '--no-world': false, '--json': false },
1575
+ sim: {
1576
+ '--script': true, '--timeout': true, '--json': false,
1577
+ '--device': true, '--runtime': true, '--no-boot': false, '--owner': true, '--force': false, '--dry-run': false,
1578
+ '--orientation': true, '--app': true, '--out': true, '--points': false, '--tool': true,
1579
+ },
1580
+ unity: {
1581
+ '--project': true, '--unity': true, '--log': true, '--no-quit': false, '--max': true, '--stale-minutes': true, '--max-wait': true,
1582
+ '--days': true, '--yes': false, '--json': false, '--disk': false, '--below': true, '--only': true, '--apply': false,
1583
+ '--target': true, '--path': true, '--seconds': true, '--tier': true, '--budget': true, '--player': true, '--player-args': true, '--strict': false, '--rebuild': false, '--no-build': false,
1584
+ '--keep-target': false, '--port': true, '--udid': true, '--device': true, '--keep-sim': false, '--visible': false, '--sound': false,
1585
+ '--all': false, '--dev': false, '--settle-ms': true, '--points': false, '--mouse': false, '--from': true, '--git': true, '--ref': true, '--absolute': false,
1586
+ '--tests': false, '--dry-run': false,
1587
+ '--since': true, '--count': true, '--scene': false, '--game': false, '--out': true, '--open': false, '--wait': true,
1588
+ '--name': true, '--at': true, '--depth': true, '--force': false,
1589
+ },
1590
+ spec: { '--spec': true, '--tier': true, '--dir': true, '--json': false },
1591
+ rooms: { '--script': true, '--timeout': true, '--by': true, '--dir': true, '--json': false },
1592
+ depth: { '--out': true, '--place': true, '--tension': true, '--progress': true, '--fill': false, '--json': false },
1593
+ reach: { '--level': true, '--json': false },
1594
+ world: { '--dir': true, '--seed': true, '--rooms': true, '--kind': true, '--from': true, '--variety': true, '--force': false, '--json': false },
1595
+ feel: { '--script': true, '--engine': true, '--journey': true, '--no-sweep': false, '--json': false },
1596
+ gdd: { '--sources': false, '--strict': false, '--json': false },
1597
+ greenlight: { '--dir': true, '--version': true, '--override': true, '--target': true, '--by': true, '--from': true, '--why': true, '--json': false },
1598
+ verify: {
1599
+ '--engine': true,
1600
+ '--players': true, '--checks': true, '--manifest': true, '--no-sweep': false, '--watch': false, '--json': false,
1601
+ '--report': false, '--viewport': true, '--front-door': false, '--click': true,
1602
+ },
1603
+ capture: { ...LOOK_SPEC, '--engine': true, '--view': true, '--all': false, '--verbs': true, '--hold': true, '--burst': true, '--out': true, '--orientation': true, '--safari': false, '--seed': true, '--free-running': false },
1604
+ 'audit-screens': { ...LOOK_SPEC, '--engine': true, '--views': true, '--orientation': true },
1605
+ compare: { '--baseline': false, '--json': false, '--target': true, '--view': true, '--viewport': true, '--fit': true, '--verbs': true, '--hold': true, '--front-door': false, '--click': true, '--out': true, '--engine': true, '--seed': true, '--free-running': false },
1606
+ parts: { '--grid': true, '--boxes': true, '--names': true, '--key': true, '--pivot': true, '--pad': true, '--merge': true, '--webp': false, '--out': true, '--json': false, '--clean': false, '--keep-shadows': false },
1607
+ cut: { '--grid': true, '--boxes': true, '--names': true, '--pivot': true, '--pad': true, '--merge': true, '--webp': false, '--out': true, '--json': false, '--keep-shadows': false },
1608
+ scene: { ...LOOK_SPEC, '--engine': true, '--orientation': true, '--view': true, '--verbs': true, '--hold': true, '--motion': false },
1609
+ hook: { ...LOOK_SPEC, '--engine': true, '--orientation': true, '--seconds': true, '--verbs': true, '--idle': false },
1610
+ life: { ...LOOK_SPEC, '--engine': true, '--orientation': true, '--view': true, '--moment': true },
1611
+ walk: { ...LOOK_SPEC, '--engine': true, '--orientation': true, '--route': true, '--chain': true, '--seconds': true, '--no-film': false },
1612
+ score: { '--viewport': true, '--json': false, '--engine': true, '--target': true, '--view': true, '--hero': true, '--hero-share': true, '--capture': true, '--no-judge': false, '--fixes': false, '--seed': true, '--free-running': false },
1613
+ framing: { ...LOOK_SPEC, '--engine': true, '--actors': true, '--view': true },
1614
+ places: { ...LOOK_SPEC, '--engine': true, '--view': true },
1615
+ boxes: { ...LOOK_SPEC, '--engine': true, '--orientation': true, '--view': true },
1616
+ 'compare-takes': { '--names': true, '--route': true, '--viewport': true, '--seconds': true, '--no-score': false, '--out': true, '--json': false, '--engine': true },
1617
+ profile: { ...LOOK_SPEC, '--views': true, '--seed': true, '--frames': true, '--settle': true, '--against': true, '--software': false, '--throttle': true, '--repeat': true, '--compare': false, '--budget': true },
1618
+ clip: { '--frames': true, '--fps': true, '--seats': true, '--dir': true, '--json': false },
1619
+ judge: { '--prompt': true, '--concept': true, '--medium': true, '--dir': true, '--json': false },
1620
+ phone: { '--sim': true, '--orientation': true, '--seconds': true, '--taps': true, '--swipes': true, '--keep': false, '--out': true, '--json': false },
1621
+ inspect: { ...LOOK_SPEC, '--orientation': true, '--at': true, '--name': true, '--tree': false, '--url': true, '--view': true, '--verbs': true, '--settle': true },
1622
+ look: { ...LOOK_SPEC, '--dir': true, '--read': false, '--hud': false, '--fit': false, '--samples': true, '--every': true, '--verbs': true, '--orientation': true, '--view': true, '--hold': true, '--player': true, '--threats': true, '--colours': true, '--sheet': false, '--3d': false, '--static': false, '--sprites': true, '--sizes': true, '--ground': true, '--out': true },
1623
+ play: { '--viewport': true, '--engine': true, '--orientation': true, '--rounds': true, '--long': true, '--dir': true, '--round': true, '--refile': false, '--look': false, '--json': false },
1624
+ journey: { '--viewport': true, '--engine': true, '--orientation': true, '--seed': true, '--seconds': true, '--repeat': true, '--against': true, '--force': false, '--dir': true, '--json': false },
1625
+ playtest: { '--quick': false, '--versus': true, '--no-build': false, '--long': true, '--phone': false, '--sim': true, '--dir': true, '--cost-usd': true, '--hosted': false, '--yes': false, '--min-score': true, '--drop': true, '--by': true, '--json': false },
1626
+ 'mobile-qa': { '--phone': false, '--sim': true, '--no-build': false, '--dir': true, '--json': false },
1627
+ flow: { '--idea': true, '--budget': true, '--autonomy': true, '--rounds': true, '--by': true, '--framework': true, '--name': true, '--bare': false, '--offline': false, '--no-git': false, '--dir': true, '--json': false },
1628
+ note: { '--stage': true, '--screenshot': true, '--by': true, '--evidence': true, '--force': false, '--hold': false, '--dir': true, '--json': false },
1629
+ owner: { '--repo': true, '--dir': true, '--json': false },
1630
+ firstlook: { '--by': true, '--dir': true, '--no-browser': false, '--page': true, '--json': false },
1631
+ progress: {
1632
+ '--stage': true, '--shot': true, '--clip': true, '--line': true, '--next': true, '--spent': true, '--evidence': true, '--decision': true,
1633
+ '--out': true, '--standin': true, '--tried': true, '--kind': true, '--options': true, '--default': true, '--timeout': true, '--for': true,
1634
+ '--dir': true, '--json': false,
1635
+ },
1636
+ feedback: {
1637
+ '--out': true, '--json': false, '--kind': true, '--cost-usd': true, '--minutes': true, '--evidence': true, '--dir': true,
1638
+ '--metric': true, '--before': true, '--after': true, '--unit': true, '--sha': true, '--film': true, '--test': true, '--minutes-lost': true,
1639
+ '--tool': true, '--stage': true, '--verdict': true, '--screenshot': true, '--propose': false, '--html': true,
1640
+ '--what': true, '--routes': true, '--overall': true, '--axes': true, '--winner': true, '--judges': true,
1641
+ },
1642
+ journal: { '--why': true, '--by': true, '--files': true, '--values': true, '--dir': true, '--json': false },
1643
+ decide: { '--because': true, '--over': true, '--supersedes': true, '--from': true, '--touches': true, '--dir': true, '--json': false },
1644
+ lanes: { '--stage': true, '--lanes': true, '--cap': true, '--timebox': true, '--by': true, '--line': true, '--shot': true, '--cost': true, '--minutes': true, '--final': false, '--all': false, '--dir': true, '--json': false },
1645
+ pick: { '--lane': true, '--question': true, '--by': true, '--dir': true, '--json': false },
1646
+ lessons: { '--fix': true, '--source': true, '--delta': true, '--genre': true, '--share': false, '--dir': true, '--json': false },
1647
+ pack: { '--dry-run': false, '--no-build': false, '--json': false, '--out': true },
1648
+ export: { '--dir': true, '--check': false, '--no-browser': false, '--strip-metadata': false, '--json': false },
1649
+ gen: { ...GEN_SPEC, '--out': true, '--unity': true, '--no-wait': false, '--yes': false, '--strip-title': false, '--cast': true },
1650
+ character: { ...GEN_SPEC, '--out': true, '--no-wait': false, '--yes': false },
1651
+ estimate: GEN_SPEC,
1652
+ assets: { '--only': true, '--family': true, '--stale': false, '--max-credits': true, '--batch': true, '--dry-run': false, '--yes': false, '--because': true, '--snap': false, '--write': false, '--from': true, '--by': true, '--dir': true, '--json': false },
1653
+ cast: { '--master': true, '--turnaround': true, '--pins': true, '--name': true, '--kind': true, '--features': true, '--may-change': true, '--moves': false, '--by': true, '--mode': true, '--dir': true, '--json': false },
1654
+ variety: { '--within': false, '--json': false },
1655
+ wow: { '--genre': true, '--json': false, '--signature': false, '--expression': true, '--why': true, '--check': true, '--dir': true },
1656
+ pitch: { '--why': true, '--label': true, '--picture': true, '--cost': true, '--note': true, '--dir': true, '--json': false, '--seed': true, '--dial': true, '--brief': true, '--text': true },
1657
+ loudness: { '--dir': true, '--json': false },
1658
+ zero: { '--json': false },
1659
+ review: { '--dir': true, '--json': false, '--loop': false, '--still': false, '--freeze': true, '--triangles': true, '--size': true, '--alpha': false, '--lufs': true },
1660
+ motion: {
1661
+ '--fps': true, '--seconds': true, '--frames': true, '--size': true, '--aspect': true, '--out': true, '--webm': false,
1662
+ '--audio': true, '--prove': false, '--seed': true, '--dir': true, '--json': false,
1663
+ },
1664
+ compose: {
1665
+ '--dir': true, '--name': true, '--aspect': true, '--seconds': true, '--fps': true, '--quality': true, '--software': false,
1666
+ '--force': false, '--out': true, '--max': true, '--dry-run': false, '--json': false,
1667
+ },
1668
+ beats: { '--dir': true, '--meter': true, '--json': false },
1669
+ schema: { '--strict': false, '--json': false },
1670
+ loop: { '--fps': true, '--min': true, '--max': true, '--size': true, '--key': true, '--name': true, '--out': true, '--dir': true, '--json': false },
1671
+ directions: { '--dirs': true, '--size': true, '--key': true, '--reverse': false, '--name': true, '--out': true, '--dir': true, '--json': false },
1672
+ board: { '--keep': true, '--lends': true, '--note': true, '--licence': true, '--by': true, '--title': true, '--limit': true, '--any-licence': false, '--dir': true, '--json': false },
1673
+ job: { '--wait': false, '--out': true, '--json': false },
1674
+ jobs: { '--tool': true, '--status': true, '--limit': true, '--cursor': true, '--refusals': false, '--json': false },
1675
+ optimize: {
1676
+ '--check': false, '--json': false, '--write': false, '--dir': true, '--max-size': true, '--format': true,
1677
+ '--quantize': false, '--padding': true, '--pot': false, '--no-trim': false, '--frame-size': true,
1678
+ '--out': true, '--out-dir': true, '--levels': true, '--class': true,
1679
+ },
1680
+ playable: { '--network': true, '--no-play': false, '--json': false },
1681
+ reel: { '--seconds': true, '--fps': true, '--viewport': true, '--frames-only': false, '--out': true, '--json': false },
1682
+ trailer: {
1683
+ '--seconds': true, '--fps': true, '--viewport': true, '--formats': true, '--for': true, '--music': true, '--no-music': false, '--no-sfx': false,
1684
+ '--title': true, '--key-art': true, '--logo': true, '--cta': true, '--intro': true, '--outro': true, '--out': true, '--json': false,
1685
+ },
1686
+ fidelity: {
1687
+ '--renders': true, '--out': true, '--size': true, '--own-axes': false, '--roll': false, '--outline': false,
1688
+ '--quarter-turns': false, '--same-scale': false, '--min': true, '--json': false,
1689
+ },
1690
+ model: {
1691
+ '--local': false, '--out': true, '--target-triangles': true, '--height-m': true, '--frames': true, '--size': true,
1692
+ '--keep-clips': true, '--tone': true, '--palette': true, '--game-id': true, '--quality': true,
1693
+ '--roughness': false, '--normal': false, '--json': false,
1694
+ },
1695
+ login: { '--key': true, '--api': true, '--scope': true }, logout: {}, whoami: {},
1696
+ usage: { '--days': true, '--this-key': false, '--json': false }, budget: { '--json': false },
1697
+ publish: {
1698
+ '--target': true, '--yes': false, '--name': true, '--game-id': true, '--json': false,
1699
+ '--update': false,
1700
+ '--itch': true, '--project': true, '--out': true,
1701
+ },
1702
+ store: { '--store': true, '--dir': true, '--json': false },
1703
+ models: { '--force': false, '--json': false },
1704
+ };
1705
+ export const ALIASES = { status: ['flow', 'status'] };
1706
+ export const VERSION_WORDS = ['--version', '-v', 'version'];
1707
+ export async function main(argv, io = console) {
1708
+ if (argv[0] !== undefined && Object.hasOwn(ALIASES, argv[0]))
1709
+ return main([...ALIASES[argv[0]], ...argv.slice(1)], io);
1710
+ const [command, ...rest] = argv;
1711
+ if (!command || command === '--help' || command === '-h') {
1712
+ io.log(USAGE);
1713
+ return command ? 0 : EXIT.error;
1714
+ }
1715
+ if (VERSION_WORDS.includes(command)) {
1716
+ io.log(versionLine());
1717
+ return 0;
1718
+ }
1719
+ const u = ui(io, command);
1720
+ const help = 'run `funtools --help` for the usage';
1721
+ if (!Object.hasOwn(SPECS, command)) {
1722
+ u.error('unknown command', help);
1723
+ return EXIT.error;
1724
+ }
1725
+ const dashes = command === 'unity' ? rest.indexOf('--') : -1;
1726
+ const passthrough = dashes >= 0 ? rest.slice(dashes + 1) : [];
1727
+ const own = dashes >= 0 ? rest.slice(0, dashes) : rest;
1728
+ if (own.includes('--help') || own.includes('-h')) {
1729
+ io.log(commandHelp(command));
1730
+ return 0;
1731
+ }
1732
+ const parsed = parse(own, SPECS[command]);
1733
+ if (typeof parsed === 'string') {
1734
+ u.error(parsed, help);
1735
+ return EXIT.error;
1736
+ }
1737
+ const { positionals, flags } = parsed;
1738
+ const target = positionals[0];
1739
+ const engineFlag = GEN_COMMANDS.has(command) ? undefined : str(flags['--engine']);
1740
+ if (engineFlag !== undefined) {
1741
+ if (!ENGINES.includes(engineFlag)) {
1742
+ u.error(`--engine ${engineFlag}: chromium or webkit`, help);
1743
+ return EXIT.error;
1744
+ }
1745
+ process.env.FUNTOOLS_ENGINE = engineFlag;
1746
+ }
1747
+ const json = !!flags['--json'];
1748
+ boardRun(command);
1749
+ try {
1750
+ switch (command) {
1751
+ case 'init': {
1752
+ const spoken = target !== undefined && /\s/.test(target.trim()) && !existsSync(target) && flags['--idea'] === undefined;
1753
+ if (positionals.length > (spoken ? 2 : 1)) {
1754
+ u.error('init takes one folder', 'funtools init <folder> --idea "one line", or funtools init "one line"');
1755
+ return EXIT.error;
1756
+ }
1757
+ const idea = spoken ? target : str(flags['--idea']);
1758
+ return await init({ target: spoken ? positionals[1] : target, framework: str(flags['--framework']), name: str(flags['--name']), offline: !!flags['--offline'], idea, bare: !!flags['--bare'], noGit: !!flags['--no-git'] }, io);
1759
+ }
1760
+ case 'dev': {
1761
+ const raw = str(flags['--bots']);
1762
+ const bots = raw === undefined ? undefined : parseBots(raw);
1763
+ if (typeof bots === 'string') {
1764
+ u.error(bots, help);
1765
+ return EXIT.error;
1766
+ }
1767
+ if (bots && !flags['--relay']) {
1768
+ u.error('--bots needs --relay', 'bots meet you in the local relay\'s dev room: funtools dev --relay --bots 3');
1769
+ return EXIT.error;
1770
+ }
1771
+ if (flags['--host'] && !flags['--phone']) {
1772
+ u.error('--host goes with --phone', 'funtools dev --phone [--host 0.0.0.0]');
1773
+ return EXIT.error;
1774
+ }
1775
+ if (flags['--no-hold'] && !flags['--relay']) {
1776
+ u.error('--no-hold goes with --relay', 'reloads are held only while a dev room is live');
1777
+ return EXIT.error;
1778
+ }
1779
+ return await dev({ target, devtools: !flags['--no-devtools'], relay: !!flags['--relay'], bots, phone: !!flags['--phone'], host: str(flags['--host']), holdReloads: !flags['--no-hold'], open: !!flags['--open'] }, io);
1780
+ }
1781
+ case 'serve': return await (await import("./commands/serve.js")).serve({ target, port: str(flags['--port']), host: str(flags['--host']), noCompress: !!flags['--no-compress'] }, io);
1782
+ case 'doctor': {
1783
+ if (!flags['--host'])
1784
+ return await doctor({ target, addHooks: !!flags['--add-hooks'] }, io);
1785
+ const named = target !== undefined && HOSTS.includes(target) && !existsSync(target);
1786
+ const other = !named && target !== undefined && /^[a-z]+$/.test(target) && !existsSync(target);
1787
+ return await doctorHost({ host: named || other ? target : undefined, target: named || other ? positionals[1] : target, json }, io);
1788
+ }
1789
+ case 'check': {
1790
+ const viewport = str(flags['--viewport']) ?? 'desktop';
1791
+ if (!VIEWPORT_CHOICES.includes(viewport)) {
1792
+ u.error(`unknown viewport: ${viewport}`, '--viewport is desktop, phone or both');
1793
+ return EXIT.error;
1794
+ }
1795
+ return await check({ target, viewport: viewport, frontDoor: frontDoorOf(flags), noTest: !!flags['--no-test'], noIdle: !!flags['--no-idle'], phone: !!flags['--phone'], ...(flags['--world'] ? { world: true } : flags['--no-world'] ? { world: false } : {}), json }, io);
1796
+ }
1797
+ case 'upgrade': return flags['--self'] ? await upgradeSelf(io) : flags['--discard'] ? await discardOffers({ target }, io) : await upgrade({ target }, io);
1798
+ case 'smoke': return await smoke({ target, json }, io);
1799
+ case 'smoke-build': {
1800
+ const plan = str(flags['--plan']);
1801
+ if (!plan) {
1802
+ u.error('smoke-build needs the plan', 'funtools smoke-build <fresh-folder> --plan <folder with design/plan.md and design/first-look/ref-*.png>');
1803
+ return EXIT.error;
1804
+ }
1805
+ const { smokeBuild } = await import("./commands/smoke-build.js");
1806
+ return await smokeBuild({ dir: positionals[0] ?? '.', plan, json, store: (await import("./keys/store.js")).osStore() }, io);
1807
+ }
1808
+ case 'compare': {
1809
+ const commas = (f) => (str(flags[f]) ?? '').split(',').map((v) => v.trim()).filter(Boolean);
1810
+ if (flags['--target'] === undefined) {
1811
+ const extra = ['--view', '--viewport', '--fit', '--verbs', '--hold', '--front-door', '--click', '--out', '--seed', '--free-running'].find((f) => flags[f] !== undefined);
1812
+ if (extra) {
1813
+ u.error(`${extra} goes with --target`, 'funtools compare --target design/first-look/walk.png --view playing');
1814
+ return EXIT.error;
1815
+ }
1816
+ return await compare({ target: target ?? '.', baseline: !!flags['--baseline'], json }, io);
1817
+ }
1818
+ if (flags['--baseline']) {
1819
+ u.error('--baseline and --target are two different compares', 'before | after: --baseline; today | target: --target');
1820
+ return EXIT.error;
1821
+ }
1822
+ const pairs = pairTargets(commas('--target'), commas('--view'));
1823
+ if (typeof pairs === 'string') {
1824
+ u.error(pairs, help);
1825
+ return EXIT.error;
1826
+ }
1827
+ const vp = str(flags['--viewport']) ?? 'both';
1828
+ if (!VIEWPORT_CHOICES.includes(vp)) {
1829
+ u.error(`unknown viewport: ${vp}`, '--viewport is phone, desktop or both');
1830
+ return EXIT.error;
1831
+ }
1832
+ const fit = str(flags['--fit']) ?? 'contain';
1833
+ if (fit !== 'contain' && fit !== 'cover') {
1834
+ u.error(`--fit ${fit}`, '--fit is contain (the whole target) or cover (fill and crop)');
1835
+ return EXIT.error;
1836
+ }
1837
+ const hold = str(flags['--hold']) === undefined ? undefined : Number(str(flags['--hold']));
1838
+ if (hold !== undefined && (!Number.isFinite(hold) || hold < 0 || hold > 10_000)) {
1839
+ u.error('--hold is milliseconds from 0 to 10000', help);
1840
+ return EXIT.error;
1841
+ }
1842
+ const viewports = vp === 'both' ? ['phone', 'desktop'] : [vp];
1843
+ const framed = heldOf(flags, u);
1844
+ if (framed === null)
1845
+ return EXIT.error;
1846
+ return await compareTarget({ target: target ?? '.', pairs, viewports: [...viewports], fit, out: str(flags['--out']), click: frontDoorOf(flags), verbs: commas('--verbs'), holdMs: hold, json, ...framed }, io);
1847
+ }
1848
+ case 'parts':
1849
+ case 'cut': {
1850
+ if (!target) {
1851
+ u.error(`${command} needs a sheet`, command === 'cut' ? 'funtools cut design/first-look/fauna.jpg --names fox,jelly,crab,goat,whale' : 'funtools parts design/gen/ren-sheet.png --names head,torso,arm-l,arm-r,leg-l,leg-r');
1852
+ return EXIT.error;
1853
+ }
1854
+ if (flags['--grid'] !== undefined && flags['--boxes'] !== undefined) {
1855
+ u.error('--grid or --boxes, not both', help);
1856
+ return EXIT.error;
1857
+ }
1858
+ const grid = str(flags['--grid']) === undefined ? undefined : parseGrid(str(flags['--grid']));
1859
+ if (grid === null) {
1860
+ u.error(`--grid ${str(flags['--grid'])}`, '--grid is columns x rows, e.g. --grid 4x2');
1861
+ return EXIT.error;
1862
+ }
1863
+ const key = parseKey(str(flags['--key']) ?? 'auto');
1864
+ if (!key) {
1865
+ u.error(`--key ${str(flags['--key'])}`, '--key is auto, none, paper or a colour like #ffffff');
1866
+ return EXIT.error;
1867
+ }
1868
+ const pivot = str(flags['--pivot']) ?? 'bottom';
1869
+ if (pivot !== 'bottom' && pivot !== 'top' && pivot !== 'center') {
1870
+ u.error(`--pivot ${pivot}`, '--pivot is bottom (poses), top (limbs) or center');
1871
+ return EXIT.error;
1872
+ }
1873
+ const int = (f, d, hi) => {
1874
+ const raw = str(flags[f]);
1875
+ if (raw === undefined)
1876
+ return d;
1877
+ const n = Number(raw);
1878
+ if (Number.isInteger(n) && n >= 0 && n <= hi)
1879
+ return n;
1880
+ u.error(`${f} is a whole number of pixels from 0 to ${hi}`, help);
1881
+ return null;
1882
+ };
1883
+ const pad = int('--pad', 2, 64), merge = int('--merge', 6, 256);
1884
+ if (pad === null || merge === null)
1885
+ return EXIT.error;
1886
+ const names = (str(flags['--names']) ?? '').split(',').map((v) => v.trim()).filter(Boolean);
1887
+ if (command === 'cut')
1888
+ return await parts(cutDefaults({ sheet: target, grid, boxes: str(flags['--boxes']), names, out: str(flags['--out']), pivot, pad, merge, webp: !!flags['--webp'], json, keepShadows: !!flags['--keep-shadows'] }), io);
1889
+ return await parts({ sheet: target, grid, boxes: str(flags['--boxes']), names, out: str(flags['--out']), key, pivot, pad, merge, webp: !!flags['--webp'], json, clean: !!flags['--clean'], keepShadows: !!flags['--keep-shadows'] }, io);
1890
+ }
1891
+ case 'test': return await test({ target, node: !!flags['--node'], goals: !!flags['--goals'], json }, io);
1892
+ case 'sim': {
1893
+ if (isSimVerb(positionals[0])) {
1894
+ const verb = positionals[0];
1895
+ const owner = str(flags['--owner']);
1896
+ if (owner !== undefined && !/^\d+$/.test(owner)) {
1897
+ u.error(`--owner ${owner}`, 'the pid of the process that owns the lease');
1898
+ return EXIT.error;
1899
+ }
1900
+ const tool = str(flags['--tool']);
1901
+ if (tool !== undefined && tool !== 'baguette' && tool !== 'idb') {
1902
+ u.error(`--tool ${tool}`, 'baguette or idb');
1903
+ return EXIT.error;
1904
+ }
1905
+ return await simulator({
1906
+ verb, args: positionals.slice(1), device: str(flags['--device']), runtime: str(flags['--runtime']), boot: !flags['--no-boot'],
1907
+ owner: owner === undefined ? undefined : Number(owner), force: !!flags['--force'], dryRun: !!flags['--dry-run'],
1908
+ orientation: str(flags['--orientation']), app: str(flags['--app']), out: str(flags['--out']), points: !!flags['--points'], json,
1909
+ tool: tool,
1910
+ }, io);
1911
+ }
1912
+ const timeout = str(flags['--timeout']);
1913
+ if (timeout !== undefined && !(Number(timeout) > 0)) {
1914
+ u.error(`--timeout ${timeout}`, 'seconds before the probe is stopped, e.g. --timeout 600');
1915
+ return EXIT.error;
1916
+ }
1917
+ return await sim({ target, script: str(flags['--script']), timeout: timeout === undefined ? undefined : Number(timeout), json }, io);
1918
+ }
1919
+ case 'spec': {
1920
+ const known = SPEC_SUBCOMMANDS.includes(positionals[0] ?? '');
1921
+ const sub = (known ? positionals[0] : 'lint');
1922
+ const rest = known ? positionals.slice(1) : positionals;
1923
+ if (rest.length > 1) {
1924
+ u.error(`spec ${sub} takes one folder`, 'funtools spec lint [dir] | spec init [dir] --tier mid|deep');
1925
+ return EXIT.error;
1926
+ }
1927
+ return await spec({ sub, dir: str(flags['--dir']) ?? rest[0], spec: str(flags['--spec']), tier: str(flags['--tier']), json }, io);
1928
+ }
1929
+ case 'rooms': {
1930
+ const sub = (positionals[0] === 'open' || positionals[0] === 'plan' ? positionals[0] : 'run');
1931
+ const rest = sub === 'run' ? positionals : positionals.slice(1);
1932
+ const timeout = str(flags['--timeout']);
1933
+ if (timeout !== undefined && !(Number(timeout) > 0)) {
1934
+ u.error(`--timeout ${timeout}`, 'seconds before the probe is stopped, e.g. --timeout 600');
1935
+ return EXIT.error;
1936
+ }
1937
+ if (sub === 'open') {
1938
+ const [room, ...more] = rest;
1939
+ const isDir = (x) => !!x && existsSync(x) && !/\s/.test(x);
1940
+ const dir = str(flags['--dir']) ?? (isDir(more[0]) ? more[0] : undefined);
1941
+ const words = (isDir(more[0]) && !flags['--dir'] ? more.slice(1) : more).join(' ').trim() || undefined;
1942
+ return await roomsCommand({ sub, room, dir, by: str(flags['--by']), words, json }, io);
1943
+ }
1944
+ if (sub === 'plan')
1945
+ return await roomsCommand({ sub, dir: str(flags['--dir']) ?? rest[0], by: str(flags['--by']), json }, io);
1946
+ return await roomsCommand({ sub, dir: str(flags['--dir']) ?? rest[0], script: str(flags['--script']), timeout: timeout === undefined ? undefined : Number(timeout), json }, io);
1947
+ }
1948
+ case 'depth': return await depth({ target, out: str(flags['--out']), place: str(flags['--place']), tension: str(flags['--tension']), progress: str(flags['--progress']), fill: !!flags['--fill'], json }, io);
1949
+ case 'world': {
1950
+ const action = positionals[0];
1951
+ if (!WORLD_ACTIONS.includes(action ?? '')) {
1952
+ u.error(action ? `unknown world action: ${action}` : 'world needs an action', 'funtools world forge --seed 7, or funtools world check');
1953
+ return EXIT.error;
1954
+ }
1955
+ if (action === 'check') {
1956
+ const extra = ['--seed', '--rooms', '--kind', '--from', '--variety', '--force'].find((f) => flags[f] !== undefined);
1957
+ if (extra) {
1958
+ u.error(`${extra} goes with world forge`, 'world check [--dir game] [--json]');
1959
+ return EXIT.error;
1960
+ }
1961
+ }
1962
+ return await world({
1963
+ action: action, dir: str(flags['--dir']) ?? positionals[1], seed: str(flags['--seed']), rooms: str(flags['--rooms']),
1964
+ kind: str(flags['--kind']), from: str(flags['--from']), variety: str(flags['--variety']), force: !!flags['--force'], json,
1965
+ }, io);
1966
+ }
1967
+ case 'reach': return await reach({ target, levels: str(flags['--level'])?.split(',').map((l) => l.trim()).filter(Boolean), json }, io);
1968
+ case 'feel': return await feel({ target, script: str(flags['--script']), journey: str(flags['--journey']), sweep: !flags['--no-sweep'], json }, io);
1969
+ case 'greenlight': {
1970
+ const known = GREENLIGHT_SUBCOMMANDS.includes(positionals[0] ?? '');
1971
+ const sub = known ? positionals[0] : 'status';
1972
+ const choose = sub === 'worth' && positionals[1] === 'choose';
1973
+ const dir = str(flags['--dir']) ?? (choose ? undefined : known ? positionals[1] : positionals[0]) ?? '.';
1974
+ return await greenlight({ sub, dir, version: str(flags['--version']), override: str(flags['--override']), json, args: choose ? positionals.slice(1) : [], target: str(flags['--target']), by: str(flags['--by']), from: str(flags['--from']), why: str(flags['--why']) }, io);
1975
+ }
1976
+ case 'gdd': {
1977
+ const advice = { sources: !!flags['--sources'], strict: !!flags['--strict'] };
1978
+ return await gdd(positionals[0] === 'page' ? { sub: 'page', target: positionals[1], json } : positionals[0] === 'lint' ? { target: positionals[1], json, ...advice } : { target, json, ...advice }, io);
1979
+ }
1980
+ case 'export': return await exportCmd({ dest: target, dir: str(flags['--dir']), check: !!flags['--check'], browser: !flags['--no-browser'], stripMetadata: !!flags['--strip-metadata'], json }, io);
1981
+ case 'pack': return await pack({ target, build: !flags['--no-build'], json, out: str(flags['--out']) }, io);
1982
+ case 'gen': return await gen({ positionals, flags, json, out: str(flags['--out']), unity: str(flags['--unity']), wait: !flags['--no-wait'], yes: !!flags['--yes'], stripTitle: !!flags['--strip-title'], score: str(flags['--score']) }, io);
1983
+ case 'estimate': return await estimateCommand({ positionals, flags, json }, io);
1984
+ case 'assets': {
1985
+ const sub = positionals[0] ?? 'status';
1986
+ if (!ASSETS_SUBCOMMANDS.includes(sub)) {
1987
+ u.error(`unknown: assets ${sub}`, `use one of ${ASSETS_SUBCOMMANDS.join(', ')}`);
1988
+ return EXIT.error;
1989
+ }
1990
+ return await assets({
1991
+ sub, args: positionals.slice(1), dir: str(flags['--dir']), only: str(flags['--only']), family: str(flags['--family']),
1992
+ stale: !!flags['--stale'], maxCredits: str(flags['--max-credits']), dryRun: !!flags['--dry-run'], yes: !!flags['--yes'],
1993
+ because: str(flags['--because']), snap: !!flags['--snap'], batch: str(flags['--batch']), write: !!flags['--write'],
1994
+ from: str(flags['--from']), by: str(flags['--by']), json,
1995
+ }, io);
1996
+ }
1997
+ case 'cast': {
1998
+ const sub = positionals[0] ?? 'list';
1999
+ if (!CAST_SUBCOMMANDS.includes(sub)) {
2000
+ u.error(`unknown: cast ${sub}`, `use one of ${CAST_SUBCOMMANDS.join(', ')}`);
2001
+ return EXIT.error;
2002
+ }
2003
+ return await cast({
2004
+ sub, args: positionals.slice(1), dir: str(flags['--dir']), master: str(flags['--master']), turnaround: str(flags['--turnaround']),
2005
+ pins: str(flags['--pins']), name: str(flags['--name']), kind: str(flags['--kind']), features: str(flags['--features']),
2006
+ mayChange: str(flags['--may-change']), moves: !!flags['--moves'], by: str(flags['--by']), mode: str(flags['--mode']), json,
2007
+ }, io);
2008
+ }
2009
+ case 'character': return await character({ positionals, flags, json, out: str(flags['--out']), wait: !flags['--no-wait'], yes: !!flags['--yes'] }, io);
2010
+ case 'playable': return await playable({ target, network: str(flags['--network']), play: !flags['--no-play'], json }, io);
2011
+ case 'reel': {
2012
+ const num = (f, d, [lo, hi]) => {
2013
+ const v = str(flags[f]);
2014
+ const n = v === undefined ? d : Number(v);
2015
+ return Number.isFinite(n) && n >= lo && n <= hi ? n : `${f} is a number from ${lo} to ${hi}`;
2016
+ };
2017
+ const seconds = num('--seconds', 12, REEL_LIMITS.seconds), fps = num('--fps', 12, REEL_LIMITS.fps);
2018
+ if (typeof seconds === 'string' || typeof fps === 'string') {
2019
+ u.error(String(typeof seconds === 'string' ? seconds : fps), help);
2020
+ return EXIT.error;
2021
+ }
2022
+ const vp = str(flags['--viewport']);
2023
+ if (vp !== undefined && vp !== 'desktop' && vp !== 'phone') {
2024
+ u.error(`unknown viewport: ${vp}`, '--viewport is desktop or phone');
2025
+ return EXIT.error;
2026
+ }
2027
+ return await reel({ target, seconds, fps: Math.round(fps), viewport: vp, framesOnly: !!flags['--frames-only'], out: str(flags['--out']), json }, io);
2028
+ }
2029
+ case 'trailer': {
2030
+ const n = (f, d, [lo, hi]) => {
2031
+ const v = Number(str(flags[f]) ?? d);
2032
+ return Number.isFinite(v) && v >= lo && v <= hi ? Math.round(v) : null;
2033
+ };
2034
+ const seconds = n('--seconds', 30, TRAILER_LIMITS.seconds), fps = n('--fps', 15, TRAILER_LIMITS.fps);
2035
+ if (seconds === null) {
2036
+ u.error(`--seconds is a number from ${TRAILER_LIMITS.seconds.join(' to ')}`, help);
2037
+ return EXIT.error;
2038
+ }
2039
+ if (fps === null) {
2040
+ u.error(`--fps is a number from ${TRAILER_LIMITS.fps.join(' to ')}`, help);
2041
+ return EXIT.error;
2042
+ }
2043
+ const vp = str(flags['--viewport']);
2044
+ if (vp !== undefined && vp !== 'desktop' && vp !== 'phone') {
2045
+ u.error(`unknown viewport: ${vp}`, '--viewport is desktop or phone');
2046
+ return EXIT.error;
2047
+ }
2048
+ if (flags['--formats'] !== undefined && flags['--for'] !== undefined) {
2049
+ u.error('--formats or --for, not both', help);
2050
+ return EXIT.error;
2051
+ }
2052
+ const places = str(flags['--for']) === undefined ? null : formatsFor(str(flags['--for']).split(',').map((s) => s.trim()).filter(Boolean));
2053
+ if (typeof places === 'string') {
2054
+ u.error(places, help);
2055
+ return EXIT.error;
2056
+ }
2057
+ const formats = places ?? (str(flags['--formats']) ?? '16x9,9x16').split(',').map((s) => s.trim().replace(':', 'x')).filter(Boolean);
2058
+ if (!formats.length || formats.some((f) => !Object.hasOwn(SAFE, f))) {
2059
+ u.error(`--formats is any of ${Object.keys(SAFE).join(', ')}`, help);
2060
+ return EXIT.error;
2061
+ }
2062
+ if (flags['--music'] !== undefined && flags['--no-music']) {
2063
+ u.error('--music and --no-music together', help);
2064
+ return EXIT.error;
2065
+ }
2066
+ return await trailer({
2067
+ target, seconds, fps, viewport: vp, formats: [...new Set(formats)],
2068
+ music: str(flags['--music']), noMusic: !!flags['--no-music'], noSfx: !!flags['--no-sfx'], title: str(flags['--title']),
2069
+ keyArt: str(flags['--key-art']), logo: str(flags['--logo']), cta: str(flags['--cta']),
2070
+ intro: str(flags['--intro']), outro: str(flags['--outro']), out: str(flags['--out']), json,
2071
+ }, io);
2072
+ }
2073
+ case 'hook': {
2074
+ const vp = str(flags['--viewport']) ?? 'desktop';
2075
+ if (vp !== 'desktop' && vp !== 'phone') {
2076
+ u.error(`unknown viewport: ${vp}`, '--viewport is desktop or phone');
2077
+ return EXIT.error;
2078
+ }
2079
+ const orientation = orientationOf(flags, vp, u);
2080
+ if (orientation === null)
2081
+ return EXIT.error;
2082
+ const seconds = Number(str(flags['--seconds']) ?? 180);
2083
+ if (!(seconds > 0 && seconds <= 900)) {
2084
+ u.error('--seconds must be between 1 and 900', help);
2085
+ return EXIT.error;
2086
+ }
2087
+ return await hook({ target, viewport: vp, orientation, json, click: frontDoorOf(flags) ?? FRONT_DOOR, seconds, idle: !!flags['--idle'], verbs: (str(flags['--verbs']) ?? '').split(',').map((v) => v.trim()).filter(Boolean) }, io);
2088
+ }
2089
+ case 'life': {
2090
+ const vp = str(flags['--viewport']) ?? 'desktop';
2091
+ if (vp !== 'desktop' && vp !== 'phone') {
2092
+ u.error(`unknown viewport: ${vp}`, '--viewport is desktop or phone');
2093
+ return EXIT.error;
2094
+ }
2095
+ const orientation = orientationOf(flags, vp, u);
2096
+ if (orientation === null)
2097
+ return EXIT.error;
2098
+ return await life({ target, viewport: vp, orientation, json, click: frontDoorOf(flags) ?? FRONT_DOOR, view: str(flags['--view']) ?? null, moment: str(flags['--moment']) ?? null }, io);
2099
+ }
2100
+ case 'walk': {
2101
+ const vp = str(flags['--viewport']) ?? 'desktop';
2102
+ if (vp !== 'desktop' && vp !== 'phone') {
2103
+ u.error(`unknown viewport: ${vp}`, '--viewport is desktop or phone');
2104
+ return EXIT.error;
2105
+ }
2106
+ const orientation = orientationOf(flags, vp, u);
2107
+ if (orientation === null)
2108
+ return EXIT.error;
2109
+ const secs = str(flags['--seconds']);
2110
+ const seconds = secs === undefined ? undefined : Number(secs);
2111
+ if (seconds !== undefined && !(seconds > 0 && seconds <= 900)) {
2112
+ u.error('--seconds must be between 1 and 900', help);
2113
+ return EXIT.error;
2114
+ }
2115
+ return await walk({ target, viewport: vp, orientation, json, click: null, routes: (str(flags['--route']) ?? '').split(',').map((v) => v.trim()).filter(Boolean), chain: (str(flags['--chain']) ?? '').split(',').map((v) => v.trim()).filter(Boolean), seconds, film: !flags['--no-film'] }, io);
2116
+ }
2117
+ case 'score': {
2118
+ if (flags['--fixes'])
2119
+ return printFixes(target ?? '.', json, io);
2120
+ const vp = str(flags['--viewport']) ?? 'desktop';
2121
+ if (vp !== 'desktop' && vp !== 'phone') {
2122
+ u.error(`unknown viewport: ${vp}`, '--viewport is desktop or phone');
2123
+ return EXIT.error;
2124
+ }
2125
+ const pic = str(flags['--target']);
2126
+ const share = str(flags['--hero-share']);
2127
+ if (share !== undefined && !(Number(share) > 0 && Number(share) <= 1)) {
2128
+ u.error('--hero-share is the hero\'s height over the frame\'s, 0 to 1', help);
2129
+ return EXIT.error;
2130
+ }
2131
+ if (!pic && (flags['--view'] || flags['--hero'] || flags['--capture'] || share !== undefined)) {
2132
+ u.error('--view, --hero, --hero-share and --capture go with --target', 'funtools score --target design/first-look/walk.jpg --view walk');
2133
+ return EXIT.error;
2134
+ }
2135
+ const moments = pic ? [{ name: str(flags['--view']) ?? 'as-loaded', view: str(flags['--view']) ?? null, target: pic, hero: str(flags['--hero']) ?? null, heroShare: share === undefined ? null : Number(share), ...(str(flags['--capture']) ? { capture: str(flags['--capture']) } : {}) }] : [];
2136
+ const framed = heldOf(flags, u);
2137
+ if (framed === null)
2138
+ return EXIT.error;
2139
+ return await score({ target: target ?? '.', moments, viewport: vp, json, noJudge: !!flags['--no-judge'], ...framed }, io);
2140
+ }
2141
+ case 'compare-takes': {
2142
+ if (positionals.length !== 2) {
2143
+ u.error('compare-takes takes two game folders', 'funtools compare-takes builds/take-a builds/take-b [--names A,B]');
2144
+ return EXIT.error;
2145
+ }
2146
+ const vp = str(flags['--viewport']) ?? 'desktop';
2147
+ if (vp !== 'desktop' && vp !== 'phone') {
2148
+ u.error(`unknown viewport: ${vp}`, '--viewport is desktop or phone');
2149
+ return EXIT.error;
2150
+ }
2151
+ const nm = (str(flags['--names']) ?? '').split(',').map((v) => v.trim()).filter(Boolean);
2152
+ if (nm.length && nm.length !== 2) {
2153
+ u.error('--names takes two names, A,B', help);
2154
+ return EXIT.error;
2155
+ }
2156
+ const secs = str(flags['--seconds']);
2157
+ const seconds = secs === undefined ? undefined : Number(secs);
2158
+ if (seconds !== undefined && !(seconds > 0 && seconds <= 900)) {
2159
+ u.error('--seconds must be between 1 and 900', help);
2160
+ return EXIT.error;
2161
+ }
2162
+ return await compareTakes({ takes: [positionals[0], positionals[1]], ...(nm.length ? { names: [nm[0], nm[1]] } : {}), routes: (str(flags['--route']) ?? '').split(',').map((v) => v.trim()).filter(Boolean), viewport: vp, seconds, score: !flags['--no-score'], out: str(flags['--out']), json }, io);
2163
+ }
2164
+ case 'boxes': {
2165
+ const vp = str(flags['--viewport']) ?? 'desktop';
2166
+ if (vp !== 'desktop' && vp !== 'phone') {
2167
+ u.error(`unknown viewport: ${vp}`, '--viewport is desktop or phone');
2168
+ return EXIT.error;
2169
+ }
2170
+ const orientation = orientationOf(flags, vp, u);
2171
+ if (orientation === null)
2172
+ return EXIT.error;
2173
+ return await boxes({ target, viewport: vp, orientation, json, click: frontDoorOf(flags) ?? FRONT_DOOR, views: (str(flags['--view']) ?? '').split(',').map((v) => v.trim()).filter(Boolean) }, io);
2174
+ }
2175
+ case 'places': {
2176
+ const vp = str(flags['--viewport']) ?? 'desktop';
2177
+ if (vp !== 'desktop' && vp !== 'phone') {
2178
+ u.error(`unknown viewport: ${vp}`, '--viewport is desktop or phone');
2179
+ return EXIT.error;
2180
+ }
2181
+ return await places({ target, viewport: vp, json, click: null, views: (str(flags['--view']) ?? '').split(',').map((v) => v.trim()).filter(Boolean) }, io);
2182
+ }
2183
+ case 'framing': {
2184
+ const vp = str(flags['--viewport']) ?? 'desktop';
2185
+ if (vp !== 'desktop' && vp !== 'phone') {
2186
+ u.error(`unknown viewport: ${vp}`, '--viewport is desktop or phone');
2187
+ return EXIT.error;
2188
+ }
2189
+ return await framing({ target, viewport: vp, json, click: null, actors: (str(flags['--actors']) ?? '').split(',').map((v) => v.trim()).filter(Boolean), view: str(flags['--view']) ?? null }, io);
2190
+ }
2191
+ case 'capture':
2192
+ case 'audit-screens':
2193
+ case 'scene': {
2194
+ const vp = str(flags['--viewport']) ?? 'desktop';
2195
+ const turned = /^phone-(portrait|landscape)$/.exec(vp);
2196
+ if (vp !== 'desktop' && vp !== 'phone') {
2197
+ u.error(`unknown viewport: ${vp}`, turned ? `--viewport phone --orientation ${turned[1]}` : '--viewport is desktop or phone');
2198
+ return EXIT.error;
2199
+ }
2200
+ const orientation = orientationOf(flags, vp, u);
2201
+ if (orientation === null)
2202
+ return EXIT.error;
2203
+ const hold = str(flags['--hold']) === undefined ? undefined : Number(str(flags['--hold']));
2204
+ if (hold !== undefined && (!Number.isFinite(hold) || hold < 0 || hold > 10_000)) {
2205
+ u.error('--hold is milliseconds from 0 to 10000', help);
2206
+ return EXIT.error;
2207
+ }
2208
+ const burst = str(flags['--burst']) === undefined ? undefined : Number(str(flags['--burst']));
2209
+ if (burst !== undefined && (!Number.isInteger(burst) || burst < 0 || burst > BURST.max)) {
2210
+ u.error(`--burst is a frame count from 0 to ${BURST.max}`, help);
2211
+ return EXIT.error;
2212
+ }
2213
+ const list = (f) => (str(flags[f]) ?? '').split(',').map((v) => v.trim()).filter(Boolean);
2214
+ const base = { target, viewport: vp, orientation, json, click: frontDoorOf(flags) };
2215
+ const framed = heldOf(flags, u);
2216
+ if (framed === null)
2217
+ return EXIT.error;
2218
+ if (command === 'audit-screens')
2219
+ return await auditScreens({ ...base, views: list('--views') }, io);
2220
+ if (flags['--safari'] && vp !== 'phone') {
2221
+ u.error('--safari is a phone in Mobile Safari', '--viewport phone --safari');
2222
+ return EXIT.error;
2223
+ }
2224
+ const look = { ...base, ...framed, safari: !!flags['--safari'], view: str(flags['--view']) ?? null, verbs: list('--verbs'), holdMs: hold, burst, out: str(flags['--out']), motion: !!flags['--motion'] };
2225
+ if (command === 'capture' && flags['--all']) {
2226
+ if (look.view !== null || look.out !== undefined || str(flags['--viewport']) !== undefined || orientation !== undefined) {
2227
+ u.error('--all shoots every view at both sizes: drop --view, --out, --viewport and --orientation', help);
2228
+ return EXIT.error;
2229
+ }
2230
+ return await captureAll({ target, json, click: base.click, verbs: look.verbs, holdMs: hold, burst, ...framed }, io);
2231
+ }
2232
+ return command === 'capture' ? await capture(look, io) : await scene(look, io);
2233
+ }
2234
+ case 'play': {
2235
+ const vp = str(flags['--viewport']) ?? 'desktop';
2236
+ if (vp !== 'desktop' && vp !== 'phone') {
2237
+ u.error(`unknown viewport: ${vp}`, '--viewport is desktop or phone');
2238
+ return EXIT.error;
2239
+ }
2240
+ const rounds = Number(str(flags['--rounds']) ?? PLAY_DEFAULTS.rounds);
2241
+ if (!Number.isInteger(rounds) || rounds < 1 || rounds > 10) {
2242
+ u.error('--rounds is 1 to 10', help);
2243
+ return EXIT.error;
2244
+ }
2245
+ const sub = PLAY_SUBCOMMANDS.includes(positionals[0] ?? '') ? positionals[0] : 'open';
2246
+ const orientation = orientationOf(flags, vp, u);
2247
+ if (orientation === null)
2248
+ return EXIT.error;
2249
+ const long = str(flags['--long']) === undefined ? undefined : Number(str(flags['--long']));
2250
+ if (long !== undefined && !(Number.isInteger(long) && long >= 1 && long <= PLAY_STEP_LIMITS.maxLongMinutes)) {
2251
+ u.error(`--long is whole minutes of game time, 1 to ${PLAY_STEP_LIMITS.maxLongMinutes}`, help);
2252
+ return EXIT.error;
2253
+ }
2254
+ const roundRaw = str(flags['--round']);
2255
+ const round = roundRaw === undefined ? undefined : Number(roundRaw);
2256
+ if (round !== undefined && !(Number.isInteger(round) && round >= 1)) {
2257
+ u.error('--round is the round number play printed when it opened (1, 2, …)', help);
2258
+ return EXIT.error;
2259
+ }
2260
+ return await play({ sub, args: sub === 'open' ? positionals : positionals.slice(1), dir: str(flags['--dir']), round, refile: !!flags['--refile'], look: !!flags['--look'], viewport: vp, orientation, rounds, long, json }, io);
2261
+ }
2262
+ case 'journey': {
2263
+ const vp = str(flags['--viewport']);
2264
+ if (vp !== undefined && vp !== 'desktop' && vp !== 'phone') {
2265
+ u.error(`unknown viewport: ${vp}`, '--viewport is desktop or phone');
2266
+ return EXIT.error;
2267
+ }
2268
+ const orientation = orientationOf(flags, vp ?? 'desktop', u);
2269
+ if (orientation === null)
2270
+ return EXIT.error;
2271
+ const int = (f, lo, hi) => {
2272
+ const raw = str(flags[f]);
2273
+ if (raw === undefined)
2274
+ return undefined;
2275
+ const n = Number(raw);
2276
+ if (Number.isInteger(n) && n >= lo && n <= hi)
2277
+ return n;
2278
+ u.error(`${f} is a whole number from ${lo} to ${hi}`, help);
2279
+ return null;
2280
+ };
2281
+ const seed = int('--seed', -2147483648, 2147483647), seconds = int('--seconds', 5, 1800), repeat = int('--repeat', 1, 3), against = int('--against', 1, 1_000_000);
2282
+ if (seed === null || seconds === null || repeat === null || against === null)
2283
+ return EXIT.error;
2284
+ const sub = JOURNEY_SUBCOMMANDS.includes(positionals[0] ?? '') ? positionals[0] : 'list';
2285
+ if (sub === 'list' && positionals.length) {
2286
+ u.error(`unknown: journey ${positionals[0]}`, 'journey, journey record|from-play|replay|diff');
2287
+ return EXIT.error;
2288
+ }
2289
+ return await journey({ sub, args: positionals.slice(1), dir: str(flags['--dir']) ?? '.', viewport: vp, orientation, seed, seconds, repeat, against, force: !!flags['--force'], json }, io);
2290
+ }
2291
+ case 'playtest': {
2292
+ const sub = PLAYTEST_SUBCOMMANDS.includes(positionals[0] ?? '') ? positionals[0] : 'run';
2293
+ const cost = str(flags['--cost-usd']);
2294
+ if (cost !== undefined && !(Number(cost) >= 0)) {
2295
+ u.error('--cost-usd is a number of dollars', help);
2296
+ return EXIT.error;
2297
+ }
2298
+ const dir = str(flags['--dir']) ?? (sub === 'run' ? positionals[0] : undefined) ?? '.';
2299
+ const longRaw = str(flags['--long']);
2300
+ const long = longRaw === undefined ? undefined : Number(longRaw);
2301
+ if (long !== undefined && !(Number.isInteger(long) && long >= 0 && long <= PLAY_STEP_LIMITS.maxLongMinutes)) {
2302
+ u.error(`--long is whole minutes of game time for the blind round, 0 (a short round) to ${PLAY_STEP_LIMITS.maxLongMinutes}`, help);
2303
+ return EXIT.error;
2304
+ }
2305
+ const minRaw = str(flags['--min-score']);
2306
+ const minScore = minRaw === undefined ? undefined : Number(minRaw);
2307
+ if (minScore !== undefined && !(minScore >= 0 && minScore <= 10)) {
2308
+ u.error('--min-score is the panel\'s overall mean to require, 0 to 10', help);
2309
+ return EXIT.error;
2310
+ }
2311
+ if (minScore !== undefined && sub !== 'report') {
2312
+ u.error('--min-score goes with `playtest report`', 'the panel informs; only a report you ask to can fail on its number');
2313
+ return EXIT.error;
2314
+ }
2315
+ const common = { dir, quick: !!flags['--quick'], build: !flags['--no-build'], versus: str(flags['--versus']) ?? null, costUsd: cost === undefined ? null : Number(cost), long, phone: !!flags['--phone'], sim: str(flags['--sim']), json, minScore };
2316
+ if (flags['--hosted'])
2317
+ return await playtestHosted({ ...common, yes: !!flags['--yes'] }, io);
2318
+ if ((flags['--drop'] || flags['--by']) && sub !== 'keep') {
2319
+ u.error('--drop goes with `playtest keep`', 'playtest keep --drop K<n> --by owner "<their words>"');
2320
+ return EXIT.error;
2321
+ }
2322
+ return await playtest({ sub, ...common, ...(sub === 'keep' ? { drop: str(flags['--drop']), by: str(flags['--by']), words: positionals.slice(1).join(' ') } : {}) }, io);
2323
+ }
2324
+ case 'mobile-qa': {
2325
+ const sub = positionals[0] === 'report' ? 'report' : 'run';
2326
+ const dir = str(flags['--dir']) ?? (sub === 'run' ? positionals[0] : undefined) ?? '.';
2327
+ return await mobileQa({ sub, dir, build: !flags['--no-build'], phone: !!flags['--phone'], sim: str(flags['--sim']), json }, io);
2328
+ }
2329
+ case 'flow': {
2330
+ const known = FLOW_SUBCOMMANDS.includes(positionals[0] ?? '');
2331
+ const sub = (known ? positionals[0] : 'status');
2332
+ const rest = known ? positionals.slice(1) : positionals;
2333
+ const isDir = (x) => !!x && existsSync(x) && !/\s/.test(x);
2334
+ const worded = sub === 'agree' || sub === 'drop';
2335
+ const dir = str(flags['--dir']) ?? (worded ? (isDir(rest[0]) ? rest[0] : undefined) : rest[0]) ?? '.';
2336
+ const args = worded ? rest.slice(isDir(rest[0]) && !flags['--dir'] ? 1 : 0) : [];
2337
+ return await flow({ sub, dir, args, idea: str(flags['--idea']), budget: str(flags['--budget']), autonomy: str(flags['--autonomy']), rounds: str(flags['--rounds']), by: str(flags['--by']), framework: str(flags['--framework']), name: str(flags['--name']), bare: !!flags['--bare'], offline: !!flags['--offline'], noGit: !!flags['--no-git'], json }, io);
2338
+ }
2339
+ case 'progress': {
2340
+ const known = PROGRESS_SUBCOMMANDS.includes(positionals[0] ?? '');
2341
+ if (!known && positionals.length) {
2342
+ u.error(`unknown: progress ${positionals[0]}`, `funtools progress ${PROGRESS_SUBCOMMANDS.join('|')}`);
2343
+ return EXIT.error;
2344
+ }
2345
+ const sub = (known ? positionals[0] : 'status');
2346
+ const port = str(flags['--port']);
2347
+ return await progress({
2348
+ sub, args: positionals.slice(1), dir: str(flags['--dir']), stage: str(flags['--stage']), shot: str(flags['--shot']), clip: str(flags['--clip']),
2349
+ line: str(flags['--line']), next: str(flags['--next']), spent: str(flags['--spent']), evidence: str(flags['--evidence']), decision: str(flags['--decision']),
2350
+ out: str(flags['--out']), standin: str(flags['--standin']), tried: str(flags['--tried']), kind: str(flags['--kind']), options: str(flags['--options']),
2351
+ default: str(flags['--default']), timeout: str(flags['--timeout']), for: str(flags['--for']), ...(port ? { port: Number(port) } : {}), phone: !!flags['--phone'], background: !!flags['--background'], json,
2352
+ store: (await import("./keys/store.js")).osStore(),
2353
+ }, io);
2354
+ }
2355
+ case 'note': {
2356
+ const known = NOTE_SUBCOMMANDS.includes(positionals[0] ?? '');
2357
+ const sub = known ? positionals[0] : positionals.length ? 'add' : 'list';
2358
+ return await note({ sub, args: known ? positionals.slice(1) : positionals, stage: str(flags['--stage']), screenshot: str(flags['--screenshot']), by: str(flags['--by']), evidence: str(flags['--evidence']), force: !!flags['--force'], hold: !!flags['--hold'], dir: str(flags['--dir']), json }, io);
2359
+ }
2360
+ case 'owner': {
2361
+ const known = OWNER_SUBCOMMANDS.includes(positionals[0] ?? '');
2362
+ if (!known && positionals.length && !existsSync(positionals[0])) {
2363
+ u.error(`unknown: owner ${positionals[0]}`, `funtools owner ${OWNER_SUBCOMMANDS.join('|')}`);
2364
+ return EXIT.error;
2365
+ }
2366
+ return await owner({ sub: (known ? positionals[0] : 'list'), args: known ? positionals.slice(1) : positionals, dir: str(flags['--dir']), repo: str(flags['--repo']), json }, io);
2367
+ }
2368
+ case 'firstlook': {
2369
+ const known = FIRSTLOOK_SUBCOMMANDS.includes(positionals[0] ?? '');
2370
+ return await firstlook({ sub: known ? positionals[0] : 'list', args: known ? positionals.slice(1) : positionals, dir: str(flags['--dir']), by: str(flags['--by']), noBrowser: !!flags['--no-browser'], page: str(flags['--page']), json }, io);
2371
+ }
2372
+ case 'feedback': return await feedback({
2373
+ sub: positionals[0], dirs: positionals.slice(1), out: str(flags['--out']), json,
2374
+ text: positionals.slice(1).join(' '), kind: str(flags['--kind']), costUsd: str(flags['--cost-usd']),
2375
+ minutes: str(flags['--minutes']), evidence: str(flags['--evidence']), dir: str(flags['--dir']),
2376
+ metric: str(flags['--metric']), before: str(flags['--before']), after: str(flags['--after']), unit: str(flags['--unit']),
2377
+ sha: str(flags['--sha']), film: str(flags['--film']), test: str(flags['--test']), minutesLost: str(flags['--minutes-lost']),
2378
+ tool: str(flags['--tool']), stage: str(flags['--stage']), verdict: str(flags['--verdict']), screenshot: str(flags['--screenshot']),
2379
+ propose: !!flags['--propose'], html: str(flags['--html']),
2380
+ what: str(flags['--what']), routes: str(flags['--routes']), overall: str(flags['--overall']), axes: str(flags['--axes']),
2381
+ winner: str(flags['--winner']), judges: str(flags['--judges']),
2382
+ }, io);
2383
+ case 'journal': return await journal({
2384
+ text: positionals.join(' '), why: str(flags['--why']), by: str(flags['--by']), files: str(flags['--files']),
2385
+ values: str(flags['--values']), dir: str(flags['--dir']), json,
2386
+ }, io);
2387
+ case 'decide': return await decide({
2388
+ text: positionals.join(' '), because: str(flags['--because']), over: str(flags['--over']),
2389
+ supersedes: str(flags['--supersedes']), from: str(flags['--from']), touches: str(flags['--touches']), dir: str(flags['--dir']), json,
2390
+ }, io);
2391
+ case 'lanes': {
2392
+ const known = LANES_SUBCOMMANDS.includes(positionals[0] ?? '');
2393
+ if (!known && positionals.length) {
2394
+ u.error(`unknown: lanes ${positionals[0]}`, `funtools lanes ${LANES_SUBCOMMANDS.join('|')}`);
2395
+ return EXIT.error;
2396
+ }
2397
+ return await lanes({
2398
+ sub: (known ? positionals[0] : 'status'), args: positionals.slice(1), dir: str(flags['--dir']), stage: str(flags['--stage']), lanes: str(flags['--lanes']),
2399
+ cap: str(flags['--cap']), timebox: str(flags['--timebox']), by: str(flags['--by']), line: str(flags['--line']), shot: str(flags['--shot']), cost: str(flags['--cost']),
2400
+ minutes: str(flags['--minutes']), final: !!flags['--final'], all: !!flags['--all'], json, has: (c) => c in SPECS,
2401
+ }, io);
2402
+ }
2403
+ case 'pick': {
2404
+ const known = PICK_SUBCOMMANDS.includes(positionals[0] ?? '');
2405
+ const sub = known ? positionals[0] : positionals.length ? 'propose' : 'list';
2406
+ return await pick({ sub, args: known ? positionals.slice(1) : positionals, lane: str(flags['--lane']), question: str(flags['--question']), by: str(flags['--by']), dir: str(flags['--dir']), json }, io);
2407
+ }
2408
+ case 'variety': return await variety({ target, json, within: !!flags['--within'] }, io);
2409
+ case 'wow': {
2410
+ const sub = positionals[0] === 'pick' || positionals[0] === 'check' ? positionals[0] : 'list';
2411
+ const dir = sub === 'pick' ? str(flags['--dir']) ?? '.' : (sub === 'check' ? positionals[1] : positionals[0]) ?? str(flags['--dir']) ?? '.';
2412
+ return await wow({ sub, dir, genre: str(flags['--genre']), id: sub === 'pick' ? positionals[1] : undefined, signature: !!flags['--signature'], expression: str(flags['--expression']), why: str(flags['--why']), check: str(flags['--check']), json }, io);
2413
+ }
2414
+ case 'pitch': {
2415
+ if (positionals[0] === 'widen') {
2416
+ const act = positionals[1] === 'score' || positionals[1] === 'keep' ? positionals[1] : 'draw';
2417
+ const after = positionals.slice(act === 'draw' ? 1 : 2);
2418
+ return await widen({
2419
+ action: act, card: act === 'keep' ? after[0] : undefined, dir: str(flags['--dir']) ?? (act === 'keep' ? after[1] : after[0]),
2420
+ seed: str(flags['--seed']), dial: str(flags['--dial']), brief: str(flags['--brief']), text: str(flags['--text']), json,
2421
+ }, io);
2422
+ }
2423
+ const known = PITCH_SUBCOMMANDS.includes(positionals[0] ?? '');
2424
+ const sub = known ? positionals[0] : 'show';
2425
+ const rest = known ? positionals.slice(1) : positionals;
2426
+ const takes = sub === 'propose' || sub === 'pick';
2427
+ return await pitch({
2428
+ sub, dir: str(flags['--dir']) ?? (takes ? undefined : rest[0]), choice: takes ? rest[0] : undefined, option: takes ? rest[1] : undefined,
2429
+ why: str(flags['--why']), label: str(flags['--label']), picture: str(flags['--picture']), cost: str(flags['--cost']), note: str(flags['--note']), json,
2430
+ }, io);
2431
+ }
2432
+ case 'loudness': return await loudness({ paths: positionals, dir: str(flags['--dir']), json }, io);
2433
+ case 'zero': return await zero({ target, json }, io);
2434
+ case 'review': {
2435
+ const n = (f, ok) => {
2436
+ const v = str(flags[f]);
2437
+ if (v === undefined)
2438
+ return undefined;
2439
+ const x = Number(v);
2440
+ return Number.isFinite(x) && ok(x) ? x : null;
2441
+ };
2442
+ const freezeS = n('--freeze', (x) => x > 0 && x <= 600), triangles = n('--triangles', (x) => Number.isInteger(x) && x > 0), lufs = n('--lufs', (x) => x < 0 && x > -70);
2443
+ if (freezeS === null) {
2444
+ u.error('--freeze is seconds (more than 0)', help);
2445
+ return EXIT.error;
2446
+ }
2447
+ if (triangles === null) {
2448
+ u.error('--triangles is a whole number', help);
2449
+ return EXIT.error;
2450
+ }
2451
+ if (lufs === null) {
2452
+ u.error('--lufs is a loudness target below 0 (e.g. -14)', help);
2453
+ return EXIT.error;
2454
+ }
2455
+ const sz = str(flags['--size']);
2456
+ const m = sz === undefined ? null : /^(\d+)[x×](\d+)$/i.exec(sz);
2457
+ if (sz !== undefined && !m) {
2458
+ u.error('--size is WxH in pixels (e.g. 512x512)', help);
2459
+ return EXIT.error;
2460
+ }
2461
+ return await review({
2462
+ paths: positionals, dir: str(flags['--dir']), json, loop: !!flags['--loop'], still: !!flags['--still'], alpha: !!flags['--alpha'] || undefined,
2463
+ freezeS, triangles, lufs, ...(m ? { size: { w: Number(m[1]), h: Number(m[2]) } } : {}),
2464
+ }, io);
2465
+ }
2466
+ case 'motion': {
2467
+ const sub = MOTION_SUBCOMMANDS.includes(target ?? '') ? target : undefined;
2468
+ if (target !== undefined && !sub) {
2469
+ u.error(`motion ${target}: ${MOTION_SUBCOMMANDS.join(', ')}`, help);
2470
+ return EXIT.error;
2471
+ }
2472
+ return await motion({
2473
+ sub, args: positionals.slice(1), fps: str(flags['--fps']), seconds: str(flags['--seconds']), frames: str(flags['--frames']),
2474
+ size: str(flags['--size']), aspect: str(flags['--aspect']), out: str(flags['--out']), webm: !!flags['--webm'], audio: str(flags['--audio']),
2475
+ prove: !!flags['--prove'], seed: str(flags['--seed']), dir: str(flags['--dir']), json,
2476
+ }, io);
2477
+ }
2478
+ case 'compose': {
2479
+ const sub = COMPOSE_SUBCOMMANDS.includes(target ?? '') ? target : undefined;
2480
+ if (target !== undefined && !sub) {
2481
+ u.error(`compose ${target}: ${COMPOSE_SUBCOMMANDS.join(', ')}`, help);
2482
+ return EXIT.error;
2483
+ }
2484
+ return await compose({
2485
+ sub, args: positionals.slice(1), dir: str(flags['--dir']), name: str(flags['--name']), aspect: str(flags['--aspect']), seconds: str(flags['--seconds']),
2486
+ fps: str(flags['--fps']), quality: str(flags['--quality']), software: !!flags['--software'], force: !!flags['--force'], out: str(flags['--out']),
2487
+ max: str(flags['--max']), dryRun: !!flags['--dry-run'], json,
2488
+ }, io);
2489
+ }
2490
+ case 'beats': {
2491
+ const m = str(flags['--meter']);
2492
+ return await beats({ paths: positionals, dir: str(flags['--dir']), meter: m === undefined ? undefined : Number(m), json }, io);
2493
+ }
2494
+ case 'schema': return await schema({ target, strict: !!flags['--strict'], json }, io);
2495
+ case 'loop':
2496
+ case 'directions': {
2497
+ const num = (f) => {
2498
+ const v = str(flags[f]);
2499
+ if (v === undefined)
2500
+ return undefined;
2501
+ const n = Number(v);
2502
+ return Number.isInteger(n) && n > 0 ? n : null;
2503
+ };
2504
+ const bad = ['--fps', '--min', '--max', '--size', '--dirs'].find((f) => num(f) === null);
2505
+ if (bad) {
2506
+ u.error(`${bad} is a whole number`, help);
2507
+ return EXIT.error;
2508
+ }
2509
+ const size = num('--size');
2510
+ if (size !== undefined && (size < LOOP_LIMITS.size[0] || size > LOOP_LIMITS.size[1])) {
2511
+ u.error(`--size is ${LOOP_LIMITS.size.join(' to ')} pixels`, help);
2512
+ return EXIT.error;
2513
+ }
2514
+ if (command === 'directions')
2515
+ return await directions({ source: target, dirs: num('--dirs'), size, key: str(flags['--key']), reverse: !!flags['--reverse'], name: str(flags['--name']), out: str(flags['--out']), dir: str(flags['--dir']), json }, io);
2516
+ const fps = num('--fps'), min = num('--min'), max = num('--max');
2517
+ if (fps !== undefined && (fps < LOOP_LIMITS.fps[0] || fps > LOOP_LIMITS.fps[1])) {
2518
+ u.error(`--fps is ${LOOP_LIMITS.fps.join(' to ')}`, help);
2519
+ return EXIT.error;
2520
+ }
2521
+ if ([min, max].some((v) => v !== undefined && (v < LOOP_LIMITS.frames[0] || v > LOOP_LIMITS.frames[1]))) {
2522
+ u.error(`--min and --max are ${LOOP_LIMITS.frames.join(' to ')} frames`, help);
2523
+ return EXIT.error;
2524
+ }
2525
+ return await loop({ source: target, fps, min, max, size, key: str(flags['--key']), name: str(flags['--name']), out: str(flags['--out']), dir: str(flags['--dir']), json }, io);
2526
+ }
2527
+ case 'board': {
2528
+ const known = BOARD_SUBCOMMANDS.includes(positionals[0] ?? '');
2529
+ if (!known && positionals.length) {
2530
+ u.error(`unknown: board ${positionals[0]}`, `use one of ${BOARD_SUBCOMMANDS.join(', ')}`);
2531
+ return EXIT.error;
2532
+ }
2533
+ const sub = known ? positionals[0] : 'show';
2534
+ const lim = str(flags['--limit']);
2535
+ if (lim !== undefined && !(Number.isInteger(Number(lim)) && Number(lim) >= 1 && Number(lim) <= 20)) {
2536
+ u.error('--limit is 1 to 20', help);
2537
+ return EXIT.error;
2538
+ }
2539
+ return await board({
2540
+ sub, arg: positionals.slice(1).join(' ') || undefined, dir: str(flags['--dir']), limit: lim === undefined ? undefined : Number(lim),
2541
+ anyLicence: !!flags['--any-licence'], keep: str(flags['--keep']), lends: str(flags['--lends']), note: str(flags['--note']),
2542
+ licence: str(flags['--licence']), by: str(flags['--by']), title: str(flags['--title']), json,
2543
+ }, io);
2544
+ }
2545
+ case 'lessons': {
2546
+ const add = positionals[0] === 'add', motif = positionals[0] === 'motif';
2547
+ if (!add && !motif && positionals.length) {
2548
+ u.error(`unknown: lessons ${positionals[0]}`, 'funtools lessons, or lessons add "<finding>" --fix "<fix>"');
2549
+ return EXIT.error;
2550
+ }
2551
+ return await lessons({
2552
+ add, motif, finding: positionals.slice(1).join(' '), fix: str(flags['--fix']), source: str(flags['--source']), delta: str(flags['--delta']),
2553
+ genre: str(flags['--genre']), share: !!flags['--share'], dir: str(flags['--dir']), json,
2554
+ }, io);
2555
+ }
2556
+ case 'profile': {
2557
+ const vp = str(flags['--viewport']) ?? 'phone';
2558
+ if (vp !== 'desktop' && vp !== 'phone') {
2559
+ u.error(`unknown viewport: ${vp}`, '--viewport is desktop or phone');
2560
+ return EXIT.error;
2561
+ }
2562
+ const int = (f, d, [lo, hi]) => {
2563
+ const n = Number(str(flags[f]) ?? d);
2564
+ return Number.isInteger(n) && n >= lo && n <= hi ? n : null;
2565
+ };
2566
+ const frames = int('--frames', 120, PROFILE_LIMITS.frames), settleMs = int('--settle', 1500, PROFILE_LIMITS.settleMs);
2567
+ if (frames === null) {
2568
+ u.error(`--frames is a whole number from ${PROFILE_LIMITS.frames.join(' to ')}`, help);
2569
+ return EXIT.error;
2570
+ }
2571
+ if (settleMs === null) {
2572
+ u.error(`--settle is milliseconds from ${PROFILE_LIMITS.settleMs.join(' to ')}`, help);
2573
+ return EXIT.error;
2574
+ }
2575
+ const seedRaw = str(flags['--seed']);
2576
+ const seed = seedRaw === undefined ? null : Number(seedRaw);
2577
+ if (seed !== null && !Number.isInteger(seed)) {
2578
+ u.error('--seed is a whole number', help);
2579
+ return EXIT.error;
2580
+ }
2581
+ const throttle = int('--throttle', 1, PROFILE_LIMITS.throttle);
2582
+ if (throttle === null) {
2583
+ u.error(`--throttle is a whole number from ${PROFILE_LIMITS.throttle.join(' to ')}`, help);
2584
+ return EXIT.error;
2585
+ }
2586
+ const repeat = int('--repeat', 1, PROFILE_LIMITS.repeat);
2587
+ if (repeat === null) {
2588
+ u.error(`--repeat is a whole number from ${PROFILE_LIMITS.repeat.join(' to ')}`, help);
2589
+ return EXIT.error;
2590
+ }
2591
+ const views = (str(flags['--views']) ?? '').split(',').map((v) => v.trim()).filter(Boolean);
2592
+ const budgetRaw = str(flags['--budget']);
2593
+ const budgetMs = budgetRaw === undefined ? undefined : Number(budgetRaw);
2594
+ if (budgetMs !== undefined && !(budgetMs >= PROFILE_LIMITS.budgetMs[0] && budgetMs <= PROFILE_LIMITS.budgetMs[1])) {
2595
+ u.error(`--budget is a frame budget in ms from ${PROFILE_LIMITS.budgetMs.join(' to ')}`, help);
2596
+ return EXIT.error;
2597
+ }
2598
+ if (budgetMs !== undefined && !flags['--compare']) {
2599
+ u.error('--budget is the burn rate\'s frame budget', 'add --compare');
2600
+ return EXIT.error;
2601
+ }
2602
+ return await profile({
2603
+ target, viewport: vp, views, seed, frames, settleMs, against: str(flags['--against']) ?? null, click: frontDoorOf(flags), json,
2604
+ software: !!flags['--software'], throttle, repeat, compare: !!flags['--compare'], budgetMs,
2605
+ }, io);
2606
+ }
2607
+ case 'clip': {
2608
+ const isReport = positionals[0] === 'report';
2609
+ const fpsRaw = str(flags['--fps']);
2610
+ const fps = fpsRaw === undefined ? undefined : Number(fpsRaw);
2611
+ if (fps !== undefined && !(fps >= 1 && fps <= 60)) {
2612
+ u.error('--fps is 1 to 60', help);
2613
+ return EXIT.error;
2614
+ }
2615
+ const seats = (str(flags['--seats']) ?? '').split(',').map((s) => s.trim()).filter(Boolean);
2616
+ return await clip({ sub: isReport ? 'report' : 'prepare', dir: str(flags['--dir']) ?? (isReport ? positionals[1] : positionals[0]) ?? '.', frames: str(flags['--frames']), fps, seats, json }, io);
2617
+ }
2618
+ case 'judge': {
2619
+ const sub = positionals[0];
2620
+ if (!JUDGE_SUBCOMMANDS.includes(sub)) {
2621
+ u.error(`judge ${sub ?? ''}: structure, identity or report`.replace(/ +:/, ':'), help);
2622
+ return EXIT.error;
2623
+ }
2624
+ const medium = str(flags['--medium']);
2625
+ if (medium !== undefined && medium !== 'model' && medium !== 'sprites') {
2626
+ u.error('--medium is model or sprites', help);
2627
+ return EXIT.error;
2628
+ }
2629
+ if (sub !== 'structure' && flags['--prompt'] !== undefined) {
2630
+ u.error('--prompt is for judge structure', help);
2631
+ return EXIT.error;
2632
+ }
2633
+ if (sub !== 'identity' && (flags['--concept'] !== undefined || medium)) {
2634
+ u.error('--concept and --medium are for judge identity', help);
2635
+ return EXIT.error;
2636
+ }
2637
+ return await judge({ sub, positionals: positionals.slice(1), dir: str(flags['--dir']) ?? '.', prompt: str(flags['--prompt']), concept: str(flags['--concept']), medium, json }, io);
2638
+ }
2639
+ case 'unity': {
2640
+ const num = (f) => { const v = str(flags[f]); return v === undefined ? undefined : Number(v); };
2641
+ for (const f of ['--max', '--stale-minutes', '--max-wait', '--days', '--below']) {
2642
+ const v = num(f);
2643
+ if (v !== undefined && !(v >= 0)) {
2644
+ u.error(`${f} ${str(flags[f])}`, 'a number');
2645
+ return 125;
2646
+ }
2647
+ }
2648
+ const sub = positionals[0];
2649
+ if (sub !== 'run' && sub !== 'probe' && sub !== 'play' && sub !== 'capture' && passthrough.length) {
2650
+ u.error('arguments after -- go with unity run (Unity\'s) or probe, play and capture (the player\'s)', 'funtools unity run -- <unity args>');
2651
+ return 125;
2652
+ }
2653
+ if (sub === 'probe' || sub === 'play' || sub === 'capture') {
2654
+ for (const f of ['--seconds', '--port', '--settle-ms']) {
2655
+ const v = num(f);
2656
+ if (v !== undefined && !(v > 0)) {
2657
+ u.error(`${f} ${str(flags[f])}`, 'a number above 0');
2658
+ return 3;
2659
+ }
2660
+ }
2661
+ const staleMinutes = num('--stale-minutes') ?? 20, maxRuns = num('--max') ?? 2, maxWait = num('--max-wait');
2662
+ return await unityPlayer({
2663
+ sub, args: positionals.slice(1), project: str(flags['--project']), target: str(flags['--target']), path: str(flags['--path']), seconds: num('--seconds'),
2664
+ tier: str(flags['--tier']), budget: str(flags['--budget']), player: str(flags['--player']), rebuild: !!flags['--rebuild'], noBuild: !!flags['--no-build'],
2665
+ keepTarget: !!flags['--keep-target'], port: num('--port'), udid: str(flags['--udid']), device: str(flags['--device']), keepSim: !!flags['--keep-sim'],
2666
+ visible: !!flags['--visible'], sound: !!flags['--sound'], out: str(flags['--out']), all: !!flags['--all'], dev: !!flags['--dev'], settleMs: num('--settle-ms'),
2667
+ playerArgs: passthrough, playerArgsFile: str(flags['--player-args']), strict: !!flags['--strict'],
2668
+ points: !!flags['--points'], mouse: !!flags['--mouse'], from: str(flags['--from']), git: str(flags['--git']), ref: str(flags['--ref']),
2669
+ absolute: !!flags['--absolute'], tests: !!flags['--tests'], force: !!flags['--force'], dryRun: !!flags['--dry-run'], json,
2670
+ queue: { staleMs: staleMinutes * 60_000, max: maxRuns, pollMs: 5000, maxWaitMs: maxWait === undefined ? null : maxWait * 60_000 },
2671
+ }, io);
2672
+ }
2673
+ if (sub === 'bridge')
2674
+ return await unityBridge({ action: positionals[1], project: str(flags['--project']), json }, io);
2675
+ if (sub === 'editor') {
2676
+ for (const f of ['--count', '--wait', '--depth']) {
2677
+ const v = num(f);
2678
+ if (v !== undefined && !(Number.isInteger(v) && v >= 1)) {
2679
+ u.error(`${f} ${str(flags[f])}`, 'a whole number, 1 or more');
2680
+ return 3;
2681
+ }
2682
+ }
2683
+ return await unityEditor({
2684
+ action: positionals[1], args: positionals.slice(2), project: str(flags['--project']), unity: str(flags['--unity']),
2685
+ since: str(flags['--since']), count: num('--count'), scene: !!flags['--scene'], game: !!flags['--game'], out: str(flags['--out']),
2686
+ open: !!flags['--open'], wait: num('--wait'), name: str(flags['--name']), at: str(flags['--at']), depth: num('--depth'),
2687
+ force: !!flags['--force'], json,
2688
+ }, io);
2689
+ }
2690
+ return await unity({
2691
+ sub, unityArgs: passthrough, project: str(flags['--project']), unity: str(flags['--unity']), log: str(flags['--log']), noQuit: !!flags['--no-quit'],
2692
+ max: num('--max'), staleMinutes: num('--stale-minutes'), maxWaitMinutes: num('--max-wait'),
2693
+ roots: sub === 'gc' ? positionals.slice(1) : [], days: num('--days'), yes: !!flags['--yes'], json,
2694
+ disk: !!flags['--disk'], below: num('--below'), only: str(flags['--only']), apply: !!flags['--apply'], strict: !!flags['--strict'],
2695
+ }, io);
2696
+ }
2697
+ case 'phone': {
2698
+ const o = str(flags['--orientation']);
2699
+ if (o !== undefined && o !== 'portrait' && o !== 'landscape') {
2700
+ u.error(`unknown orientation: ${o}`, '--orientation is portrait or landscape');
2701
+ return EXIT.error;
2702
+ }
2703
+ const seconds = Number(str(flags['--seconds']) ?? 6);
2704
+ if (!Number.isFinite(seconds) || seconds < 1 || seconds > 60) {
2705
+ u.error('--seconds is 1 to 60', help);
2706
+ return EXIT.error;
2707
+ }
2708
+ const taps = (str(flags['--taps']) ?? '').split(/\s+/).map((t) => t.trim()).filter(Boolean);
2709
+ const swipes = (str(flags['--swipes']) ?? '').split(/[\s,]+/).map((t) => t.trim()).filter(Boolean);
2710
+ return await phone({ target, sim: str(flags['--sim']), orientation: o, seconds, taps, swipes, keep: !!flags['--keep'], out: str(flags['--out']), json }, io);
2711
+ }
2712
+ case 'inspect': {
2713
+ const vp = str(flags['--viewport']) ?? 'desktop';
2714
+ if (vp !== 'desktop' && vp !== 'phone') {
2715
+ u.error(`unknown viewport: ${vp}`, '--viewport is desktop or phone');
2716
+ return EXIT.error;
2717
+ }
2718
+ const orientation = orientationOf(flags, vp, u);
2719
+ if (orientation === null)
2720
+ return EXIT.error;
2721
+ const settle = Number(str(flags['--settle']) ?? 1500);
2722
+ if (!Number.isFinite(settle) || settle < 0 || settle > 20_000) {
2723
+ u.error('--settle is milliseconds from 0 to 20000', help);
2724
+ return EXIT.error;
2725
+ }
2726
+ const url = str(flags['--url']);
2727
+ if (url !== undefined && !/^https?:\/\//.test(url)) {
2728
+ u.error(`--url ${url} is not a web address`, 'the address `funtools dev` printed, e.g. http://localhost:5173');
2729
+ return EXIT.error;
2730
+ }
2731
+ return await inspect({
2732
+ target, url, at: str(flags['--at']), name: str(flags['--name']), tree: !!flags['--tree'], viewport: vp, orientation,
2733
+ view: str(flags['--view']) ?? null, verbs: (str(flags['--verbs']) ?? '').split(',').map((v) => v.trim()).filter(Boolean),
2734
+ settleMs: settle, click: frontDoorOf(flags), json,
2735
+ }, io);
2736
+ }
2737
+ case 'look': {
2738
+ if (THEME_SUBCOMMANDS.includes(positionals[0] ?? '')) {
2739
+ const sub = positionals[0];
2740
+ const dir = str(flags['--dir']) ?? (sub === 'report' ? positionals[1] : undefined) ?? '.';
2741
+ return await lookTheme({ sub, dir, pairs: sub === 'set' ? positionals.slice(1) : undefined, file: sub === 'patch' ? positionals[1] : undefined, json }, io);
2742
+ }
2743
+ if (flags['--hud']) {
2744
+ const vp = str(flags['--viewport']) ?? 'phone', orientation = str(flags['--orientation']);
2745
+ const samples = Number(str(flags['--samples']) ?? HUD_SAMPLING.samples), every = Number(str(flags['--every']) ?? HUD_SAMPLING.everyMs);
2746
+ if (vp !== 'desktop' && vp !== 'phone') {
2747
+ u.error(`unknown viewport: ${vp}`, '--viewport is desktop or phone');
2748
+ return EXIT.error;
2749
+ }
2750
+ if (orientation !== undefined && orientation !== 'portrait' && orientation !== 'landscape') {
2751
+ u.error('--orientation is portrait or landscape', help);
2752
+ return EXIT.error;
2753
+ }
2754
+ if (!Number.isInteger(samples) || samples < 1 || samples > HUD_SAMPLING.max) {
2755
+ u.error(`--samples is a whole number from 1 to ${HUD_SAMPLING.max}`, help);
2756
+ return EXIT.error;
2757
+ }
2758
+ if (!Number.isFinite(every) || every < 100 || every > 5_000) {
2759
+ u.error('--every is milliseconds from 100 to 5000', help);
2760
+ return EXIT.error;
2761
+ }
2762
+ return await lookHud({ target, viewport: vp, orientation, view: str(flags['--view']) ?? null, verbs: (str(flags['--verbs']) ?? '').split(',').map((v) => v.trim()).filter(Boolean), samples, everyMs: every, click: frontDoorOf(flags), json }, io);
2763
+ }
2764
+ if (flags['--3d'])
2765
+ return await look3d({ target, static: !!flags['--static'], view: str(flags['--view']) ?? null, click: frontDoorOf(flags), json }, io);
2766
+ if (flags['--fit'])
2767
+ return await lookFit({ target, view: str(flags['--view']) ?? null, click: frontDoorOf(flags), json }, io);
2768
+ if (flags['--sheet'])
2769
+ return await lookSheet({ target, sprites: str(flags['--sprites']), sizes: str(flags['--sizes']), ground: str(flags['--ground']), out: str(flags['--out']), json }, io);
2770
+ if (!flags['--read']) {
2771
+ u.error('look measures --read, --hud, --fit, --sheet or --3d, or sets the look (set, patch, report)', 'funtools look --read [dir] · funtools look --hud [dir] · funtools look --fit [dir] · funtools look --sheet [dir] · funtools look --3d [dir] · funtools look set plate-ink=#3a2618 · funtools look report');
2772
+ return EXIT.error;
2773
+ }
2774
+ const vp = str(flags['--viewport']) ?? 'desktop';
2775
+ if (vp !== 'desktop' && vp !== 'phone') {
2776
+ u.error(`unknown viewport: ${vp}`, '--viewport is desktop or phone');
2777
+ return EXIT.error;
2778
+ }
2779
+ const hold = Number(str(flags['--hold']) ?? 1500);
2780
+ if (!Number.isFinite(hold) || hold < 0 || hold > 10_000) {
2781
+ u.error('--hold is milliseconds from 0 to 10000', help);
2782
+ return EXIT.error;
2783
+ }
2784
+ return await lookRead({
2785
+ target, viewport: vp, view: str(flags['--view']) ?? null, holdMs: hold, click: frontDoorOf(flags),
2786
+ player: str(flags['--player']), threats: str(flags['--threats']), colours: str(flags['--colours']), json,
2787
+ }, io);
2788
+ }
2789
+ case 'optimize': return await optimize({ positionals, flags, json }, io);
2790
+ case 'fidelity': return await fidelity({
2791
+ positionals, renders: str(flags['--renders']), out: str(flags['--out']), size: str(flags['--size']), min: str(flags['--min']),
2792
+ ownAxes: !!flags['--own-axes'], roll: !!flags['--roll'], outline: !!flags['--outline'],
2793
+ quarterTurns: !!flags['--quarter-turns'], sameScale: !!flags['--same-scale'], json,
2794
+ }, io);
2795
+ case 'model': return await model({
2796
+ local: !!flags['--local'], positionals, out: str(flags['--out']), json,
2797
+ targetTriangles: str(flags['--target-triangles']), heightM: str(flags['--height-m']),
2798
+ frames: str(flags['--frames']), size: str(flags['--size']), keepClips: str(flags['--keep-clips']),
2799
+ tone: str(flags['--tone']), palette: str(flags['--palette']), gameId: str(flags['--game-id']),
2800
+ quality: str(flags['--quality']), roughness: !!flags['--roughness'] || undefined, normal: !!flags['--normal'] || undefined,
2801
+ }, io);
2802
+ case 'job': return await job({ id: target, wait: !!flags['--wait'], out: str(flags['--out']), json }, io);
2803
+ case 'jobs': return await jobs({ tool: str(flags['--tool']), status: str(flags['--status']), limit: str(flags['--limit']), cursor: str(flags['--cursor']), refusals: !!flags['--refusals'], json }, io);
2804
+ case 'login': {
2805
+ const asked = str(flags['--scope']);
2806
+ const scopes = asked === undefined ? undefined : asked.split(/[\s,]+/).filter(Boolean);
2807
+ if (scopes !== undefined && scopes.length === 0) {
2808
+ u.error('--scope needs at least one scope', 'funtools login --scope community:read,community:write');
2809
+ return EXIT.error;
2810
+ }
2811
+ if (scopes !== undefined && flags['--key']) {
2812
+ u.error('--scope goes with the browser sign-in', 'a key you paste keeps the scopes it was made with (Settings › Developers)');
2813
+ return EXIT.error;
2814
+ }
2815
+ if (!flags['--key'])
2816
+ return await browserLogin(io, undefined, undefined, undefined, scopes);
2817
+ return await login({ key: str(flags['--key']), api: str(flags['--api']) }, io);
2818
+ }
2819
+ case 'whoami': return await whoami(io);
2820
+ case 'setup': return await (await import("./commands/setup.js")).setup({ host: str(flags['--host']), dryRun: !!flags['--dry-run'], json }, io);
2821
+ case 'mcp': {
2822
+ const { serveStdio } = await import("./mcp/server.js");
2823
+ await serveStdio({ cwd: process.cwd(), bin: [process.execPath, ...process.execArgv, process.argv[1]] });
2824
+ return EXIT.pass;
2825
+ }
2826
+ case 'find': return await (await import("./commands/find.js")).find({ ask: positionals.join(' '), usage: USAGE, names: Object.keys(SPECS), json }, io);
2827
+ case 'open': {
2828
+ const what = positionals[0];
2829
+ if (!what) {
2830
+ u.error('open needs a URL or a file', 'funtools open http://localhost:5317/ | funtools open design/first-look/target-key-art.png');
2831
+ return EXIT.error;
2832
+ }
2833
+ const target = /^[a-z]+:\/\//i.test(what) ? what : (await import('node:path')).resolve(what);
2834
+ if (!/^[a-z]+:\/\//i.test(what) && !(await import('node:fs')).existsSync(target)) {
2835
+ u.error(`no such file: ${what}`, 'give a URL or a path that exists');
2836
+ return EXIT.error;
2837
+ }
2838
+ const { openTarget } = await import("./dev/open.js");
2839
+ if (openTarget(target)) {
2840
+ u.summary('pass', `opened ${what}`);
2841
+ return EXIT.pass;
2842
+ }
2843
+ u.summary('note', `nothing opens here (CI, FUNPIXEL_NO_OPEN, or no display): ${what}`);
2844
+ return EXIT.not_observed;
2845
+ }
2846
+ case 'usage': return await usage({ days: str(flags['--days']), thisKey: !!flags['--this-key'], json }, io);
2847
+ case 'budget': return await budget({ json }, io);
2848
+ case 'logout': return await logout(io);
2849
+ case 'publish': {
2850
+ const to = str(flags['--target']) ?? 'funpixel';
2851
+ if (!TARGETS.includes(to)) {
2852
+ u.error(`unknown target: ${to}`, `use one of ${TARGETS.join(', ')}`);
2853
+ return EXIT.error;
2854
+ }
2855
+ return await publish({
2856
+ target, to: to, yes: !!flags['--yes'], json,
2857
+ name: str(flags['--name']), gameId: str(flags['--game-id']),
2858
+ itch: str(flags['--itch']), project: str(flags['--project']), out: str(flags['--out']),
2859
+ }, io);
2860
+ }
2861
+ case 'models': {
2862
+ const sub = positionals[0];
2863
+ if (!sub || !MODELS_SUBCOMMANDS.includes(sub)) {
2864
+ u.error(sub ? `unknown models step: ${sub}` : 'models needs a step', 'funtools models list | models install <local id>');
2865
+ return EXIT.error;
2866
+ }
2867
+ if (positionals.length > (sub === 'install' ? 2 : 1)) {
2868
+ u.error(`models ${sub} takes ${sub === 'install' ? 'one model id' : 'no argument'}`, 'funtools models list | models install kokoro-82m');
2869
+ return EXIT.error;
2870
+ }
2871
+ return await models({ sub, id: positionals[1], force: !!flags['--force'], json }, io);
2872
+ }
2873
+ case 'store': {
2874
+ const sub = positionals[0];
2875
+ if (!sub || !STORE_SUBCOMMANDS.includes(sub)) {
2876
+ u.error(sub ? `unknown store step: ${sub}` : 'store needs a step', 'funtools store init|doctor|lint|plan [dir] [--store play|ios|steam]');
2877
+ return EXIT.error;
2878
+ }
2879
+ if (positionals.length > 2) {
2880
+ u.error(`store ${sub} takes one folder`, `funtools store ${sub} [dir]`);
2881
+ return EXIT.error;
2882
+ }
2883
+ return await store({ sub, dir: str(flags['--dir']) ?? positionals[1], store: str(flags['--store']), json }, io);
2884
+ }
2885
+ default: {
2886
+ const viewport = str(flags['--viewport']) ?? 'desktop';
2887
+ if (!VIEWPORT_CHOICES.includes(viewport)) {
2888
+ u.error(`unknown viewport: ${viewport}`, '--viewport is desktop, phone or both');
2889
+ return EXIT.error;
2890
+ }
2891
+ const players = str(flags['--players']);
2892
+ if (players !== undefined && players !== '2') {
2893
+ u.error(`--players ${players}`, 'two players is what verify measures: --players 2');
2894
+ return EXIT.error;
2895
+ }
2896
+ return await verify({
2897
+ players: players ? 2 : undefined,
2898
+ target, checks: str(flags['--checks']), manifest: str(flags['--manifest']), sweep: !flags['--no-sweep'], watch: !!flags['--watch'],
2899
+ json, report: !!flags['--report'], viewport: viewport, frontDoor: frontDoorOf(flags),
2900
+ }, io);
2901
+ }
2902
+ }
2903
+ }
2904
+ catch (e) {
2905
+ const m = message(e), dash = m.indexOf(' — ');
2906
+ u.error(dash < 0 ? m : m.slice(0, dash), dash < 0 ? 'run `funtools doctor` to check the setup; if it repeats, report it with the command you ran' : m.slice(dash + 3));
2907
+ return EXIT.error;
2908
+ }
2909
+ }
2910
+ const invokedDirectly = () => { try {
2911
+ return !!process.argv[1] && realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url));
2912
+ }
2913
+ catch {
2914
+ return false;
2915
+ } };
2916
+ if (invokedDirectly())
2917
+ process.exitCode = await main(process.argv.slice(2));