@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.
- package/.agents/plugins/marketplace.json +20 -0
- package/.agents/skills/bmad-advanced-elicitation/SKILL.md +64 -0
- package/.agents/skills/bmad-advanced-elicitation/assets/methods.csv +72 -0
- package/.agents/skills/bmad-advanced-elicitation/customize.toml +54 -0
- package/.agents/skills/bmad-advanced-elicitation/scripts/pick_methods.py +233 -0
- package/.agents/skills/bmad-advanced-elicitation/scripts/tests/test_pick_methods.py +228 -0
- package/.agents/skills/bmad-agent-analyst/SKILL.md +76 -0
- package/.agents/skills/bmad-agent-analyst/customize.toml +103 -0
- package/.agents/skills/bmad-agent-architect/SKILL.md +76 -0
- package/.agents/skills/bmad-agent-architect/customize.toml +63 -0
- package/.agents/skills/bmad-agent-dev/SKILL.md +76 -0
- package/.agents/skills/bmad-agent-dev/customize.toml +81 -0
- package/.agents/skills/bmad-agent-pm/SKILL.md +76 -0
- package/.agents/skills/bmad-agent-pm/customize.toml +73 -0
- package/.agents/skills/bmad-agent-ux-designer/SKILL.md +76 -0
- package/.agents/skills/bmad-agent-ux-designer/customize.toml +58 -0
- package/.agents/skills/bmad-architecture/SKILL.md +85 -0
- package/.agents/skills/bmad-architecture/assets/spine-template.md +79 -0
- package/.agents/skills/bmad-architecture/customize.toml +101 -0
- package/.agents/skills/bmad-architecture/references/headless.md +26 -0
- package/.agents/skills/bmad-architecture/references/reviewer-gate.md +13 -0
- package/.agents/skills/bmad-architecture/scripts/lint_spine.py +257 -0
- package/.agents/skills/bmad-architecture/scripts/tests/test_lint_spine.py +270 -0
- package/.agents/skills/bmad-brainstorming/SKILL.md +80 -0
- package/.agents/skills/bmad-brainstorming/assets/brain-icons.json +166 -0
- package/.agents/skills/bmad-brainstorming/assets/brain-methods.csv +109 -0
- package/.agents/skills/bmad-brainstorming/assets/brain-selector.html +328 -0
- package/.agents/skills/bmad-brainstorming/customize.toml +83 -0
- package/.agents/skills/bmad-brainstorming/references/converge.md +24 -0
- package/.agents/skills/bmad-brainstorming/references/finalize.md +26 -0
- package/.agents/skills/bmad-brainstorming/references/headless.md +54 -0
- package/.agents/skills/bmad-brainstorming/references/in-chat-techniques.md +18 -0
- package/.agents/skills/bmad-brainstorming/references/mode-autonomous.md +10 -0
- package/.agents/skills/bmad-brainstorming/references/mode-facilitator.md +11 -0
- package/.agents/skills/bmad-brainstorming/references/mode-partner.md +16 -0
- package/.agents/skills/bmad-brainstorming/references/resume.md +5 -0
- package/.agents/skills/bmad-brainstorming/scripts/brain.py +789 -0
- package/.agents/skills/bmad-brainstorming/scripts/tests/test_brain.py +289 -0
- package/.agents/skills/bmad-build/SKILL.md +13 -0
- package/.agents/skills/bmad-build/compile-epic-context.md +62 -0
- package/.agents/skills/bmad-build/customize.toml +152 -0
- package/.agents/skills/bmad-build/references/claims-check.md +14 -0
- package/.agents/skills/bmad-build/references/deletion-check.md +14 -0
- package/.agents/skills/bmad-build/review-prompts/edge-case-hunter.md +112 -0
- package/.agents/skills/bmad-build/review-prompts/verification-gap.md +113 -0
- package/.agents/skills/bmad-build/spec-template.md +111 -0
- package/.agents/skills/bmad-build/step-01-clarify-and-route.md +100 -0
- package/.agents/skills/bmad-build/step-02-plan.md +62 -0
- package/.agents/skills/bmad-build/step-03-implement.md +51 -0
- package/.agents/skills/bmad-build/step-04-review.md +85 -0
- package/.agents/skills/bmad-build/step-05-present.md +43 -0
- package/.agents/skills/bmad-build/step-oneshot.md +107 -0
- package/.agents/skills/bmad-build/sync-sprint-status.md +5 -0
- package/.agents/skills/bmad-build/workflow.md +84 -0
- package/.agents/skills/bmad-build-auto/SKILL.md +13 -0
- package/.agents/skills/bmad-build-auto/compile-epic-context.md +62 -0
- package/.agents/skills/bmad-build-auto/customize.toml +119 -0
- package/.agents/skills/bmad-build-auto/references/claims-check.md +14 -0
- package/.agents/skills/bmad-build-auto/references/deletion-check.md +14 -0
- package/.agents/skills/bmad-build-auto/review-prompts/edge-case-hunter.md +112 -0
- package/.agents/skills/bmad-build-auto/review-prompts/verification-gap.md +113 -0
- package/.agents/skills/bmad-build-auto/spec-template.md +96 -0
- package/.agents/skills/bmad-build-auto/step-01-clarify-and-route.md +84 -0
- package/.agents/skills/bmad-build-auto/step-02-plan.md +27 -0
- package/.agents/skills/bmad-build-auto/step-03-implement.md +48 -0
- package/.agents/skills/bmad-build-auto/step-04-review.md +116 -0
- package/.agents/skills/bmad-build-auto/workflow.md +104 -0
- package/.agents/skills/bmad-code-review/SKILL.md +90 -0
- package/.agents/skills/bmad-code-review/customize.toml +110 -0
- package/.agents/skills/bmad-code-review/references/claims-check.md +14 -0
- package/.agents/skills/bmad-code-review/references/deletion-check.md +14 -0
- package/.agents/skills/bmad-code-review/review-prompts/edge-case-hunter.md +112 -0
- package/.agents/skills/bmad-code-review/review-prompts/verification-gap.md +113 -0
- package/.agents/skills/bmad-code-review/steps/step-01-gather-context.md +94 -0
- package/.agents/skills/bmad-code-review/steps/step-02-review.md +32 -0
- package/.agents/skills/bmad-code-review/steps/step-03-triage.md +54 -0
- package/.agents/skills/bmad-code-review/steps/step-04-present.md +134 -0
- package/.agents/skills/bmad-correct-course/SKILL.md +308 -0
- package/.agents/skills/bmad-correct-course/checklist.md +288 -0
- package/.agents/skills/bmad-correct-course/customize.toml +39 -0
- package/.agents/skills/bmad-create-epics-and-stories/SKILL.md +93 -0
- package/.agents/skills/bmad-create-epics-and-stories/customize.toml +39 -0
- package/.agents/skills/bmad-create-epics-and-stories/steps/step-01-validate-prerequisites.md +263 -0
- package/.agents/skills/bmad-create-epics-and-stories/steps/step-02-design-epics.md +242 -0
- package/.agents/skills/bmad-create-epics-and-stories/steps/step-03-create-stories.md +255 -0
- package/.agents/skills/bmad-create-epics-and-stories/steps/step-04-final-validation.md +143 -0
- package/.agents/skills/bmad-create-epics-and-stories/templates/epics-template.md +61 -0
- package/.agents/skills/bmad-customize/SKILL.md +111 -0
- package/.agents/skills/bmad-customize/scripts/list_customizable_skills.py +231 -0
- package/.agents/skills/bmad-customize/scripts/tests/test_list_customizable_skills.py +249 -0
- package/.agents/skills/bmad-deep-recon/SKILL.md +82 -0
- package/.agents/skills/bmad-deep-recon/assets/research.template.md +18 -0
- package/.agents/skills/bmad-deep-recon/customize.toml +212 -0
- package/.agents/skills/bmad-deep-recon/references/draft.md +8 -0
- package/.agents/skills/bmad-deep-recon/references/finalize.md +11 -0
- package/.agents/skills/bmad-deep-recon/references/html-briefing.md +16 -0
- package/.agents/skills/bmad-deep-recon/references/lifecycle.md +11 -0
- package/.agents/skills/bmad-deep-recon/references/process.md +10 -0
- package/.agents/skills/bmad-deep-recon/references/run.md +73 -0
- package/.agents/skills/bmad-deep-recon/references/selection.md +13 -0
- package/.agents/skills/bmad-deep-recon/references/synthesis.md +16 -0
- package/.agents/skills/bmad-deep-recon/references/verification.md +29 -0
- package/.agents/skills/bmad-deep-recon/scripts/recon_kit.py +322 -0
- package/.agents/skills/bmad-deep-recon/scripts/tests/test_recon_kit.py +144 -0
- package/.agents/skills/bmad-deep-recon/types/academic-lit.md +19 -0
- package/.agents/skills/bmad-deep-recon/types/competitive.md +19 -0
- package/.agents/skills/bmad-deep-recon/types/domain.md +19 -0
- package/.agents/skills/bmad-deep-recon/types/market.md +19 -0
- package/.agents/skills/bmad-deep-recon/types/technical.md +19 -0
- package/.agents/skills/bmad-deep-recon/types/user-voice.md +19 -0
- package/.agents/skills/bmad-forge-idea/SKILL.md +107 -0
- package/.agents/skills/bmad-forge-idea/customize.toml +41 -0
- package/.agents/skills/bmad-forge-idea/scripts/resolve_personas.py +277 -0
- package/.agents/skills/bmad-forge-idea/scripts/tests/test_resolve_personas.py +160 -0
- package/.agents/skills/bmad-help/SKILL.md +77 -0
- package/.agents/skills/bmad-party-mode/SKILL.md +60 -0
- package/.agents/skills/bmad-party-mode/customize.toml +211 -0
- package/.agents/skills/bmad-party-mode/references/create-party.md +70 -0
- package/.agents/skills/bmad-party-mode/references/mode-agent-team.md +13 -0
- package/.agents/skills/bmad-party-mode/references/mode-auto.md +13 -0
- package/.agents/skills/bmad-party-mode/references/mode-subagent.md +31 -0
- package/.agents/skills/bmad-party-mode/references/party-memory.md +51 -0
- package/.agents/skills/bmad-party-mode/scripts/resolve_party.py +284 -0
- package/.agents/skills/bmad-party-mode/scripts/tests/test_resolve_party.py +168 -0
- package/.agents/skills/bmad-prd/SKILL.md +94 -0
- package/.agents/skills/bmad-prd/assets/headless-schemas.md +76 -0
- package/.agents/skills/bmad-prd/assets/prd-template.md +165 -0
- package/.agents/skills/bmad-prd/assets/prd-validation-checklist.md +135 -0
- package/.agents/skills/bmad-prd/assets/validation-report-template.html +325 -0
- package/.agents/skills/bmad-prd/customize.toml +148 -0
- package/.agents/skills/bmad-prd/references/headless.md +39 -0
- package/.agents/skills/bmad-prd/references/validate.md +97 -0
- package/.agents/skills/bmad-prfaq/SKILL.md +135 -0
- package/.agents/skills/bmad-prfaq/agents/artifact-analyzer.md +60 -0
- package/.agents/skills/bmad-prfaq/agents/web-researcher.md +49 -0
- package/.agents/skills/bmad-prfaq/assets/prfaq-template.md +62 -0
- package/.agents/skills/bmad-prfaq/bmad-manifest.json +16 -0
- package/.agents/skills/bmad-prfaq/customize.toml +39 -0
- package/.agents/skills/bmad-prfaq/references/customer-faq.md +55 -0
- package/.agents/skills/bmad-prfaq/references/internal-faq.md +51 -0
- package/.agents/skills/bmad-prfaq/references/press-release.md +60 -0
- package/.agents/skills/bmad-prfaq/references/verdict.md +83 -0
- package/.agents/skills/bmad-product-brief/SKILL.md +91 -0
- package/.agents/skills/bmad-product-brief/assets/brief-template.md +41 -0
- package/.agents/skills/bmad-product-brief/customize.toml +100 -0
- package/.agents/skills/bmad-project-context/SKILL.md +121 -0
- package/.agents/skills/bmad-project-context/customize.toml +24 -0
- package/.agents/skills/bmad-project-context/references/best-practices.md +84 -0
- package/.agents/skills/bmad-project-context/references/template.md +55 -0
- package/.agents/skills/bmad-qa-generate-e2e-tests/SKILL.md +176 -0
- package/.agents/skills/bmad-qa-generate-e2e-tests/checklist.md +33 -0
- package/.agents/skills/bmad-qa-generate-e2e-tests/customize.toml +39 -0
- package/.agents/skills/bmad-retrospective/SKILL.md +94 -0
- package/.agents/skills/bmad-retrospective/customize.toml +39 -0
- package/.agents/skills/bmad-retrospective/references/acceptance-verdict.md +55 -0
- package/.agents/skills/bmad-retrospective/references/aggregate-views.md +17 -0
- package/.agents/skills/bmad-retrospective/references/evidence-gathering.md +30 -0
- package/.agents/skills/bmad-retrospective/references/retro-document.md +84 -0
- package/.agents/skills/bmad-retrospective/references/team-discussion.md +22 -0
- package/.agents/skills/bmad-retrospective/scripts/git_evidence.py +304 -0
- package/.agents/skills/bmad-retrospective/scripts/sprint_status.py +746 -0
- package/.agents/skills/bmad-retrospective/scripts/tests/fixtures/sprint-status-template.yaml +71 -0
- package/.agents/skills/bmad-retrospective/scripts/tests/test_git_evidence.py +750 -0
- package/.agents/skills/bmad-retrospective/scripts/tests/test_sprint_status.py +1579 -0
- package/.agents/skills/bmad-review/SKILL.md +50 -0
- package/.agents/skills/bmad-review/customize.toml +141 -0
- package/.agents/skills/bmad-review/references/editorial-common.md +56 -0
- package/.agents/skills/bmad-review/references/lens-adversarial.md +19 -0
- package/.agents/skills/bmad-review/references/lens-edge-case-hunter.md +72 -0
- package/.agents/skills/bmad-review/references/lens-prose.md +7 -0
- package/.agents/skills/bmad-review/references/lens-structure.md +9 -0
- package/.agents/skills/bmad-review/references/lens-verification-gap.md +92 -0
- package/.agents/skills/bmad-review/references/structure-models.md +44 -0
- package/.agents/skills/bmad-review/scripts/tests/test_word_metrics.py +62 -0
- package/.agents/skills/bmad-review/scripts/word_metrics.py +102 -0
- package/.agents/skills/bmad-spec/SKILL.md +160 -0
- package/.agents/skills/bmad-spec/assets/headless-schemas.md +33 -0
- package/.agents/skills/bmad-spec/assets/spec-template.md +49 -0
- package/.agents/skills/bmad-spec/assets/stories-schema.md +44 -0
- package/.agents/skills/bmad-spec/customize.toml +52 -0
- package/.agents/skills/bmad-sprint-planning/SKILL.md +62 -0
- package/.agents/skills/bmad-sprint-planning/customize.toml +39 -0
- package/.agents/skills/bmad-sprint-planning/references/fix-sprint-status.md +30 -0
- package/.agents/skills/bmad-sprint-planning/references/generate-tracking.md +25 -0
- package/.agents/skills/bmad-sprint-planning/references/readiness-gate.md +20 -0
- package/.agents/skills/bmad-sprint-planning/references/status-view.md +14 -0
- package/.agents/skills/bmad-sprint-planning/references/validate.md +10 -0
- package/.agents/skills/bmad-sprint-planning/scripts/sprint_plan.py +697 -0
- package/.agents/skills/bmad-sprint-planning/scripts/tests/test_sprint_plan.py +524 -0
- package/.agents/skills/bmad-sprint-planning/sprint-status-template.yaml +71 -0
- package/.agents/skills/bmad-ux/SKILL.md +90 -0
- package/.agents/skills/bmad-ux/assets/color-themes.md +9 -0
- package/.agents/skills/bmad-ux/assets/design-directions.md +9 -0
- package/.agents/skills/bmad-ux/assets/design-example-editorial.md +158 -0
- package/.agents/skills/bmad-ux/assets/design-example-mobile.md +93 -0
- package/.agents/skills/bmad-ux/assets/design-example-shadcn.md +109 -0
- package/.agents/skills/bmad-ux/assets/excalidraw-wireframe.md +19 -0
- package/.agents/skills/bmad-ux/assets/experience-example-mobile.md +112 -0
- package/.agents/skills/bmad-ux/assets/experience-example-shadcn.md +133 -0
- package/.agents/skills/bmad-ux/assets/headless-schemas.md +84 -0
- package/.agents/skills/bmad-ux/assets/key-screens.md +29 -0
- package/.agents/skills/bmad-ux/assets/validation-report-template.html +319 -0
- package/.agents/skills/bmad-ux/customize.toml +100 -0
- package/.agents/skills/bmad-ux/references/creative-tools.md +19 -0
- package/.agents/skills/bmad-ux/references/design-md-spec.md +50 -0
- package/.agents/skills/bmad-ux/references/headless.md +37 -0
- package/.agents/skills/bmad-ux/references/validate.md +115 -0
- package/.agents/skills/bmad-walkthrough/SKILL.md +68 -0
- package/.agents/skills/bmad-walkthrough/customize.toml +39 -0
- package/.agents/skills/bmad-walkthrough/generate-trail.md +38 -0
- package/.agents/skills/bmad-walkthrough/step-01-orientation.md +105 -0
- package/.agents/skills/bmad-walkthrough/step-02-walkthrough.md +89 -0
- package/.agents/skills/bmad-walkthrough/step-03-detail-pass.md +106 -0
- package/.agents/skills/bmad-walkthrough/step-04-testing.md +74 -0
- package/.agents/skills/bmad-walkthrough/step-05-wrapup.md +30 -0
- package/README.md +111 -0
- package/bin/pcgf.js +8 -0
- package/installer/clean.js +137 -0
- package/installer/cli.js +479 -0
- package/installer/deps.js +160 -0
- package/installer/fs-utils.js +58 -0
- package/installer/install.js +201 -0
- package/installer/paths.js +17 -0
- package/installer/scaffold.js +274 -0
- package/installer/tools.js +38 -0
- package/package.json +37 -0
- package/plugins/phaser-casual-game-factory/.codex-plugin/plugin.json +27 -0
- package/plugins/phaser-casual-game-factory/PROGRESS.md +120 -0
- package/plugins/phaser-casual-game-factory/README.md +79 -0
- package/plugins/phaser-casual-game-factory/assets/sfx/README.md +8 -0
- package/plugins/phaser-casual-game-factory/assets/sfx/ui_click.mp3 +0 -0
- package/plugins/phaser-casual-game-factory/assets/sfx/ui_close.mp3 +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/README.md +9 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_DarkGray.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_Gray.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_Green.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_Mint.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_Pink.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_Purple.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_Red.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_Sky.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_White_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_White_Light1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_White_Light2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_l_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_DarkGray.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_Flat.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_Gray.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_Green.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_Mint.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_PInk.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_Purple.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_Red.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_Sky.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_White_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_White_Light1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_White_Light2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button01_s_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Circle118.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Circle120.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Circle122.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Circle74_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Circle74_Border.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Circle82.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_LeftFlush_Dark.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_LeftFlush_White1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_LeftFlush_White2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round01_White_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round01_White_Light1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round01_White_Light2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round01_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round02_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round02_White_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round02_White_Light.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round03_Dark.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round03_WhiteBg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round03_White_Light.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round04_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round04_Oblique.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round05.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round06_Red.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round06_White.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round07.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round08.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round09.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round10_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Round10_Light.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_SkillBtnMask.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_SkillBtn_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_SkillBtn_Dark.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_SkillBtn_Orange.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_SkillBtn_Red.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_SkillBtn_White_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_SkillBtn_White_Light.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Tapered_White1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Tapered_White2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Tapered_White3.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Button_Tapered_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Menu_BottomBtn_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Menu_BottomBtn_TabFocus.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Menu_BottomBtn_TabFocus_Light.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Menu_MiddleBtn_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Button/Menu_MiddleBtn_TabFocus.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_01~02_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_01~02_InnerBg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_01~02_InnerLine.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_01~02_Light.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_01~02_Pattern.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_01~02_Pattern.psd +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_03_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_03_Border.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_04~06_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_04~06_BgLight.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_04~06_Border.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame00_04~06_Pattern.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame03_Demo.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame04_Demo.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame05_Demo.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame06_Demo_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame06_Demo__Gray.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BannerFrame07.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BasicFrame_Circle160.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BasicFrame_Hexagon87.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BasicFrame_Oval44.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BasicFrame_Oval50.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BasicFrame_Round12.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BasicFrame_Round17.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BasicFrame_Round20.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BasicFrame_Round24.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Circle60.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Circle75_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Circle75_Light.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Circle78.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Flag_Demo_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Flag_Demo_Green.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Flag_Demo_Red.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Flag_White_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Flag_White_BgGradient.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Flag_White_BgLine01.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Flag_White_BgLine02.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Oval46_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Oval46_InnerLine.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Oval58.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Rhombus_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Rhombus_Inner.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Round18_Transparent.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Round20_Demo_Dark.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Round20_Demo_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Round20_White_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Round20_White_Light.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Round24.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Round30.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Squrare_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BorderFrame_Squrare_Inner.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame01_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame01_BgArrow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame01_BgShadow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame01_Hexagon_Bg_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame01_Hexagon_Bg_Green.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame01_Hexagon_Bg_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame01_Hexagon_FocusBorder.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame01_Hexagon_FocusGlow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame02_Arrow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame02_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame02_BgShadow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame03_Arrow_Left.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame03_Arrow_Right.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame03_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame04_Blue_Arrow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame04_Blue_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame04_White_Arrow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame04_White_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame05_InnerBg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame05_InnerBorder.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame05_Left_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame05_Left_BgShadow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame05_Right_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/BubbleFrame05_Right_BgShadow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame01_Bg_d.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame01_Bg_d_Pattern.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame01_Bg_n.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame01_Border.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame01_Bottom.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame01_Glow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame01_Gradient.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame01_Gradient_Hologram.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame02_d_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame02_d_Bg_Pattern.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame02_d_Border.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame02_n_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame02_n_Bottom.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame02_n_Light.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame03_d.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame03_n_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame03_n_InnerBg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame03_n_Light.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame04_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame04_Bg_DividerLine.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame04_Bg_Gradient.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame04_Border.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame04_FocusBorder.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame04_FocusGlow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame04_Glow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame05_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame05_Bg_Corner.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame05_Border.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame05_FocusBorder.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame05_FocusGlow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame05_Glow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame06_Demo_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame06_Demo_Bg_Glow_Green.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame06_Demo_Deco_Green.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame06_Demo_Frame_Green.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame06_White_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame06_White_Bg_Glow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame06_White_Deco.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/CardFrame06_White_Frame.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame00~03_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame00~03_BgGlow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame00~03_BgLight.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame00~03_Bg_Hologram.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame00~03_Border.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame00~03_CornerDeco.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame00~03_FocusLine.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_Gray.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_Green.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_Hologram1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_Hologram2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_Navy.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_OffWhite.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_Purple.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_Red.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame01_Demo_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_Gray.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_Green.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_Hologram1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_Hologram2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_Navy.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_OffWhite.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_Purple.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_Red.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame02_Demo_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame03_Demo_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame03_Demo_Gray.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame03_Demo_Green.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame03_Demo_Hologram.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame03_Demo_Navy.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame03_Demo_Purple.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame03_Demo_Red.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ItemFrame03_Demo_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ListFrame00_01~02_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ListFrame00_01~02_BgInner.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ListFrame00_01~02_Oblique.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ListFrame00_03~04_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ListFrame00_03~04_BgInner.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ListFrame00_03~04_Dim.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ListFrame04_Demo_f_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ListFrame04_Demo_f_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/PanelFrame01_Line.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/PanelFrame02.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/PanelFrame03_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/PanelFrame03_Oblique.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/PanelFrame04_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/PanelFrame04_OutTilte1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/PanelFrame04_OutTilte2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ProfileFrame01_l_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ProfileFrame01_l_Border.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ProfileFrame01_m~s_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ProfileFrame01_m~s_Inner.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ProfileFrame02_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ProfileFrame02_Inner.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ProfileFrame_Circle275_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/ProfileFrame_Circle275_Inner.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/SkillFrame_l~m_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/SkillFrame_l~m_Border.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/SkillFrame_l~m_Empty.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/SkillFrame_s_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/SkillFrame_s_Border.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Frame/SkillFrame_s_Empty.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_brz.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_chn.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_cze.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_deu.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_eng.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_esp.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_fra.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_gbr.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_gre.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_ind.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_ita.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_jpn.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_kor.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_pol.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_prt.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_rou.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_rsa.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_rus.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_swe.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_tha.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_tur.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_twn.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_ukr.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_Flag/Small/Icon_Flag_usa.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Beginner.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Bronze.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Challenger.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Diamond.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Gold.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Grandmaster.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Iron.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Master.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Platinum.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_GradeBadge/256/Icon_GradeBadge_Silver.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Badge_Crown.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Badge_Gold.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Bag_Brown.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Bag_Gray.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Battle.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Book_1_Purple.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Book_1_Wine.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Calendar.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Calendar_Check.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Chat.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Chest_Gem.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Chest_Gold.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Chest_Premium.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Chest_Wood.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Clover_Gold.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Clover_Green.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Damage.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Dungeon.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Earth.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Energy_Blue.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Friend.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gear.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gear_Armor_Bottom.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gear_Armor_Top.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gear_Boots.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gear_Hat_Witch.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gear_Ring.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gear_Sword.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gem_Circle.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gem_Diamond_Purple.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gem_Ellipse_Red.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gem_Star_Blue.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gift_Blue.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gift_Green.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Gift_Red.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Heart_Dimmed.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Heart_Red.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Key_Gold.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Mail.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Map.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Meat.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Medal_Bronze_1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Medal_Bronze_2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Medal_Gold_1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Medal_Gold_2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Medal_Silver_1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Medal_Silver_2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Medalstand.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_MemoPad.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Money_Bill.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Money_Coin.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Pot.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Shop.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Skull.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Star_Blue.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Star_Bronze.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Star_Gold.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Star_Purple.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Star_Red.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Star_Silver.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_TV_AdBlock.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Ticket_Gold.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Ticket_Red.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Trophy_Bronze.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Trophy_Gold.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Trophy_Silver.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_ItemIcons/256/ItemIcon_Video.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Again_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Again_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Aiming_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Aiming_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Alarm.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Anchor.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Archer.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Armor.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Arrow_Down.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Arrow_Left_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Arrow_Left_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Arrow_Left_3.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Arrow_Right_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Arrow_Right_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Arrow_Right_3.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Arrow_Up.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_At.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Attack.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Ax.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Ax_Double.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Back_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Back_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Badge.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bag.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bank.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Basket.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Battery_Charge.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Battle.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bell.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bell_Off.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bell_On.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bell_Sleep.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Blacksmith.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Block.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bluetooth.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bomb_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bomb_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Book_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Book_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Book_3.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Boots.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Boss.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bow.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Brief_Bag.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Brush.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bulb.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bulb_Charge.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Bullet.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Calendar.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Camera.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Camera_Off.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Cap.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Card_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Card_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Cart_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Cart_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Castle.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Caution.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Certification.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Change.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Chat_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Chat_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Check_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Check_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Chest.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Chisel.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Class_A.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Class_B.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Class_C.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Class_D.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Class_S.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Class_Ss.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Clock_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Clock_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Closet.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Clothes.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Coin.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Coin_Star.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Compass.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Console_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Console_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Contraction.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Cooking.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Copy.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Costume.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Critical_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Critical_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Critical_3.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Crown_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Crown_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Crystal.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Delete.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Diamond.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Dice.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Direction_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Direction_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Discount.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Dollar_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Dollar_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Download.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Earth.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Earth_Pin.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Effect.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Energy_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Energy_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Exit.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Exit_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Exit_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Exp.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Expansion.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Face.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Faint.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Female.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Fire.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Firework.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Fish.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Fishing.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Flag.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Float.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Food.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Freezee.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Friends.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Gallery.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Game.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Gear.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Gift.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Glasses.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Globe.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Graduation_Cap.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Hammer.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Hammer_Claw.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Hand_Touch.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Hanger.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Hat.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Headset.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Heart.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Heart_Add.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Heart_Empty.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Helmet_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Helmet_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Help_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Help_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_History.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Home_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Home_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Hp.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Icecream.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Illuminati.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Infinity.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Info_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Info_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Info_3.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Info_4.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Key.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Kitchen_Knife.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Layer_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Layer_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Leaf.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Link.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Lock_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Lock_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Lock_Open.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Magic.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Magic_Ball.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Mail_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Mail_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Male.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Map_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Map_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Map_Pin.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Meal.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Medal_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Medal_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Megaphone.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Menu_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Menu_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Menu_3.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Menu_4.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Menu_5.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Menu_6.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Merge.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Message_Bottle.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Minus_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Minus_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Mission.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Money_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Money_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Money_Pouch.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Movie.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Mushroom.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Music_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Music_1_Off.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Music_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Music_2_Off.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Necklace.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Night.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Note.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Object.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Page_Next.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Page_Prev.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Paper_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Paper_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Path.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Pause_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Pause_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Paw.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Pen.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Pen_Feather.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Pencil.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Phone.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Photo_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Photo_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Pick.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Pickax.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Plants.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Play_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Play_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Plus_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Plus_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Potion_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Potion_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Potion_3.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Pouch.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Power_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Power_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Power_Off.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Rampart.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Rank_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Rank_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Recommendation.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Recycle.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Refresh_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Refresh_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Refresh_3.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Refresh_4.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Ring.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Roulette.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Safebox.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sandglass.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Saw.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Scale.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Scroll_Old.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Search.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Security.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Setting.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Share.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sheos.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sheos_Wing.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sheriff.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Shield_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Shield_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Shield_Viking.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Ship.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Shop_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Shop_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Shop_3.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Shovel.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sickle.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sign.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Skull.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sound.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sound_Off.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Star_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Star_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Star_3.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Star_Empty.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Step.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Stopwatch_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Stopwatch_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Storage.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sun.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Switch.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sword_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Sword_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Tag.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Target.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Telescope.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Temple.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Ticket.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Tool_Fix.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Top.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Trophy_1.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Trophy_2.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Tv.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Typhoon.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Under.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_User.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_User_Add.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_User_Info.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Video.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_View.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_View_Off.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Vr.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Warehouse.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Water.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Wing.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Wood.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_World.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Zoom_In.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_PictoIcons/256/PictoIcon_Zoom_Out.Png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_TutorialHand/256/tutorial_hand_1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_TutorialHand/256/tutorial_hand_2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_TutorialHand/256/tutorial_hand_3.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_TutorialHand/256/tutorial_hand_4.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_TutorialHand/256/tutorial_hand_5.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Icon_TutorialHand/256/tutorial_hand_6.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Badge01_Green.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Badge01_Purple.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Badge01_Red.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Badge01_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Badge02.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Bubble_Arrow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Bubble_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Parallelogram_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Parallelogram_Gray.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Parallelogram_Green.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Parallelogram_Hologram.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Parallelogram_Purple.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Parallelogram_Red.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Parallelogram_White_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Parallelogram_White_Inner.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Parallelogram_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Ribbon_Hologram.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Ribbon_White.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Tail_Demo_Red.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Tail_White_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Label_Tail_White_Border.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_LIne04_Under.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Line01_Divider_Left.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Line01_Divider_Right.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Line02_Divider_Left.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Line02_Divider_Right.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Line03_Divider.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Oval.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Gray.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Green.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Magenta.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Navy.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Orange.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Peacock.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Plum.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Purple.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Red.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Sky.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon01_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon02_Red.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon02_White1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon02_White2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon03_Red.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon03_White1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon03_White2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon04_Red.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Ribbon05.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Tapered01.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Tapered02.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Label/Title_Tapered03.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/PACK.md +6 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup01_Basic_Demo.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup01_Basic_White_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup01_Basic_White_Light.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup02~09_Topber_Demo_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup02~09_Topber_White_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup02~09_Topber_White_BgTop.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup02~09_Topber_White_BgTopLight.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup03_Gradient.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup06_Glow_Bottom.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup06_Pattern.psd +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup09_Topber_White_Label_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup09_Topber_White_Label_Inner.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_Chat_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_Chat_BgLight.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_Chat_TabFocus.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_FullWidth_Dark.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_FullWidth_White.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_List_VerticalLayout.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_OutTitle_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_OutTitle_Bg_Title.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_OutTitle_Inner_Bottom.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_OutTitle_Inner_Top.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_Ticket_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_Ticket_Border.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_Ticket_BottomPattern.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Popup/Popup_Ticket_Gradient.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic01_Bg_Demo.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic01_Bg_White1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic01_Bg_White2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic01_FillMask.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic01_Fill_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic01_Fill_Green.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic01_Fill_White.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic01_Fill_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic02_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic02_FillMask.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic02_Fill_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic02_Fill_Green.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic02_Fill_White.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic02_Fill_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic03_Bg_Demo.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic03_Bg_White1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic03_Bg_White2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic03_FillMask.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic03_Fill_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic03_Fill_Green.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic03_Fill_White.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic03_Fill_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic04_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic04_Fill_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic04_Fill_Orange.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic04_White_Fill1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Basic04_White_Fill2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Handle_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Handle_FillMask.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Handle_Fill_Pink.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Handle_Fill_White1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Handle_Fill_White2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Handle_Handle.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon01_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon01_FillMask.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon01_Fill_Orange.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon01_Fill_White.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon01_Icon1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon01_Icon2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon02_Badge1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon02_Badge2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon02_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon02_FillMask.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon02_Fill_Orange.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon02_Fill_White.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Icon02_Icon1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level01_Badge_l.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level01_Badge_s.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level01_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level01_Fill.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level01_FillMask.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Bg_Demo.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Bg_White1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Bg_White2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Fill01_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Fill01_White.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Fill01_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Fill02_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Fill02_White.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Fill02_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Icon_Badge_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Icon_Badge_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Icon_Up_Green.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level02_Icon_Up_White.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level03_Badge1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level03_Badge2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level03_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level03_Fill1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Level03_Fill2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Panel_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Panel_Fill1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Panel_Fill2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Play01_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Play01_Fill.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Play01_FillMask.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Play02_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Play02_FillMask.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Icon_l_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Icon_l_Gray.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Icon_l_White1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Icon_l_White2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Icon_l_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Icon_s_Blue.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Icon_s_White1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Icon_s_White2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageHorizontal_Icon_s_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageVertical_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageVertical_Icon1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_StageVertical_Icon2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Wave_Badge1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Wave_Badge2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Wave_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/Slider_Wave_Fill.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/_Slider_Basic_R6_Fill_Orange.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/_Slider_Round6_01_White_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/Slider/_Slider_Round6_01_White_Fill.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Alert_Circle_Icon_Exclamation.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Alert_Circle_l_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Alert_Circle_l_Border.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Alert_Circle_s_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Alert_Circle_s_Border.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Alert_Dot_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Alert_Dot_Border.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Alert_Dot_Light.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField01_Bg_Demo.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField01_Bg_White1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField01_Bg_White2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField01_Bg_White3.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField01_Icon_Lock.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField01_Icon_Mail.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField02_Demo.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField02_White1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField02_White2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField03.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/InputField04.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Btn_Blue1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Btn_Blue2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Btn_Purple1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Btn_Purple2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Btn_Yellow1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Btn_Yellow2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Icon_Coin.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Icon_Energy.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Icon_Gem.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_Demo_Icon_Monster.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_White_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_White_Btn1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_White_Btn2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_White_Btn3.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_White_Icon1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ResourceBar_White_Icon2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Switch_Demo_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Switch_Demo_Fill.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Switch_Demo_Handle.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Switch_White_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Switch_White_BgInner.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Switch_White_Fill1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Switch_White_Fill2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Switch_White_Handle.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ToastMessage_Bg_Gray.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ToastMessage_Bg_Green.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ToastMessage_Bg_Red.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ToastMessage_Bg_White.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ToastMessage_Bg_Yellow.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ToastMessage_Gradient.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ToastMessage_Light1.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/ToastMessage_Light2.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Toggle_Check_Demo_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Toggle_Check_Demo_Icon.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Toggle_Check_White_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Toggle_Check_White_BgLight.png +0 -0
- package/plugins/phaser-casual-game-factory/assets/ui-packs/super-casual/UI_Etc/Toggle_Check_White_Icon.png +0 -0
- package/plugins/phaser-casual-game-factory/examples/README.md +44 -0
- package/plugins/phaser-casual-game-factory/examples/economy-demo-config.ts +255 -0
- package/plugins/phaser-casual-game-factory/examples/economy-demo.ts +89 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/index.html +342 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/package-lock.json +1293 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/package.json +21 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/playwright.config.ts +26 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/assets/sfx/ui_click.mp3 +0 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/assets/sfx/ui_close.mp3 +0 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/assets/ui/BG_lobby.png +0 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/assets/ui/Bar_Bg.png +0 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/assets/ui/progress_inner.png +0 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/assets/ui/progress_outer.png +0 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-400-latin-OEyTajQY.woff2 +0 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-400-viet-SOx6iaFb.woff2 +0 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-600-latin-xAC4kEK0.woff2 +0 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-600-viet-DbGrrtCq.woff2 +0 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-700-latin-CPfR8Jz_.woff2 +0 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-700-viet-DptIoWwl.woff2 +0 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-800-latin-B5VTH9An.woff2 +0 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-800-viet-BEUwTqXl.woff2 +0 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-900-latin-B6esVQUu.woff2 +0 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/fonts/bvp-900-viet-DUJ3fpCl.woff2 +0 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/public/logo-frog.png +0 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/brand/BootLoadingScreen.js +7 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/brand/SplashFullscreenBg.js +4 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/brand-shims.d.ts +33 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/demo-scenes.ts +12 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/demo-tools.ts +34 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/main.ts +1358 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/scenes/BootScene.ts +236 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/scenes/GameScene.ts +152 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/scenes/HomeScene.ts +21 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/scenes/scene-hooks.ts +12 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/styles.css +623 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/src/ui-audio.ts +156 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/tests/browser-smoke.spec.ts +170 -0
- package/plugins/phaser-casual-game-factory/examples/factory-browser-demo/vite.config.ts +23 -0
- package/plugins/phaser-casual-game-factory/examples/leveling-demo-config.ts +107 -0
- package/plugins/phaser-casual-game-factory/references/condition-service.md +38 -0
- package/plugins/phaser-casual-game-factory/references/core-contracts.md +39 -0
- package/plugins/phaser-casual-game-factory/references/daily-login-service.md +32 -0
- package/plugins/phaser-casual-game-factory/references/economy-service.md +192 -0
- package/plugins/phaser-casual-game-factory/references/leveling-service.md +56 -0
- package/plugins/phaser-casual-game-factory/references/loading-view.md +181 -0
- package/plugins/phaser-casual-game-factory/references/time-service.md +42 -0
- package/plugins/phaser-casual-game-factory/scripts/new-phaser-casual-game.ps1 +152 -0
- package/plugins/phaser-casual-game-factory/scripts/run-browser-demo.ps1 +13 -0
- package/plugins/phaser-casual-game-factory/scripts/run-economy-demo.ps1 +4 -0
- package/plugins/phaser-casual-game-factory/scripts/test-all.ps1 +11 -0
- package/plugins/phaser-casual-game-factory/scripts/test-browser.ps1 +10 -0
- package/plugins/phaser-casual-game-factory/scripts/test-economy.ps1 +4 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/SKILL.md +846 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/client/.env.example +19 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/client/bgremove.py +127 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/client/codex_extract.py +123 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/client/codex_gen.sh +172 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/client/envfile.py +121 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/client/gemini_image_mcp.py +1870 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/client/imglib.py +2138 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/client/remote_backend.py +498 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/client/remote_codex.py +59 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/client/remote_proto.py +135 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/client/requirements-client.txt +22 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/client/test_imglib.py +1647 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/client/test_restyle_tools.py +256 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/client/tools/restyle/styles/unscrew-casual.refs/ref-lose.jpg +0 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/client/tools/restyle/styles/unscrew-casual.refs/ref-welcome.jpg +0 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/client/tools/restyle/styles/unscrew-casual.refs/ref-win.jpg +0 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/client/upscale.py +289 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/reference/client-guide.md +180 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/reference/mcp-image-input.md +148 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/reference/prompt-template.md +216 -0
- package/plugins/phaser-casual-game-factory/skills/game-art/reference/remote-lan.md +224 -0
- package/plugins/phaser-casual-game-factory/skills/pcgf-git-merge-request/SKILL.md +96 -0
- package/plugins/phaser-casual-game-factory/skills/pcgf-ui-reskin/SKILL.md +144 -0
- package/plugins/phaser-casual-game-factory/skills/phaser-adaptive-loading/SKILL.md +33 -0
- package/plugins/phaser-casual-game-factory/skills/phaser-casual-game-factory/SKILL.md +225 -0
- package/plugins/phaser-casual-game-factory/skills/phaser-condition-service/SKILL.md +21 -0
- package/plugins/phaser-casual-game-factory/skills/phaser-daily-login-service/SKILL.md +20 -0
- package/plugins/phaser-casual-game-factory/skills/phaser-economy-service/SKILL.md +72 -0
- package/plugins/phaser-casual-game-factory/skills/phaser-foundation/SKILL.md +60 -0
- package/plugins/phaser-casual-game-factory/skills/phaser-leveling-service/SKILL.md +39 -0
- package/plugins/phaser-casual-game-factory/skills/phaser-loading-view/SKILL.md +167 -0
- package/plugins/phaser-casual-game-factory/skills/phaser-studio25-boot-brand/SKILL.md +107 -0
- package/plugins/phaser-casual-game-factory/skills/phaser-time-service/SKILL.md +26 -0
- package/plugins/phaser-casual-game-factory/skills/phaser-ui-motion/SKILL.md +161 -0
- package/plugins/phaser-casual-game-factory/skills/phaser-ui-motion/fix-off-canvas-press.md +198 -0
- package/plugins/phaser-casual-game-factory/skills/phaser-ui-sfx/SKILL.md +83 -0
- package/plugins/phaser-casual-game-factory/skills/theme-cream-casual/SKILL.md +136 -0
- package/plugins/phaser-casual-game-factory/skills/theme-dark-casual/SKILL.md +23 -0
- package/plugins/phaser-casual-game-factory/skills/tool-demo-qa/SKILL.md +264 -0
- package/plugins/phaser-casual-game-factory/templates/adaptive-loading/adaptive-loading-manager.ts +103 -0
- package/plugins/phaser-casual-game-factory/templates/adaptive-loading/device-profile.ts +76 -0
- package/plugins/phaser-casual-game-factory/templates/adaptive-loading/device-tier-session.ts +133 -0
- package/plugins/phaser-casual-game-factory/templates/adaptive-loading/index.ts +4 -0
- package/plugins/phaser-casual-game-factory/templates/adaptive-loading/types.ts +27 -0
- package/plugins/phaser-casual-game-factory/templates/boot/brand/BootLoadingScreen.js +370 -0
- package/plugins/phaser-casual-game-factory/templates/boot/brand/SplashFullscreenBg.js +18 -0
- package/plugins/phaser-casual-game-factory/templates/boot/brand/brand-defaults.js +36 -0
- package/plugins/phaser-casual-game-factory/templates/boot/brand-shims.d.ts +40 -0
- package/plugins/phaser-casual-game-factory/templates/boot/close-styles.ts +26 -0
- package/plugins/phaser-casual-game-factory/templates/boot/index.ts +32 -0
- package/plugins/phaser-casual-game-factory/templates/boot/iris-close.ts +85 -0
- package/plugins/phaser-casual-game-factory/templates/boot/map-dom-rect-to-game.ts +53 -0
- package/plugins/phaser-casual-game-factory/templates/boot/play-boot-loading-view.ts +124 -0
- package/plugins/phaser-casual-game-factory/templates/commerce/commerce-service.ts +22 -0
- package/plugins/phaser-casual-game-factory/templates/commerce/index.ts +1 -0
- package/plugins/phaser-casual-game-factory/templates/commerce/types.ts +6 -0
- package/plugins/phaser-casual-game-factory/templates/condition/condition-service.ts +166 -0
- package/plugins/phaser-casual-game-factory/templates/condition/index.ts +2 -0
- package/plugins/phaser-casual-game-factory/templates/condition/types.ts +69 -0
- package/plugins/phaser-casual-game-factory/templates/core/events.ts +71 -0
- package/plugins/phaser-casual-game-factory/templates/core/gameplay.ts +15 -0
- package/plugins/phaser-casual-game-factory/templates/core/index.ts +9 -0
- package/plugins/phaser-casual-game-factory/templates/core/layout.ts +25 -0
- package/plugins/phaser-casual-game-factory/templates/core/loading.ts +33 -0
- package/plugins/phaser-casual-game-factory/templates/core/service-registry.ts +28 -0
- package/plugins/phaser-casual-game-factory/templates/core/services.ts +19 -0
- package/plugins/phaser-casual-game-factory/templates/core/storage.ts +7 -0
- package/plugins/phaser-casual-game-factory/templates/core/time.ts +70 -0
- package/plugins/phaser-casual-game-factory/templates/core/types.ts +21 -0
- package/plugins/phaser-casual-game-factory/templates/daily-login/daily-login-service.ts +136 -0
- package/plugins/phaser-casual-game-factory/templates/daily-login/index.ts +3 -0
- package/plugins/phaser-casual-game-factory/templates/daily-login/reward-service.ts +108 -0
- package/plugins/phaser-casual-game-factory/templates/daily-login/types.ts +39 -0
- package/plugins/phaser-casual-game-factory/templates/demo-tools/demo-device-tier.ts +73 -0
- package/plugins/phaser-casual-game-factory/templates/demo-tools/demo-perf.ts +232 -0
- package/plugins/phaser-casual-game-factory/templates/demo-tools/demo-tools.css +355 -0
- package/plugins/phaser-casual-game-factory/templates/demo-tools/demo-tools.ts +305 -0
- package/plugins/phaser-casual-game-factory/templates/demo-tools/index.ts +7 -0
- package/plugins/phaser-casual-game-factory/templates/demo-tools/init-demo-qa-tools.ts +101 -0
- package/plugins/phaser-casual-game-factory/templates/demo-tools/tool-param-fields.ts +214 -0
- package/plugins/phaser-casual-game-factory/templates/demo-tools/tool-sections.ts +238 -0
- package/plugins/phaser-casual-game-factory/templates/demo-tools/tool-shell.html +57 -0
- package/plugins/phaser-casual-game-factory/templates/demo-tools/tool-shell.ts +141 -0
- package/plugins/phaser-casual-game-factory/templates/economy/default-registry.ts +14 -0
- package/plugins/phaser-casual-game-factory/templates/economy/economy-service.ts +65 -0
- package/plugins/phaser-casual-game-factory/templates/economy/exchange-handlers.ts +58 -0
- package/plugins/phaser-casual-game-factory/templates/economy/grant-handler.ts +58 -0
- package/plugins/phaser-casual-game-factory/templates/economy/index.ts +15 -0
- package/plugins/phaser-casual-game-factory/templates/economy/inventory-service.ts +170 -0
- package/plugins/phaser-casual-game-factory/templates/economy/item-service.ts +220 -0
- package/plugins/phaser-casual-game-factory/templates/economy/item-utils.ts +126 -0
- package/plugins/phaser-casual-game-factory/templates/economy/merge-handler.ts +42 -0
- package/plugins/phaser-casual-game-factory/templates/economy/operation-handler.ts +44 -0
- package/plugins/phaser-casual-game-factory/templates/economy/package-handler.ts +41 -0
- package/plugins/phaser-casual-game-factory/templates/economy/random.ts +33 -0
- package/plugins/phaser-casual-game-factory/templates/economy/repository.ts +64 -0
- package/plugins/phaser-casual-game-factory/templates/economy/state-utils.ts +221 -0
- package/plugins/phaser-casual-game-factory/templates/economy/types.ts +309 -0
- package/plugins/phaser-casual-game-factory/templates/economy/ui-view-models.ts +79 -0
- package/plugins/phaser-casual-game-factory/templates/entitlement/entitlement-service.ts +29 -0
- package/plugins/phaser-casual-game-factory/templates/entitlement/index.ts +1 -0
- package/plugins/phaser-casual-game-factory/templates/entitlement/types.ts +26 -0
- package/plugins/phaser-casual-game-factory/templates/leveling/condition-evaluator.ts +17 -0
- package/plugins/phaser-casual-game-factory/templates/leveling/config-validator.ts +63 -0
- package/plugins/phaser-casual-game-factory/templates/leveling/index.ts +5 -0
- package/plugins/phaser-casual-game-factory/templates/leveling/leveling-service.ts +306 -0
- package/plugins/phaser-casual-game-factory/templates/leveling/types.ts +80 -0
- package/plugins/phaser-casual-game-factory/templates/leveling/view-model.ts +52 -0
- package/plugins/phaser-casual-game-factory/templates/loading-view/index.ts +4 -0
- package/plugins/phaser-casual-game-factory/templates/loading-view/loading-view-model.ts +203 -0
- package/plugins/phaser-casual-game-factory/templates/loading-view/presets.ts +26 -0
- package/plugins/phaser-casual-game-factory/templates/loading-view/progress.ts +30 -0
- package/plugins/phaser-casual-game-factory/templates/loading-view/types.ts +49 -0
- package/plugins/phaser-casual-game-factory/templates/motion/index.ts +2 -0
- package/plugins/phaser-casual-game-factory/templates/motion/phaser-ui-motion.ts +363 -0
- package/plugins/phaser-casual-game-factory/templates/motion/types.ts +21 -0
- package/plugins/phaser-casual-game-factory/templates/phaser/browser-storage-adapter.ts +91 -0
- package/plugins/phaser-casual-game-factory/templates/phaser/design-size.ts +34 -0
- package/plugins/phaser-casual-game-factory/templates/phaser/foundation-scene.ts +39 -0
- package/plugins/phaser-casual-game-factory/templates/phaser/hybrid-loading-layer.css +46 -0
- package/plugins/phaser-casual-game-factory/templates/phaser/loading-overlay-scene.ts +653 -0
- package/plugins/phaser-casual-game-factory/templates/phaser/phaser-event-bus.ts +35 -0
- package/plugins/phaser-casual-game-factory/templates/phaser/scene-keys.ts +12 -0
- package/plugins/phaser-casual-game-factory/templates/phaser/scene-registration.ts +28 -0
- package/plugins/phaser-casual-game-factory/templates/phaser/system-time-adapter.ts +33 -0
- package/plugins/phaser-casual-game-factory/templates/time/index.ts +2 -0
- package/plugins/phaser-casual-game-factory/templates/time/time-service.ts +184 -0
- package/plugins/phaser-casual-game-factory/templates/ui/audio-settings.ts +148 -0
- package/plugins/phaser-casual-game-factory/templates/ui/bind-factory-dom-press.ts +108 -0
- package/plugins/phaser-casual-game-factory/templates/ui/factory-cream-casual.css +380 -0
- package/plugins/phaser-casual-game-factory/templates/ui/factory-dark-casual.css +11 -0
- package/plugins/phaser-casual-game-factory/templates/ui/index.ts +5 -0
- package/plugins/phaser-casual-game-factory/templates/ui/settings-popup-dom.ts +349 -0
- package/plugins/phaser-casual-game-factory/templates/ui/settings-popup-phaser.ts +284 -0
- package/plugins/phaser-casual-game-factory/templates/ui/ui-sfx.ts +131 -0
- package/plugins/phaser-casual-game-factory/templates/ui-reskin/compare.html +235 -0
- package/plugins/phaser-casual-game-factory/tests/README.md +29 -0
- package/plugins/phaser-casual-game-factory/tests/condition.test.ts +92 -0
- package/plugins/phaser-casual-game-factory/tests/daily-login-reward.test.ts +45 -0
- package/plugins/phaser-casual-game-factory/tests/daily-login.test.ts +73 -0
- package/plugins/phaser-casual-game-factory/tests/economy.test.ts +258 -0
- package/plugins/phaser-casual-game-factory/tests/entitlement.test.ts +18 -0
- package/plugins/phaser-casual-game-factory/tests/leveling.test.ts +158 -0
- package/plugins/phaser-casual-game-factory/tests/loading-view.test.ts +39 -0
- package/plugins/phaser-casual-game-factory/tests/time.test.ts +60 -0
|
@@ -0,0 +1,1870 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
#
|
|
4
|
+
# gemini_image_mcp.py — Self-contained MCP server for image generation via the
|
|
5
|
+
# Google Gemini WEB session (cookie auth). No dependency on any git-HEAD fork,
|
|
6
|
+
# no browser-cookie3, no AGPL code, single tool surface.
|
|
7
|
+
#
|
|
8
|
+
# WHAT THIS IS / IS NOT
|
|
9
|
+
# - It talks to Google's PRIVATE web endpoints using your own session cookies.
|
|
10
|
+
# This is unofficial and may violate Google's Terms of Service. Use a throwaway
|
|
11
|
+
# Google account, never a corporate one. Risk of account action is yours.
|
|
12
|
+
# - Code cannot remove that ToS/account risk. It only removes the *software*
|
|
13
|
+
# risks: unpinned moving dependency, browser cookie scanning, and AGPL entanglement.
|
|
14
|
+
#
|
|
15
|
+
# - CẢNH BÁO: generate_image() ĐỌC file từ image_paths và GHI file vào out_dir.
|
|
16
|
+
# Bản gốc cố ý không có bề mặt file nào, để nếu expose qua tunnel thì caller
|
|
17
|
+
# không chạm được filesystem. Điều đó KHÔNG còn đúng nữa.
|
|
18
|
+
# => Server này CHỈ được chạy stdio local. KHÔNG tunnel/expose ra ngoài.
|
|
19
|
+
# - The private protocol (endpoints, RPC payload shape, model ids, image URL
|
|
20
|
+
# patterns) can change without notice. All such volatile constants are grouped
|
|
21
|
+
# in the PROTOCOL block below so you can fix them in one place.
|
|
22
|
+
#
|
|
23
|
+
# DEPENDENCIES (pin these exactly in your requirements.txt):
|
|
24
|
+
# mcp==1.12.* curl_cffi==0.14.*
|
|
25
|
+
#
|
|
26
|
+
# COOKIES (env only — nothing is scraped from your browser):
|
|
27
|
+
# Cách BỀN nhất (khuyến nghị) — nạp NGUYÊN bộ cookie như browser để tự xoay vòng:
|
|
28
|
+
# GEMINI_COOKIES_FILE đường dẫn file chứa nguyên chuỗi `Cookie:` copy từ DevTools
|
|
29
|
+
# GEMINI_COOKIES (thay thế) chính chuỗi đó nhét thẳng vào env
|
|
30
|
+
# Có đủ họ SID/SAPISID thì server tự gọi RotateCookies đúc __Secure-1PSIDTS mới,
|
|
31
|
+
# session tự trôi tới khi __Secure-1PSID gốc hết hạn (hàng tuần→tháng).
|
|
32
|
+
#
|
|
33
|
+
# Cách tối thiểu (dễ rơi hơn — thiếu cookie để rotate ổn định):
|
|
34
|
+
# GEMINI_1PSID value of the __Secure-1PSID cookie (required)
|
|
35
|
+
# GEMINI_1PSIDTS value of the __Secure-1PSIDTS cookie (recommended)
|
|
36
|
+
#
|
|
37
|
+
# OPTIONAL ENV:
|
|
38
|
+
# GEMINI_IMAGE_DIR where to save images (default ~/Pictures/gemini)
|
|
39
|
+
# GEMINI_IMAGE_MODEL_ID model id used for the image model header
|
|
40
|
+
# GEMINI_ACCOUNT_INDEX /u/<n> account slot (default 0)
|
|
41
|
+
# GEMINI_IMG_SIZE CDN size suffix for full-res download (default s2048)
|
|
42
|
+
# GEMINI_TIMEOUT per-request timeout seconds (default 300)
|
|
43
|
+
|
|
44
|
+
import asyncio
|
|
45
|
+
import hashlib
|
|
46
|
+
import io
|
|
47
|
+
import json
|
|
48
|
+
import os
|
|
49
|
+
import random
|
|
50
|
+
import re
|
|
51
|
+
import shutil
|
|
52
|
+
import sys
|
|
53
|
+
import time
|
|
54
|
+
from datetime import datetime
|
|
55
|
+
from pathlib import Path
|
|
56
|
+
from typing import Any
|
|
57
|
+
|
|
58
|
+
# .env PHẢI nạp TRƯỚC mọi import bên dưới: gemini_image_mcp (ngay file này), bgremove,
|
|
59
|
+
# upscale và remote_proto đều đọc os.environ NGAY LÚC IMPORT. Đặt sau thì file .env coi như
|
|
60
|
+
# không tồn tại, và triệu chứng là "đã tạo .env mà chẳng thấy tác dụng gì".
|
|
61
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
62
|
+
import envfile as _envfile # noqa: E402
|
|
63
|
+
_envfile.load(base=Path(__file__).resolve().parent) # .env cùng thư mục entry
|
|
64
|
+
|
|
65
|
+
from curl_cffi import CurlHttpVersion, CurlMime # noqa: E402
|
|
66
|
+
from curl_cffi.requests import AsyncSession, Cookies
|
|
67
|
+
|
|
68
|
+
import numpy as np
|
|
69
|
+
from PIL import Image
|
|
70
|
+
|
|
71
|
+
from mcp.server.fastmcp import FastMCP
|
|
72
|
+
|
|
73
|
+
import imglib as L
|
|
74
|
+
import bgremove
|
|
75
|
+
import upscale as UP
|
|
76
|
+
import remote_backend as RB
|
|
77
|
+
|
|
78
|
+
# --------------------------------------------------------------------------- #
|
|
79
|
+
# PROTOCOL — volatile constants. If Google changes their web app and generation
|
|
80
|
+
# breaks, this is the only block you should normally need to touch.
|
|
81
|
+
# --------------------------------------------------------------------------- #
|
|
82
|
+
_BASE = "https://gemini.google.com"
|
|
83
|
+
_INIT_PATH = "/app" # GET here to scrape auth tokens
|
|
84
|
+
_GENERATE_PATH = "/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate"
|
|
85
|
+
# Xoá hội thoại vừa tạo để không để lại rác trong tài khoản Gemini. Web app dùng chung
|
|
86
|
+
# endpoint batchexecute với rpcid GzXR5e, payload là [conversation_id].
|
|
87
|
+
_BATCH_PATH = "/_/BardChatUi/data/batchexecute"
|
|
88
|
+
_DELETE_RPC = "GzXR5e"
|
|
89
|
+
# Endpoint xoay vòng cookie của Google Accounts. Với đủ họ SID/SAPISID trong jar, POST vào
|
|
90
|
+
# đây trả về __Secure-1PSIDTS mới qua Set-Cookie — không phải chờ /app tình cờ set lại.
|
|
91
|
+
_ROTATE_URL = "https://accounts.google.com/RotateCookies"
|
|
92
|
+
# Luồng "trang" mà browser thật dùng cho Gemini: GET trang này -> Google Set-Cookie 1PSIDTS
|
|
93
|
+
# (đôi khi cả 1PSID) MỚI ngay trong response. Ta bắt Set-Cookie đó rồi GHI ĐÈ lại file cookie.
|
|
94
|
+
_ROTATE_PAGE_URL = "https://accounts.google.com/RotateCookiesPage"
|
|
95
|
+
|
|
96
|
+
# The "nano banana" image model id, injected via the model-selection header.
|
|
97
|
+
_IMAGE_MODEL_ID = os.environ.get("GEMINI_IMAGE_MODEL_ID", "56fdd199312815e2")
|
|
98
|
+
_MODEL_HEADER_KEY = "x-goog-ext-525001261-jspb"
|
|
99
|
+
def _model_header() -> dict[str, str]:
|
|
100
|
+
return {_MODEL_HEADER_KEY: f'[1,null,null,null,"{_IMAGE_MODEL_ID}",null,null,0,[4],null,null,1]'}
|
|
101
|
+
|
|
102
|
+
_BASE_HEADERS = {
|
|
103
|
+
"Content-Type": "application/x-www-form-urlencoded;charset=utf-8",
|
|
104
|
+
"Origin": _BASE,
|
|
105
|
+
"Referer": _BASE + "/",
|
|
106
|
+
"User-Agent": ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
|
|
107
|
+
"(KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36"),
|
|
108
|
+
"X-Same-Domain": "1",
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# Tokens embedded in the /app HTML. SNlM0e was removed by Google ~Feb 2025 and
|
|
112
|
+
# may be empty; cfb2h (build label) and FdrFJe (session id) are what matter.
|
|
113
|
+
_TOKEN_RE = {
|
|
114
|
+
"at": re.compile(r'"SNlM0e":\s*"(.*?)"'), # -> data["at"]
|
|
115
|
+
"bl": re.compile(r'"cfb2h":\s*"(.*?)"'), # -> params["bl"]
|
|
116
|
+
"f.sid": re.compile(r'"FdrFJe":\s*"(.*?)"'), # -> params["f.sid"]
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
# Image URLs Google returns inside the streamed response.
|
|
120
|
+
_IMG_URL_RE = re.compile(r'https?://lh3\.(?:googleusercontent\.com|google\.com)/[A-Za-z0-9_\-./]+')
|
|
121
|
+
|
|
122
|
+
# conversation_id của lượt chat vừa tạo (dạng "c_<hex>") — dùng để xoá hội thoại sau khi
|
|
123
|
+
# lấy xong ảnh. Nằm trong metadata new-chat của response StreamGenerate.
|
|
124
|
+
_CID_RE = re.compile(r'c_[0-9a-f]{10,}')
|
|
125
|
+
|
|
126
|
+
# File upload — Gemini web đẩy ảnh lên đây rồi tham chiếu bằng id trả về.
|
|
127
|
+
_UPLOAD_URL = "https://content-push.googleapis.com/upload/"
|
|
128
|
+
_UPLOAD_PUSH_ID = "feeds/mcudyrk2a4khkz"
|
|
129
|
+
_MAX_IMAGES = 4 # Gemini web chỉ nhận tối đa 4 ảnh / lượt
|
|
130
|
+
_MAX_IMAGE_BYTES = 7 * 1024 * 1024
|
|
131
|
+
_ALLOWED_EXT = {".png", ".jpg", ".jpeg", ".webp"}
|
|
132
|
+
_MIME_BY_EXT = {
|
|
133
|
+
".png": "image/png",
|
|
134
|
+
".jpg": "image/jpeg",
|
|
135
|
+
".jpeg": "image/jpeg",
|
|
136
|
+
".webp": "image/webp",
|
|
137
|
+
}
|
|
138
|
+
# --------------------------------------------------------------------------- #
|
|
139
|
+
|
|
140
|
+
_ACCOUNT = int(os.environ.get("GEMINI_ACCOUNT_INDEX", "0"))
|
|
141
|
+
_IMG_SIZE = os.environ.get("GEMINI_IMG_SIZE", "s2048")
|
|
142
|
+
_TIMEOUT = float(os.environ.get("GEMINI_TIMEOUT", "300"))
|
|
143
|
+
# Mặc định XOÁ đoạn chat sau mỗi lượt sinh để không làm rác tài khoản Gemini.
|
|
144
|
+
# Đặt GEMINI_DELETE_CHAT=0 (hoặc false/no) nếu muốn giữ lại lịch sử chat.
|
|
145
|
+
_DELETE_CHAT = os.environ.get("GEMINI_DELETE_CHAT", "1").strip().lower() not in ("0", "false", "no", "off", "")
|
|
146
|
+
_IMAGE_DIR = Path(os.environ.get("GEMINI_IMAGE_DIR", str(Path.home() / "Pictures" / "gemini")))
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _prefix(idx: int) -> str:
|
|
150
|
+
return f"/u/{idx}" if idx > 0 else ""
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
# __Secure-1PSIDTS XOAY VÒNG. Google trả giá trị mới qua Set-Cookie sau vài request, và giá trị
|
|
154
|
+
# CŨ chết ngay. Bản gốc nạp cookie từ env mỗi lần gọi rồi vứt cookie mới đi -> chỉ cần Google xoay
|
|
155
|
+
# một nhịp là session rơi về trạng thái ĐĂNG XUẤT. Triệu chứng rất dễ chẩn đoán nhầm: chat vẫn trả
|
|
156
|
+
# lời bình thường (Gemini cho chat ẩn danh), chỉ TẠO ẢNH là bị từ chối -> trông như lỗi model/prompt.
|
|
157
|
+
# Nên phải LƯU LẠI giá trị mới nhất và ưu tiên nó hơn env.
|
|
158
|
+
_PSIDTS_CACHE = Path(
|
|
159
|
+
os.environ.get("GEMINI_PSIDTS_CACHE", str(Path.home() / ".cache" / "gemini_mcp" / "psidts"))
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _parse_cookie_header(raw: str) -> dict[str, str]:
|
|
164
|
+
"""Tách chuỗi `Cookie:` (copy nguyên từ DevTools) thành dict tên->giá trị.
|
|
165
|
+
|
|
166
|
+
Chấp nhận cả xuống dòng lẫn "; " để dán thoải mái. Bỏ qua phần rỗng/không có "=".
|
|
167
|
+
"""
|
|
168
|
+
out: dict[str, str] = {}
|
|
169
|
+
for part in raw.replace("\n", ";").split(";"):
|
|
170
|
+
part = part.strip()
|
|
171
|
+
if not part or "=" not in part:
|
|
172
|
+
continue
|
|
173
|
+
k, _, v = part.partition("=")
|
|
174
|
+
k = k.strip()
|
|
175
|
+
if k:
|
|
176
|
+
out[k] = v.strip()
|
|
177
|
+
return out
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _raw_cookies() -> dict[str, str]:
|
|
181
|
+
"""Bộ cookie ĐẦY ĐỦ (như browser) — ưu tiên file, rồi inline env, rồi rỗng.
|
|
182
|
+
|
|
183
|
+
GEMINI_COOKIES_FILE: đường dẫn file chứa nguyên chuỗi `Cookie:`.
|
|
184
|
+
GEMINI_COOKIES: chính chuỗi đó, nhét thẳng vào env.
|
|
185
|
+
Rỗng -> quay về chế độ 2-cookie cũ (GEMINI_1PSID/1PSIDTS) trong _cookies().
|
|
186
|
+
"""
|
|
187
|
+
path = os.environ.get("GEMINI_COOKIES_FILE", "").strip()
|
|
188
|
+
if path:
|
|
189
|
+
try:
|
|
190
|
+
raw = Path(path).read_text(encoding="utf-8").strip()
|
|
191
|
+
if raw:
|
|
192
|
+
return _parse_cookie_header(raw)
|
|
193
|
+
except OSError:
|
|
194
|
+
pass
|
|
195
|
+
inline = os.environ.get("GEMINI_COOKIES", "").strip()
|
|
196
|
+
if inline:
|
|
197
|
+
return _parse_cookie_header(inline)
|
|
198
|
+
return {}
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _psidts_seed() -> str:
|
|
202
|
+
"""Hạt giống 1PSIDTS hiện tại: lấy từ bộ cookie đầy đủ nếu có, không thì env cũ.
|
|
203
|
+
|
|
204
|
+
Cache cookie-đã-xoay khoá theo hạt giống này. Đổi cookie = đổi seed = cache cũ bị vứt,
|
|
205
|
+
đúng như thiết kế ở _load_psidts (tránh cache chết đè lên cookie tươi user vừa dán).
|
|
206
|
+
"""
|
|
207
|
+
bag = _raw_cookies()
|
|
208
|
+
if bag.get("__Secure-1PSIDTS"):
|
|
209
|
+
return bag["__Secure-1PSIDTS"].strip()
|
|
210
|
+
return os.environ.get("GEMINI_1PSIDTS", "").strip()
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def _load_psidts() -> str:
|
|
214
|
+
"""Cookie đã xoay (nếu có) thắng env — NHƯNG chỉ khi nó sinh ra từ đúng env hiện tại.
|
|
215
|
+
|
|
216
|
+
Cache phải nhớ HẠT GIỐNG đã sinh ra nó. Nếu không, kịch bản này sẽ xảy ra và rất khó
|
|
217
|
+
truy: cache đi vào trạng thái chết -> user đi lấy cookie tươi dán vào env -> _load_psidts
|
|
218
|
+
vẫn ưu tiên cache -> cookie tươi BỊ BỎ QUA, session vẫn đăng xuất, user tưởng cookie mình
|
|
219
|
+
lấy sai và đi lấy lại lần nữa, mãi không thoát. Env đổi = user chủ động reset, cache vứt.
|
|
220
|
+
"""
|
|
221
|
+
seed = _psidts_seed()
|
|
222
|
+
try:
|
|
223
|
+
blob = json.loads(_PSIDTS_CACHE.read_text(encoding="utf-8"))
|
|
224
|
+
if blob.get("seed") == seed and blob.get("psidts"):
|
|
225
|
+
return blob["psidts"]
|
|
226
|
+
except (OSError, ValueError, AttributeError):
|
|
227
|
+
pass
|
|
228
|
+
return seed
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def _load_psid() -> str:
|
|
232
|
+
"""__Secure-1PSID đã xoay (nếu Google có xoay và cache khớp seed) — cùng seed với
|
|
233
|
+
1PSIDTS nên khi user dán cookie mới thì cả hai cùng bị vô hiệu, không kẹt cache chết."""
|
|
234
|
+
seed = _psidts_seed()
|
|
235
|
+
try:
|
|
236
|
+
blob = json.loads(_PSIDTS_CACHE.read_text(encoding="utf-8"))
|
|
237
|
+
if blob.get("seed") == seed and blob.get("psid"):
|
|
238
|
+
return blob["psid"]
|
|
239
|
+
except (OSError, ValueError, AttributeError):
|
|
240
|
+
pass
|
|
241
|
+
bag = _raw_cookies()
|
|
242
|
+
return bag.get("__Secure-1PSID") or os.environ.get("GEMINI_1PSID", "").strip()
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def _sapisid_auth(session: AsyncSession) -> str | None:
|
|
246
|
+
"""Header Authorization kiểu SAPISIDHASH mà Google Accounts đòi cho RotateCookies.
|
|
247
|
+
|
|
248
|
+
Dạng: '<prefix> <ts>_<sha1(f"{ts} {SAPISID} {origin}")>' cho cả 3 prefix (SAPISIDHASH,
|
|
249
|
+
SAPISID1PHASH, SAPISID3PHASH). Thiếu header này thì RotateCookies thường bỏ qua, không
|
|
250
|
+
đúc __Secure-1PSIDTS mới — nghi là mắt xích khiến rotate lâu nay không tự làm tươi được.
|
|
251
|
+
"""
|
|
252
|
+
sapisid = _cookie_val(session, "SAPISID") or _cookie_val(session, "__Secure-3PAPISID")
|
|
253
|
+
if not sapisid:
|
|
254
|
+
return None
|
|
255
|
+
ts = int(time.time())
|
|
256
|
+
raw = f"{ts} {sapisid} {_BASE}"
|
|
257
|
+
digest = hashlib.sha1(raw.encode("utf-8")).hexdigest()
|
|
258
|
+
return " ".join(f"{p} {ts}_{digest}" for p in ("SAPISIDHASH", "SAPISID1PHASH", "SAPISID3PHASH"))
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def _rotate_headers(session: AsyncSession) -> dict[str, str]:
|
|
262
|
+
h = {"Content-Type": "application/json", "Origin": _BASE, "Referer": f"{_BASE}/"}
|
|
263
|
+
auth = _sapisid_auth(session)
|
|
264
|
+
if auth:
|
|
265
|
+
h["Authorization"] = auth
|
|
266
|
+
return h
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def _cookie_val(session: AsyncSession, name: str) -> str | None:
|
|
270
|
+
"""Đọc giá trị cookie từ jar sau khi Google Set-Cookie. Thử cả domain có/không
|
|
271
|
+
chấm vì curl_cffi có thể lưu ở '.google.com' hoặc 'google.com'."""
|
|
272
|
+
for kw in ({"domain": ".google.com"}, {"domain": "google.com"}, {}):
|
|
273
|
+
try:
|
|
274
|
+
v = session.cookies.get(name, **kw)
|
|
275
|
+
if v:
|
|
276
|
+
return v
|
|
277
|
+
except Exception:
|
|
278
|
+
pass
|
|
279
|
+
return None
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def _save_psidts(session: AsyncSession) -> None:
|
|
283
|
+
"""Bắt lấy __Secure-1PSIDTS (và __Secure-1PSID nếu Google xoay) mới nhất và ghi
|
|
284
|
+
xuống cache đĩa, KÈM hạt giống.
|
|
285
|
+
|
|
286
|
+
Không có bước này thì cookie chết sau vài phút và user phải đi lấy tay lại liên tục.
|
|
287
|
+
"""
|
|
288
|
+
fresh = _cookie_val(session, "__Secure-1PSIDTS")
|
|
289
|
+
fresh_id = _cookie_val(session, "__Secure-1PSID")
|
|
290
|
+
if (not fresh or fresh == _load_psidts()) and (not fresh_id or fresh_id == _load_psid()):
|
|
291
|
+
return
|
|
292
|
+
try:
|
|
293
|
+
_PSIDTS_CACHE.parent.mkdir(parents=True, exist_ok=True)
|
|
294
|
+
_PSIDTS_CACHE.write_text(
|
|
295
|
+
json.dumps({
|
|
296
|
+
"seed": _psidts_seed(),
|
|
297
|
+
"psidts": fresh or _load_psidts(),
|
|
298
|
+
"psid": fresh_id or _load_psid(),
|
|
299
|
+
}),
|
|
300
|
+
encoding="utf-8",
|
|
301
|
+
)
|
|
302
|
+
except OSError:
|
|
303
|
+
pass # không ghi được cache thì thôi, đừng làm hỏng lượt sinh
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def _persist_cookies(session: AsyncSession) -> None:
|
|
307
|
+
"""GHI ĐÈ cookie mới (Google vừa Set-Cookie sau rotate) trở lại NGUỒN cookie.
|
|
308
|
+
|
|
309
|
+
Đây là điều user muốn: không chỉ nhớ 1PSIDTS trong cache riêng, mà cập nhật thẳng
|
|
310
|
+
file GEMINI_COOKIES_FILE để nguyên bộ `Cookie:` luôn tươi cho các request sau. Cập
|
|
311
|
+
nhật mọi cookie có trong file mà jar đã đổi + kéo thêm 1PSIDTS/1PSID nếu mới. Ghi
|
|
312
|
+
atomic (.tmp + os.replace) để không để lại file cụt. Luôn đồng bộ cache 1PSIDTS.
|
|
313
|
+
"""
|
|
314
|
+
_save_psidts(session) # cache luôn được cập nhật, kể cả khi không có file
|
|
315
|
+
path = os.environ.get("GEMINI_COOKIES_FILE", "").strip()
|
|
316
|
+
if not path:
|
|
317
|
+
return
|
|
318
|
+
try:
|
|
319
|
+
current = _parse_cookie_header(Path(path).read_text(encoding="utf-8"))
|
|
320
|
+
except OSError:
|
|
321
|
+
return
|
|
322
|
+
if not current:
|
|
323
|
+
return
|
|
324
|
+
changed = False
|
|
325
|
+
# Quét MỌI cookie google trong jar sau rotate (Google Set-Cookie cả nhóm *SIDCC:
|
|
326
|
+
# SIDCC, __Secure-1PSIDCC, __Secure-3PSIDCC... — đây mới là thứ giữ session sống),
|
|
327
|
+
# không chỉ vài tên cố định. Hợp nhất với tên đã có trong file + nhóm secure đã biết.
|
|
328
|
+
jar_names: set[str] = set()
|
|
329
|
+
try:
|
|
330
|
+
for c in session.cookies.jar:
|
|
331
|
+
if "google" in (getattr(c, "domain", "") or ""):
|
|
332
|
+
jar_names.add(c.name)
|
|
333
|
+
except Exception:
|
|
334
|
+
pass
|
|
335
|
+
names = set(current) | jar_names | {
|
|
336
|
+
"__Secure-1PSIDTS", "__Secure-3PSIDTS",
|
|
337
|
+
"__Secure-1PSID", "__Secure-3PSID",
|
|
338
|
+
"SIDCC", "__Secure-1PSIDCC", "__Secure-3PSIDCC",
|
|
339
|
+
}
|
|
340
|
+
for name in names:
|
|
341
|
+
v = _cookie_val(session, name)
|
|
342
|
+
if v and current.get(name) != v:
|
|
343
|
+
current[name] = v
|
|
344
|
+
changed = True
|
|
345
|
+
if not changed:
|
|
346
|
+
return
|
|
347
|
+
header = "; ".join(f"{k}={v}" for k, v in current.items())
|
|
348
|
+
try:
|
|
349
|
+
tmp = Path(f"{path}.tmp")
|
|
350
|
+
tmp.write_text(header, encoding="utf-8")
|
|
351
|
+
os.replace(tmp, path) # atomic
|
|
352
|
+
except OSError:
|
|
353
|
+
pass
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def _cookies() -> Cookies:
|
|
357
|
+
"""Dựng cookie jar. Ưu tiên bộ cookie ĐẦY ĐỦ (GEMINI_COOKIES[_FILE]) để RotateCookies
|
|
358
|
+
có đủ họ SID/SAPISID mà đúc 1PSIDTS mới — giống hệt browser đóng/mở lại vẫn vào được.
|
|
359
|
+
Không có bộ đầy đủ thì quay về chế độ 2-cookie cũ.
|
|
360
|
+
|
|
361
|
+
Dù ở chế độ nào, giá trị 1PSIDTS ĐÃ XOAY trong cache (nếu khớp seed) luôn thắng, vì nó
|
|
362
|
+
mới hơn cái nằm trong header cookie tĩnh user dán vào.
|
|
363
|
+
"""
|
|
364
|
+
bag = _raw_cookies()
|
|
365
|
+
psid = bag.get("__Secure-1PSID") or os.environ.get("GEMINI_1PSID", "").strip()
|
|
366
|
+
if not psid:
|
|
367
|
+
raise RuntimeError(
|
|
368
|
+
"Thiếu cookie. Set GEMINI_COOKIES_FILE (hoặc GEMINI_COOKIES) = nguyên chuỗi "
|
|
369
|
+
"`Cookie:` copy từ DevTools trên gemini.google.com; hoặc tối thiểu GEMINI_1PSID "
|
|
370
|
+
"(+GEMINI_1PSIDTS)."
|
|
371
|
+
)
|
|
372
|
+
jar = Cookies()
|
|
373
|
+
if bag:
|
|
374
|
+
for k, v in bag.items():
|
|
375
|
+
jar.set(k, v, domain=".google.com")
|
|
376
|
+
else:
|
|
377
|
+
jar.set("__Secure-1PSID", psid, domain=".google.com")
|
|
378
|
+
# Giá trị ĐÃ XOAY (cache khớp seed) luôn thắng bản tĩnh trong file/env vì nó mới hơn.
|
|
379
|
+
rotated_id = _load_psid()
|
|
380
|
+
if rotated_id:
|
|
381
|
+
jar.set("__Secure-1PSID", rotated_id, domain=".google.com")
|
|
382
|
+
psidts = _load_psidts()
|
|
383
|
+
if psidts:
|
|
384
|
+
jar.set("__Secure-1PSIDTS", psidts, domain=".google.com")
|
|
385
|
+
return jar
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def _new_session() -> AsyncSession:
|
|
389
|
+
s = AsyncSession(
|
|
390
|
+
impersonate="chrome", # real TLS fingerprint; plain httpx gets blocked
|
|
391
|
+
http_version=CurlHttpVersion.V2_0,
|
|
392
|
+
allow_redirects=True,
|
|
393
|
+
timeout=_TIMEOUT,
|
|
394
|
+
)
|
|
395
|
+
s.headers.update(_BASE_HEADERS)
|
|
396
|
+
s.cookies = _cookies()
|
|
397
|
+
return s
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
async def _rotate_psidts(session: AsyncSession) -> None:
|
|
401
|
+
"""Chủ động bảo Google Accounts cấp __Secure-1PSIDTS mới, thay vì chờ /app.
|
|
402
|
+
|
|
403
|
+
Đây là cái làm session 'tự trôi' mà không cần dán tay: chừng nào các cookie BỀN
|
|
404
|
+
(__Secure-1PSID + họ SAPISID/SID) còn sống, endpoint này luôn đúc được token ngắn hạn mới.
|
|
405
|
+
Best-effort tuyệt đối — hỏng (mạng, 401, đổi payload) thì bỏ qua, /app phía sau vẫn là
|
|
406
|
+
lưới đỡ. Payload [0,"-0000000000000000000"] là dạng RotateCookies web app dùng.
|
|
407
|
+
"""
|
|
408
|
+
try:
|
|
409
|
+
r = await session.post(
|
|
410
|
+
_ROTATE_URL,
|
|
411
|
+
json=[0, "-0000000000000000000"],
|
|
412
|
+
headers=_rotate_headers(session),
|
|
413
|
+
)
|
|
414
|
+
if r.status_code == 200:
|
|
415
|
+
_persist_cookies(session) # bắt token mới Google vừa Set-Cookie, ghi lại file
|
|
416
|
+
except Exception:
|
|
417
|
+
pass
|
|
418
|
+
# Thử THÊM luồng "trang" của browser — GET RotateCookiesPage, Google Set-Cookie cả
|
|
419
|
+
# nhóm *SIDCC (+ đôi khi 1PSIDTS/1PSID) mới; ta ghi đè lại file cookie.
|
|
420
|
+
await _rotate_cookies_page(session)
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
async def _rotate_cookies_page(session: AsyncSession) -> None:
|
|
424
|
+
"""GET https://accounts.google.com/RotateCookiesPage như iframe browser mở cho Gemini.
|
|
425
|
+
|
|
426
|
+
Google trả Set-Cookie cookie tươi (SIDCC/__Secure-1PSIDCC/__Secure-3PSIDCC..., đôi khi
|
|
427
|
+
cả 1PSIDTS/1PSID) NGAY trong response GET này. Ta bắt hết rồi GHI ĐÈ về file cookie để
|
|
428
|
+
request sau dùng bộ mới. Nếu trang có nhúng token rotate thì POST tiếp lên /RotateCookies.
|
|
429
|
+
Best-effort tuyệt đối — hỏng thì thôi, /app phía sau vẫn là lưới đỡ.
|
|
430
|
+
"""
|
|
431
|
+
try:
|
|
432
|
+
r = await session.get(
|
|
433
|
+
_ROTATE_PAGE_URL,
|
|
434
|
+
params={"og_pid": "658", "rot": "3", "origin": _BASE, "exp_id": "0"},
|
|
435
|
+
headers={
|
|
436
|
+
"Referer": f"{_BASE}/",
|
|
437
|
+
"Sec-Fetch-Dest": "iframe",
|
|
438
|
+
"Sec-Fetch-Mode": "navigate",
|
|
439
|
+
"Sec-Fetch-Site": "cross-site",
|
|
440
|
+
"Upgrade-Insecure-Requests": "1",
|
|
441
|
+
},
|
|
442
|
+
)
|
|
443
|
+
if r.status_code != 200:
|
|
444
|
+
return
|
|
445
|
+
_persist_cookies(session) # Set-Cookie đã vào jar ngay ở GET -> lưu lại
|
|
446
|
+
# Trang có thể nhúng mảng [rot,"token"] để POST xác nhận rotate; thử bắt và gửi.
|
|
447
|
+
m = re.search(r'\[\s*(\d+)\s*,\s*"([^"]{10,})"\s*\]', r.text)
|
|
448
|
+
if m:
|
|
449
|
+
try:
|
|
450
|
+
rp = await session.post(
|
|
451
|
+
_ROTATE_URL,
|
|
452
|
+
json=[int(m.group(1)), m.group(2)],
|
|
453
|
+
headers=_rotate_headers(session),
|
|
454
|
+
)
|
|
455
|
+
if rp.status_code == 200:
|
|
456
|
+
_persist_cookies(session)
|
|
457
|
+
except Exception:
|
|
458
|
+
pass
|
|
459
|
+
except Exception:
|
|
460
|
+
pass
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
class _LoggedOut(RuntimeError):
|
|
464
|
+
"""Cookie đã chết/bị thu hồi -> /app trả trang đăng xuất. Tách riêng để lớp trên
|
|
465
|
+
biết mà TỰ REFRESH cookie từ Brave rồi thử lại, thay vì ném thẳng cho user."""
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
# refresh_gemini_cookies.py là công cụ NODE, nằm ở ../server. Bản client mang đi KHÔNG có
|
|
469
|
+
# nó — nhưng đường refresh chỉ chạy ở chế độ Gemini-local (client mượn-node không đụng),
|
|
470
|
+
# và mọi chỗ dùng đều đã guard `.exists()`. Tìm ở server/ trước, rồi cạnh file (layout phẳng).
|
|
471
|
+
_REFRESH_SCRIPT = Path(__file__).resolve().parent.parent / "server" / "refresh_gemini_cookies.py"
|
|
472
|
+
if not _REFRESH_SCRIPT.exists():
|
|
473
|
+
_REFRESH_SCRIPT = Path(__file__).with_name("refresh_gemini_cookies.py")
|
|
474
|
+
# Tự chạy refresh_gemini_cookies.py khi phát hiện đăng xuất. Tắt bằng GEMINI_AUTO_REFRESH=0.
|
|
475
|
+
_AUTO_REFRESH = os.environ.get("GEMINI_AUTO_REFRESH", "1").strip().lower() not in ("0", "false", "no", "off", "")
|
|
476
|
+
_REFRESH_TIMEOUT = float(os.environ.get("GEMINI_REFRESH_TIMEOUT", "120"))
|
|
477
|
+
# Sau một lần refresh THẤT BẠI, khoá không thử lại trong ngần này giây. Không có nó thì
|
|
478
|
+
# một lô n=3 với cookie chết sẽ chạy refresh Brave 3 lần -> treo lâu vô ích.
|
|
479
|
+
_REFRESH_COOLDOWN = float(os.environ.get("GEMINI_REFRESH_COOLDOWN", "120"))
|
|
480
|
+
_last_refresh_fail = 0.0
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
async def _refresh_cookies_via_brave() -> bool:
|
|
484
|
+
"""Rotate không cứu được session bị thu hồi — chỉ ĐĂNG NHẬP LẠI từ Brave mới đúc
|
|
485
|
+
credential mới. Chạy refresh_gemini_cookies.py (đọc cookie từ profile Brave qua CDP).
|
|
486
|
+
Exit 0 = cookie tươi và ĐÃ verify đăng nhập được -> trả True.
|
|
487
|
+
|
|
488
|
+
AN TOÀN: script đó GHI ĐÈ cookies.txt bằng cookie Brave TRƯỚC khi verify, nên nếu Brave
|
|
489
|
+
đang logout thì nó xoá mất cookie TỐT user vừa dán. Vì vậy ở đây SAO LƯU file trước, và
|
|
490
|
+
KHÔI PHỤC lại nếu refresh thất bại. Kèm cooldown để cookie chết không làm mỗi lượt gen treo.
|
|
491
|
+
"""
|
|
492
|
+
global _last_refresh_fail
|
|
493
|
+
if not _AUTO_REFRESH or not _REFRESH_SCRIPT.exists():
|
|
494
|
+
return False
|
|
495
|
+
if time.monotonic() - _last_refresh_fail < _REFRESH_COOLDOWN:
|
|
496
|
+
return False # vừa thất bại xong -> đừng thử lại Brave cho từng lượt trong lô
|
|
497
|
+
|
|
498
|
+
cookie_path = os.environ.get("GEMINI_COOKIES_FILE", "").strip()
|
|
499
|
+
backup = None
|
|
500
|
+
if cookie_path:
|
|
501
|
+
try:
|
|
502
|
+
backup = Path(cookie_path).read_bytes()
|
|
503
|
+
except OSError:
|
|
504
|
+
backup = None
|
|
505
|
+
|
|
506
|
+
ok = False
|
|
507
|
+
try:
|
|
508
|
+
proc = await asyncio.create_subprocess_exec(
|
|
509
|
+
sys.executable, str(_REFRESH_SCRIPT),
|
|
510
|
+
stdout=asyncio.subprocess.PIPE,
|
|
511
|
+
stderr=asyncio.subprocess.STDOUT,
|
|
512
|
+
env=dict(os.environ),
|
|
513
|
+
)
|
|
514
|
+
try:
|
|
515
|
+
await asyncio.wait_for(proc.communicate(), timeout=_REFRESH_TIMEOUT)
|
|
516
|
+
ok = proc.returncode == 0
|
|
517
|
+
except asyncio.TimeoutError:
|
|
518
|
+
try:
|
|
519
|
+
proc.kill()
|
|
520
|
+
except Exception:
|
|
521
|
+
pass
|
|
522
|
+
except Exception:
|
|
523
|
+
ok = False
|
|
524
|
+
|
|
525
|
+
if ok:
|
|
526
|
+
_last_refresh_fail = 0.0
|
|
527
|
+
return True
|
|
528
|
+
# Thất bại -> trả cookie cũ về (script có thể đã ghi đè bằng cookie Brave logout).
|
|
529
|
+
_last_refresh_fail = time.monotonic()
|
|
530
|
+
if backup is not None and cookie_path:
|
|
531
|
+
try:
|
|
532
|
+
Path(cookie_path).write_bytes(backup)
|
|
533
|
+
except OSError:
|
|
534
|
+
pass
|
|
535
|
+
return False
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
async def _auth(session: AsyncSession) -> dict[str, str]:
|
|
539
|
+
"""GET /app and scrape the auth tokens. Raises on expired/invalid cookies."""
|
|
540
|
+
await _rotate_psidts(session) # đúc 1PSIDTS tươi TRƯỚC khi dùng, nếu có đủ cookie bền
|
|
541
|
+
url = f"{_BASE}{_prefix(_ACCOUNT)}{_INIT_PATH}"
|
|
542
|
+
r = await session.get(url)
|
|
543
|
+
r.raise_for_status()
|
|
544
|
+
if "consent.google.com" in str(r.url):
|
|
545
|
+
raise _LoggedOut("Redirected to consent page — cookies are expired/invalid. Refresh them.")
|
|
546
|
+
_persist_cookies(session) # Google vừa có thể đã xoay cookie — giữ lấy, ghi lại file
|
|
547
|
+
|
|
548
|
+
html = r.text
|
|
549
|
+
tokens = {}
|
|
550
|
+
for key, rx in _TOKEN_RE.items():
|
|
551
|
+
m = rx.search(html)
|
|
552
|
+
tokens[key] = m.group(1) if m else ""
|
|
553
|
+
if not (tokens["bl"] or tokens["f.sid"] or tokens["at"]):
|
|
554
|
+
raise _LoggedOut("Could not find any auth token in /app — layout changed or cookies bad.")
|
|
555
|
+
|
|
556
|
+
# ĐĂNG XUẤT: bắt SỚM và nói THẲNG. Không có kiểm tra này, Gemini vẫn chat bình thường (chat
|
|
557
|
+
# ẩn danh được phép) nhưng TỪ CHỐI tạo ảnh, và lỗi hiện ra là "No image URL in response" —
|
|
558
|
+
# câu đó khiến người ta đi sửa nhầm model id hoặc prompt, trong khi vấn đề chỉ là cookie chết.
|
|
559
|
+
if not tokens["at"] and "accounts.google.com/ServiceLogin" in html:
|
|
560
|
+
raise _LoggedOut(
|
|
561
|
+
"Session ĐĂNG XUẤT và auto-refresh từ Brave KHÔNG cứu được (profile Brave riêng "
|
|
562
|
+
"chưa đăng nhập, hoặc Google đã bind/thu hồi). Mở cửa sổ Brave debug mà "
|
|
563
|
+
"refresh_gemini_cookies.py bật lên, ĐĂNG NHẬP Gemini một lần, rồi thử lại. "
|
|
564
|
+
"(Tắt auto-refresh bằng GEMINI_AUTO_REFRESH=0.)"
|
|
565
|
+
)
|
|
566
|
+
return tokens
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
def _build_freq(prompt: str, files: list[tuple[str, str]] | None = None) -> str:
|
|
570
|
+
"""Dựng lại payload f.req của StreamGenerate cho một lượt chat mới.
|
|
571
|
+
|
|
572
|
+
`files` = [(file_id, filename)]. Index 3 của message_content là chỗ Gemini web
|
|
573
|
+
đặt danh sách file đính kèm; để None nếu chỉ có text.
|
|
574
|
+
"""
|
|
575
|
+
attachments = [[[fid, 1], name] for fid, name in (files or [])] or None
|
|
576
|
+
message_content: list[Any] = [prompt, 0, None, attachments, None, None, 0]
|
|
577
|
+
inner: list[Any] = [None] * 73
|
|
578
|
+
inner[0] = message_content
|
|
579
|
+
inner[2] = ["", "", "", None, None, None, None, None, None, ""] # new-chat metadata
|
|
580
|
+
inner[7] = 1 # snapshot streaming
|
|
581
|
+
return json.dumps([None, json.dumps(inner)])
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
async def _resolve_image(session: AsyncSession, url: str) -> bytes | None:
|
|
585
|
+
"""Some Google image hops return a text/plain body holding the next URL.
|
|
586
|
+
Follow up to a few hops, then return the raw image bytes."""
|
|
587
|
+
if "=" not in url.rsplit("/", 1)[-1]:
|
|
588
|
+
url = f"{url}={_IMG_SIZE}"
|
|
589
|
+
if _ACCOUNT > 0 and "authuser=" not in url:
|
|
590
|
+
url += f"{'&' if '?' in url else '?'}authuser={_ACCOUNT}"
|
|
591
|
+
for _ in range(5):
|
|
592
|
+
r = await session.get(url)
|
|
593
|
+
r.raise_for_status()
|
|
594
|
+
ctype = (r.headers.get("content-type") or "").lower()
|
|
595
|
+
if ctype.startswith("image/"):
|
|
596
|
+
return r.content
|
|
597
|
+
if ctype.startswith("text/plain"):
|
|
598
|
+
nxt = r.text.strip()
|
|
599
|
+
if nxt.startswith("http"):
|
|
600
|
+
url = nxt
|
|
601
|
+
continue
|
|
602
|
+
# Unknown but non-empty binary — assume it's the image.
|
|
603
|
+
if r.content and not ctype.startswith("text/html"):
|
|
604
|
+
return r.content
|
|
605
|
+
return None
|
|
606
|
+
return None
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
async def _delete_conversation(session: AsyncSession, tokens: dict[str, str], cid: str) -> None:
|
|
610
|
+
"""Xoá hội thoại vừa tạo trên Gemini (best-effort tuyệt đối).
|
|
611
|
+
|
|
612
|
+
Mỗi lượt generate mở một chat MỚI, để lại một mục trong lịch sử tài khoản. Sau khi đã
|
|
613
|
+
lấy xong ảnh (ảnh nằm trên CDN lh3, không phụ thuộc hội thoại) thì hội thoại vô dụng —
|
|
614
|
+
xoá luôn để không tích rác. Hỏng (mạng, đổi RPC, thiếu token) thì bỏ qua, KHÔNG được
|
|
615
|
+
làm hỏng lượt sinh: ảnh đã lưu rồi.
|
|
616
|
+
"""
|
|
617
|
+
if not cid:
|
|
618
|
+
return
|
|
619
|
+
try:
|
|
620
|
+
params: dict[str, Any] = {"rpcids": _DELETE_RPC, "_reqid": random.randint(10000, 99999), "rt": "c"}
|
|
621
|
+
if tokens.get("bl"):
|
|
622
|
+
params["bl"] = tokens["bl"]
|
|
623
|
+
if tokens.get("f.sid"):
|
|
624
|
+
params["f.sid"] = tokens["f.sid"]
|
|
625
|
+
freq = json.dumps([[[_DELETE_RPC, json.dumps([cid]), None, "generic"]]])
|
|
626
|
+
data = {"f.req": freq, "at": tokens.get("at", "")}
|
|
627
|
+
url = f"{_BASE}{_prefix(_ACCOUNT)}{_BATCH_PATH}"
|
|
628
|
+
await session.post(url, params=params, data=data)
|
|
629
|
+
except Exception:
|
|
630
|
+
pass
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
async def _upload(path: Path) -> tuple[str, str]:
|
|
634
|
+
"""Đẩy 1 ảnh lên Gemini, trả (file_id, filename).
|
|
635
|
+
|
|
636
|
+
Dùng session RIÊNG, không tái dùng session chat: _BASE_HEADERS đặt sẵn
|
|
637
|
+
Content-Type: application/x-www-form-urlencoded, mà upload cần multipart/form-data
|
|
638
|
+
kèm boundary do curl tự sinh. Tái dùng session sẽ ghi đè content-type -> upload hỏng.
|
|
639
|
+
|
|
640
|
+
Endpoint này cũng KHÔNG cần cookie auth — nó nhận file rồi trả về một id đục,
|
|
641
|
+
id đó mới được nhét vào payload StreamGenerate.
|
|
642
|
+
|
|
643
|
+
LƯU Ý curl_cffi: KHÔNG dùng được `files=`/`data=` kiểu requests/httpx — curl_cffi ném
|
|
644
|
+
NotImplementedError("files is not supported, use `multipart`"). Phải dựng CurlMime.
|
|
645
|
+
"""
|
|
646
|
+
blob = path.read_bytes()
|
|
647
|
+
|
|
648
|
+
mime = CurlMime()
|
|
649
|
+
mime.addpart(
|
|
650
|
+
name="file",
|
|
651
|
+
content_type=_MIME_BY_EXT.get(path.suffix.lower(), "application/octet-stream"),
|
|
652
|
+
filename=path.name,
|
|
653
|
+
data=blob,
|
|
654
|
+
)
|
|
655
|
+
mime.addpart(name="File name", data=path.name.encode("utf-8"))
|
|
656
|
+
|
|
657
|
+
try:
|
|
658
|
+
async with AsyncSession(impersonate="chrome", timeout=_TIMEOUT) as up:
|
|
659
|
+
r = await up.post(
|
|
660
|
+
_UPLOAD_URL,
|
|
661
|
+
headers={"push-id": _UPLOAD_PUSH_ID},
|
|
662
|
+
multipart=mime,
|
|
663
|
+
)
|
|
664
|
+
finally:
|
|
665
|
+
mime.close()
|
|
666
|
+
|
|
667
|
+
if r.status_code != 200:
|
|
668
|
+
raise RuntimeError(f"Upload thất bại cho {path.name}: HTTP {r.status_code}")
|
|
669
|
+
file_id = r.text.strip()
|
|
670
|
+
if not file_id:
|
|
671
|
+
raise RuntimeError(f"Upload cho {path.name} trả về id rỗng")
|
|
672
|
+
return file_id, path.name
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
def _validate_images(image_paths: list[str]) -> list[Path]:
|
|
676
|
+
if len(image_paths) > _MAX_IMAGES:
|
|
677
|
+
raise RuntimeError(f"Tối đa {_MAX_IMAGES} ảnh, nhận được {len(image_paths)}")
|
|
678
|
+
out: list[Path] = []
|
|
679
|
+
for raw in image_paths:
|
|
680
|
+
p = Path(raw)
|
|
681
|
+
if not p.is_file():
|
|
682
|
+
raise RuntimeError(f"Không thấy file ảnh: {p}")
|
|
683
|
+
if p.suffix.lower() not in _ALLOWED_EXT:
|
|
684
|
+
raise RuntimeError(f"Đuôi file không hỗ trợ {p.suffix} ({p.name})")
|
|
685
|
+
if p.stat().st_size > _MAX_IMAGE_BYTES:
|
|
686
|
+
raise RuntimeError(f"Ảnh quá lớn (>7MB): {p.name}")
|
|
687
|
+
out.append(p)
|
|
688
|
+
return out
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
# Xoá watermark ✦ ngay lúc tải về. Tắt bằng GEMINI_KEEP_WATERMARK=1.
|
|
692
|
+
_KEEP_WM = os.environ.get("GEMINI_KEEP_WATERMARK", "").strip().lower() in ("1", "true", "yes", "on")
|
|
693
|
+
|
|
694
|
+
|
|
695
|
+
def _strip_wm(blob: bytes) -> bytes:
|
|
696
|
+
"""Bỏ ngôi sao ✦ Gemini đóng ở góc dưới-phải, TRƯỚC khi ảnh chạm đĩa.
|
|
697
|
+
|
|
698
|
+
Phải làm ở ĐÚNG đây — điểm hẹp duy nhất mọi ảnh Gemini web đi qua — vì watermark nằm
|
|
699
|
+
trong pixel màu: mọi bước sau (tách nền, cắt sheet, resize về size asset gốc) đều bôi nó
|
|
700
|
+
ra hoặc bake thẳng vào asset xuất ra, và khi ảnh đã bị resize/cắt thì hình học
|
|
701
|
+
48x48@96px không còn đúng nên KHÔNG còn cách lấy lại pixel gốc nữa.
|
|
702
|
+
|
|
703
|
+
Dùng verify=False: ảnh ở đây chắc chắn từ Gemini web nên không cần dò, và phép đảo trộn
|
|
704
|
+
alpha là chính xác (sai số ≤ ~1 mức, xem imglib.unwatermark_gemini).
|
|
705
|
+
|
|
706
|
+
Hỏng thì trả blob GỐC: watermark là lỗi nhỏ, mất ảnh vừa sinh mới là lỗi to.
|
|
707
|
+
"""
|
|
708
|
+
if _KEEP_WM:
|
|
709
|
+
return blob
|
|
710
|
+
try:
|
|
711
|
+
with Image.open(io.BytesIO(blob)) as im:
|
|
712
|
+
im.load()
|
|
713
|
+
clean, info = L.unwatermark_gemini(im)
|
|
714
|
+
if info is None:
|
|
715
|
+
return blob
|
|
716
|
+
buf = io.BytesIO()
|
|
717
|
+
clean.save(buf, format="PNG")
|
|
718
|
+
return buf.getvalue()
|
|
719
|
+
except Exception:
|
|
720
|
+
return blob
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
def dest_of(out_dir: str | None) -> Path:
|
|
724
|
+
"""Thư mục lưu ảnh sinh ra. Tách riêng để đường local và đường mượn-máy dùng CHUNG."""
|
|
725
|
+
return Path(out_dir) if out_dir else _IMAGE_DIR
|
|
726
|
+
|
|
727
|
+
|
|
728
|
+
async def _generate(
|
|
729
|
+
prompt: str,
|
|
730
|
+
image_paths: list[str] | None = None,
|
|
731
|
+
out_dir: str | None = None,
|
|
732
|
+
) -> list[str]:
|
|
733
|
+
"""Full flow: validate -> auth -> upload ảnh -> StreamGenerate -> tải ảnh về.
|
|
734
|
+
|
|
735
|
+
CHẾ ĐỘ MƯỢN MÁY: đặt GAMEART_REMOTE_URL/TOKEN thì cả khối này chạy trên MÁY CHỦ (nơi
|
|
736
|
+
có cookie Gemini) — máy khách chỉ gửi prompt + ảnh tham chiếu dạng base64 rồi nhận ảnh
|
|
737
|
+
về và tự ghi xuống đĩa CỦA NÓ. Mọi tool phía trên không hề biết, tên tool không đổi.
|
|
738
|
+
"""
|
|
739
|
+
# Validate TRƯỚC khi mkdir: một lời gọi sai (quá 4 ảnh, sai đuôi, path không tồn tại)
|
|
740
|
+
# không nên để lại thư mục rác trên đĩa.
|
|
741
|
+
paths = _validate_images(image_paths or [])
|
|
742
|
+
|
|
743
|
+
if RB.enabled():
|
|
744
|
+
# KHÔNG rớt về local khi máy chủ hỏng: máy khách thường KHÔNG có cookie Gemini, nên
|
|
745
|
+
# "thử lại tại chỗ" chỉ đổi một lỗi rõ ràng thành một lỗi khó hiểu hơn.
|
|
746
|
+
return await RB.generate(prompt, [str(p) for p in paths], str(dest_of(out_dir)))
|
|
747
|
+
|
|
748
|
+
dest = dest_of(out_dir)
|
|
749
|
+
dest.mkdir(parents=True, exist_ok=True)
|
|
750
|
+
|
|
751
|
+
files = [await _upload(p) for p in paths]
|
|
752
|
+
|
|
753
|
+
session = _new_session()
|
|
754
|
+
try:
|
|
755
|
+
try:
|
|
756
|
+
tokens = await _auth(session)
|
|
757
|
+
except _LoggedOut:
|
|
758
|
+
# Cookie bị thu hồi -> rotate vô ích. TỰ đăng nhập lại từ Brave (profile vẫn
|
|
759
|
+
# login), ghi cookie tươi, rồi thử LẠI đúng 1 lần với session mới. Refresh hỏng
|
|
760
|
+
# (Brave chưa login/không có) thì ném _LoggedOut nguyên gốc cho user xử lý.
|
|
761
|
+
if not await _refresh_cookies_via_brave():
|
|
762
|
+
raise
|
|
763
|
+
await session.close()
|
|
764
|
+
session = _new_session()
|
|
765
|
+
tokens = await _auth(session)
|
|
766
|
+
|
|
767
|
+
params: dict[str, Any] = {"_reqid": random.randint(10000, 99999), "rt": "c"}
|
|
768
|
+
if tokens["bl"]:
|
|
769
|
+
params["bl"] = tokens["bl"]
|
|
770
|
+
if tokens["f.sid"]:
|
|
771
|
+
params["f.sid"] = tokens["f.sid"]
|
|
772
|
+
|
|
773
|
+
data = {"at": tokens["at"], "f.req": _build_freq(prompt, files)}
|
|
774
|
+
gen_url = f"{_BASE}{_prefix(_ACCOUNT)}{_GENERATE_PATH}"
|
|
775
|
+
|
|
776
|
+
r = await session.post(gen_url, params=params, data=data, headers=_model_header())
|
|
777
|
+
if r.status_code != 200:
|
|
778
|
+
raise RuntimeError(f"StreamGenerate failed: HTTP {r.status_code}")
|
|
779
|
+
|
|
780
|
+
body = r.text
|
|
781
|
+
if body.startswith(")]}'"):
|
|
782
|
+
body = body[4:]
|
|
783
|
+
|
|
784
|
+
# Robust extraction: pull every image URL out of the raw frames, dedup,
|
|
785
|
+
# preserve order. More resilient than depending on exact nested indices.
|
|
786
|
+
seen: set[str] = set()
|
|
787
|
+
urls: list[str] = []
|
|
788
|
+
for u in _IMG_URL_RE.findall(body):
|
|
789
|
+
u = u.replace("\\/", "/").rstrip("\\")
|
|
790
|
+
if u not in seen:
|
|
791
|
+
seen.add(u)
|
|
792
|
+
urls.append(u)
|
|
793
|
+
if not urls:
|
|
794
|
+
raise RuntimeError(
|
|
795
|
+
"No image URL in response. The prompt may have been refused, or the "
|
|
796
|
+
"image model id / URL pattern changed. Try a clearer 'generate an image of ...' prompt."
|
|
797
|
+
)
|
|
798
|
+
|
|
799
|
+
saved: list[str] = []
|
|
800
|
+
stamp = datetime.now().strftime("%Y%m%d%H%M%S")
|
|
801
|
+
for i, u in enumerate(urls):
|
|
802
|
+
try:
|
|
803
|
+
blob = await _resolve_image(session, u)
|
|
804
|
+
except Exception:
|
|
805
|
+
blob = None
|
|
806
|
+
if not blob:
|
|
807
|
+
continue
|
|
808
|
+
out = dest / f"{stamp}_{i}.png"
|
|
809
|
+
out.write_bytes(_strip_wm(blob))
|
|
810
|
+
saved.append(str(out))
|
|
811
|
+
|
|
812
|
+
# Ảnh đã tải xong (nằm trên CDN, độc lập với hội thoại) -> xoá chat vừa tạo để không
|
|
813
|
+
# làm rác tài khoản Gemini. Best-effort: chạy TRƯỚC khi kiểm 'saved' rỗng để cả lượt
|
|
814
|
+
# hỏng-download cũng không để lại chat treo.
|
|
815
|
+
if _DELETE_CHAT:
|
|
816
|
+
m = _CID_RE.search(body)
|
|
817
|
+
if m:
|
|
818
|
+
await _delete_conversation(session, tokens, m.group(0))
|
|
819
|
+
|
|
820
|
+
if not saved:
|
|
821
|
+
raise RuntimeError("Found image URLs but could not download any (cookies/redirect issue).")
|
|
822
|
+
return saved
|
|
823
|
+
finally:
|
|
824
|
+
await session.close()
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
# --------------------------------------------------------------------------- #
|
|
828
|
+
# RESTYLE HELPERS — port nguyên từ scripts/restyle.py (CLI cũ), giữ y hệt các
|
|
829
|
+
# rào an toàn của `apply` vì đó là nơi có thể phá HỎNG asset gốc của người dùng.
|
|
830
|
+
# --------------------------------------------------------------------------- #
|
|
831
|
+
def _open_rgba(path: str) -> Image.Image:
|
|
832
|
+
return Image.open(path).convert("RGBA")
|
|
833
|
+
|
|
834
|
+
|
|
835
|
+
def _parse_size(s: str) -> tuple[int, int]:
|
|
836
|
+
w, _, h = s.lower().partition("x")
|
|
837
|
+
return (int(w), int(h))
|
|
838
|
+
|
|
839
|
+
|
|
840
|
+
# Auto-key: chroma-key trượt CẢ KHUNG khi model vẽ nền LỆCH màu key yêu cầu (đo thật:
|
|
841
|
+
# yêu cầu #00FF00, agy/Nano Banana vẽ "xanh studio" #2ED246 kèm vignette -> coverage=1.0,
|
|
842
|
+
# bad_background, dù bản sinh dùng tốt). Trước khi bắt sinh lại (tốn 1 lượt), dò màu nền
|
|
843
|
+
# THẬT từ vành ảnh và key lại bằng màu đó. Chỉ áp cho đường chroma-key — BEN2 không quan
|
|
844
|
+
# tâm màu nền nên không bao giờ cần cứu kiểu này.
|
|
845
|
+
_AUTOKEY_MIN_PURITY = 0.85 # vành phải thuần 1 màu mới dám tin nó là nền phẳng
|
|
846
|
+
_AUTOKEY_MIN_DIST = 40.0 # màu dò được phải LỆCH hẳn key yêu cầu (không thì key lại vô ích)
|
|
847
|
+
|
|
848
|
+
|
|
849
|
+
def _postprocess_autokey(img, key_hex, src_img, size_wh, cutout, full_bleed=False, up=None):
|
|
850
|
+
"""L.postprocess ở chế độ ĐA PHƯƠNG PHÁP. Trả (out_img, report).
|
|
851
|
+
|
|
852
|
+
report luôn có `key_auto` (bool); khi màu nền dò được lệch hẳn màu yêu cầu thì `key` là
|
|
853
|
+
màu ĐÃ DÙNG còn `key_requested` giữ màu ban đầu. Ngoài ra có `cutout_method` (cách đã
|
|
854
|
+
thắng) và `cutout_table` (điểm của MỌI ứng viên, kể cả bị loại).
|
|
855
|
+
|
|
856
|
+
KHÔNG còn tự dò `bg_hex` rồi truyền vào nữa — `L.best_cutout` bên trong postprocess làm
|
|
857
|
+
việc đó tốt hơn hẳn, và truyền tay sẽ CHẶN nó tự dò:
|
|
858
|
+
• nó dùng MODE trên vành đã lọc theo màu key, thay cho MEAN của sample_border_color.
|
|
859
|
+
Đo thật trên ảnh nền full-bleed (home_grass/gpt1.png): mean trả `#AC4978` purity
|
|
860
|
+
**0.0002** nên cửa `purity >= 0.85` không bao giờ mở và cả pipeline rơi về màu yêu
|
|
861
|
+
cầu; mode trả `#FB0EE0`, đúng màu model đã vẽ.
|
|
862
|
+
• nhịp "tự cứu" cũ (dò màu -> nếu bad_subject thì quay về màu yêu cầu) cũng bỏ được:
|
|
863
|
+
best_cutout luôn để CẢ HAI cách trong danh sách ứng viên rồi chấm điểm, nên không
|
|
864
|
+
cần chạy lại lần hai và không cần đoán trước cách nào đúng.
|
|
865
|
+
`sample_border_color` vẫn được đo và báo cáo (`bg_sampled`/`bg_purity`) để đối chiếu.
|
|
866
|
+
|
|
867
|
+
`full_bleed`: chuyển tiếp cho postprocess — xem docstring ở đó. Bật cho ảnh nền tràn viền.
|
|
868
|
+
`up`: backend phóng to (upscale.upscale_rgb) — chỉ có tác dụng khi bản sinh NHỎ hơn
|
|
869
|
+
khung đích. Ảnh sinh thường TO hơn asset game nên phần lớn lượt chạy sẽ không đụng tới.
|
|
870
|
+
"""
|
|
871
|
+
out_img, report = L.postprocess(
|
|
872
|
+
img, key_hex, src=src_img, size=size_wh, cutout=cutout, full_bleed=full_bleed,
|
|
873
|
+
upscale=up,
|
|
874
|
+
)
|
|
875
|
+
|
|
876
|
+
# Hợp đồng báo cáo giữ nguyên như đời auto-key: key_auto=True khi màu THẬT DÙNG để key
|
|
877
|
+
# lệch hẳn màu yêu cầu; `key` là màu đã dùng, `key_requested` giữ màu ban đầu.
|
|
878
|
+
used = report.get("bg_color_used", key_hex)
|
|
879
|
+
auto = L.color_dist(L.hex_to_rgb(used), L.hex_to_rgb(key_hex)) >= _AUTOKEY_MIN_DIST
|
|
880
|
+
report["key_auto"] = auto
|
|
881
|
+
if auto:
|
|
882
|
+
report["key"] = used
|
|
883
|
+
report["key_requested"] = key_hex
|
|
884
|
+
bg_sampled, purity = L.sample_border_color(img)
|
|
885
|
+
report["bg_sampled"] = bg_sampled
|
|
886
|
+
report["bg_purity"] = purity
|
|
887
|
+
return out_img, report
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
def _sanitize_drive_component(drive: str) -> str:
|
|
891
|
+
"""Biến prefix ổ đĩa/UNC thành MỘT thành phần đường dẫn phẳng, an toàn.
|
|
892
|
+
|
|
893
|
+
Với dst là đường dẫn UNC (`\\\\server\\share\\art\\a.png`), `dst.drive` =
|
|
894
|
+
`\\\\server\\share` — CHÍNH nó đã là một anchor tuyệt đối theo pathlib. Nối trực tiếp
|
|
895
|
+
`Path("_abs") / dst.drive / ...` khiến pathlib coi vế phải là gốc mới và ÂM THẦM VỨT
|
|
896
|
+
BỎ mọi thứ bên trái (kể cả `backup_dir`) — backup thoát hẳn ra khỏi `backup_dir`, có
|
|
897
|
+
thể trùng khớp lên chính `dst`. Hàm này tước mọi separator/colon ở đầu-cuối rồi thay
|
|
898
|
+
separator còn lại bằng "_", đảm bảo kết quả KHÔNG BAO GIỜ được pathlib hiểu là rooted.
|
|
899
|
+
"""
|
|
900
|
+
s = drive.strip("\\/")
|
|
901
|
+
s = s.replace(":", "").replace("\\", "_").replace("/", "_")
|
|
902
|
+
return s or "root"
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
def _backup_path(backup_dir: Path, dst: Path, project_root: Path | None = None) -> Path:
|
|
906
|
+
"""Backup mirror ĐƯỜNG DẪN của dst (tính từ `project_root`), không chỉ basename.
|
|
907
|
+
|
|
908
|
+
backup_dir/<basename> đụng nhau khi hai asset trùng tên (img/a/icon.png vs
|
|
909
|
+
img/b/icon.png). Guard "không ghi đè backup đã có" khi đó sẽ thấy backup của asset
|
|
910
|
+
ĐẦU, bỏ qua bước backup asset thứ hai, và bản gốc thứ hai bị ghi đè mà không lưu ở đâu
|
|
911
|
+
cả. Mirror path giữ mỗi asset một backup riêng.
|
|
912
|
+
|
|
913
|
+
`project_root` KHÔNG được ngầm định cwd ở đây — cwd lúc gọi là trạng thái AMBIENT.
|
|
914
|
+
Hai lần `apply` cùng `dst` gọi từ hai cwd khác nhau sẽ mirror ra HAI backup path khác
|
|
915
|
+
nhau, và bản ghi thứ hai coi asset "chưa có backup" rồi ghi đè lên biến thể #1 thay vì
|
|
916
|
+
bản gốc thật. Luôn truyền `project_root` cố định.
|
|
917
|
+
"""
|
|
918
|
+
dst = dst.resolve()
|
|
919
|
+
root = (project_root if project_root is not None else Path.cwd()).resolve()
|
|
920
|
+
try:
|
|
921
|
+
rel = dst.relative_to(root)
|
|
922
|
+
except ValueError:
|
|
923
|
+
rel = Path("_abs", _sanitize_drive_component(dst.drive), *dst.parts[1:])
|
|
924
|
+
return backup_dir / rel
|
|
925
|
+
|
|
926
|
+
|
|
927
|
+
# --------------------------------------------------------------------------- #
|
|
928
|
+
# MCP surface. These tools NOW read image_paths and write out_dir/dst,
|
|
929
|
+
# so exposing this over a network tunnel WOULD hand callers local file access.
|
|
930
|
+
# stdio-local only. See CẢNH BÁO in the header docstring above.
|
|
931
|
+
# --------------------------------------------------------------------------- #
|
|
932
|
+
mcp = FastMCP("gemini-image")
|
|
933
|
+
|
|
934
|
+
|
|
935
|
+
@mcp.tool()
|
|
936
|
+
async def generate_image(
|
|
937
|
+
prompt: str,
|
|
938
|
+
image_paths: list[str] | None = None,
|
|
939
|
+
out_dir: str | None = None,
|
|
940
|
+
) -> str:
|
|
941
|
+
"""Sinh ảnh từ prompt, có thể kèm ảnh đầu vào (image-to-image).
|
|
942
|
+
|
|
943
|
+
Args:
|
|
944
|
+
prompt: Mô tả cần vẽ. Khi có image_paths, hãy nói rõ "the FIRST image",
|
|
945
|
+
"the SECOND image" để chỉ đúng ảnh nào.
|
|
946
|
+
image_paths: Tối đa 4 ảnh (.png/.jpg/.jpeg/.webp, mỗi ảnh <=7MB) gửi kèm
|
|
947
|
+
làm ảnh tham chiếu — dùng cho restyle giữ nguyên hình dạng.
|
|
948
|
+
out_dir: Thư mục lưu ảnh. Mặc định GEMINI_IMAGE_DIR.
|
|
949
|
+
Returns:
|
|
950
|
+
Các đường dẫn PNG đã lưu, cách nhau bằng xuống dòng.
|
|
951
|
+
"""
|
|
952
|
+
try:
|
|
953
|
+
paths = await _generate(prompt.strip(), image_paths, out_dir)
|
|
954
|
+
return "Saved:\n" + "\n".join(paths)
|
|
955
|
+
except Exception as e:
|
|
956
|
+
return f"Error: {type(e).__name__}: {e}"
|
|
957
|
+
|
|
958
|
+
|
|
959
|
+
@mcp.tool()
|
|
960
|
+
async def plan_asset(src: str, avoid: list[str] | None = None) -> dict:
|
|
961
|
+
"""Đọc asset gốc -> size, bbox, bảng màu, và MÀU KEY an toàn để tách nền.
|
|
962
|
+
|
|
963
|
+
Chạy TRƯỚC khi restyle: cho biết dùng màu key nào, có an toàn không, và kích thước
|
|
964
|
+
đích để bám 1-1 khi thay asset.
|
|
965
|
+
|
|
966
|
+
Args:
|
|
967
|
+
src: đường dẫn asset gốc (.png…).
|
|
968
|
+
avoid: danh sách hex ("#RRGGBB") của BẢNG MÀU STYLE PRESET — gộp vào việc chấm
|
|
969
|
+
điểm chọn key. BẮT BUỘC truyền khi đã có style: chroma key chạy trên ảnh ĐÃ
|
|
970
|
+
RESTYLE (palette mới), không phải palette asset gốc mà tool này tự đọc; bỏ qua
|
|
971
|
+
thì một style neon-xanh-lá trên asset đỏ vẫn có thể khiến chọn nhầm xanh lá.
|
|
972
|
+
Returns:
|
|
973
|
+
dict gồm width, height, bbox, palette, key, key_margin, key_safe.
|
|
974
|
+
key_safe=false -> màu key sát màu asset, chủ thể có nguy cơ ra mờ như bóng ma.
|
|
975
|
+
"""
|
|
976
|
+
try:
|
|
977
|
+
img = _open_rgba(src)
|
|
978
|
+
avoid_rgb = [L.hex_to_rgb(h.strip()) for h in (avoid or []) if h.strip()]
|
|
979
|
+
key, margin = L.pick_key_color(img, avoid=avoid_rgb)
|
|
980
|
+
safe = margin == float("inf") or margin >= L.MIN_KEY_MARGIN
|
|
981
|
+
return {
|
|
982
|
+
"path": src,
|
|
983
|
+
"width": img.width,
|
|
984
|
+
"height": img.height,
|
|
985
|
+
"bbox": L.content_bbox(img),
|
|
986
|
+
"palette": L.extract_palette(img, n=8),
|
|
987
|
+
"key": key,
|
|
988
|
+
"key_margin": None if margin == float("inf") else round(margin, 1),
|
|
989
|
+
"key_safe": safe,
|
|
990
|
+
}
|
|
991
|
+
except Exception as e:
|
|
992
|
+
return {"error": f"{type(e).__name__}: {e}"}
|
|
993
|
+
|
|
994
|
+
|
|
995
|
+
@mcp.tool()
|
|
996
|
+
async def restyle_asset(
|
|
997
|
+
prompt: str,
|
|
998
|
+
image_paths: list[str],
|
|
999
|
+
src: str | None = None,
|
|
1000
|
+
key: str | None = None,
|
|
1001
|
+
size: str | None = None,
|
|
1002
|
+
n: int = 3,
|
|
1003
|
+
out_dir: str | None = None,
|
|
1004
|
+
full_bleed: bool = False,
|
|
1005
|
+
) -> dict:
|
|
1006
|
+
"""Sinh N biến thể restyle rồi TÁCH NỀN + bám kích thước gốc cho từng bản (gộp
|
|
1007
|
+
generate + postprocess). Trả đường dẫn ảnh input/output kèm cờ lỗi để duyệt.
|
|
1008
|
+
|
|
1009
|
+
Tách nền chạy NHIỀU cách rồi chấm điểm chọn bản tốt nhất — xem `process_raws`.
|
|
1010
|
+
|
|
1011
|
+
Mỗi biến thể là một lượt Gemini ĐỘC LẬP (chat mới). Ảnh thô lưu ở out_dir/_raw/,
|
|
1012
|
+
ảnh đã tách nền lưu out_dir/v{i}.png.
|
|
1013
|
+
|
|
1014
|
+
Args:
|
|
1015
|
+
prompt: prompt đầy đủ (đã nhét sẵn màu nền key vào — xem `key`).
|
|
1016
|
+
image_paths: [asset_gốc, (anchor/ref…)] tối đa 4 ảnh cho mỗi lượt.
|
|
1017
|
+
src: asset gốc để BÁM size+bbox 1-1 (thường = image_paths[0]). Bỏ qua nếu dùng `size`.
|
|
1018
|
+
key: màu key HEX cho chroma key — PHẢI khớp màu nền mà `prompt` yêu cầu Gemini vẽ.
|
|
1019
|
+
Bỏ trống -> suy ra từ `src` (chỉ đúng khi prompt cũng dùng đúng màu đó).
|
|
1020
|
+
size: "WxH" ép kích thước khác thay vì bám `src`.
|
|
1021
|
+
n: số biến thể (mặc định 3). Mỗi biến thể tốn 1 lượt Gemini.
|
|
1022
|
+
out_dir: thư mục lưu. Mặc định GEMINI_IMAGE_DIR.
|
|
1023
|
+
full_bleed: BẬT cho ảnh NỀN tràn viền — xem `process_raws`. Mặc định tắt (asset rời).
|
|
1024
|
+
Returns:
|
|
1025
|
+
dict: key, size, src, n_requested, n_produced, variants[] (mỗi phần tử có
|
|
1026
|
+
out/raw/status/flags/coverage/solid_ratio/border_impurity/hole_ratio/
|
|
1027
|
+
speckles_removed/key_auto/cutout_method/cutout_table — key_auto=true nghĩa là màu
|
|
1028
|
+
nền dò được lệch hẳn key yêu cầu nên tool đã key theo màu dò được; khi đó
|
|
1029
|
+
`key` là màu dò được, `key_requested` giữ màu ban đầu. `cutout_method` là cách tách
|
|
1030
|
+
nền đã THẮNG điểm, `cutout_table` là điểm của mọi ứng viên kể cả bị loại), gen_errors[].
|
|
1031
|
+
"""
|
|
1032
|
+
try:
|
|
1033
|
+
if n < 1:
|
|
1034
|
+
return {"error": "n phải >= 1"}
|
|
1035
|
+
src_img = _open_rgba(src) if src else None
|
|
1036
|
+
size_wh = _parse_size(size) if size else None
|
|
1037
|
+
if src_img is None and size_wh is None:
|
|
1038
|
+
return {"error": "cần `src` (bám gốc) hoặc `size` (WxH)"}
|
|
1039
|
+
|
|
1040
|
+
if key:
|
|
1041
|
+
key_hex = key
|
|
1042
|
+
elif src_img is not None:
|
|
1043
|
+
key_hex = L.pick_key_color(src_img)[0]
|
|
1044
|
+
else:
|
|
1045
|
+
key_hex = L.KEY_CANDIDATES[0]
|
|
1046
|
+
|
|
1047
|
+
dest = Path(out_dir) if out_dir else _IMAGE_DIR
|
|
1048
|
+
raw_dir = dest / "_raw"
|
|
1049
|
+
raw_dir.mkdir(parents=True, exist_ok=True)
|
|
1050
|
+
|
|
1051
|
+
# Tách nền "xịn" bằng BEN2 nếu có torch+ben2; nếu thiếu thì rớt về chroma-key.
|
|
1052
|
+
# Ưu tiên GPU TẠI CHỖ; không có thì mượn máy chủ. Thứ tự này là cố ý — chạy local
|
|
1053
|
+
# luôn nhanh hơn và không tốn băng thông; mượn máy chỉ để cứu máy không có GPU.
|
|
1054
|
+
cutout = (bgremove.remove_background if bgremove.available()
|
|
1055
|
+
else RB.cutout_backend())
|
|
1056
|
+
# Backend PHÓNG TO — chỉ có tác dụng khi bản sinh NHỎ hơn khung đích. Không có ở đâu
|
|
1057
|
+
# cả thì None và mọi thứ rơi về LANCZOS, KHÔNG lỗi.
|
|
1058
|
+
up = UP.backend() or RB.upscale_backend()
|
|
1059
|
+
# `remover` giờ là DANH SÁCH Ứng viên khả dụng, không phải cách sẽ dùng: tách nền chạy
|
|
1060
|
+
# nhiều cách rồi chấm điểm, nên cách THẬT SỰ dùng cho từng ảnh nằm ở
|
|
1061
|
+
# variants[i]["cutout_method"]. Báo "ben2" ở đây từng đúng khi BEN2 độc quyền,
|
|
1062
|
+
# nhưng bây giờ nó sẽ NÓI SAI — đo thật trên 4 bản home_grass: remover="ben2"
|
|
1063
|
+
# trong khi cả 4 đều thắng bằng `unmix`.
|
|
1064
|
+
remover = "multi+ben2" if cutout else "multi"
|
|
1065
|
+
|
|
1066
|
+
variants: list[dict] = []
|
|
1067
|
+
gen_errors: list[str] = []
|
|
1068
|
+
idx = 0
|
|
1069
|
+
for _ in range(n):
|
|
1070
|
+
try:
|
|
1071
|
+
raws = await _generate(prompt.strip(), image_paths, str(raw_dir))
|
|
1072
|
+
except Exception as e:
|
|
1073
|
+
gen_errors.append(f"{type(e).__name__}: {e}")
|
|
1074
|
+
continue
|
|
1075
|
+
for raw in raws:
|
|
1076
|
+
idx += 1
|
|
1077
|
+
out_img, report = _postprocess_autokey(
|
|
1078
|
+
_open_rgba(raw), key_hex, src_img, size_wh, cutout,
|
|
1079
|
+
full_bleed=full_bleed, up=up,
|
|
1080
|
+
)
|
|
1081
|
+
report["raw"] = raw
|
|
1082
|
+
report["remover"] = report.get("cutout_method") or remover
|
|
1083
|
+
report["cutout_candidates_available"] = remover
|
|
1084
|
+
if out_img is None:
|
|
1085
|
+
report["out"] = None
|
|
1086
|
+
else:
|
|
1087
|
+
out_path = dest / f"v{idx}.png"
|
|
1088
|
+
out_img.save(out_path, optimize=True)
|
|
1089
|
+
report["out"] = str(out_path)
|
|
1090
|
+
variants.append(report)
|
|
1091
|
+
|
|
1092
|
+
return {
|
|
1093
|
+
"key": key_hex,
|
|
1094
|
+
"remover": remover,
|
|
1095
|
+
"upscaler": UP.info(),
|
|
1096
|
+
"remote": RB.info(),
|
|
1097
|
+
"size": list(size_wh) if size_wh else None,
|
|
1098
|
+
"src": src,
|
|
1099
|
+
"out_dir": str(dest),
|
|
1100
|
+
"n_requested": n,
|
|
1101
|
+
"n_produced": len(variants),
|
|
1102
|
+
"variants": variants,
|
|
1103
|
+
"gen_errors": gen_errors,
|
|
1104
|
+
"compare_group": _compare_group(src, dest, variants),
|
|
1105
|
+
}
|
|
1106
|
+
except Exception as e:
|
|
1107
|
+
return {"error": f"{type(e).__name__}: {e}"}
|
|
1108
|
+
|
|
1109
|
+
|
|
1110
|
+
@mcp.tool()
|
|
1111
|
+
async def process_raws(
|
|
1112
|
+
raws: list[str],
|
|
1113
|
+
src: str | None = None,
|
|
1114
|
+
key: str | None = None,
|
|
1115
|
+
size: str | None = None,
|
|
1116
|
+
out_dir: str | None = None,
|
|
1117
|
+
prefix: str = "v",
|
|
1118
|
+
full_bleed: bool = False,
|
|
1119
|
+
) -> dict:
|
|
1120
|
+
"""TÁCH NỀN + bám size gốc cho ảnh THÔ sinh từ backend NGOÀI (agy CLI / Codex CLI).
|
|
1121
|
+
|
|
1122
|
+
Đây là nửa postprocess của restyle_asset tách riêng: khi ảnh thô KHÔNG do Gemini
|
|
1123
|
+
MCP sinh (Antigravity `agy` hoặc Codex `codex` đã sinh và lưu file), đưa danh sách
|
|
1124
|
+
file vào đây để tách nền + bám size+bbox asset gốc, trả về cùng cấu trúc variants[]
|
|
1125
|
+
như restyle_asset để duyệt chung một luồng.
|
|
1126
|
+
|
|
1127
|
+
TÁCH NỀN CHẠY NHIỀU CÁCH RỒI CHỌN BẢN TỐT NHẤT (không còn tin sẵn một cách): unmix đại
|
|
1128
|
+
số theo màu nền đo được, chroma-key theo màu đo được, chroma-key theo màu yêu cầu, và
|
|
1129
|
+
BEN2 nếu có. Mỗi bản được chấm bằng 4 tiêu chí đo được (viền còn ám màu nền / sai màu
|
|
1130
|
+
tiền cảnh / ăn lòng chủ thể / nền còn sót); bản điểm tốt nhất được giao ra, tên nó ở
|
|
1131
|
+
`cutout_method` và bảng điểm đủ mọi ứng viên ở `cutout_table`.
|
|
1132
|
+
|
|
1133
|
+
Args:
|
|
1134
|
+
raws: ảnh thô đã sinh sẵn (.png/.jpg/.jpeg/.webp), theo thứ tự muốn đánh số.
|
|
1135
|
+
src: asset gốc để BÁM size+bbox 1-1. Bỏ qua nếu dùng `size`.
|
|
1136
|
+
key: màu key HEX — PHẢI khớp màu nền mà prompt đã yêu cầu backend vẽ.
|
|
1137
|
+
Bỏ trống -> suy ra từ `src` (chỉ đúng khi prompt cũng dùng đúng màu đó).
|
|
1138
|
+
size: "WxH" ép kích thước khác thay vì bám `src`.
|
|
1139
|
+
out_dir: thư mục lưu ảnh đã tách nền. Mặc định GEMINI_IMAGE_DIR.
|
|
1140
|
+
prefix: tiền tố tên file ra, dùng đánh dấu backend — "agy" -> agy1.png, agy2.png;
|
|
1141
|
+
"gpt" -> gpt1.png... Mặc định "v". Chỉ nhận [A-Za-z0-9_-], tối đa 32 ký tự.
|
|
1142
|
+
full_bleed: BẬT cho ảnh NỀN tràn viền (background plate) — tranh phủ kín khung nên
|
|
1143
|
+
chủ thể CHẠM vành ảnh là đúng thiết kế. Nó tắt riêng cửa gác `border_impurity`
|
|
1144
|
+
(cửa đó giả định vành ảnh toàn là nền). Không bật thì MỌI ảnh nền đều bị đánh
|
|
1145
|
+
`bad_background` dù tách nền hoàn hảo — đo thật trên 4 bản home_grass: cast 0,
|
|
1146
|
+
bg_residue 0.0000, vẫn bị báo hỏng. `bg_residue`/`coverage`/bộ chấm điểm vẫn gác
|
|
1147
|
+
như thường. ĐỪNG bật cho asset rời (sprite/icon) — ở đó lề nền là yêu cầu thật.
|
|
1148
|
+
Returns:
|
|
1149
|
+
dict: key, remover, size, src, out_dir, n_raws, n_produced, variants[] (mỗi
|
|
1150
|
+
phần tử có out/raw/status/flags/coverage/solid_ratio/border_impurity/
|
|
1151
|
+
hole_ratio/speckles_removed/key_auto/cutout_method/cutout_table — xem restyle_asset
|
|
1152
|
+
về ý nghĩa key_auto/key_requested), errors[] (raw không đọc được).
|
|
1153
|
+
"""
|
|
1154
|
+
try:
|
|
1155
|
+
if not raws:
|
|
1156
|
+
return {"error": "raws rỗng — cần ít nhất 1 ảnh thô"}
|
|
1157
|
+
# prefix đi thẳng vào tên file trong out_dir — chặn separator/'..' để không
|
|
1158
|
+
# thoát ra ngoài thư mục đích.
|
|
1159
|
+
if not re.fullmatch(r"[A-Za-z0-9_-]{1,32}", prefix):
|
|
1160
|
+
return {"error": f"prefix không hợp lệ ({prefix!r}) — chỉ [A-Za-z0-9_-], <=32 ký tự"}
|
|
1161
|
+
src_img = _open_rgba(src) if src else None
|
|
1162
|
+
size_wh = _parse_size(size) if size else None
|
|
1163
|
+
if src_img is None and size_wh is None:
|
|
1164
|
+
return {"error": "cần `src` (bám gốc) hoặc `size` (WxH)"}
|
|
1165
|
+
|
|
1166
|
+
if key:
|
|
1167
|
+
key_hex = key
|
|
1168
|
+
elif src_img is not None:
|
|
1169
|
+
key_hex = L.pick_key_color(src_img)[0]
|
|
1170
|
+
else:
|
|
1171
|
+
key_hex = L.KEY_CANDIDATES[0]
|
|
1172
|
+
|
|
1173
|
+
dest = Path(out_dir) if out_dir else _IMAGE_DIR
|
|
1174
|
+
dest.mkdir(parents=True, exist_ok=True)
|
|
1175
|
+
|
|
1176
|
+
# Ưu tiên GPU TẠI CHỖ; không có thì mượn máy chủ. Thứ tự này là cố ý — chạy local
|
|
1177
|
+
# luôn nhanh hơn và không tốn băng thông; mượn máy chỉ để cứu máy không có GPU.
|
|
1178
|
+
cutout = (bgremove.remove_background if bgremove.available()
|
|
1179
|
+
else RB.cutout_backend())
|
|
1180
|
+
# Backend PHÓNG TO — chỉ có tác dụng khi bản sinh NHỎ hơn khung đích. Không có ở đâu
|
|
1181
|
+
# cả thì None và mọi thứ rơi về LANCZOS, KHÔNG lỗi.
|
|
1182
|
+
up = UP.backend() or RB.upscale_backend()
|
|
1183
|
+
# `remover` giờ là DANH SÁCH Ứng viên khả dụng, không phải cách sẽ dùng: tách nền chạy
|
|
1184
|
+
# nhiều cách rồi chấm điểm, nên cách THẬT SỰ dùng cho từng ảnh nằm ở
|
|
1185
|
+
# variants[i]["cutout_method"]. Báo "ben2" ở đây từng đúng khi BEN2 độc quyền,
|
|
1186
|
+
# nhưng bây giờ nó sẽ NÓI SAI — đo thật trên 4 bản home_grass: remover="ben2"
|
|
1187
|
+
# trong khi cả 4 đều thắng bằng `unmix`.
|
|
1188
|
+
remover = "multi+ben2" if cutout else "multi"
|
|
1189
|
+
|
|
1190
|
+
variants: list[dict] = []
|
|
1191
|
+
errors: list[str] = []
|
|
1192
|
+
idx = 0
|
|
1193
|
+
for raw in raws:
|
|
1194
|
+
try:
|
|
1195
|
+
img = _open_rgba(raw)
|
|
1196
|
+
except Exception as e:
|
|
1197
|
+
errors.append(f"{raw}: {type(e).__name__}: {e}")
|
|
1198
|
+
continue
|
|
1199
|
+
idx += 1
|
|
1200
|
+
# Ảnh thô ở đây NGUỒN LẪN: `agy` cũng là Gemini nên có thể mang watermark ✦, còn
|
|
1201
|
+
# Codex/GPT Image 2 thì không. Vì vậy verify=True — đảo trộn alpha chỉ khi đo được
|
|
1202
|
+
# bằng chứng, bằng không sẽ đóng một ngôi sao TỐI vào ảnh Codex sạch. Phải xoá
|
|
1203
|
+
# TRƯỚC _postprocess_autokey: bước đó tách nền + resize, sau đó thì hình học
|
|
1204
|
+
# 48x48@96px không còn đúng và watermark bị bake luôn vào asset.
|
|
1205
|
+
img, wm = L.unwatermark_gemini(img, verify=True)
|
|
1206
|
+
out_img, report = _postprocess_autokey(
|
|
1207
|
+
img, key_hex, src_img, size_wh, cutout, full_bleed=full_bleed, up=up
|
|
1208
|
+
)
|
|
1209
|
+
report["watermark_removed"] = bool(wm)
|
|
1210
|
+
report["raw"] = str(raw)
|
|
1211
|
+
report["remover"] = report.get("cutout_method") or remover
|
|
1212
|
+
report["cutout_candidates_available"] = remover
|
|
1213
|
+
if out_img is None:
|
|
1214
|
+
report["out"] = None
|
|
1215
|
+
else:
|
|
1216
|
+
out_path = dest / f"{prefix}{idx}.png"
|
|
1217
|
+
out_img.save(out_path, optimize=True)
|
|
1218
|
+
report["out"] = str(out_path)
|
|
1219
|
+
variants.append(report)
|
|
1220
|
+
|
|
1221
|
+
return {
|
|
1222
|
+
"key": key_hex,
|
|
1223
|
+
"remover": remover,
|
|
1224
|
+
"upscaler": UP.info(),
|
|
1225
|
+
"remote": RB.info(),
|
|
1226
|
+
"size": list(size_wh) if size_wh else None,
|
|
1227
|
+
"src": src,
|
|
1228
|
+
"out_dir": str(dest),
|
|
1229
|
+
"n_raws": len(raws),
|
|
1230
|
+
"n_produced": len(variants),
|
|
1231
|
+
"variants": variants,
|
|
1232
|
+
"errors": errors,
|
|
1233
|
+
"compare_group": _compare_group(src, dest, variants),
|
|
1234
|
+
}
|
|
1235
|
+
except Exception as e:
|
|
1236
|
+
return {"error": f"{type(e).__name__}: {e}"}
|
|
1237
|
+
|
|
1238
|
+
|
|
1239
|
+
@mcp.tool()
|
|
1240
|
+
async def slice_sheet(
|
|
1241
|
+
sheet: str,
|
|
1242
|
+
key: str,
|
|
1243
|
+
out_dir: str,
|
|
1244
|
+
prefix: str = "cell",
|
|
1245
|
+
mockup_frac: float = 0.5,
|
|
1246
|
+
min_cell: int = 24,
|
|
1247
|
+
pad: int = 4,
|
|
1248
|
+
) -> dict:
|
|
1249
|
+
"""Chế độ SCREEN SHEET: mổ một ảnh "màn hình + dải chi tiết" thành mockup + từng asset.
|
|
1250
|
+
|
|
1251
|
+
Đầu vào là MỘT ảnh do model sinh theo prompt screen-sheet (xem
|
|
1252
|
+
reference/prompt-template.md § Screen sheet): phần TRÊN là mockup cả màn hình đã
|
|
1253
|
+
restyle, phần DƯỚI là các chi tiết (nút, icon, panel…) vẽ RỜI NHAU trên nền phẳng màu
|
|
1254
|
+
key. Tool cắt phần trên ra `<prefix>_mockup.png` (giữ nguyên, không tách nền), tự dò
|
|
1255
|
+
từng mảng liên thông ở phần dưới làm một cell, tách nền từng cell (BEN2, fallback
|
|
1256
|
+
chroma-key + auto-key như process_raws) và lưu `<prefix>1.png`… theo thứ tự đọc
|
|
1257
|
+
(trên→dưới, trái→phải).
|
|
1258
|
+
|
|
1259
|
+
Args:
|
|
1260
|
+
sheet: đường dẫn ảnh sheet model sinh ra.
|
|
1261
|
+
key: màu key HEX mà prompt yêu cầu cho nền dải chi tiết. Nền lệch màu (xanh
|
|
1262
|
+
studio…) sẽ được tự dò lại từ vành dải — xem `key_auto` trong kết quả.
|
|
1263
|
+
out_dir: thư mục lưu mockup + cells.
|
|
1264
|
+
prefix: đánh dấu backend, như process_raws ("agy" -> agy_mockup.png, agy1.png…).
|
|
1265
|
+
mockup_frac: phần CAO của sheet là mockup (0..0.9, mặc định 0.5 = nửa trên).
|
|
1266
|
+
Đặt 0 nếu sheet chỉ có dải chi tiết, không có mockup.
|
|
1267
|
+
min_cell: mảng có CẢ hai chiều dưới ngưỡng này (px) bị coi là nhiễu, bỏ qua.
|
|
1268
|
+
pad: nới bbox mỗi cell thêm ngần này px trước khi cắt.
|
|
1269
|
+
Returns:
|
|
1270
|
+
dict: mockup (path hoặc null), key (màu đã dùng thật), key_auto, remover,
|
|
1271
|
+
n_cells, cells[] (mỗi phần tử: out, box [x0,y0,x1,y1] trên sheet, flags,
|
|
1272
|
+
coverage, solid_ratio…), out_dir. Cells là asset MỚI kích thước tự nhiên —
|
|
1273
|
+
muốn thay 1-1 asset cũ thì đưa cell qua process_raws với src=<asset gốc>.
|
|
1274
|
+
"""
|
|
1275
|
+
try:
|
|
1276
|
+
if not re.fullmatch(r"[A-Za-z0-9_-]{1,32}", prefix):
|
|
1277
|
+
return {"error": f"prefix không hợp lệ ({prefix!r}) — chỉ [A-Za-z0-9_-], <=32 ký tự"}
|
|
1278
|
+
if not (0.0 <= mockup_frac <= 0.9):
|
|
1279
|
+
return {"error": f"mockup_frac phải trong [0, 0.9], nhận {mockup_frac}"}
|
|
1280
|
+
img = _open_rgba(sheet)
|
|
1281
|
+
# Watermark ✦ nằm ở góc dưới-phải sheet, tức LỌT VÀO dải chi tiết — không xoá trước
|
|
1282
|
+
# thì nó vừa bị dò thành một "cell" rác, vừa bake vào cell nào nằm gần góc. verify=True
|
|
1283
|
+
# vì sheet có thể do backend ngoài (agy/Codex) sinh, không riêng Gemini web.
|
|
1284
|
+
img, wm_info = L.unwatermark_gemini(img, verify=True)
|
|
1285
|
+
w, h = img.size
|
|
1286
|
+
y_split = int(h * mockup_frac)
|
|
1287
|
+
|
|
1288
|
+
dest = Path(out_dir)
|
|
1289
|
+
dest.mkdir(parents=True, exist_ok=True)
|
|
1290
|
+
|
|
1291
|
+
mockup_path = None
|
|
1292
|
+
if y_split > 0:
|
|
1293
|
+
mp = dest / f"{prefix}_mockup.png"
|
|
1294
|
+
img.crop((0, 0, w, y_split)).save(mp, optimize=True)
|
|
1295
|
+
mockup_path = str(mp)
|
|
1296
|
+
|
|
1297
|
+
strip = img.crop((0, y_split, w, h))
|
|
1298
|
+
if strip.height < 4:
|
|
1299
|
+
return {"error": "phần dải chi tiết quá mỏng — kiểm lại mockup_frac"}
|
|
1300
|
+
|
|
1301
|
+
# Nền dải có thể lệch màu key yêu cầu (xanh studio #2ED246…) — dò từ vành dải,
|
|
1302
|
+
# cùng ngưỡng với _postprocess_autokey.
|
|
1303
|
+
key_hex = key
|
|
1304
|
+
key_auto = False
|
|
1305
|
+
bg_hex, purity = L.sample_border_color(strip)
|
|
1306
|
+
if (purity >= _AUTOKEY_MIN_PURITY
|
|
1307
|
+
and L.color_dist(L.hex_to_rgb(bg_hex), L.hex_to_rgb(key_hex)) > _AUTOKEY_MIN_DIST):
|
|
1308
|
+
key_hex, key_auto = bg_hex, True
|
|
1309
|
+
|
|
1310
|
+
rgb = np.asarray(strip.convert("RGB"), dtype=np.uint8)
|
|
1311
|
+
dist = L._dist_map(rgb, L.hex_to_rgb(key_hex))
|
|
1312
|
+
boxes = L.component_boxes(dist > 80.0, min_size=min_cell)
|
|
1313
|
+
|
|
1314
|
+
cutout = (bgremove.remove_background if bgremove.available()
|
|
1315
|
+
else RB.cutout_backend())
|
|
1316
|
+
# `remover` giờ là DANH SÁCH Ứng viên khả dụng, không phải cách sẽ dùng: tách nền chạy
|
|
1317
|
+
# nhiều cách rồi chấm điểm, nên cách THẬT SỰ dùng cho từng ảnh nằm ở
|
|
1318
|
+
# variants[i]["cutout_method"]. Báo "ben2" ở đây từng đúng khi BEN2 độc quyền,
|
|
1319
|
+
# nhưng bây giờ nó sẽ NÓI SAI — đo thật trên 4 bản home_grass: remover="ben2"
|
|
1320
|
+
# trong khi cả 4 đều thắng bằng `unmix`.
|
|
1321
|
+
remover = "multi+ben2" if cutout else "multi"
|
|
1322
|
+
|
|
1323
|
+
cells: list[dict] = []
|
|
1324
|
+
for i, (x0, y0, x1, y1) in enumerate(boxes, start=1):
|
|
1325
|
+
bx0 = max(0, x0 - pad)
|
|
1326
|
+
bx1 = min(w, x1 + pad)
|
|
1327
|
+
by0 = y_split + max(0, y0 - pad)
|
|
1328
|
+
by1 = y_split + min(strip.height, y1 + pad)
|
|
1329
|
+
cell = img.crop((bx0, by0, bx1, by1))
|
|
1330
|
+
out_img, report = L.postprocess(
|
|
1331
|
+
cell, key_hex, size=(cell.width, cell.height), cutout=cutout
|
|
1332
|
+
)
|
|
1333
|
+
report["box"] = [bx0, by0, bx1, by1]
|
|
1334
|
+
if out_img is None:
|
|
1335
|
+
report["out"] = None
|
|
1336
|
+
else:
|
|
1337
|
+
out_path = dest / f"{prefix}{i}.png"
|
|
1338
|
+
out_img.save(out_path, optimize=True)
|
|
1339
|
+
report["out"] = str(out_path)
|
|
1340
|
+
cells.append(report)
|
|
1341
|
+
|
|
1342
|
+
return {
|
|
1343
|
+
"mockup": mockup_path,
|
|
1344
|
+
"key": key_hex,
|
|
1345
|
+
"key_requested": key,
|
|
1346
|
+
"key_auto": key_auto,
|
|
1347
|
+
"remover": remover,
|
|
1348
|
+
"watermark_removed": bool(wm_info),
|
|
1349
|
+
"n_cells": len(cells),
|
|
1350
|
+
"cells": cells,
|
|
1351
|
+
"out_dir": str(dest),
|
|
1352
|
+
# Sẵn sàng cho make_compare_sheet: nhóm mockup lấy CHÍNH sheet gốc làm `original`
|
|
1353
|
+
# (lật để thấy layout có xê dịch không), nhóm cells `original: null` vì cell là
|
|
1354
|
+
# asset MỚI, không có bản gốc 1-1.
|
|
1355
|
+
"compare_groups": [
|
|
1356
|
+
g for g in (
|
|
1357
|
+
{"name": "Màn hình (mockup)", "original": str(sheet),
|
|
1358
|
+
"variants": ([{"label": f"{prefix}_mockup", "image": mockup_path}]
|
|
1359
|
+
if mockup_path else [])},
|
|
1360
|
+
{"name": "Cells cắt ra", "original": None,
|
|
1361
|
+
"variants": [{"label": Path(c["out"]).stem, "image": c["out"]}
|
|
1362
|
+
for c in cells if c.get("out")]},
|
|
1363
|
+
) if g["variants"]
|
|
1364
|
+
],
|
|
1365
|
+
}
|
|
1366
|
+
except Exception as e:
|
|
1367
|
+
return {"error": f"{type(e).__name__}: {e}"}
|
|
1368
|
+
|
|
1369
|
+
|
|
1370
|
+
@mcp.tool()
|
|
1371
|
+
async def make_contact_sheet(
|
|
1372
|
+
labels: list[str], images: list[str], out: str, cell: int = 160
|
|
1373
|
+
) -> dict:
|
|
1374
|
+
"""Dựng contact sheet để DUYỆT BẰNG MẮT: mỗi ảnh 1 cột, 3 hàng nền (sáng/tối/caro).
|
|
1375
|
+
|
|
1376
|
+
Ba nền là có chủ đích — sáng lộ viền tối, tối lộ viền sáng+spill, caro lộ vùng bán
|
|
1377
|
+
trong suốt. Đây là cửa gác THẬT SỰ trước khi apply, không phải các cờ tự động.
|
|
1378
|
+
|
|
1379
|
+
Args:
|
|
1380
|
+
labels: nhãn mỗi cột (vd "original", "v1", "v2"…). Cùng độ dài với `images`.
|
|
1381
|
+
images: đường dẫn ảnh mỗi cột (asset gốc + các biến thể).
|
|
1382
|
+
out: đường dẫn PNG sheet xuất ra.
|
|
1383
|
+
cell: cạnh ô (px), mặc định 160.
|
|
1384
|
+
Returns:
|
|
1385
|
+
dict: out, cells (nhãn).
|
|
1386
|
+
"""
|
|
1387
|
+
try:
|
|
1388
|
+
if len(labels) != len(images):
|
|
1389
|
+
return {"error": f"labels ({len(labels)}) và images ({len(images)}) phải cùng độ dài"}
|
|
1390
|
+
cells = [(labels[i], _open_rgba(images[i])) for i in range(len(images))]
|
|
1391
|
+
Path(out).parent.mkdir(parents=True, exist_ok=True)
|
|
1392
|
+
L.make_sheet(cells, cell=cell).save(out)
|
|
1393
|
+
return {"out": out, "cells": labels}
|
|
1394
|
+
except Exception as e:
|
|
1395
|
+
return {"error": f"{type(e).__name__}: {e}"}
|
|
1396
|
+
|
|
1397
|
+
|
|
1398
|
+
@mcp.tool()
|
|
1399
|
+
async def make_web_sheet(
|
|
1400
|
+
labels: list[str], images: list[str], out: str, cell: int = 240
|
|
1401
|
+
) -> dict:
|
|
1402
|
+
"""Dựng TRANG WEB duyệt cutout (review.html tự chứa) — bản web của make_contact_sheet.
|
|
1403
|
+
|
|
1404
|
+
Hơn PNG tĩnh ở chỗ đổi nền TRỰC TIẾP (caro/sáng/tối/màu tùy chọn) để soi mép và vùng
|
|
1405
|
+
bán trong suốt, kéo slider phóng to, mở bằng trình duyệt nào cũng chạy. Một file HTML
|
|
1406
|
+
duy nhất (ảnh nhúng base64), không phụ thuộc file ngoài — gửi đi/mở lại đều được.
|
|
1407
|
+
|
|
1408
|
+
Args:
|
|
1409
|
+
labels: nhãn mỗi ảnh (vd "original", "v1", "v2"…). Cùng độ dài với `images`.
|
|
1410
|
+
images: đường dẫn ảnh (asset gốc + các biến thể đã tách nền).
|
|
1411
|
+
out: đường dẫn .html xuất ra.
|
|
1412
|
+
cell: cạnh ô hiển thị mặc định (px), slider zoom chỉnh được sau.
|
|
1413
|
+
Returns:
|
|
1414
|
+
dict: out, cells (nhãn).
|
|
1415
|
+
"""
|
|
1416
|
+
try:
|
|
1417
|
+
if len(labels) != len(images):
|
|
1418
|
+
return {"error": f"labels ({len(labels)}) và images ({len(images)}) phải cùng độ dài"}
|
|
1419
|
+
cells = [(labels[i], _open_rgba(images[i])) for i in range(len(images))]
|
|
1420
|
+
dest = Path(out)
|
|
1421
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
1422
|
+
dest.write_text(L.web_sheet(cells, cell=cell), encoding="utf-8")
|
|
1423
|
+
return {"out": str(dest), "cells": labels}
|
|
1424
|
+
except Exception as e:
|
|
1425
|
+
return {"error": f"{type(e).__name__}: {e}"}
|
|
1426
|
+
|
|
1427
|
+
|
|
1428
|
+
@mcp.tool()
|
|
1429
|
+
async def make_thumbs(
|
|
1430
|
+
sources: list[dict], out_dir: str, anchor: str = "center", prefix: str = "thumb"
|
|
1431
|
+
) -> dict:
|
|
1432
|
+
"""Chế độ THUMBNAIL: đưa ảnh thô về ĐÚNG 3 kích thước cửa hàng. KHÔNG tách nền.
|
|
1433
|
+
|
|
1434
|
+
Model sinh ảnh không cho chọn kích thước đầu ra, nên luồng đúng là sinh ở tỉ lệ gần nhất
|
|
1435
|
+
rồi cắt bù + resize ở đây. Đo thật trên Gemini web: yêu cầu dọc → 864x1216, ngang →
|
|
1436
|
+
1376x768, vuông → 1024x1024 — đều sát mục tiêu, cắt bù chỉ mất ≤1%.
|
|
1437
|
+
|
|
1438
|
+
Thumbnail là tranh FULL-BLEED: đừng đưa qua `process_raws`/`restyle_asset` (hai đường đó
|
|
1439
|
+
tách nền + bám bbox asset gốc, sai hoàn toàn mục đích).
|
|
1440
|
+
|
|
1441
|
+
Args:
|
|
1442
|
+
sources: mỗi phần tử `{"raw": "<đường dẫn ảnh thô>", "preset": "1:1"|"5:7"|"16:9"}`.
|
|
1443
|
+
Thêm `"size": "WxH"` để ép kích thước khác preset. Thêm `"label"` để đặt tên file
|
|
1444
|
+
(mặc định lấy theo preset).
|
|
1445
|
+
out_dir: thư mục lưu thumb.
|
|
1446
|
+
anchor: giữ phần nào khi cắt — "center" (mặc định), "top", "bottom", "left", "right".
|
|
1447
|
+
Thumb dọc hay có logo ở trên → "top" an toàn hơn. Đặt riêng cho từng nguồn bằng
|
|
1448
|
+
khoá `"anchor"` trong phần tử của `sources`.
|
|
1449
|
+
prefix: tiền tố tên file. Chỉ [A-Za-z0-9_-], tối đa 32 ký tự.
|
|
1450
|
+
Returns:
|
|
1451
|
+
dict: out_dir, thumbs[] (out, preset, src, target, crop, lost_frac, upscaled),
|
|
1452
|
+
warnings[] (ảnh phải PHÓNG TO — thumb sẽ mềm, nên sinh lại nguồn to hơn),
|
|
1453
|
+
errors[] (nguồn không đọc được / preset sai).
|
|
1454
|
+
"""
|
|
1455
|
+
try:
|
|
1456
|
+
if not sources:
|
|
1457
|
+
return {"error": "sources rỗng — cần ít nhất 1 ảnh thô"}
|
|
1458
|
+
if not re.fullmatch(r"[A-Za-z0-9_-]{1,32}", prefix):
|
|
1459
|
+
return {"error": f"prefix không hợp lệ ({prefix!r}) — chỉ [A-Za-z0-9_-], <=32 ký tự"}
|
|
1460
|
+
dest = Path(out_dir)
|
|
1461
|
+
dest.mkdir(parents=True, exist_ok=True)
|
|
1462
|
+
|
|
1463
|
+
thumbs: list[dict] = []
|
|
1464
|
+
warnings: list[str] = []
|
|
1465
|
+
errors: list[str] = []
|
|
1466
|
+
# Hai nguồn cùng preset trong MỘT lời gọi sẽ ra cùng tên file và ghi đè nhau im lặng —
|
|
1467
|
+
# gặp ngay khi mỗi preset có 2 bản để so sánh. Đếm để đánh số _2, _3.
|
|
1468
|
+
used: dict[str, int] = {}
|
|
1469
|
+
for i, s in enumerate(sources):
|
|
1470
|
+
if not isinstance(s, dict):
|
|
1471
|
+
errors.append(f"sources[{i}] phải là dict, nhận {type(s).__name__}")
|
|
1472
|
+
continue
|
|
1473
|
+
raw = s.get("raw")
|
|
1474
|
+
preset = str(s.get("preset") or "")
|
|
1475
|
+
if not raw:
|
|
1476
|
+
errors.append(f"sources[{i}] thiếu `raw`")
|
|
1477
|
+
continue
|
|
1478
|
+
if s.get("size"):
|
|
1479
|
+
try:
|
|
1480
|
+
target = _parse_size(str(s["size"]))
|
|
1481
|
+
except Exception as e:
|
|
1482
|
+
errors.append(f"sources[{i}] size sai: {e}")
|
|
1483
|
+
continue
|
|
1484
|
+
elif preset in L.THUMB_PRESETS:
|
|
1485
|
+
target = L.THUMB_PRESETS[preset]
|
|
1486
|
+
else:
|
|
1487
|
+
errors.append(
|
|
1488
|
+
f"sources[{i}] preset {preset!r} không có — chọn "
|
|
1489
|
+
f"{'/'.join(L.THUMB_PRESETS)} hoặc truyền `size`: \"WxH\""
|
|
1490
|
+
)
|
|
1491
|
+
continue
|
|
1492
|
+
try:
|
|
1493
|
+
img = Image.open(str(raw))
|
|
1494
|
+
img.load()
|
|
1495
|
+
except Exception as e:
|
|
1496
|
+
errors.append(f"{raw}: {type(e).__name__}: {e}")
|
|
1497
|
+
continue
|
|
1498
|
+
|
|
1499
|
+
fitted, info = L.fit_thumb(img, target, anchor=str(s.get("anchor") or anchor),
|
|
1500
|
+
upscale=UP.backend())
|
|
1501
|
+
label = str(s.get("label") or (preset.replace(":", "x") or f"{target[0]}x{target[1]}"))
|
|
1502
|
+
safe = re.sub(r"[^A-Za-z0-9_-]", "_", label)[:40]
|
|
1503
|
+
used[safe] = used.get(safe, 0) + 1
|
|
1504
|
+
if used[safe] > 1:
|
|
1505
|
+
safe = f"{safe}_{used[safe]}"
|
|
1506
|
+
out_path = dest / f"{prefix}_{safe}.png"
|
|
1507
|
+
fitted.save(out_path, optimize=True)
|
|
1508
|
+
info.update({"out": str(out_path), "preset": preset or None, "raw": str(raw)})
|
|
1509
|
+
thumbs.append(info)
|
|
1510
|
+
if info["upscaled"]:
|
|
1511
|
+
how = info.get("upscale_method") or "lanczos"
|
|
1512
|
+
tail = ("ảnh sẽ mềm" if how == "lanczos"
|
|
1513
|
+
else f"đã dựng nét lại bằng `{how}`, nhưng chi tiết là do model ĐOÁN")
|
|
1514
|
+
warnings.append(
|
|
1515
|
+
f"{out_path.name}: nguồn {info['src'][0]}x{info['src'][1]} NHỎ hơn đích "
|
|
1516
|
+
f"{target[0]}x{target[1]} -> đã phóng to, {tail}. Sinh lại nguồn to hơn vẫn tốt hơn."
|
|
1517
|
+
)
|
|
1518
|
+
if not thumbs:
|
|
1519
|
+
return {"error": "không tạo được thumb nào", "errors": errors}
|
|
1520
|
+
return {
|
|
1521
|
+
"out_dir": str(dest), "n_thumbs": len(thumbs),
|
|
1522
|
+
"thumbs": thumbs, "warnings": warnings, "errors": errors,
|
|
1523
|
+
}
|
|
1524
|
+
except Exception as e:
|
|
1525
|
+
return {"error": f"{type(e).__name__}: {e}"}
|
|
1526
|
+
|
|
1527
|
+
|
|
1528
|
+
@mcp.tool()
|
|
1529
|
+
async def remote_nodes() -> dict:
|
|
1530
|
+
"""Bảng TẢI + QUOTA của mọi node đang cấu hình — dùng để xem vì sao node nào được chọn.
|
|
1531
|
+
|
|
1532
|
+
Chỉ có nghĩa ở CHẾ ĐỘ MƯỢN MÁY (đã đặt GAMEART_REMOTE_NODES / GAMEART_REMOTE_URL).
|
|
1533
|
+
Không tốn lượt sinh ảnh, không chạm GPU: `status` bên máy chủ cố tình KHÔNG khoá gì cả,
|
|
1534
|
+
nên node đang bận vẫn trả lời được là nó đang bận.
|
|
1535
|
+
|
|
1536
|
+
Returns:
|
|
1537
|
+
dict: enabled, env (nạp .env từ file nào + TÊN các biến đã có — không bao giờ trả
|
|
1538
|
+
giá trị), nodes[] (url, name, available{gemini,codex,ben2,esrgan},
|
|
1539
|
+
slots{running,waiting,capacity,queue_max,load,full},
|
|
1540
|
+
quota{state,used_hour,used_day,limit_hour,limit_day,cooldown_left},
|
|
1541
|
+
client_cooldown_left nếu máy khách đang tạm bỏ qua node đó).
|
|
1542
|
+
`state`: ok | limited (chạm hạn mức tự khai) | exhausted (backend đã báo hết quota).
|
|
1543
|
+
"""
|
|
1544
|
+
try:
|
|
1545
|
+
# Báo luôn .env đã nạp từ đâu: "tạo .env rồi mà không ăn" là ca hỏng hay gặp nhất,
|
|
1546
|
+
# và không có dòng này thì chẳng có cách nào biết file có được đọc hay không.
|
|
1547
|
+
env = _envfile.info()
|
|
1548
|
+
if not RB.enabled():
|
|
1549
|
+
return {"enabled": False, "env": env,
|
|
1550
|
+
"hint": f"đặt {RB.P.ENV_NODES} hoặc {RB.P.ENV_URL} + {RB.P.ENV_TOKEN} "
|
|
1551
|
+
f"(trong .env cạnh SKILL.md, hoặc env hệ thống)"}
|
|
1552
|
+
return {"enabled": True, "wait_budget_sec": RB.P.DEFAULT_WAIT, "env": env,
|
|
1553
|
+
"nodes": RB.status_all(force=True)}
|
|
1554
|
+
except Exception as e:
|
|
1555
|
+
return {"error": f"{type(e).__name__}: {e}"}
|
|
1556
|
+
|
|
1557
|
+
|
|
1558
|
+
@mcp.tool()
|
|
1559
|
+
async def upscale_image(
|
|
1560
|
+
image_paths: list[str],
|
|
1561
|
+
out_dir: str,
|
|
1562
|
+
size: str | None = None,
|
|
1563
|
+
scale: float | None = None,
|
|
1564
|
+
prefix: str = "up",
|
|
1565
|
+
) -> dict:
|
|
1566
|
+
"""PHÓNG TO ảnh đã có mà không sinh lại — khi bản AI sinh ra nhỏ hơn kích thước cần.
|
|
1567
|
+
|
|
1568
|
+
Chạy NHIỀU cách rồi chấm điểm chọn bản tốt nhất, giống đường tách nền: LANCZOS,
|
|
1569
|
+
Real-ESRGAN x4plus_anime_6B, và biến thể "LANCZOS trước / model sau" cho hệ số > 4x.
|
|
1570
|
+
Cách thắng nằm ở `upscale_method`, điểm của mọi ứng viên ở `upscale_table`.
|
|
1571
|
+
|
|
1572
|
+
Giữ nguyên alpha: RGB và matte được phóng riêng, và màu tiền cảnh được loang ra vùng
|
|
1573
|
+
trong suốt TRƯỚC khi phóng — nếu không, màu nền key còn nằm lại ở đó (vô hình nhưng
|
|
1574
|
+
model vẫn thấy) sẽ bị kéo vào mép và sinh viền màu.
|
|
1575
|
+
|
|
1576
|
+
ĐỪNG dùng thay cho việc sinh lại ở độ phân giải đúng: chi tiết thêm vào là model ĐOÁN,
|
|
1577
|
+
không phải thông tin thật. Đây là cách chữa cháy khi không sinh lại được.
|
|
1578
|
+
|
|
1579
|
+
Args:
|
|
1580
|
+
image_paths: ảnh cần phóng (.png/.jpg/.jpeg/.webp).
|
|
1581
|
+
out_dir: thư mục lưu.
|
|
1582
|
+
size: "WxH" — ép ĐÚNG kích thước này (bỏ qua tỉ lệ gốc nếu lệch).
|
|
1583
|
+
scale: hệ số phóng, vd 2.0. Dùng khi không truyền `size`. Mặc định 2.0.
|
|
1584
|
+
prefix: tiền tố tên file ra. Chỉ [A-Za-z0-9_-], tối đa 32 ký tự.
|
|
1585
|
+
Returns:
|
|
1586
|
+
dict: out_dir, upscaler (model/thiết bị), results[] (out/src/from/to/
|
|
1587
|
+
upscale_method/upscale_score/upscale_table), errors[].
|
|
1588
|
+
"""
|
|
1589
|
+
try:
|
|
1590
|
+
if not image_paths:
|
|
1591
|
+
return {"error": "image_paths rỗng"}
|
|
1592
|
+
if not re.fullmatch(r"[A-Za-z0-9_-]{1,32}", prefix):
|
|
1593
|
+
return {"error": f"prefix không hợp lệ ({prefix!r}) — chỉ [A-Za-z0-9_-], <=32 ký tự"}
|
|
1594
|
+
if size and scale:
|
|
1595
|
+
return {"error": "chỉ truyền MỘT trong `size` hoặc `scale`"}
|
|
1596
|
+
size_wh = _parse_size(size) if size else None
|
|
1597
|
+
if size_wh is None:
|
|
1598
|
+
scale = 2.0 if scale is None else float(scale)
|
|
1599
|
+
if not (1.0 < scale <= 16.0):
|
|
1600
|
+
return {"error": f"scale phải trong khoảng (1, 16], nhận {scale}"}
|
|
1601
|
+
|
|
1602
|
+
dest = Path(out_dir)
|
|
1603
|
+
dest.mkdir(parents=True, exist_ok=True)
|
|
1604
|
+
up = UP.backend()
|
|
1605
|
+
|
|
1606
|
+
results: list[dict] = []
|
|
1607
|
+
errors: list[str] = []
|
|
1608
|
+
for i, p in enumerate(image_paths, start=1):
|
|
1609
|
+
try:
|
|
1610
|
+
img = _open_rgba(p)
|
|
1611
|
+
except Exception as e:
|
|
1612
|
+
errors.append(f"{p}: {type(e).__name__}: {e}")
|
|
1613
|
+
continue
|
|
1614
|
+
target = size_wh or (max(1, round(img.width * scale)), max(1, round(img.height * scale)))
|
|
1615
|
+
out_img, rep = L.best_upscale(img, target, backend=up)
|
|
1616
|
+
out_path = dest / f"{prefix}{i}.png"
|
|
1617
|
+
out_img.save(out_path, optimize=True)
|
|
1618
|
+
rep.update({"out": str(out_path), "src": str(p)})
|
|
1619
|
+
results.append(rep)
|
|
1620
|
+
|
|
1621
|
+
if not results:
|
|
1622
|
+
return {"error": "không phóng được ảnh nào", "errors": errors}
|
|
1623
|
+
return {
|
|
1624
|
+
"out_dir": str(dest),
|
|
1625
|
+
"upscaler": UP.info(),
|
|
1626
|
+
"n_produced": len(results),
|
|
1627
|
+
"results": results,
|
|
1628
|
+
"errors": errors,
|
|
1629
|
+
}
|
|
1630
|
+
except Exception as e:
|
|
1631
|
+
return {"error": f"{type(e).__name__}: {e}"}
|
|
1632
|
+
|
|
1633
|
+
|
|
1634
|
+
def _compare_group(src: str | None, dest: Path, variants: list[dict]) -> dict:
|
|
1635
|
+
"""Dựng sẵn một `group` để truyền THẲNG vào make_compare_sheet.
|
|
1636
|
+
|
|
1637
|
+
Trả kèm trong kết quả của mọi tool sinh ảnh, vì trang đối chiếu là bản giao BẮT BUỘC sau
|
|
1638
|
+
mỗi lượt (xem SKILL.md): tự lắp tay thì dễ ghép lệch `original` với biến thể của asset
|
|
1639
|
+
khác, hoặc quên hẳn bản gốc — đúng cái làm mất khả năng đối chiếu. Nhãn lấy theo tên file
|
|
1640
|
+
(`agy1`, `gpt2`…) nên biết ngay bản nào của AI nào.
|
|
1641
|
+
|
|
1642
|
+
Một asset thường qua HAI lượt gọi (prefix `agy` rồi `gpt`) → hai group cùng `name`;
|
|
1643
|
+
người gọi GỘP chúng lại bằng cách nối `variants`, đừng dựng hai section cho một asset.
|
|
1644
|
+
"""
|
|
1645
|
+
return {
|
|
1646
|
+
"name": Path(src).stem if src else dest.name,
|
|
1647
|
+
"original": str(src) if src else None,
|
|
1648
|
+
"variants": [
|
|
1649
|
+
{"label": Path(v["out"]).stem, "image": v["out"]}
|
|
1650
|
+
for v in variants if v.get("out")
|
|
1651
|
+
],
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
|
|
1655
|
+
@mcp.tool()
|
|
1656
|
+
async def make_compare_sheet(groups: list[dict], out: str, cell: int = 240) -> dict:
|
|
1657
|
+
"""Dựng trang ĐỐI CHIẾU gốc↔mới (compare.html tự chứa) — BẢN GIAO sau MỖI lượt thiết kế.
|
|
1658
|
+
|
|
1659
|
+
Khác `make_web_sheet` (lưới phẳng, mọi ảnh ngang hàng): ở đây gom NHÓM THEO ASSET, bản
|
|
1660
|
+
gốc nằm ngay cạnh biến thể của chính nó, và mỗi thẻ biến thể lật được về gốc NGAY TẠI CHỖ
|
|
1661
|
+
(nhấn giữ / nháy đúp để khoá / nút xem tất cả bản gốc). Xếp chồng đúng một vị trí và một
|
|
1662
|
+
kích thước mới thấy được lệch hình dạng nhỏ — hai thẻ nằm cạnh nhau thì mắt bỏ qua.
|
|
1663
|
+
|
|
1664
|
+
Args:
|
|
1665
|
+
groups: mỗi phần tử là một asset:
|
|
1666
|
+
{"name": "coin", "original": "<path asset gốc>|null",
|
|
1667
|
+
"variants": [{"label": "agy1", "image": "<path>"}, ...]}
|
|
1668
|
+
`original: null` cho thứ không có asset gốc 1-1 (vd cells screen-sheet) —
|
|
1669
|
+
khi đó thẻ chỉ hiện bản mới, không có nút lật.
|
|
1670
|
+
out: đường dẫn .html xuất ra.
|
|
1671
|
+
cell: cạnh ô hiển thị mặc định (px); slider zoom chỉnh sau.
|
|
1672
|
+
Returns:
|
|
1673
|
+
dict: out, n_groups, n_variants, missing[] (ảnh không đọc được, đã bỏ qua).
|
|
1674
|
+
"""
|
|
1675
|
+
try:
|
|
1676
|
+
if not groups:
|
|
1677
|
+
return {"error": "groups rỗng — cần ít nhất 1 asset"}
|
|
1678
|
+
parsed: list[tuple[str, Image.Image | None, list[tuple[str, Image.Image]]]] = []
|
|
1679
|
+
missing: list[str] = []
|
|
1680
|
+
n_var = 0
|
|
1681
|
+
for gi, g in enumerate(groups):
|
|
1682
|
+
if not isinstance(g, dict):
|
|
1683
|
+
return {"error": f"groups[{gi}] phải là dict, nhận {type(g).__name__}"}
|
|
1684
|
+
name = str(g.get("name") or f"asset{gi + 1}")
|
|
1685
|
+
orig = None
|
|
1686
|
+
op = g.get("original")
|
|
1687
|
+
if op:
|
|
1688
|
+
try:
|
|
1689
|
+
orig = _open_rgba(str(op))
|
|
1690
|
+
except Exception as e:
|
|
1691
|
+
missing.append(f"{op}: {type(e).__name__}: {e}")
|
|
1692
|
+
variants: list[tuple[str, Image.Image]] = []
|
|
1693
|
+
for vi, v in enumerate(g.get("variants") or []):
|
|
1694
|
+
# Nhận cả {"label","image"} và ["label","path"] để gọi cho đỡ cứng nhắc.
|
|
1695
|
+
if isinstance(v, dict):
|
|
1696
|
+
lbl, ip = str(v.get("label") or f"v{vi + 1}"), v.get("image")
|
|
1697
|
+
elif isinstance(v, (list, tuple)) and len(v) == 2:
|
|
1698
|
+
lbl, ip = str(v[0]), v[1]
|
|
1699
|
+
else:
|
|
1700
|
+
missing.append(f"{name}.variants[{vi}]: dạng không hiểu ({v!r})")
|
|
1701
|
+
continue
|
|
1702
|
+
if not ip:
|
|
1703
|
+
continue
|
|
1704
|
+
try:
|
|
1705
|
+
variants.append((lbl, _open_rgba(str(ip))))
|
|
1706
|
+
except Exception as e:
|
|
1707
|
+
missing.append(f"{ip}: {type(e).__name__}: {e}")
|
|
1708
|
+
if orig is None and not variants:
|
|
1709
|
+
continue # nhóm rỗng hoàn toàn -> bỏ, đừng dựng section trống
|
|
1710
|
+
n_var += len(variants)
|
|
1711
|
+
parsed.append((name, orig, variants))
|
|
1712
|
+
if not parsed:
|
|
1713
|
+
return {"error": "không đọc được ảnh nào", "missing": missing}
|
|
1714
|
+
|
|
1715
|
+
dest = Path(out)
|
|
1716
|
+
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
1717
|
+
dest.write_text(L.compare_sheet(parsed, cell=cell), encoding="utf-8")
|
|
1718
|
+
return {
|
|
1719
|
+
"out": str(dest), "n_groups": len(parsed),
|
|
1720
|
+
"n_variants": n_var, "missing": missing,
|
|
1721
|
+
}
|
|
1722
|
+
except Exception as e:
|
|
1723
|
+
return {"error": f"{type(e).__name__}: {e}"}
|
|
1724
|
+
|
|
1725
|
+
|
|
1726
|
+
@mcp.tool()
|
|
1727
|
+
async def apply_asset(
|
|
1728
|
+
variant: str, dst: str, backup_dir: str, project_root: str | None = None
|
|
1729
|
+
) -> dict:
|
|
1730
|
+
"""Backup asset gốc rồi GHI ĐÈ bằng biến thể đã duyệt. Chỉ chạy sau khi người dùng
|
|
1731
|
+
duyệt sheet.
|
|
1732
|
+
|
|
1733
|
+
An toàn (không bao giờ phá bản gốc):
|
|
1734
|
+
- Chỉ ghi đè file .png (từ chối mọi loại khác).
|
|
1735
|
+
- Backup mirror đúng đường dẫn dst dưới backup_dir (theo project_root, không theo cwd).
|
|
1736
|
+
- KHÔNG BAO GIỜ ghi đè backup đã có -> luôn giữ bản gốc THẬT đầu tiên.
|
|
1737
|
+
- Từ chối nếu backup resolve TRÙNG lên dst, hoặc THOÁT ra ngoài backup_dir. Không ghi gì.
|
|
1738
|
+
- Copy backup atomic (.tmp + os.replace) để không để lại backup cụt.
|
|
1739
|
+
|
|
1740
|
+
Args:
|
|
1741
|
+
variant: đường dẫn biến thể .png đã duyệt.
|
|
1742
|
+
dst: asset gốc .png trong project (sẽ bị ghi đè).
|
|
1743
|
+
backup_dir: thư mục lưu backup (vd tools/restyle/backup).
|
|
1744
|
+
project_root: gốc project (tuyệt đối) để mirror path backup. PHẢI truyền tường minh
|
|
1745
|
+
trong pipeline nhiều lệnh apply; mặc định cwd nếu bỏ trống.
|
|
1746
|
+
Returns:
|
|
1747
|
+
dict: {applied, backup} khi thành công, hoặc {error} — không ghi gì khi có error.
|
|
1748
|
+
"""
|
|
1749
|
+
try:
|
|
1750
|
+
src, dst_p = Path(variant), Path(dst)
|
|
1751
|
+
if not src.is_file():
|
|
1752
|
+
return {"error": f"không thấy variant: {src}"}
|
|
1753
|
+
if not dst_p.is_file():
|
|
1754
|
+
return {"error": f"không thấy asset đích: {dst_p}"}
|
|
1755
|
+
if src.suffix.lower() != ".png":
|
|
1756
|
+
return {"error": f"variant phải là .png, nhận: {src}"}
|
|
1757
|
+
if dst_p.suffix.lower() != ".png":
|
|
1758
|
+
return {"error": f"asset đích phải là .png, nhận: {dst_p}"}
|
|
1759
|
+
|
|
1760
|
+
root = Path(project_root) if project_root else Path.cwd()
|
|
1761
|
+
bdir = Path(backup_dir)
|
|
1762
|
+
bdir.mkdir(parents=True, exist_ok=True)
|
|
1763
|
+
bdir_resolved = bdir.resolve()
|
|
1764
|
+
dst_resolved = dst_p.resolve()
|
|
1765
|
+
|
|
1766
|
+
backup = _backup_path(bdir, dst_p, project_root=root)
|
|
1767
|
+
backup_resolved = backup.resolve()
|
|
1768
|
+
|
|
1769
|
+
# Hai cách backup có thể trùng lên chính dst (vd `backup_dir=.` từ project root, hoặc
|
|
1770
|
+
# dst là UNC). Nếu lọt, guard "không ghi đè backup đã có" sẽ thấy backup==dst tồn tại,
|
|
1771
|
+
# BỎ QUA bước backup rồi ghi đè dst — bản gốc biến mất. KHÔNG GHI GÌ trước khi qua cả hai.
|
|
1772
|
+
if backup_resolved == dst_resolved:
|
|
1773
|
+
return {"error": (
|
|
1774
|
+
f"backup path ({backup_resolved}) trùng với chính asset đích — "
|
|
1775
|
+
"backup_dir/project_root không được resolve trùng lên dst. Không ghi gì cả."
|
|
1776
|
+
)}
|
|
1777
|
+
try:
|
|
1778
|
+
backup_resolved.relative_to(bdir_resolved)
|
|
1779
|
+
except ValueError:
|
|
1780
|
+
return {"error": (
|
|
1781
|
+
f"backup path ({backup_resolved}) thoát ra ngoài backup_dir "
|
|
1782
|
+
f"({bdir_resolved}). Không ghi gì cả."
|
|
1783
|
+
)}
|
|
1784
|
+
|
|
1785
|
+
if not backup.exists():
|
|
1786
|
+
backup.parent.mkdir(parents=True, exist_ok=True)
|
|
1787
|
+
# shutil.copy2 không atomic — ngắt giữa chừng để lại backup cụt mà `backup.exists()`
|
|
1788
|
+
# vẫn True, guard bỏ qua backup, bản gốc bị ghi đè vĩnh viễn. .tmp + os.replace đảm
|
|
1789
|
+
# bảo backup hoặc tồn tại ĐẦY ĐỦ hoặc không tồn tại.
|
|
1790
|
+
tmp = backup.with_suffix(backup.suffix + ".tmp")
|
|
1791
|
+
shutil.copy2(dst_p, tmp)
|
|
1792
|
+
os.replace(tmp, backup)
|
|
1793
|
+
|
|
1794
|
+
shutil.copy2(src, dst_p)
|
|
1795
|
+
return {"applied": str(dst_p), "backup": str(backup)}
|
|
1796
|
+
except Exception as e:
|
|
1797
|
+
return {"error": f"{type(e).__name__}: {e}"}
|
|
1798
|
+
|
|
1799
|
+
|
|
1800
|
+
@mcp.tool()
|
|
1801
|
+
async def auth_status() -> dict:
|
|
1802
|
+
"""Chẩn đoán cookie/đăng nhập Gemini — KHÔNG tốn lượt sinh ảnh.
|
|
1803
|
+
|
|
1804
|
+
Chạy rotate (POST RotateCookies + GET RotateCookiesPage, ghi cookie mới về file)
|
|
1805
|
+
rồi GET /app, báo lại: có đăng nhập không, cookie nào Google vừa xoay, file cookie
|
|
1806
|
+
có được cập nhật không. Dùng để kiểm luồng rotate mới có giữ session sống không.
|
|
1807
|
+
|
|
1808
|
+
Returns:
|
|
1809
|
+
dict: logged_in, logged_out_marker, status_code, final_url,
|
|
1810
|
+
psidts_changed / psid_changed (sau rotate), cookies_updated (tên cookie đã đổi
|
|
1811
|
+
trong file), cookies_present.
|
|
1812
|
+
"""
|
|
1813
|
+
if RB.enabled():
|
|
1814
|
+
# Máy khách KHÔNG có cookie Gemini — hỏi thẳng máy chủ, đừng báo "logged_out" cho một
|
|
1815
|
+
# cấu hình hoàn toàn bình thường.
|
|
1816
|
+
pr = RB.probe(force=True)
|
|
1817
|
+
return {
|
|
1818
|
+
"mode": "remote",
|
|
1819
|
+
"remote": RB.info(),
|
|
1820
|
+
# Khả năng ở đây là của CẢ CỤM: một node có Gemini là cụm sinh ảnh được.
|
|
1821
|
+
"logged_in": bool(pr.get("gemini")),
|
|
1822
|
+
"codex": bool(pr.get("codex")),
|
|
1823
|
+
"ben2": bool(pr.get("ben2")),
|
|
1824
|
+
"esrgan": bool(pr.get("esrgan")),
|
|
1825
|
+
"n_nodes": pr.get("n_nodes"),
|
|
1826
|
+
"n_alive": pr.get("n_alive"),
|
|
1827
|
+
"nodes": pr.get("nodes"),
|
|
1828
|
+
"error": pr.get("error"),
|
|
1829
|
+
}
|
|
1830
|
+
try:
|
|
1831
|
+
before = {
|
|
1832
|
+
"1PSIDTS": _load_psidts(),
|
|
1833
|
+
"1PSID": _load_psid(),
|
|
1834
|
+
"file": _raw_cookies(),
|
|
1835
|
+
}
|
|
1836
|
+
async with _new_session() as session:
|
|
1837
|
+
await _rotate_psidts(session)
|
|
1838
|
+
url = f"{_BASE}{_prefix(_ACCOUNT)}{_INIT_PATH}"
|
|
1839
|
+
r = await session.get(url)
|
|
1840
|
+
_persist_cookies(session)
|
|
1841
|
+
|
|
1842
|
+
after_file = _raw_cookies()
|
|
1843
|
+
updated = sorted(
|
|
1844
|
+
k for k in set(before["file"]) | set(after_file)
|
|
1845
|
+
if before["file"].get(k) != after_file.get(k)
|
|
1846
|
+
)
|
|
1847
|
+
html = r.text
|
|
1848
|
+
at_m = _TOKEN_RE["at"].search(html)
|
|
1849
|
+
at = at_m.group(1) if at_m else ""
|
|
1850
|
+
logged_out = (not at) and "accounts.google.com/ServiceLogin" in html
|
|
1851
|
+
return {
|
|
1852
|
+
"logged_in": bool(at) and not logged_out,
|
|
1853
|
+
"logged_out_marker": logged_out,
|
|
1854
|
+
"status_code": r.status_code,
|
|
1855
|
+
"final_url": str(r.url),
|
|
1856
|
+
"psidts_changed": before["1PSIDTS"] != _load_psidts(),
|
|
1857
|
+
"psid_changed": before["1PSID"] != _load_psid(),
|
|
1858
|
+
"cookies_updated_in_file": updated,
|
|
1859
|
+
"cookies_present": sorted(after_file.keys()),
|
|
1860
|
+
}
|
|
1861
|
+
except Exception as e:
|
|
1862
|
+
return {"error": f"{type(e).__name__}: {e}"}
|
|
1863
|
+
|
|
1864
|
+
|
|
1865
|
+
def main() -> None:
|
|
1866
|
+
mcp.run()
|
|
1867
|
+
|
|
1868
|
+
|
|
1869
|
+
if __name__ == "__main__":
|
|
1870
|
+
main()
|