Open-Source Animation DSL

Text-to-motion animation DSL.

Define actors, timelines, and interactions in a simple text language. Markdy is built for animated scenes, not static chart or graph diagrams.

Try the PlaygroundLearn the Syntax
npm i @markdy/core @markdy/renderer-dom
import { createPlayer } from "@markdy/renderer-dom";

createPlayer({
  container: document.getElementById("stage"),
  code: `scene width=600 height=300
  actor a = figure(#c68642, m, 😎) at (300, 150)
  @0.3: a.enter(from=left, dur=0.8)`,
  autoplay: true,
});
pnpm add -D @markdy/cli
# validate, format, and preview a scene
markdy lint trailer.markdy
markdy fmt trailer.markdy --write
markdy render trailer.markdy --out dist/trailer.html
markdy check-all examples
pnpm add @markdy/astro
---
import { Markdy } from "@markdy/astro";

const code = `
  scene width=800 height=400 bg=#fff5f9
  actor hero = figure(#c68642, m, 😎) at (400, 200)
  @0.0: hero.enter(from=left, dur=0.8)
  @1.5: hero.say("Hello!", dur=1.2)
`;
---

<Markdy {code} width={800} height={400} bg="#fff5f9" autoplay />
pnpm add @markdy/mdx react react-dom
// mdx.config.mjs β€” one-time setup
import { remarkMarkdy } from "@markdy/mdx";

export default {
  remarkPlugins: [remarkMarkdy],
};

// content.mdx β€” no imports, just write markdown
```markdy
scene width=600 height=300 bg=white
actor label = text("Hello") at (200, 130) size 40
@0.3: label.fade_in(dur=0.6)
```

Key Features

πŸ“¦

Zero Dependencies

Pure TypeScript parser β€” no DOM, no runtime deps.

🌐

Web-Native Renderer

Web Animations API + CSS transforms. No Canvas, no GSAP.

πŸ€–

AI-Agent Friendly

Structured DSL that LLMs can generate, validate, and iterate.

🧩

Framework Agnostic

Works anywhere. Astro island component included.

Lightweight Packages

Two packages to render a scene anywhere. Everything else is an optional add-on for your stack.

Playground

Start from a real shipped example, tweak the script, and preview the result instantly.

Editor
Ctrl+Space autocomplete Β· Cmd+Enter run
Preview

Learn MarkdyScript

Follow this guide from basics to advanced. Each card builds on the last.

1

Scene Setup

Every animation starts by defining the canvas. This must be the first line in your .markdy file.

