{"record":{"id":"dea414d4314604e8","repo":"nexu-io/open-design","slug":"source-atlas-must-be-atlas-width-x-atlas-height","errorCode":null,"errorMessage":"source atlas must be {ATLAS_WIDTH}x{ATLAS_HEIGHT}; got {source.width}x{source.height}","messagePattern":"source atlas must be (.+?)x(.+?); got (.+?)x(.+?)","errorType":"exception","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"skills/hatch-pet/scripts/compose_atlas.py","lineNumber":74,"sourceCode":"        files.extend(p for p in root.glob(pattern) if p.suffix.lower() in IMAGE_SUFFIXES)\n    return sorted(set(files))\n\n\ndef paste_centered(atlas: Image.Image, source: Image.Image, row: int, column: int) -> None:\n    frame = source.convert(\"RGBA\")\n    if frame.size != (CELL_WIDTH, CELL_HEIGHT):\n        frame.thumbnail((CELL_WIDTH, CELL_HEIGHT), Image.Resampling.LANCZOS)\n    left = column * CELL_WIDTH + (CELL_WIDTH - frame.width) // 2\n    top = row * CELL_HEIGHT + (CELL_HEIGHT - frame.height) // 2\n    atlas.alpha_composite(frame, (left, top))\n\n\ndef compose_from_source_atlas(path: Path, resize_source: bool) -> Image.Image:\n    with Image.open(path) as opened:\n        source = opened.convert(\"RGBA\")\n    if source.size != (ATLAS_WIDTH, ATLAS_HEIGHT):\n        if not resize_source:\n            raise SystemExit(\n                f\"source atlas must be {ATLAS_WIDTH}x{ATLAS_HEIGHT}; got {source.width}x{source.height}\"\n            )\n        source_ratio = source.width / source.height\n        if abs(source_ratio - ATLAS_ASPECT_RATIO) > 0.02:\n            raise SystemExit(\n                \"refusing to resize source atlas because its aspect ratio does not match \"\n                f\"the Codex atlas ratio {ATLAS_ASPECT_RATIO:.3f}; got {source_ratio:.3f}. \"\n                \"Generate exact atlas dimensions or use --frames-root.\"\n            )\n        source = source.resize((ATLAS_WIDTH, ATLAS_HEIGHT), Image.Resampling.LANCZOS)\n\n    atlas = Image.new(\"RGBA\", (ATLAS_WIDTH, ATLAS_HEIGHT), (0, 0, 0, 0))\n    for _state, row, frame_count in ROW_SPECS:\n        for column in range(frame_count):\n            left = column * CELL_WIDTH\n            top = row * CELL_HEIGHT\n            cell = source.crop((left, top, left + CELL_WIDTH, top + CELL_HEIGHT))\n            atlas.alpha_composite(cell, (left, top))","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/skills/hatch-pet/scripts/compose_atlas.py#L56-L92","documentation":"Thrown by compose_from_source_atlas() in compose_atlas.py when a --source-atlas image's pixel dimensions do not equal ATLAS_WIDTH x ATLAS_HEIGHT (1536x1872 for the Codex pet grid) and --resize-source was not passed. Without consent to resize, the script refuses to silently distort a mismatched atlas.","triggerScenarios":"Run compose_atlas.py --source-atlas <png> without --resize-source where the image is not exactly 1536x1872 (8 columns x 192px by 9 rows x 208px).","commonSituations":"Using a lower-resolution or differently-cropped source atlas; exporting at the wrong canvas size from an image editor; feeding a single-frame sprite instead of a full atlas.","solutions":["Regenerate the source atlas at exactly 1536x1872 (8*192 by 9*208).","Pass --resize-source if (and only if) the source already has the correct aspect ratio so the resize is lossless in shape.","Switch to --frames-root to compose the atlas from individual frame files instead of a precomposed sheet."],"exampleFix":"# before\npython compose_atlas.py --source-atlas sheet.png --output out.png  # wrong size\n# after\npython compose_atlas.py --source-atlas sheet.png --output out.png --resize-source  # only if aspect matches","handlingStrategy":"validation","validationCode":"from PIL import Image\nATLAS_W, ATLAS_H = 1536, 1872\ndef assert_atlas_size(path):\n    with Image.open(path) as im:\n        if im.size != (ATLAS_W, ATLAS_H):\n            raise SystemExit(f\"atlas is {im.width}x{im.height}; need {ATLAS_W}x{ATLAS_H} or pass --resize-source\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Export atlases at exactly 1536x1872 (8*192 by 9*208).","Prefer --frames-root when you cannot guarantee exact atlas dimensions."],"tags":["image-processing","hatch-pet","atlas"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}