{
  "slug": "video/e2e",
  "title": "Video E2E visibility",
  "description": "Run local end-to-end video generation and inspect the inputs, IR, frames, FFmpeg logs, and output video.",
  "url": "https://cuitty.com/docs/video/e2e",
  "markdown_url": "https://cuitty.com/docs/video/e2e.md",
  "json_url": "https://cuitty.com/docs/video/e2e.json",
  "frontmatter": {
    "title": "Video E2E visibility",
    "description": "Run local end-to-end video generation and inspect the inputs, IR, frames, FFmpeg logs, and output video.",
    "order": 4,
    "section": "Video",
    "updatedAt": "2026-05-24"
  },
  "headings": [
    {
      "depth": 1,
      "slug": "video-e2e-visibility",
      "text": "Video E2E visibility"
    },
    {
      "depth": 2,
      "slug": "run-the-deterministic-e2e-test",
      "text": "Run the deterministic E2E test"
    },
    {
      "depth": 2,
      "slug": "run-the-visible-artifact-workflow",
      "text": "Run the visible artifact workflow"
    },
    {
      "depth": 2,
      "slug": "ci-expectations",
      "text": "CI expectations"
    },
    {
      "depth": 2,
      "slug": "troubleshooting",
      "text": "Troubleshooting"
    }
  ],
  "body_markdown": "# Video E2E visibility\n\nThe Video E2E path should make the whole generation pipeline inspectable:\n\n1. YAML input\n2. Parsed Composition IR\n3. Rendered frame images\n4. FFmpeg command and logs\n5. Final encoded video\n6. Summary metadata\n\n## Run the deterministic E2E test\n\nFrom the video repository:\n\n```bash\ncd ~/Code/cuitty/video\nnode --import tsx --test packages/render/src/e2e.test.ts\n```\n\nThe test parses a YAML composition, checks the generated IR, renders frames when Playwright and FFmpeg are available, and verifies the output artifact.\n\n## Run the visible artifact workflow\n\nUse the visible workflow when you want to keep artifacts after the run:\n\n```bash\n./run e2e:visible\n```\n\nThe visible workflow should write a timestamped directory under the E2E artifacts root. Keep that directory when debugging local failures or uploading CI artifacts.\n\nExpected files:\n\n| Artifact | Purpose |\n| --- | --- |\n| `input.yaml` | Exact DSL input used by the test. |\n| `composition.ir.json` | Parsed and normalized Composition IR. |\n| `render-options.json` | Render options passed into the renderer. |\n| `frames/` | Sampled frame HTML and PNG files. |\n| `ffmpeg/args.json` | Encoder command arguments. |\n| `ffmpeg/stderr.log` | Captured encoder stderr. |\n| `trace-events.json` | Renderer trace events from composition through encode. |\n| `output/e2e-smoke.mp4` | Final rendered video. |\n| `output/ffprobe.json` | ffprobe metadata when ffprobe is available. |\n| `manifest.json` | Artifact index with dimensions, frame count, codec, size, and timings. |\n| `summary.md` | Human-readable CI summary. |\n\n## CI expectations\n\nCI should upload the visible artifact directory for every E2E run, including failures. That makes a failed render debuggable without reproducing the exact runner state locally.\n\n## Troubleshooting\n\nIf rendering is skipped, check for missing local prerequisites:\n\n```bash\nffmpeg -version\nnode --import tsx --test packages/render/src/e2e.test.ts\n```\n\nUse CLI `--dry-run` to separate DSL or IR failures from browser and encoder failures:\n\n```bash\ncuitty-video render composition.yaml --dry-run\n```",
  "body_html": "<h1 id=\"video-e2e-visibility\">Video E2E visibility</h1>\n<p>The Video E2E path should make the whole generation pipeline inspectable:</p>\n<ol>\n<li>YAML input</li>\n<li>Parsed Composition IR</li>\n<li>Rendered frame images</li>\n<li>FFmpeg command and logs</li>\n<li>Final encoded video</li>\n<li>Summary metadata</li>\n</ol>\n<h2 id=\"run-the-deterministic-e2e-test\">Run the deterministic E2E test</h2>\n<p>From the video repository:</p>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"bash\"><code><span class=\"line\"><span style=\"color:#79B8FF\">cd</span><span style=\"color:#9ECBFF\"> ~/Code/cuitty/video</span></span>\n<span class=\"line\"><span style=\"color:#B392F0\">node</span><span style=\"color:#79B8FF\"> --import</span><span style=\"color:#9ECBFF\"> tsx</span><span style=\"color:#79B8FF\"> --test</span><span style=\"color:#9ECBFF\"> packages/render/src/e2e.test.ts</span></span></code></pre>\n<p>The test parses a YAML composition, checks the generated IR, renders frames when Playwright and FFmpeg are available, and verifies the output artifact.</p>\n<h2 id=\"run-the-visible-artifact-workflow\">Run the visible artifact workflow</h2>\n<p>Use the visible workflow when you want to keep artifacts after the run:</p>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"bash\"><code><span class=\"line\"><span style=\"color:#B392F0\">./run</span><span style=\"color:#9ECBFF\"> e2e:visible</span></span></code></pre>\n<p>The visible workflow should write a timestamped directory under the E2E artifacts root. Keep that directory when debugging local failures or uploading CI artifacts.</p>\n<p>Expected files:</p>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<table><thead><tr><th>Artifact</th><th>Purpose</th></tr></thead><tbody><tr><td><code>input.yaml</code></td><td>Exact DSL input used by the test.</td></tr><tr><td><code>composition.ir.json</code></td><td>Parsed and normalized Composition IR.</td></tr><tr><td><code>render-options.json</code></td><td>Render options passed into the renderer.</td></tr><tr><td><code>frames/</code></td><td>Sampled frame HTML and PNG files.</td></tr><tr><td><code>ffmpeg/args.json</code></td><td>Encoder command arguments.</td></tr><tr><td><code>ffmpeg/stderr.log</code></td><td>Captured encoder stderr.</td></tr><tr><td><code>trace-events.json</code></td><td>Renderer trace events from composition through encode.</td></tr><tr><td><code>output/e2e-smoke.mp4</code></td><td>Final rendered video.</td></tr><tr><td><code>output/ffprobe.json</code></td><td>ffprobe metadata when ffprobe is available.</td></tr><tr><td><code>manifest.json</code></td><td>Artifact index with dimensions, frame count, codec, size, and timings.</td></tr><tr><td><code>summary.md</code></td><td>Human-readable CI summary.</td></tr></tbody></table>\n<h2 id=\"ci-expectations\">CI expectations</h2>\n<p>CI should upload the visible artifact directory for every E2E run, including failures. That makes a failed render debuggable without reproducing the exact runner state locally.</p>\n<h2 id=\"troubleshooting\">Troubleshooting</h2>\n<p>If rendering is skipped, check for missing local prerequisites:</p>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"bash\"><code><span class=\"line\"><span style=\"color:#B392F0\">ffmpeg</span><span style=\"color:#79B8FF\"> -version</span></span>\n<span class=\"line\"><span style=\"color:#B392F0\">node</span><span style=\"color:#79B8FF\"> --import</span><span style=\"color:#9ECBFF\"> tsx</span><span style=\"color:#79B8FF\"> --test</span><span style=\"color:#9ECBFF\"> packages/render/src/e2e.test.ts</span></span></code></pre>\n<p>Use CLI <code>--dry-run</code> to separate DSL or IR failures from browser and encoder failures:</p>\n<pre class=\"astro-code github-dark\" style=\"background-color:#24292e;color:#e1e4e8; overflow-x: auto;\" tabindex=\"0\" data-language=\"bash\"><code><span class=\"line\"><span style=\"color:#B392F0\">cuitty-video</span><span style=\"color:#9ECBFF\"> render</span><span style=\"color:#9ECBFF\"> composition.yaml</span><span style=\"color:#79B8FF\"> --dry-run</span></span></code></pre>",
  "links_out": []
}