Skip to main content

whiteboard-animator

Turn any whiteboard-style image into a hand-drawn animation. One command, CPU only, about a second per scene.

A sun, a leaf and a glucose molecule drawing themselves

pip install whiteboard-animator
whiteboard-animate sketch.png --duration 8 -o sketch.mp4

Give it a finished whiteboard picture and it writes the text word by word, traces the outlines, fills the shapes with brush strokes, and draws branched line art one stroke at a time, the way a person at a whiteboard would. Add a narration file and the drawing paces itself to the voice.

This is the render engine behind the Whiteboard format at Kinoslide. Kinoslide turns a PDF or a prompt into a full narrated whiteboard video: it writes the script, generates each scene image, records the voice, and syncs the drawing to the narration. The engine in this repo is the last step, released so anyone can use it on their own images.

Examples

Every image in examples/ ships with the MP4 the CLI produced from it. The scene images were generated by Kinoslide for a lecture on photosynthesis.

Image Rendered
examples/photosynthesis/01_light_to_glucose.png 01_light_to_glucose.mp4
examples/photosynthesis/03_carbon_fixation.png 03_carbon_fixation.mp4
examples/photosynthesis/04_energy_flow.png 04_energy_flow.mp4
examples/equation.png equation.mp4
examples/gyroscope.png gyroscope.mp4

Try one:

git clone https://github.com/masihsultani/whiteboard-animator
cd whiteboard-animator && pip install -e .
whiteboard-animate examples/gyroscope.png --duration 8 -o gyroscope.mp4

What it does with your image

  1. Finds the ink. Every connected blob of non-white pixels becomes a component. A bundled CRAFT text detector (ONNX, CPU) marks which components are text so words are written rather than traced like shapes.
  2. Orders the components the way a hand would. Containers before contents, shapes before their labels, text in reading order, small dots attached to the glyph they belong to.
  3. Gives each one a time slot. Slots scale with the square root of area so a big fill does not hog the timeline. With a region plan (below), slots follow the narration instead.
  4. Assigns every pixel a reveal time. Strokes follow their skeleton from a real endpoint, so a V starts at a tip and not the apex. Closed outlines get one travelling front. Fills get an outline pass, then either an angled sweep or bristled brush strokes depending on size. Line art with junctions is decomposed into sequential pen paths so an X or a grid does not grow from the middle outward.
  5. Streams frames to ffmpeg. Only pixels currently fading are touched each frame. A 1280px scene encodes in about a second on a laptop.

There is no model at render time apart from the small text detector. No GPU, no training, no API keys.

Install

Python 3.10+, with ffmpeg and ffprobe on your PATH.

pip install whiteboard-animator

Rendering needs no API key. The one optional feature that does is --detect-regions, which asks Gemini to work out the drawing order from the image and narration. It needs the gemini extra and GOOGLE_API_KEY. You can skip it and write a region plan by hand (see below).

pip install 'whiteboard-animator[gemini]'

From a checkout:

pip install -e '.[dev]'
pytest

Usage

Fixed length, no audio:

whiteboard-animate scene.png --duration 8 -o scene.mp4

With narration. The drawing finishes inside the audio and the finished frame holds until the audio ends:

whiteboard-animate scene.png --audio scene.wav -o scene.mp4

Several scenes, concatenated in order:

whiteboard-animate a.png b.png c.png --audio a.wav b.wav c.wav -o lecture.mp4

Quality presets: low (20 fps, 500k), medium (24 fps, 1500k, default), high (24 fps, 3000k). Images wider than 1280px are downscaled.

Make the drawing follow the voice

By default the whole image draws over the first 70% of the scene in a heuristic order. A region plan tells the engine what the image contains, in what order to draw it, and which narration phrase belongs to each part. Each region then draws in a window sized by how long its phrase takes to say, so the pen lands on the sun while the narrator says "sunlight".

whiteboard-animate scene.png --audio scene.wav --regions scene.regions.json -o scene.mp4

A plan is JSON. Boxes are normalized 0 to 1000 with the origin at the top left:

