Agent Skills › pixtuoid/pixtuoid › beautify-decoration

beautify-decoration

GitHub

用于在pixtuoid中迭代设计和美化装饰物(如家具、灯具)的视觉工作流。涵盖精灵图编辑、快照生成与裁剪、视觉自检及构建陷阱规避,确保设计变更正确反映到最终产品中。

.claude/skills/beautify-decoration/SKILL.md pixtuoid/pixtuoid

Trigger Scenarios

用户要求美化现有装饰物 添加新的装饰道具 调整装饰物大小或清晰度 修改后未看到视觉变化

Install

npx skills add pixtuoid/pixtuoid --skill beautify-decoration -g -y
More Options

Non-standard path

npx skills add https://github.com/pixtuoid/pixtuoid/tree/main/.claude/skills/beautify-decoration -g -y

Use without installing

npx skills use pixtuoid/pixtuoid@beautify-decoration

指定 Agent (Claude Code)

npx skills add pixtuoid/pixtuoid --skill beautify-decoration -a claude-code -g -y

安装 repo 全部 skill

npx skills add pixtuoid/pixtuoid --all -g -y

预览 repo 内 skill

npx skills add pixtuoid/pixtuoid --list

SKILL.md

Frontmatter
{
    "name": "beautify-decoration",
    "version": "1.0.0",
    "metadata": {
        "scope": "pixtuoid repo only"
    },
    "description": "Iterate on the visual identity of a top-down pixel-art decoration (sprite + layout integration) in pixtuoid. Use when redesigning an existing decoration (pantry, lounge, meeting room, cubicle decor) or adding a new one. Captures the rebuild trap, the visual-verification loop, resolution constraints, sprite-format pitfalls, and the layout-integration checklist."
}

beautify-decoration

A repo-specific iteration loop for visually redesigning a decoration in pixtuoid. Follow this when the user says "beautify X" or "make Y look better" — it short-circuits several rebuild traps and visual-design dead ends that aren't obvious from the codebase alone.

When to use

  • Redesigning an existing decoration sprite (pantry, lounge, meeting, cubicle decor)
  • Adding a new fixture (pendant lamp, water cooler, chalkboard, etc.)
  • User says "items look too small / don't read like X / blend together"
  • After making sprite edits and "I don't see any change"

The visual-iteration loop

1. Edit sprite OR layout
   ↓
2. cargo build --release --example snapshot
   ↓
3. ./target/release/examples/snapshot /tmp/snap.png
   ↓
4. .venv/bin/python3 scripts/crop-snapshot.py /tmp/snap.png --scale 3 -q <quadrant>
   (its QUADRANTS table is the zone map — or skip the quadrant guessing: snapshot --crop-furniture pantry|couch|vending|
   printer|meeting|sofa|chair|island|snackshelf|desk OR --crop-agent <label> renders a `CROP_WINDOW`
   already centered on the target — no Python step)
   ↓
5. Read the cropped PNG → self-critique → back to step 1
   ↓
6. When the checklist below passes, send the crop to the user with a short caption
   ↓
7. cargo build --release --workspace    ← rebuild the LIVE binary too
   ↓
8. Commit with iteration history (which designs were tried, why rejected)

The user is the final judge of "does it look like a fridge / coffee machine / etc." — send only once your own critique against the checklist below passes.

Step 7 is mandatory. cargo build --release --example snapshot does NOT rebuild the main binary. Users testing with ./target/release/pixtuoid run won't see sprite changes until the workspace is rebuilt. Forgetting this step is how "I changed the sprite but nothing happened in the live TUI" bugs get filed.

Step 8 is mandatory. Commit messages for sprite changes must include the iteration count and a one-line rationale for each rejected attempt. Future editors need to know which alternatives were explored — otherwise they'll re-try the same dead-end designs.

Sharp edges

1. The rebuild trap

  • cargo build --release --workspace does not rebuild examples. Use cargo build --release --example snapshot when iterating on examples/snapshot.
  • crates/pixtuoid-scene/build.rs embeds every .sprite in sprites/default/ at compile time, and a sprite edit, add or remove rebuilds it.
  • If unsure, verify with: strings target/release/examples/snapshot | grep "<some unique string from your sprite>".

2. Snapshot size gates the large sprite variants

examples/snapshot defaults to its COLS×ROWS cells. Several layouts (pantry, corridor appliances) have conditional variants based on room dimensions. Corridor items (vending machine, printer) only appear when the cubicle aisle clears VENDING_MIN_AISLE_* / PRINTER_MIN_AISLE_* (layout/compute.rs). The default size clears every gate — don't shrink it while iterating.

Pantry-specific threshold: the large pantry counter needs the left column to fit PANTRY_COUNTER_LARGE_W plus margin (the pantry_counter_size pick in layout/compute.rs); below that, pantry_small.sprite is used (layout::pantry_counter_anim).

3. Resolution budget

  • A terminal cell shows one pixel column and two pixel rows (half-block ▀): a 1x sprite is as many cells wide as it has pixels, and half as many tall.
  • Subzones smaller than ~5 display cells wide blur into pixel noise — users can't read them.
  • Sub-pixel detail (a 1-cell handle, a 1-cell stripe) is invisible. Iterate on silhouette + color identity, not pixel polish.
  • Budget subzones against the sprite's width in cells: the pantry's 32-wide counter read at three zones (8/10/10), not six. Drop items; don't shrink them.

4. Identity mistakes that look identical to each other

