Lesson 236: Clip Studio Sprite Sheet Hash Receipt on BUILD_RECEIPT (2026)
Direct answer: Before summer playtest builds promote, file sprite_sheet_hash_receipt_v1.json proving sha256 on PNG sheet + JSON manifest matches a re-export with pinned CSP settings, and that Godot/Unity import sees the same atlas hash. Distinct from Lesson 204 Fab ORM metallic (material channels) and Lesson 230 Fab 8K throttle (texture path size)—this lesson is 2D animation reproducibility on BUILD_RECEIPT.

Why this matters now (June 2027 playtest animation drift)
June 2027 teams close Q2 spring fest shipping and open a summer playtest wave. Artists merge CSP timeline tweaks the night before branch promotion—tag names unchanged, frame order changed, new PNG hash, but old manifest still in git. Playtesters report attack frame 3 plays idle; CI skipped art because only .clip changed. The Clip Studio hash preflight is the ninety-second export gate—this lesson wires sprite_sheet_hash_receipt on BUILD_RECEIPT with gate verify_sprite_sheet_hash_v1.
Beginner path (export → hash → re-export → engine spot)
| Step | Action | Success check |
|---|---|---|
| 1 | Pin csp_export_preset_v1.json |
K1 pass |
| 2 | Export sheet + manifest from CSP | Files in art/characters/ |
| 3 | sha256sum sheet + manifest |
Logged in receipt |
| 4 | Re-export without edits | Identical hash (K4) |
| 5 | Godot or Unity import spot | K5 frame tag matches |
| 6 | File sprite_sheet_hash_receipt_v1.json |
sheet_hash_ok: true |
| 7 | BUILD_RECEIPT column | sprite_sheet_hash GREEN |
Time: ~62 minutes first hero sheet; ~15 minutes when preset and manifest schema are pinned.
Developer path (gates K1–K6)
| Gate | Check | Fail when |
|---|---|---|
| K1 | CSP export preset pinned | Ad-hoc cell size per export |
| K2 | Timeline tag ↔ manifest audit | Orphan tags or duplicate rows |
| K3 | sha256 bundle computed |
Sheet without manifest |
| K4 | Re-export reproducibility | Second hash differs |
| K5 | Engine import hash / region spot | Wrong clip length in player |
| K6 | Receipt + BUILD_RECEIPT | Promote with stale manifest |
K1 — Export preset (versioned)
Archive tools/csp/csp_export_preset_v1.json:
{
"format": "png",
"transparent_background": true,
"cell_width": 128,
"cell_height": 128,
"padding_px": 2,
"interpolation": "nearest_neighbor",
"timeline_visibility_respected": true
}
Fail when cell_width changes without manifest cell_width bump.
K2 — Manifest frame audit
Example manifest fragment:
{
"character_id": "hero_combat",
"cell_width": 128,
"cell_height": 128,
"fps": 12,
"actions": [
{ "tag": "idle", "row": 0, "frames": [0, 1, 2, 3] },
{ "tag": "attack_light", "row": 1, "frames": [0, 1, 2, 3, 4] }
]
}
| Check | Pass |
|---|---|
Every CSP timeline tag in actions[].tag |
Yes |
No duplicate row indices |
Yes |
frames contiguous 0..n−1 per tag |
Yes |
Cross-check timeline handoff preflight and Aseprite bridge when frames pass through another tool.
K3–K4 — sha256 bundle + re-export
sha256sum art/characters/hero/hero_combat_128_sheet.png \
art/characters/hero/hero_combat_manifest.json \
| tee release-evidence/art/hero_sheet_hash.txt
Re-export from CSP without layer visibility changes → identical lines.
Fail when hash drifts—hunt non-determinism (dither, effects, wrong visibility).
K5 — Engine spot check
| Engine | Spot check |
|---|---|
| Godot 4.x | .import uid + first frame region for attack_light |
| Unity | Sprite Library / Animator clip length = fps × frame count |
Log engine_spot_tag and engine_frame_count_ok in receipt.
sprite_sheet_hash_receipt_v1.json
{
"schema": "sprite_sheet_hash_receipt_v1",
"build_label": "summer-playtest-2027-rc1",
"character_id": "hero_combat",
"sheet_path": "art/characters/hero/hero_combat_128_sheet.png",
"manifest_path": "art/characters/hero/hero_combat_manifest.json",
"csp_export_preset": "tools/csp/csp_export_preset_v1.json",
"sha256_bundle": "sha256:REPLACE_AFTER_COMPUTE",
"reexport_match": true,
"engine_spot": {
"engine": "godot_4.5",
"spot_tag": "attack_light",
"frame_count_ok": true
},
"gates": {
"K1_export_preset": "pass",
"K2_manifest_audit": "pass",
"K3_sha256_bundle": "pass",
"K4_reexport_match": "pass",
"K5_engine_spot": "pass",
"K6_build_receipt": "pass"
},
"sheet_hash_ok": true,
"playtest_promotion_allowed": true
}
Pin under release-evidence/art/SPRITE_SHEET_HASH_RECEIPT.json.
BUILD_RECEIPT row (K6)
| Column | Pass when |
|---|---|
sprite_sheet_hash |
sheet_hash_ok: true + receipt path |
fab_pipeline |
Lesson 204 ORM independent |
fab_8k_throttle |
Lesson 230 3D path independent |
ALTER TABLE release_publish_gate ADD COLUMN IF NOT EXISTS
sprite_sheet_hash_blocked BOOLEAN NOT NULL DEFAULT false;
Pair with Thursday BUILD_RECEIPT review—one Animation row, not a Slack screenshot thread.
Relationship to guide vs lesson 204
| Artifact | Role |
|---|---|
| CSP hash preflight | K1–K6 editor checklist |
| Timeline handoff | Manifest schema + tag naming |
| Lesson 204 | 3D ORM metallic—different receipt schema |
| This lesson | BUILD_RECEIPT sprite_sheet_hash milestone |
Proof table (characters)
| Character | Sheet | Manifest | Re-export | Engine spot | Notes |
|---|---|---|---|---|---|
| hero_combat | Playtest combat set | ||||
| hero_idle | optional | Menu-only if separate sheet |
Key takeaways
- Hash sheet + manifest together—PNG alone is insufficient.
- Re-export match (K4) catches non-deterministic CSP exports.
- Lesson 204 — 3D materials; 236 — 2D animation reproducibility.
- Lesson 230 — 8K paths; not sprite frame order.
- Q3 capstone 244 will wire 236 with 237–243.
- Q2 capstone 235 closed store/LCP—236 opens playtest art ops.
- Pin
csp_export_preset_v1.jsonin git—artists bump version when cell size changes. - Wednesday smoke — one combat animation row in photo proof.
Common mistakes
- Committing
.cliponly—CI never sees PNG hash change. - Hashing sheet but not manifest—frame order drift undetected.
- Passing K4 on dev machine with different CSP version than CI.
- Conflating ORM receipts with sprite hash JSON.
- Skipping engine spot (K5) because “atlas looked fine in CSP.”
Troubleshooting
| Symptom | Lane |
|---|---|
| Re-export hash differs | Visibility layers, effects, dither—K4 |
| Engine wrong frame, hash OK | K2 manifest row vs CSP tags |
| Attack plays idle | Frame index drift—re-run K2 + K5 |
| Godot import stale | .import cache—reimport after hash bump |
| Aseprite in pipeline | Aseprite bridge re-number pass |
Mini exercise (60 minutes)
- Change one timeline frame order—confirm K4 fails.
- Re-export with pinned preset; pass K1–K4.
- Spot-check
attack_lightin Godot or Unity (K5). - File receipt; set BUILD_RECEIPT
sprite_sheet_hashGREEN. - Link receipt path in Thursday review row.
Continuity — Q3 2027 summer playtest wave (236–244)
| Lesson | Receipt focus |
|---|---|
| 236 (this) | Clip Studio sprite sheet hash |
| 237 | Wwise DSP init boot path |
| 238–244 | Save isolation → Q3 capstone |
Previous: Lesson 235 — Q2 spring fest shipping capstone — Q2 arc 230–235 closed.
Next: Lesson 237 — Wwise DSP init boot path receipt — published.
FAQ
Same as CSP hash preflight guide?
Guide = K1–K6 export checklist; 236 = BUILD_RECEIPT sprite_sheet_hash column.
Same as Lesson 204 ORM receipt?
No—204 is Fab metallic glTF; 236 is 2D sheet+manifest sha256.
Required for every character?
One receipt row per sheet + manifest pair per build_label; batch heroes in proof table.
Does Fab 8K throttle replace this?
No—Lesson 230 is 3D texture URI audit.
Playtest animation bugs often start at export—pin preset, hash bundle, re-export match, engine spot, then promote on BUILD_RECEIPT.