{
  "idea": "Photosynthesis in one picture",
  "regions": [
    {
      "label": "sun",
      "role": "main_concept",
      "object": "a sun with rays",
      "reveal_order": 1,
      "box": {"ymin": 120, "xmin": 40, "ymax": 620, "xmax": 380},
      "expected_visual": "Sun with orange rays",
      "annotation": "Photosynthesis starts with sunlight",
      "reveal": "fill"
    }
  ]
}

With the gemini extra and GOOGLE_API_KEY set, the plan can be detected from the image and the narration text:

whiteboard-animate scene.png --audio scene.wav \
  --detect-regions --narration "Photosynthesis starts with sunlight. ..." \
  --save-regions -o scene.mp4

--save-regions writes the detected plan next to the output so you can edit it and re-render with --regions.

Python API

from whiteboard_animator import Scene, SnippetRegionPlan, render_video

plan = SnippetRegionPlan.model_validate_json(open("a.regions.json").read())
render_video(
    [Scene("a.png", audio="a.wav", region_plan=plan), Scene("b.png", audio="b.wav")],
    "lecture.mp4",
    quality="high",
)

Lower level, WhiteboardAnimator.render_to_file(img_array, draw_duration, total_duration, output_path, fps=24, bitrate="1500k", element_plan=None) takes an RGB numpy array and writes a silent MP4. The constructor exposes every tuning knob: fade length, fill detection thresholds, brush angle and width, the S-curve that decides when a fill uses brush strokes instead of a sweep, and the line-art decomposition thresholds.

What makes a good input

The engine expects ink on white. Pixels lighter than 240 gray are background, and near-white is snapped to white. Clean marker-style drawings with a handful of flat colors animate best. Photos, gradients, and textured or colored backgrounds will not.

Kinoslide generates images that fit this shape on purpose. If you want the whole pipeline, from a topic or a PDF to a narrated video with the drawing synced to the voice, that is what kinoslide.ai does.

Engine alone vs Kinoslide

This repo Kinoslide
Animate an image you already have yes yes
Write the script from a PDF or prompt yes
Generate the scene images yes
Narration (Gemini and ElevenLabs voices) bring your own audio yes
Drawing synced to narration with a region plan automatic
Multiple scenes joined into one video yes yes
Hosted rendering, sharing, editing yes

Text detection model

whiteboard_animator/models/craft.onnx (83 MB) is an ONNX export of craft_mlt_25k from CRAFT-pytorch (MIT). Set CRAFT_MODEL_PATH to use a different file. If the model cannot be loaded the engine still runs and treats text as ordinary strokes.

Contributing

Issues and pull requests are welcome. Things we would like help with:

  • Non-white backgrounds (dark boards, paper textures)
  • SVG input, tracing real vector paths instead of a raster skeleton
  • Better ordering for dense diagrams without a region plan
  • A hand or marker sprite that follows the pen position

License

MIT. Made by the team behind Kinoslide.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

whiteboard_animator-0.1.0.tar.gz (77.2 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

whiteboard_animator-0.1.0-py3-none-any.whl (77.2 MB view details)

Uploaded Python 3

File details

Details for the file whiteboard_animator-0.1.0.tar.gz.

File metadata

  • Download URL: whiteboard_animator-0.1.0.tar.gz
  • Upload date:
  • Size: 77.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.10.16

File hashes

Hashes for whiteboard_animator-0.1.0.tar.gz
Algorithm Hash digest
SHA256 876fef7cd073741c1c6b0a952686d5fef44d9cb192a8e2264a3283a564e4fbf1
MD5 8204e1c28e5e7938bcae9d083f94b681
BLAKE2b-256 8afe7a2c08fad672ce30a99a095209c18fac05504b9d2ebc60892ee7839181ac

See more details on using hashes here.

File details

Details for the file whiteboard_animator-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for whiteboard_animator-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 31730d56efe5ec88a47e60fab23bd5a60185f6d821258a8e19828309c383531b
MD5 8a3b31fd12a3de6643ef32adb72ebe6d
BLAKE2b-256 f5c061731f7bf3b08c836a0a170032024eac467db9415b275aedbea7a5eb3f23

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.1

2 files

This release

0.1.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page