Symptoms of weak identity:

  • Transparent body (.): the wall color shows through, weakening the silhouette. Use a solid fill color for appliances.
  • All-dark appliances: a row of M-bodied items reads as "row of dark boxes." Give each appliance a distinct base color (e.g., w white fridge against M dark coffee machine + M dark microwave with q glass).
  • Symmetric H-frame on a white box → reads as washing machine, not fridge. Use asymmetric handles (single-side handle, or center-French-door pair).
  • Cyan + blue dispenser dots next to each other → reads as cyan-cyan because b is dark and gets dim. Space them out or use c + r.

5. Sprite-format pitfalls

  • Every row in a .sprite file must have exactly the same number of space-separated cells. Off-by-one is the most common bug.
  • Verify with: awk '/^@/{next}/^#/{next}NF{print NR": "NF}' crates/pixtuoid-scene/sprites/default/foo.sprite — all NF values must match.
  • Or visualize packed rows: awk '/^@/{next}/^#/{next}NF{for(i=1;i<=NF;i++)printf "%s",$i;print " ["NF"]"}' foo.sprite.
  • Reuse existing palette keys when possible; new keys go in crates/pixtuoid-scene/sprites/default/pack.toml [palette] section.
  • A sprite whose header carries the provenance line (every foo@Nx.sprite, and the 1x pieces the generator owns) is drawn by scripts/gen-art.py: redraw it there and run just gen-art — just gen-art-check fails on a hand edit.

6. Layout integration checklist

When a sprite changes size:

  1. Update the decoration's footprint in the furniture_def(Furniture) geometry table in crates/pixtuoid-scene/src/layout/decor.rs — the single source of truth for footprint + visual, read by mask::build_walkable_mask (waypoints via approach::obstacle_footprint), approach.rs, and the z-sort. Do NOT hardcode a (w, h) at the mask stamp site; it would diverge from the table that stand_point/approach and render-centering read.
  2. A non-waypoint obstacle (plant, wall decor, pod decor) is likewise stamped from its FurnitureDef row via furniture_def(kind.furniture()).footprint, not an inline literal — so the same table edit covers it.
  3. Run just test -p pixtuoid-scene — the walkable_is_one_connected_region test (lives in layout/placement_sweep.rs) catches mask/sprite mismatches by sweeping buffer sizes × seeds and asserting every walkable pixel is reachable from the door threshold; narrow_band_connectivity_boundary_scan re-runs the same assert at the step-1 widths that discrete grid skips.
  4. If the connectivity test fails at a small buffer (SWEEP_SIZES starts at the minimum layout size), the sprite is too big for that pantry. Add a _small variant + conditional pick (see PantryRoom::counter_size / SceneLayout::pantry_counter_size() for the pattern).
  5. Register both foo.sprite and foo_small.sprite in crates/pixtuoid-scene/sprites/default/pack.toml if you added a variant (an unregistered sprite fails every_bundled_sprite_is_a_frame_the_pack_loads).
  6. If the piece has a density variant (foo@Nx.sprite, drawn by scripts/gen-art.py), resize it there too, with its 1x where the generator owns that; a variant not exactly N× its base reds the_bundled_pack_passes_its_own_validation.

Self-critique checklist — before sending a render to the user

Run this checklist before each render you send in a beautify loop, and state each row's result (✅/⚠️/❌) in the message. Fix any ❌ first; call out any ⚠️ you ship so the user sees the trade-off.

Check What it means
Stranger-ID If a stranger saw this with no context, would they identify each new element as the intended thing? Name each element explicitly.
Visually differs Diff is noticeable, not a sub-pixel tweak. If hash-identical to last attempt, you didn't actually rebuild.
Subzone width Each new sub-element ≥ 5 display cells wide (§3).
Color distinctness New elements use colors distinct from immediate neighbours.
Alive The asset ships what makes it alive — idle frames (frame_ms), a state-driven change, a response to weather or window light, or variety across agents — named in the PR body.
just test The connectivity tests pass (§6 step 3).
--debug-walkable Rendered the overlay and visually checked no narrow / isolated walkable pockets near the new element.

Workflow when adding a NEW decoration

  1. Sketch the design as a list of cells per row (count exactly).
  2. Pick a palette: reuse pack.toml keys; only add new ones if necessary.
  3. Write the .sprite file; verify row widths with the awk command above.
  4. Add a Piece::Foo variant (core sprite::format) and the [animations.foo] block to pack.toml (build.rs embeds the file itself): a pack without it, or a key no piece names, does not load.
  5. Decide where it lives in the layout — add a Point placement in SceneLayout::compute.
  6. Give it a Furniture variant + furniture_def row (§6 step 1). A new plant, wall-decor or pod-decor kind is then stamped by its collection's loop in mask::build_walkable_mask; a one-off piece also needs a MaskObstacles field and its own stamp_ground from that row, like fish_tank (or add a waypoint kind if it's interactive).
  7. Add a DrawableKind::Foo variant + paint_drawable arm if z-sorting matters.
  8. Run the connectivity tests (§6 step 3).
  9. Snapshot + iterate.

Version History

  • d03b337 Current 2026-10-19 00:32
  • b5af634 2026-08-01 07:42
  • 6fce833 2026-07-23 06:31
  • 0620ccd 2026-07-05 20:27

Same Skill Collection

.claude/skills/add-source/SKILL.md
.claude/skills/add-theme/SKILL.md
.claude/skills/local-review/SKILL.md
.claude/skills/procedural-lofi/SKILL.md
.claude/skills/two-lens-review/SKILL.md

Metadata

Files
0
Version
d03b337
Hash
c79bf5bc
Indexed
2026-07-05 20:27

ホーム - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-10-24 19:55
浙ICP备14020137号-1