{"record":{"id":"2592913976bc32b7","repo":"calesthio/OpenMontage","slug":"playwright-is-required-to-render-preview-mp4","errorCode":null,"errorMessage":"Playwright is required to render preview MP4","messagePattern":"Playwright is required to render preview MP4","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"tools/character/character_animation.py","lineNumber":76,"sourceCode":"    visual_style = style.get(\"visual_style\") or style.get(\"name\") or style.get(\"style\")\n    if visual_style:\n        normalized[\"visual_style\"] = str(visual_style)\n    palette = style.get(\"palette\")\n    if isinstance(palette, list):\n        normalized[\"palette\"] = [str(color) for color in palette]\n    for key in [\"line_style\", \"texture\"]:\n        if style.get(key):\n            normalized[key] = str(style[key])\n    return normalized\n\n\ndef _render_preview_mp4(preview_path: Path, video_path: Path, duration_seconds: float, fps: int) -> None:\n    if shutil.which(\"ffmpeg\") is None:\n        raise RuntimeError(\"ffmpeg is required to render preview MP4\")\n    try:\n        from playwright.sync_api import sync_playwright\n    except Exception as exc:  # pragma: no cover - dependency-specific branch\n        raise RuntimeError(\"Playwright is required to render preview MP4\") from exc\n\n    frame_dir = video_path.parent / f\"{video_path.stem}_frames\"\n    frame_dir.mkdir(parents=True, exist_ok=True)\n    frame_count = max(2, int(duration_seconds * fps))\n    with sync_playwright() as p:\n        browser = p.chromium.launch()\n        page = browser.new_page(viewport={\"width\": 1280, \"height\": 720})\n        page.goto(preview_path.resolve().as_uri(), wait_until=\"networkidle\")\n        for frame in range(frame_count):\n            if frame:\n                page.wait_for_timeout(int(1000 / fps))\n            page.screenshot(path=str(frame_dir / f\"frame_{frame:04d}.png\"))\n        browser.close()\n\n    cmd = [\n        \"ffmpeg\",\n        \"-y\",\n        \"-framerate\",","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/character/character_animation.py#L58-L94","documentation":"Raised by _render_preview_mp4 when `from playwright.sync_api import sync_playwright` raises ImportError. The preview renderer drives headless Chromium via Playwright to screenshot the HTML preview frame-by-frame, so the playwright package is a hard requirement once ffmpeg is present. The original ImportError is chained (`from exc`) so the underlying cause is preserved.","triggerScenarios":"Reaching _render_preview_mp4 with ffmpeg installed but the playwright pip package missing (not in requirements, installed in a different venv, or the process runs under a different interpreter). Note the package install alone is not enough — `playwright install chromium` is also needed later.","commonSituations":"Installing only the project's core deps without the preview extras, mixing system Python and virtualenv, or CI that installs playwright but forgets the browser download step and fails one step later with a different error.","solutions":["Install playwright into the same interpreter that runs the tool: `pip install playwright`.","Install the browser binary: `playwright install chromium` (otherwise the subsequent p.chromium.launch() will fail with its own error).","If it is installed but still ImportError, verify with the running interpreter: `python -c \"from playwright.sync_api import sync_playwright; print('ok')\"` to detect venv mismatch.","Add playwright + the chromium browser step to CI/Docker so preview rendering works out of the box."],"exampleFix":"# before\npip install -r requirements.txt  # playwright missing -> RuntimeError\n\n# after\npip install playwright\nplaywright install chromium","handlingStrategy":"validation","validationCode":"def playwright_available() -> bool:\n    try:\n        from playwright.sync_api import sync_playwright  # noqa: F401\n        return True\n    except ImportError:\n        return False\n\nassert playwright_available(), \"pip install playwright && playwright install chromium\"","typeGuard":null,"tryCatchPattern":"try:\n    from playwright.sync_api import sync_playwright\nexcept ImportError as e:\n    raise RuntimeError(\"Install playwright: pip install playwright && playwright install chromium\") from e","preventionTips":["Pin playwright in requirements and add `playwright install chromium` to setup scripts.","Check both the package and the browser binary at startup for preview workloads.","Keep preview extras in a dedicated requirements-extra.txt so they are not forgotten."],"tags":["playwright","dependency","environment","character-animation","rendering"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}