How to add a blueprint with Claude

One second in, the shot fades into an architect's drawing: the bottle, dropper and acrylic block traced in thin white lines on deep blue paper ruled with a faint grid, redrawn as the camera circles.

Get this effect

  1. Switch to Code in your Claude Desktop App

  2. Install the skill (once)

    Show the prompt
    Install the Recharm video effects skill: download https://recharm-growth-staging.s3.us-east-2.amazonaws.com/website/downloads/recharm-video-effects.zip and unzip it into ~/.claude/skills
  3. Ask for the effect

    Add a blueprint to input.mp4
    Second the blueprint look starts: 1.0
    Seconds the switch from the normal shot takes: 0.3

Several videos, several effects, one ask

Put your clips in the folder, mention them with @, and ask for everything at once. Claude runs one tested script after another on each clip, then joins them.

Add a blueprint to @clip1.mp4, put a sale badge on @clip2.mp4, give @clip3.mp4 a VHS look, then join all three with crossfades.

Settings you can change

Ask Claude to change any of these, or edit them at the top of the script.

SettingDefaultWhat it does
START1.0Second the blueprint look starts.
FADE0.3Seconds the switch from the normal shot takes.
PAPER(18, 58, 140)Blueprint paper color.
GRID, MAJOR(52, 96, 176), (84, 128, 200)Grid line colors; every fifth line uses MAJOR.
CELL24Grid spacing in pixels.
INK(255, 255, 255)Line color.
LOW, HIGH30, 90Canny thresholds: lower finds more, fainter edges.
LINE2Line thickness in pixels.

Without the skill

Don’t want to install the skill? Paste this prompt into Claude Code and Claude writes the script itself.

Show the prompt
Turn input.mp4 into a blueprint from 1 second on. Before 1.0 seconds leave the video untouched; from 1.0 to 1.3 seconds fade linearly from the normal frame to the blueprint, then keep it to the end. For the blueprint, in Python with OpenCV and numpy, fill a sheet with deep blue paper (18, 58, 140) and rule a 1-pixel grid on it every 24 pixels starting at x = 0 and y = 0, in (52, 96, 176), with every fifth line brighter in (84, 128, 200). Take each frame's grayscale, Gaussian-blur it 5x5, find edges with cv2.Canny at thresholds 30 and 90, and thicken them with a 2x2 dilate. Draw those lines in pure white (255, 255, 255) over the sheet, softened by taking the larger of the line and 0.6 times the line Gaussian-blurred with sigma 1.2 as the opacity, with no trace of the original picture. Read and write the frames with ffmpeg, don't draw any text (if you ever do, use Pillow, not ffmpeg's drawtext), keep the audio, output 30fps H.264 yuv420p, and save it as output.mp4.

Run it without Claude

This is the exact script we tested. Save it as blueprint.py and run:

python3 blueprint.py input.mp4 output.mp4
Show the script
#!/usr/bin/env python3
"""Blueprint: at 1s the shot fades into a technical drawing, its outlines in crisp white on deep blue paper with a faint grid.

Usage: python3 blueprint.py input.mp4 output.mp4
Needs ffmpeg, numpy and OpenCV to find the outlines (pip install numpy opencv-python-headless).
"""
import json
import subprocess
import sys

import cv2
import numpy as np

START = 1.0                  # second the blueprint look starts
FADE = 0.3                   # seconds the switch from the normal shot takes
PAPER = (18, 58, 140)        # blueprint paper color (deep blue)
GRID = (52, 96, 176)         # minor grid line color
MAJOR = (84, 128, 200)       # every fifth grid line, a little brighter
CELL = 24                    # grid spacing in pixels
INK = (255, 255, 255)        # line color
LOW, HIGH = 30, 90           # Canny thresholds: lower finds more, fainter edges
LINE = 2                     # line thickness in pixels


def grid_sheet():
    """Blue paper with a fine grid and a brighter line every fifth cell."""
    sheet = np.empty((h, w, 3), np.float32)
    sheet[:] = PAPER
    for i, x in enumerate(range(0, w, CELL)):
        sheet[:, x] = MAJOR if i % 5 == 0 else GRID
    for i, y in enumerate(range(0, h, CELL)):
        sheet[y, :] = MAJOR if i % 5 == 0 else GRID
    return sheet


def blueprint(rgb):
    """The frame's outlines drawn in white over the grid sheet."""
    edges = cv2.Canny(cv2.GaussianBlur(cv2.cvtColor(rgb, cv2.COLOR_RGB2GRAY), (5, 5), 0), LOW, HIGH)
    line = cv2.dilate(edges, np.ones((LINE, LINE), np.uint8)).astype(np.float32) / 255
    soft = np.maximum(line, cv2.GaussianBlur(line, (0, 0), 1.2) * 0.6)[:, :, None]  # anti-aliased ink edge
    return sheet * (1 - soft) + ink * soft


def composite(rgb, t):
    """The normal frame before START, then a fade into the blueprint."""
    if t < START:
        return rgb
    mix = min((t - START) / FADE, 1)
    return (rgb * (1 - mix) + blueprint(rgb) * mix).round().astype(np.uint8)


def probe(path):
    info = json.loads(subprocess.check_output(["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries",
                                               "stream=width,height,r_frame_rate", "-of", "json", path]))
    s = info["streams"][0]
    num, den = s["r_frame_rate"].split("/")
    return s["width"], s["height"], s["r_frame_rate"], float(num) / float(den)


def render(src, out):
    """Read src frame by frame, composite each one and save to out, keeping the audio."""
    reader = subprocess.Popen(["ffmpeg", "-v", "error", "-i", src, "-f", "rawvideo", "-pix_fmt", "rgb24", "-"],
                              stdout=subprocess.PIPE)
    writer = subprocess.Popen(["ffmpeg", "-y", "-v", "error",
                               "-f", "rawvideo", "-pix_fmt", "rgb24", "-s", f"{w}x{h}", "-r", rate, "-i", "-",
                               "-i", src, "-map", "0:v", "-map", "1:a?", "-c:v", "libx264", "-crf", "18",
                               "-pix_fmt", "yuv420p", "-c:a", "copy", "-shortest", out], stdin=subprocess.PIPE)
    i = 0
    while raw := reader.stdout.read(w * h * 3):
        rgb = np.frombuffer(raw, np.uint8).reshape(h, w, 3)
        writer.stdin.write(composite(rgb, i / fps).tobytes())
        i += 1
    writer.stdin.close()
    if reader.wait() or writer.wait():
        sys.exit("ffmpeg failed")


src, out = sys.argv[1:3]
w, h, rate, fps = probe(src)
sheet = grid_sheet()
ink = np.array(INK, np.float32)
render(src, out)

Find 3x winning ads

Recharm cuts your ad footage into tagged, searchable clips: hooks, testimonials, product shots. Find the shots that win, add the effect with Claude, and ship 3x more ad edits.

Start 14-day free trial