prototype-blob-geom: migrate bake pipeline to node atlas-baker v0.2.0

Python atlas_pack.py was a stop-gap substitute while davoryn was
down (preventing pull of the real node baker). With sporel-tool-
atlas-baker v0.2.0 shipping padding + blob-14 schema validation +
collision sidecar pass-through + alpha-analysis opaque flag, the
Python substitute is no longer needed.

Changes:

  - scripts/atlas_pack.py removed
  - scripts/bake_testbench.py: drop atlas_pack import + pack() call;
    now produces source PNGs only. Node baker does the packing.
  - scripts/bake_singles.py: same simplification, plus copies the
    shared blob_rectilinear collision.json into each single-material
    source dir (so atlas-baker E2 validation finds the sidecar).
  - scripts/bake.sh: rewritten to call the node baker for all 8
    atlases. Single-material variants (4 base styles + 3 tinted
    singles) bake with `--schema blob-14` for E1+E2 validation.
    Mixed-material blob_testbench bakes without --schema (42 tiles
    don't match the canonical 14-slot pattern).
  - 3 collision.json copies committed under assets/_sources/blob_
    rect_{stone,grass,wood}/ — same content as the shared
    blob_rectilinear one (since these single-material atlases share
    the same blob geometry).

Single codepath for atlas production now: node baker only. No more
two-tool drift. Future-Python-changes to source generation auto-
flow through to baked atlases via bake.sh.

End-to-end verification: bake.sh produces 8 atlases cleanly; all
single-material bakes pass --schema blob-14 + collision validation;
opaque flag set on slot_13_solid (alpha-all-255), absent on the
other slots (transparent regions). SPOREL_CI=1 vagrant-skeleton
rc=0 with both blob_testbench (legacy multi-material) and
blob_rect_stone (vertex-painted single-material) loading correctly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
calic
2026-05-28 22:55:05 +02:00
parent 247cdf0575
commit 1a99e22e1f
7 changed files with 871 additions and 204 deletions

View File

@@ -0,0 +1,270 @@
{
"schema": "blob-14",
"tile_size_px": 64,
"sub_cell_px": 16,
"shape_kind": "rect_list",
"_note": "Collision matches the rectilinear visual exactly. For diagonal_cut/organic/concave styles, the visible boundary deviates by up to 5 px at convex external corners \u2014 acceptable for typical gameplay collision. Modders needing pixel-perfect physics ship per-style polygon overrides.",
"slots": [
{
"slot": 0,
"name": "isolated",
"bitmask": "0b00000000",
"rects": [
[
16,
16,
32,
32
]
]
},
{
"slot": 1,
"name": "end",
"bitmask": "0b00000001",
"rects": [
[
16,
0,
32,
48
]
]
},
{
"slot": 2,
"name": "corner_open",
"bitmask": "0b00000101",
"rects": [
[
16,
0,
32,
16
],
[
16,
16,
48,
32
]
]
},
{
"slot": 3,
"name": "corner_full",
"bitmask": "0b00000111",
"rects": [
[
16,
0,
48,
48
]
]
},
{
"slot": 4,
"name": "straight",
"bitmask": "0b00010001",
"rects": [
[
16,
0,
32,
64
]
]
},
{
"slot": 5,
"name": "tee_open",
"bitmask": "0b00010101",
"rects": [
[
16,
0,
32,
16
],
[
16,
16,
48,
32
],
[
16,
48,
32,
16
]
]
},
{
"slot": 6,
"name": "tee_half",
"bitmask": "0b00010111",
"rects": [
[
16,
0,
48,
48
],
[
16,
48,
32,
16
]
]
},
{
"slot": 7,
"name": "tee_full",
"bitmask": "0b00011111",
"rects": [
[
16,
0,
48,
64
]
]
},
{
"slot": 8,
"name": "cross_open",
"bitmask": "0b01010101",
"rects": [
[
16,
0,
32,
16
],
[
0,
16,
64,
32
],
[
16,
48,
32,
16
]
]
},
{
"slot": 9,
"name": "cross_q1",
"bitmask": "0b01010111",
"rects": [
[
16,
0,
48,
16
],
[
0,
16,
64,
32
],
[
16,
48,
32,
16
]
]
},
{
"slot": 10,
"name": "cross_q2adj",
"bitmask": "0b01011111",
"rects": [
[
16,
0,
48,
16
],
[
0,
16,
64,
32
],
[
16,
48,
48,
16
]
]
},
{
"slot": 11,
"name": "cross_q2opp",
"bitmask": "0b01110111",
"rects": [
[
16,
0,
48,
16
],
[
0,
16,
64,
32
],
[
0,
48,
48,
16
]
]
},
{
"slot": 12,
"name": "cross_q3",
"bitmask": "0b01111111",
"rects": [
[
16,
0,
48,
16
],
[
0,
16,
64,
48
]
]
},
{
"slot": 13,
"name": "solid",
"bitmask": "0b11111111",
"rects": [
[
0,
0,
64,
64
]
]
}
],
"style": "rectilinear"
}

View File

@@ -0,0 +1,270 @@
{
"schema": "blob-14",
"tile_size_px": 64,
"sub_cell_px": 16,
"shape_kind": "rect_list",
"_note": "Collision matches the rectilinear visual exactly. For diagonal_cut/organic/concave styles, the visible boundary deviates by up to 5 px at convex external corners \u2014 acceptable for typical gameplay collision. Modders needing pixel-perfect physics ship per-style polygon overrides.",
"slots": [
{
"slot": 0,
"name": "isolated",
"bitmask": "0b00000000",
"rects": [
[
16,
16,
32,
32
]
]
},
{
"slot": 1,
"name": "end",
"bitmask": "0b00000001",
"rects": [
[
16,
0,
32,
48
]
]
},
{
"slot": 2,
"name": "corner_open",
"bitmask": "0b00000101",
"rects": [
[
16,
0,
32,
16
],
[
16,
16,
48,
32
]
]
},
{
"slot": 3,
"name": "corner_full",
"bitmask": "0b00000111",
"rects": [
[
16,
0,
48,
48
]
]
},
{
"slot": 4,
"name": "straight",
"bitmask": "0b00010001",
"rects": [
[
16,
0,
32,
64
]
]
},
{
"slot": 5,
"name": "tee_open",
"bitmask": "0b00010101",
"rects": [
[
16,
0,
32,
16
],
[
16,
16,
48,
32
],
[
16,
48,
32,
16
]
]
},
{
"slot": 6,
"name": "tee_half",
"bitmask": "0b00010111",
"rects": [
[
16,
0,
48,
48
],
[
16,
48,
32,
16
]
]
},
{
"slot": 7,
"name": "tee_full",
"bitmask": "0b00011111",
"rects": [
[
16,
0,
48,
64
]
]
},
{
"slot": 8,
"name": "cross_open",
"bitmask": "0b01010101",
"rects": [
[
16,
0,
32,
16
],
[
0,
16,
64,
32
],
[
16,
48,
32,
16
]
]
},
{
"slot": 9,
"name": "cross_q1",
"bitmask": "0b01010111",
"rects": [
[
16,
0,
48,
16
],
[
0,
16,
64,
32
],
[
16,
48,
32,
16
]
]
},
{
"slot": 10,
"name": "cross_q2adj",
"bitmask": "0b01011111",
"rects": [
[
16,
0,
48,
16
],
[
0,
16,
64,
32
],
[
16,
48,
48,
16
]
]
},
{
"slot": 11,
"name": "cross_q2opp",
"bitmask": "0b01110111",
"rects": [
[
16,
0,
48,
16
],
[
0,
16,
64,
32
],
[
0,
48,
48,
16
]
]
},
{
"slot": 12,
"name": "cross_q3",
"bitmask": "0b01111111",
"rects": [
[
16,
0,
48,
16
],
[
0,
16,
64,
48
]
]
},
{
"slot": 13,
"name": "solid",
"bitmask": "0b11111111",
"rects": [
[
0,
0,
64,
64
]
]
}
],
"style": "rectilinear"
}

View File

@@ -0,0 +1,270 @@
{
"schema": "blob-14",
"tile_size_px": 64,
"sub_cell_px": 16,
"shape_kind": "rect_list",
"_note": "Collision matches the rectilinear visual exactly. For diagonal_cut/organic/concave styles, the visible boundary deviates by up to 5 px at convex external corners \u2014 acceptable for typical gameplay collision. Modders needing pixel-perfect physics ship per-style polygon overrides.",
"slots": [
{
"slot": 0,
"name": "isolated",
"bitmask": "0b00000000",
"rects": [
[
16,
16,
32,
32
]
]
},
{
"slot": 1,
"name": "end",
"bitmask": "0b00000001",
"rects": [
[
16,
0,
32,
48
]
]
},
{
"slot": 2,
"name": "corner_open",
"bitmask": "0b00000101",
"rects": [
[
16,
0,
32,
16
],
[
16,
16,
48,
32
]
]
},
{
"slot": 3,
"name": "corner_full",
"bitmask": "0b00000111",
"rects": [
[
16,
0,
48,
48
]
]
},
{
"slot": 4,
"name": "straight",
"bitmask": "0b00010001",
"rects": [
[
16,
0,
32,
64
]
]
},
{
"slot": 5,
"name": "tee_open",
"bitmask": "0b00010101",
"rects": [
[
16,
0,
32,
16
],
[
16,
16,
48,
32
],
[
16,
48,
32,
16
]
]
},
{
"slot": 6,
"name": "tee_half",
"bitmask": "0b00010111",
"rects": [
[
16,
0,
48,
48
],
[
16,
48,
32,
16
]
]
},
{
"slot": 7,
"name": "tee_full",
"bitmask": "0b00011111",
"rects": [
[
16,
0,
48,
64
]
]
},
{
"slot": 8,
"name": "cross_open",
"bitmask": "0b01010101",
"rects": [
[
16,
0,
32,
16
],
[
0,
16,
64,
32
],
[
16,
48,
32,
16
]
]
},
{
"slot": 9,
"name": "cross_q1",
"bitmask": "0b01010111",
"rects": [
[
16,
0,
48,
16
],
[
0,
16,
64,
32
],
[
16,
48,
32,
16
]
]
},
{
"slot": 10,
"name": "cross_q2adj",
"bitmask": "0b01011111",
"rects": [
[
16,
0,
48,
16
],
[
0,
16,
64,
32
],
[
16,
48,
48,
16
]
]
},
{
"slot": 11,
"name": "cross_q2opp",
"bitmask": "0b01110111",
"rects": [
[
16,
0,
48,
16
],
[
0,
16,
64,
32
],
[
0,
48,
48,
16
]
]
},
{
"slot": 12,
"name": "cross_q3",
"bitmask": "0b01111111",
"rects": [
[
16,
0,
48,
16
],
[
0,
16,
64,
48
]
]
},
{
"slot": 13,
"name": "solid",
"bitmask": "0b11111111",
"rects": [
[
0,
0,
64,
64
]
]
}
],
"style": "rectilinear"
}