devlyn-cli 1.9.0 → 1.10.0
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/CLAUDE.md +3 -1
- package/bin/devlyn.js +1 -0
- package/config/skills/devlyn:auto-resolve/SKILL.md +52 -2
- package/optional-skills/asset-creator/CATALOG-SCHEMA.md +99 -0
- package/optional-skills/asset-creator/SKILL.md +291 -0
- package/optional-skills/asset-creator/STYLE-GUIDE.md +174 -0
- package/package.json +1 -1
package/CLAUDE.md
CHANGED
|
@@ -56,10 +56,12 @@ For hands-free build-evaluate-polish cycles — works for bugs, features, refact
|
|
|
56
56
|
/devlyn:auto-resolve [task description]
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
This runs the full pipeline automatically: **Build → Build Gate → Browser Validate → Evaluate → Fix Loop → Simplify → Review → Security Review → Clean → Docs**. Each phase runs as a separate subagent with its own context. Communication between phases happens via files (`.devlyn/done-criteria.md`, `.devlyn/BUILD-GATE.md`, `.devlyn/EVAL-FINDINGS.md`, `.devlyn/BROWSER-RESULTS.md`).
|
|
59
|
+
This runs the full pipeline automatically: **Build → Build Gate → Browser Validate → Evaluate → Fix Loop → Simplify → Review → Challenge → Security Review → Clean → Docs**. Each phase runs as a separate subagent with its own context. Communication between phases happens via files (`.devlyn/done-criteria.md`, `.devlyn/BUILD-GATE.md`, `.devlyn/EVAL-FINDINGS.md`, `.devlyn/BROWSER-RESULTS.md`, `.devlyn/CHALLENGE-FINDINGS.md`).
|
|
60
60
|
|
|
61
61
|
The **Build Gate** (Phase 1.4) runs real compilers, typecheckers, and linters — the same commands CI/Docker/production will run. It auto-detects project types (Next.js, Rust, Go, Solidity, Expo, Swift, etc.) and Dockerfiles. This is the primary defense against "tests pass locally, breaks in CI/Docker" class of bugs (type errors in un-tested files, cross-package drift, Dockerfile copy mismatches).
|
|
62
62
|
|
|
63
|
+
The **Challenge** phase (Phase 4.5) is a fresh skeptical review with no checklist — a subagent reads the entire diff cold with zero context from prior phases and asks "would I ship this to production with my name on it?" This catches the subtle issues that structured checklist-driven reviews miss: wrong-but-working approaches, unstated assumptions, non-idiomatic patterns, and integration gaps.
|
|
64
|
+
|
|
63
65
|
For web projects, the Browser Validate phase starts the dev server and tests the implemented feature in a real browser — clicking buttons, filling forms, verifying results. If the feature doesn't work, findings feed back into the fix loop.
|
|
64
66
|
|
|
65
67
|
Optional flags:
|
package/bin/devlyn.js
CHANGED
|
@@ -138,6 +138,7 @@ ${g} v${PKG.version} ${COLORS.dim}· ${k}🍩 by Nocodecat @ Donu
|
|
|
138
138
|
|
|
139
139
|
const OPTIONAL_ADDONS = [
|
|
140
140
|
// Local optional skills (copied to .claude/skills/)
|
|
141
|
+
{ name: 'asset-creator', desc: 'AI pixel art game asset pipeline — generate, chroma-key, catalog', type: 'local' },
|
|
141
142
|
{ name: 'cloudflare-nextjs-setup', desc: 'Cloudflare Workers + Next.js deployment with OpenNext', type: 'local' },
|
|
142
143
|
{ name: 'generate-skill', desc: 'Create well-structured Claude Code skills following Anthropic best practices', type: 'local' },
|
|
143
144
|
{ name: 'prompt-engineering', desc: 'Claude 4 prompt optimization using Anthropic best practices', type: 'local' },
|
|
@@ -45,7 +45,7 @@ This pipeline runs hands-free. The user launches it to walk away and come back t
|
|
|
45
45
|
```
|
|
46
46
|
Auto-resolve pipeline starting
|
|
47
47
|
Task: [extracted task description]
|
|
48
|
-
Phases: Build → Build Gate → [Browser] → Evaluate → [Fix loop if needed] → Simplify → [Review] → [Security] → [Clean] → [Docs]
|
|
48
|
+
Phases: Build → Build Gate → [Browser] → Evaluate → [Fix loop if needed] → Simplify → [Review] → Challenge → [Security] → [Clean] → [Docs]
|
|
49
49
|
Max evaluation rounds: [N]
|
|
50
50
|
Cross-model evaluation (Codex): [evaluate / review / both / disabled]
|
|
51
51
|
```
|
|
@@ -278,6 +278,55 @@ Clean up the team after completion.
|
|
|
278
278
|
1. If CRITICAL issues remain unfixed, log a warning in the final report
|
|
279
279
|
2. **Checkpoint**: Run `git add -A && git commit -m "chore(pipeline): review fixes complete"` if there are changes
|
|
280
280
|
|
|
281
|
+
## PHASE 4.5: CHALLENGE
|
|
282
|
+
|
|
283
|
+
Every prior phase used checklists, done-criteria, or structured categories. This phase is deliberately different — it's a fresh pair of eyes with no checklist, no prior context, and a skeptical mandate. The subagent hasn't seen the done-criteria, the eval findings, or the review results. It reads the raw diff cold and asks: "would I mass-ship this?"
|
|
284
|
+
|
|
285
|
+
This is what catches the things structured reviews miss — subtle logic that technically works but isn't the right approach, assumptions nobody questioned, patterns that are fine but not best-practice, and integration seams that look correct in isolation but feel wrong when you read the whole changeset.
|
|
286
|
+
|
|
287
|
+
Spawn a subagent using the Agent tool with `mode: "bypassPermissions"`.
|
|
288
|
+
|
|
289
|
+
Agent prompt — pass this to the Agent tool:
|
|
290
|
+
|
|
291
|
+
You are a senior engineer doing a final skeptical review before this code ships to production. You have NOT seen any prior reviews, test results, or design docs — read the code cold.
|
|
292
|
+
|
|
293
|
+
Run `git diff main` to see all changes. Read every changed file in full (not just the diff hunks — you need surrounding context).
|
|
294
|
+
|
|
295
|
+
Your job is NOT to check boxes. Your job is to find the things that would make a staff engineer say "hold on, let's talk about this before we ship." Think about:
|
|
296
|
+
|
|
297
|
+
- Would this approach survive a 10x traffic spike? A midnight oncall page? A junior dev maintaining it 6 months from now?
|
|
298
|
+
- Are there assumptions baked in that nobody stated out loud? Hardcoded limits, implicit ordering, missing edge cases in business logic?
|
|
299
|
+
- Is the error handling actually helpful, or does it just prevent crashes while leaving the user confused?
|
|
300
|
+
- Are there simpler, more idiomatic ways to do what this code does? Not "clever" alternatives — genuinely better approaches?
|
|
301
|
+
- Would you mass-confidence approve this PR, or would you leave comments?
|
|
302
|
+
|
|
303
|
+
Be brutally honest. Do NOT start with praise. Do NOT soften findings. Every finding must include `file:line` and a concrete fix — not "consider improving" but "change X to Y because Z."
|
|
304
|
+
|
|
305
|
+
Write `.devlyn/CHALLENGE-FINDINGS.md`:
|
|
306
|
+
|
|
307
|
+
```
|
|
308
|
+
# Challenge Findings
|
|
309
|
+
## Verdict: [PASS / NEEDS WORK]
|
|
310
|
+
## Findings
|
|
311
|
+
### [severity: CRITICAL / HIGH / MEDIUM]
|
|
312
|
+
- `file:line` — what's wrong — Fix: concrete change
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Verdict: PASS only if you would mass-confidently mass-ship this code with your name on it. If you found anything CRITICAL or HIGH, verdict is NEEDS WORK.
|
|
316
|
+
|
|
317
|
+
**After the agent completes**:
|
|
318
|
+
1. Read `.devlyn/CHALLENGE-FINDINGS.md`
|
|
319
|
+
2. Extract the verdict
|
|
320
|
+
3. Branch:
|
|
321
|
+
- `PASS` → continue to PHASE 5
|
|
322
|
+
- `NEEDS WORK` → spawn a fix subagent with `mode: "bypassPermissions"`:
|
|
323
|
+
|
|
324
|
+
Read `.devlyn/CHALLENGE-FINDINGS.md` — it contains findings from a fresh skeptical review. Fix every CRITICAL and HIGH finding at the root cause. For MEDIUM findings, fix if straightforward. After fixing, run the test suite to verify nothing broke.
|
|
325
|
+
|
|
326
|
+
After the fix agent completes:
|
|
327
|
+
1. **Checkpoint**: Run `git add -A && git commit -m "chore(pipeline): challenge fixes complete"`
|
|
328
|
+
2. Continue to PHASE 5 (do NOT re-run the challenge — one pass is sufficient to avoid infinite loops)
|
|
329
|
+
|
|
281
330
|
## PHASE 5: SECURITY REVIEW (conditional)
|
|
282
331
|
|
|
283
332
|
Determine whether to run this phase:
|
|
@@ -343,7 +392,7 @@ Synchronize documentation with recent code changes. Use `git log --oneline -20`
|
|
|
343
392
|
After all phases complete:
|
|
344
393
|
|
|
345
394
|
1. Clean up temporary files:
|
|
346
|
-
- Delete the `.devlyn/` directory entirely (contains done-criteria.md, BUILD-GATE.md, EVAL-FINDINGS.md, BROWSER-RESULTS.md, screenshots/, playwright temp files)
|
|
395
|
+
- Delete the `.devlyn/` directory entirely (contains done-criteria.md, BUILD-GATE.md, EVAL-FINDINGS.md, BROWSER-RESULTS.md, CHALLENGE-FINDINGS.md, screenshots/, playwright temp files)
|
|
347
396
|
- Kill any dev server process still running from browser validation
|
|
348
397
|
|
|
349
398
|
2. Run `git log --oneline -10` to show commits made during the pipeline
|
|
@@ -367,6 +416,7 @@ After all phases complete:
|
|
|
367
416
|
| Simplify | [completed / skipped] | [changes made] |
|
|
368
417
|
| Review (Claude team) | [completed / skipped] | [findings summary] |
|
|
369
418
|
| Review (Codex) | [completed / skipped] | [Codex-only findings, agreed findings] |
|
|
419
|
+
| Challenge | [PASS / NEEDS WORK] | [findings count, fixes applied] |
|
|
370
420
|
| Security review | [completed / skipped / auto-skipped] | [findings or "no security-sensitive changes"] |
|
|
371
421
|
| Clean | [completed / skipped] | [items cleaned] |
|
|
372
422
|
| Docs (update-docs) | [completed / skipped] | [docs updated] |
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Asset Catalog Schema
|
|
2
|
+
|
|
3
|
+
The manifest.json file catalogs all generated assets with metadata that supports both runtime rendering and future marketplace features.
|
|
4
|
+
|
|
5
|
+
## manifest.json structure
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"version": "1.0",
|
|
10
|
+
"style": "gather-town",
|
|
11
|
+
"generatedWith": "gemini-3-pro-image-preview",
|
|
12
|
+
"assets": {
|
|
13
|
+
"furniture/desk-basic": {
|
|
14
|
+
"file": "furniture/desk-basic.png",
|
|
15
|
+
"category": "furniture",
|
|
16
|
+
"width": 765,
|
|
17
|
+
"height": 746,
|
|
18
|
+
"anchorX": 0.5,
|
|
19
|
+
"anchorY": 1.0,
|
|
20
|
+
"tags": ["workspace", "desk", "monitor"],
|
|
21
|
+
"theme": "default",
|
|
22
|
+
"tier": "free",
|
|
23
|
+
"price": 0,
|
|
24
|
+
"animation": null
|
|
25
|
+
},
|
|
26
|
+
"characters/char-research-sitting": {
|
|
27
|
+
"file": "characters/char-research-sitting.png",
|
|
28
|
+
"category": "character",
|
|
29
|
+
"width": 342,
|
|
30
|
+
"height": 500,
|
|
31
|
+
"anchorX": 0.5,
|
|
32
|
+
"anchorY": 1.0,
|
|
33
|
+
"tags": ["research", "sitting", "typing"],
|
|
34
|
+
"theme": "default",
|
|
35
|
+
"tier": "free",
|
|
36
|
+
"price": 0,
|
|
37
|
+
"animation": {
|
|
38
|
+
"frameWidth": 342,
|
|
39
|
+
"frameCount": 1,
|
|
40
|
+
"fps": 0
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Field reference
|
|
48
|
+
|
|
49
|
+
| Field | Type | Required | Description |
|
|
50
|
+
|-------|------|----------|-------------|
|
|
51
|
+
| `file` | string | yes | Relative path from asset root |
|
|
52
|
+
| `category` | enum | yes | `tile`, `furniture`, `character`, `pet`, `decoration`, `background` |
|
|
53
|
+
| `width` | number | yes | Pixel width after trim |
|
|
54
|
+
| `height` | number | yes | Pixel height after trim |
|
|
55
|
+
| `anchorX` | number | yes | 0-1, horizontal anchor for positioning (0.5 = center) |
|
|
56
|
+
| `anchorY` | number | yes | 0-1, vertical anchor (1.0 = bottom for isometric depth sort) |
|
|
57
|
+
| `tags` | string[] | yes | Searchable keywords |
|
|
58
|
+
| `theme` | string | yes | Theme pack ID (`"default"`, `"cyberpunk"`, `"nature"`, etc.) |
|
|
59
|
+
| `tier` | enum | yes | `"free"`, `"premium"`, `"exclusive"` |
|
|
60
|
+
| `price` | number | yes | 0 for free, positive integer for paid (currency unit TBD) |
|
|
61
|
+
| `animation` | object\|null | no | Spritesheet info if animated |
|
|
62
|
+
|
|
63
|
+
## Animation field
|
|
64
|
+
|
|
65
|
+
For spritesheet assets (multiple frames in one image):
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"frameWidth": 64,
|
|
70
|
+
"frameCount": 4,
|
|
71
|
+
"fps": 8
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The renderer reads left-to-right, each frame `frameWidth` pixels wide, cycling at `fps` frames per second.
|
|
76
|
+
|
|
77
|
+
## Anchor conventions
|
|
78
|
+
|
|
79
|
+
| Asset type | anchorX | anchorY | Reason |
|
|
80
|
+
|------------|---------|---------|--------|
|
|
81
|
+
| Most assets | 0.5 | 1.0 | Bottom-center — standard for isometric depth sorting |
|
|
82
|
+
| Ceiling items (lights, plants) | 0.5 | 0.0 | Top-center — hangs from above |
|
|
83
|
+
| Wall items (clock, frame) | 0.5 | 0.5 | Center — placed on wall surface |
|
|
84
|
+
| Floor tiles | 0.5 | 0.5 | Center — aligned to grid |
|
|
85
|
+
|
|
86
|
+
## Theme packs
|
|
87
|
+
|
|
88
|
+
A theme is a set of assets that share a visual style. The `"default"` theme ships free with the product. Premium themes are sold as packs.
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
assets/
|
|
92
|
+
├── themes/
|
|
93
|
+
│ ├── default/ → symlinks or copies of base assets
|
|
94
|
+
│ ├── cyberpunk/ → neon-tinted variants
|
|
95
|
+
│ ├── nature/ → wood-and-leaf variants
|
|
96
|
+
│ └── cozy-night/ → warm lamp-lit variants
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
When a user switches themes, the renderer swaps asset paths: `furniture/desk-basic.png` → `themes/cyberpunk/desk-basic.png`. Assets not overridden by the theme fall back to `default`.
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: asset-creator
|
|
3
|
+
description: >
|
|
4
|
+
Generate consistent pixel art game assets using AI image generation + meta-prompting
|
|
5
|
+
for style lock + HSL chroma-key background removal. Produces transparent PNGs ready
|
|
6
|
+
for PixiJS, Phaser, or any 2D game engine. Use when building pixel art games, creating
|
|
7
|
+
game sprites, generating isometric assets, making character sprites, or when user says
|
|
8
|
+
"create asset", "generate sprite", "make game art", "pixel art asset", or "에셋 만들어".
|
|
9
|
+
allowed-tools: Read, Grep, Glob, Edit, Write, Bash
|
|
10
|
+
argument-hint: "[category] [name] \"[description]\" or batch [category] or list or init"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Asset Creator — AI-Powered Game Asset Pipeline
|
|
14
|
+
|
|
15
|
+
Generate production-ready pixel art game assets with consistent style, transparent backgrounds, and catalog metadata.
|
|
16
|
+
|
|
17
|
+
Reference files in this skill directory:
|
|
18
|
+
- `STYLE-GUIDE.md` — Art direction defaults, per-category templates, predefined asset batches
|
|
19
|
+
- `CATALOG-SCHEMA.md` — manifest.json structure and marketplace metadata
|
|
20
|
+
|
|
21
|
+
## Pipeline overview
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
0. STYLE LOCK Meta-prompt one reference asset → extract style DNA (once per project)
|
|
25
|
+
1. GENERATE Swap [SUBJECT] in meta prompt → Gemini 3.0 Pro Image
|
|
26
|
+
2. BG REMOVE HSL flood fill (Pillow) — magenta + near-white removal
|
|
27
|
+
3. NORMALIZE Auto-crop + category-based size normalization
|
|
28
|
+
4. CATALOG manifest.json auto-registration with marketplace metadata
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
This pipeline was validated through iterative testing. The meta-prompting approach extracts the "style DNA" from one good asset and replicates it precisely — more consistent than reference images (which the AI may reinterpret) and more token-efficient (264 chars vs 2MB image per call).
|
|
32
|
+
|
|
33
|
+
## Prerequisites
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Python 3 with Pillow — required for HSL background removal
|
|
37
|
+
python3 -c "from PIL import Image; print('OK')"
|
|
38
|
+
|
|
39
|
+
# API key — required for AI image generation
|
|
40
|
+
grep GEMINI_API_KEY .env
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
ImageMagick is NOT required — the pipeline uses pure Python (Pillow) for background removal.
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
/asset-creator init — Set up project + extract meta prompt from reference
|
|
49
|
+
/asset-creator [category] [name] "[description]" — Generate one asset
|
|
50
|
+
/asset-creator batch [category] — Generate all predefined assets in a category
|
|
51
|
+
/asset-creator list — Show current asset inventory
|
|
52
|
+
/asset-creator gallery — Generate visual review HTML
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Workflow
|
|
56
|
+
|
|
57
|
+
### Parse the command
|
|
58
|
+
|
|
59
|
+
Read `$ARGUMENTS` and determine the mode:
|
|
60
|
+
|
|
61
|
+
| Input | Mode | Action |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `init` | **Init** | Set up directories + extract meta prompt from reference asset |
|
|
64
|
+
| `[category] [name] "[desc]"` | **Single** | Generate one asset |
|
|
65
|
+
| `batch [category]` | **Batch** | Generate all predefined assets for category |
|
|
66
|
+
| `list` | **List** | Show asset inventory from manifest.json |
|
|
67
|
+
| `gallery` | **Gallery** | Generate review HTML |
|
|
68
|
+
| Empty | **Interactive** | Ask what to create |
|
|
69
|
+
|
|
70
|
+
Valid categories: `tile`, `furniture`, `character`, `pet`, `decoration`, `background`
|
|
71
|
+
|
|
72
|
+
### Step 0: Style Lock (init mode, or first run)
|
|
73
|
+
|
|
74
|
+
This is the foundation of style consistency. Run once per project.
|
|
75
|
+
|
|
76
|
+
**If no meta prompt exists** (`{asset-root}/style-prompt.txt` missing):
|
|
77
|
+
|
|
78
|
+
1. Check if the project has a reference asset. If not, generate one "hero asset" (a character or prominent furniture piece) using the default style from `STYLE-GUIDE.md`.
|
|
79
|
+
|
|
80
|
+
2. Send the reference asset to Gemini for meta-prompt extraction:
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
# Send image + extraction prompt to Gemini (text model, not image gen)
|
|
84
|
+
prompt = """Look at this pixel art game asset. Reverse-engineer the EXACT image
|
|
85
|
+
generation prompt that would recreate this STYLE. Replace the specific subject
|
|
86
|
+
with [SUBJECT]. Capture: pixel density, outline thickness, shading technique,
|
|
87
|
+
color palette warmth, perspective angle, proportions, and the solid magenta
|
|
88
|
+
#FF00FF background. Output ONLY the prompt text, max 3 sentences, be precise."""
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Use `gemini-2.5-flash` (text model) for extraction — it's fast and cheap. NOT the image model.
|
|
92
|
+
|
|
93
|
+
3. Save the extracted meta prompt to `{asset-root}/style-prompt.txt`.
|
|
94
|
+
|
|
95
|
+
4. **Validate**: Generate a test asset using the meta prompt. Show it to the user alongside the reference. If the style matches, the meta prompt is locked. If not, regenerate with adjusted extraction prompt.
|
|
96
|
+
|
|
97
|
+
**If meta prompt exists**: Read `{asset-root}/style-prompt.txt` and use it for all generation.
|
|
98
|
+
|
|
99
|
+
### Step 1: Locate project asset directory
|
|
100
|
+
|
|
101
|
+
Look for existing asset directories in order:
|
|
102
|
+
1. `dashboard/public/assets/office/` (Pyx Org)
|
|
103
|
+
2. `public/assets/game/` (generic game)
|
|
104
|
+
3. `assets/` (fallback)
|
|
105
|
+
|
|
106
|
+
If none exists, create:
|
|
107
|
+
```
|
|
108
|
+
{asset-root}/
|
|
109
|
+
├── tiles/
|
|
110
|
+
├── furniture/
|
|
111
|
+
├── characters/
|
|
112
|
+
├── pets/
|
|
113
|
+
├── decorations/
|
|
114
|
+
├── backgrounds/
|
|
115
|
+
├── raw/ # AI originals (magenta bg, never delete)
|
|
116
|
+
├── manifest.json
|
|
117
|
+
└── style-prompt.txt # Meta prompt (style DNA)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Step 2: Generate the asset
|
|
121
|
+
|
|
122
|
+
Read the meta prompt from `{asset-root}/style-prompt.txt`.
|
|
123
|
+
|
|
124
|
+
Construct the final prompt by replacing `[SUBJECT]`:
|
|
125
|
+
```
|
|
126
|
+
{meta_prompt with [SUBJECT] replaced by user's description}
|
|
127
|
+
|
|
128
|
+
Generate a pixel art IMAGE.
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Call Gemini 3.0 Pro Image API (`gemini-3-pro-image-preview`):
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
import json, base64, urllib.request
|
|
135
|
+
|
|
136
|
+
api_key = os.environ.get("GEMINI_API_KEY") or read_from_dotenv()
|
|
137
|
+
|
|
138
|
+
payload = {
|
|
139
|
+
"contents": [{"parts": [{"text": full_prompt}]}],
|
|
140
|
+
"generationConfig": {
|
|
141
|
+
"responseModalities": ["IMAGE", "TEXT"],
|
|
142
|
+
"temperature": 0.3
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-3-pro-image-preview:generateContent?key={api_key}"
|
|
147
|
+
req = urllib.request.Request(url, data=json.dumps(payload).encode(),
|
|
148
|
+
headers={"Content-Type": "application/json"}, method="POST")
|
|
149
|
+
|
|
150
|
+
with urllib.request.urlopen(req, timeout=120) as resp:
|
|
151
|
+
result = json.loads(resp.read().decode())
|
|
152
|
+
|
|
153
|
+
# Extract image from response
|
|
154
|
+
for part in result["candidates"][0]["content"]["parts"]:
|
|
155
|
+
if "inlineData" in part:
|
|
156
|
+
data = base64.b64decode(part["inlineData"]["data"])
|
|
157
|
+
with open(f"{asset_root}/raw/{name}.jpg", "wb") as f:
|
|
158
|
+
f.write(data)
|
|
159
|
+
break
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Step 3: Remove background (HSL flood fill)
|
|
163
|
+
|
|
164
|
+
This is the optimized approach — uses HSL color space instead of RGB for robust chroma-key removal that handles JPG compression artifacts.
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
from PIL import Image
|
|
168
|
+
import colorsys
|
|
169
|
+
from collections import deque
|
|
170
|
+
|
|
171
|
+
def remove_background(input_path, output_path):
|
|
172
|
+
img = Image.open(input_path).convert("RGBA")
|
|
173
|
+
pixels = img.load()
|
|
174
|
+
w, h = img.size
|
|
175
|
+
|
|
176
|
+
def should_remove(r, g, b):
|
|
177
|
+
rn, gn, bn = r/255.0, g/255.0, b/255.0
|
|
178
|
+
h_val, l_val, s_val = colorsys.rgb_to_hls(rn, gn, bn)
|
|
179
|
+
hue_deg = h_val * 360
|
|
180
|
+
# Magenta hue range (robust against JPG compression)
|
|
181
|
+
if 250 <= hue_deg <= 340 and s_val > 0.2:
|
|
182
|
+
return True
|
|
183
|
+
# Near-white (catches desaturated magenta from JPG artifacts)
|
|
184
|
+
if r > 230 and g > 230 and b > 230:
|
|
185
|
+
return True
|
|
186
|
+
# Very light + low saturation
|
|
187
|
+
if l_val > 0.9 and s_val < 0.15:
|
|
188
|
+
return True
|
|
189
|
+
return False
|
|
190
|
+
|
|
191
|
+
# Phase 1: Flood fill from all edges (only removes connected background)
|
|
192
|
+
visited = set()
|
|
193
|
+
queue = deque()
|
|
194
|
+
for x in range(w):
|
|
195
|
+
queue.append((x, 0)); queue.append((x, h-1))
|
|
196
|
+
for y in range(h):
|
|
197
|
+
queue.append((0, y)); queue.append((w-1, y))
|
|
198
|
+
|
|
199
|
+
while queue:
|
|
200
|
+
x, y = queue.popleft()
|
|
201
|
+
if (x, y) in visited or x < 0 or x >= w or y < 0 or y >= h:
|
|
202
|
+
continue
|
|
203
|
+
visited.add((x, y))
|
|
204
|
+
r, g, b, a = pixels[x, y]
|
|
205
|
+
if should_remove(r, g, b):
|
|
206
|
+
pixels[x, y] = (0, 0, 0, 0)
|
|
207
|
+
for dx, dy in [(-1,0),(1,0),(0,-1),(0,1),(-1,-1),(1,-1),(-1,1),(1,1)]:
|
|
208
|
+
nx, ny = x+dx, y+dy
|
|
209
|
+
if 0 <= nx < w and 0 <= ny < h and (nx, ny) not in visited:
|
|
210
|
+
queue.append((nx, ny))
|
|
211
|
+
|
|
212
|
+
# Phase 2: Edge cleanup (remove remaining pink fringe)
|
|
213
|
+
for y in range(1, h-1):
|
|
214
|
+
for x in range(1, w-1):
|
|
215
|
+
r, g, b, a = pixels[x, y]
|
|
216
|
+
if a == 0: continue
|
|
217
|
+
rn, gn, bn = r/255.0, g/255.0, b/255.0
|
|
218
|
+
h_val, l_val, s_val = colorsys.rgb_to_hls(rn, gn, bn)
|
|
219
|
+
hue_deg = h_val * 360
|
|
220
|
+
if (250 <= hue_deg <= 340 and s_val > 0.1) or (l_val > 0.85 and s_val < 0.2):
|
|
221
|
+
for dx, dy in [(-1,0),(1,0),(0,-1),(0,1)]:
|
|
222
|
+
if pixels[x+dx, y+dy][3] == 0:
|
|
223
|
+
pixels[x, y] = (0, 0, 0, 0)
|
|
224
|
+
break
|
|
225
|
+
|
|
226
|
+
# Auto-crop to content
|
|
227
|
+
bbox = img.getbbox()
|
|
228
|
+
if bbox:
|
|
229
|
+
img = img.crop(bbox)
|
|
230
|
+
img.save(output_path)
|
|
231
|
+
return img.size
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Why HSL instead of RGB:
|
|
235
|
+
- JPG compression shifts RGB values but barely affects Hue
|
|
236
|
+
- Magenta has a distinctive hue (~300°) that's stable across compression levels
|
|
237
|
+
- Saturation check prevents false positives on gray/white pixels
|
|
238
|
+
- Flood fill from edges ensures interior light pixels are preserved
|
|
239
|
+
|
|
240
|
+
### Step 4: Register in manifest
|
|
241
|
+
|
|
242
|
+
Read `{asset-root}/manifest.json`. Get dimensions from the processed PNG. Add entry:
|
|
243
|
+
|
|
244
|
+
```json
|
|
245
|
+
{
|
|
246
|
+
"{category}/{name}": {
|
|
247
|
+
"file": "{category}/{name}.png",
|
|
248
|
+
"category": "{category}",
|
|
249
|
+
"width": W,
|
|
250
|
+
"height": H,
|
|
251
|
+
"anchorX": 0.5,
|
|
252
|
+
"anchorY": 1.0,
|
|
253
|
+
"tags": ["inferred", "from", "description"],
|
|
254
|
+
"theme": "default",
|
|
255
|
+
"tier": "free",
|
|
256
|
+
"price": 0
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
See `CATALOG-SCHEMA.md` for full field reference and anchor conventions.
|
|
262
|
+
|
|
263
|
+
### Step 5: Show result
|
|
264
|
+
|
|
265
|
+
Display the generated PNG using the Read tool. Report:
|
|
266
|
+
- File path and size
|
|
267
|
+
- Dimensions (W × H)
|
|
268
|
+
- Category, tags, tier
|
|
269
|
+
- Manifest status
|
|
270
|
+
|
|
271
|
+
If unsatisfied, offer to regenerate with an adjusted subject description.
|
|
272
|
+
|
|
273
|
+
## Batch Mode
|
|
274
|
+
|
|
275
|
+
Read predefined asset lists from `STYLE-GUIDE.md`. Generate each sequentially with 1.5s delay (rate limiting). Show progress. Generate gallery at end.
|
|
276
|
+
|
|
277
|
+
## List Mode
|
|
278
|
+
|
|
279
|
+
Read manifest.json, group by category, display inventory table with dimensions, tier, and file size.
|
|
280
|
+
|
|
281
|
+
## Gallery Mode
|
|
282
|
+
|
|
283
|
+
Generate `{asset-root}/gallery.html` showing all assets on checkered transparency background, grouped by category. Suggest `python3 -m http.server 8888` to view.
|
|
284
|
+
|
|
285
|
+
## Adapting to other AI generators
|
|
286
|
+
|
|
287
|
+
The pipeline is model-agnostic. To swap generators:
|
|
288
|
+
1. Replace the API call in Step 2
|
|
289
|
+
2. Keep the meta prompt + magenta background instruction
|
|
290
|
+
3. HSL background removal works identically regardless of source
|
|
291
|
+
4. If your model outputs PNG with native transparency, skip Step 3
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Asset Creator — Style Guide
|
|
2
|
+
|
|
3
|
+
This document defines the art direction defaults and per-category templates. In production, the meta prompt (extracted from a reference asset) overrides the default style prefix.
|
|
4
|
+
|
|
5
|
+
## Style System: Meta Prompting
|
|
6
|
+
|
|
7
|
+
The best way to ensure style consistency is **meta prompting** — extracting the "style DNA" from one good reference asset, then using that exact prompt for all subsequent generations with only the `[SUBJECT]` swapped.
|
|
8
|
+
|
|
9
|
+
### How it works
|
|
10
|
+
|
|
11
|
+
1. Generate or find one "hero asset" that nails the visual style you want
|
|
12
|
+
2. Send it to Gemini text model to reverse-engineer the prompt
|
|
13
|
+
3. Save the extracted prompt as `style-prompt.txt` in the asset root
|
|
14
|
+
4. Every subsequent generation uses this prompt, replacing `[SUBJECT]` only
|
|
15
|
+
|
|
16
|
+
### Why meta prompting beats alternatives
|
|
17
|
+
|
|
18
|
+
| Approach | Consistency | Token cost | Reliability |
|
|
19
|
+
|---|---|---|---|
|
|
20
|
+
| Fixed text prefix (old approach) | Medium — AI interprets loosely | Low | Medium |
|
|
21
|
+
| Reference image every call | High — but AI may reinterpret | Very High (~2MB/call) | Medium |
|
|
22
|
+
| **Meta prompt (current)** | **High — exact reproduction** | **Low (264 chars)** | **High** |
|
|
23
|
+
| Fine-tuned model (Scenario.gg) | Highest | Setup cost | Highest |
|
|
24
|
+
|
|
25
|
+
### Default style prefix (fallback)
|
|
26
|
+
|
|
27
|
+
If no `style-prompt.txt` exists yet (first run / init), use this as the initial generation prompt:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
Gather Town / Habbo Hotel style pixel art game asset, isometric 3/4 view, bright cheerful warm colors, clean pixel outlines, highly detailed pixel art
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Then extract the meta prompt from the first successful generation.
|
|
34
|
+
|
|
35
|
+
## Background Instruction (always appended)
|
|
36
|
+
|
|
37
|
+
Regardless of meta prompt, ALWAYS append this to every generation prompt:
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
on a solid bright magenta #FF00FF background. The ENTIRE background must be exactly #FF00FF magenta, with NO gradients or shadows on the background. ONLY the single isolated object, nothing else in the scene.
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
This is required by the HSL chroma-key removal pipeline. Magenta (#FF00FF) is the game industry standard chroma-key color — it never appears in natural pixel art palettes.
|
|
44
|
+
|
|
45
|
+
## Perspective
|
|
46
|
+
|
|
47
|
+
- **Angle**: Isometric ¾ top-down view (~30° from horizontal)
|
|
48
|
+
- **Camera**: Looking from bottom-left toward top-right
|
|
49
|
+
- **Shadow direction**: Bottom-right, short and crisp
|
|
50
|
+
- **Light source**: Top-left (consistent with shadow direction)
|
|
51
|
+
|
|
52
|
+
## Proportions (relative to character height)
|
|
53
|
+
|
|
54
|
+
| Element | Relative size | Notes |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| Character (standing) | 1.0x | Reference unit |
|
|
57
|
+
| Character (sitting) | 0.7x | At desk |
|
|
58
|
+
| Desk | 0.5x height, 1.2x width | With monitor, wider than tall |
|
|
59
|
+
| Chair | 0.4x | Office swivel chair |
|
|
60
|
+
| Bookshelf | 1.2x | Taller than character |
|
|
61
|
+
| Door | 1.5x | Tallest common furniture |
|
|
62
|
+
| Floor plant | 0.8-1.0x | Varies by type |
|
|
63
|
+
| Desk plant | 0.2x | Small succulent/cactus |
|
|
64
|
+
| Wall decoration | 0.3-0.5x | Clock, picture frame |
|
|
65
|
+
| Bean bag | 0.4x height, 0.8x width | Wide and low |
|
|
66
|
+
| Kit (pet) | 0.5x | Smaller than character |
|
|
67
|
+
|
|
68
|
+
## Color palette guidelines
|
|
69
|
+
|
|
70
|
+
- **Warm base**: Browns, beiges, warm grays for furniture and floors
|
|
71
|
+
- **Department accents**: Orange (Research), Green (Engineering), Blue (Growth), Purple (Ops)
|
|
72
|
+
- **Skin tones**: Varied, warm undertones
|
|
73
|
+
- **Outlines**: Dark brown or black, 1-2px, clean and consistent
|
|
74
|
+
- **Highlights**: Top-left facing surfaces lighter
|
|
75
|
+
- **Shadows**: Bottom-right facing surfaces darker, 2-3 tone steps
|
|
76
|
+
|
|
77
|
+
## Per-category prompt templates
|
|
78
|
+
|
|
79
|
+
### tile
|
|
80
|
+
```
|
|
81
|
+
{STYLE_PREFIX}. A single isometric {description} tile, 64x64 pixel grid aligned, seamlessly tileable. {BG_SUFFIX}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### furniture
|
|
85
|
+
```
|
|
86
|
+
{STYLE_PREFIX}. A single {description}. Isometric perspective, detailed with visible texture and shading. {BG_SUFFIX}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### character
|
|
90
|
+
```
|
|
91
|
+
{STYLE_PREFIX}. A single cute office worker character, {description}. Gather Town style proportions: blocky square head wider than body, dot eyes with white highlight, small body. {BG_SUFFIX}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### pet
|
|
95
|
+
```
|
|
96
|
+
{STYLE_PREFIX}. A single small cute {description}. Expressive face, big eyes, stubby limbs. Game mascot style. {BG_SUFFIX}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### decoration
|
|
100
|
+
```
|
|
101
|
+
{STYLE_PREFIX}. A single {description}. Small decorative object, detailed pixel art. {BG_SUFFIX}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### background
|
|
105
|
+
```
|
|
106
|
+
{STYLE_PREFIX}. A wide panoramic {description}. Suitable as a background layer, horizontally tileable or wide format. {BG_SUFFIX}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Predefined asset batches
|
|
110
|
+
|
|
111
|
+
### tile
|
|
112
|
+
| name | description |
|
|
113
|
+
|------|-------------|
|
|
114
|
+
| floor-wood | wooden floor tile with warm wood grain texture |
|
|
115
|
+
| floor-carpet-orange | orange carpet tile for Research department |
|
|
116
|
+
| floor-carpet-green | green carpet tile for Engineering department |
|
|
117
|
+
| floor-carpet-blue | blue carpet tile for Growth department |
|
|
118
|
+
| floor-carpet-purple | purple carpet tile for Ops department |
|
|
119
|
+
| wall-back | cream/beige back wall section |
|
|
120
|
+
| wall-side | slightly darker side wall section |
|
|
121
|
+
|
|
122
|
+
### furniture
|
|
123
|
+
| name | description |
|
|
124
|
+
|------|-------------|
|
|
125
|
+
| desk-basic | wooden office desk with computer monitor, keyboard, mouse, and coffee mug |
|
|
126
|
+
| desk-standing | modern standing desk with large monitor and adjustable height |
|
|
127
|
+
| chair-office | dark office swivel chair with armrests |
|
|
128
|
+
| bookshelf | tall wooden bookshelf packed with colorful books, small plant on top |
|
|
129
|
+
| whiteboard | office whiteboard covered in colorful sticky notes, marker tray at bottom |
|
|
130
|
+
| beanbag-green | large green bean bag chair, puffy and round |
|
|
131
|
+
| beanbag-orange | large orange bean bag chair, puffy and round |
|
|
132
|
+
| beanbag-purple | large purple bean bag chair, puffy and round |
|
|
133
|
+
| coffee-station | espresso machine on wooden counter with white mug underneath |
|
|
134
|
+
| water-cooler | water cooler dispenser with blue water jug on top |
|
|
135
|
+
| meeting-table | round meeting table with 4 small chairs |
|
|
136
|
+
| sofa | comfortable modern office couch |
|
|
137
|
+
|
|
138
|
+
### character
|
|
139
|
+
| name | description |
|
|
140
|
+
|------|-------------|
|
|
141
|
+
| char-research-sitting | in orange shirt, brown hair, sitting and typing on laptop |
|
|
142
|
+
| char-research-standing | in orange shirt, brown hair, standing casually |
|
|
143
|
+
| char-engineering-sitting | in green shirt, black hair, sitting and typing on laptop |
|
|
144
|
+
| char-engineering-standing | in green shirt, black hair, standing casually |
|
|
145
|
+
| char-growth-sitting | in blue shirt, blonde hair, sitting and typing on laptop |
|
|
146
|
+
| char-growth-standing | in blue shirt, blonde hair, standing casually |
|
|
147
|
+
| char-ops-sitting | in purple shirt, red ponytail, sitting and typing on laptop |
|
|
148
|
+
| char-ops-standing | in purple shirt, red ponytail, standing casually |
|
|
149
|
+
|
|
150
|
+
### pet
|
|
151
|
+
| name | description |
|
|
152
|
+
|------|-------------|
|
|
153
|
+
| kit-idle | golden yellow cat creature mascot, happy expression, standing still |
|
|
154
|
+
| kit-bounce-1 | golden yellow cat creature mascot, jumping up with arms raised |
|
|
155
|
+
| kit-bounce-2 | golden yellow cat creature mascot, at peak of jump |
|
|
156
|
+
| kit-blink | golden yellow cat creature mascot, eyes closed, smiling |
|
|
157
|
+
|
|
158
|
+
### decoration
|
|
159
|
+
| name | description |
|
|
160
|
+
|------|-------------|
|
|
161
|
+
| plant-hanging | hanging potted plant with green vines draping from terracotta pot on chain |
|
|
162
|
+
| plant-floor-large | tall floor potted plant with large green leaves in brown pot |
|
|
163
|
+
| plant-desk | small succulent in tiny pot for desk |
|
|
164
|
+
| clock-wall | round wall clock with simple markers |
|
|
165
|
+
| picture-frame | framed picture/certificate for wall |
|
|
166
|
+
| pendant-light | hanging ceiling pendant light with warm glow |
|
|
167
|
+
| window-large | large floor-to-ceiling window panel |
|
|
168
|
+
| bulletin-board | cork board with pinned papers and photos |
|
|
169
|
+
|
|
170
|
+
### background
|
|
171
|
+
| name | description |
|
|
172
|
+
|------|-------------|
|
|
173
|
+
| skyline-day | city skyline with buildings, blue sky, white clouds, wide panorama |
|
|
174
|
+
| skyline-night | nighttime city skyline with lit windows, dark blue sky, wide panorama |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devlyn-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "AI development toolkit for Claude Code — ideate, auto-resolve, and ship with context engineering and agent orchestration",
|
|
5
5
|
"homepage": "https://github.com/fysoul17/devlyn-cli#readme",
|
|
6
6
|
"bin": {
|