{"record":{"id":"03a1362dcb61b603","repo":"Hmbown/CodeWhale","slug":"app-icon-blob-not-found-in-the-founder-sheet","errorCode":null,"errorMessage":"app-icon blob not found in the founder sheet","messagePattern":"app-icon blob not found in the founder sheet","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"scripts/brand/braille-mark.py","lineNumber":155,"sourceCode":"                continue\n            blob, stack = [], collections.deque([(sx, sy)])\n            seen[sy * width + sx] = 1\n            while stack:\n                x, y = stack.pop()\n                blob.append((x, y))\n                for nx, ny in ((x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)):\n                    if (\n                        x0 <= nx < x1\n                        and y0 <= ny < y1\n                        and not seen[ny * width + nx]\n                        and is_navy(pixels[nx, ny])\n                    ):\n                        seen[ny * width + nx] = 1\n                        stack.append((nx, ny))\n            if len(blob) > len(best):\n                best = blob\n    if len(best) < 10_000:\n        raise SystemExit(\"app-icon blob not found in the founder sheet\")\n    bx0 = min(x for x, _ in best)\n    bx1 = max(x for x, _ in best)\n    by0 = min(y for _, y in best)\n    by1 = max(y for _, y in best)\n    # The white whale cuts the blob's left side, but its full height shows:\n    # the icon is square, so the edge is the height.\n    edge = by1 - by0 + 1\n    if not 150 <= edge <= 260:\n        raise SystemExit(f\"app-icon blob has unexpected height: {edge}\")\n    cx = (bx0 + bx1) // 2\n    cy = (by0 + by1) // 2\n    half = edge // 2 + ICON_PAD\n    box = (cx - half, cy - half, cx + half, cy + half)\n    print(\n        f\"// app-icon navy blob x {bx0}-{bx1} y {by0}-{by1}, \"\n        f\"square crop {box[0]},{box[1]}-{box[2]},{box[3]}\",\n        file=sys.stderr,\n    )","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/scripts/brand/braille-mark.py#L137-L173","documentation":"icon_square in scripts/brand/braille-mark.py locates the largest connected navy blob in the founder sheet image (via flood fill) and raises SystemExit when the best blob is smaller than 10,000 pixels. This guard exists because the tool expects the app icon to be a large solid region; a smaller 'best' blob means the sheet was not found, changed color, or the icon was resized/replaced, so continuing would produce a corrupt crop.","triggerScenarios":"Running braille-mark.py against a founder sheet image whose largest same-color connected component has fewer than 10,000 pixels — e.g. the icon artwork was changed, the sheet resolution was reduced, the icon color no longer matches the flood-fill target, or the wrong image path was passed so the biggest blob found is just a decorative element.","commonSituations":"Rebranding/redesigning the icon so its color or size no longer matches; downscaling the founder sheet; pointing the script at a placeholder or unrelated image; icon split into multiple smaller blobs by overlaid artwork (like the white whale cut) so no single component reaches the threshold.","solutions":["Verify the correct founder-sheet image path is passed to the script","Check the icon artwork still forms one large contiguous region of the expected color; merge split components or adjust the flood-fill color match","Regenerate/restore the original founder sheet asset at its intended resolution","If the icon is legitimately smaller, lower the 10_000 threshold deliberately in icon_square"],"exampleFix":"# before\nif len(best) < 10_000:\n    raise SystemExit(\"app-icon blob not found in the founder sheet\")\n# after\nif len(best) < 10_000:\n    print(f\"largest blob only {len(best)} px; check sheet path/resolution\")\n    raise SystemExit(\"app-icon blob not found in the founder sheet\")","handlingStrategy":"validation","validationCode":"from PIL import Image\nimg = Image.open(path).convert(\"L\")\nnavy_px = sum(1 for p in img.getdata() if p < 80)\nassert navy_px >= 10_000, f\"sheet has only {navy_px} navy px\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the founder sheet at a fixed canonical resolution and regenerate derived assets from it","Add a CI check that runs icon_square against every rebrand PR","Never hand-edit the sheet; export it from the design source each time","Log blob size before the threshold check to speed diagnosis"],"tags":["image-processing","asset-validation","build-script"],"backgroundTag":"resource-not-found","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}