scene width=800 height=400 fps=30 bg=#fafafa
PropertyDefaultDescription
width800Canvas width in pixels
height400Canvas height in pixels
fps30Frame rate for the rendering engine
bgwhiteAny CSS color value (e.g. #1a1a2e)
durationautoOverride total length in seconds
2

Actors & Positioning

Actors are the objects in your scene. Place them with at (x, y) and add optional modifiers.

actor a = figure(#c68642, m, 😎) at (100, 200) scale 1.2
actor b = text("Hello World") at (50, 50) size 24
actor c = box() at (300, 200)
TypeArgumentsDescription
text"quoted string"Plain text label. Customise with size.
boxβ€”100x100 solid box. Great for prototyping.
figureskinColor, gender, faceStick figure with articulatable limbs.
spriteasset nameRenders an image or icon asset.

Modifiers: opacity (0–1), scale, rotate, size (text only), z (layer order).

3

Timeline & Motion

Schedule actions on a timeline with @time: actor.action(). Time is in decimal seconds.

@0.5: a.enter(from=left, dur=0.8)
@1.5: a.move(to=(400, 200), dur=1.0, ease=out)
@3.0: a.fade_out(dur=0.5)
ActionParametersWhat it does
enterfrom, durSlides in from canvas edge
moveto, dur, easeTranslates to target coordinates
fade_in / fade_outdurAnimates opacity
scale / rotateto, durTransforms the actor

Easing: linear, in, out, inout

4

Speech & Effects

Make actors talk with comic speech bubbles and add dynamic effects like shaking.

@1.0: a.say("Hello! πŸ‘‹", dur=1.5)
@2.5: a.shake(intensity=8, dur=0.4)
ActionParametersWhat it does
say"text", durShows an anchored speech bubble
shakeintensity, durOscillates on the X axis
throwasset, to, durLaunches a projectile between actors
5

Expressions & Limbs

figure actors have articulated limbs you can individually control for expressive animations.

@1.0: a.face("😡")
@1.5: a.rotate_part(part=arm_right, to=130, dur=0.4)
@2.0: a.punch(side=right, dur=0.2)
@2.5: a.kick(side=left, dur=0.3)
ActionParameters
face"emoji" β€” instant expression swap
rotate_partpart, to (degrees), dur
punch / kickside (left|right), dur

Body parts: head, face, body, arm_left, arm_right, leg_left, leg_right

5b

Gestures & Posing

Built-in gestures save you from chaining rotate_part calls. pose sets multiple parts at once.

@1.0: a.wave(side=right, dur=0.8)
@2.0: a.nod(dur=0.4)
@3.0: a.pose(arm_left=70, arm_right=-70, dur=0.4)
@4.0: a.jump(height=25, dur=0.5)
@4.5: a.bounce(intensity=12, count=3, dur=0.5)
ActionParametersWhat it does
waveside, durWave gesture β€” arm up, oscillate, return
noddurHead nod β€” down and up twice
posearm_left, arm_right, leg_left, leg_right, head, body, durSet multiple parts at once
jumpheight, durJump with squash/stretch
bounceintensity, count, durDiminishing vertical bounce
6

Assets & Sprites

Load external images and vector icons as assets, then render them as sprite actors.

# Declare assets first
asset cat = image("https://example.com/cat.gif")
asset fire = icon("lucide:flame")

# Render them as actors
actor meme = sprite(cat) at (400, 200) scale 0.5
actor icon = sprite(fire) at (100, 100) scale 2.0
image("url")Loads images, GIFs, photos β€” any URL or local path.
icon("set:name")Loads SVG icons from Iconify. Never blurs when scaled.
7

Variables & Templates

Avoid repetition with var for values and def for reusable actor templates.

var accent_skin = #fad4c0

def char(skin, face) {
  figure($${skin}, f, $${face})
}

actor lily = char($${accent_skin}, 😊) at (100, 200)

var substitutes values (robust for #hex colors). def creates actor factory templates β€” build character systems without any JavaScript.

8

Sequences

Package multi-step choreographies into reusable seq blocks. The ultimate power move.

seq wave(arm, angle) {
  @+0.0: $.rotate_part(part=$${arm}, to=$${angle}, dur=0.3)
  @+0.3: $.rotate_part(part=$${arm}, to=25, dur=0.3)
}

@2.0: lily.play(wave, arm=arm_left, angle=-80)

$ refers to the calling actor. Times with @+ are relative offsets from when .play() is triggered.

AI-Friendly by Design

MarkdyScript is a structured DSL that AI agents can generate, validate, and iterate on. Just describe what you want.

How it works

  1. Point your AI to the docs

    Share the AGENT.md β€” a single all-in-one reference with grammar, actions, patterns and examples.

  2. Describe your scene in plain English

    Tell the AI what you want to visualize β€” characters, actions, emotions, timing.

  3. Get valid MarkdyScript back

    The AI generates syntactically correct code. Paste it into the playground or your app.

Example prompt

You β†’ Claude / ChatGPT / Copilot
Use https://github.com/HoangYell/markdy-com/blob/main/docs/AGENT.md as a complete reference (grammar, actions, patterns, examples), then write a Markdy scene:

"A guy holding a coffee cup walks in, trips on a rock, and loses his coffee cup. The cup flies and smashes. He looks sad."

The AI reads the docs, understands the grammar, and outputs a complete .markdy scene with actors, timeline events, and expressions β€” ready to render.

Works with any AI that accepts URL context

ClaudeChatGPTGitHub CopilotCursorWindsurf

Built with Markdy

Real projects using Markdy in production.