Skip to content

NotDrake100/code-to-video

Repository files navigation

🎬 Code-to-Video β€” Product Videos with Pure HTML, CSS & JavaScript

No After Effects. No Premiere Pro. No Figma. Just code.

This repo contains the full pipeline for creating high-quality product promo videos using nothing but HTML/CSS/JS animations rendered to MP4 via Playwright (headless Chrome) and FFmpeg.

Built for CooBear β€” a group dinner expense tracker.


🧠 How It Works

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  HTML/CSS/JS     │────▢│  Playwright     │────▢│  FFmpeg       β”‚
β”‚  Animation       β”‚     β”‚  Frame Capture  β”‚     β”‚  MP4 Encode   β”‚
β”‚  (single file)   β”‚     β”‚  (30 FPS PNGs)  β”‚     β”‚  (H.264)      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  1. Design your animation as a single HTML file with CSS animations and JS-driven sequencing
  2. Capture every frame using Playwright's headless Chrome with a virtual time system
  3. Encode to MP4 using FFmpeg with high-quality H.264 settings

The key innovation is the virtual time system β€” the render script overrides setTimeout so animations run in deterministic, frame-perfect time rather than real-time. This means every frame is captured exactly right, regardless of how fast or slow your machine is.


πŸ“ Project Structure

.
β”œβ”€β”€ README.md
β”œβ”€β”€ package.json
β”œβ”€β”€ render-video.js              # πŸŽ₯ The rendering engine
β”œβ”€β”€ coobear_dinner_animation_v2.html   # Animation: iMessage chat sequence
β”œβ”€β”€ coobear_dinner_animation_v3_followup.html  # Animation: app walkthrough
β”œβ”€β”€ coobear_uber_edit.html       # Animation: Uber-style edit
β”œβ”€β”€ COOBEAR_WHITE_FF.PNG         # Logo asset
β”œβ”€β”€ render_frames/               # (generated) PNG frames during render
└── rendered/                    # (generated) Final MP4 output

πŸš€ Quick Start

Prerequisites

  • Node.js v18+
  • Google Chrome installed (used as the rendering engine)
  • FFmpeg installed

Install FFmpeg (macOS)

brew install ffmpeg

Install FFmpeg (Ubuntu/Debian)

sudo apt install ffmpeg

Install FFmpeg (Windows)

Download from ffmpeg.org and add to PATH.

Setup

# Clone the repo
git clone https://github.com/AVinashthorat2211/code-to-video.git
cd code-to-video

# Install dependencies
npm install

Render a Video

# Render the default animation
node render-video.js

# Render a specific animation
node render-video.js coobear_dinner_animation_v2.html

# Render with background audio
node render-video.js coobear_dinner_animation_v3_followup.html audio.mp3

The rendered MP4 will appear in the rendered/ directory.


🎨 Create Your Own Animation

Step 1: Create an HTML File

Create a single HTML file with your animation. The file must:

  1. Expose window.__animationDurationMs β€” total duration in milliseconds
  2. Expose window.__animationDone β€” set to true when animation completes
  3. Define a runSequence() function β€” the main animation entry point
  4. Support ?render=1 query parameter β€” to disable auto-restart loops
<!DOCTYPE html>
<html>
<head>
  <style>
    /* Your styles here */
    * { margin: 0; padding: 0; box-sizing: border-box; }
    
    body {
      width: 100vw;
      height: 100vh;
      overflow: hidden;
      background: #000;
      font-family: -apple-system, sans-serif;
    }

    .element {
      opacity: 0;
      transform: translateY(10px);
      transition: opacity 0.35s ease, transform 0.35s ease;
    }

    .element.visible {
      opacity: 1;
      transform: translateY(0);
    }
  </style>
