Your words,
choreographed.

kinetic-type turns a YAML timeline and a voiceover into a finished motion-graphics film — typography, camera, physics, and a fully synthesized sound mix. No editor. One command.

$ kinetic build spec.yaml -o film.mp4
8 block types 1080p60 out of the box sound derived from the spec deterministic renders
typewriter → invert_at → gravity — one YAML file
Playground

Type a line. Watch it get directed.

A miniature in-browser version of four blocks. Play it, then take the generated YAML — the same words with the same timings — straight into your spec.

wrap a word in *stars* → bold + accent. In typewriter, the starred word is the invert_at moment.
# press play — the matching spec block appears here
Blocks

Eight moves. Compose freely.

Every block renders itself for a time window and emits its own sound events. All footage below is real engine output.

title

Staggered hero lines. fontcycle glitches a word through typefaces before it lands on the one you chose.

spec
- type: title
  lines:
    - y: 400
      size: 150
      groups:
        - {text: "GEN Z", t: 0.10, font: bold}
        - text: "customizes"
          t: 0.70
          fontcycle: {cycle: [bold, mono, med, lora],
                      step: 0.09, land_t: 1.50, land_font: lora}
word_pop

VO-synced word-by-word reveal — each word pops with scale + blur at its exact spoken moment.

spec
- type: word_pop
  align: center
  size: 84
  lines:
    - [["to", 7.98], ["one", 8.11], ["of", 8.26],
       ["the", 8.36], ["choices", 8.52, bold]]
media

Footage sequences, drawn device screens with typed lines, fly-in entrances, idle float, soft shadows.

spec
- type: media
  layers:
    - {kind: sequence, dir: assets/L, count: 266,
       rect: [55, 42, 590, 1038],
       enter: {t: 3.24, from: left, dur: 0.38}, shadow: true}
    - kind: device_text
      enter: {t: 3.30, from: bottom, dur: 0.38}
      lines: [["Their coffee.", 3.35], ["Their food.", 4.12]]
typewriter

Char-by-char with a live caret. Words complete on their VO timestamps; slam words punch in whole.

spec
- type: typewriter
  x: 220
  char_dur: 0.055
  lines:
    - y: 300
      size: 80
      words: [["21", 14.80, bold], ["million", 15.15, bold],
              ["eligible", 15.65]]
gravity

Point it at a typewriter block and everything drops — staggered release, spin, one floor bounce. Falls by words or by chars.

spec
- type: gravity
  from: stats        # id of the typewriter block
  start: 23.85
  t0: 23.85
  stagger: 0.32
  mode: words        # or: chars — every glyph tumbles alone
fade_line
fade_line

The quiet beat. A centered line whose letter-tracking settles as it fades in, then slips away.

spec
- type: fade_line
  t_in: 24.45
  t_out: 26.60
  size: 46
  color: dim
  text: "So we started with a simple human truth." 
select_delete

Words pop in, get cursor-selected on cue, then vanish with an RGB-split glitch and a cut sound.

spec
- type: select_delete
  select: [30.02, 30.76]
  delete_t: 30.82
  dots: [29.55, 29.72, 29.89]
  lines:
    - [["the", 28.20], ["value", 28.42, bold], ["of", 28.62],
       ["having", 28.85], ["a", 29.05], ["choice", 29.24, "bold,accent"]]
cta

The typed end card — keyed-in headline, two-tone sub-line, accent underline sweep with a bass hit.

spec
- type: cta
  keys: [["V", 32.25], ["O", 32.43], ["T", 32.60],
         ["E", 32.78], [".", 32.98]]
  sub: {t0: 33.50, a_text: "your future. ",
        b_text: "customize it.", b_font: lora}
  underline: [34.85, 35.03]

Blocks overlap. Draw order is spec order — here a left-aligned word_pop shares its window with a media block: a live phone screen flying in with a whoosh, plus a floating image layer fading in on cue.

The reference film

36 seconds. 10 blocks. One YAML file.

kinetic-type was extracted from a real production — a Gen Z voter-turnout PSA. The full spec ships in the repo as examples/genz.yaml; a script regenerates its footage crops from the campaign master.

film strip
$ kinetic analyze assets/vo.m4a
pauses (>=0.10s below -38dB) — likely sentence breaks:
   13.76 -  13.92  (0.16s)
   14.17 -  14.58  (0.41s)
   23.94 -  24.09  (0.15s)

syllable nuclei (energy peaks) per speech span:
  [0.00-4.71]  17 nuclei: 0.11 0.26 0.42 0.71 1.00 ...
  [4.82-13.76] 35 nuclei: 4.88 5.29 5.69 5.98 6.22 ...
hint: one nucleus ~= one syllable; map words to
nuclei to fill word times in the spec.

$ kinetic build examples/genz.yaml -o genz.mp4
  frame 2100/2160
wrote genz.mp4

21.20sThe blackout

One field — invert_at — cuts the background, flips the ink, fires the sub-drop, and ends the riser. Timed to the acoustic onset of the word “worse”.

23.85sThe fall

A gravity block pointed at the stats typewriter. Every word releases on a stagger, spins, bounces once. Nothing stays anchored.

30.82sThe delete

“The value of having a choice” gets cursor-selected, then removed — selection sweep, RGB-split glitch, cut sound. Then the CTA types itself.

Workflow

Analyze. Preview. Build.

01

analyze

No ML needed — signal analysis finds sentence pauses and syllable nuclei so you can pin every word to the voice.

$ kinetic analyze vo.m4a
02

preview

Render single frames at any timestamp to check a beat before committing to a full render.

$ kinetic preview my.yaml 21.26 33.2
03

build

Frames pipe straight into x264; the SFX mix is synthesized from the spec and ducked under your VO. Move a timestamp — picture and sound move together.

$ kinetic build my.yaml -o film.mp4
Get it

32 KB of engine. Bring your own words.

$ unzip kinetic-type.zip && cd kinetic-type
$ pip install -e .   # or: python3 -m kinetic ...
$ kinetic build examples/genz.yaml -o genz.mp4

requires: python 3.9+, ffmpeg, numpy scipy Pillow PyYAML
kinetic-type/
├─ kinetic/
│  ├─ engine.py    # scene, bg wipes, drift, shake, ffmpeg
│  ├─ blocks.py    # the 8 animation blocks
│  ├─ fxaudio.py   # synth kit + mixdown
│  ├─ analyze.py   # VO pauses + syllable nuclei
│  └─ text.py      # sprites, baseline layout
└─ examples/
   ├─ genz.yaml    # the reference film
   └─ extract_assets.sh