{"record":{"id":"65052b9ce971e9aa","repo":"nexu-io/open-design","slug":"cursor-at-self-y-exceeds-footer-rail-self-cap","errorCode":null,"errorMessage":"cursor at {self.y} exceeds footer rail {self.cap}; reduce block height or split slide","messagePattern":"cursor at (.+?) exceeds footer rail (.+?); reduce block height or split slide","errorType":"exception","errorClass":"OverflowError","httpStatus":null,"severity":"error","filePath":"skills/pptx-html-fidelity-audit/SKILL.md","lineNumber":136,"sourceCode":"FOOTER_TOP     = Inches(6.85)     # footer row pinned here, edge-to-edge\n```\n\n> **Customizing the rails.** The defaults above suit a 16:9 canvas with a slim footer. If your design system uses a wider footer or a 4:3 canvas, override these constants in your export script and pass the same values to `verify_layout.py` via `--content-max-y` / `--canvas-h` / `--canvas-w`. See `references/layout-discipline.md` §1 for the full constant table.\n\n\n**Use a cursor for content blocks instead of pinning each block at an absolute y:**\n\n```python\nclass Cursor:\n    \"\"\"Advances down the slide; refuses to cross the footer rail.\"\"\"\n    def __init__(self, y_start, cap=CONTENT_MAX_Y):\n        self.y = y_start\n        self.cap = cap\n    def take(self, h, gap=Inches(0.12)):  # ~1 line of whitespace at 14pt; tighten/loosen per design system\n        top = self.y\n        self.y = top + h + gap\n        if self.y > self.cap:\n            raise OverflowError(\n                f\"cursor at {self.y} exceeds footer rail {self.cap}; \"\n                f\"reduce block height or split slide\"\n            )\n        return top\n```\n\nFor each slide, instantiate `Cursor(MARGIN_TOP)` and `take(height)` each block in reading order. The slide refuses to render if any block would cross the rail, so overflows become loud build errors instead of silent visual bugs.\n\n**Hero (vertically-centered) slides use a budget instead of a cursor:**\n\n```python\ndef hero_layout(blocks):\n    \"\"\"blocks = list of (height, gap_after) tuples in reading order.\"\"\"\n    total = sum(h + g for h, g in blocks)\n    y_start = (CANVAS_H - total) / 2\n    return Cursor(y_start)\n```\n","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/skills/pptx-html-fidelity-audit/SKILL.md#L118-L154","documentation":"Raised by the Cursor.take() helper documented in skills/pptx-html-fidelity-audit/SKILL.md when advancing the content cursor would push self.y past self.cap (CONTENT_MAX_Y, the footer rail). It is an intentional OverflowError that turns a silent visual overflow (content crossing the footer) into a loud build error during pptx re-export.","triggerScenarios":"Calling cursor.take(h) for a block whose height plus gap pushes the running y beyond CONTENT_MAX_Y; too many blocks stacked in reading order; a single oversized block (e.g. a tall image or long bullet list).","commonSituations":"Re-exporting a deck where a slide has more content than the content area allows; design system changed footer height so CONTENT_MAX_Y shrank; image heights computed too generously.","solutions":["Reduce the offending block's height (tighten image height, trim text, shrink padding).","Split the slide into two slides so each fits within the rail.","Raise CONTENT_MAX_Y only if the design system genuinely allows a smaller footer (update FOOTER_TOP accordingly and pass --content-max-y to verify_layout.py).","Switch the slide to hero_layout (centered budget) if it is a vertically-centered hero, not a top-pinned flow."],"exampleFix":"# before\ncursor = Cursor(MARGIN_TOP)\ncursor.take(Inches(6.5))   # single block too tall, raises OverflowError\n# after\ncursor.take(Inches(3.0))\ncursor.take(Inches(2.8))   # split into two blocks that fit","handlingStrategy":"try-catch","validationCode":"if cursor.y + h + gap > cursor.cap:\n    raise SystemExit(f\"block of height {h} would overflow footer rail; split or shrink\")","typeGuard":null,"tryCatchPattern":"try:\n    top = cursor.take(block_height)\nexcept OverflowError as e:\n    # split the slide or shrink the block, then retry\n    split_or_shrink(block, e)\n    raise","preventionTips":["Compute per-block heights from text metrics + minimal padding, not generous wrappers.","Keep CONTENT_MAX_Y and FOOTER_TOP defined once per deck and passed to verify_layout.py.","Use hero_layout for centered slides instead of a top-pinned Cursor.","Run verify_layout.py after every re-export so overflows are caught early."],"tags":["layout","pptx","presentation","overflow"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}