How to add an anime style with Claude

At one second the shot turns into a cel-shaded cartoon: the serum bottle and acrylic block get thick dark-ink outlines, the purple glass fills in flat and vivid, and the holographic backdrop becomes smooth painted patches of sky blue and pink.

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 an anime style to input.mp4
    Second the picture turns into a cartoon: 1.0
    Median filter size at half resolution: 5

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 an anime style 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 picture turns into a cartoon.
SMOOTH5Median filter size at half resolution. Bigger irons out more texture into flat color.
SHADES4Flat brightness bands for the cel shading. 3 is bolder and more graphic; 6 keeps more of the original shading.
SATURATION2.2Color boost. 1 keeps the original colors.
EDGE15How sharp a brightness change must be to get an outline. Lower draws more lines, higher keeps only the strongest contours.
LINE3Outline thickness in pixels (odd numbers).
INK(25, 15, 40)Outline color.

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
Give input.mp4 (540x960) an anime cartoon look from 1.0 seconds to the end; before 1.0 seconds leave every frame untouched. For each frame from 1.0 s: shrink it to half size (270x480, box filter) and run a 5x5 median filter on it (Pillow's MedianFilter(5)) to flatten texture into smooth areas of color. Color: scale that back up to 540x960 (bicubic), convert to HSV, cut V into 4 flat bands (v becomes (floor(v*4/256)+0.5)*64, so 32, 96, 160 or 224), multiply S by 2.2 (capped at 255), keep H, and convert back to RGB. Outlines: on the half-size smoothed frame's grayscale, take the brightness difference between the pixels on either side horizontally and vertically (central differences), and mark every pixel where the length of that gradient is above 15. Scale the mask up to 540x960, thicken it with a 3x3 max filter, soften it with a 0.6 pixel Gaussian blur and use it to paint dark ink (25, 15, 40) over the color image. Use Python with numpy and Pillow for the frames and ffmpeg to read and write the video (don't use ffmpeg's drawtext if you add any text), keep the size, 30fps, the 6 second length and the audio, and save it as output.mp4.

Run it without Claude

This is the exact script we tested. Save it as anime-style.py and run:

python3 anime-style.py input.mp4 output.mp4
Show the script
#!/usr/bin/env python3
"""Anime style: at one second the shot is redrawn as a cel-shaded cartoon with dark ink outlines and vivid flat color.

Usage: python3 anime-style.py input.mp4 output.mp4
Needs ffmpeg, Pillow and numpy (pip install pillow numpy).
"""
import json
import subprocess
import sys

import numpy as np
from PIL import Image, ImageFilter

START = 1.0              # second the picture turns into a cartoon
SMOOTH = 5               # median filter size (at half resolution) that irons out texture into flat areas of color
SHADES = 4               # flat brightness bands (cel shading); fewer gives a bolder, more graphic look
SATURATION = 2.2         # color boost; 1 keeps the original colors
EDGE = 15                # brightness step (0-255, across 2 half-size pixels) that gets an outline; lower draws more lines
LINE = 3                 # outline thickness in pixels (odd)
INK = (25, 15, 40)       # outline color


def anime(img):
    """Redraw one frame as a cartoon: flatten it, band its brightness, boost its color and ink its edges."""
    half = img.resize((img.width // 2, img.height // 2), Image.BOX)        # half size: faster, and smooths grain
    flat = half.filter(ImageFilter.MedianFilter(SMOOTH))
    h, s, v = [np.asarray(c, np.float32) for c in flat.resize(img.size, Image.BICUBIC).convert("HSV").split()]
    v = (np.floor(v / 256 * SHADES) + 0.5) * 256 / SHADES                 # flat cel-shading bands
    s = np.clip(s * SATURATION, 0, 255)
    hsv = Image.merge("HSV", [Image.fromarray(c.astype(np.uint8)) for c in (h, s, v)])
    color = np.asarray(hsv.convert("RGB"), np.float32)

    gray = np.asarray(flat.convert("L"), np.float32)
    gx, gy = np.zeros_like(gray), np.zeros_like(gray)
    gx[:, 1:-1] = gray[:, 2:] - gray[:, :-2]
    gy[1:-1] = gray[2:] - gray[:-2]
    edges = Image.fromarray((np.hypot(gx, gy) > EDGE).astype(np.uint8) * 255)
    edges = edges.resize(img.size, Image.BILINEAR).filter(ImageFilter.MaxFilter(LINE)).filter(ImageFilter.GaussianBlur(0.6))
    ink = (np.asarray(edges, np.float32) / 255)[..., None]
    return color * (1 - ink) + np.array(INK, np.float32) * ink


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)


src, out = sys.argv[1:3]
w, h, rate, fps = probe(src)
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):
    if i / fps >= START:
        img = anime(Image.frombytes("RGB", (w, h), raw))
        raw = np.clip(img, 0, 255).astype(np.uint8).tobytes()
    writer.stdin.write(raw)
    i += 1
writer.stdin.close()
if reader.wait() or writer.wait():
    sys.exit("ffmpeg failed")

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