@quybt93/pcgf 0.0.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 (1320) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/.agents/skills/bmad-advanced-elicitation/SKILL.md +64 -0
  3. package/.agents/skills/bmad-advanced-elicitation/assets/methods.csv +72 -0
  4. package/.agents/skills/bmad-advanced-elicitation/customize.toml +54 -0
  5. package/.agents/skills/bmad-advanced-elicitation/scripts/pick_methods.py +233 -0
  6. package/.agents/skills/bmad-advanced-elicitation/scripts/tests/test_pick_methods.py +228 -0
  7. package/.agents/skills/bmad-agent-analyst/SKILL.md +76 -0
  8. package/.agents/skills/bmad-agent-analyst/customize.toml +103 -0
  9. package/.agents/skills/bmad-agent-architect/SKILL.md +76 -0
  10. package/.agents/skills/bmad-agent-architect/customize.toml +63 -0
  11. package/.agents/skills/bmad-agent-dev/SKILL.md +76 -0
  12. package/.agents/skills/bmad-agent-dev/customize.toml +81 -0
  13. package/.agents/skills/bmad-agent-pm/SKILL.md +76 -0
  14. package/.agents/skills/bmad-agent-pm/customize.toml +73 -0
  15. package/.agents/skills/bmad-agent-ux-designer/SKILL.md +76 -0
  16. package/.agents/skills/bmad-agent-ux-designer/customize.toml +58 -0
  17. package/.agents/skills/bmad-architecture/SKILL.md +85 -0
  18. package/.agents/skills/bmad-architecture/assets/spine-template.md +79 -0
  19. package/.agents/skills/bmad-architecture/customize.toml +101 -0
  20. package/.agents/skills/bmad-architecture/references/headless.md +26 -0
  21. package/.agents/skills/bmad-architecture/references/reviewer-gate.md +13 -0
  22. package/.agents/skills/bmad-architecture/scripts/lint_spine.py +257 -0
  23. package/.agents/skills/bmad-architecture/scripts/tests/test_lint_spine.py +270 -0
  24. package/.agents/skills/bmad-brainstorming/SKILL.md +80 -0
  25. package/.agents/skills/bmad-brainstorming/assets/brain-icons.json +166 -0
  26. package/.agents/skills/bmad-brainstorming/assets/brain-methods.csv +109 -0
  27. package/.agents/skills/bmad-brainstorming/assets/brain-selector.html +328 -0
  28. package/.agents/skills/bmad-brainstorming/customize.toml +83 -0
  29. package/.agents/skills/bmad-brainstorming/references/converge.md +24 -0
  30. package/.agents/skills/bmad-brainstorming/references/finalize.md +26 -0
  31. package/.agents/skills/bmad-brainstorming/references/headless.md +54 -0
  32. package/.agents/skills/bmad-brainstorming/references/in-chat-techniques.md +18 -0
  33. package/.agents/skills/bmad-brainstorming/references/mode-autonomous.md +10 -0
  34. package/.agents/skills/bmad-brainstorming/references/mode-facilitator.md +11 -0
  35. package/.agents/skills/bmad-brainstorming/references/mode-partner.md +16 -0
  36. package/.agents/skills/bmad-brainstorming/references/resume.md +5 -0
  37. package/.agents/skills/bmad-brainstorming/scripts/brain.py +789 -0
  38. package/.agents/skills/bmad-brainstorming/scripts/tests/test_brain.py +289 -0
  39. package/.agents/skills/bmad-build/SKILL.md +13 -0
  40. package/.agents/skills/bmad-build/compile-epic-context.md +62 -0
  41. package/.agents/skills/bmad-build/customize.toml +152 -0
  42. package/.agents/skills/bmad-build/references/claims-check.md +14 -0
  43. package/.agents/skills/bmad-build/references/deletion-check.md +14 -0
  44. package/.agents/skills/bmad-build/review-prompts/edge-case-hunter.md +112 -0
  45. package/.agents/skills/bmad-build/review-prompts/verification-gap.md +113 -0
  46. package/.agents/skills/bmad-build/spec-template.md +111 -0
  47. package/.agents/skills/bmad-build/step-01-clarify-and-route.md +100 -0
  48. package/.agents/skills/bmad-build/step-02-plan.md +62 -0
  49. package/.agents/skills/bmad-build/step-03-implement.md +51 -0
  50. package/.agents/skills/bmad-build/step-04-review.md +85 -0
  51. package/.agents/skills/bmad-build/step-05-present.md +43 -0
  52. package/.agents/skills/bmad-build/step-oneshot.md +107 -0
  53. package/.agents/skills/bmad-build/sync-sprint-status.md +5 -0
  54. package/.agents/skills/bmad-build/workflow.md +84 -0
  55. package/.agents/skills/bmad-build-auto/SKILL.md +13 -0
  56. package/.agents/skills/bmad-build-auto/compile-epic-context.md +62 -0
  57. package/.agents/skills/bmad-build-auto/customize.toml +119 -0
  58. package/.agents/skills/bmad-build-auto/references/claims-check.md +14 -0
  59. package/.agents/skills/bmad-build-auto/references/deletion-check.md +14 -0
  60. package/.agents/skills/bmad-build-auto/review-prompts/edge-case-hunter.md +112 -0
  61. package/.agents/skills/bmad-build-auto/review-prompts/verification-gap.md +113 -0
  62. package/.agents/skills/bmad-build-auto/spec-template.md +96 -0
  63. package/.agents/skills/bmad-build-auto/step-01-clarify-and-route.md +84 -0
  64. package/.agents/skills/bmad-build-auto/step-02-plan.md +27 -0
  65. package/.agents/skills/bmad-build-auto/step-03-implement.md +48 -0
  66. package/.agents/skills/bmad-build-auto/step-04-review.md +116 -0
  67. package/.agents/skills/bmad-build-auto/workflow.md +104 -0
  68. package/.agents/skills/bmad-code-review/SKILL.md +90 -0
  69. package/.agents/skills/bmad-code-review/customize.toml +110 -0
  70. package/.agents/skills/bmad-code-review/references/claims-check.md +14 -0
  71. package/.agents/skills/bmad-code-review/references/deletion-check.md +14 -0
  72. package/.agents/skills/bmad-code-review/review-prompts/edge-case-hunter.md +112 -0
  73. package/.agents/skills/bmad-code-review/review-prompts/verification-gap.md +113 -0
  74. package/.agents/skills/bmad-code-review/steps/step-01-gather-context.md +94 -0
  75. package/.agents/skills/bmad-code-review/steps/step-02-review.md +32 -0
  76. package/.agents/skills/bmad-code-review/steps/step-03-triage.md +54 -0
  77. package/.agents/skills/bmad-code-review/steps/step-04-present.md +134 -0
  78. package/.agents/skills/bmad-correct-course/SKILL.md +308 -0
  79. package/.agents/skills/bmad-correct-course/checklist.md +288 -0
  80. package/.agents/skills/bmad-correct-course/customize.toml +39 -0
  81. package/.agents/skills/bmad-create-epics-and-stories/SKILL.md +93 -0
  82. package/.agents/skills/bmad-create-epics-and-stories/customize.toml +39 -0
  83. package/.agents/skills/bmad-create-epics-and-stories/steps/step-01-validate-prerequisites.md +263 -0
  84. package/.agents/skills/bmad-create-epics-and-stories/steps/step-02-design-epics.md +242 -0
  85. package/.agents/skills/bmad-create-epics-and-stories/steps/step-03-create-stories.md +255 -0
  86. package/.agents/skills/bmad-create-epics-and-stories/steps/step-04-final-validation.md +143 -0
  87. package/.agents/skills/bmad-create-epics-and-stories/templates/epics-template.md +61 -0
  88. package/.agents/skills/bmad-customize/SKILL.md +111 -0
  89. package/.agents/skills/bmad-customize/scripts/list_customizable_skills.py +231 -0
  90. package/.agents/skills/bmad-customize/scripts/tests/test_list_customizable_skills.py +249 -0
  91. package/.agents/skills/bmad-deep-recon/SKILL.md +82 -0
  92. package/.agents/skills/bmad-deep-recon/assets/research.template.md +18 -0
  93. package/.agents/skills/bmad-deep-recon/customize.toml +212 -0
  94. package/.agents/skills/bmad-deep-recon/references/draft.md +8 -0
  95. package/.agents/skills/bmad-deep-recon/references/finalize.md +11 -0
  96. package/.agents/skills/bmad-deep-recon/references/html-briefing.md +16 -0
  97. package/.agents/skills/bmad-deep-recon/references/lifecycle.md +11 -0
  98. package/.agents/skills/bmad-deep-recon/references/process.md +10 -0
  99. package/.agents/skills/bmad-deep-recon/references/run.md +73 -0
  100. package/.agents/skills/bmad-deep-recon/references/selection.md +13 -0
  101. package/.agents/skills/bmad-deep-recon/references/synthesis.md +16 -0
  102. package/.agents/skills/bmad-deep-recon/references/verification.md +29 -0
  103. package/.agents/skills/bmad-deep-recon/scripts/recon_kit.py +322 -0
  104. package/.agents/skills/bmad-deep-recon/scripts/tests/test_recon_kit.py +144 -0
  105. package/.agents/skills/bmad-deep-recon/types/academic-lit.md +19 -0
  106. package/.agents/skills/bmad-deep-recon/types/competitive.md +19 -0
  107. package/.agents/skills/bmad-deep-recon/types/domain.md +19 -0
  108. package/.agents/skills/bmad-deep-recon/types/market.md +19 -0
  109. package/.agents/skills/bmad-deep-recon/types/technical.md +19 -0
  110. package/.agents/skills/bmad-deep-recon/types/user-voice.md +19 -0
  111. package/.agents/skills/bmad-forge-idea/SKILL.md +107 -0
  112. package/.agents/skills/bmad-forge-idea/customize.toml +41 -0
  113. package/.agents/skills/bmad-forge-idea/scripts/resolve_personas.py +277 -0
  114. package/.agents/skills/bmad-forge-idea/scripts/tests/test_resolve_personas.py +160 -0
  115. package/.agents/skills/bmad-help/SKILL.md +77 -0
  116. package/.agents/skills/bmad-party-mode/SKILL.md +60 -0
  117. package/.agents/skills/bmad-party-mode/customize.toml +211 -0
  118. package/.agents/skills/bmad-party-mode/references/create-party.md +70 -0
  119. package/.agents/skills/bmad-party-mode/references/mode-agent-team.md +13 -0
  120. package/.agents/skills/bmad-party-mode/references/mode-auto.md +13 -0
  121. package/.agents/skills/bmad-party-mode/references/mode-subagent.md +31 -0
  122. package/.agents/skills/bmad-party-mode/references/party-memory.md +51 -0
  123. package/.agents/skills/bmad-party-mode/scripts/resolve_party.py +284 -0
  124. package/.agents/skills/bmad-party-mode/scripts/tests/test_resolve_party.py +168 -0
  125. package/.agents/skills/bmad-prd/SKILL.md +94 -0
  126. package/.agents/skills/bmad-prd/assets/headless-schemas.md +76 -0
  127. package/.agents/skills/bmad-prd/assets/prd-template.md +165 -0
  128. package/.agents/skills/bmad-prd/assets/prd-validation-checklist.md +135 -0
  129. package/.agents/skills/bmad-prd/assets/validation-report-template.html +325 -0
  130. package/.agents/skills/bmad-prd/customize.toml +148 -0
  131. package/.agents/skills/bmad-prd/references/headless.md +39 -0
  132. package/.agents/skills/bmad-prd/references/validate.md +97 -0
  133. package/.agents/skills/bmad-prfaq/SKILL.md +135 -0
  134. package/.agents/skills/bmad-prfaq/agents/artifact-analyzer.md +60 -0
  135. package/.agents/skills/bmad-prfaq/agents/web-researcher.md +49 -0
  136. package/.agents/skills/bmad-prfaq/assets/prfaq-template.md +62 -0
  137. package/.agents/skills/bmad-prfaq/bmad-manifest.json +16 -0
  138. package/.agents/skills/bmad-prfaq/customize.toml +39 -0
  139. package/.agents/skills/bmad-prfaq/references/customer-faq.md +55 -0
  140. package/.agents/skills/bmad-prfaq/references/internal-faq.md +51 -0
  141. package/.agents/skills/bmad-prfaq/references/press-release.md +60 -0
  142. package/.agents/skills/bmad-prfaq/references/verdict.md +83 -0
  143. package/.agents/skills/bmad-product-brief/SKILL.md +91 -0
  144. package/.agents/skills/bmad-product-brief/assets/brief-template.md +41 -0
  145. package/.agents/skills/bmad-product-brief/customize.toml +100 -0
  146. package/.agents/skills/bmad-project-context/SKILL.md +121 -0
  147. package/.agents/skills/bmad-project-context/customize.toml +24 -0
  148. package/.agents/skills/bmad-project-context/references/best-practices.md +84 -0
  149. package/.agents/skills/bmad-project-context/references/template.md +55 -0
  150. package/.agents/skills/bmad-qa-generate-e2e-tests/SKILL.md +176 -0
  151. package/.agents/skills/bmad-qa-generate-e2e-tests/checklist.md +33 -0
  152. package/.agents/skills/bmad-qa-generate-e2e-tests/customize.toml +39 -0
  153. package/.agents/skills/bmad-retrospective/SKILL.md +94 -0
  154. package/.agents/skills/bmad-retrospective/customize.toml +39 -0
  155. package/.agents/skills/bmad-retrospective/references/acceptance-verdict.md +55 -0
  156. package/.agents/skills/bmad-retrospective/references/aggregate-views.md +17 -0
  157. package/.agents/skills/bmad-retrospective/references/evidence-gathering.md +30 -0
  158. package/.agents/skills/bmad-retrospective/references/retro-document.md +84 -0
  159. package/.agents/skills/bmad-retrospective/references/team-discussion.md +22 -0
  160. package/.agents/skills/bmad-retrospective/scripts/git_evidence.py +304 -0
  161. package/.agents/skills/bmad-retrospective/scripts/sprint_status.py +746 -0
  162. package/.agents/skills/bmad-retrospective/scripts/tests/fixtures/sprint-status-template.yaml +71 -0
  163. package/.agents/skills/bmad-retrospective/scripts/tests/test_git_evidence.py +750 -0
  164. package/.agents/skills/bmad-retrospective/scripts/tests/test_sprint_status.py +1579 -0
  165. package/.agents/skills/bmad-review/SKILL.md +50 -0
  166. package/.agents/skills/bmad-review/customize.toml +141 -0
  167. package/.agents/skills/bmad-review/references/editorial-common.md +56 -0
  168. package/.agents/skills/bmad-review/references/lens-adversarial.md +19 -0
  169. package/.agents/skills/bmad-review/references/lens-edge-case-hunter.md +72 -0
  170. package/.agents/skills/bmad-review/references/lens-prose.md +7 -0
  171. package/.agents/skills/bmad-review/references/lens-structure.md +9 -0
  172. package/.agents/skills/bmad-review/references/lens-verification-gap.md +92 -0
  173. package/.agents/skills/bmad-review/references/structure-models.md +44 -0
  174. package/.agents/skills/bmad-review/scripts/tests/test_word_metrics.py +62 -0
  175. package/.agents/skills/bmad-review/scripts/word_metrics.py +102 -0
  176. package/.agents/skills/bmad-spec/SKILL.md +160 -0
  177. package/.agents/skills/bmad-spec/assets/headless-schemas.md +33 -0
  178. package/.agents/skills/bmad-spec/assets/spec-template.md +49 -0
  179. package/.agents/skills/bmad-spec/assets/stories-schema.md +44 -0
  180. package/.agents/skills/bmad-spec/customize.toml +52 -0
  181. package/.agents/skills/bmad-sprint-planning/SKILL.md +62 -0
  182. package/.agents/skills/bmad-sprint-planning/customize.toml +39 -0
  183. package/.agents/skills/bmad-sprint-planning/references/fix-sprint-status.md +30 -0
  184. package/.agents/skills/bmad-sprint-planning/references/generate-tracking.md +25 -0
  185. package/.agents/skills/bmad-sprint-planning/references/readiness-gate.md +20 -0
  186. package/.agents/skills/bmad-sprint-planning/references/status-view.md +14 -0
  187. package/.agents/skills/bmad-sprint-planning/references/validate.md +10 -0
  188. package/.agents/skills/bmad-sprint-planning/scripts/sprint_plan.py +697 -0
  189. package/.agents/skills/bmad-sprint-planning/scripts/tests/test_sprint_plan.py +524 -0
  190. package/.agents/skills/bmad-sprint-planning/sprint-status-template.yaml +71 -0
  191. package/.agents/skills/bmad-ux/SKILL.md +90 -0
  192. package/.agents/skills/bmad-ux/assets/color-themes.md +9 -0
  193. package/.agents/skills/bmad-ux/assets/design-directions.md +9 -0
  194. package/.agents/skills/bmad-ux/assets/design-example-editorial.md +158 -0
  195. package/.agents/skills/bmad-ux/assets/design-example-mobile.md +93 -0
  196. package/.agents/skills/bmad-ux/assets/design-example-shadcn.md +109 -0
  197. package/.agents/skills/bmad-ux/assets/excalidraw-wireframe.md +19 -0
  198. package/.agents/skills/bmad-ux/assets/experience-example-mobile.md +112 -0
  199. package/.agents/skills/bmad-ux/assets/experience-example-shadcn.md +133 -0
  200. package/.agents/skills/bmad-ux/assets/headless-schemas.md +84 -0
  201. package/.agents/skills/bmad-ux/assets/key-screens.md +29 -0
  202. package/.agents/skills/bmad-ux/assets/validation-report-template.html +319 -0
  203. package/.agents/skills/bmad-ux/customize.toml +100 -0
  204. package/.agents/skills/bmad-ux/references/creative-tools.md +19 -0
  205. package/.agents/skills/bmad-ux/references/design-md-spec.md +50 -0
  206. package/.agents/skills/bmad-ux/references/headless.md +37 -0
  207. package/.agents/skills/bmad-ux/references/validate.md +115 -0
  208. package/.agents/skills/bmad-walkthrough/SKILL.md +68 -0
  209. package/.agents/skills/bmad-walkthrough/customize.toml +39 -0
  210. package/.agents/skills/bmad-walkthrough/generate-trail.md +38 -0
  211. package/.agents/skills/bmad-walkthrough/step-01-orientation.md +105 -0
  212. package/.agents/skills/bmad-walkthrough/step-02-walkthrough.md +89 -0
  213. package/.agents/skills/bmad-walkthrough/step-03-detail-pass.md +106 -0
  214. package/.agents/skills/bmad-walkthrough/step-04-testing.md +74 -0
  215. package/.agents/skills/bmad-walkthrough/step-05-wrapup.md +30 -0
  216. package/README.md +111 -0
  217. package/bin/pcgf.js +8 -0
  218. package/installer/clean.js +137 -0
  219. package/installer/cli.js +479 -0
  220. package/installer/deps.js +160 -0
  221. package/installer/fs-utils.js +58 -0
  222. package/installer/install.js +201 -0
  223. package/installer/paths.js +17 -0
  224. package/installer/scaffold.js +274 -0
  225. package/installer/tools.js +38 -0
  226. package/package.json +37 -0
  227. package/plugins/phaser-casual-game-factory/.codex-plugin/plugin.json +27 -0
  228. package/plugins/phaser-casual-game-factory/PROGRESS.md +120 -0
  229. package/plugins/phaser-casual-game-factory/README.md +79 -0
  230. package/plugins/phaser-casual-game-factory/assets/sfx/README.md +8 -0
  231. package/plugins/phaser-casual-game-factory/assets/sfx/ui_click.mp3 +0 -0
  232. package/plugins/phaser-casual-game-factory/assets/sfx/ui_close.mp3 +0 -0
  233. package/plugins/phaser-casual-game-factory/assets/ui-packs/README.md +9 -0
  234. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_Blue.png +0 -0
  235. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_DarkGray.png +0 -0
  236. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_Gray.png +0 -0
  237. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_Green.png +0 -0
  238. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_Mint.png +0 -0
  239. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_Pink.png +0 -0
  240. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_Purple.png +0 -0
  241. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_Red.png +0 -0
  242. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_Sky.png +0 -0
  243. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_White_Bg.png +0 -0
  244. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_White_Light1.png +0 -0
  245. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_White_Light2.png +0 -0
  246. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_Yellow.png +0 -0
  247. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_Blue.png +0 -0
  248. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_DarkGray.png +0 -0
  249. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_Flat.png +0 -0
  250. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_Gray.png +0 -0
  251. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_Green.png +0 -0
  252. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_Mint.png +0 -0
  253. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_PInk.png +0 -0
  254. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_Purple.png +0 -0
  255. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_Red.png +0 -0
  256. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_Sky.png +0 -0
  257. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_White_Bg.png +0 -0
  258. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_White_Light1.png +0 -0
  259. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_White_Light2.png +0 -0
  260. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_Yellow.png +0 -0
  261. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Circle118.png +0 -0
  262. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Circle120.png +0 -0
  263. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Circle122.png +0 -0
  264. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Circle74_Bg.png +0 -0
  265. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Circle74_Border.png +0 -0
  266. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Circle82.png +0 -0
  267. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_LeftFlush_Dark.png +0 -0
  268. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_LeftFlush_White1.png +0 -0
  269. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_LeftFlush_White2.png +0 -0
  270. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round01_White_Bg.png +0 -0
  271. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round01_White_Light1.png +0 -0
  272. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round01_White_Light2.png +0 -0
  273. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round01_Yellow.png +0 -0
  274. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round02_Blue.png +0 -0
  275. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round02_White_Bg.png +0 -0
  276. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round02_White_Light.png +0 -0
  277. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round03_Dark.png +0 -0
  278. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round03_WhiteBg.png +0 -0
  279. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round03_White_Light.png +0 -0
  280. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round04_Bg.png +0 -0
  281. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round04_Oblique.png +0 -0
  282. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round05.png +0 -0
  283. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round06_Red.png +0 -0
  284. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round06_White.png +0 -0
  285. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round07.png +0 -0
  286. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round08.png +0 -0
  287. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round09.png +0 -0
  288. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round10_Bg.png +0 -0
  289. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round10_Light.png +0 -0
  290. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_SkillBtnMask.png +0 -0
  291. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_SkillBtn_Blue.png +0 -0
  292. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_SkillBtn_Dark.png +0 -0
  293. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_SkillBtn_Orange.png +0 -0
  294. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_SkillBtn_Red.png +0 -0
  295. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_SkillBtn_White_Bg.png +0 -0
  296. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_SkillBtn_White_Light.png +0 -0
  297. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Tapered_White1.png +0 -0
  298. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Tapered_White2.png +0 -0
  299. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Tapered_White3.png +0 -0
  300. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Tapered_Yellow.png +0 -0
  301. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Menu_BottomBtn_Bg.png +0 -0
  302. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Menu_BottomBtn_TabFocus.png +0 -0
  303. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Menu_BottomBtn_TabFocus_Light.png +0 -0
  304. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Menu_MiddleBtn_Bg.png +0 -0
  305. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Menu_MiddleBtn_TabFocus.png +0 -0
  306. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_01~02_Bg.png +0 -0
  307. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_01~02_InnerBg.png +0 -0
  308. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_01~02_InnerLine.png +0 -0
  309. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_01~02_Light.png +0 -0
  310. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_01~02_Pattern.png +0 -0
  311. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_01~02_Pattern.psd +0 -0
  312. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_03_Bg.png +0 -0
  313. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_03_Border.png +0 -0
  314. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_04~06_Bg.png +0 -0
  315. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_04~06_BgLight.png +0 -0
  316. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_04~06_Border.png +0 -0
  317. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_04~06_Pattern.png +0 -0
  318. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame03_Demo.png +0 -0
  319. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame04_Demo.png +0 -0
  320. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame05_Demo.png +0 -0
  321. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame06_Demo_Blue.png +0 -0
  322. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame06_Demo__Gray.png +0 -0
  323. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame07.png +0 -0
  324. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BasicFrame_Circle160.png +0 -0
  325. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BasicFrame_Hexagon87.png +0 -0
  326. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BasicFrame_Oval44.png +0 -0
  327. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BasicFrame_Oval50.png +0 -0
  328. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BasicFrame_Round12.png +0 -0
  329. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BasicFrame_Round17.png +0 -0
  330. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BasicFrame_Round20.png +0 -0
  331. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BasicFrame_Round24.png +0 -0
  332. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Circle60.png +0 -0
  333. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Circle75_Bg.png +0 -0
  334. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Circle75_Light.png +0 -0
  335. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Circle78.png +0 -0
  336. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Flag_Demo_Blue.png +0 -0
  337. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Flag_Demo_Green.png +0 -0
  338. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Flag_Demo_Red.png +0 -0
  339. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Flag_White_Bg.png +0 -0
  340. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Flag_White_BgGradient.png +0 -0
  341. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Flag_White_BgLine01.png +0 -0
  342. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Flag_White_BgLine02.png +0 -0
  343. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Oval46_Bg.png +0 -0
  344. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Oval46_InnerLine.png +0 -0
  345. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Oval58.png +0 -0
  346. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Rhombus_Bg.png +0 -0
  347. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Rhombus_Inner.png +0 -0
  348. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Round18_Transparent.png +0 -0
  349. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Round20_Demo_Dark.png +0 -0
  350. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Round20_Demo_Yellow.png +0 -0
  351. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Round20_White_Bg.png +0 -0
  352. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Round20_White_Light.png +0 -0
  353. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Round24.png +0 -0
  354. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Round30.png +0 -0
  355. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Squrare_Bg.png +0 -0
  356. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Squrare_Inner.png +0 -0
  357. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame01_Bg.png +0 -0
  358. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame01_BgArrow.png +0 -0
  359. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame01_BgShadow.png +0 -0
  360. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame01_Hexagon_Bg_Blue.png +0 -0
  361. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame01_Hexagon_Bg_Green.png +0 -0
  362. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame01_Hexagon_Bg_Yellow.png +0 -0
  363. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame01_Hexagon_FocusBorder.png +0 -0
  364. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame01_Hexagon_FocusGlow.png +0 -0
  365. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame02_Arrow.png +0 -0
  366. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame02_Bg.png +0 -0
  367. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame02_BgShadow.png +0 -0
  368. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame03_Arrow_Left.png +0 -0
  369. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame03_Arrow_Right.png +0 -0
  370. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame03_Bg.png +0 -0
  371. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame04_Blue_Arrow.png +0 -0
  372. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame04_Blue_Bg.png +0 -0
  373. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame04_White_Arrow.png +0 -0
  374. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame04_White_Bg.png +0 -0
  375. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame05_InnerBg.png +0 -0
  376. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame05_InnerBorder.png +0 -0
  377. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame05_Left_Bg.png +0 -0
  378. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame05_Left_BgShadow.png +0 -0
  379. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame05_Right_Bg.png +0 -0
  380. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame05_Right_BgShadow.png +0 -0
  381. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame01_Bg_d.png +0 -0
  382. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame01_Bg_d_Pattern.png +0 -0
  383. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame01_Bg_n.png +0 -0
  384. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame01_Border.png +0 -0
  385. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame01_Bottom.png +0 -0
  386. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame01_Glow.png +0 -0
  387. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame01_Gradient.png +0 -0
  388. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame01_Gradient_Hologram.png +0 -0
  389. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame02_d_Bg.png +0 -0
  390. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame02_d_Bg_Pattern.png +0 -0
  391. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame02_d_Border.png +0 -0
  392. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame02_n_Bg.png +0 -0
  393. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame02_n_Bottom.png +0 -0
  394. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame02_n_Light.png +0 -0
  395. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame03_d.png +0 -0
  396. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame03_n_Bg.png +0 -0
  397. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame03_n_InnerBg.png +0 -0
  398. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame03_n_Light.png +0 -0
  399. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame04_Bg.png +0 -0
  400. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame04_Bg_DividerLine.png +0 -0
  401. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame04_Bg_Gradient.png +0 -0
  402. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame04_Border.png +0 -0
  403. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame04_FocusBorder.png +0 -0
  404. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame04_FocusGlow.png +0 -0
  405. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame04_Glow.png +0 -0
  406. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame05_Bg.png +0 -0
  407. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame05_Bg_Corner.png +0 -0
  408. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame05_Border.png +0 -0
  409. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame05_FocusBorder.png +0 -0
  410. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame05_FocusGlow.png +0 -0
  411. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame05_Glow.png +0 -0
  412. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame06_Demo_Bg.png +0 -0
  413. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame06_Demo_Bg_Glow_Green.png +0 -0
  414. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame06_Demo_Deco_Green.png +0 -0
  415. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame06_Demo_Frame_Green.png +0 -0
  416. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame06_White_Bg.png +0 -0
  417. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame06_White_Bg_Glow.png +0 -0
  418. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame06_White_Deco.png +0 -0
  419. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame06_White_Frame.png +0 -0
  420. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame00~03_Bg.png +0 -0
  421. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame00~03_BgGlow.png +0 -0
  422. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame00~03_BgLight.png +0 -0
  423. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame00~03_Bg_Hologram.png +0 -0
  424. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame00~03_Border.png +0 -0
  425. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame00~03_CornerDeco.png +0 -0
  426. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame00~03_FocusLine.png +0 -0
  427. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_Blue.png +0 -0
  428. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_Gray.png +0 -0
  429. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_Green.png +0 -0
  430. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_Hologram1.png +0 -0
  431. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_Hologram2.png +0 -0
  432. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_Navy.png +0 -0
  433. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_OffWhite.png +0 -0
  434. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_Purple.png +0 -0
  435. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_Red.png +0 -0
  436. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_Yellow.png +0 -0
  437. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_Blue.png +0 -0
  438. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_Gray.png +0 -0
  439. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_Green.png +0 -0
  440. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_Hologram1.png +0 -0
  441. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_Hologram2.png +0 -0
  442. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_Navy.png +0 -0
  443. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_OffWhite.png +0 -0
  444. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_Purple.png +0 -0
  445. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_Red.png +0 -0
  446. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_Yellow.png +0 -0
  447. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame03_Demo_Blue.png +0 -0
  448. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame03_Demo_Gray.png +0 -0
  449. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame03_Demo_Green.png +0 -0
  450. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame03_Demo_Hologram.png +0 -0
  451. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame03_Demo_Navy.png +0 -0
  452. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame03_Demo_Purple.png +0 -0
  453. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame03_Demo_Red.png +0 -0
  454. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame03_Demo_Yellow.png +0 -0
  455. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ListFrame00_01~02_Bg.png +0 -0
  456. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ListFrame00_01~02_BgInner.png +0 -0
  457. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ListFrame00_01~02_Oblique.png +0 -0
  458. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ListFrame00_03~04_Bg.png +0 -0
  459. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ListFrame00_03~04_BgInner.png +0 -0
  460. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ListFrame00_03~04_Dim.png +0 -0
  461. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ListFrame04_Demo_f_Blue.png +0 -0
  462. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ListFrame04_Demo_f_Yellow.png +0 -0
  463. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/PanelFrame01_Line.png +0 -0
  464. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/PanelFrame02.png +0 -0
  465. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/PanelFrame03_Bg.png +0 -0
  466. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/PanelFrame03_Oblique.png +0 -0
  467. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/PanelFrame04_Bg.png +0 -0
  468. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/PanelFrame04_OutTilte1.png +0 -0
  469. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/PanelFrame04_OutTilte2.png +0 -0
  470. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ProfileFrame01_l_Bg.png +0 -0
  471. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ProfileFrame01_l_Border.png +0 -0
  472. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ProfileFrame01_m~s_Bg.png +0 -0
  473. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ProfileFrame01_m~s_Inner.png +0 -0
  474. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ProfileFrame02_Bg.png +0 -0
  475. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ProfileFrame02_Inner.png +0 -0
  476. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ProfileFrame_Circle275_Bg.png +0 -0
  477. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ProfileFrame_Circle275_Inner.png +0 -0
  478. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/SkillFrame_l~m_Bg.png +0 -0
  479. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/SkillFrame_l~m_Border.png +0 -0
  480. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/SkillFrame_l~m_Empty.png +0 -0
  481. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/SkillFrame_s_Bg.png +0 -0
  482. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/SkillFrame_s_Border.png +0 -0
  483. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/SkillFrame_s_Empty.png +0 -0
  484. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_brz.png +0 -0
  485. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_chn.png +0 -0
  486. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_cze.png +0 -0
  487. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_deu.png +0 -0
  488. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_eng.png +0 -0
  489. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_esp.png +0 -0
  490. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_fra.png +0 -0
  491. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_gbr.png +0 -0
  492. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_gre.png +0 -0
  493. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_ind.png +0 -0
  494. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_ita.png +0 -0
  495. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_jpn.png +0 -0
  496. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_kor.png +0 -0
  497. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_pol.png +0 -0
  498. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_prt.png +0 -0
  499. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_rou.png +0 -0
  500. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_rsa.png +0 -0
  501. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_rus.png +0 -0
  502. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_swe.png +0 -0
  503. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_tha.png +0 -0
  504. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_tur.png +0 -0
  505. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_twn.png +0 -0
  506. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_ukr.png +0 -0
  507. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_usa.png +0 -0
  508. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Beginner.Png +0 -0
  509. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Bronze.Png +0 -0
  510. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Challenger.Png +0 -0
  511. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Diamond.Png +0 -0
  512. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Gold.Png +0 -0
  513. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Grandmaster.Png +0 -0
  514. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Iron.Png +0 -0
  515. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Master.Png +0 -0
  516. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Platinum.Png +0 -0
  517. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Silver.Png +0 -0
  518. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Badge_Crown.Png +0 -0
  519. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Badge_Gold.png +0 -0
  520. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Bag_Brown.Png +0 -0
  521. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Bag_Gray.Png +0 -0
  522. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Battle.Png +0 -0
  523. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Book_1_Purple.Png +0 -0
  524. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Book_1_Wine.Png +0 -0
  525. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Calendar.Png +0 -0
  526. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Calendar_Check.Png +0 -0
  527. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Chat.Png +0 -0
  528. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Chest_Gem.Png +0 -0
  529. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Chest_Gold.Png +0 -0
  530. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Chest_Premium.Png +0 -0
  531. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Chest_Wood.Png +0 -0
  532. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Clover_Gold.Png +0 -0
  533. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Clover_Green.Png +0 -0
  534. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Damage.Png +0 -0
  535. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Dungeon.Png +0 -0
  536. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Earth.Png +0 -0
  537. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Energy_Blue.Png +0 -0
  538. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Friend.Png +0 -0
  539. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gear.Png +0 -0
  540. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gear_Armor_Bottom.Png +0 -0
  541. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gear_Armor_Top.Png +0 -0
  542. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gear_Boots.Png +0 -0
  543. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gear_Hat_Witch.Png +0 -0
  544. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gear_Ring.png +0 -0
  545. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gear_Sword.Png +0 -0
  546. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gem_Circle.Png +0 -0
  547. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gem_Diamond_Purple.Png +0 -0
  548. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gem_Ellipse_Red.Png +0 -0
  549. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gem_Star_Blue.Png +0 -0
  550. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gift_Blue.Png +0 -0
  551. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gift_Green.Png +0 -0
  552. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gift_Red.Png +0 -0
  553. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Heart_Dimmed.Png +0 -0
  554. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Heart_Red.Png +0 -0
  555. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Key_Gold.png +0 -0
  556. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Mail.Png +0 -0
  557. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Map.Png +0 -0
  558. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Meat.Png +0 -0
  559. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Medal_Bronze_1.png +0 -0
  560. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Medal_Bronze_2.png +0 -0
  561. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Medal_Gold_1.png +0 -0
  562. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Medal_Gold_2.png +0 -0
  563. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Medal_Silver_1.png +0 -0
  564. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Medal_Silver_2.png +0 -0
  565. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Medalstand.Png +0 -0
  566. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_MemoPad.Png +0 -0
  567. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Money_Bill.Png +0 -0
  568. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Money_Coin.Png +0 -0
  569. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Pot.Png +0 -0
  570. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Shop.Png +0 -0
  571. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Skull.png +0 -0
  572. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Star_Blue.Png +0 -0
  573. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Star_Bronze.Png +0 -0
  574. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Star_Gold.Png +0 -0
  575. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Star_Purple.Png +0 -0
  576. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Star_Red.Png +0 -0
  577. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Star_Silver.Png +0 -0
  578. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_TV_AdBlock.png +0 -0
  579. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Ticket_Gold.Png +0 -0
  580. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Ticket_Red.Png +0 -0
  581. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Trophy_Bronze.Png +0 -0
  582. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Trophy_Gold.Png +0 -0
  583. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Trophy_Silver.Png +0 -0
  584. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Video.Png +0 -0
  585. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Again_1.Png +0 -0
  586. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Again_2.Png +0 -0
  587. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Aiming_1.Png +0 -0
  588. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Aiming_2.Png +0 -0
  589. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Alarm.Png +0 -0
  590. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Anchor.Png +0 -0
  591. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Archer.Png +0 -0
  592. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Armor.Png +0 -0
  593. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Arrow_Down.Png +0 -0
  594. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Arrow_Left_1.Png +0 -0
  595. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Arrow_Left_2.Png +0 -0
  596. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Arrow_Left_3.Png +0 -0
  597. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Arrow_Right_1.Png +0 -0
  598. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Arrow_Right_2.Png +0 -0
  599. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Arrow_Right_3.Png +0 -0
  600. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Arrow_Up.Png +0 -0
  601. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_At.Png +0 -0
  602. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Attack.Png +0 -0
  603. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Ax.Png +0 -0
  604. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Ax_Double.Png +0 -0
  605. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Back_1.Png +0 -0
  606. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Back_2.Png +0 -0
  607. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Badge.Png +0 -0
  608. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bag.Png +0 -0
  609. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bank.Png +0 -0
  610. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Basket.Png +0 -0
  611. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Battery_Charge.Png +0 -0
  612. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Battle.Png +0 -0
  613. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bell.Png +0 -0
  614. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bell_Off.Png +0 -0
  615. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bell_On.Png +0 -0
  616. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bell_Sleep.Png +0 -0
  617. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Blacksmith.Png +0 -0
  618. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Block.Png +0 -0
  619. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bluetooth.Png +0 -0
  620. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bomb_1.Png +0 -0
  621. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bomb_2.Png +0 -0
  622. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Book_1.Png +0 -0
  623. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Book_2.Png +0 -0
  624. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Book_3.Png +0 -0
  625. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Boots.Png +0 -0
  626. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Boss.Png +0 -0
  627. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bow.Png +0 -0
  628. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Brief_Bag.Png +0 -0
  629. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Brush.Png +0 -0
  630. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bulb.Png +0 -0
  631. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bulb_Charge.Png +0 -0
  632. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bullet.Png +0 -0
  633. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Calendar.Png +0 -0
  634. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Camera.Png +0 -0
  635. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Camera_Off.Png +0 -0
  636. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Cap.Png +0 -0
  637. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Card_1.Png +0 -0
  638. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Card_2.Png +0 -0
  639. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Cart_1.Png +0 -0
  640. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Cart_2.Png +0 -0
  641. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Castle.Png +0 -0
  642. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Caution.Png +0 -0
  643. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Certification.Png +0 -0
  644. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Change.Png +0 -0
  645. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Chat_1.Png +0 -0
  646. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Chat_2.Png +0 -0
  647. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Check_1.Png +0 -0
  648. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Check_2.Png +0 -0
  649. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Chest.Png +0 -0
  650. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Chisel.Png +0 -0
  651. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Class_A.Png +0 -0
  652. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Class_B.Png +0 -0
  653. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Class_C.Png +0 -0
  654. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Class_D.Png +0 -0
  655. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Class_S.Png +0 -0
  656. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Class_Ss.Png +0 -0
  657. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Clock_1.Png +0 -0
  658. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Clock_2.Png +0 -0
  659. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Closet.Png +0 -0
  660. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Clothes.Png +0 -0
  661. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Coin.Png +0 -0
  662. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Coin_Star.Png +0 -0
  663. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Compass.Png +0 -0
  664. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Console_1.Png +0 -0
  665. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Console_2.Png +0 -0
  666. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Contraction.Png +0 -0
  667. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Cooking.Png +0 -0
  668. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Copy.Png +0 -0
  669. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Costume.Png +0 -0
  670. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Critical_1.Png +0 -0
  671. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Critical_2.Png +0 -0
  672. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Critical_3.Png +0 -0
  673. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Crown_1.Png +0 -0
  674. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Crown_2.Png +0 -0
  675. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Crystal.Png +0 -0
  676. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Delete.Png +0 -0
  677. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Diamond.Png +0 -0
  678. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Dice.Png +0 -0
  679. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Direction_1.Png +0 -0
  680. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Direction_2.Png +0 -0
  681. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Discount.Png +0 -0
  682. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Dollar_1.Png +0 -0
  683. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Dollar_2.Png +0 -0
  684. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Download.Png +0 -0
  685. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Earth.Png +0 -0
  686. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Earth_Pin.Png +0 -0
  687. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Effect.Png +0 -0
  688. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Energy_1.Png +0 -0
  689. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Energy_2.Png +0 -0
  690. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Exit.Png +0 -0
  691. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Exit_1.Png +0 -0
  692. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Exit_2.Png +0 -0
  693. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Exp.Png +0 -0
  694. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Expansion.Png +0 -0
  695. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Face.Png +0 -0
  696. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Faint.Png +0 -0
  697. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Female.Png +0 -0
  698. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Fire.Png +0 -0
  699. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Firework.Png +0 -0
  700. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Fish.Png +0 -0
  701. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Fishing.Png +0 -0
  702. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Flag.Png +0 -0
  703. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Float.Png +0 -0
  704. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Food.Png +0 -0
  705. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Freezee.Png +0 -0
  706. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Friends.Png +0 -0
  707. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Gallery.Png +0 -0
  708. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Game.Png +0 -0
  709. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Gear.Png +0 -0
  710. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Gift.Png +0 -0
  711. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Glasses.Png +0 -0
  712. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Globe.Png +0 -0
  713. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Graduation_Cap.Png +0 -0
  714. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Hammer.Png +0 -0
  715. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Hammer_Claw.Png +0 -0
  716. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Hand_Touch.Png +0 -0
  717. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Hanger.Png +0 -0
  718. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Hat.Png +0 -0
  719. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Headset.Png +0 -0
  720. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Heart.Png +0 -0
  721. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Heart_Add.Png +0 -0
  722. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Heart_Empty.Png +0 -0
  723. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Helmet_1.Png +0 -0
  724. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Helmet_2.Png +0 -0
  725. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Help_1.Png +0 -0
  726. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Help_2.Png +0 -0
  727. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_History.Png +0 -0
  728. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Home_1.Png +0 -0
  729. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Home_2.Png +0 -0
  730. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Hp.Png +0 -0
  731. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Icecream.Png +0 -0
  732. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Illuminati.Png +0 -0
  733. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Infinity.Png +0 -0
  734. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Info_1.Png +0 -0
  735. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Info_2.Png +0 -0
  736. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Info_3.Png +0 -0
  737. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Info_4.Png +0 -0
  738. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Key.Png +0 -0
  739. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Kitchen_Knife.Png +0 -0
  740. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Layer_1.Png +0 -0
  741. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Layer_2.Png +0 -0
  742. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Leaf.Png +0 -0
  743. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Link.Png +0 -0
  744. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Lock_1.Png +0 -0
  745. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Lock_2.Png +0 -0
  746. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Lock_Open.Png +0 -0
  747. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Magic.Png +0 -0
  748. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Magic_Ball.Png +0 -0
  749. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Mail_1.Png +0 -0
  750. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Mail_2.Png +0 -0
  751. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Male.Png +0 -0
  752. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Map_1.Png +0 -0
  753. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Map_2.Png +0 -0
  754. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Map_Pin.Png +0 -0
  755. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Meal.Png +0 -0
  756. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Medal_1.Png +0 -0
  757. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Medal_2.Png +0 -0
  758. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Megaphone.Png +0 -0
  759. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Menu_1.Png +0 -0
  760. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Menu_2.Png +0 -0
  761. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Menu_3.Png +0 -0
  762. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Menu_4.Png +0 -0
  763. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Menu_5.Png +0 -0
  764. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Menu_6.Png +0 -0
  765. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Merge.Png +0 -0
  766. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Message_Bottle.Png +0 -0
  767. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Minus_1.Png +0 -0
  768. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Minus_2.Png +0 -0
  769. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Mission.Png +0 -0
  770. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Money_1.Png +0 -0
  771. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Money_2.Png +0 -0
  772. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Money_Pouch.Png +0 -0
  773. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Movie.Png +0 -0
  774. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Mushroom.Png +0 -0
  775. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Music_1.Png +0 -0
  776. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Music_1_Off.Png +0 -0
  777. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Music_2.Png +0 -0
  778. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Music_2_Off.Png +0 -0
  779. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Necklace.Png +0 -0
  780. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Night.Png +0 -0
  781. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Note.Png +0 -0
  782. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Object.Png +0 -0
  783. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Page_Next.Png +0 -0
  784. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Page_Prev.Png +0 -0
  785. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Paper_1.Png +0 -0
  786. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Paper_2.Png +0 -0
  787. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Path.Png +0 -0
  788. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Pause_1.Png +0 -0
  789. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Pause_2.Png +0 -0
  790. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Paw.Png +0 -0
  791. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Pen.Png +0 -0
  792. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Pen_Feather.Png +0 -0
  793. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Pencil.Png +0 -0
  794. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Phone.Png +0 -0
  795. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Photo_1.Png +0 -0
  796. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Photo_2.Png +0 -0
  797. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Pick.Png +0 -0
  798. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Pickax.Png +0 -0
  799. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Plants.Png +0 -0
  800. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Play_1.Png +0 -0
  801. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Play_2.Png +0 -0
  802. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Plus_1.Png +0 -0
  803. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Plus_2.Png +0 -0
  804. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Potion_1.Png +0 -0
  805. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Potion_2.Png +0 -0
  806. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Potion_3.Png +0 -0
  807. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Pouch.Png +0 -0
  808. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Power_1.Png +0 -0
  809. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Power_2.Png +0 -0
  810. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Power_Off.Png +0 -0
  811. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Rampart.Png +0 -0
  812. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Rank_1.Png +0 -0
  813. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Rank_2.Png +0 -0
  814. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Recommendation.Png +0 -0
  815. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Recycle.Png +0 -0
  816. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Refresh_1.Png +0 -0
  817. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Refresh_2.Png +0 -0
  818. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Refresh_3.Png +0 -0
  819. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Refresh_4.Png +0 -0
  820. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Ring.Png +0 -0
  821. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Roulette.Png +0 -0
  822. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Safebox.Png +0 -0
  823. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sandglass.Png +0 -0
  824. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Saw.Png +0 -0
  825. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Scale.Png +0 -0
  826. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Scroll_Old.Png +0 -0
  827. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Search.Png +0 -0
  828. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Security.Png +0 -0
  829. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Setting.Png +0 -0
  830. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Share.Png +0 -0
  831. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sheos.Png +0 -0
  832. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sheos_Wing.Png +0 -0
  833. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sheriff.Png +0 -0
  834. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Shield_1.Png +0 -0
  835. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Shield_2.Png +0 -0
  836. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Shield_Viking.Png +0 -0
  837. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Ship.Png +0 -0
  838. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Shop_1.Png +0 -0
  839. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Shop_2.Png +0 -0
  840. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Shop_3.Png +0 -0
  841. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Shovel.Png +0 -0
  842. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sickle.Png +0 -0
  843. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sign.Png +0 -0
  844. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Skull.Png +0 -0
  845. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sound.Png +0 -0
  846. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sound_Off.Png +0 -0
  847. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Star_1.Png +0 -0
  848. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Star_2.Png +0 -0
  849. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Star_3.Png +0 -0
  850. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Star_Empty.Png +0 -0
  851. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Step.Png +0 -0
  852. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Stopwatch_1.Png +0 -0
  853. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Stopwatch_2.Png +0 -0
  854. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Storage.Png +0 -0
  855. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sun.Png +0 -0
  856. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Switch.Png +0 -0
  857. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sword_1.Png +0 -0
  858. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sword_2.Png +0 -0
  859. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Tag.Png +0 -0
  860. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Target.Png +0 -0
  861. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Telescope.Png +0 -0
  862. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Temple.Png +0 -0
  863. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Ticket.Png +0 -0
  864. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Tool_Fix.Png +0 -0
  865. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Top.Png +0 -0
  866. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Trophy_1.Png +0 -0
  867. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Trophy_2.Png +0 -0
  868. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Tv.Png +0 -0
  869. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Typhoon.Png +0 -0
  870. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Under.Png +0 -0
  871. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_User.Png +0 -0
  872. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_User_Add.Png +0 -0
  873. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_User_Info.Png +0 -0
  874. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Video.Png +0 -0
  875. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_View.Png +0 -0
  876. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_View_Off.Png +0 -0
  877. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Vr.Png +0 -0
  878. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Warehouse.Png +0 -0
  879. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Water.Png +0 -0
  880. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Wing.Png +0 -0
  881. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Wood.Png +0 -0
  882. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_World.Png +0 -0
  883. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Zoom_In.Png +0 -0
  884. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Zoom_Out.Png +0 -0
  885. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_TutorialHand/256/tutorial_hand_1.png +0 -0
  886. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_TutorialHand/256/tutorial_hand_2.png +0 -0
  887. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_TutorialHand/256/tutorial_hand_3.png +0 -0
  888. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_TutorialHand/256/tutorial_hand_4.png +0 -0
  889. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_TutorialHand/256/tutorial_hand_5.png +0 -0
  890. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_TutorialHand/256/tutorial_hand_6.png +0 -0
  891. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Badge01_Green.png +0 -0
  892. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Badge01_Purple.png +0 -0
  893. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Badge01_Red.png +0 -0
  894. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Badge01_Yellow.png +0 -0
  895. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Badge02.png +0 -0
  896. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Bubble_Arrow.png +0 -0
  897. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Bubble_Bg.png +0 -0
  898. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Parallelogram_Blue.png +0 -0
  899. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Parallelogram_Gray.png +0 -0
  900. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Parallelogram_Green.png +0 -0
  901. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Parallelogram_Hologram.png +0 -0
  902. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Parallelogram_Purple.png +0 -0
  903. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Parallelogram_Red.png +0 -0
  904. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Parallelogram_White_Bg.png +0 -0
  905. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Parallelogram_White_Inner.png +0 -0
  906. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Parallelogram_Yellow.png +0 -0
  907. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Ribbon_Hologram.png +0 -0
  908. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Ribbon_White.png +0 -0
  909. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Tail_Demo_Red.png +0 -0
  910. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Tail_White_Bg.png +0 -0
  911. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Tail_White_Border.png +0 -0
  912. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_LIne04_Under.png +0 -0
  913. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Line01_Divider_Left.png +0 -0
  914. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Line01_Divider_Right.png +0 -0
  915. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Line02_Divider_Left.png +0 -0
  916. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Line02_Divider_Right.png +0 -0
  917. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Line03_Divider.png +0 -0
  918. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Oval.png +0 -0
  919. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Blue.png +0 -0
  920. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Gray.png +0 -0
  921. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Green.png +0 -0
  922. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Magenta.png +0 -0
  923. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Navy.png +0 -0
  924. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Orange.png +0 -0
  925. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Peacock.png +0 -0
  926. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Plum.png +0 -0
  927. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Purple.png +0 -0
  928. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Red.png +0 -0
  929. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Sky.png +0 -0
  930. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Yellow.png +0 -0
  931. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon02_Red.png +0 -0
  932. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon02_White1.png +0 -0
  933. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon02_White2.png +0 -0
  934. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon03_Red.png +0 -0
  935. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon03_White1.png +0 -0
  936. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon03_White2.png +0 -0
  937. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon04_Red.png +0 -0
  938. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon05.png +0 -0
  939. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Tapered01.png +0 -0
  940. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Tapered02.png +0 -0
  941. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Tapered03.png +0 -0
  942. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/PACK.md +6 -0
  943. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup01_Basic_Demo.png +0 -0
  944. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup01_Basic_White_Bg.png +0 -0
  945. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup01_Basic_White_Light.png +0 -0
  946. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup02~09_Topber_Demo_Bg.png +0 -0
  947. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup02~09_Topber_White_Bg.png +0 -0
  948. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup02~09_Topber_White_BgTop.png +0 -0
  949. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup02~09_Topber_White_BgTopLight.png +0 -0
  950. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup03_Gradient.png +0 -0
  951. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup06_Glow_Bottom.png +0 -0
  952. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup06_Pattern.psd +0 -0
  953. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup09_Topber_White_Label_Bg.png +0 -0
  954. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup09_Topber_White_Label_Inner.png +0 -0
  955. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_Chat_Bg.png +0 -0
  956. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_Chat_BgLight.png +0 -0
  957. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_Chat_TabFocus.png +0 -0
  958. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_FullWidth_Dark.png +0 -0
  959. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_FullWidth_White.png +0 -0
  960. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_List_VerticalLayout.png +0 -0
  961. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_OutTitle_Bg.png +0 -0
  962. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_OutTitle_Bg_Title.png +0 -0
  963. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_OutTitle_Inner_Bottom.png +0 -0
  964. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_OutTitle_Inner_Top.png +0 -0
  965. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_Ticket_Bg.png +0 -0
  966. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_Ticket_Border.png +0 -0
  967. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_Ticket_BottomPattern.png +0 -0
  968. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_Ticket_Gradient.png +0 -0
  969. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic01_Bg_Demo.png +0 -0
  970. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic01_Bg_White1.png +0 -0
  971. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic01_Bg_White2.png +0 -0
  972. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic01_FillMask.png +0 -0
  973. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic01_Fill_Blue.png +0 -0
  974. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic01_Fill_Green.png +0 -0
  975. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic01_Fill_White.png +0 -0
  976. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic01_Fill_Yellow.png +0 -0
  977. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic02_Bg.png +0 -0
  978. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic02_FillMask.png +0 -0
  979. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic02_Fill_Blue.png +0 -0
  980. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic02_Fill_Green.png +0 -0
  981. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic02_Fill_White.png +0 -0
  982. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic02_Fill_Yellow.png +0 -0
  983. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic03_Bg_Demo.png +0 -0
  984. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic03_Bg_White1.png +0 -0
  985. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic03_Bg_White2.png +0 -0
  986. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic03_FillMask.png +0 -0
  987. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic03_Fill_Blue.png +0 -0
  988. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic03_Fill_Green.png +0 -0
  989. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic03_Fill_White.png +0 -0
  990. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic03_Fill_Yellow.png +0 -0
  991. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic04_Bg.png +0 -0
  992. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic04_Fill_Blue.png +0 -0
  993. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic04_Fill_Orange.png +0 -0
  994. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic04_White_Fill1.png +0 -0
  995. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic04_White_Fill2.png +0 -0
  996. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Handle_Bg.png +0 -0
  997. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Handle_FillMask.png +0 -0
  998. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Handle_Fill_Pink.png +0 -0
  999. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Handle_Fill_White1.png +0 -0
  1000. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Handle_Fill_White2.png +0 -0
  1001. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Handle_Handle.png +0 -0
  1002. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon01_Bg.png +0 -0
  1003. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon01_FillMask.png +0 -0
  1004. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon01_Fill_Orange.png +0 -0
  1005. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon01_Fill_White.png +0 -0
  1006. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon01_Icon1.png +0 -0
  1007. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon01_Icon2.png +0 -0
  1008. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon02_Badge1.png +0 -0
  1009. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon02_Badge2.png +0 -0
  1010. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon02_Bg.png +0 -0
  1011. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon02_FillMask.png +0 -0
  1012. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon02_Fill_Orange.png +0 -0
  1013. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon02_Fill_White.png +0 -0
  1014. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon02_Icon1.png +0 -0
  1015. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level01_Badge_l.png +0 -0
  1016. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level01_Badge_s.png +0 -0
  1017. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level01_Bg.png +0 -0
  1018. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level01_Fill.png +0 -0
  1019. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level01_FillMask.png +0 -0
  1020. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Bg_Demo.png +0 -0
  1021. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Bg_White1.png +0 -0
  1022. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Bg_White2.png +0 -0
  1023. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Fill01_Blue.png +0 -0
  1024. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Fill01_White.png +0 -0
  1025. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Fill01_Yellow.png +0 -0
  1026. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Fill02_Blue.png +0 -0
  1027. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Fill02_White.png +0 -0
  1028. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Fill02_Yellow.png +0 -0
  1029. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Icon_Badge_Blue.png +0 -0
  1030. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Icon_Badge_Yellow.png +0 -0
  1031. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Icon_Up_Green.png +0 -0
  1032. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Icon_Up_White.png +0 -0
  1033. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level03_Badge1.png +0 -0
  1034. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level03_Badge2.png +0 -0
  1035. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level03_Bg.png +0 -0
  1036. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level03_Fill1.png +0 -0
  1037. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level03_Fill2.png +0 -0
  1038. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Panel_Bg.png +0 -0
  1039. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Panel_Fill1.png +0 -0
  1040. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Panel_Fill2.png +0 -0
  1041. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Play01_Bg.png +0 -0
  1042. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Play01_Fill.png +0 -0
  1043. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Play01_FillMask.png +0 -0
  1044. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Play02_Bg.png +0 -0
  1045. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Play02_FillMask.png +0 -0
  1046. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Bg.png +0 -0
  1047. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Icon_l_Blue.png +0 -0
  1048. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Icon_l_Gray.png +0 -0
  1049. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Icon_l_White1.png +0 -0
  1050. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Icon_l_White2.png +0 -0
  1051. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Icon_l_Yellow.png +0 -0
  1052. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Icon_s_Blue.png +0 -0
  1053. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Icon_s_White1.png +0 -0
  1054. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Icon_s_White2.png +0 -0
  1055. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Icon_s_Yellow.png +0 -0
  1056. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageVertical_Bg.png +0 -0
  1057. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageVertical_Icon1.png +0 -0
  1058. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageVertical_Icon2.png +0 -0
  1059. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Wave_Badge1.png +0 -0
  1060. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Wave_Badge2.png +0 -0
  1061. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Wave_Bg.png +0 -0
  1062. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Wave_Fill.png +0 -0
  1063. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/_Slider_Basic_R6_Fill_Orange.png +0 -0
  1064. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/_Slider_Round6_01_White_Bg.png +0 -0
  1065. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/_Slider_Round6_01_White_Fill.png +0 -0
  1066. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Alert_Circle_Icon_Exclamation.png +0 -0
  1067. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Alert_Circle_l_Bg.png +0 -0
  1068. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Alert_Circle_l_Border.png +0 -0
  1069. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Alert_Circle_s_Bg.png +0 -0
  1070. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Alert_Circle_s_Border.png +0 -0
  1071. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Alert_Dot_Bg.png +0 -0
  1072. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Alert_Dot_Border.png +0 -0
  1073. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Alert_Dot_Light.png +0 -0
  1074. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField01_Bg_Demo.png +0 -0
  1075. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField01_Bg_White1.png +0 -0
  1076. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField01_Bg_White2.png +0 -0
  1077. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField01_Bg_White3.png +0 -0
  1078. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField01_Icon_Lock.png +0 -0
  1079. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField01_Icon_Mail.png +0 -0
  1080. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField02_Demo.png +0 -0
  1081. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField02_White1.png +0 -0
  1082. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField02_White2.png +0 -0
  1083. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField03.png +0 -0
  1084. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField04.png +0 -0
  1085. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Bg.png +0 -0
  1086. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Btn_Blue1.png +0 -0
  1087. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Btn_Blue2.png +0 -0
  1088. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Btn_Purple1.png +0 -0
  1089. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Btn_Purple2.png +0 -0
  1090. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Btn_Yellow1.png +0 -0
  1091. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Btn_Yellow2.png +0 -0
  1092. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Icon_Coin.png +0 -0
  1093. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Icon_Energy.png +0 -0
  1094. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Icon_Gem.png +0 -0
  1095. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Icon_Monster.png +0 -0
  1096. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_White_Bg.png +0 -0
  1097. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_White_Btn1.png +0 -0
  1098. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_White_Btn2.png +0 -0
  1099. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_White_Btn3.png +0 -0
  1100. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_White_Icon1.png +0 -0
  1101. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_White_Icon2.png +0 -0
  1102. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Switch_Demo_Bg.png +0 -0
  1103. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Switch_Demo_Fill.png +0 -0
  1104. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Switch_Demo_Handle.png +0 -0
  1105. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Switch_White_Bg.png +0 -0
  1106. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Switch_White_BgInner.png +0 -0
  1107. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Switch_White_Fill1.png +0 -0
  1108. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Switch_White_Fill2.png +0 -0
  1109. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Switch_White_Handle.png +0 -0
  1110. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ToastMessage_Bg_Gray.png +0 -0
  1111. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ToastMessage_Bg_Green.png +0 -0
  1112. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ToastMessage_Bg_Red.png +0 -0
  1113. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ToastMessage_Bg_White.png +0 -0
  1114. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ToastMessage_Bg_Yellow.png +0 -0
  1115. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ToastMessage_Gradient.png +0 -0
  1116. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ToastMessage_Light1.png +0 -0
  1117. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ToastMessage_Light2.png +0 -0
  1118. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Toggle_Check_Demo_Bg.png +0 -0
  1119. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Toggle_Check_Demo_Icon.png +0 -0
  1120. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Toggle_Check_White_Bg.png +0 -0
  1121. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Toggle_Check_White_BgLight.png +0 -0
  1122. package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Toggle_Check_White_Icon.png +0 -0
  1123. package/plugins/phaser-casual-game-factory/examples/README.md +44 -0
  1124. package/plugins/phaser-casual-game-factory/examples/economy-demo-config.ts +255 -0
  1125. package/plugins/phaser-casual-game-factory/examples/economy-demo.ts +89 -0
  1126. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/index.html +342 -0
  1127. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/package-lock.json +1293 -0
  1128. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/package.json +21 -0
  1129. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/playwright.config.ts +26 -0
  1130. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/assets/sfx/ui_click.mp3 +0 -0
  1131. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/assets/sfx/ui_close.mp3 +0 -0
  1132. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/assets/ui/BG_lobby.png +0 -0
  1133. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/assets/ui/Bar_Bg.png +0 -0
  1134. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/assets/ui/progress_inner.png +0 -0
  1135. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/assets/ui/progress_outer.png +0 -0
  1136. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-400-latin-OEyTajQY.woff2 +0 -0
  1137. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-400-viet-SOx6iaFb.woff2 +0 -0
  1138. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-600-latin-xAC4kEK0.woff2 +0 -0
  1139. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-600-viet-DbGrrtCq.woff2 +0 -0
  1140. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-700-latin-CPfR8Jz_.woff2 +0 -0
  1141. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-700-viet-DptIoWwl.woff2 +0 -0
  1142. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-800-latin-B5VTH9An.woff2 +0 -0
  1143. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-800-viet-BEUwTqXl.woff2 +0 -0
  1144. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-900-latin-B6esVQUu.woff2 +0 -0
  1145. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-900-viet-DUJ3fpCl.woff2 +0 -0
  1146. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/logo-frog.png +0 -0
  1147. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/brand/BootLoadingScreen.js +7 -0
  1148. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/brand/SplashFullscreenBg.js +4 -0
  1149. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/brand-shims.d.ts +33 -0
  1150. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/demo-scenes.ts +12 -0
  1151. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/demo-tools.ts +34 -0
  1152. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/main.ts +1358 -0
  1153. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/scenes/BootScene.ts +236 -0
  1154. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/scenes/GameScene.ts +152 -0
  1155. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/scenes/HomeScene.ts +21 -0
  1156. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/scenes/scene-hooks.ts +12 -0
  1157. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/styles.css +623 -0
  1158. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/ui-audio.ts +156 -0
  1159. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/tests/browser-smoke.spec.ts +170 -0
  1160. package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/vite.config.ts +23 -0
  1161. package/plugins/phaser-casual-game-factory/examples/leveling-demo-config.ts +107 -0
  1162. package/plugins/phaser-casual-game-factory/references/condition-service.md +38 -0
  1163. package/plugins/phaser-casual-game-factory/references/core-contracts.md +39 -0
  1164. package/plugins/phaser-casual-game-factory/references/daily-login-service.md +32 -0
  1165. package/plugins/phaser-casual-game-factory/references/economy-service.md +192 -0
  1166. package/plugins/phaser-casual-game-factory/references/leveling-service.md +56 -0
  1167. package/plugins/phaser-casual-game-factory/references/loading-view.md +181 -0
  1168. package/plugins/phaser-casual-game-factory/references/time-service.md +42 -0
  1169. package/plugins/phaser-casual-game-factory/scripts/new-phaser-casual-game.ps1 +152 -0
  1170. package/plugins/phaser-casual-game-factory/scripts/run-browser-demo.ps1 +13 -0
  1171. package/plugins/phaser-casual-game-factory/scripts/run-economy-demo.ps1 +4 -0
  1172. package/plugins/phaser-casual-game-factory/scripts/test-all.ps1 +11 -0
  1173. package/plugins/phaser-casual-game-factory/scripts/test-browser.ps1 +10 -0
  1174. package/plugins/phaser-casual-game-factory/scripts/test-economy.ps1 +4 -0
  1175. package/plugins/phaser-casual-game-factory/skills/game-art/SKILL.md +846 -0
  1176. package/plugins/phaser-casual-game-factory/skills/game-art/client/.env.example +19 -0
  1177. package/plugins/phaser-casual-game-factory/skills/game-art/client/bgremove.py +127 -0
  1178. package/plugins/phaser-casual-game-factory/skills/game-art/client/codex_extract.py +123 -0
  1179. package/plugins/phaser-casual-game-factory/skills/game-art/client/codex_gen.sh +172 -0
  1180. package/plugins/phaser-casual-game-factory/skills/game-art/client/envfile.py +121 -0
  1181. package/plugins/phaser-casual-game-factory/skills/game-art/client/gemini_image_mcp.py +1870 -0
  1182. package/plugins/phaser-casual-game-factory/skills/game-art/client/imglib.py +2138 -0
  1183. package/plugins/phaser-casual-game-factory/skills/game-art/client/remote_backend.py +498 -0
  1184. package/plugins/phaser-casual-game-factory/skills/game-art/client/remote_codex.py +59 -0
  1185. package/plugins/phaser-casual-game-factory/skills/game-art/client/remote_proto.py +135 -0
  1186. package/plugins/phaser-casual-game-factory/skills/game-art/client/requirements-client.txt +22 -0
  1187. package/plugins/phaser-casual-game-factory/skills/game-art/client/test_imglib.py +1647 -0
  1188. package/plugins/phaser-casual-game-factory/skills/game-art/client/test_restyle_tools.py +256 -0
  1189. package/plugins/phaser-casual-game-factory/skills/game-art/client/tools/restyle/styles/unscrew-casual.refs/ref-lose.jpg +0 -0
  1190. package/plugins/phaser-casual-game-factory/skills/game-art/client/tools/restyle/styles/unscrew-casual.refs/ref-welcome.jpg +0 -0
  1191. package/plugins/phaser-casual-game-factory/skills/game-art/client/tools/restyle/styles/unscrew-casual.refs/ref-win.jpg +0 -0
  1192. package/plugins/phaser-casual-game-factory/skills/game-art/client/upscale.py +289 -0
  1193. package/plugins/phaser-casual-game-factory/skills/game-art/reference/client-guide.md +180 -0
  1194. package/plugins/phaser-casual-game-factory/skills/game-art/reference/mcp-image-input.md +148 -0
  1195. package/plugins/phaser-casual-game-factory/skills/game-art/reference/prompt-template.md +216 -0
  1196. package/plugins/phaser-casual-game-factory/skills/game-art/reference/remote-lan.md +224 -0
  1197. package/plugins/phaser-casual-game-factory/skills/pcgf-git-merge-request/SKILL.md +96 -0
  1198. package/plugins/phaser-casual-game-factory/skills/pcgf-ui-reskin/SKILL.md +144 -0
  1199. package/plugins/phaser-casual-game-factory/skills/phaser-adaptive-loading/SKILL.md +33 -0
  1200. package/plugins/phaser-casual-game-factory/skills/phaser-casual-game-factory/SKILL.md +225 -0
  1201. package/plugins/phaser-casual-game-factory/skills/phaser-condition-service/SKILL.md +21 -0
  1202. package/plugins/phaser-casual-game-factory/skills/phaser-daily-login-service/SKILL.md +20 -0
  1203. package/plugins/phaser-casual-game-factory/skills/phaser-economy-service/SKILL.md +72 -0
  1204. package/plugins/phaser-casual-game-factory/skills/phaser-foundation/SKILL.md +60 -0
  1205. package/plugins/phaser-casual-game-factory/skills/phaser-leveling-service/SKILL.md +39 -0
  1206. package/plugins/phaser-casual-game-factory/skills/phaser-loading-view/SKILL.md +167 -0
  1207. package/plugins/phaser-casual-game-factory/skills/phaser-studio25-boot-brand/SKILL.md +107 -0
  1208. package/plugins/phaser-casual-game-factory/skills/phaser-time-service/SKILL.md +26 -0
  1209. package/plugins/phaser-casual-game-factory/skills/phaser-ui-motion/SKILL.md +161 -0
  1210. package/plugins/phaser-casual-game-factory/skills/phaser-ui-motion/fix-off-canvas-press.md +198 -0
  1211. package/plugins/phaser-casual-game-factory/skills/phaser-ui-sfx/SKILL.md +83 -0
  1212. package/plugins/phaser-casual-game-factory/skills/theme-cream-casual/SKILL.md +136 -0
  1213. package/plugins/phaser-casual-game-factory/skills/theme-dark-casual/SKILL.md +23 -0
  1214. package/plugins/phaser-casual-game-factory/skills/tool-demo-qa/SKILL.md +264 -0
  1215. package/plugins/phaser-casual-game-factory/templates/adaptive-loading/adaptive-loading-manager.ts +103 -0
  1216. package/plugins/phaser-casual-game-factory/templates/adaptive-loading/device-profile.ts +76 -0
  1217. package/plugins/phaser-casual-game-factory/templates/adaptive-loading/device-tier-session.ts +133 -0
  1218. package/plugins/phaser-casual-game-factory/templates/adaptive-loading/index.ts +4 -0
  1219. package/plugins/phaser-casual-game-factory/templates/adaptive-loading/types.ts +27 -0
  1220. package/plugins/phaser-casual-game-factory/templates/boot/brand/BootLoadingScreen.js +370 -0
  1221. package/plugins/phaser-casual-game-factory/templates/boot/brand/SplashFullscreenBg.js +18 -0
  1222. package/plugins/phaser-casual-game-factory/templates/boot/brand/brand-defaults.js +36 -0
  1223. package/plugins/phaser-casual-game-factory/templates/boot/brand-shims.d.ts +40 -0
  1224. package/plugins/phaser-casual-game-factory/templates/boot/close-styles.ts +26 -0
  1225. package/plugins/phaser-casual-game-factory/templates/boot/index.ts +32 -0
  1226. package/plugins/phaser-casual-game-factory/templates/boot/iris-close.ts +85 -0
  1227. package/plugins/phaser-casual-game-factory/templates/boot/map-dom-rect-to-game.ts +53 -0
  1228. package/plugins/phaser-casual-game-factory/templates/boot/play-boot-loading-view.ts +124 -0
  1229. package/plugins/phaser-casual-game-factory/templates/commerce/commerce-service.ts +22 -0
  1230. package/plugins/phaser-casual-game-factory/templates/commerce/index.ts +1 -0
  1231. package/plugins/phaser-casual-game-factory/templates/commerce/types.ts +6 -0
  1232. package/plugins/phaser-casual-game-factory/templates/condition/condition-service.ts +166 -0
  1233. package/plugins/phaser-casual-game-factory/templates/condition/index.ts +2 -0
  1234. package/plugins/phaser-casual-game-factory/templates/condition/types.ts +69 -0
  1235. package/plugins/phaser-casual-game-factory/templates/core/events.ts +71 -0
  1236. package/plugins/phaser-casual-game-factory/templates/core/gameplay.ts +15 -0
  1237. package/plugins/phaser-casual-game-factory/templates/core/index.ts +9 -0
  1238. package/plugins/phaser-casual-game-factory/templates/core/layout.ts +25 -0
  1239. package/plugins/phaser-casual-game-factory/templates/core/loading.ts +33 -0
  1240. package/plugins/phaser-casual-game-factory/templates/core/service-registry.ts +28 -0
  1241. package/plugins/phaser-casual-game-factory/templates/core/services.ts +19 -0
  1242. package/plugins/phaser-casual-game-factory/templates/core/storage.ts +7 -0
  1243. package/plugins/phaser-casual-game-factory/templates/core/time.ts +70 -0
  1244. package/plugins/phaser-casual-game-factory/templates/core/types.ts +21 -0
  1245. package/plugins/phaser-casual-game-factory/templates/daily-login/daily-login-service.ts +136 -0
  1246. package/plugins/phaser-casual-game-factory/templates/daily-login/index.ts +3 -0
  1247. package/plugins/phaser-casual-game-factory/templates/daily-login/reward-service.ts +108 -0
  1248. package/plugins/phaser-casual-game-factory/templates/daily-login/types.ts +39 -0
  1249. package/plugins/phaser-casual-game-factory/templates/demo-tools/demo-device-tier.ts +73 -0
  1250. package/plugins/phaser-casual-game-factory/templates/demo-tools/demo-perf.ts +232 -0
  1251. package/plugins/phaser-casual-game-factory/templates/demo-tools/demo-tools.css +355 -0
  1252. package/plugins/phaser-casual-game-factory/templates/demo-tools/demo-tools.ts +305 -0
  1253. package/plugins/phaser-casual-game-factory/templates/demo-tools/index.ts +7 -0
  1254. package/plugins/phaser-casual-game-factory/templates/demo-tools/init-demo-qa-tools.ts +101 -0
  1255. package/plugins/phaser-casual-game-factory/templates/demo-tools/tool-param-fields.ts +214 -0
  1256. package/plugins/phaser-casual-game-factory/templates/demo-tools/tool-sections.ts +238 -0
  1257. package/plugins/phaser-casual-game-factory/templates/demo-tools/tool-shell.html +57 -0
  1258. package/plugins/phaser-casual-game-factory/templates/demo-tools/tool-shell.ts +141 -0
  1259. package/plugins/phaser-casual-game-factory/templates/economy/default-registry.ts +14 -0
  1260. package/plugins/phaser-casual-game-factory/templates/economy/economy-service.ts +65 -0
  1261. package/plugins/phaser-casual-game-factory/templates/economy/exchange-handlers.ts +58 -0
  1262. package/plugins/phaser-casual-game-factory/templates/economy/grant-handler.ts +58 -0
  1263. package/plugins/phaser-casual-game-factory/templates/economy/index.ts +15 -0
  1264. package/plugins/phaser-casual-game-factory/templates/economy/inventory-service.ts +170 -0
  1265. package/plugins/phaser-casual-game-factory/templates/economy/item-service.ts +220 -0
  1266. package/plugins/phaser-casual-game-factory/templates/economy/item-utils.ts +126 -0
  1267. package/plugins/phaser-casual-game-factory/templates/economy/merge-handler.ts +42 -0
  1268. package/plugins/phaser-casual-game-factory/templates/economy/operation-handler.ts +44 -0
  1269. package/plugins/phaser-casual-game-factory/templates/economy/package-handler.ts +41 -0
  1270. package/plugins/phaser-casual-game-factory/templates/economy/random.ts +33 -0
  1271. package/plugins/phaser-casual-game-factory/templates/economy/repository.ts +64 -0
  1272. package/plugins/phaser-casual-game-factory/templates/economy/state-utils.ts +221 -0
  1273. package/plugins/phaser-casual-game-factory/templates/economy/types.ts +309 -0
  1274. package/plugins/phaser-casual-game-factory/templates/economy/ui-view-models.ts +79 -0
  1275. package/plugins/phaser-casual-game-factory/templates/entitlement/entitlement-service.ts +29 -0
  1276. package/plugins/phaser-casual-game-factory/templates/entitlement/index.ts +1 -0
  1277. package/plugins/phaser-casual-game-factory/templates/entitlement/types.ts +26 -0
  1278. package/plugins/phaser-casual-game-factory/templates/leveling/condition-evaluator.ts +17 -0
  1279. package/plugins/phaser-casual-game-factory/templates/leveling/config-validator.ts +63 -0
  1280. package/plugins/phaser-casual-game-factory/templates/leveling/index.ts +5 -0
  1281. package/plugins/phaser-casual-game-factory/templates/leveling/leveling-service.ts +306 -0
  1282. package/plugins/phaser-casual-game-factory/templates/leveling/types.ts +80 -0
  1283. package/plugins/phaser-casual-game-factory/templates/leveling/view-model.ts +52 -0
  1284. package/plugins/phaser-casual-game-factory/templates/loading-view/index.ts +4 -0
  1285. package/plugins/phaser-casual-game-factory/templates/loading-view/loading-view-model.ts +203 -0
  1286. package/plugins/phaser-casual-game-factory/templates/loading-view/presets.ts +26 -0
  1287. package/plugins/phaser-casual-game-factory/templates/loading-view/progress.ts +30 -0
  1288. package/plugins/phaser-casual-game-factory/templates/loading-view/types.ts +49 -0
  1289. package/plugins/phaser-casual-game-factory/templates/motion/index.ts +2 -0
  1290. package/plugins/phaser-casual-game-factory/templates/motion/phaser-ui-motion.ts +363 -0
  1291. package/plugins/phaser-casual-game-factory/templates/motion/types.ts +21 -0
  1292. package/plugins/phaser-casual-game-factory/templates/phaser/browser-storage-adapter.ts +91 -0
  1293. package/plugins/phaser-casual-game-factory/templates/phaser/design-size.ts +34 -0
  1294. package/plugins/phaser-casual-game-factory/templates/phaser/foundation-scene.ts +39 -0
  1295. package/plugins/phaser-casual-game-factory/templates/phaser/hybrid-loading-layer.css +46 -0
  1296. package/plugins/phaser-casual-game-factory/templates/phaser/loading-overlay-scene.ts +653 -0
  1297. package/plugins/phaser-casual-game-factory/templates/phaser/phaser-event-bus.ts +35 -0
  1298. package/plugins/phaser-casual-game-factory/templates/phaser/scene-keys.ts +12 -0
  1299. package/plugins/phaser-casual-game-factory/templates/phaser/scene-registration.ts +28 -0
  1300. package/plugins/phaser-casual-game-factory/templates/phaser/system-time-adapter.ts +33 -0
  1301. package/plugins/phaser-casual-game-factory/templates/time/index.ts +2 -0
  1302. package/plugins/phaser-casual-game-factory/templates/time/time-service.ts +184 -0
  1303. package/plugins/phaser-casual-game-factory/templates/ui/audio-settings.ts +148 -0
  1304. package/plugins/phaser-casual-game-factory/templates/ui/bind-factory-dom-press.ts +108 -0
  1305. package/plugins/phaser-casual-game-factory/templates/ui/factory-cream-casual.css +380 -0
  1306. package/plugins/phaser-casual-game-factory/templates/ui/factory-dark-casual.css +11 -0
  1307. package/plugins/phaser-casual-game-factory/templates/ui/index.ts +5 -0
  1308. package/plugins/phaser-casual-game-factory/templates/ui/settings-popup-dom.ts +349 -0
  1309. package/plugins/phaser-casual-game-factory/templates/ui/settings-popup-phaser.ts +284 -0
  1310. package/plugins/phaser-casual-game-factory/templates/ui/ui-sfx.ts +131 -0
  1311. package/plugins/phaser-casual-game-factory/templates/ui-reskin/compare.html +235 -0
  1312. package/plugins/phaser-casual-game-factory/tests/README.md +29 -0
  1313. package/plugins/phaser-casual-game-factory/tests/condition.test.ts +92 -0
  1314. package/plugins/phaser-casual-game-factory/tests/daily-login-reward.test.ts +45 -0
  1315. package/plugins/phaser-casual-game-factory/tests/daily-login.test.ts +73 -0
  1316. package/plugins/phaser-casual-game-factory/tests/economy.test.ts +258 -0
  1317. package/plugins/phaser-casual-game-factory/tests/entitlement.test.ts +18 -0
  1318. package/plugins/phaser-casual-game-factory/tests/leveling.test.ts +158 -0
  1319. package/plugins/phaser-casual-game-factory/tests/loading-view.test.ts +39 -0
  1320. package/plugins/phaser-casual-game-factory/tests/time.test.ts +60 -0