</head>
<body>

  <div id="scene">
    <h1 class="element" id="title">Your Product</h1>
    <p class="element" id="subtitle">A tagline here</p>
  </div>

  <script>
    // Required: sleep helper using setTimeout (gets overridden by renderer)
    const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

    // Required: detect render mode
    const renderMode = new URLSearchParams(window.location.search).get("render") === "1";

    // Required: expose these globals
    window.__animationDone = false;
    window.__animationDurationMs = 5000; // total duration in ms

    // Required: main animation function
    async function runSequence() {
      window.__animationDone = false;

      // Reset all elements
      document.querySelectorAll('.element').forEach(el => {
        el.classList.remove('visible');
      });

      // Animate!
      await sleep(500);
      document.getElementById('title').classList.add('visible');

      await sleep(1000);
      document.getElementById('subtitle').classList.add('visible');

      await sleep(2000);
      // ... more animation steps

      window.__animationDone = true;

      // Auto-restart for browser preview (not during render)
      if (!renderMode) {
        setTimeout(runSequence, 1000);
      }
    }

    // Start the animation
    runSequence();
  </script>
</body>
</html>

Step 2: Preview in Browser

Open your HTML file directly in Chrome to preview:

open your_animation.html

The animation will loop continuously so you can tweak it.

Step 3: Render to MP4

node render-video.js your_animation.html

βš™οΈ Renderer Configuration

Edit the constants at the top of render-video.js:

Variable Default Description
FPS 30 Frames per second
WIDTH 1280 Video width in pixels
HEIGHT 720 Video height in pixels
CHROME_PATH /Applications/Google Chrome.app/... Path to Chrome executable

Chrome Path by OS

OS Path
macOS /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
Linux /usr/bin/google-chrome or /usr/bin/chromium-browser
Windows C:\Program Files\Google\Chrome\Application\chrome.exe

Update CHROME_PATH in render-video.js for your platform.


πŸ”‘ Key Concepts

Virtual Time System

The renderer replaces setTimeout with a virtual time-controlled version. This means:

  • βœ… Frame-perfect captures β€” no dropped frames, no timing issues
  • βœ… Machine-independent β€” same output on fast or slow hardware
  • βœ… Deterministic β€” render the same animation twice, get identical output

The virtual time advances exactly 1000/FPS milliseconds per frame (33.33ms at 30 FPS).

Animation Techniques Used

Technique How
iMessage chat bubbles CSS border-radius, flexbox layout, opacity transitions
Typing indicators Three dots with staggered @keyframes bounce
Slide-up reveals transform: translateY(10px) β†’ translateY(0) with opacity
Screen transitions Layer-based system with .on class toggling display: grid
Camera crosshair Absolute-positioned element with CSS pseudo-elements
Flash effect Full-screen white overlay with quick opacity pulse
Progress bars CSS width transition on inner div
Button press transform: scale(0.985) on .pressed class

Adding Audio

Pass an audio file as the second argument:

node render-video.js animation.html background_music.mp3

The audio will be encoded as AAC at 256kbps. The -shortest flag ensures the video length matches the shorter of video/audio.


πŸ“ Tips for Great Animations

  1. Use system fonts β€” -apple-system, "SF Pro Display", sans-serif for native feel
  2. Keep transitions snappy β€” 300-400ms is the sweet spot
  3. Add breathing room β€” await sleep(500-800) between major beats
  4. Layer your scenes β€” use absolute-positioned sections toggled with classes
  5. Design at 16:9 β€” use aspect-ratio: 16/9 on your frame container
  6. Retina quality β€” the renderer captures at 2x deviceScaleFactor
  7. Use sleep() for all timing β€” never use setInterval or requestAnimationFrame

πŸŽ₯ Example Animations

iMessage Chat Sequence (coobear_dinner_animation_v2.html)

A conversation between friends deciding where to eat, ending with a CooBear logo reveal. Features typing indicators, read receipts, and a camera flash transition.

App Walkthrough (coobear_dinner_animation_v3_followup.html)

Multi-scene product demo: search β†’ expense details β†’ PDF download β†’ iMessage share β†’ logo. Shows the full CooBear user flow with crosshair click interactions.


πŸ“„ License

MIT β€” use this pipeline for your own product videos!


πŸ™Œ Credits

Built by @thoratarchit@gmail.com

If you use this to make a product video, tag me β€” I'd love to see it! 🐻

About

Create product promo videos with pure HTML, CSS & JavaScript. No After Effects needed. Renders to MP4 via Playwright + FFmpeg.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors