@playcraft/cli 0.0.42 → 0.0.43
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/dist/atom-plan/validate-asr-coverage.js +317 -0
- package/dist/commands/prad.js +61 -0
- package/dist/commands/remix.js +4 -2
- package/dist/commands/skills.js +24 -0
- package/dist/prad/atom-ref.js +23 -0
- package/dist/prad/check.js +377 -0
- package/dist/prad/check.test.js +27 -0
- package/dist/prad/explain.js +109 -0
- package/dist/prad/load-spec.js +23 -0
- package/dist/prad/paths.js +83 -0
- package/dist/prad/skills-index.js +60 -0
- package/package.json +3 -3
- package/project-template/.claude/agents/designer.md +26 -22
- package/project-template/.claude/agents/developer.md +2 -0
- package/project-template/.claude/agents/pm.md +3 -1
- package/project-template/.claude/agents/refs/designer-deliverable-spec.md +46 -7
- package/project-template/.claude/agents/refs/designer-handoff-v2-checklist.md +21 -13
- package/project-template/.claude/agents/refs/designer-style-exploration-flow.md +39 -9
- package/project-template/.claude/agents/refs/developer-dev-handoff.md +1 -1
- package/project-template/.claude/agents/refs/pm-workflow-detail.md +18 -2
- package/project-template/.claude/agents/refs/reviewer-convergence-eval.md +17 -5
- package/project-template/.claude/agents/refs/ta-pipeline-cookbook.md +42 -6
- package/project-template/.claude/agents/reviewer.md +8 -5
- package/project-template/.claude/agents/technical-artist.md +2 -0
- package/project-template/.claude/hooks/README.md +34 -6
- package/project-template/.claude/hooks/asr-coverage-validate.mjs +381 -0
- package/project-template/.claude/hooks/validate-workflow-stop.mjs +113 -7
- package/project-template/.claude/skills/playcraft-asset-state-sheet/SKILL.md +76 -22
- package/project-template/.claude/skills/playcraft-image-generation/SKILL.md +19 -0
- package/project-template/docs/team/agent-runtime-matrix.md +71 -39
- package/project-template/docs/team/atom-plan-format.md +68 -0
- package/project-template/docs/team/core-model.md +20 -19
- package/project-template/docs/team/workflow-consistency-checklist.md +52 -0
- package/project-template/templates/atom-plan.template.json +18 -0
- package/project-template/templates/designer-log.template.md +78 -5
- package/project-template/templates/layout-spec.template.md +48 -8
- package/project-template/templates/ta-log.template.md +50 -22
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@playcraft/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.43",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"@gltf-transform/core": "^4.3.0",
|
|
28
28
|
"@gltf-transform/extensions": "^4.3.0",
|
|
29
29
|
"@gltf-transform/functions": "^4.3.0",
|
|
30
|
-
"@playcraft/build": "^0.0.
|
|
31
|
-
"@playcraft/common": "^0.0.
|
|
30
|
+
"@playcraft/build": "^0.0.44",
|
|
31
|
+
"@playcraft/common": "^0.0.32",
|
|
32
32
|
"chokidar": "^4.0.3",
|
|
33
33
|
"commander": "^13.1.0",
|
|
34
34
|
"cors": "^2.8.6",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "Designer: (1) Gate #2
|
|
2
|
+
description: "Designer: (1) Gate #2 image production (MC + ASR), (2) TA-ready handoff, (3) audio + digit strip after #2b — not TA mass production."
|
|
3
3
|
allowedTools:
|
|
4
4
|
- "Read"
|
|
5
5
|
- "Grep"
|
|
@@ -25,6 +25,8 @@ allowedTools:
|
|
|
25
25
|
---
|
|
26
26
|
|
|
27
27
|
> **First Step**: Read `docs/project-state.md` → **`## Agent handoff`** → **## Runtime** → branch; read `refs/` only when Runtime says so. STOP: [STOP sync checklist](../../docs/team/collaboration.md#stop-sync-checklist).
|
|
28
|
+
>
|
|
29
|
+
> **Workflow spec**: `convergence-v1` + `designer-handoff-v2` — stage chain `pm → style_exploration → production → ui_pass → ui_review ⇄ ui_rework → gameplay_pass → done`. See [workflow-changelog.md](../../docs/team/workflow-changelog.md).
|
|
28
30
|
|
|
29
31
|
# Designer — Playable Ads Design Agent
|
|
30
32
|
|
|
@@ -60,16 +62,16 @@ allowedTools:
|
|
|
60
62
|
|
|
61
63
|
When trade-offs arise, preserve **#1 over #2 over #3**.
|
|
62
64
|
|
|
63
|
-
1. **
|
|
64
|
-
2. **
|
|
65
|
-
3. **Deliver audio + digit strip
|
|
65
|
+
1. **Image production (Gate #2)** — Master Composite (MC Panel 1 = all element types + UI) + **ASR** dual sheets with **isolated, crop-ready cells**; Coverage Matrix 100% rows with CoverageLayer (on-asr / mc-crop / ta-extends).
|
|
66
|
+
2. **Lock visual + narrative direction** — MC storyboard panels + experience flow; MC is **Developer UI design spec**.
|
|
67
|
+
3. **Deliver audio + digit strip after Gate #2b** — BGM / SFX / digit strip (Phase 2 `production` only); mood-matched to locked MC.
|
|
66
68
|
|
|
67
69
|
### Success criteria
|
|
68
70
|
|
|
69
|
-
| Phase | You succeed when
|
|
70
|
-
| --------------------------------- |
|
|
71
|
-
| **Phase 1** (`style_exploration`) | ≥2 MC; ASR dual sheets; Handoff Pack (Coverage Matrix, Palette Locked, Motion Notes); MC ratio checks |
|
|
72
|
-
| **Phase 2** (`production`) | BGM/SFX/digit strip; VisualAtoms `done` per v2 rules; no open ICP for Designer
|
|
71
|
+
| Phase | You succeed when |
|
|
72
|
+
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
73
|
+
| **Phase 1** (`style_exploration`) | ≥2 MC; ASR dual sheets (cells isolated); Image Production Preflight; Handoff Pack (Coverage Matrix 100% rows + CoverageLayer, Palette Locked, Motion Notes); MC ratio checks |
|
|
74
|
+
| **Phase 2** (`production`) | BGM/SFX/digit strip; VisualAtoms `done` per v2 rules; no open ICP for Designer |
|
|
73
75
|
|
|
74
76
|
### Deprioritized / Non-goals (summary)
|
|
75
77
|
|
|
@@ -83,7 +85,7 @@ Full element sets & TA pipelines; single MC before Gate #2; audio before style l
|
|
|
83
85
|
|
|
84
86
|
## Identity
|
|
85
87
|
|
|
86
|
-
**Art Director
|
|
88
|
+
**Art Director** (image-first, designer-handoff-v2): you **生** direction — **MC + ASR** (Phase 1), then audio (Phase 2). TA **产** — crop, remove-background, atlases. Ph.2: **no** batch `tile_sample_*.png`; visual baseline = MC + ASR. **Do not** run `remove-background` on ASR sheets — TA owns that. TA tools **not yours**: `sprite-sheet`, `animate`, `use-vfx`, `segment`, `3d *`.
|
|
87
89
|
|
|
88
90
|
## File Access
|
|
89
91
|
|
|
@@ -103,18 +105,20 @@ Full element sets & TA pipelines; single MC before Gate #2; audio before style l
|
|
|
103
105
|
|
|
104
106
|
**Skills:** `playcraft-audio-generation`; `playcraft-style-qa` (ICP supplementary PNGs only) | **Refs:** `designer-color-audio-recipes.md`, `designer-deliverable-spec.md` § Phase 2 | Mark VisualAtoms `actualOutput: ASR:...` when covered.
|
|
105
107
|
|
|
106
|
-
## DAG & critical rules
|
|
108
|
+
## DAG & critical rules
|
|
107
109
|
|
|
108
110
|
0. **四件套纪律** — visual narrative / Handoff Pack / ASR tables live in **`style-exploration` + `designer-log`** only; do **not** bloat `design-brief` or `layout-spec` (PM owns contracts). Palette deltas → `designer-log` § Palette Locked.
|
|
109
|
-
1. **
|
|
110
|
-
2.
|
|
111
|
-
3.
|
|
112
|
-
4. MC
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
6. **
|
|
116
|
-
7. **
|
|
117
|
-
8. **
|
|
118
|
-
9. **
|
|
119
|
-
10. **
|
|
120
|
-
11. **
|
|
111
|
+
1. **Image Production Preflight (Phase 1)** — before MC/ASR: fill `designer-log.md` § **Image Production Preflight** (storyboard + asset-state-sheet + image-generation §3/§3.1).
|
|
112
|
+
2. **DAG**: redundant atom → `⏭️ skipped`; missing asset → add row; direction changes → STOP; append **DAG Revisions**.
|
|
113
|
+
3. MC concept panel = **real game**, not sketch — **all element types** visible; storyboards mandatory for Gate #2 narrative lock.
|
|
114
|
+
4. **≥2 MC options** before #2a unless user pre-locked reference; **ASR only after** `selectedMcOption`.
|
|
115
|
+
5. MC = **5×完整 9:16 H5** (e.g. 3600×1280 or 4096×1455); never `1:1` / `10:3`; verify with `playcraft image info`.
|
|
116
|
+
5b. **MC models whitelist only** — `mulerouter/gpt-image-2` or `mulerouter/nano-banana-2` (provider prefix required); **never** gemini/flux/hy-image/wan/qwen or bare `gpt-image-2` for MC (see `playcraft-storyboard` §3).
|
|
117
|
+
6. **ASR: zero overlap + crop-ready cells** — grid cells non-overlapping; each cell **one isolated element**; sheet opaque OK; gold/orange cells use blue chroma per `playcraft-image-generation` §3; **never** remove-background on ASR.
|
|
118
|
+
7. **Coverage Matrix** — 100% contract rows; each **elementType** ≥1 row with CoverageLayer `on-asr` or `mc-crop`; mirror `on-asr` → `atom-plan.json` `asrSlot`.
|
|
119
|
+
8. **No audio** until Gate #2b passed (Phase 2 only).
|
|
120
|
+
9. **Layout Spec** binding — paths, palette, naming; Palette Locked documents MC vs spec delta.
|
|
121
|
+
10. **English prompts**; **size gate** after every image generation; **no VisualAtom `done` without Coverage Matrix row**.
|
|
122
|
+
11. **mediaGroups first for audio (Phase 2)** — read `atom-plan.json` → `skillsMatch.mediaGroups` for AudioAtom matches; link before generate.
|
|
123
|
+
12. **Skill Preflight before Phase 2** — audio/digit Skills in `designer-log.md` § Skill Preflight (Phase 2 section).
|
|
124
|
+
13. **Update atom status on completion** — `atom-plan.json` status + `actualOutput` (`ASR:...` or path); **never** leave atoms `pending` after delivery.
|
|
@@ -19,6 +19,8 @@ allowedTools:
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
21
|
> **First Step**: Read `docs/project-state.md` → **`## Agent handoff`** → **## Runtime** → branch; read `refs/` only when Runtime says so. STOP: [STOP sync checklist](../../docs/team/collaboration.md#stop-sync-checklist).
|
|
22
|
+
>
|
|
23
|
+
> **Workflow spec**: `convergence-v1` — Developer runs in `ui_pass` (devStatus `ui_ready`) then `gameplay_pass` (devStatus `ready`); never in `production`. See [workflow-changelog.md](../../docs/team/workflow-changelog.md).
|
|
22
24
|
|
|
23
25
|
# Developer — Playable Ads Developer Agent
|
|
24
26
|
|
|
@@ -17,6 +17,8 @@ allowedTools:
|
|
|
17
17
|
---
|
|
18
18
|
|
|
19
19
|
> **First Step**: Read `docs/project-state.md` → **`## Agent handoff`** → **## Runtime** → branch; read `refs/` only when Runtime says so. STOP: [STOP sync checklist](../../docs/team/collaboration.md#stop-sync-checklist).
|
|
20
|
+
>
|
|
21
|
+
> **Workflow spec**: `convergence-v1` — stage chain `pm → style_exploration → production → ui_pass → ui_review ⇄ ui_rework → gameplay_pass → done`. See [workflow-changelog.md](../../docs/team/workflow-changelog.md).
|
|
20
22
|
|
|
21
23
|
# PM — Playable Ads Project Manager
|
|
22
24
|
|
|
@@ -102,7 +104,7 @@ Intent fidelity, spec completeness, schedule feasibility, Gate clarity.
|
|
|
102
104
|
| --- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
|
103
105
|
| 1 | `docs/project-state.md` | `stage: pm`, `gates.#1 = pending`, handoff STOP (`gate_pending: "1"`) |
|
|
104
106
|
| 2 | `docs/design-brief.md` | Style Direction: Dimension + Modality + Arc + 6 elements; experience flow |
|
|
105
|
-
| 3 | `docs/layout-spec.md` | `assetMapping`
|
|
107
|
+
| 3 | `docs/layout-spec.md` | `assetMapping` + atlas groups + **Element Type Registry** (≤20 types) |
|
|
106
108
|
| 4 | `docs/atom-plan.json` | **`skillsMatch`** + **`atoms[]`** with `assignTo`/`dependsOn`; Gameplay/Config **`skillRef`** from snapshot — hook validates on STOP |
|
|
107
109
|
| 5 | `docs/atom-plan.md` | **Acceptance criteria only** at Gate #1 (no Atom List / DAG Order mirror) |
|
|
108
110
|
|
|
@@ -29,10 +29,12 @@ All visible text is image assets — **zero font files**. Static text is baked i
|
|
|
29
29
|
| Extract from MC concept panel | TA → `layout-spec` bg path |
|
|
30
30
|
| 2.5D / hero bg needs dedicated sample | PM marks VisualAtom `assignTo: Designer` → ICP isolated PNG only |
|
|
31
31
|
|
|
32
|
-
## Phase 1 Deliverables
|
|
32
|
+
## Phase 1 Deliverables — Image production (MC + ASR)
|
|
33
33
|
|
|
34
34
|
Gate #2a: **one MC per option** + Experience Flow text. Gate #2b (after `selectedMcOption`): **ASR dual sheets** + **Handoff Pack** (below).
|
|
35
35
|
|
|
36
|
+
> **Phase 1 scope = images only.** Audio/digit strip is **Phase 2** after Gate #2b — see § Phase 2 Deliverables.
|
|
37
|
+
|
|
36
38
|
| # | Deliverable | Format | Spec |
|
|
37
39
|
| --- | --------------------------------- | ------ | ---------------------------------------------------------- |
|
|
38
40
|
| 1 | **Master Composite** | PNG 4K | 5 panels: concept + 4 storyboard scenes |
|
|
@@ -67,15 +69,34 @@ Paths: `assets/images/storyboard/master_composite_option_[A|B|C].png`
|
|
|
67
69
|
|
|
68
70
|
### Deliverable 2: ASR
|
|
69
71
|
|
|
70
|
-
> **Skill**: `playcraft-asset-state-sheet`
|
|
72
|
+
> **Skill**: `playcraft-asset-state-sheet` + `playcraft-image-generation` §3.1 (ASR branch)
|
|
71
73
|
|
|
72
74
|
Only after `selectedMcOption` is set. `--reference-image` = confirmed MC.
|
|
73
75
|
|
|
74
76
|
```
|
|
75
77
|
assets/images/reference/ui_state_sheet_[X].png
|
|
76
78
|
assets/images/reference/element_state_sheet_[X].png
|
|
79
|
+
# optional when types > 12:
|
|
80
|
+
assets/images/reference/element_state_sheet_[X]_2.png
|
|
77
81
|
```
|
|
78
82
|
|
|
83
|
+
**ASR whole PNG is opaque by design** — TA crops cells then `remove-background`. Designer must deliver **isolated elements per cell** (no white box / scene inside cells).
|
|
84
|
+
|
|
85
|
+
#### Three-layer coverage model
|
|
86
|
+
|
|
87
|
+
| CoverageLayer | Meaning | Matrix columns |
|
|
88
|
+
| -------------- | ----------------------------------- | ------------------------------------------- |
|
|
89
|
+
| **on-asr** | Physical slot on ASR PNG (`R#C#`) | `ASR sheet` + `Grid` |
|
|
90
|
+
| **mc-crop** | Visible in MC Panel 1, no ASR slot | `ASR sheet` = `MC-crop` + note Panel region |
|
|
91
|
+
| **ta-extends** | Color variant / extra states for TA | `TA extends? = yes` + Style Intent line |
|
|
92
|
+
|
|
93
|
+
**100% Matrix rows** = every `assetMapping` elementId + every static text id has **one row**.
|
|
94
|
+
**NOT** every row needs a physical ASR slot — use layers above.
|
|
95
|
+
|
|
96
|
+
**Type representative rule**: each **element type** (from `layout-spec` § Element Type Registry or Matrix `elementType` column) must appear in **on-asr** or **mc-crop** at least once.
|
|
97
|
+
|
|
98
|
+
Physical slot budget: **8–12 slots per sheet**; overflow → second element sheet or mc-crop + ta-extends.
|
|
99
|
+
|
|
79
100
|
---
|
|
80
101
|
|
|
81
102
|
### Gate #2b Handoff Pack (mandatory before `#2b` STOP)
|
|
@@ -86,12 +107,20 @@ assets/images/reference/element_state_sheet_[X].png
|
|
|
86
107
|
|
|
87
108
|
One row per contract item from `layout-spec.md`:
|
|
88
109
|
|
|
89
|
-
| Contract id | Type | ASR sheet
|
|
90
|
-
| ------------------------------- | ------ |
|
|
91
|
-
| `elementId` from assetMapping | visual | ui / element |
|
|
92
|
-
| `staticTextId` from Text Assets | text | ui / MC
|
|
110
|
+
| Contract id | elementType | Type | CoverageLayer | ASR sheet | Grid | State(s) | TA extends? |
|
|
111
|
+
| ------------------------------- | ----------- | ------ | ----------------------------- | ---------------------- | ---- | ------------ | ----------- |
|
|
112
|
+
| `elementId` from assetMapping | `tile` | visual | on-asr / mc-crop / ta-extends | ui / element / MC-crop | R1C1 | e.g. default | yes/no |
|
|
113
|
+
| `staticTextId` from Text Assets | — | text | mc-crop or on-asr | ui / MC-crop | — | baked | yes/no |
|
|
93
114
|
|
|
94
|
-
**100% rule**: every `elementId` in `assetMapping` and every static text id must have a row.
|
|
115
|
+
**100% rule**: every `elementId` in `assetMapping` and every static text id must have a row.
|
|
116
|
+
|
|
117
|
+
**CoverageLayer rules**:
|
|
118
|
+
|
|
119
|
+
- **on-asr**: must have valid `Grid` (R#C#) and matching PNG slot; mirror to `atom-plan.json` → `asrSlot`
|
|
120
|
+
- **mc-crop**: MC Panel 1 shows type; document region in Style Intent Notes
|
|
121
|
+
- **ta-extends**: color variants / full state sets; `TA extends? = yes` + one-line extension hint
|
|
122
|
+
|
|
123
|
+
**Forbidden**: missing rows; all rows `ta-extends` with no on-asr/mc-crop type representative; overlapping ASR slots.
|
|
95
124
|
|
|
96
125
|
#### 2. Palette Locked (`logs/designer-log.md`)
|
|
97
126
|
|
|
@@ -172,6 +201,16 @@ For each `assignTo: Designer` VisualAtom:
|
|
|
172
201
|
|
|
173
202
|
**Forbidden**: mark VisualAtom `done` without ASR row or supplementary file.
|
|
174
203
|
|
|
204
|
+
#### ICP supplementary PNG — when (and only when) to produce
|
|
205
|
+
|
|
206
|
+
Designer Phase 2 supplementary PNGs are a **fallback path**, not a default. Produce one **only if all three** are true:
|
|
207
|
+
|
|
208
|
+
1. **TA Step 0c Style Interpretation** marks that atom's `confidence = low` in `logs/ta-log.md` (i.e. Designer's MC/ASR didn't tell TA enough).
|
|
209
|
+
2. **Crop / segment from ASR or MC failed** — TA tried `playcraft image crop` (grid coord from ASR Coverage Matrix) and `playcraft image segment --boxes` / `--text` on the MC concept panel, and the extracted region is unusable (chroma residue, partial element, wrong perspective).
|
|
210
|
+
3. **TA opens an ICP entry** in `docs/intent-clarifications.md` with `routeTo: designer`, citing both ① the failed extraction command and ② the specific style ambiguity.
|
|
211
|
+
|
|
212
|
+
If any of ①②③ is missing, the fix lives elsewhere (TA tool chain, Designer Style Intent Notes patch, or PM contract patch) — not a supplementary PNG. Document the chosen route in `designer-log.md`.
|
|
213
|
+
|
|
175
214
|
Run **`playcraft-style-qa` §1** only for **ICP supplementary** image files (not for ASR sheets themselves).
|
|
176
215
|
|
|
177
216
|
### TA ownership in Phase 2 (not Designer)
|
|
@@ -8,17 +8,24 @@
|
|
|
8
8
|
- [ ] `selectedMcOption` set (Gate #2a passed)
|
|
9
9
|
- [ ] MC path: `assets/images/storyboard/master_composite_option_[X].png`
|
|
10
10
|
- [ ] ASR paths exist and pass zero-overlap visual check
|
|
11
|
+
- [ ] ASR cells: isolated elements, no white box / scene inside cells (whole sheet opaque is OK)
|
|
12
|
+
- [ ] § **Image Production Preflight** filled (Phase 1 — three Skills read)
|
|
11
13
|
|
|
12
|
-
## 1. ASR Coverage Matrix (100%)
|
|
14
|
+
## 1. ASR Coverage Matrix (100% rows)
|
|
13
15
|
|
|
14
16
|
In `logs/designer-log.md` § ASR Coverage Matrix:
|
|
15
17
|
|
|
16
|
-
1. List every `elementId` from `layout-spec.md` § Asset Mapping (
|
|
18
|
+
1. List every `elementId` from `layout-spec.md` § Asset Mapping (atlas `frameId` groups = one row per logical element).
|
|
17
19
|
2. List every static text `id` from § Text Assets → Static Text.
|
|
18
|
-
3.
|
|
19
|
-
4.
|
|
20
|
+
3. **Row count** must equal assetMapping + static text id count (verify before STOP).
|
|
21
|
+
4. For each row, set **CoverageLayer** = `on-asr` | `mc-crop` | `ta-extends`.
|
|
22
|
+
5. For each row: `ASR sheet` = `ui` | `element` | `element_2` | `MC-crop` | `ICP-pending`.
|
|
23
|
+
6. `TA extends?` = `no` only when on-asr shows final representative state; else `yes`.
|
|
24
|
+
7. **Sheet grid metadata** table filled with real numbers (not `{{placeholder}}`).
|
|
20
25
|
|
|
21
|
-
**
|
|
26
|
+
**Type representative rule**: each distinct **elementType** (Matrix column or `layout-spec` § Element Type Registry) must have at least one row with CoverageLayer `on-asr` or `mc-crop`.
|
|
27
|
+
|
|
28
|
+
**Stop rule**: any contract row missing → do not set `#2b` pending.
|
|
22
29
|
|
|
23
30
|
## 2. Palette Locked
|
|
24
31
|
|
|
@@ -50,9 +57,9 @@ In `docs/style-exploration.md` under confirmed option:
|
|
|
50
57
|
```
|
|
51
58
|
For each atom-plan row where assignTo = Designer:
|
|
52
59
|
├─ VisualAtom + covered in Coverage Matrix?
|
|
53
|
-
│ └─ yes → status=done, actualOutput=ASR:...
|
|
60
|
+
│ └─ yes → status=done, actualOutput=ASR:... (on-asr rows → asrSlot in atom-plan.json)
|
|
54
61
|
├─ AudioAtom?
|
|
55
|
-
│ └─ deliver MP3 at path → done
|
|
62
|
+
│ └─ deliver MP3 at path → done (Phase 2 only)
|
|
56
63
|
├─ Gap / TA extract failed (ICP)?
|
|
57
64
|
│ └─ generate one PNG → done with path, or blocked until answered
|
|
58
65
|
└─ Never: done with only "will extract later"
|
|
@@ -60,9 +67,10 @@ For each atom-plan row where assignTo = Designer:
|
|
|
60
67
|
|
|
61
68
|
## 5. Files to verify before STOP
|
|
62
69
|
|
|
63
|
-
| File
|
|
64
|
-
|
|
|
65
|
-
| `docs/style-exploration.md`
|
|
66
|
-
| `logs/designer-log.md`
|
|
67
|
-
| `assets/images/reference/ui_state_sheet_[X].png`
|
|
68
|
-
| `assets/images/reference/element_state_sheet_[X].png`
|
|
70
|
+
| File | Contains |
|
|
71
|
+
| ------------------------------------------------------- | ------------------------------------------------------------------------- |
|
|
72
|
+
| `docs/style-exploration.md` | MC paths, Motion Notes, Experience Flow |
|
|
73
|
+
| `logs/designer-log.md` | Image Production Preflight, Coverage Matrix, Palette Locked, Style Intent |
|
|
74
|
+
| `assets/images/reference/ui_state_sheet_[X].png` | exists |
|
|
75
|
+
| `assets/images/reference/element_state_sheet_[X].png` | exists |
|
|
76
|
+
| `assets/images/reference/element_state_sheet_[X]_2.png` | if types > 12 / overflow |
|
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
# Designer — Style exploration flow (Phase 1, steps 2–5)
|
|
2
2
|
|
|
3
|
-
> **Scope**: After **Step 1 — Skill Discovery** in `agents/designer.md`, follow this document for MC
|
|
3
|
+
> **Scope**: After **Step 1 — Skill Discovery** in `agents/designer.md`, follow this document for **image production** (MC + ASR) through Gate #2b STOP. **Exit criteria**: see `agents/designer.md` Goals § Success criteria.
|
|
4
4
|
>
|
|
5
5
|
> **Deliverable shapes & tables**: `refs/designer-deliverable-spec.md`.
|
|
6
6
|
|
|
7
7
|
**Trigger**: `project-state.md` stage = `style_exploration`
|
|
8
8
|
|
|
9
|
+
## Step 1.5 — Image Production Preflight (before MC option B+ or before ASR)
|
|
10
|
+
|
|
11
|
+
Fill `logs/designer-log.md` § **Image Production Preflight**:
|
|
12
|
+
|
|
13
|
+
1. Read `playcraft-storyboard`, `playcraft-asset-state-sheet`, `playcraft-image-generation` (§3 + §3.1)
|
|
14
|
+
2. Mark each Skill row ✓ with one-line decision summary
|
|
15
|
+
3. Read `layout-spec.md` — count assetMapping rows + note Element Type Registry (if present)
|
|
16
|
+
|
|
17
|
+
**Do not generate ASR until this section is complete.**
|
|
18
|
+
|
|
9
19
|
## Step 2 — Generate Master Composite only (one image per option A/B[/C])
|
|
10
20
|
|
|
11
21
|
- Follow `playcraft-storyboard` skill:**每格完整 9:16 H5**;`45:16` + `--width 3600 --height 1280`(2K)或 `4096×1455`(4K);**禁止 `1:1` / `10:3`**
|
|
12
|
-
-
|
|
22
|
+
- **Panel 1 must show every element type** from `layout-spec` (or Element Type Registry)
|
|
23
|
+
- 每个方案用不同 prompt/美术方向(模型均用白名单,见 `refs/designer-master-composite-recipes.md`)
|
|
13
24
|
- 生成后立即 `playcraft image info`:总比例 **width/height ≈ 2.81**,**(width÷5)/height ≈ 0.5625**;不合格则重生成
|
|
14
25
|
- **Review the auto-generated `.json` sidecar** — 确认 `aspectRatio` / `imageSize` / 实际像素正确
|
|
15
26
|
|
|
@@ -22,16 +33,35 @@
|
|
|
22
33
|
## Step 4 — Generate ASR sheets(仅针对 `project-state.selectedMcOption`)
|
|
23
34
|
|
|
24
35
|
- Read `selectedMcOption` from `docs/project-state.md` — if missing, **STOP**
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
- `--reference-image` = `master_composite_option_[selectedMcOption].png`
|
|
28
|
-
-
|
|
36
|
+
- **Re-read** `playcraft-asset-state-sheet` + `playcraft-image-generation` §3.1 (cell chroma / isolated)
|
|
37
|
+
- 输出:`ui_state_sheet_[X].png` + `element_state_sheet_[X].png`(类型 >12 时可加 `element_state_sheet_[X]_2.png`)
|
|
38
|
+
- `--reference-image` = `master_composite_option_[selectedMcOption].png`;`--image-model` 与 MC 一致
|
|
39
|
+
- Prompt:sheet `#808080` 或统一色幕;每格 **one isolated element**;金/橙格用蓝幕
|
|
40
|
+
- 生成后 `playcraft image info`;目视:零重叠、格内无白盒/场景底
|
|
41
|
+
- **Do not** `remove-background` on ASR — TA handles post-crop
|
|
29
42
|
|
|
30
43
|
## Step 5 — Gate #2b Handoff Pack
|
|
31
44
|
|
|
32
45
|
> **Checklist**: `refs/designer-handoff-v2-checklist.md`
|
|
33
46
|
|
|
34
47
|
1. 补全 `docs/style-exploration.md`(ASR 路径、**Motion Notes**、Experience Flow)
|
|
35
|
-
2. 更新 `logs/designer-log.md
|
|
36
|
-
|
|
37
|
-
|
|
48
|
+
2. 更新 `logs/designer-log.md`:
|
|
49
|
+
- **ASR Coverage Matrix** — 100% contract rows + **CoverageLayer** column
|
|
50
|
+
- 每种 **elementType** ≥1 行 `on-asr` 或 `mc-crop`
|
|
51
|
+
- **Palette Locked**、Style Intent / Anti-Pattern
|
|
52
|
+
- Mirror `on-asr` rows → `atom-plan.json` → `atoms[].asrSlot`
|
|
53
|
+
3. **Self-check before STOP**:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# MC ratio
|
|
57
|
+
playcraft image info --input assets/images/storyboard/master_composite_option_[X].png
|
|
58
|
+
|
|
59
|
+
# Count contract rows (adjust grep to your layout-spec format)
|
|
60
|
+
grep -c 'elementId\|"id":' docs/layout-spec.md # approximate — Matrix row count must match
|
|
61
|
+
|
|
62
|
+
# ASR files exist
|
|
63
|
+
ls assets/images/reference/ui_state_sheet_[X].png assets/images/reference/element_state_sheet_[X].png
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
4. 更新 handoff + `gates.#2b = pending`
|
|
67
|
+
5. **STOP** — 禁止 Phase 2 音频与批量视觉样本 PNG
|
|
@@ -96,7 +96,7 @@ Set `project-state.md`:
|
|
|
96
96
|
2. `npm run dev`
|
|
97
97
|
3. Re-run UI + gameplay + runtime checklists for affected areas
|
|
98
98
|
4. Close blocker rows (`status: resolved`) or escalate if still wrong
|
|
99
|
-
5. Only then set `devStatus: ready` and
|
|
99
|
+
5. Only then set `devStatus: ui_ready` (after `ui_pass`) or `devStatus: ready` (after `gameplay_pass`) and handoff `next_orchestrator_action: "Invoke @reviewer ui_diff"` (or `load_check`)
|
|
100
100
|
|
|
101
101
|
## Dev ready checklist (`devStatus: ready` — all required)
|
|
102
102
|
|
|
@@ -141,7 +141,7 @@ Design the shared contract between Designer, TA, and Developer:
|
|
|
141
141
|
3. **Asset specifications** — size, format, naming for each type
|
|
142
142
|
4. **Asset mapping** — element ID → file path (the integration bridge)
|
|
143
143
|
|
|
144
|
-
**Critical**: `assetMapping` paths are **locked after Gate #1**. No agent may unilaterally change paths — this is the Asset Contract: TA fills paths in production Wave 2; Developer binds **real files** in `
|
|
144
|
+
**Critical**: `assetMapping` paths are **locked after Gate #1**. No agent may unilaterally change paths — this is the Asset Contract: TA fills paths in production Wave 2; Developer binds **real files** in `ui_pass` after TA Compliance green.
|
|
145
145
|
|
|
146
146
|
**Transparency**: TA auto-derives transparency requirements from `assetMapping` path conventions (`bg/` = opaque, `ui/`/`vfx/`/`txt/` = needs alpha, `tiles/` = needs alpha unless card faces). PM does NOT need to define transparency fields — chroma key selection and background removal are TA's technical domain. See `ta-pipeline-cookbook.md` Step 0e.
|
|
147
147
|
|
|
@@ -163,6 +163,22 @@ Single-element groups stay as single-file paths; do not invent atlases for one t
|
|
|
163
163
|
|
|
164
164
|
---
|
|
165
165
|
|
|
166
|
+
## Element Type Registry + ASR budget (Gate #1)
|
|
167
|
+
|
|
168
|
+
After atlas groups, add **§ Element Type Registry** in `layout-spec.md`:
|
|
169
|
+
|
|
170
|
+
- Group variant elementIds under a shared `typeId` (e.g. `tile` → red/blue/green ids)
|
|
171
|
+
- Count **unique types** — target **≤ 20** for playable ads
|
|
172
|
+
- ASR physical slot budget: ~12 ui + ~12 element states; overflow → second element sheet or mc-crop/ta-extends plan
|
|
173
|
+
- If user request implies >20 types, PM degrades or splits variants to TA-extends in Gate #1 options
|
|
174
|
+
|
|
175
|
+
Pre-Write checklist addition:
|
|
176
|
+
|
|
177
|
+
- [ ] Element Type Registry present; unique type count documented
|
|
178
|
+
- [ ] Variant-only ids marked for TA-extends in Designer handoff notes (optional one line in atom-plan.md)
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
166
182
|
## Step 7: Experience Flow Design
|
|
167
183
|
|
|
168
184
|
Design each stage with four fields — from "what happens" to "what the player feels" (MDA player perspective):
|
|
@@ -244,7 +260,7 @@ playcraft skills link --from-atom-plan --prune
|
|
|
244
260
|
- `validate-atom-plan`:PM 定稿前手动跑;**PM STOP** 时 hook 再拦一层(invalid skillRef 无法 STOP)。
|
|
245
261
|
- `link`:读取 `atom-plan.json` 中所有非空 `skillRef`。
|
|
246
262
|
|
|
247
|
-
**PM does not** pre-fill `atom-plan.md` § Impl Skill Context — **Developer** in `
|
|
263
|
+
**PM does not** pre-fill `atom-plan.md` § Impl Skill Context — **Developer** in `ui_pass` / `gameplay_pass`.
|
|
248
264
|
|
|
249
265
|
### 8e. `atom-plan.md`(可选)
|
|
250
266
|
|
|
@@ -21,16 +21,28 @@ Soft checklist only — **do not judge subjective design quality**.
|
|
|
21
21
|
|
|
22
22
|
**Fail →** list missing items + `routeTo: pm` (or `designer` if visual doc gap).
|
|
23
23
|
|
|
24
|
-
### Gate #2b additional checklist
|
|
24
|
+
### Gate #2b additional checklist (structural — hard fail)
|
|
25
|
+
|
|
26
|
+
Gate #2b **structural** gaps are hard fails (missing files, row count, type representatives). Do not fail for subjective aesthetics.
|
|
25
27
|
|
|
26
28
|
```
|
|
27
29
|
[ ] MC five panels complete (concept + 4 storyboard)
|
|
28
|
-
[ ] MC aspect ratio correct —
|
|
29
|
-
[ ]
|
|
30
|
-
[ ] ASR
|
|
30
|
+
[ ] MC aspect ratio correct — playcraft image info <mc-path> (width/height ≈ 2.81)
|
|
31
|
+
[ ] MC Panel 1 shows every element type from layout-spec § Element Type Registry (or assetMapping)
|
|
32
|
+
[ ] ASR dual sheets exist: ui_state_sheet_[X].png + element_state_sheet_[X].png
|
|
33
|
+
[ ] Optional overflow: element_state_sheet_[X]_2.png when types > 12
|
|
34
|
+
[ ] logs/designer-log.md § Image Production Preflight complete (3 image Skills)
|
|
35
|
+
[ ] ASR Coverage Matrix row count == assetMapping rows + static text ids
|
|
36
|
+
[ ] CoverageLayer column present; each elementType has ≥1 on-asr OR mc-crop row
|
|
37
|
+
[ ] Sheet grid metadata filled (no {{placeholders}})
|
|
38
|
+
[ ] on-asr rows mirrored to atom-plan.json asrSlot where applicable
|
|
39
|
+
[ ] ASR semantic split: UI board has no gameplay tiles; element board has no full HUD screenshot
|
|
40
|
+
[ ] Spot-check: ASR cells look isolated (no white box / scene floor inside cells) — note in report if obvious
|
|
31
41
|
```
|
|
32
42
|
|
|
33
|
-
|
|
43
|
+
Optional CLI: `playcraft skills validate-asr-coverage --project-dir .`
|
|
44
|
+
|
|
45
|
+
**Pass →** handoff `Run Gate #2b`. **Fail →** routeTo Designer (or PM if layout-spec/type budget issue).
|
|
34
46
|
|
|
35
47
|
---
|
|
36
48
|
|
|
@@ -742,21 +742,55 @@ Designer's **ASR sheets** (UI + element state reference) contain **representativ
|
|
|
742
742
|
|
|
743
743
|
1. From **ASR** (preferred): `crop` each state slot → `resize` to spec → these become your `--reference-image` for Stage A batch generation
|
|
744
744
|
2. From **Master Composite** (fallback): extract elements not covered in ASR
|
|
745
|
-
3. Check `designer-log.md` **ASR
|
|
745
|
+
3. Check `designer-log.md` § **ASR Coverage Matrix** — note which states are covered vs which need expansion; Sheet grid metadata table at the top has `rows × cols + cell W×H + padding` for pixel-coordinate computation
|
|
746
746
|
4. Background: generate clean bg using composite as `--reference-image`
|
|
747
747
|
5. Text assets: → **invoke `playcraft-text-rendering` skill**
|
|
748
748
|
6. Representative quality insufficient → ICP request to Designer for supplementary samples
|
|
749
749
|
|
|
750
|
+
**若 ASR crop 后不可抠**(白边/色幕残留/元素截断/格内场景底)→ **`routeTo: designer`** 重生成 ASR 对应格;**不要** TA 自行用 AI 重画整张 ASR。
|
|
751
|
+
|
|
750
752
|
**ASR 提取方法(按优先级)**:
|
|
751
753
|
|
|
752
754
|
> ⚠️ **严禁对 ASR 网格布局图使用纯 text prompt 的 segment!** 使用 `designer-log` 中的槽位坐标 + `crop`。
|
|
753
755
|
|
|
756
|
+
**优先路径:直接读 `atom-plan.json` → `atoms[].asrSlot`(最高优先级)**
|
|
757
|
+
|
|
758
|
+
Designer 在 Phase 1 完成 ASR 后会把每个 VisualAtom 的网格坐标写到 `atom-plan.json` → `atoms[i].asrSlot: { sheet, row, col }`(详见 [`docs/team/atom-plan-format.md` § `asrSlot`](../../../docs/team/atom-plan-format.md#asrslot-字段可选--visualatom-基线绑定))。TA 直接用这个字段 + `designer-log` § Sheet grid metadata,省去手翻 Coverage Matrix 的步骤:
|
|
759
|
+
|
|
760
|
+
```bash
|
|
761
|
+
# 1) 从 atom-plan.json 读取所有有 asrSlot 的 VisualAtom
|
|
762
|
+
cat docs/atom-plan.json | jq -r '
|
|
763
|
+
.atoms[]
|
|
764
|
+
| select(.asrSlot != null)
|
|
765
|
+
| "\(.atomId)\t\(.asrSlot.sheet)\t\(.asrSlot.row)\t\(.asrSlot.col)"
|
|
766
|
+
'
|
|
767
|
+
# 输出格式: <atomId>\t<sheet>\t<row>\t<col>
|
|
768
|
+
|
|
769
|
+
# 2) 从 designer-log.md § ASR Coverage Matrix § Sheet grid metadata 读 cellW / cellH / padding
|
|
770
|
+
# (单独读一次,缓存到 ta-log 备查)
|
|
771
|
+
|
|
772
|
+
# 3) 计算像素坐标并 crop(脚本化 — ta-workspace/scripts/asr-extract.mjs)
|
|
773
|
+
# x = (col - 1) * (cellW + padding) + padding
|
|
774
|
+
# y = (row - 1) * (cellH + padding) + padding
|
|
775
|
+
# sheetPath 映射:
|
|
776
|
+
# ui → assets/images/reference/ui_state_sheet_<selectedMcOption>.png
|
|
777
|
+
# element → assets/images/reference/element_state_sheet_<selectedMcOption>.png
|
|
778
|
+
# element_2 → assets/images/reference/element_state_sheet_<selectedMcOption>_2.png
|
|
779
|
+
# contractPath 从 layout-spec assetMapping 中按 atom slot 反查
|
|
780
|
+
#
|
|
781
|
+
# playcraft image crop --input <sheetPath> --x <x> --y <y> --width <cellW> --height <cellH> --output <contractPath>
|
|
782
|
+
```
|
|
783
|
+
|
|
754
784
|
```
|
|
755
|
-
ASR 是已知网格布局?(ui_state_sheet / element_state_sheet,行列分明)
|
|
756
|
-
├─
|
|
785
|
+
ASR 是已知网格布局?(ui_state_sheet / element_state_sheet / element_state_sheet_*_2,行列分明)
|
|
786
|
+
├─ atom-plan.json 有 asrSlot 字段 → 方法 0(推荐): 上面脚本化批量 crop
|
|
787
|
+
│
|
|
788
|
+
├─ 是但 asrSlot 缺失 → 方法 1: crop 直切(手动查 Coverage Matrix R#C#)
|
|
757
789
|
│ 1. playcraft image info --input assets/images/reference/ui_state_sheet_<X>.png → 获取尺寸
|
|
758
|
-
│ 2. 从 designer-log ASR
|
|
759
|
-
│
|
|
790
|
+
│ 2. 从 designer-log § ASR Coverage Matrix 读取 Sheet grid 元数据 + 目标行列 (R#C#)
|
|
791
|
+
│ pixel coords: x = (C-1) × (cellW + padding) + padding
|
|
792
|
+
│ y = (R-1) × (cellH + padding) + padding
|
|
793
|
+
│ 3. playcraft image crop --input <asr_sheet> --x <x> --y <y> --width <cellW> --height <cellH> --output <out>
|
|
760
794
|
│ 4. 对有背景底色的元素:crop 后再 remove-background --method floodfill
|
|
761
795
|
│
|
|
762
796
|
├─ 元素位置不规则但 bbox 已知 → 方法 2: segment --boxes(精确框选)
|
|
@@ -765,6 +799,8 @@ ASR 是已知网格布局?(ui_state_sheet / element_state_sheet,行列分
|
|
|
765
799
|
└─ 仅 MC 有该类型 → 方法 3: decompose-layers 或 segment --text(最后手段,见 playcraft-masking)
|
|
766
800
|
```
|
|
767
801
|
|
|
802
|
+
> **若 Designer 没有填 `asrSlot`** — 不需要重新 invoke Designer,TA 可以手动从 `designer-log § ASR Coverage Matrix § Coverage` 反查 R#C# 并继续。在 ICP 中提示 PM/Designer 下次预填可加速。
|
|
803
|
+
|
|
768
804
|
**常见踩坑**:
|
|
769
805
|
|
|
770
806
|
- ❌ `segment --text "apple tile icon"` → SAM3 可能只切出苹果图案,丢失 tile 方块底板
|
|
@@ -858,7 +894,7 @@ assetMapping 路径所在目录?
|
|
|
858
894
|
| ----------------------------- | ---------- | ------------- | ------------------------------------- | ------------------------------------------- | -------------------- | -------- |
|
|
859
895
|
| assets/images/bg/bg_main.webp | false | full-coverage | N/A | N/A | 边缘全覆盖检查 | ❓ |
|
|
860
896
|
| assets/images/ui/btn_cta.webp | true | greenscreen | `remove-background --floodfill -t 25` | `segment --boxes` / `remove-bg --method ai` | 深色背景 overlay | ❓ |
|
|
861
|
-
| assets/images/
|
|
897
|
+
| assets/images/txt/digits.webp | true | bluescreen | `remove-background --floodfill -t 25` | `segment --boxes` / `remove-bg --method ai` | 深色背景 overlay | ❓ |
|
|
862
898
|
| assets/images/vfx/glow.webp | true | bluescreen | `remove-background --floodfill -t 25` | `segment --boxes` | 逐帧深色背景 overlay | ❓ |
|
|
863
899
|
| assets/images/tiles/tile.webp | true | greenscreen | `remove-background --floodfill -t 25` | `segment --boxes` / `remove-bg --method ai` | 深色背景 overlay | ❓ |
|
|
864
900
|
| assets/images/txt/title.webp | true | bluescreen | `remove-background --floodfill -t 25` | `remove-bg --method ai` | 深色背景 overlay | ❓ |
|
|
@@ -20,6 +20,8 @@ allowedTools:
|
|
|
20
20
|
---
|
|
21
21
|
|
|
22
22
|
> **First Step**: Read `docs/project-state.md` → **`## Agent handoff`** → **## Runtime** → branch; read `refs/` only when Runtime says so. STOP: [STOP sync checklist](../../docs/team/collaboration.md#stop-sync-checklist).
|
|
23
|
+
>
|
|
24
|
+
> **Workflow spec**: `convergence-v1` — three modes: `design_check` (Gate #1/#2b pre-check), `ui_diff` (screenshots vs MC), `load_check` (before Gate #3). Increment `uiReworkRound` on `ui_diff` fail (max 5). See [workflow-changelog.md](../../docs/team/workflow-changelog.md).
|
|
23
25
|
|
|
24
26
|
# Reviewer — Playable Ads Convergence Review Agent
|
|
25
27
|
|
|
@@ -120,8 +122,9 @@ Afterward update handoff per **Runtime**. **Never** write mainline `stage`.
|
|
|
120
122
|
## Important Rules
|
|
121
123
|
|
|
122
124
|
1. **Never modify production files** — only `logs/review-report.md` and `docs/project-state.md` checkpoint.
|
|
123
|
-
2. **`design_check` is soft** — block missing docs / wrong MC ratio / empty assetMapping; do not fail for aesthetics.
|
|
124
|
-
3. **`
|
|
125
|
-
4. **`
|
|
126
|
-
5. **`
|
|
127
|
-
6.
|
|
125
|
+
2. **`design_check` is soft for Gate #1** — block missing docs / wrong MC ratio / empty assetMapping; do not fail for aesthetics.
|
|
126
|
+
3. **`design_check` Gate #2b structural items are hard fails** — missing ASR files, Coverage Matrix row count mismatch, missing type representative (on-asr/mc-crop), empty Sheet grid metadata.
|
|
127
|
+
4. **`ui_diff` uses playwright-cli** — save screenshots under `logs/`; each diff needs severity + `routeTo: developer | ta | designer`.
|
|
128
|
+
5. **`load_check` is not gameplay QA** — only load + console errors; gameplay = user at Gate #3.
|
|
129
|
+
6. **`uiReworkRound` max 5** — increment on `ui_diff` fail; minor issues log only, do not block pass.
|
|
130
|
+
7. **Orchestrator owns stage** — you set handoff `next_orchestrator_action` only.
|
|
@@ -23,6 +23,8 @@ allowedTools:
|
|
|
23
23
|
---
|
|
24
24
|
|
|
25
25
|
> **First Step**: Read `docs/project-state.md` → **`## Agent handoff`** → **## Runtime** → branch; read `refs/` only when Runtime says so. STOP: [STOP sync checklist](../../docs/team/collaboration.md#stop-sync-checklist).
|
|
26
|
+
>
|
|
27
|
+
> **Workflow spec**: `convergence-v1` — stage chain `pm → style_exploration → production → ui_pass → ui_review ⇄ ui_rework → gameplay_pass → done`. TA runs in `production` Wave 2 (after Designer Ph.2). See [workflow-changelog.md](../../docs/team/workflow-changelog.md).
|
|
26
28
|
|
|
27
29
|
# Technical Artist — Playable Ads Production Agent
|
|
28
30
|
|