@@ -0,0 +1,2138 @@
1
+ """Hàm xử lý ảnh thuần cho skill restyle-asset.
2
+
3
+ Không CLI, không mạng, không biết layout thư mục — chỉ nhận/trả PIL Image.
4
+ Nhờ vậy test được offline. Mọi phép toán pixel dùng numpy (Pillow 12 đã bỏ ImageMath.eval).
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import base64
9
+ import html as _html
10
+ import io
11
+ import json as _json
12
+ import math
13
+
14
+ import numpy as np
15
+ from PIL import Image, ImageDraw, ImageFilter
16
+
17
+ # Màu key ứng viên, theo thứ tự ưu tiên. Xanh lá đứng đầu vì đó là mặc định mong muốn.
18
+ KEY_CANDIDATES = ["#00FF00", "#FF00FF", "#00FFFF", "#0000FF"]
19
+
20
+ # chroma_key() mặc định t_high=170: alpha CHỈ đạt 255 (đục hoàn toàn) khi khoảng cách tới
21
+ # key >= 170. Một margin "an toàn" mà thấp hơn t_high là VÔ NGHĨA — pixel chủ thể ở đúng
22
+ # khoảng cách margin đó sẽ không đạt alpha đục, tức là chủ thể bị bào mờ (Finding I1: đo
23
+ # thực tế asset màu (0,230,70), margin=131 tới #00FF00, ra alpha~169 — ma). Margin phải
24
+ # LỚN HƠN t_high mới thật sự an toàn; 190 = t_high(170) + buffer ~20 unit dự phòng
25
+ # rounding/variance giữa các lần đo màu.
26
+ MIN_KEY_MARGIN = 190.0
27
+
28
+ # "An toàn" nghĩa là margin của asset gốc tới #00FF00 phải vượt MIN_KEY_MARGIN. Dùng
29
+ # CHUNG một hằng số ở đây và ở cảnh báo `key_safe` trong CLI `plan` để hai nơi luôn khớp
30
+ # nhau — tách rời chúng là đúng lỗi I1 (một ngưỡng "an toàn" thấp hơn t_high thực tế).
31
+ # Thực tế khoảng cách giữa #00FF00 và #00C800 (xanh lá đậm) là 110.0 trên thang redmean,
32
+ # tức là dưới MIN_KEY_MARGIN, nên xanh lá đậm vẫn ĐẨY được ta sang màu key khác — đúng ý.
33
+ GREEN_SAFE_THRESHOLD = MIN_KEY_MARGIN
34
+
35
+ ALPHA_FLOOR = 8 # alpha > ngưỡng này mới tính là nội dung (khi tìm bbox)
36
+ PALETTE_ALPHA_FLOOR = 16 # alpha > ngưỡng này khi lấy mẫu bảng màu (muốn pixel mờ bị bỏ qua vì màu blended)
37
+ BAD_HIGH = 0.95 # alpha phủ hơn mức này -> nền không tách được
38
+ BAD_LOW = 0.02 # alpha phủ dưới mức này -> chủ thể NHỎ (không nhất thiết hỏng, xem
39
+ # bad_subject trong postprocess() — coverage thấp một mình không còn
40
+ # đủ để kết luận "hỏng" kể từ Finding I3)
41
+
42
+
43
+ def hex_to_rgb(h: str) -> tuple[int, int, int]:
44
+ h = h.lstrip("#")
45
+ return (int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16))
46
+
47
+
48
+ def rgb_to_hex(c) -> str:
49
+ r, g, b = (int(round(v)) for v in tuple(c)[:3])
50
+ return f"#{r:02X}{g:02X}{b:02X}"
51
+
52
+
53
+ def color_dist(c1, c2) -> float:
54
+ """Khoảng cách màu 'redmean' — xấp xỉ cảm nhận mắt người, rẻ hơn CIELAB nhiều.
55
+
56
+ Thang 0..~765. Dùng chung một công thức cho cả pick_key_color và chroma_key
57
+ để ngưỡng ở hai nơi so sánh được với nhau.
58
+ """
59
+ r1, g1, b1 = (float(v) for v in c1[:3])
60
+ r2, g2, b2 = (float(v) for v in c2[:3])
61
+ rm = (r1 + r2) / 2.0
62
+ dr, dg, db = r1 - r2, g1 - g2, b1 - b2
63
+ return math.sqrt(
64
+ (2 + rm / 256.0) * dr * dr + 4 * dg * dg + (2 + (255 - rm) / 256.0) * db * db
65
+ )
66
+
67
+
68
+ def extract_palette(img: Image.Image, n: int = 8) -> list[tuple[str, float]]:
69
+ """Bảng màu chủ đạo, bỏ qua pixel trong suốt. Trả [(hex, tỉ lệ)] giảm dần."""
70
+ arr = np.asarray(img.convert("RGBA"))
71
+ opaque = arr[arr[..., 3] > PALETTE_ALPHA_FLOOR][:, :3]
72
+ if opaque.size == 0:
73
+ return []
74
+
75
+ strip = Image.fromarray(opaque.reshape(1, -1, 3).astype(np.uint8), "RGB")
76
+ q = strip.quantize(colors=max(1, n), method=Image.Quantize.MEDIANCUT)
77
+ pal = q.getpalette() or []
78
+ counts = q.getcolors(maxcolors=256) or []
79
+ total = float(sum(c for c, _ in counts)) or 1.0
80
+
81
+ out: list[tuple[str, float]] = []
82
+ for count, idx in sorted(counts, key=lambda t: t[0], reverse=True):
83
+ rgb = pal[idx * 3 : idx * 3 + 3]
84
+ if len(rgb) == 3:
85
+ out.append((rgb_to_hex(rgb), count / total))
86
+ return out
87
+
88
+
89
+ def pick_key_color(
90
+ img: Image.Image, avoid: list[tuple[int, int, int]] | None = None
91
+ ) -> tuple[str, float]:
92
+ """Chọn màu key xa mọi màu trong asset nhất, ưu tiên xanh lá.
93
+
94
+ Trả (hex, margin) — margin là khoảng cách tới màu GẦN NHẤT trong asset (hoặc trong
95
+ `avoid`, xem dưới). Margin thấp = rủi ro ăn thủng chủ thể. KHÔNG BAO GIỜ raise — kể cả
96
+ khi mọi ứng viên đều tệ (margin thấp/0), hàm này vẫn trả ứng viên tốt nhất tìm được;
97
+ nơi gọi (CLI `plan`) chịu trách nhiệm surface rủi ro đó qua field `key_safe`, không
98
+ phải hàm này từ chối chạy.
99
+
100
+ `avoid`: các màu RGB THÊM VÀO việc chấm điểm, không lấy từ palette của `img`. Cần vì
101
+ chroma_key() chạy trên ẢNH ĐÃ RESTYLE — một phong cách MỚI, bảng màu MỚI, khác hẳn
102
+ palette của asset gốc mà hàm này đọc được. Nếu phong cách mới có màu nổi bật (vd neon
103
+ xanh lá trên một asset gốc toàn màu đỏ), chấm điểm chỉ dựa trên palette nguồn sẽ báo
104
+ xanh lá "an toàn" (đúng với nguồn) rồi Gemini vẽ ra đúng highlight đó và bị chroma-key
105
+ ăn mất. Truyền bảng màu của style preset vào `avoid` (CLI: `plan --avoid`) để gộp
106
+ nguy cơ đó vào điểm số TRƯỚC khi sinh ảnh.
107
+ """
108
+ colors = [hex_to_rgb(h) for h, _ in extract_palette(img, n=16)]
109
+ colors += list(avoid or [])
110
+ if not colors:
111
+ return KEY_CANDIDATES[0], float("inf")
112
+
113
+ scored = [
114
+ (min(color_dist(c, hex_to_rgb(k)) for c in colors), k) for k in KEY_CANDIDATES
115
+ ]
116
+ green_margin = next(m for m, k in scored if k == "#00FF00")
117
+ if green_margin > GREEN_SAFE_THRESHOLD:
118
+ return "#00FF00", green_margin
119
+
120
+ # Green không an toàn; chọn ứng viên tốt nhất TRỪ green
121
+ margin, key = max((m, k) for m, k in scored if k != "#00FF00")
122
+ return key, margin
123
+
124
+
125
+ def _dist_map(arr_rgb: np.ndarray, key: tuple[int, int, int]) -> np.ndarray:
126
+ """color_dist() bản vector hoá, cho cả ảnh cùng lúc."""
127
+ r = arr_rgb[..., 0].astype(np.float64)
128
+ g = arr_rgb[..., 1].astype(np.float64)
129
+ b = arr_rgb[..., 2].astype(np.float64)
130
+ kr, kg, kb = (float(v) for v in key)
131
+ rm = (r + kr) / 2.0
132
+ dr, dg, db = r - kr, g - kg, b - kb
133
+ return np.sqrt(
134
+ (2 + rm / 256.0) * dr * dr + 4 * dg * dg + (2 + (255 - rm) / 256.0) * db * db
135
+ )
136
+
137
+
138
+ def chroma_key(
139
+ img: Image.Image, key_hex: str, t_low: float = 70.0, t_high: float = 170.0
140
+ ) -> Image.Image:
141
+ """Tách nền bằng ngưỡng MỀM.
142
+
143
+ Pixel cách màu key < t_low -> trong suốt hoàn toàn.
144
+ Pixel cách màu key > t_high -> đục hoàn toàn.
145
+ Ở giữa -> smoothstep. Ngưỡng mềm là thứ giữ cho mép không bị răng cưa;
146
+ ngưỡng cứng sẽ làm hỏng anti-alias mà Gemini vẽ ra.
147
+ """
148
+ key = hex_to_rgb(key_hex)
149
+ rgb = np.asarray(img.convert("RGB"), dtype=np.uint8)
150
+ d = _dist_map(rgb, key)
151
+
152
+ t = np.clip((d - t_low) / max(1e-6, t_high - t_low), 0.0, 1.0)
153
+ alpha = t * t * (3.0 - 2.0 * t) # smoothstep
154
+
155
+ out = np.dstack([rgb.astype(np.float64), alpha * 255.0])
156
+ return Image.fromarray(np.rint(out).clip(0, 255).astype(np.uint8), "RGBA")
157
+
158
+
159
+ def despill(img: Image.Image, key_hex: str, strength: float = 1.0) -> Image.Image:
160
+ """Khử ám màu key còn sót Ở MÉP (green fringe) — KHÔNG đụng vào chủ thể đục.
161
+
162
+ Kênh nào 'sáng' trong màu key thì bị kẹp xuống mức trung bình của các kênh còn lại.
163
+ Với #00FF00 -> kẹp G xuống (R+B)/2. Với #FF00FF -> kẹp R và B xuống G.
164
+
165
+ Mức kẹp được NHÂN theo `weight = (1 - alpha/255) * strength`, alpha là alpha của
166
+ CHÍNH pixel đó SAU chroma_key: pixel đục hoàn toàn (alpha=255, chủ thể thật) có
167
+ weight=0 -> KHÔNG bị đụng vào một chút nào; pixel trong suốt hoàn toàn (alpha=0, nền)
168
+ có weight=1 -> bị kẹp full; pixel mép bán trong suốt được kẹp tỉ lệ theo alpha.
169
+
170
+ VÌ SAO CẦN WEIGHT NÀY (Finding C1 — trước đây là bug CRITICAL): nền trong pipeline
171
+ này là một mảng phẳng số hoá mà Gemini vẽ ra (được yêu cầu vẽ nền màu key thuần),
172
+ không phải phông xanh vật lý bị ánh sáng dội lên diễn viên — nên KHÔNG hề có "ánh
173
+ sáng key dội vào chủ thể" ở pixel đục. Spill thật sự chỉ tồn tại ở dải anti-alias nơi
174
+ Gemini blend RGB của chủ thể với RGB của nền. Bản cũ áp công thức kẹp lên MỌI pixel
175
+ bất kể alpha — tức là một phép crush kênh TOÀN CỤC, không phải sửa mép — và ăn cả
176
+ màu vàng/nâu/đỏ hợp lệ của chủ thể: đo được trên bản cũ, vàng #FFD700 trên key xanh
177
+ lá ra (255,128,0) cam; đỏ (200,30,40) trên key hồng ra gần đen. Xem
178
+ test_despill_never_touches_opaque_subject_pixels (test hồi quy cho đúng bug này) và
179
+ test_despill_still_removes_edge_fringe (chứng minh mép bán trong suốt vẫn được sửa).
180
+ """
181
+ key = hex_to_rgb(key_hex)
182
+ spill = [i for i in range(3) if key[i] >= 200]
183
+ base = [i for i in range(3) if key[i] < 200]
184
+ if not spill or not base:
185
+ return img.convert("RGBA")
186
+
187
+ arr = np.asarray(img.convert("RGBA"), dtype=np.float64)
188
+ weight = (1.0 - arr[..., 3] / 255.0) * strength
189
+ limit = arr[..., base].mean(axis=-1)
190
+ for i in spill:
191
+ ch = arr[..., i]
192
+ arr[..., i] = np.where(ch > limit, ch + (limit - ch) * weight, ch)
193
+ return Image.fromarray(np.rint(arr).clip(0, 255).astype(np.uint8), "RGBA")
194
+
195
+
196
+ def alpha_coverage(img: Image.Image) -> float:
197
+ """Tỉ lệ pixel được coi là nội dung. Dùng để phát hiện bản sinh hỏng."""
198
+ a = np.asarray(img.convert("RGBA"))[..., 3]
199
+ return float((a > ALPHA_FLOOR).sum()) / float(a.size)
200
+
201
+
202
+ # Alpha từ mức này trở lên mới coi là "đục thật" (không phải pixel mép anti-alias).
203
+ SOLID_ALPHA = 200
204
+
205
+ # Dưới tỉ lệ này thì chủ thể coi như bị bào thành bóng ma trong suốt.
206
+ # Đặt thấp (0.25) là cố ý: line-art mảnh (râu mèo) có rất nhiều pixel mép hợp lệ,
207
+ # không được báo nhầm chúng là hỏng.
208
+ BAD_SOLID_RATIO = 0.25
209
+
210
+
211
+ def solid_ratio(img: Image.Image) -> float:
212
+ """Tỉ lệ pixel ĐỤC THẬT trên tổng pixel CÓ NỘI DUNG.
213
+
214
+ alpha_coverage() chỉ trả lời "có pixel không", hàm này trả lời "pixel có đặc không".
215
+ Cần cả hai: màu key sát màu chủ thể sẽ bào chủ thể xuống alpha ~40 — vẫn đếm là
216
+ 'có nội dung' nên coverage trông bình thường, nhưng asset thực tế là một bóng ma.
217
+ """
218
+ a = np.asarray(img.convert("RGBA"))[..., 3]
219
+ content = int((a > ALPHA_FLOOR).sum())
220
+ if content == 0:
221
+ return 0.0
222
+ return float((a >= SOLID_ALPHA).sum()) / float(content)
223
+
224
+
225
+ def content_bbox(img: Image.Image, floor: int = ALPHA_FLOOR) -> tuple[int, int, int, int] | None:
226
+ """Bbox của phần nhìn thấy được. Trả None nếu ảnh rỗng hoàn toàn.
227
+
228
+ Không dùng Image.getbbox() vì nó lấy alpha > 0, tức là dính cả nhiễu alpha=1
229
+ mà chroma key mềm để lại quanh mép.
230
+ """
231
+ a = np.asarray(img.convert("RGBA"))[..., 3]
232
+ ys, xs = np.nonzero(a > floor)
233
+ if xs.size == 0:
234
+ return None
235
+ return (int(xs.min()), int(ys.min()), int(xs.max()) + 1, int(ys.max()) + 1)
236
+
237
+
238
+ # Trên tỉ lệ này thì coi vùng thủng bên trong bbox là đáng ngờ (Finding I2).
239
+ BAD_HOLE_RATIO = 0.10
240
+
241
+
242
+ def hole_ratio(img: Image.Image, bbox: tuple[int, int, int, int] | None = None) -> float:
243
+ """Tỉ lệ pixel BÊN TRONG content_bbox bị thủng hoàn toàn (alpha <= ALPHA_FLOOR).
244
+
245
+ Bịt lỗ hổng cấu trúc của coverage/solid_ratio/border_impurity: cả ba đều đo tín hiệu
246
+ TOÀN CỤC hoặc VÀNH NGOÀI, nên một màu sát-key nằm LỌT THỎM giữa chủ thể (vd một viên
247
+ ngọc xanh lá trên nền chủ thể đỏ-nâu) bị chroma_key khoét thành lỗ trong suốt giữa
248
+ asset — coverage/solid_ratio/border_impurity đều không nhìn vào GIỮA bbox nên không
249
+ thấy gì, report ra "ok", `flags: []`, và asset lọt lưới với một lỗ thủng giữa thân.
250
+
251
+ CẢNH BÁO — cờ `bad_holes` dùng hàm này CHỈ MANG TÍNH THAM KHẢO, không phải gate cứng:
252
+ art hollow HỢP LỆ rất phổ biến (nhẫn, chữ "O", khung ảnh, bánh donut) và có thể có
253
+ hole_ratio cao mà không hề hỏng. BAD_HOLE_RATIO được chọn để bắt một viên ngọc bị
254
+ khoét GIỮA chủ thể (test_hole_ratio_flags_interior_hole) trong khi vẫn bỏ qua một
255
+ hình khối rỗng vừa phải, hợp lệ (test_hole_ratio_tolerates_legit_hollow_shape).
256
+ Ngưỡng này KHÔNG THỂ phân biệt hoàn hảo mọi trường hợp — art hollow rất lớn (interior
257
+ chiếm phần lớn bbox) vẫn có thể bị flag nhầm. Vì vậy `bad_holes` không bao giờ được
258
+ dùng để tự động loại bỏ asset (không trả None, không ép `bad_subject`) — contact
259
+ sheet, nơi người duyệt nhìn bằng mắt, mới là cửa gác thật sự.
260
+ """
261
+ if bbox is None:
262
+ bbox = content_bbox(img)
263
+ if bbox is None:
264
+ return 0.0
265
+ x0, y0, x1, y1 = bbox
266
+ a = np.asarray(img.convert("RGBA"))[..., 3]
267
+ inner = a[y0:y1, x0:x1]
268
+ if inner.size == 0:
269
+ return 0.0
270
+ return float((inner <= ALPHA_FLOOR).sum()) / float(inner.size)
271
+
272
+
273
+ # Vệt rác nhỏ hơn tỉ lệ này (so với mảng lớn nhất) thì bị xoá.
274
+ # Ca thật bắt buộc phải có nó: Gemini ĐÓNG DẤU WATERMARK ✦ lên góc dưới-phải MỌI ảnh nó sinh ra.
275
+ # Watermark đó là màu xanh hơi lệch key — đo được (81,249,77), cách #00FF00 đúng 176 trên thang
276
+ # redmean, tức là NHỈNH HƠN t_high=170 — nên nó sống sót qua chroma key và thành một chấm xanh
277
+ # ĐỤC HOÀN TOÀN nằm trong asset. Không despeckle thì mọi asset xuất ra đều dính chấm xanh.
278
+ SPECKLE_RATIO = 0.01
279
+
280
+
281
+ def _components(mask: np.ndarray) -> tuple[list, dict, dict]:
282
+ """Gán nhãn liên thông 4-hướng bằng run-length + union-find.
283
+
284
+ scipy.ndimage.label không có trong môi trường này. Nhưng duyệt theo RUN (đoạn pixel liền
285
+ nhau trên một hàng) thay vì theo từng pixel thì số phần tử tụt từ ~1 triệu xuống vài nghìn,
286
+ nên union-find thuần Python vẫn nhanh.
287
+ """
288
+ h, w = mask.shape
289
+ parent: dict[int, int] = {}
290
+
291
+ def find(x: int) -> int:
292
+ while parent[x] != x:
293
+ parent[x] = parent[parent[x]]
294
+ x = parent[x]
295
+ return x
296
+
297
+ def union(a: int, b: int) -> None:
298
+ ra, rb = find(a), find(b)
299
+ if ra != rb:
300
+ parent[rb] = ra
301
+
302
+ rows: list[list[tuple[int, int, int]]] = []
303
+ nxt = 0
304
+ for y in range(h):
305
+ edge = np.diff(np.concatenate(([0], mask[y].astype(np.int8), [0])))
306
+ runs = []
307
+ for s, e in zip(np.flatnonzero(edge == 1), np.flatnonzero(edge == -1)):
308
+ parent[nxt] = nxt
309
+ runs.append((int(s), int(e), nxt))
310
+ nxt += 1
311
+ if y > 0:
312
+ for s, e, lbl in runs:
313
+ for ps, pe, plbl in rows[-1]:
314
+ if ps < e and s < pe: # hai run chồng nhau theo cột -> cùng mảng
315
+ union(plbl, lbl)
316
+ rows.append(runs)
317
+
318
+ areas: dict[int, int] = {}
319
+ for runs in rows:
320
+ for s, e, lbl in runs:
321
+ r = find(lbl)
322
+ areas[r] = areas.get(r, 0) + (e - s)
323
+ return rows, {"find": find}, areas
324
+
325
+
326
+ def component_boxes(mask: np.ndarray, min_size: int = 24) -> list[tuple[int, int, int, int]]:
327
+ """Bounding box (x0, y0, x1, y1) của từng mảng liên thông True trong `mask`.
328
+
329
+ Dùng cho chế độ SCREEN SHEET: dải chi tiết là các chủ thể rời nhau trên nền key —
330
+ mỗi mảng liên thông = một asset. Bỏ mảng mà CẢ HAI chiều đều dưới `min_size`
331
+ (nhiễu/speck; asset mảnh dài như thanh progress 200×10 vẫn giữ vì một chiều đủ lớn).
332
+
333
+ Thứ tự trả về là THỨ TỰ ĐỌC: gom theo hàng (mảng nào có tâm-y nằm trong dải-y của
334
+ hàng hiện có thì vào hàng đó), hàng trên trước, trong hàng thì trái trước — để
335
+ cell1..cellN ổn định và khớp với cách người nhìn sheet."""
336
+ rows, uf, _areas = _components(mask)
337
+ find = uf["find"]
338
+ boxes: dict[int, list[int]] = {}
339
+ for y, runs in enumerate(rows):
340
+ for s, e, lbl in runs:
341
+ r = find(lbl)
342
+ b = boxes.get(r)
343
+ if b is None:
344
+ boxes[r] = [s, y, e, y + 1]
345
+ else:
346
+ if s < b[0]:
347
+ b[0] = s
348
+ if e > b[2]:
349
+ b[2] = e
350
+ b[3] = y + 1
351
+ keep = [tuple(b) for b in boxes.values()
352
+ if (b[2] - b[0]) >= min_size or (b[3] - b[1]) >= min_size]
353
+
354
+ keep.sort(key=lambda b: b[1])
355
+ bands: list[list[tuple[int, int, int, int]]] = []
356
+ for b in keep:
357
+ cy = (b[1] + b[3]) / 2
358
+ for band in bands:
359
+ if min(x[1] for x in band) <= cy <= max(x[3] for x in band):
360
+ band.append(b)
361
+ break
362
+ else:
363
+ bands.append([b])
364
+ ordered: list[tuple[int, int, int, int]] = []
365
+ for band in bands:
366
+ band.sort(key=lambda b: b[0])
367
+ ordered.extend(band)
368
+ return ordered
369
+
370
+
371
+ def despeckle(img: Image.Image, ratio: float = SPECKLE_RATIO) -> tuple[Image.Image, int]:
372
+ """Xoá các mảng liên thông nhỏ hơn `ratio` lần mảng lớn nhất. Trả (ảnh, số mảng đã xoá).
373
+
374
+ Chủ yếu để diệt watermark của Gemini (xem SPECKLE_RATIO), tiện thể dọn luôn nhiễu lấm tấm
375
+ mà chroma key để sót.
376
+
377
+ RỦI RO đã biết: asset gồm nhiều mảnh rời hợp lệ mà có mảnh rất nhỏ (hạt lấp lánh quanh ngôi
378
+ sao, dấu chấm trên chữ "i") thì mảnh đó có thể bị xoá oan. Ngưỡng 1% là bảo thủ, và số mảng
379
+ bị xoá LUÔN được báo trong report (`speckles_removed`) để người duyệt thấy — nhưng contact
380
+ sheet vẫn là cửa gác cuối, không phải con số này.
381
+ """
382
+ arr = np.array(img.convert("RGBA"))
383
+ mask = arr[..., 3] > ALPHA_FLOOR
384
+ if not mask.any():
385
+ return img, 0
386
+
387
+ rows, uf, areas = _components(mask)
388
+ find = uf["find"]
389
+ biggest = max(areas.values())
390
+ doomed = {r for r, a in areas.items() if a < ratio * biggest}
391
+ if not doomed:
392
+ return img, 0
393
+
394
+ for y, runs in enumerate(rows):
395
+ for s, e, lbl in runs:
396
+ if find(lbl) in doomed:
397
+ arr[y, s:e, 3] = 0
398
+
399
+ return Image.fromarray(arr, "RGBA"), len(doomed)
400
+
401
+
402
+ # ── Watermark ✦ của Gemini: hằng số ĐO ĐƯỢC, không phải đoán ────────────────────────────
403
+ # Gemini web dán một ngôi sao 4 cánh TRẮNG vào ô 48x48 px, cách cạnh phải và cạnh dưới đúng
404
+ # 96 px. Hiệu chuẩn bằng 3 ảnh "nền đen thuần" sinh riêng: hình học trùng khít từng pixel
405
+ # (828 pixel sáng, đỉnh 78/255, lệch giữa 3 mẫu < 1.4/255), và ba kênh RGB lệch nhau ĐÚNG 0.0
406
+ # -> overlay là TRẮNG THUẦN với alpha CỐ ĐỊNH. Đo lại trên canvas 1024x1024: vẫn 48x48 @ 96px,
407
+ # tức hình học KHÔNG scale theo cạnh ảnh.
408
+ #
409
+ # Vì alpha cố định, đây là phép trộn tuyến tính ĐẢO ĐƯỢC:
410
+ # O = S*(1-α) + 255*α => S = (O - 255*α) / (1-α)
411
+ # nên lấy lại được ĐÚNG pixel gốc — không cần inpaint/blur đoán nội dung. Sai số duy nhất là
412
+ # lượng tử hoá, bị khuếch đại 1/(1-α) ≈ 1.44 lần, tức tối đa ~±1.4 mức: mắt không thấy.
413
+ # Tính chất phụ tiện lợi: nền TRẮNG thuần (255) thì watermark vô hình VÀ phép đảo là ánh xạ
414
+ # đồng nhất, nên chạy trên ảnh nền trắng cũng vô hại.
415
+ _WM_BOX = 48 # cạnh ô watermark (px)
416
+ _WM_MARGIN = 96 # lề từ ô tới cạnh phải/dưới (px)
417
+
418
+ # 48x48 PNG grayscale, mỗi pixel = round(α*255). Nhúng base64 để imglib TỰ CHỨA: một file
419
+ # mask rời rất dễ bị bỏ quên khi copy skill sang máy khác, và thiếu nó thì watermark lặng lẽ
420
+ # không được xoá.
421
+ _WM_ALPHA_B64 = (
422
+ "iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAAAAAByaaZbAAABlUlEQVR42p2WwU/CMBTGv6KL0EQXswkjphcO48rReeU/94Ax"
423
+ "XDwKBzWOhBFpjB66mJHpgTlW1q6d79J07e+9167vawG1TaeagY76s0ep3woYAoNWwABgbQCPAo7fAmAAENoDlP2FsQRCqTED"
424
+ "tFgv8y2B6CiSZCeKhIZlqN2HRQQ6rrAX5gg0ciqj/VVuAqLzas+5jA3ApH8UkCaNwIQB5NAlgHtESIBzE9Q3zQ3eMw3gRq7q"
425
+ "33aDTaYERpOu+kQ7I8KrWe7NDz3oTdwLGaAhQ7PFS3EAmr2XyGoLgMAfMAd2JpLNlkz3ZUJ+LJlOsQjL+SAEXjDsWfrfvSWc"
426
+ "AIDHmMV0vuD/3lYAoLc9o3cJAMKxNvenl/rRaAiSzj/VpzVLrs5kF/t0ZkJXD9krrR/weJ43VFxSI+LH5ppOfFlRvx5MujRP"
427
+ "5fUadSnn1xUnd8Isld/5QWmWiY0YP5cFnC7s1LucNrOUe17IYyxsb6Cl1FgAgmsDaG7RBQCsWly7fAek2zYvgRhYt3o6rIGN"
428
+ "euRUU5Ip1BnhFzx/an1wRZA/AAAAAElFTkSuQmCC"
429
+ )
430
+
431
+ _WM_CACHE: dict[str, np.ndarray] = {}
432
+
433
+
434
+ def _wm_alpha() -> np.ndarray:
435
+ """Mask alpha 48x48 (float 0..1) của ngôi sao. Cache vì gọi cho mọi ảnh tải về."""
436
+ a = _WM_CACHE.get("a")
437
+ if a is None:
438
+ raw = base64.b64decode(_WM_ALPHA_B64)
439
+ a = np.asarray(Image.open(io.BytesIO(raw)).convert("L")).astype(np.float64) / 255.0
440
+ _WM_CACHE["a"] = a
441
+ return a
442
+
443
+
444
+ def _wm_seam_energy(gray: np.ndarray, edge_w: np.ndarray) -> float:
445
+ """Năng lượng gradient của `gray`, CHỈ tính trên đường viền ngôi sao (`edge_w`).
446
+
447
+ Dùng làm bằng chứng watermark có mặt hay không: viền ngôi sao là bước nhảy alpha
448
+ 0 -> 0.3 trong ~1px, nên nếu watermark có thật thì gradient dồn đúng vào đó, và
449
+ sau khi đảo phép trộn nó phải TAN đi. Nếu ảnh KHÔNG có watermark, phép đảo tạo ra một
450
+ ngôi sao TỐI -> năng lượng viền TĂNG. Nhờ vậy một phép đo phân biệt được cả hai chiều.
451
+ """
452
+ gy, gx = np.gradient(gray)
453
+ return float((np.hypot(gx, gy) * edge_w).sum())
454
+
455
+
456
+ def unwatermark_gemini(
457
+ img: Image.Image, verify: bool = False, search: int = 0, min_gain: float = 0.25
458
+ ) -> tuple[Image.Image, dict | None]:
459
+ """Xoá ngôi sao ✦ của Gemini bằng cách ĐẢO phép trộn alpha. Trả (ảnh, info|None).
460
+
461
+ Phải chạy TRƯỚC mọi thao tác khác (tách nền, cắt sheet, resize): watermark nằm trong
462
+ pixel màu, nên mọi bước sau đó đều bôi nó ra hoặc bake nó vào asset. Sau khi resize/cắt,
463
+ hình học 48x48@96px không còn đúng và không còn cách nào lấy lại pixel gốc.
464
+
465
+ verify=False (mặc định): đảo VÔ ĐIỀU KIỆN tại đúng ô đã hiệu chuẩn. Dùng cho ảnh CHẮC
466
+ CHẮN từ Gemini web — ở đó không cần dò, và dò thì chỉ thêm đường hỏng.
467
+ verify=True: chỉ đảo khi đo được bằng chứng watermark có thật. Dùng cho ảnh NGUỒN LẪN
468
+ (vd process_raws nhận cả ảnh Codex/GPT Image 2 không có watermark) — ở đó đảo bừa sẽ
469
+ ĐÓNG một ngôi sao TỐI vào ảnh sạch.
470
+
471
+ `search` = bán kính dò lệch vị trí, MẶC ĐỊNH 0 vì hình học đã hiệu chuẩn là chính xác.
472
+ Bật lên chỉ khi Google dịch watermark: dò trên nền có hoa văn tuần hoàn có thể khớp
473
+ nhầm chỗ và đảo sai (đo được: nền vạch sọc chu kỳ 7px, sai số phục hồi vọt lên 67 mức).
474
+
475
+ info: {"box": (x0,y0,w,h), "gain": float|None} nếu đã xoá, None nếu bỏ qua.
476
+ """
477
+ alpha = _wm_alpha()
478
+ box = _WM_BOX
479
+ rgb = img.convert("RGB") if img.mode not in ("RGB", "RGBA") else img
480
+ arr = np.asarray(rgb.convert("RGB")).astype(np.float64)
481
+ H, W = arr.shape[:2]
482
+ if W < box + _WM_MARGIN or H < box + _WM_MARGIN:
483
+ return img, None # ảnh nhỏ hơn cả lề -> không phải khung Gemini gốc
484
+
485
+ x_nom = W - _WM_MARGIN - box
486
+ y_nom = H - _WM_MARGIN - box
487
+ a3 = alpha[..., None]
488
+ inv = 1.0 - a3
489
+
490
+ def restore(x0: int, y0: int) -> np.ndarray:
491
+ reg = arr[y0:y0 + box, x0:x0 + box]
492
+ return (reg - 255.0 * a3) / inv
493
+
494
+ if not verify:
495
+ best = (x_nom, y_nom, None)
496
+ else:
497
+ gy, gx = np.gradient(alpha)
498
+ edge_w = np.hypot(gx, gy)
499
+ solid = alpha > 0.29 # lòng ngôi sao: alpha hằng, ~744 px
500
+ clear = alpha <= 0.0 # bốn góc ô 48x48: hoàn toàn ngoài ngôi sao, ~1400 px
501
+ if edge_w.sum() <= 0 or not solid.any() or not clear.any():
502
+ return img, None
503
+ a_solid = float(alpha[solid].mean())
504
+
505
+ # Hai VÀNH sát viền ngôi sao — một vành ngay trong, một vành ngay ngoài. Cần chúng vì
506
+ # so trung bình lòng-sao với bốn góc ô BỎ SÓT khi nền có hoa văn cỡ gần bằng ô (đo
507
+ # được: checker 16px lọt, do nền ở lòng sao khác nền ở góc). Hai vành kề nhau nên
508
+ # nền CỤC BỘ khớp, hiệu giữa chúng gần như chỉ còn phần watermark cộng vào.
509
+ sm = Image.fromarray((solid * 255).astype(np.uint8), "L")
510
+ grown = np.asarray(sm.filter(ImageFilter.MaxFilter(7))) > 127
511
+ shrunk = np.asarray(sm.filter(ImageFilter.MinFilter(7))) > 127
512
+ rim_in = solid & ~shrunk
513
+ rim_out = grown & clear
514
+ use_rim = rim_in.any() and rim_out.any()
515
+ a_rim = float(alpha[rim_in].mean()) if use_rim else 0.0
516
+
517
+ best_score, best = -1e9, None
518
+ for dy in range(-search, search + 1):
519
+ for dx in range(-search, search + 1):
520
+ x0, y0 = x_nom + dx, y_nom + dy
521
+ if x0 < 0 or y0 < 0 or x0 + box > W or y0 + box > H:
522
+ continue
523
+ reg = arr[y0:y0 + box, x0:x0 + box]
524
+ g = reg.mean(axis=2)
525
+
526
+ # RÀNG BUỘC CỨNG loại trước mọi phép đo mềm: nếu ô này thật sự có lớp trắng
527
+ # alpha α phủ lên ảnh gốc S ≥ 0 thì buộc O = S(1-α) + 255α ≥ 255α. Vậy chỉ cần
528
+ # thấy pixel trong lòng sao TỐI HƠN 255α là giả thiết SAI hẳn — không cần đoán
529
+ # thêm. Đây là thứ chặn ảnh sạch có chi tiết tối ở góc (đo được: nền checker
530
+ # 8px sạch từng bị xoá bừa trước khi có cổng này). Nới 6 mức cho nhiễu nén, và
531
+ # cho phép 1% pixel vi phạm.
532
+ floor = 255.0 * a_solid - 6.0
533
+ if float((g[solid] < floor).mean()) > 0.01:
534
+ continue
535
+
536
+ before = _wm_seam_energy(g, edge_w)
537
+ after = _wm_seam_energy(restore(x0, y0).mean(axis=2), edge_w)
538
+ gain = (before - after) / before if before > 1e-9 else 0.0
539
+
540
+ # Phép đo thứ hai, MIỄN NHIỄM với texture tần số cao: lấy trung bình trên
541
+ # ~744 px lòng sao so với ~1400 px bốn góc ô. Lớp phủ trắng alpha hằng nâng
542
+ # lòng sao lên đúng α*(255 - nền); nhiễu/checker bị triệt vì lấy trung bình
543
+ # hàng trăm pixel. Cần phép này vì đo gradient viền một mình BỎ SÓT khi nền
544
+ # rối (đo được: nền noise và checker 16px đều lọt).
545
+ def step_conf(inside: np.ndarray, outside: np.ndarray, a_in: float) -> float:
546
+ """Độ tin cậy từ bậc sáng: 1.0 khi bậc đo được khớp đúng α*(255-nền)."""
547
+ bg = float(g[outside].mean())
548
+ pred = a_in * (255.0 - bg)
549
+ if pred <= 2.0: # nền gần trắng -> watermark vô hình, phép này vô nghĩa
550
+ return -1e9
551
+ r = (float(g[inside].mean()) - bg) / pred
552
+ return 1.0 - abs(r - 1.0) / 0.4 if 0.6 <= r <= 1.4 else -1e9
553
+
554
+ # Điểm = mức tin cậy CAO NHẤT trong ba phép đo độc lập, để mỗi phép bù điểm yếu
555
+ # của phép kia (gradient viền chịu nền rối; bậc sáng chịu nền có hoa văn to).
556
+ # Ràng buộc hai phía của tỉ lệ bậc sáng khiến ngôi sao THẬT với alpha khác
557
+ # (vd 0.6) KHÔNG bị nhận nhầm là watermark.
558
+ score = max(gain, step_conf(solid, clear, a_solid))
559
+ if use_rim:
560
+ score = max(score, step_conf(rim_in, rim_out, a_rim))
561
+ if score > best_score:
562
+ best_score, best = score, (x0, y0, gain)
563
+ if best is None or best_score < min_gain:
564
+ return img, None
565
+
566
+ x0, y0, gain = best
567
+ out = np.asarray(img.convert("RGBA") if img.mode == "RGBA" else rgb.convert("RGB")).copy()
568
+ out[y0:y0 + box, x0:x0 + box, :3] = np.clip(
569
+ np.rint(restore(x0, y0)), 0, 255).astype(np.uint8)
570
+ return Image.fromarray(out, img.mode if img.mode == "RGBA" else "RGB"), {
571
+ "box": (x0, y0, box, box), "gain": gain,
572
+ }
573
+
574
+
575
+ def strip_gemini_watermark(
576
+ img: Image.Image, corner: float = 0.22, max_ratio: float = 0.08
577
+ ) -> tuple[Image.Image, int]:
578
+ """LƯỚI AN TOÀN dọn dấu ✦ còn sót SAU khi đã tách nền. Không phải đường xoá chính.
579
+
580
+ Đường chính bây giờ là unwatermark_gemini(): nó đảo phép trộn alpha NGAY khi ảnh tải về,
581
+ lấy lại đúng pixel gốc. Bình thường tới đây không còn gì để xoá (`speckles_removed: 0`).
582
+ Giữ hàm này cho trường hợp Google đổi hình học watermark khiến phép đảo không khớp nữa —
583
+ lúc đó dấu ✦ lại sống sót qua chroma key và cần dọn thô ở đây.
584
+
585
+ Cách làm THÔ, chỉ dùng được sau tách nền: xoá mọi mảng liên thông nằm GỌN trong ô góc
586
+ dưới-phải (`corner` phần cạnh) VÀ nhỏ hơn `max_ratio` lần mảng lớn nhất — nên không đụng
587
+ chủ thể chính, nhưng cũng KHÔNG cứu được khi watermark nằm đè lên chủ thể hoặc trên nền
588
+ đục (vd mockup screen-sheet). Đó chính là lý do phải xoá sớm ở unwatermark_gemini().
589
+ """
590
+ arr = np.array(img.convert("RGBA"))
591
+ H, W = arr.shape[:2]
592
+ mask = arr[..., 3] > ALPHA_FLOOR
593
+ if not mask.any():
594
+ return img, 0
595
+
596
+ rows, uf, areas = _components(mask)
597
+ find = uf["find"]
598
+ biggest = max(areas.values())
599
+
600
+ boxes: dict[int, list[int]] = {}
601
+ for y, runs in enumerate(rows):
602
+ for s, e, lbl in runs:
603
+ r = find(lbl)
604
+ b = boxes.get(r)
605
+ if b is None:
606
+ boxes[r] = [s, y, e, y + 1]
607
+ else:
608
+ b[0] = min(b[0], s); b[1] = min(b[1], y)
609
+ b[2] = max(b[2], e); b[3] = max(b[3], y + 1)
610
+
611
+ cx0, cy0 = W * (1.0 - corner), H * (1.0 - corner)
612
+ doomed = {
613
+ r for r, b in boxes.items()
614
+ if areas[r] < max_ratio * biggest and b[0] >= cx0 and b[1] >= cy0
615
+ }
616
+ if not doomed:
617
+ return img, 0
618
+ for y, runs in enumerate(rows):
619
+ for s, e, lbl in runs:
620
+ if find(lbl) in doomed:
621
+ arr[y, s:e, 3] = 0
622
+ return Image.fromarray(arr, "RGBA"), len(doomed)
623
+
624
+
625
+ def fit_into(
626
+ content: Image.Image,
627
+ canvas_size: tuple[int, int],
628
+ target_box: tuple[int, int, int, int],
629
+ upscale=None,
630
+ report: dict | None = None,
631
+ ) -> Image.Image:
632
+ """Scale `content` vừa khít (contain) vào target_box, căn giữa, dán lên canvas trong suốt.
633
+
634
+ Giữ đúng tỉ lệ của content — thà chừa khoảng trống còn hơn bóp méo asset.
635
+
636
+ `upscale`: callable phóng 4x một mảng HxWx3 uint8 (xem upscale.upscale_rgb). Chỉ dùng
637
+ khi phải PHÓNG TO (scale > UPSCALE_MIN_GAIN) — đó đúng là ca LANCZOS làm ảnh mềm nhũn.
638
+ Thu nhỏ thì LANCZOS đã là tốt nhất, không đụng tới. Truyền None để giữ hành vi cũ.
639
+ `report`: dict tuỳ chọn, sẽ được NHÉT THÊM báo cáo chọn cách phóng to (xem best_upscale).
640
+ """
641
+ tx0, ty0, tx1, ty1 = target_box
642
+ tw, th = max(1, tx1 - tx0), max(1, ty1 - ty0)
643
+ cw, ch = content.size
644
+
645
+ scale = min(tw / cw, th / ch)
646
+ nw, nh = max(1, round(cw * scale)), max(1, round(ch * scale))
647
+
648
+ if scale > UPSCALE_MIN_GAIN:
649
+ scaled, up_rep = best_upscale(content, (nw, nh), backend=upscale)
650
+ else:
651
+ # Gọi thẳng resize(): Pillow tự convert RGBA -> RGBa (premultiplied) bên trong rồi
652
+ # convert ngược, nên mép không bị rỉ màu. Premultiply BẰNG TAY ở đây là phản tác dụng —
653
+ # Pillow sẽ nhân lần hai và phá màu ở alpha thấp (đo được: R 255 -> 0 tại alpha ~2).
654
+ scaled = content.convert("RGBA").resize((nw, nh), Image.LANCZOS)
655
+ up_rep = {"upscale_method": None, "upscale_factor": round(scale, 4)}
656
+ if report is not None:
657
+ report.update(up_rep)
658
+ canvas = Image.new("RGBA", canvas_size, (0, 0, 0, 0))
659
+ canvas.paste(scaled, (tx0 + (tw - nw) // 2, ty0 + (th - nh) // 2))
660
+ return canvas
661
+
662
+
663
+ # ---------------------------------------------------------------------- PHÓNG TO
664
+ # Ảnh AI sinh ra hay NHỎ hơn kích thước đích (Gemini/GPT trả về khung cố định, còn asset
665
+ # game thì cần đúng size gốc). LANCZOS phóng to chỉ trải mép ra cho mềm đi — nó không có
666
+ # thông tin nào để thêm. Real-ESRGAN anime_6B thì dựng lại nét. Nhưng nó cũng có thể BỊA:
667
+ # thêm quầng sáng, đổi nét, ăn mất chi tiết nhỏ. Nên ở đây cũng chạy nhiều cách rồi chấm
668
+ # điểm chọn bản tốt nhất, đúng như đường tách nền.
669
+
670
+ UPSCALE_MIN_GAIN = 1.02 # phóng dưới mức này thì LANCZOS đã đủ, không gọi model làm gì
671
+ UPSCALE_MAX_PASS = 2 # tối đa 2 lượt x4 = 16x; hơn nữa là ảnh nguồn quá nhỏ, vô vọng
672
+ UPSCALE_GRAY = 128.0 # nền xám để "nhìn thấy" ảnh RGBA lúc đo (xem _visible)
673
+ UPSCALE_RING_TOL = 3.0 # vượt biên min/max cục bộ quá mức này mới tính là quầng/ringing
674
+ UPSCALE_BLEED_ITERS = 8 # số vòng loang màu tiền cảnh ra vùng trong suốt trước khi phóng
675
+ UPSCALE_FLAT_ENERGY = 1e-6 # dưới mức này coi ảnh nguồn là PHẲNG (xem score_upscale)
676
+
677
+ # Ngưỡng LOẠI THẲNG — LƯỚI AN TOÀN cho ca thảm hoạ, KHÔNG phải công cụ xếp hạng. Đặt cao
678
+ # hẳn trên vùng giá trị của bản TỐT, vì loại nhầm bản tốt thì hậu quả là âm thầm rơi về
679
+ # LANCZOS mờ — tệ hơn hẳn việc để lọt một bản hơi kém.
680
+ # Số đo (bản dựng sẵn cho 4 cảnh x 2 độ phân giải, xem SKILL.md § Phóng to):
681
+ # lr_err bản OK 1.0–6.5 (asset thật lên tới 14.4) | ảnh SAI HẲN 72.8–87.7
682
+ # cov_err bản OK <= 0.053 | matte bị phá 0.099–0.122
683
+ UPSCALE_BAD_LR = 30.0 # thu nhỏ ngược lại mà lệch ảnh gốc quá mức này -> bịa nội dung
684
+ UPSCALE_BAD_COV = 0.08 # coverage lệch quá mức này -> matte bị ăn mòn hoặc phình ra
685
+
686
+ # Trọng số chấm điểm — DÒ ĐƯỢC, không phải chọn cho đẹp. Cách dò: vẽ cùng một cảnh ở CẢ
687
+ # HAI độ phân giải (không ảnh nào suy ra từ ảnh kia) rồi tìm bộ trọng số cho thứ tự xếp
688
+ # hạng trùng với LPIPS. Kết quả: đúng 87.5% trên phần huấn luyện VÀ 87.5% trên nửa giữ
689
+ # lại. Hai chi tiết đáng nhớ vì chúng đi ngược trực giác:
690
+ #
691
+ # 1. `ring` mới là tiêu chí phân định, không phải `lr_err`. Bỏ ring (W_RING=0) thì độ đúng
692
+ # tụt xuống 66.9% — đúng bằng mức của "cứ luôn chọn esrgan", tức là bộ điểm không còn
693
+ # đóng góp gì. Chính ring bắt được đúng nhóm ca mà LANCZOS thật sự thắng (hoạ tiết
694
+ # dày, nét mảnh san sát — chỗ model bịa ra nhiều nhất).
695
+ # 2. `lr_err` và `cov_err` KHÔNG có sức xếp hạng. Dò ra trọng số tối ưu của chúng bằng 0;
696
+ # đẩy W_LR lên 0.2 làm độ đúng tụt còn 80.6%. Giữ W_LR bé xíu chỉ để phá thế hoà, còn
697
+ # cov_err rời hẳn khỏi tổng điểm — nó sống bằng vai trò loại thẳng ở trên.
698
+ W_BLUR = 3.0
699
+ W_RING = 0.40 # trên thang mức màu vượt biên trung bình (0.2–0.6 đều cho 87.5%)
700
+ W_LR = 0.05 # trên thang mức màu 0..255 — chỉ để phá thế hoà
701
+
702
+
703
+ def _shift(a: np.ndarray, dy: int, dx: int) -> np.ndarray:
704
+ """Dịch mảng `dy/dx` pixel, chỗ trống điền 0 (KHÔNG cuộn vòng như np.roll)."""
705
+ out = np.zeros_like(a)
706
+ h, w = a.shape[:2]
707
+ ys0, ys1 = max(0, -dy), h - max(0, dy)
708
+ xs0, xs1 = max(0, -dx), w - max(0, dx)
709
+ out[max(0, dy):h - max(0, -dy), max(0, dx):w - max(0, -dx)] = a[ys0:ys1, xs0:xs1]
710
+ return out
711
+
712
+
713
+ def _bleed_rgb(rgb: np.ndarray, opaque: np.ndarray,
714
+ iters: int = UPSCALE_BLEED_ITERS) -> np.ndarray:
715
+ """Loang màu tiền cảnh ra vùng trong suốt trước khi đưa vào model phóng to.
716
+
717
+ BẮT BUỘC, không phải tinh chỉnh: sau unmix_cutout, pixel nền vẫn GIỮ NGUYÊN màu key
718
+ (magenta/xanh lá) với alpha 0 — vô hình khi hiển thị, nhưng model phóng to chỉ nhận
719
+ RGB nên nó thấy magenta thật và kéo màu đó vào mép chủ thể. Kết quả: viền hồng trên
720
+ ảnh mà đường tách nền vừa mới làm sạch tới mức cast = 0.
721
+ """
722
+ out = rgb.astype(np.float32).copy()
723
+ if not opaque.any():
724
+ return out
725
+ known = opaque.copy()
726
+ for _ in range(max(0, iters)):
727
+ if known.all():
728
+ break
729
+ k = known.astype(np.float32)
730
+ s = np.zeros_like(out)
731
+ c = np.zeros_like(k)
732
+ for dy, dx in ((-1, 0), (1, 0), (0, -1), (0, 1)):
733
+ s += _shift(out * k[..., None], dy, dx)
734
+ c += _shift(k, dy, dx)
735
+ fill = (~known) & (c > 0)
736
+ if not fill.any():
737
+ break
738
+ out[fill] = s[fill] / c[fill][:, None]
739
+ known |= fill
740
+ if not known.all():
741
+ # Vùng trong suốt rộng, loang không tới: điền màu trung bình chủ thể. Miễn là KHÔNG
742
+ # còn màu key nằm lại, còn màu gì thì cũng vô hình (alpha 0).
743
+ out[~known] = rgb[opaque].mean(axis=0)
744
+ return out
745
+
746
+
747
+ def upscale_rgba(img: Image.Image, backend, alpha_esrgan: bool = True) -> Image.Image:
748
+ """Phóng 4x một ảnh RGBA bằng `backend` (callable HxWx3 uint8 -> 4x uint8).
749
+
750
+ RGB và ALPHA được phóng RIÊNG: model chỉ ăn 3 kênh. Alpha đi qua chính model đó dưới
751
+ dạng ảnh xám 3 kênh (`alpha_esrgan=True`) — mặc định này là kết quả ĐO, không phải
752
+ phỏng đoán; xem bảng trong SKILL.md § Phóng to. Đặt False để phóng alpha bằng LANCZOS.
753
+ """
754
+ a = np.asarray(img.convert("RGBA"))
755
+ rgb, al = a[..., :3], a[..., 3]
756
+ opaque = al > 0
757
+
758
+ if opaque.all():
759
+ big = backend(np.ascontiguousarray(rgb))
760
+ alpha = np.full(big.shape[:2], 255, np.uint8)
761
+ return Image.fromarray(np.dstack([big, alpha]), "RGBA")
762
+
763
+ filled = np.clip(_bleed_rgb(rgb.astype(np.float32), opaque), 0, 255).astype(np.uint8)
764
+ big = backend(np.ascontiguousarray(filled))
765
+ th, tw = big.shape[:2]
766
+ if alpha_esrgan:
767
+ gray = backend(np.ascontiguousarray(np.dstack([al, al, al])))
768
+ alpha = gray[..., 0]
769
+ if alpha.shape != (th, tw): # backend giả trong test có thể lệch
770
+ alpha = np.asarray(Image.fromarray(alpha, "L").resize((tw, th), Image.LANCZOS))
771
+ else:
772
+ alpha = np.asarray(Image.fromarray(al, "L").resize((tw, th), Image.LANCZOS))
773
+ return Image.fromarray(np.dstack([big, alpha]), "RGBA")
774
+
775
+
776
+ def _visible(img: Image.Image) -> np.ndarray:
777
+ """Ảnh RGBA ghép lên nền xám -> float32 HxWx3: đúng thứ MẮT THẤY.
778
+
779
+ Đo trên kênh RGB thô là sai: sau tách nền, vùng alpha 0 vẫn mang màu key, và mọi tiêu
780
+ chí sẽ bị màu vô hình đó chi phối thay vì bị chi phối bởi chủ thể.
781
+ """
782
+ a = np.asarray(img.convert("RGBA"), dtype=np.float32)
783
+ al = a[..., 3:4] / 255.0
784
+ return a[..., :3] * al + UPSCALE_GRAY * (1.0 - al)
785
+
786
+
787
+ def _grad_energy(g: np.ndarray) -> float:
788
+ """NĂNG LƯỢNG gradient (bình phương), KHÔNG phải độ lớn trung bình.
789
+
790
+ Phân biệt sắc/mờ phải dùng bình phương: một cạnh cao Δ trải qua s pixel có tổng |∇|
791
+ KHÔNG đổi (vẫn = Δ) nên |∇| trung bình mù với độ mờ; còn tổng ∇² tụt từ Δ² xuống
792
+ Δ²/s. Đây chính là chỗ LANCZOS thua và là lý do tiêu chí `blur` tồn tại.
793
+ """
794
+ gy = np.diff(g, axis=0)
795
+ gx = np.diff(g, axis=1)
796
+ return float((gy ** 2).mean() + (gx ** 2).mean())
797
+
798
+
799
+ def _local_minmax(v: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
800
+ """Min/max trong cửa sổ 3x3 cho từng kênh (numpy thuần)."""
801
+ lo, hi = v.copy(), v.copy()
802
+ for dy in (-1, 0, 1):
803
+ for dx in (-1, 0, 1):
804
+ if dy == 0 and dx == 0:
805
+ continue
806
+ # Ngoài biên coi như chính pixel đó -> không tạo ra cực trị giả ở mép ảnh.
807
+ s = _shift(v, dy, dx)
808
+ edge = _shift(np.ones(v.shape[:2], np.float32), dy, dx) == 0
809
+ s[edge] = v[edge]
810
+ lo = np.minimum(lo, s)
811
+ hi = np.maximum(hi, s)
812
+ return lo, hi
813
+
814
+
815
+ def score_upscale(src: Image.Image, out: Image.Image) -> dict:
816
+ """Chấm điểm một bản phóng to. ĐIỂM THẤP = TỐT (giống score_cutout).
817
+
818
+ XẾP HẠNG bằng hai tiêu chí, mỗi cái bắt một kiểu hỏng mà cái kia mù hoàn toàn:
819
+
820
+ blur Năng lượng gradient (bình phương) so với bản phóng NEAREST — NEAREST giữ
821
+ nguyên độ cao mọi bậc nhảy của ảnh gốc nên nó là trần lý thuyết của độ sắc.
822
+ Bắt ảnh MỀM NHŨN, đúng thứ LANCZOS luôn mắc phải khi phóng to.
823
+ ring Độ lớn TRUNG BÌNH mà pixel vượt ra ngoài biên min/max cục bộ của ảnh gốc
824
+ (đơn vị mức màu). Bắt QUẦNG SÁNG và chi tiết BỊA RA — thứ `blur` chấm
825
+ NGƯỢC: quầng làm gradient mạnh hơn nên blur tưởng là "sắc nét, tốt".
826
+
827
+ Hai tiêu chí còn lại được ĐO là KHÔNG có sức xếp hạng, nên chúng chỉ làm LƯỚI AN TOÀN
828
+ (loại thẳng), không kéo điểm:
829
+
830
+ lr_err Thu nhỏ bản phóng về đúng size gốc rồi so với gốc — chỗ duy nhất có sự thật
831
+ nền tuyệt đối. Nghe thì cứng nhất, nhưng nó thiên vị ảnh MỜ một cách có hệ
832
+ thống (đúng bài toán distortion–perception), nên dùng nó để xếp hạng là tự
833
+ tay chọn bản mờ. Vào tổng điểm với trọng số bé xíu, chỉ để phá thế hoà.
834
+ cov_err Chỉ cho ảnh RGBA: lệch alpha_coverage so với gốc. Bắt matte bị ăn mòn hoặc
835
+ phình ra. Đo được là quá thô để xếp hạng (matte hỏng vẫn cho cov_err 0.002),
836
+ nhưng vẫn chặn được ca phá hoại rõ rệt.
837
+ """
838
+ sw, sh = src.size
839
+ tw, th = out.size
840
+ vs = _visible(src)
841
+ vo = _visible(out)
842
+
843
+ # 1. back-projection: thu nhỏ bản phóng về size gốc rồi so với gốc.
844
+ back = out.resize((sw, sh), Image.LANCZOS)
845
+ lr_err = float(np.sqrt(((_visible(back) - vs) ** 2).mean()))
846
+
847
+ # 2. độ sắc, lấy bản NEAREST làm mốc trần.
848
+ nn = src.convert("RGBA").resize((tw, th), Image.NEAREST)
849
+ e_nn = _grad_energy(_visible(nn) @ np.array([0.299, 0.587, 0.114], np.float32))
850
+ e_out = _grad_energy(vo @ np.array([0.299, 0.587, 0.114], np.float32))
851
+ if e_nn <= UPSCALE_FLAT_ENERGY:
852
+ # Ảnh nguồn PHẲNG (mảng màu đặc, khung trơn): không có cạnh nào để mà làm sắc, nên
853
+ # "mờ" là khái niệm vô nghĩa ở đây. Không có nhánh này thì e_nn ~ 0 biến sharp thành
854
+ # 0/0 -> blur = 1.0 cho MỌI ứng viên, điểm bằng nhau, và bản thắng rơi vào tay thứ
855
+ # tự dict — tức là chọn bừa. Bắt được nhờ test end-to-end trên chủ thể màu đặc.
856
+ sharp, blur = 1.0, 0.0
857
+ else:
858
+ sharp = e_out / e_nn
859
+ blur = max(0.0, 1.0 - min(1.0, sharp))
860
+
861
+ # 3. quầng sáng: ĐỘ LỚN vượt biên trung bình (đơn vị mức màu 0..255), không phải SỐ
862
+ # ĐẾM pixel vượt biên. Bản đếm đã thử và bỏ: nó báo 27–37% pixel "ringing" trên ảnh
863
+ # đục, trong khi sai số thật lại nói bản đó TỐT HƠN — thứ nó đếm là vân nhiễu li ti
864
+ # của GAN (vượt biên 1–4 mức), không phải quầng. Quầng thật vượt biên hàng chục mức
865
+ # và nằm cạnh cạnh mạnh, nên đo độ lớn mới tách được hai thứ đó ra.
866
+ lo, hi = _local_minmax(vs)
867
+ yi = np.minimum((np.arange(th) * sh) // max(1, th), sh - 1)
868
+ xi = np.minimum((np.arange(tw) * sw) // max(1, tw), sw - 1)
869
+ over = 0.0
870
+ for c in range(3):
871
+ lo_c = lo[..., c][yi][:, xi]
872
+ hi_c = hi[..., c][yi][:, xi]
873
+ o_c = vo[..., c]
874
+ ex = np.maximum(np.maximum(o_c - hi_c, lo_c - o_c) - UPSCALE_RING_TOL, 0.0)
875
+ over += float(ex.mean())
876
+ ring = over / 3.0
877
+
878
+ cov_err = abs(alpha_coverage(out) - alpha_coverage(src))
879
+
880
+ m = {
881
+ "lr_err": lr_err,
882
+ "blur": blur,
883
+ "sharp": sharp,
884
+ "ring": ring,
885
+ "cov_err": cov_err,
886
+ }
887
+ dq: list[str] = []
888
+ if lr_err > UPSCALE_BAD_LR:
889
+ dq.append("bia_noi_dung")
890
+ if cov_err > UPSCALE_BAD_COV:
891
+ dq.append("lech_matte")
892
+ m["disqualified"] = dq
893
+
894
+ m["score"] = W_BLUR * blur + W_RING * ring + W_LR * lr_err + (10.0 if dq else 0.0)
895
+ return m
896
+
897
+
898
+ def best_upscale(img: Image.Image, target: tuple[int, int], backend=None) -> tuple[Image.Image, dict]:
899
+ """Phóng `img` lên đúng `target`, chạy NHIỀU cách rồi chấm điểm chọn bản tốt nhất.
900
+
901
+ Ứng viên:
902
+ lanczos Pillow LANCZOS thẳng tới đích. Luôn có, luôn là lưới an toàn.
903
+ esrgan Real-ESRGAN 4x (lặp tới khi đủ lớn, tối đa UPSCALE_MAX_PASS lượt) rồi
904
+ LANCZOS thu về đúng đích. Tốt nhất khi đích <= 4x.
905
+ esrgan-pre LANCZOS lên đích/4 TRƯỚC rồi mới 4x. Chỉ dựng khi đích > 4x: lúc đó
906
+ `esrgan` phải LANCZOS PHÓNG TO lần nữa sau model (mờ lại đúng thứ vừa
907
+ làm nét), còn cách này để model chạy sau cùng.
908
+
909
+ `backend=None` (thiếu torch) -> chỉ còn lanczos, vẫn trả ảnh đúng size. Model nổ giữa
910
+ chừng cũng vậy: ghi vào report["upscale_errors"] rồi đi tiếp, KHÔNG làm hỏng pipeline.
911
+ """
912
+ tw, th = int(target[0]), int(target[1])
913
+ sw, sh = img.size
914
+ factor = max(tw / max(1, sw), th / max(1, sh))
915
+ src = img.convert("RGBA")
916
+
917
+ cands: list[tuple[str, Image.Image]] = [("lanczos", src.resize((tw, th), Image.LANCZOS))]
918
+ errs: list[str] = []
919
+
920
+ if backend is not None and factor > UPSCALE_MIN_GAIN:
921
+ def _net(im: Image.Image, passes: int) -> Image.Image:
922
+ for _ in range(passes):
923
+ im = upscale_rgba(im, backend)
924
+ return im
925
+
926
+ passes = min(UPSCALE_MAX_PASS, max(1, math.ceil(math.log(max(factor, 1.0), 4) - 1e-9)))
927
+ try:
928
+ big = _net(src, passes)
929
+ cands.append(("esrgan", big.resize((tw, th), Image.LANCZOS)))
930
+ except Exception as e:
931
+ errs.append(f"esrgan: {type(e).__name__}: {e}")
932
+
933
+ if factor > 4.0:
934
+ try:
935
+ pre = src.resize((max(1, -(-tw // 4)), max(1, -(-th // 4))), Image.LANCZOS)
936
+ out = _net(pre, 1)
937
+ if out.size != (tw, th):
938
+ out = out.resize((tw, th), Image.LANCZOS)
939
+ cands.append(("esrgan-pre", out))
940
+ except Exception as e:
941
+ errs.append(f"esrgan-pre: {type(e).__name__}: {e}")
942
+
943
+ table: dict[str, dict] = {}
944
+ for name, im in cands:
945
+ try:
946
+ table[name] = score_upscale(src, im)
947
+ except Exception as e: # chấm điểm hỏng != ảnh hỏng
948
+ errs.append(f"score {name}: {type(e).__name__}: {e}")
949
+ table[name] = {"score": float("inf"), "disqualified": ["khong_cham_duoc"]}
950
+
951
+ best = min(table, key=lambda k: table[k]["score"])
952
+ report = {
953
+ "upscale_method": best,
954
+ "upscale_score": table[best]["score"],
955
+ "upscale_table": table,
956
+ "upscale_factor": round(factor, 4),
957
+ "upscale_from": [sw, sh],
958
+ "upscale_to": [tw, th],
959
+ "upscale_candidates": [n for n, _ in cands],
960
+ "upscale_all_disqualified": all(t.get("disqualified") for t in table.values()),
961
+ }
962
+ if errs:
963
+ report["upscale_errors"] = errs
964
+ return dict(cands)[best], report
965
+
966
+
967
+ # Bề dày vành ngoài dùng để kiểm nền, tính bằng pixel của ảnh Gemini sinh ra.
968
+ BORDER_PX = 4
969
+
970
+ # Vành ngoài lệch màu key quá mức này -> nền không phẳng (Gemini vẽ bóng/gradient/viền lên nền).
971
+ BAD_BORDER_DIST = 60.0
972
+
973
+
974
+ def border_impurity(img: Image.Image, key_hex: str, border: int = BORDER_PX) -> float:
975
+ """Khoảng cách trung bình của VÀNH NGOÀI ảnh so với màu key.
976
+
977
+ Kiểm nền một cách TRỰC TIẾP. alpha_coverage chỉ suy ra gián tiếp: nó chỉ nổ khi
978
+ nền hỏng TOÀN BỘ (coverage > 95%). Nền hỏng MỘT PHẦN — bóng đổ, gradient, viền —
979
+ thì coverage không thấy gì, mà mảng đặc đó lại thổi phồng solid_ratio và che mất
980
+ chủ thể bóng ma. Vành ngoài gần như luôn là nền thuần, nên đo thẳng vào đó.
981
+
982
+ GIẢ ĐỊNH CHƯA GHI RÕ TRƯỚC ĐÂY, nay ghi lại: hàm này giả định bản sinh của Gemini
983
+ CHỪA MỘT LỀ NỀN quanh chủ thể — tức là vành `border` px ngoài cùng thực sự là nền,
984
+ không phải một phần của chủ thể. Prompt gửi Gemini BẮT BUỘC phải yêu cầu điều này
985
+ ("chủ thể không được chạm mép ảnh"). Nếu Gemini vẫn vẽ chủ thể tràn sát mép canvas
986
+ (không chừa lề key nào) — có thật, asset `cell_base.png` của game có bbox phủ kín
987
+ cả canvas 249x249, nên một model được yêu cầu restyle nó hoàn toàn có thể vẽ tràn
988
+ mép — thì vành ngoài sẽ chứa pixel CHỦ THỂ chứ không phải nền, và hàm này sẽ báo
989
+ `bad_background` dù nền thật ra ổn (hoặc dù không hề có "nền" nào cả).
990
+
991
+ Đây là đánh đổi CÓ CHỦ ĐÍCH, không sửa: false positive (báo hỏng nhầm) là lỗi AN
992
+ TOÀN — cái giá là một lần sinh lại tốn kém vài giây, và asset lỗi không bao giờ lọt
993
+ được vào game. False negative (không báo hỏng) mới là thứ nguy hiểm — asset bị bóng
994
+ ma/nền lỗi sẽ lọt thẳng vào game. Nên giữa hai loại sai, hàm này LUÔN chọn nghiêng
995
+ về false positive. Xem test_border_impurity_false_positive_when_subject_touches_edge
996
+ để thấy ca này được đo và chấp nhận, không phải một bug chờ sửa.
997
+ """
998
+ rgb = np.asarray(img.convert("RGB"), dtype=np.uint8)
999
+ h, w = rgb.shape[:2]
1000
+ b = max(1, min(border, h // 2, w // 2))
1001
+
1002
+ ring = np.concatenate([
1003
+ rgb[:b, :, :].reshape(-1, 3),
1004
+ rgb[-b:, :, :].reshape(-1, 3),
1005
+ rgb[b:-b, :b, :].reshape(-1, 3),
1006
+ rgb[b:-b, -b:, :].reshape(-1, 3),
1007
+ ])
1008
+ return float(_dist_map(ring.reshape(1, -1, 3), hex_to_rgb(key_hex)).mean())
1009
+
1010
+
1011
+ def sample_border_color(img: Image.Image, border: int = BORDER_PX) -> tuple[str, float]:
1012
+ """Màu nền THẬT của bản sinh, đo từ vành ngoài `border`px, kèm độ thuần của vành.
1013
+
1014
+ Trả (hex, purity). purity = tỉ lệ pixel vành nằm trong BAD_BORDER_DIST quanh màu
1015
+ trung bình — purity cao nghĩa là vành thực sự là MỘT màu nền phẳng, và hex đó chính
1016
+ là màu key hiệu dụng để chroma_key.
1017
+
1018
+ Lý do tồn tại (đo thật): model có thể vẽ nền "xanh studio" (#2ED246, vignette nhẹ)
1019
+ thay vì #00FF00 được yêu cầu — chroma_key theo key yêu cầu khi đó trượt CẢ khung
1020
+ (coverage=1.0, bad_background) dù bản sinh hoàn toàn dùng được. Dò màu nền thật rồi
1021
+ key lại cứu được bản đó mà không tốn lượt sinh nào. Cùng giả định lề với
1022
+ border_impurity: vành ngoài phải là nền (prompt đã ép chủ thể chừa lề)."""
1023
+ rgb = np.asarray(img.convert("RGB"), dtype=np.float32)
1024
+ h, w = rgb.shape[:2]
1025
+ b = max(1, min(border, h // 2, w // 2))
1026
+ ring = np.concatenate([
1027
+ rgb[:b, :, :].reshape(-1, 3),
1028
+ rgb[-b:, :, :].reshape(-1, 3),
1029
+ rgb[b:-b, :b, :].reshape(-1, 3),
1030
+ rgb[b:-b, -b:, :].reshape(-1, 3),
1031
+ ])
1032
+ mean = ring.mean(axis=0)
1033
+ d = np.sqrt(((ring - mean) ** 2).sum(axis=1))
1034
+ purity = float((d <= BAD_BORDER_DIST).mean())
1035
+ return rgb_to_hex(tuple(int(round(float(x))) for x in mean)), purity
1036
+
1037
+
1038
+ # Ngưỡng cho lớp dọn nền SÓT (strip_bg_residue / bg_residue). Đo theo redmean, so với màu
1039
+ # nền ĐO ĐƯỢC (sample_border_color) — KHÔNG phải màu key yêu cầu. Vì sao: model gần như không
1040
+ # bao giờ vẽ đúng #00FF00; đo thật trên ảnh sinh ra là #0CF508 và #0BD009 (G=209!). Key theo màu
1041
+ # YÊU CẦU để lại tới 100% nền dưới dạng màng bán trong suốt, key theo màu ĐO ĐƯỢC thì sạch 0 px.
1042
+ BG_RESIDUE_TOL = 48.0 # sát màu nền đo được thì mới coi là nền sót (chặt, tránh gặm vào art)
1043
+ BAD_BG_RESIDUE = 0.02 # còn >2% pixel đục mang màu nền -> cờ bad_background
1044
+
1045
+
1046
+ def bg_residue(img: Image.Image, bg_hex: str, tol: float = BG_RESIDUE_TOL) -> float:
1047
+ """Tỉ lệ pixel ĐỤC vẫn đang mang màu nền — thước đo "tách nền còn bẩn không".
1048
+
1049
+ Thay cho border_impurity trên đường BEN2: border_impurity đo VÀNH ẢNH GỐC theo màu key,
1050
+ nên khi BEN2 chạy nó vô nghĩa và trước đây bị ép cứng `0.0` — tức KHÔNG cờ nào báo được
1051
+ nền còn sót, lỗi cứ thế đi thẳng vào asset. Hàm này đo trên ẢNH ĐÃ TÁCH nên đúng thứ cần biết.
1052
+ """
1053
+ arr = np.asarray(img.convert("RGBA"))
1054
+ opaque = arr[..., 3] > ALPHA_FLOOR
1055
+ if not opaque.any():
1056
+ return 0.0
1057
+ d = _dist_map(arr[..., :3].astype(np.float64), hex_to_rgb(bg_hex))
1058
+ return float((d[opaque] <= tol).mean())
1059
+
1060
+
1061
+ def strip_bg_residue(
1062
+ img: Image.Image, bg_hex: str, tol: float = BG_RESIDUE_TOL
1063
+ ) -> tuple[Image.Image, int]:
1064
+ """Xoá màng/vệt nền còn sót sau tách nền, theo MÀU NỀN ĐO ĐƯỢC. Trả (ảnh, số px đã xoá).
1065
+
1066
+ Chỉ xoá vùng màu-nền **LIỀN MẠCH với nền đã trong suốt** (hoặc chạm vành ảnh). Ràng buộc
1067
+ liên thông này là phần quan trọng nhất: bản thử nghiệm xoá theo màu/hue KHÔNG kèm liên
1068
+ thông đã gặm mép thành rỗ như mối ăn (đo thật trên ảnh bánh răng) vì nó đục cả những pixel
1069
+ art tình cờ trùng màu. Có liên thông thì art nằm trong lòng chủ thể không bao giờ bị chạm —
1070
+ muốn bị xoá, một vùng phải nối được ra tới nền thật.
1071
+
1072
+ KHÔNG cứu được ca model dùng chính hue của key làm MÀU NÉT trong tranh (vd viền xanh đậm
1073
+ quanh bánh răng): thứ đó là art thật, nằm kẹp giữa hai lớp art khác nên không liền mạch
1074
+ với nền, và về nguyên tắc không phân biệt được bằng màu. Ca đó phải chặn từ prompt —
1075
+ xem reference/prompt-template.md § Đừng để model dùng màu key làm màu nét.
1076
+ """
1077
+ arr = np.array(img.convert("RGBA"))
1078
+ alpha = arr[..., 3]
1079
+ d = _dist_map(arr[..., :3].astype(np.float64), hex_to_rgb(bg_hex))
1080
+ cand = d <= tol
1081
+ clear = alpha <= ALPHA_FLOOR
1082
+ if not cand.any():
1083
+ return img, 0
1084
+
1085
+ # Vùng để dò liên thông = pixel màu-nền CỘNG pixel đã trong suốt. Phải gộp cả pixel trong
1086
+ # suốt vào: nếu bộ tách nền xoá luôn RGB về 0 thì nền đã xoá không còn "màu nền" nữa và
1087
+ # mọi vệt sót sẽ mất đường nối ra ngoài.
1088
+ region = cand | clear
1089
+ rows, uf, _ = _components(region)
1090
+ find = uf["find"]
1091
+
1092
+ h, w = alpha.shape
1093
+ doomed: set[int] = set()
1094
+ for y, runs in enumerate(rows):
1095
+ edge_row = y == 0 or y == h - 1
1096
+ for s, e, lbl in runs:
1097
+ # Mầm: chạm nền đã trong suốt, hoặc chạm vành ảnh (theo hợp đồng prompt lề rộng,
1098
+ # vành ngoài là nền — cùng giả định của sample_border_color/border_impurity).
1099
+ if clear[y, s:e].any() or edge_row or s == 0 or e >= w:
1100
+ doomed.add(find(lbl))
1101
+ if not doomed:
1102
+ return img, 0
1103
+
1104
+ killed = 0
1105
+ for y, runs in enumerate(rows):
1106
+ for s, e, lbl in runs:
1107
+ if find(lbl) not in doomed:
1108
+ continue
1109
+ seg_a = arr[y, s:e, 3]
1110
+ seg_c = cand[y, s:e]
1111
+ hit = seg_c & (seg_a > ALPHA_FLOOR) # chỉ chạm pixel MÀU NỀN còn đang đục
1112
+ if hit.any():
1113
+ killed += int(hit.sum())
1114
+ seg_a[hit] = 0
1115
+ if not killed:
1116
+ return img, 0
1117
+ return Image.fromarray(arr, "RGBA"), killed
1118
+
1119
+
1120
+ def _erode_alpha(img: Image.Image, px: int = 1) -> Image.Image:
1121
+ """Bào rìa alpha `px` pixel bằng min-filter — cắt vành anti-alias/viền key còn
1122
+ sót quanh silhouette mà KHÔNG đổi màu pixel nào (chỉ hạ alpha ở mép). RGB giữ
1123
+ nguyên; chỉ kênh A co lại. `px<=0` -> trả nguyên ảnh."""
1124
+ if px <= 0:
1125
+ return img.convert("RGBA")
1126
+ rgba = img.convert("RGBA")
1127
+ a = rgba.getchannel("A")
1128
+ for _ in range(px):
1129
+ a = a.filter(ImageFilter.MinFilter(3))
1130
+ rgba.putalpha(a)
1131
+ return rgba
1132
+
1133
+
1134
+ # ══════════════════════════════════════════════════════════════════════════════════════════
1135
+ # Tách nền ĐA PHƯƠNG PHÁP: chạy nhiều cách, tự chấm điểm, lấy bản tốt nhất
1136
+ # ══════════════════════════════════════════════════════════════════════════════════════════
1137
+ # VÌ SAO không có MỘT phương pháp thắng mọi ảnh (đo thật, 10 cách trên 4 bản sinh):
1138
+ # • BEN2 hạng nhất trên asset rời có mép lông/tơ, nhưng trên ảnh NỀN full-bleed (thảm cỏ
1139
+ # tràn hết khung, không có "vật thể nổi bật") nó ăn mất 8.99% chủ thể và làm mép nhoè
1140
+ # thành dải 77.425 px — trong khi các cách theo màu chỉ ~1.500 px.
1141
+ # • chroma_key theo màu key YÊU CẦU để lại viền hồng nhìn thấy rõ, vì model vẽ #FB0EE0
1142
+ # chứ không phải #FF00FF được yêu cầu, và khoảng cách trung vị 57.7 chỉ còn 12 đơn vị
1143
+ # biên an toàn dưới t_low=70.
1144
+ # • Bề rộng dải anti-alias KHÁC NHAU theo nguồn: đo được 2px trên bản GPT nhưng 7–8px trên
1145
+ # bản Gemini (chân trời vẽ nhoè). Một hằng số cố định thì hoặc sót viền hoặc gặm chủ thể.
1146
+ # Nên cách đúng là ĐO rồi CHỌN, không phải chọn trước rồi tin.
1147
+
1148
+ CUTOUT_BAND_MAX = 12 # trần nới dải AA — trên mức này gần như chắc là đo sai
1149
+ CUTOUT_LOOSE_TOL = 60.0 # ngưỡng "coi như màu nền" khi dựng mask thô (redmean)
1150
+ CUTOUT_BAD_FG_LOSS = 0.02 # ăn >2% lòng chủ thể -> loại thẳng, không cần so điểm
1151
+ CUTOUT_MIN_BORDER_SHARE = 0.10 # mode viền phải chiếm >=10% vành mới tin là màu nền
1152
+
1153
+
1154
+ def modal_border_color(
1155
+ img: Image.Image, border: int = BORDER_PX, quant: int = 8,
1156
+ key_hex: str | None = None, max_dist: float = MIN_KEY_MARGIN,
1157
+ ) -> tuple[str, float]:
1158
+ """Màu nền trên vành ảnh theo MODE, kèm tỉ lệ vành mà nó chiếm. Trả (hex, share).
1159
+
1160
+ Khác `sample_border_color` ở chỗ dùng mode chứ không phải mean, và ĐÓ LÀ LÝ DO nó tồn
1161
+ tại: với ảnh NỀN full-bleed (nửa trên là trời màu key, nửa dưới là thảm cỏ tràn ra tận
1162
+ vành), mean trộn hai nửa thành bùn tím — đo thật trên home_grass/gpt1.png:
1163
+ sample_border_color trả `#AC4978` với purity **0.0002**, tức đường auto-key trong MCP
1164
+ KHÔNG BAO GIỜ kích hoạt và cả pipeline rơi về màu key yêu cầu. Mode trả `#FB0EE0`, đúng
1165
+ màu model đã vẽ.
1166
+
1167
+ `key_hex` (NÊN LUÔN TRUYỀN): chỉ xét pixel vành nằm trong `max_dist` quanh màu key YÊU
1168
+ CẦU, rồi lấy mode trong số đó. Không có nó thì mode toàn cục CHỈ ĐÚNG NHỜ MAY: nó thắng
1169
+ trên ảnh thật vì nền key phẳng còn thảm cỏ có vân (không bin xanh nào áp đảo), nhưng
1170
+ trên ảnh mà chủ thể PHẲNG và chiếm nhiều vành hơn nền thì mode trả về màu CHỦ THỂ — và
1171
+ key theo màu chủ thể sẽ xoá mất chính chủ thể. Ca này bắt được bằng test
1172
+ (`_plate` có nền xanh phẳng: vành có 1312 px xanh so với 1168 px hồng, mode toàn cục
1173
+ chọn XANH). Lọc theo màu key yêu cầu thì hết phụ thuộc vào vân bề mặt.
1174
+
1175
+ `quant` gộp màu về lưới 8 mức để nhiễu số hoá không xé mode thành nghìn bin riêng lẻ.
1176
+ share thấp (< CUTOUT_MIN_BORDER_SHARE) nghĩa là vành không có mảng màu-key nào đáng kể
1177
+ -> đừng tin, quay về màu key yêu cầu.
1178
+ """
1179
+ rgb = np.asarray(img.convert("RGB"), dtype=np.int32)
1180
+ h, w = rgb.shape[:2]
1181
+ b = max(1, min(border, h // 2, w // 2))
1182
+ ring = np.concatenate([
1183
+ rgb[:b, :, :].reshape(-1, 3),
1184
+ rgb[-b:, :, :].reshape(-1, 3),
1185
+ rgb[b:-b, :b, :].reshape(-1, 3),
1186
+ rgb[b:-b, -b:, :].reshape(-1, 3),
1187
+ ])
1188
+ total = len(ring)
1189
+ if not total:
1190
+ return "#000000", 0.0
1191
+
1192
+ if key_hex is not None:
1193
+ near = _dist_map(ring.reshape(1, -1, 3).astype(np.uint8), hex_to_rgb(key_hex))
1194
+ ring = ring[near.reshape(-1) <= max_dist]
1195
+ if not len(ring):
1196
+ return key_hex, 0.0
1197
+
1198
+ q = ring // quant
1199
+ keys = (q[:, 0] << 16) | (q[:, 1] << 8) | q[:, 2]
1200
+ vals, cnt = np.unique(keys, return_counts=True)
1201
+ top = vals[int(cnt.argmax())]
1202
+ share = float(cnt.max()) / float(total) # so với TOÀN vành, không chỉ phần đã lọc
1203
+ mean = ring[keys == top].mean(axis=0)
1204
+ return rgb_to_hex(tuple(int(round(float(x))) for x in mean)), share
1205
+
1206
+
1207
+ def _dilate(mask: np.ndarray, px: int = 1) -> np.ndarray:
1208
+ """Nới mask `px` pixel theo 4 hướng (numpy thuần — không có scipy trong môi trường này)."""
1209
+ out = mask
1210
+ for _ in range(max(0, px)):
1211
+ p = np.pad(out, 1, constant_values=False)
1212
+ out = out | p[:-2, 1:-1] | p[2:, 1:-1] | p[1:-1, :-2] | p[1:-1, 2:]
1213
+ return out
1214
+
1215
+
1216
+ def _frame_mask(mask: np.ndarray) -> np.ndarray:
1217
+ """Chỉ giữ những vùng liền mạch của `mask` có CHẠM vành ảnh — tức nền thật.
1218
+
1219
+ Cùng ràng buộc liên thông với strip_bg_residue, và cùng một lý do: art nằm trong lòng
1220
+ chủ thể mà tình cờ trùng màu nền thì không nối được ra vành, nên không bao giờ bị xoá.
1221
+ """
1222
+ if not mask.any():
1223
+ return np.zeros_like(mask)
1224
+ rows, uf, _ = _components(mask)
1225
+ find = uf["find"]
1226
+ h, w = mask.shape
1227
+ good: set[int] = set()
1228
+ for y, runs in enumerate(rows):
1229
+ for s, e, lbl in runs:
1230
+ if y == 0 or y == h - 1 or s == 0 or e == w:
1231
+ good.add(find(lbl))
1232
+ out = np.zeros_like(mask)
1233
+ for y, runs in enumerate(rows):
1234
+ for s, e, lbl in runs:
1235
+ if find(lbl) in good:
1236
+ out[y, s:e] = True
1237
+ return out
1238
+
1239
+
1240
+ def _cutout_regions(img: Image.Image, bg_hex: str) -> dict:
1241
+ """Các vùng dùng để CHẤM ĐIỂM, dựng từ ảnh gốc — KHÔNG từ đầu ra của cách nào cả.
1242
+
1243
+ Mọi phương pháp phải được đo trên cùng một bộ vùng, nếu không thì so điểm là vô nghĩa.
1244
+ Trả dict: hard (nền chắc chắn), band (dải AA đã đo bề rộng), far (lòng chủ thể), band_w.
1245
+ """
1246
+ u8 = np.asarray(img.convert("RGB"))
1247
+ bg = hex_to_rgb(bg_hex)
1248
+ d = _dist_map(u8, bg)
1249
+ hard = _frame_mask(d <= CUTOUT_LOOSE_TOL)
1250
+
1251
+ out = {"hard": hard, "d": d, "band_w": 0,
1252
+ "band": np.zeros_like(hard), "far": ~hard, "d_fg": float(np.percentile(d, 95))}
1253
+ if not hard.any():
1254
+ return out
1255
+
1256
+ outer = ~_dilate(hard, CUTOUT_BAND_MAX + 4)
1257
+ out["d_fg"] = float(np.median(d[outer])) if outer.any() else float(np.percentile(d, 95))
1258
+
1259
+ # Bề rộng dải AA ĐO TỪ ẢNH, không phải hằng số: nới từng ring một, dừng khi ring đã
1260
+ # gần như tiền cảnh thuần. Đo thật: bản GPT dừng ở 2, bản Gemini đi tới 7–8.
1261
+ k, prev = 0, hard
1262
+ while k < CUTOUT_BAND_MAX:
1263
+ cur = _dilate(hard, k + 1)
1264
+ ring = cur & ~prev
1265
+ if not ring.any():
1266
+ break
1267
+ k += 1
1268
+ if float(np.median(d[ring])) >= 0.90 * out["d_fg"]:
1269
+ break # ring này gần như fg thuần -> đã lấy nó rồi thì dừng
1270
+ prev = cur
1271
+ out["band_w"] = max(1, k)
1272
+ out["band"] = _dilate(hard, out["band_w"]) & ~hard
1273
+ out["far"] = ~_dilate(hard, out["band_w"] + 3)
1274
+ return out
1275
+
1276
+
1277
+ def unmix_cutout(
1278
+ img: Image.Image, bg_hex: str, regions: dict | None = None
1279
+ ) -> tuple[Image.Image, dict]:
1280
+ """Tách nền bằng NGHỊCH ĐẢO ĐẠI SỐ phương trình ghép ảnh. Trả (RGBA, info).
1281
+
1282
+ despill là heuristic kẹp kênh. Nhưng ta ĐO ĐƯỢC màu nền, nên đảo thẳng được:
1283
+
1284
+ O = F·α + BG·(1−α) -> F = (O − BG·(1−α)) / α
1285
+
1286
+ α lấy từ ramp tuyến tính theo khoảng cách màu trên dải AA (bề rộng đo từ ảnh), 0 trong
1287
+ vùng nền liền-vành, 255 ngoài dải. Kiểm chứng bằng roundtrip (ghép kết quả trở lại lên
1288
+ màu nền rồi so với ảnh gốc): sai số trên dải mềm **0.228** so với 25.09 của region-grow
1289
+ +despill và 16.45 của chroma_key+despill. Nới rộng dải là AN TOÀN vì α tính từ khoảng
1290
+ cách màu thật — pixel đã là tiền cảnh thuần thì tự nhận α=255, nằm trong dải cũng không
1291
+ bị hạ. Đo thật: cast (px còn ám màu nền khi ghép lên trắng/đen) = 0 trên cả 4 bản sinh.
1292
+ """
1293
+ u8 = np.asarray(img.convert("RGB"))
1294
+ rgb = u8.astype(np.float64)
1295
+ r = regions if regions is not None else _cutout_regions(img, bg_hex)
1296
+ hard, band, d = r["hard"], r["band"], r["d"]
1297
+ bg = np.array(hex_to_rgb(bg_hex), dtype=np.float64)
1298
+
1299
+ info = {"band_w": r["band_w"], "bg_hex": bg_hex, "soft_px": 0,
1300
+ "clipped_px": 0, "hard_frac": float(hard.mean())}
1301
+ if not hard.any():
1302
+ # Không có vùng màu-nền nào chạm vành -> không có gì để xoá. Trả ảnh đục nguyên vẹn
1303
+ # thay vì đoán bừa; lớp chấm điểm sẽ thấy bg_residue cao và loại nó nếu có cách khác.
1304
+ return Image.fromarray(
1305
+ np.dstack([u8, np.full(u8.shape[:2], 255, np.uint8)]), "RGBA"), info
1306
+
1307
+ base = float(np.percentile(d[hard], 98))
1308
+ span = max(1e-6, r["d_fg"] - base)
1309
+ alpha = np.where(hard, 0.0, 255.0)
1310
+ if band.any():
1311
+ alpha[band] = np.clip((d[band] - base) / span, 0.0, 1.0) * 255.0
1312
+
1313
+ a = (alpha / 255.0)[..., None]
1314
+ F = rgb.copy()
1315
+ solve = band & (alpha > ALPHA_FLOOR) & (alpha < 255.0)
1316
+ if solve.any():
1317
+ with np.errstate(divide="ignore", invalid="ignore"):
1318
+ cand = (rgb - bg[None, None, :] * (1.0 - a)) / np.maximum(a, 1e-6)
1319
+ info["clipped_px"] = int(((cand < -10) | (cand > 265)).any(axis=2)[solve].sum())
1320
+ F[solve] = np.clip(cand[solve], 0.0, 255.0)
1321
+ info["soft_px"] = int(solve.sum())
1322
+
1323
+ out = np.dstack([F, alpha])
1324
+ return Image.fromarray(np.rint(out).clip(0, 255).astype(np.uint8), "RGBA"), info
1325
+
1326
+
1327
+ def score_cutout(src: Image.Image, out: Image.Image, bg_hex: str,
1328
+ regions: dict | None = None) -> dict:
1329
+ """Chấm điểm một bản tách nền — KHÔNG cần ảnh tham chiếu. Điểm THẤP là tốt.
1330
+
1331
+ Bốn thành phần, mỗi cái bắt một kiểu hỏng khác nhau; thiếu bất kỳ cái nào là mở đường
1332
+ cho một cách dở thắng điểm:
1333
+ • cast — số px còn ÁM MÀU NỀN khi ghép lên trắng/đen. Bắt "viền hồng/xanh còn
1334
+ sót". Đo trên dải AA lấy từ ẢNH GỐC nên mọi cách chịu cùng một thước.
1335
+ • f_err — màu tiền cảnh lệch bao nhiêu so với nghịch đảo đại số. Bắt "giữ nguyên
1336
+ màu đã bị nền trộn vào". Một mình nó KHÔNG đủ: cách nào để alpha=255
1337
+ khắp dải sẽ có f_err=0 hiển nhiên (vì khi α=1 thì F_ideal ≡ O) — chính
1338
+ `cast` mới bắt được ca đó.
1339
+ • fg_loss — % lòng chủ thể (vùng `far`) bị làm không-đục. Bắt "ăn mất chủ thể":
1340
+ BEN2 trên ảnh nền full-bleed đo được 8.99%.
1341
+ • bg_residue— % px đục vẫn mang màu nền. Bắt "để nguyên nền".
1342
+ Giả định: chủ thể ĐỤC ở trong lòng (đúng với asset game trên phông key phẳng). Chủ thể
1343
+ trong suốt thật (kính, khói) sẽ bị fg_loss phạt oan — khi đó dùng multi=False.
1344
+ """
1345
+ r = regions if regions is not None else _cutout_regions(src, bg_hex)
1346
+ O = np.asarray(src.convert("RGB"), dtype=np.float64)
1347
+ arr = np.asarray(out.convert("RGBA"), dtype=np.float64)
1348
+ al, F = arr[..., 3], arr[..., :3]
1349
+ bg = np.array(hex_to_rgb(bg_hex), dtype=np.float64)
1350
+
1351
+ m: dict = {}
1352
+ far, band = r["far"], r["band"]
1353
+
1354
+ # `far` (lòng chủ thể) chỉ có nghĩa khi TÌM ĐƯỢC vùng màu nền. Nếu không có pixel nào
1355
+ # mang màu key chạm vành — ảnh chụp/tranh nền thật, không có phông key — thì `hard` rỗng,
1356
+ # `far` biến thành TOÀN ẢNH, và fg_loss quay ra đo "bao nhiêu phần ảnh không đục", tức
1357
+ # PHẠT ĐÚNG cách đã tách nền thành công. Bug thật đã gặp: BEN2 tách đúng chủ thể
1358
+ # (coverage 0.156 so với diện tích thật 0.181) nhưng bị loại với fg_loss 0.8484, và bản
1359
+ # KHÔNG LÀM GÌ CẢ thắng, giao ra ảnh nguyên vẹn. Khi không có phông key thì bỏ hẳn tiêu
1360
+ # chí này và để `coverage` làm cửa gác — nó loại đúng những cách phủ kín khung.
1361
+ fg_valid = bool(r["hard"].any()) and bool(far.any())
1362
+ m["fg_loss"] = float((al[far] < 247).mean()) if fg_valid else 0.0
1363
+ m["fg_loss_valid"] = fg_valid
1364
+ m["bg_residue"] = bg_residue(out, bg_hex)
1365
+ m["coverage"] = float((al > ALPHA_FLOOR).mean())
1366
+ m["soft_px"] = int(((al > ALPHA_FLOOR) & (al < 247)).sum())
1367
+
1368
+ # cast: hướng sắc của pixel đã ghép có trùng hướng sắc của màu nền không (không phụ
1369
+ # thuộc hue cụ thể -> dùng được cho cả key xanh lá và key hồng).
1370
+ vb = bg - bg.mean()
1371
+ nb = float(np.linalg.norm(vb))
1372
+ zone = band & (al > ALPHA_FLOOR)
1373
+ cast = 0
1374
+ if nb > 1e-6 and zone.any():
1375
+ for back in (255.0, 32.0):
1376
+ aa = (al[zone] / 255.0)[:, None]
1377
+ comp = F[zone] * aa + back * (1.0 - aa)
1378
+ u = comp - comp.mean(axis=1, keepdims=True)
1379
+ nu = np.linalg.norm(u, axis=1)
1380
+ cos = (u @ vb) / np.maximum(nu * nb, 1e-6)
1381
+ cast += int(((cos > 0.85) & (nu > 12.0)).sum())
1382
+ m["cast"] = cast
1383
+
1384
+ soft = band & (al > ALPHA_FLOOR) & (al < 247)
1385
+ if soft.sum() >= 50:
1386
+ aa = (al[soft] / 255.0)[:, None]
1387
+ ideal = (O[soft] - bg[None, :] * (1.0 - aa)) / np.maximum(aa, 1e-6)
1388
+ m["f_err"] = float(np.abs(F[soft] - np.clip(ideal, 0.0, 255.0)).mean())
1389
+ else:
1390
+ m["f_err"] = 0.0
1391
+
1392
+ aa = (al / 255.0)[..., None]
1393
+ m["roundtrip"] = float(np.abs(F * aa + bg[None, None, :] * (1.0 - aa) - O).mean())
1394
+
1395
+ # Loại thẳng (không so điểm) những kiểu hỏng mà không đánh đổi nào bù được.
1396
+ dq = []
1397
+ if m["fg_loss"] > CUTOUT_BAD_FG_LOSS:
1398
+ dq.append("an_chu_the")
1399
+ if m["bg_residue"] > BAD_BG_RESIDUE:
1400
+ dq.append("sot_nen")
1401
+ if m["coverage"] < BAD_LOW or m["coverage"] > BAD_HIGH:
1402
+ dq.append("phu_bat_thuong")
1403
+ m["disqualify"] = dq
1404
+
1405
+ band_n = max(1, int(band.sum()))
1406
+ m["score"] = (3.0 * cast / band_n
1407
+ + 1.0 * m["f_err"] / 255.0
1408
+ + 0.5 * m["roundtrip"] / 255.0
1409
+ + 2.0 * m["fg_loss"]
1410
+ + 2.0 * m["bg_residue"])
1411
+ return m
1412
+
1413
+
1414
+ def best_cutout(
1415
+ img: Image.Image, key_hex: str, bg_hex: str | None = None, cutout=None
1416
+ ) -> tuple[Image.Image, dict]:
1417
+ """Chạy NHIỀU cách tách nền, chấm điểm từng cách, trả bản điểm tốt nhất.
1418
+
1419
+ Trả (RGBA, report). report["cutout_method"] là tên cách đã thắng, report["cutout_table"]
1420
+ là bảng điểm ĐẦY ĐỦ của mọi cách (kể cả cách bị loại) để người duyệt thấy VÌ SAO nó thắng.
1421
+
1422
+ `bg_hex` bỏ trống -> tự đo bằng modal_border_color, nhưng chỉ nhận nếu vừa chiếm đủ
1423
+ vành vừa KHÔNG lệch màu key yêu cầu quá MIN_KEY_MARGIN. Cửa gác thứ hai đó là để chặn ca
1424
+ chủ thể tràn sát vành: khi đó màu đo được là màu CHỦ THỂ (vẫn "thuần" một màu!) và key
1425
+ theo nó sẽ xoá mất chính chủ thể. Ngưỡng 190 là ĐO ĐƯỢC, không phải đoán: độ lệch
1426
+ model-vẽ-so-với-yêu-cầu đo trên 6 bản sinh nằm trong 6.0–96.5, còn khoảng cách từ màu key
1427
+ tới màu chủ thể thật là 353–536. 190 nằm giữa với biên ~2× cả hai phía.
1428
+ """
1429
+ # Lọc theo màu key yêu cầu NGAY trong modal_border_color: mode toàn cục có thể trả về
1430
+ # màu CHỦ THỂ khi chủ thể phẳng và chiếm nhiều vành hơn nền (xem docstring hàm đó).
1431
+ sampled, share = modal_border_color(img, key_hex=key_hex)
1432
+ chosen, why = bg_hex, "duoc_truyen_vao"
1433
+ if chosen is None:
1434
+ if share >= CUTOUT_MIN_BORDER_SHARE:
1435
+ chosen, why = sampled, "mode_vien"
1436
+ else:
1437
+ chosen, why = key_hex, "khong_thay_mau_key_o_vien"
1438
+
1439
+ regions = _cutout_regions(img, chosen)
1440
+ cands: list[tuple[str, Image.Image]] = []
1441
+
1442
+ unm, unm_info = unmix_cutout(img, chosen, regions)
1443
+ cands.append(("unmix", unm))
1444
+ cands.append(("chroma-bg", despill(chroma_key(img, chosen), chosen)))
1445
+ if color_dist(hex_to_rgb(chosen), hex_to_rgb(key_hex)) > 1.0:
1446
+ # Lưới an toàn: nếu màu đo được sai thì key theo màu YÊU CẦU vẫn còn đó để thắng.
1447
+ cands.append(("chroma-key", despill(chroma_key(img, key_hex), key_hex)))
1448
+ if cutout is not None:
1449
+ try:
1450
+ ben = cutout(img)
1451
+ if ben.mode != "RGBA":
1452
+ ben = ben.convert("RGBA")
1453
+ cands.append(("ben2", _erode_alpha(ben, 1)))
1454
+ except Exception as exc: # noqa: BLE001
1455
+ cands.append(("ben2-loi", None)) # ghi lại để báo cáo
1456
+ del exc
1457
+
1458
+ table = []
1459
+ ranked: list[tuple[float, str, Image.Image]] = []
1460
+ for name, im in cands:
1461
+ if im is None:
1462
+ table.append({"method": name, "error": True})
1463
+ continue
1464
+ s = score_cutout(img, im, chosen, regions)
1465
+ s["method"] = name
1466
+ table.append(s)
1467
+ if not s["disqualify"]:
1468
+ ranked.append((s["score"], name, im))
1469
+
1470
+ table.sort(key=lambda t: (bool(t.get("error")), bool(t.get("disqualify")), t.get("score", 9e9)))
1471
+ if ranked:
1472
+ ranked.sort(key=lambda t: t[0])
1473
+ win_score, win_name, win_img = ranked[0]
1474
+ else:
1475
+ # Mọi cách đều bị loại -> lấy cách điểm thấp nhất trong số không-lỗi và NÓI RA,
1476
+ # không âm thầm trả ảnh rỗng. Cờ bad_* của postprocess vẫn sẽ bắt tiếp.
1477
+ ok = [t for t in table if not t.get("error")]
1478
+ win_name = ok[0]["method"] if ok else "unmix"
1479
+ win_score = ok[0]["score"] if ok else float("nan")
1480
+ win_img = dict(cands)[win_name] if win_name in dict(cands) else unm
1481
+
1482
+ report = {
1483
+ "cutout_method": win_name,
1484
+ "cutout_score": win_score,
1485
+ "cutout_table": table,
1486
+ "cutout_candidates": [n for n, _ in cands],
1487
+ "bg_color_used": chosen,
1488
+ "bg_source": why,
1489
+ "bg_sampled_mode": sampled,
1490
+ "bg_mode_share": share,
1491
+ "band_w": regions["band_w"],
1492
+ "unmix_info": unm_info,
1493
+ "all_disqualified": not ranked,
1494
+ }
1495
+ return win_img, report
1496
+
1497
+
1498
+ def postprocess(
1499
+ gen: Image.Image,
1500
+ key_hex: str,
1501
+ src: Image.Image | None = None,
1502
+ size: tuple[int, int] | None = None,
1503
+ cutout=None,
1504
+ bg_hex: str | None = None,
1505
+ multi: bool = True,
1506
+ full_bleed: bool = False,
1507
+ upscale=None,
1508
+ ) -> tuple[Image.Image | None, dict]:
1509
+ """Ảnh Gemini thô -> asset game dùng được ngay.
1510
+
1511
+ Mặc định BÁM GỐC: canvas = size của src, nội dung căn vào đúng bbox của src
1512
+ -> thay 1-1 vào game, không phải chỉnh anchor/hitbox/layout.
1513
+ Truyền `size` để ép ra kích thước khác (asset hoàn toàn mới).
1514
+
1515
+ `cutout`: hàm (Image -> RGBA) để TÁCH NỀN. Truyền vào thì dùng nó (vd BEN2
1516
+ qua bgremove.remove_background) — segmentation ngữ nghĩa, không cần màu key,
1517
+ không viền xanh. BỎ TRỐNG -> quay về chroma-key + despill như cũ (đường mặc
1518
+ định, thuần, test offline được). `key_hex` vẫn cần cho despeckle/báo cáo.
1519
+
1520
+ `bg_hex`: màu nền THẬT đo từ bản sinh (sample_border_color). Truyền vào thì MỌI phép
1521
+ dựa-trên-màu dùng nó thay cho `key_hex`: chroma_key, despill và lớp dọn nền sót. Đây là
1522
+ thứ quyết định độ sạch — model gần như không bao giờ vẽ đúng màu key được yêu cầu (đo
1523
+ thật: yêu cầu #00FF00, model vẽ #0CF508 và #0BD009), và key theo màu yêu cầu có thể để
1524
+ lại NGUYÊN nền dưới dạng màng bán trong suốt. Bỏ trống -> dùng `key_hex` như cũ.
1525
+
1526
+ `multi` (MẶC ĐỊNH BẬT): chạy NHIỀU cách tách nền qua best_cutout() rồi lấy bản chấm
1527
+ điểm tốt nhất, thay vì tin sẵn một cách. Không có cách nào thắng mọi ảnh — đo thật 10
1528
+ cách trên 4 bản sinh: BEN2 hạng nhất ở asset rời nhưng ăn mất 8.99% chủ thể ở ảnh nền
1529
+ full-bleed; chroma_key theo màu key yêu cầu để lại viền hồng thấy rõ; bề rộng dải AA
1530
+ khác nhau 2px vs 7–8px tuỳ nguồn. `cutout` khi đó là MỘT ứng viên (không còn độc quyền).
1531
+ Tắt (`multi=False`) khi chủ thể trong suốt thật (kính, khói) — fg_loss sẽ phạt oan.
1532
+
1533
+ `full_bleed`: BẬT cho ảnh NỀN tràn viền (background plate, thumbnail) — tranh phủ kín
1534
+ khung, chủ thể CHẠM vành ảnh là đúng thiết kế. Nó tắt duy nhất cửa gác `border_impurity`,
1535
+ KHÔNG tắt `bg_residue`/`coverage`/bộ chấm điểm.
1536
+
1537
+ VÌ SAO phải là THAM SỐ chứ không tự suy ra: `border_impurity` giả định vành ảnh toàn là
1538
+ nền. Với ảnh nền full-bleed giả định đó sai (đo thật home_grass/gpt1.png: thảm cỏ tràn ra
1539
+ vành dưới và hai vành bên) nên nó báo bad_background trên một bản tách nền HOÀN HẢO —
1540
+ cast 0, bg_residue 0.0000 — và cả 4 bản sinh đều bị đánh hỏng. Đó không còn là "một lượt
1541
+ sinh lại tốn kém" như docstring border_impurity chấp nhận, mà là chặn vĩnh viễn cả một
1542
+ lớp asset. Nhưng KHÔNG suy ra được từ pixel: "thảm cỏ chạm vành dưới" và "mảng xám panel
1543
+ chưa key chạm vành trên" đều là nội dung đục chạm vành, chỉ khác Ý ĐỊNH. Tỉ lệ vành mang
1544
+ màu key cũng không tách được hai ca: đo tay 0.552 ở ca CẦN gác (test_postprocess_flags_
1545
+ partial_background_failure) so với 0.225–0.390 ở ảnh nền cần TẮT gác — quá gần nhau để
1546
+ đặt ngưỡng. Nên người gọi phải nói ra. Mặc định False giữ nguyên hành vi cũ.
1547
+
1548
+ `upscale`: hàm phóng 4x mảng HxWx3 uint8 (upscale.upscale_rgb). CHỈ dùng khi bản sinh
1549
+ NHỎ HƠN khung đích — lúc đó LANCZOS chỉ trải mép ra cho mềm chứ không thêm được gì.
1550
+ Cũng chạy nhiều cách rồi chấm điểm chọn (xem best_upscale). Bỏ trống -> LANCZOS như cũ.
1551
+ """
1552
+ bg_for_color = bg_hex or key_hex
1553
+ multi_rep: dict | None = None
1554
+ diag: Image.Image | None = None
1555
+ if multi:
1556
+ keyed, multi_rep = best_cutout(gen, key_hex, bg_hex=bg_hex, cutout=cutout)
1557
+ bg_for_color = multi_rep["bg_color_used"]
1558
+ # Ảnh CHẨN ĐOÁN, tách khỏi ảnh GIAO RA. Đây là điểm dễ hiểu sai nhất của khối này.
1559
+ #
1560
+ # Toàn bộ lớp cờ của postprocess đọc alpha theo NGỮ NGHĨA RAMP MỀM của chroma_key:
1561
+ # "có nội dung nhưng không đục" (ALPHA_FLOOR < a < SOLID_ALPHA) chính là cách nó
1562
+ # phát hiện chủ thể bóng ma, lỗ khoét giữa thân, và mảng nền chưa key. `unmix` lại
1563
+ # cố ý cho alpha GẦN NHƯ NHỊ PHÂN — đúng cái làm nó sạch — nên nếu đo cờ trên đầu ra
1564
+ # của nó thì mọi tín hiệu đó biến mất: đo thật, 4 test defect (viên ngọc giữa thân,
1565
+ # bóng ma, mảng xám chưa key, hai-lỗi-cùng-lúc) đều tụt xuống status "ok".
1566
+ #
1567
+ # Nhưng các chỉ số đó trả lời câu "BẢN SINH có dùng được không?", không phải câu
1568
+ # "thuật toán tách nền nào sạch hơn?" — chúng độc lập với việc sau đó ta cắt bằng gì.
1569
+ # Nên: cờ đo trên bản chroma_key (giữ nguyên hợp đồng đời cũ), pixel giao ra lấy từ
1570
+ # bản thắng điểm. `bg_residue` thì vẫn đo trên bản GIAO RA, vì nó hỏi đúng câu
1571
+ # "ảnh mình sắp ghi ra có còn bẩn không".
1572
+ diag = chroma_key(gen, bg_for_color)
1573
+ impurity = None
1574
+ elif cutout is not None:
1575
+ # Đường BEN2: alpha đã là segmentation của chủ thể, không dính màu nền
1576
+ # -> border_impurity (đo theo màu key) VÔ NGHĨA ở đây, ép 0 để không báo
1577
+ # nhầm bad_background. Coverage>BAD_HIGH vẫn là cửa gác thật (segmentation
1578
+ # trượt, phủ nguyên khung -> đục hết).
1579
+ keyed = cutout(gen)
1580
+ if keyed.mode != "RGBA":
1581
+ keyed = keyed.convert("RGBA")
1582
+ # BEN2 đôi khi gộp cả dải anti-alias (nơi Gemini blend chủ thể với nền
1583
+ # key) vào mask ĐỤC -> viền xanh mảnh bám theo silhouette, rõ nhất trên chủ
1584
+ # thể sáng/viền trắng như logo. despill CHỈ chạm pixel bán trong suốt nên
1585
+ # KHÔNG dọn được dải đục này. Bào 1px alpha (min-filter) cắt đúng vành ngoài
1586
+ # đó — an toàn màu (không declamp xanh nên hoa xanh/teal không hề hấn), chỉ
1587
+ # thu silhouette 1px. Sau đó despill dọn nốt mép mềm mới lộ ra.
1588
+ keyed = _erode_alpha(keyed, 1)
1589
+ impurity = 0.0
1590
+ else:
1591
+ keyed = chroma_key(gen, bg_for_color)
1592
+ impurity = None # tính bằng border_impurity bên dưới
1593
+
1594
+ # Dọn nền SÓT rồi ĐO độ bẩn — cả hai việc phải làm TRƯỚC despill. despill kéo kênh màu key
1595
+ # xuống, nên sau nó nền sót không còn mang màu nền nữa và mọi phép so-màu đều mù: đo thật
1596
+ # trên ca nền sống sót 100% khung, chạy sau despill thì bg_residue báo 0.0000 và lớp dọn xoá
1597
+ # được 0 px. Đây cũng là lý do despill KHÔNG còn nằm chung dòng với chroma_key/cutout ở trên.
1598
+ keyed, bg_killed = strip_bg_residue(keyed, bg_for_color)
1599
+ residue = bg_residue(keyed, bg_for_color)
1600
+ if not multi:
1601
+ keyed = despill(keyed, bg_for_color)
1602
+ # Ở đường multi TUYỆT ĐỐI KHÔNG despill lần nữa. Hai lý do, cả hai đều làm ảnh XẤU ĐI:
1603
+ # 1. Ứng viên nào CẦN despill thì đã được despill ngay trong best_cutout() rồi
1604
+ # (`chroma-bg`, `chroma-key`) — chạy lần hai là kẹp kênh hai lần.
1605
+ # 2. Với bản `unmix` thắng, F đã là NGHIỆM CHÍNH XÁC của phương trình ghép ảnh.
1606
+ # despill chỉ chạm pixel alpha<255 — tức đúng dải AA mà unmix vừa giải xong — nên
1607
+ # nó sẽ kéo nghiệm đúng lệch trở lại về phía heuristic kẹp kênh. Đo thật: sai màu
1608
+ # tiền cảnh 0.44/255 sau unmix, chạy thêm despill thì vọt lên hàng chục.
1609
+
1610
+ # Despeckle TRƯỚC khi đo bất cứ chỉ số nào: watermark ✦ của Gemini là một mảng ĐỤC HOÀN
1611
+ # TOÀN ~580px ở góc dưới-phải mọi ảnh nó sinh. Để nguyên thì nó vừa hiện thành chấm xanh
1612
+ # trong asset, vừa làm lệch coverage/solid_ratio/bbox/hole_ratio. Đo sau khi dọn mới đúng.
1613
+ keyed, speckles = despeckle(keyed)
1614
+ keyed, wm = strip_gemini_watermark(keyed) # diệt hẳn dấu ✦ ở góc dưới-phải nếu despeckle sót
1615
+ speckles += wm
1616
+
1617
+ if impurity is None:
1618
+ impurity = border_impurity(gen, bg_for_color)
1619
+
1620
+ if diag is not None:
1621
+ # Cùng chuỗi dọn dẹp như bản giao ra, để cờ đo trên ảnh tương đương — chỉ khác là
1622
+ # bản này CÓ despill (đúng ngữ nghĩa đời cũ mà lớp cờ được thiết kế quanh nó).
1623
+ diag, _ = strip_bg_residue(diag, bg_for_color)
1624
+ diag = despill(diag, bg_for_color)
1625
+ diag, _ = despeckle(diag)
1626
+ diag, _ = strip_gemini_watermark(diag)
1627
+ metric_img = diag
1628
+ else:
1629
+ metric_img = keyed
1630
+
1631
+ coverage = alpha_coverage(metric_img)
1632
+ solid = solid_ratio(metric_img)
1633
+ bbox = content_bbox(metric_img)
1634
+ holes = hole_ratio(metric_img, bbox)
1635
+
1636
+ # bbox dùng để CẮT ảnh giao ra thì phải lấy từ chính ảnh giao ra, không phải từ bản
1637
+ # chẩn đoán: hai bản có silhouette khác nhau (unmix giữ lại vùng mà chroma_key khoét
1638
+ # thủng), cắt theo bbox của bản kia sẽ lệch khung.
1639
+ out_bbox = content_bbox(keyed) if diag is not None else bbox
1640
+
1641
+ flags: list[str] = []
1642
+ # `residue` là cửa gác THẬT cho đường BEN2 (ở đó impurity bị ép 0 vì đo theo vành ảnh gốc
1643
+ # là vô nghĩa). Đo trên ảnh ĐÃ tách nên bắt được đúng thứ trước đây trôi lọt.
1644
+ impurity_gates = not full_bleed # xem docstring `full_bleed`
1645
+ if ((impurity_gates and impurity > BAD_BORDER_DIST)
1646
+ or coverage > BAD_HIGH or residue > BAD_BG_RESIDUE):
1647
+ flags.append("bad_background")
1648
+ # Ở đường multi, bộ chấm điểm là một cửa gác ĐỘC LẬP: mọi ứng viên đều bị loại nghĩa là
1649
+ # KHÔNG cách nào tách sạch được bản sinh này (nền sót, hoặc ăn chủ thể, hoặc phủ bất
1650
+ # thường) -> đó là lỗi của BẢN SINH, cần sinh lại, chứ không phải chọn bản đỡ tệ nhất
1651
+ # rồi im lặng đi tiếp.
1652
+ elif multi_rep is not None and multi_rep.get("all_disqualified"):
1653
+ flags.append("bad_background")
1654
+
1655
+ # Finding I3: coverage thấp MỘT MÌNH không còn nghĩa là "hỏng" — icon/line-art nhỏ
1656
+ # (vd nút X 12px nét) đo được coverage=0.0161 < BAD_LOW nhưng solid_ratio=1.0, một
1657
+ # bản sinh HOÀN HẢO bị bản cũ vứt bỏ (trả None) vì "nhỏ" bị đánh đồng với "hỏng", và
1658
+ # retry đổi màu key không thể cứu ca này vì màu key chưa từng là vấn đề. bad_subject
1659
+ # giờ chỉ bật khi chủ thể THẬT SỰ bị phá huỷ: bbox rỗng hoàn toàn, HOẶC vừa nhỏ vừa
1660
+ # không đục (ăn thủng thành bóng ma mờ). "Nhỏ nhưng đặc" không phải lỗi.
1661
+ bad_subject = bbox is None or (coverage < BAD_LOW and solid < BAD_SOLID_RATIO)
1662
+ if bad_subject:
1663
+ flags.append("bad_subject")
1664
+ elif coverage < BAD_LOW:
1665
+ flags.append("sparse") # thông tin, KHÔNG phải lỗi — xem docstring ở trên
1666
+
1667
+ # Lưu ý: nếu bad_background đã lên tiếng thì solid_ratio KHÔNG còn đáng tin — mảng nền
1668
+ # hỏng (bóng/gradient/viền chưa key) tự nó đã đục, bơm phồng solid_ratio giả, không phản
1669
+ # ánh chủ thể thật (xem test_postprocess_flags_partial_background_failure). ĐỪNG bỏ
1670
+ # border_impurity đi với lý do "solid_ratio đã bắt được rồi" — nó không bắt được ca này.
1671
+ if solid < BAD_SOLID_RATIO:
1672
+ flags.append("bad_translucent")
1673
+
1674
+ # Finding I2: cờ THAM KHẢO, không phải gate cứng — xem docstring hole_ratio(). KHÔNG
1675
+ # ép bad_subject, KHÔNG trả None chỉ vì bad_holes — contact sheet mới là cửa gác thật.
1676
+ if bbox is not None and holes > BAD_HOLE_RATIO:
1677
+ flags.append("bad_holes")
1678
+
1679
+ report: dict = {
1680
+ "status": flags[0] if flags else "ok", # nặng nhất trước; xem thứ tự append ở trên
1681
+ "flags": flags, # BÁO ĐỦ: một bản sinh có thể hỏng nhiều kiểu
1682
+ "coverage": coverage,
1683
+ "solid_ratio": solid, # luôn báo cáo, kể cả khi ok — người duyệt cần thấy con số
1684
+ "border_impurity": impurity,
1685
+ "bg_residue": residue, # tỉ lệ pixel đục còn mang màu nền SAU khi dọn
1686
+ "bg_px_removed": bg_killed, # số px nền sót mà strip_bg_residue đã xoá
1687
+ "bg_color_used": bg_for_color, # màu thực sự dùng để key/despill/dọn sót
1688
+ "hole_ratio": holes, # luôn báo cáo, kể cả khi ok — xem hole_ratio() (advisory)
1689
+ "speckles_removed": speckles, # >0 là bình thường: watermark Gemini luôn bị dọn
1690
+ "key": key_hex,
1691
+ "full_bleed": full_bleed,
1692
+ # Nói RÕ border_impurity có quyền phủ quyết hay không, để người đọc report không phải
1693
+ # đoán vì sao một impurity cao lại không sinh ra cờ nào.
1694
+ "impurity_gated": impurity_gates,
1695
+ }
1696
+ if multi_rep is not None:
1697
+ # Báo cáo ĐỦ bảng điểm, kể cả ứng viên bị loại: người duyệt cần thấy VÌ SAO cách này
1698
+ # thắng, chứ không chỉ thấy tên nó.
1699
+ report.update({k: multi_rep[k] for k in (
1700
+ "cutout_method", "cutout_score", "cutout_table", "cutout_candidates",
1701
+ "bg_source", "bg_sampled_mode", "bg_mode_share", "band_w", "all_disqualified",
1702
+ )})
1703
+ # coverage/solid_ratio ở trên đo trên bản CHẨN ĐOÁN (xem khối diag). Hai số dưới đây
1704
+ # đo trên bản THỰC SỰ GIAO RA, để chênh lệch giữa chúng không bị che đi.
1705
+ report["out_coverage"] = alpha_coverage(keyed)
1706
+ report["out_solid_ratio"] = solid_ratio(keyed)
1707
+
1708
+ if bad_subject:
1709
+ report["status"] = "bad_subject"
1710
+ return None, report
1711
+
1712
+ if size is not None:
1713
+ canvas_size = size
1714
+ target_box = (0, 0, size[0], size[1])
1715
+ elif src is not None:
1716
+ canvas_size = src.size
1717
+ target_box = content_bbox(src) or (0, 0, src.size[0], src.size[1])
1718
+ else:
1719
+ raise ValueError("postprocess() cần `src` hoặc `size`")
1720
+
1721
+ report["size"] = canvas_size
1722
+ report["target_box"] = target_box
1723
+ out = fit_into(keyed.crop(out_bbox or bbox), canvas_size, target_box,
1724
+ upscale=upscale, report=report)
1725
+ return out, report
1726
+
1727
+
1728
+ LABEL_H = 20
1729
+ SHEET_LIGHT = (240, 240, 240)
1730
+ SHEET_DARK = (28, 28, 32)
1731
+ SHEET_CHECKER = ((205, 205, 205), (170, 170, 170))
1732
+ CHECKER_SIZE = 8
1733
+
1734
+
1735
+ # ── Thumbnail cửa hàng: 3 tỉ lệ cố định ─────────────────────────────────────────────────
1736
+ # Model sinh ảnh KHÔNG cho chọn kích thước đầu ra — nó trả size riêng của nó. Đo thật trên
1737
+ # Gemini web: yêu cầu dọc → 864x1216 (0.7105), ngang → 1376x768 (1.7917), vuông → 1024x1024
1738
+ # (1.0000). Tức nó TÔN TRỌNG HƯỚNG và rơi rất sát mục tiêu, nên đường đi đúng là: sinh ở tỉ lệ
1739
+ # gần nhất → cắt bù phần lệch (đo được ≤1%) → resize về ĐÚNG số pixel yêu cầu.
1740
+ # Giá trị dưới đây theo yêu cầu cửa hàng: 1:1 tối thiểu 512x512, 5:7 đúng 540x756,
1741
+ # 16:9 tối thiểu 1280x720. Với 1:1 giao 1024 thay vì 512 vì nguồn vốn đã 1024 — hạ xuống 512
1742
+ # là bỏ chi tiết không lý do (yêu cầu là SÀN, không phải trần).
1743
+ THUMB_PRESETS: dict[str, tuple[int, int]] = {
1744
+ "1:1": (1024, 1024),
1745
+ "5:7": (540, 756),
1746
+ "16:9": (1280, 720),
1747
+ }
1748
+
1749
+
1750
+ def fit_thumb(
1751
+ img: Image.Image, target: tuple[int, int], anchor: str = "center", upscale=None
1752
+ ) -> tuple[Image.Image, dict]:
1753
+ """Cắt về đúng tỉ lệ `target` rồi resize về ĐÚNG số pixel đó. Trả (ảnh, info).
1754
+
1755
+ KHÔNG tách nền, KHÔNG bám bbox asset gốc — thumbnail là tranh full-bleed, khác hẳn đường
1756
+ restyle asset. Đừng đưa ảnh thumb qua postprocess/process_raws.
1757
+
1758
+ `anchor` quyết định giữ phần nào khi cắt: "center" (mặc định), "top", "bottom", "left",
1759
+ "right". Thumb dọc hay đặt logo/tiêu đề ở trên → dùng "top" cho chắc.
1760
+
1761
+ info: src, target, crop (hộp đã cắt), lost_frac (tỉ lệ pixel bị cắt bỏ), scale,
1762
+ upscaled (True nếu phải PHÓNG TO — ảnh sẽ mềm, nên biết mà sinh lại to hơn).
1763
+ """
1764
+ tw, th = int(target[0]), int(target[1])
1765
+ if tw <= 0 or th <= 0:
1766
+ raise ValueError(f"target không hợp lệ: {target!r}")
1767
+ w, h = img.size
1768
+ ta, sa = tw / th, w / h
1769
+
1770
+ if sa > ta: # nguồn RỘNG hơn mục tiêu -> cắt bớt chiều ngang
1771
+ cw, ch = max(1, round(h * ta)), h
1772
+ else: # nguồn CAO hơn -> cắt bớt chiều dọc
1773
+ cw, ch = w, max(1, round(w / ta))
1774
+ cw, ch = min(cw, w), min(ch, h)
1775
+
1776
+ if anchor == "left":
1777
+ x0, y0 = 0, (h - ch) // 2
1778
+ elif anchor == "right":
1779
+ x0, y0 = w - cw, (h - ch) // 2
1780
+ elif anchor == "top":
1781
+ x0, y0 = (w - cw) // 2, 0
1782
+ elif anchor == "bottom":
1783
+ x0, y0 = (w - cw) // 2, h - ch
1784
+ else:
1785
+ x0, y0 = (w - cw) // 2, (h - ch) // 2
1786
+
1787
+ box = (x0, y0, x0 + cw, y0 + ch)
1788
+ out = img.crop(box)
1789
+ info = {
1790
+ "src": [w, h],
1791
+ "target": [tw, th],
1792
+ "crop": list(box),
1793
+ "lost_frac": 1.0 - (cw * ch) / float(w * h),
1794
+ "scale": tw / float(cw),
1795
+ "upscaled": tw > cw or th > ch,
1796
+ }
1797
+ if out.size != (tw, th):
1798
+ if info["upscaled"] and tw / float(cw) > UPSCALE_MIN_GAIN:
1799
+ out, up_rep = best_upscale(out, (tw, th), backend=upscale)
1800
+ info.update(up_rep)
1801
+ else:
1802
+ out = out.resize((tw, th), Image.LANCZOS)
1803
+ return out, info
1804
+
1805
+
1806
+ def _checker(size: tuple[int, int]) -> Image.Image:
1807
+ """Nền caro — kiểu 'ô cờ' của Photoshop. Lộ rõ pixel bán trong suốt."""
1808
+ w, h = size
1809
+ a, b = SHEET_CHECKER
1810
+ tile = np.zeros((h, w, 3), dtype=np.uint8)
1811
+ yy, xx = np.mgrid[0:h, 0:w]
1812
+ odd = ((xx // CHECKER_SIZE) + (yy // CHECKER_SIZE)) % 2 == 1
1813
+ tile[...] = a
1814
+ tile[odd] = b
1815
+ return Image.fromarray(tile, "RGB")
1816
+
1817
+
1818
+ def _bg(size: tuple[int, int], row: int) -> Image.Image:
1819
+ if row == 0:
1820
+ return Image.new("RGB", size, SHEET_LIGHT)
1821
+ if row == 1:
1822
+ return Image.new("RGB", size, SHEET_DARK)
1823
+ return _checker(size)
1824
+
1825
+
1826
+ def _contain(img: Image.Image, box: int) -> Image.Image:
1827
+ w, h = img.size
1828
+ s = min(box / max(1, w), box / max(1, h))
1829
+ return img.resize((max(1, round(w * s)), max(1, round(h * s))), Image.LANCZOS)
1830
+
1831
+
1832
+ def make_sheet(
1833
+ cells: list[tuple[str, Image.Image]], cell: int = 160, pad: int = 12
1834
+ ) -> Image.Image:
1835
+ """Lưới so sánh: mỗi cột 1 ảnh, mỗi hàng 1 nền (sáng / tối / caro).
1836
+
1837
+ Ba nền là có chủ đích: nền sáng lộ viền tối, nền tối lộ viền sáng và spill,
1838
+ nền caro lộ vùng bán trong suốt. Một nền thôi là sẽ bỏ sót lỗi.
1839
+ """
1840
+ n = max(1, len(cells))
1841
+ width = n * (cell + pad) + pad
1842
+ height = 3 * (cell + pad) + pad + LABEL_H
1843
+
1844
+ sheet = Image.new("RGB", (width, height), (255, 255, 255))
1845
+ draw = ImageDraw.Draw(sheet)
1846
+
1847
+ for col, (label, img) in enumerate(cells):
1848
+ x = pad + col * (cell + pad)
1849
+ draw.text((x, 4), label[:22], fill=(0, 0, 0))
1850
+
1851
+ thumb = _contain(img.convert("RGBA"), cell)
1852
+ for row in range(3):
1853
+ y = LABEL_H + pad + row * (cell + pad)
1854
+ tile = _bg((cell, cell), row)
1855
+ tile.paste(thumb, ((cell - thumb.width) // 2, (cell - thumb.height) // 2), thumb)
1856
+ sheet.paste(tile, (x, y))
1857
+
1858
+ return sheet
1859
+
1860
+
1861
+ def _png_b64(img: Image.Image) -> str:
1862
+ """Ảnh -> chuỗi base64 PNG (RGBA) để nhúng thẳng vào HTML (self-contained)."""
1863
+ buf = io.BytesIO()
1864
+ img.convert("RGBA").save(buf, "PNG")
1865
+ return base64.b64encode(buf.getvalue()).decode("ascii")
1866
+
1867
+
1868
+ def compare_sheet(
1869
+ groups: list[tuple[str, Image.Image | None, list[tuple[str, Image.Image]]]],
1870
+ cell: int = 240,
1871
+ ) -> str:
1872
+ """Trang HTML ĐỐI CHIẾU gốc↔mới, tự chứa. Đây là bản giao cho user sau MỖI lượt thiết kế.
1873
+
1874
+ Khác `web_sheet` (lưới thẻ phẳng, mọi ảnh ngang hàng): ở đây ảnh được NHÓM THEO ASSET,
1875
+ bản gốc nằm ngay cạnh các biến thể của chính nó, và mỗi thẻ biến thể lật được về gốc
1876
+ NGAY TẠI CHỖ (nhấn giữ; nháy đúp để khoá). Đặt chồng đúng một vị trí và một kích thước
1877
+ là cách duy nhất thấy được lệch hình dạng/tỉ lệ nhỏ — hai thẻ nằm cạnh nhau thì mắt
1878
+ không bắt được. Lô nhiều asset mà không nhóm lại thì user phải tự nhớ ảnh nào của asset
1879
+ nào; đó là lý do gom nhóm chứ không phải để trang trí.
1880
+
1881
+ `groups`: list (tên asset, ảnh gốc | None, [(nhãn, ảnh biến thể), ...]).
1882
+ Gốc = None thì thẻ chỉ hiện biến thể, không có nút lật (vd cells screen-sheet vốn
1883
+ không có asset gốc 1-1).
1884
+
1885
+ Ảnh gốc được nhúng MỘT LẦN cho mỗi nhóm rồi gán bằng JS lúc lật, chứ không nhúng lại
1886
+ trong từng thẻ — một lô 10 asset × 4 biến thể mà nhúng lặp thì file phình vô ích.
1887
+ """
1888
+ origs: list[str] = []
1889
+ sections: list[str] = []
1890
+
1891
+ for gi, (name, orig, variants) in enumerate(groups):
1892
+ nm = _html.escape(str(name))[:60]
1893
+ cards = []
1894
+
1895
+ if orig is not None:
1896
+ origs.append(_png_b64(orig))
1897
+ ow, oh = orig.size
1898
+ cards.append(
1899
+ '<figure class="card is-orig">'
1900
+ f'<figcaption><span class="lbl">GỐC</span>'
1901
+ f'<span class="dim">{ow}×{oh}</span></figcaption>'
1902
+ f'<div class="stage"><img src="data:image/png;base64,{origs[-1]}" '
1903
+ f'alt="{nm} gốc" loading="lazy"></div>'
1904
+ "</figure>"
1905
+ )
1906
+ else:
1907
+ origs.append("")
1908
+
1909
+ for label, img in variants:
1910
+ w, h = img.size
1911
+ lbl = _html.escape(str(label))[:40]
1912
+ flip = (
1913
+ f'<img class="ov" data-g="{gi}" alt="" loading="lazy">'
1914
+ if orig is not None else ""
1915
+ )
1916
+ cards.append(
1917
+ f'<figure class="card{" can-flip" if orig is not None else ""}" data-g="{gi}">'
1918
+ f'<figcaption><span class="lbl">{lbl}</span>'
1919
+ f'<span class="state"></span>'
1920
+ f'<span class="dim">{w}×{h}</span></figcaption>'
1921
+ f'<div class="stage"><img class="nw" '
1922
+ f'src="data:image/png;base64,{_png_b64(img)}" alt="{lbl}" loading="lazy">'
1923
+ f"{flip}</div>"
1924
+ "</figure>"
1925
+ )
1926
+
1927
+ sections.append(
1928
+ f'<section class="grp"><h2>{nm}'
1929
+ f'<span class="cnt">{len(variants)} bản</span></h2>'
1930
+ f'<div class="row">{"".join(cards)}</div></section>'
1931
+ )
1932
+
1933
+ doc = """<!doctype html><html lang="vi"><head><meta charset="utf-8">
1934
+ <meta name="viewport" content="width=device-width,initial-scale=1">
1935
+ <title>game-art — đối chiếu gốc / mới</title>
1936
+ <style>
1937
+ :root{--cell:__CELL__px;--custom:#3aa675;color-scheme:dark light}
1938
+ *{box-sizing:border-box}
1939
+ body{margin:0;background:#0d1117;color:#e6edf3;font:14px/1.5 system-ui,Segoe UI,sans-serif}
1940
+ header{position:sticky;top:0;z-index:5;background:#161b22e6;backdrop-filter:blur(8px);
1941
+ border-bottom:1px solid #30363d;padding:12px 20px;display:flex;gap:14px;align-items:center;flex-wrap:wrap}
1942
+ h1{font-size:16px;margin:0 12px 0 0}
1943
+ .seg{display:inline-flex;border:1px solid #30363d;border-radius:8px;overflow:hidden}
1944
+ .seg button{background:#0d1117;color:#adbac7;border:0;padding:6px 12px;cursor:pointer;font:inherit}
1945
+ .seg button+button{border-left:1px solid #30363d}
1946
+ .seg button.on{background:#1f6feb;color:#fff}
1947
+ label.ctl{display:inline-flex;gap:6px;align-items:center;color:#8b949e}
1948
+ input[type=range]{width:130px}
1949
+ input[type=color]{width:30px;height:26px;border:1px solid #30363d;border-radius:6px;background:none;padding:0}
1950
+ .hint{color:#8b949e;font-size:12px;margin-left:auto}
1951
+ .hint kbd{background:#21262d;border:1px solid #30363d;border-radius:4px;padding:1px 5px;font:inherit}
1952
+ main{padding:20px}
1953
+ .grp{margin:0 0 26px}
1954
+ .grp h2{font-size:14px;margin:0 0 10px;padding-bottom:7px;border-bottom:1px solid #30363d;
1955
+ display:flex;align-items:center;gap:10px;color:#e6edf3}
1956
+ .cnt{color:#8b949e;font-weight:400;font-size:12px}
1957
+ .row{display:grid;gap:14px;grid-template-columns:repeat(auto-fill,minmax(var(--cell),1fr))}
1958
+ .card{background:#161b22;border:1px solid #30363d;border-radius:10px;overflow:hidden}
1959
+ .card.is-orig{border-color:#8957e5}
1960
+ .card.can-flip{cursor:pointer;user-select:none}
1961
+ figcaption{display:flex;justify-content:space-between;align-items:center;gap:8px;
1962
+ padding:7px 10px;font-size:12px;border-bottom:1px solid #30363d}
1963
+ .lbl{font-weight:600;color:#e6edf3}
1964
+ .is-orig .lbl{color:#d2a8ff}
1965
+ .dim{color:#8b949e;font-variant-numeric:tabular-nums}
1966
+ .state{margin-left:auto;font-size:11px;color:#8b949e}
1967
+ .showing-orig .state{color:#d2a8ff;font-weight:600}
1968
+ .stage{position:relative;height:var(--cell);display:flex;align-items:center;justify-content:center;padding:8px}
1969
+ .stage img{max-width:100%;max-height:100%;object-fit:contain}
1970
+ .ov{position:absolute;inset:8px;margin:auto;display:none}
1971
+ .showing-orig .nw{visibility:hidden}
1972
+ .showing-orig .ov{display:block}
1973
+ [data-bg=light] .stage{background:#f2f2f2}
1974
+ [data-bg=dark] .stage{background:#181818}
1975
+ [data-bg=custom] .stage{background:var(--custom)}
1976
+ [data-bg=checker] .stage{background-color:#fff;background-image:
1977
+ linear-gradient(45deg,#c9c9c9 25%,transparent 25%,transparent 75%,#c9c9c9 75%),
1978
+ linear-gradient(45deg,#c9c9c9 25%,transparent 25%,transparent 75%,#c9c9c9 75%);
1979
+ background-size:22px 22px;background-position:0 0,11px 11px}
1980
+ </style></head>
1981
+ <body data-bg="checker">
1982
+ <header>
1983
+ <h1>\U0001f3ae game-art — đối chiếu gốc / mới</h1>
1984
+ <div class="seg" id="bgseg">
1985
+ <button data-b="checker" class="on">Caro</button>
1986
+ <button data-b="light">Sáng</button>
1987
+ <button data-b="dark">Tối</button>
1988
+ <button data-b="custom">Màu</button>
1989
+ </div>
1990
+ <label class="ctl">Nền <input type="color" id="pick" value="#3aa675"></label>
1991
+ <label class="ctl">Zoom <input type="range" id="zoom" min="140" max="560" value="__CELL__"></label>
1992
+ <div class="seg"><button id="allorig">Xem tất cả bản GỐC</button></div>
1993
+ <div class="hint"><kbd>nhấn giữ</kbd> lật về gốc · <kbd>nháy đúp</kbd> khoá</div>
1994
+ </header>
1995
+ <main>
1996
+ __SECTIONS__
1997
+ </main>
1998
+ <script>
1999
+ var ORIG=__ORIGS__;
2000
+ var body=document.body,root=document.documentElement;
2001
+ document.querySelectorAll('#bgseg button').forEach(function(b){
2002
+ b.onclick=function(){
2003
+ document.querySelectorAll('#bgseg button').forEach(function(x){x.classList.remove('on')});
2004
+ b.classList.add('on'); body.dataset.bg=b.dataset.b;
2005
+ };
2006
+ });
2007
+ var pick=document.getElementById('pick');
2008
+ pick.oninput=function(){
2009
+ root.style.setProperty('--custom',pick.value);
2010
+ body.dataset.bg='custom';
2011
+ document.querySelectorAll('#bgseg button').forEach(function(x){x.classList.toggle('on',x.dataset.b==='custom')});
2012
+ };
2013
+ document.getElementById('zoom').oninput=function(){root.style.setProperty('--cell',this.value+'px')};
2014
+
2015
+ // Ảnh gốc chỉ gán src lúc CẦN, từ bảng ORIG nhúng một lần mỗi nhóm — tránh lặp base64.
2016
+ function fill(card){
2017
+ var ov=card.querySelector('.ov');
2018
+ if(ov && !ov.getAttribute('src')) ov.src=ORIG[card.dataset.g];
2019
+ }
2020
+ function show(card,on){
2021
+ if(!card.classList.contains('can-flip')) return;
2022
+ fill(card);
2023
+ card.classList.toggle('showing-orig',on);
2024
+ var s=card.querySelector('.state'); if(s) s.textContent=on?'đang xem GỐC':'';
2025
+ }
2026
+ document.querySelectorAll('.card.can-flip').forEach(function(card){
2027
+ card.addEventListener('pointerdown',function(){show(card,true)});
2028
+ card.addEventListener('pointerup',function(){if(card.dataset.lock!=='1')show(card,false)});
2029
+ card.addEventListener('pointerleave',function(){if(card.dataset.lock!=='1')show(card,false)});
2030
+ card.addEventListener('dblclick',function(){
2031
+ card.dataset.lock=card.dataset.lock==='1'?'0':'1';
2032
+ show(card,card.dataset.lock==='1');
2033
+ });
2034
+ });
2035
+ var all=false,btn=document.getElementById('allorig');
2036
+ btn.onclick=function(){
2037
+ all=!all; btn.classList.toggle('on',all);
2038
+ btn.textContent=all?'Xem tất cả bản MỚI':'Xem tất cả bản GỐC';
2039
+ document.querySelectorAll('.card.can-flip').forEach(function(c){
2040
+ c.dataset.lock=all?'1':'0'; show(c,all);
2041
+ });
2042
+ };
2043
+ </script>
2044
+ </body></html>"""
2045
+ return (doc.replace("__CELL__", str(int(cell)))
2046
+ .replace("__SECTIONS__", "\n".join(sections))
2047
+ .replace("__ORIGS__", _json.dumps(
2048
+ {i: (f"data:image/png;base64,{b}" if b else "") for i, b in enumerate(origs)})))
2049
+
2050
+
2051
+ def web_sheet(cells: list[tuple[str, Image.Image]], cell: int = 240) -> str:
2052
+ """Trang HTML DUYỆT BẰNG MẮT, tự chứa (nhúng base64 PNG) — thay contact sheet tĩnh.
2053
+
2054
+ Ưu điểm so với PNG: đổi nền TRỰC TIẾP (sáng/tối/caro/màu tùy chọn) để soi mép cutout
2055
+ và vùng bán trong suốt, kéo slider phóng to từng ảnh, không cần mở Photoshop. Một file
2056
+ HTML duy nhất, mở bằng trình duyệt nào cũng chạy, không phụ thuộc file ngoài.
2057
+
2058
+ `cells`: list (nhãn, ảnh RGBA) — vd [("original", src), ("v1", var1), ...].
2059
+ """
2060
+ cards = []
2061
+ for label, img in cells:
2062
+ w, h = img.size
2063
+ lbl = _html.escape(str(label))[:40]
2064
+ cards.append(
2065
+ '<figure class="card">'
2066
+ f'<figcaption><span class="lbl">{lbl}</span>'
2067
+ f'<span class="dim">{w}×{h}</span></figcaption>'
2068
+ f'<div class="stage"><img src="data:image/png;base64,{_png_b64(img)}" '
2069
+ f'alt="{lbl}" loading="lazy"></div>'
2070
+ "</figure>"
2071
+ )
2072
+ grid = "\n".join(cards)
2073
+
2074
+ doc = """<!doctype html><html lang="vi"><head><meta charset="utf-8">
2075
+ <meta name="viewport" content="width=device-width,initial-scale=1">
2076
+ <title>game-art — review cutout</title>
2077
+ <style>
2078
+ :root{--cell:__CELL__px;--custom:#3aa675;color-scheme:dark light}
2079
+ *{box-sizing:border-box}
2080
+ body{margin:0;background:#0d1117;color:#e6edf3;font:14px/1.5 system-ui,Segoe UI,sans-serif}
2081
+ header{position:sticky;top:0;z-index:5;background:#161b22e6;backdrop-filter:blur(8px);
2082
+ border-bottom:1px solid #30363d;padding:12px 20px;display:flex;gap:14px;align-items:center;flex-wrap:wrap}
2083
+ h1{font-size:16px;margin:0 12px 0 0}
2084
+ .seg{display:inline-flex;border:1px solid #30363d;border-radius:8px;overflow:hidden}
2085
+ .seg button{background:#0d1117;color:#adbac7;border:0;padding:6px 12px;cursor:pointer;font:inherit}
2086
+ .seg button+button{border-left:1px solid #30363d}
2087
+ .seg button.on{background:#1f6feb;color:#fff}
2088
+ label.ctl{display:inline-flex;gap:6px;align-items:center;color:#8b949e}
2089
+ input[type=range]{width:130px}
2090
+ input[type=color]{width:30px;height:26px;border:1px solid #30363d;border-radius:6px;background:none;padding:0}
2091
+ main{padding:20px;display:grid;gap:16px;grid-template-columns:repeat(auto-fill,minmax(var(--cell),1fr))}
2092
+ .card{background:#161b22;border:1px solid #30363d;border-radius:10px;overflow:hidden}
2093
+ figcaption{display:flex;justify-content:space-between;align-items:center;padding:7px 10px;font-size:12px;border-bottom:1px solid #30363d}
2094
+ .lbl{font-weight:600;color:#e6edf3}
2095
+ .dim{color:#8b949e;font-variant-numeric:tabular-nums}
2096
+ .stage{height:var(--cell);display:flex;align-items:center;justify-content:center;padding:8px}
2097
+ .stage img{max-width:100%;max-height:100%;object-fit:contain;image-rendering:auto}
2098
+ [data-bg=light] .stage{background:#f2f2f2}
2099
+ [data-bg=dark] .stage{background:#181818}
2100
+ [data-bg=custom] .stage{background:var(--custom)}
2101
+ [data-bg=checker] .stage{background-color:#fff;background-image:
2102
+ linear-gradient(45deg,#c9c9c9 25%,transparent 25%,transparent 75%,#c9c9c9 75%),
2103
+ linear-gradient(45deg,#c9c9c9 25%,transparent 25%,transparent 75%,#c9c9c9 75%);
2104
+ background-size:22px 22px;background-position:0 0,11px 11px}
2105
+ </style></head>
2106
+ <body data-bg="checker">
2107
+ <header>
2108
+ <h1>\U0001f3ae game-art — review</h1>
2109
+ <div class="seg" id="bgseg">
2110
+ <button data-b="checker" class="on">Caro</button>
2111
+ <button data-b="light">Sáng</button>
2112
+ <button data-b="dark">Tối</button>
2113
+ <button data-b="custom">Màu</button>
2114
+ </div>
2115
+ <label class="ctl">Nền <input type="color" id="pick" value="#3aa675"></label>
2116
+ <label class="ctl">Zoom <input type="range" id="zoom" min="140" max="560" value="__CELL__"></label>
2117
+ </header>
2118
+ <main id="grid">
2119
+ __GRID__
2120
+ </main>
2121
+ <script>
2122
+ var body=document.body,root=document.documentElement;
2123
+ document.querySelectorAll('#bgseg button').forEach(function(b){
2124
+ b.onclick=function(){
2125
+ document.querySelectorAll('#bgseg button').forEach(function(x){x.classList.remove('on')});
2126
+ b.classList.add('on'); body.dataset.bg=b.dataset.b;
2127
+ };
2128
+ });
2129
+ var pick=document.getElementById('pick');
2130
+ pick.oninput=function(){
2131
+ root.style.setProperty('--custom',pick.value);
2132
+ body.dataset.bg='custom';
2133
+ document.querySelectorAll('#bgseg button').forEach(function(x){x.classList.toggle('on',x.dataset.b==='custom')});
2134
+ };
2135
+ document.getElementById('zoom').oninput=function(){root.style.setProperty('--cell',this.value+'px')};
2136
+ </script>
2137
+ </body></html>"""
2138
+ return doc.replace("__CELL__", str(int(cell))).replace("__GRID__", grid)