# @devmotion/cli

HTML-first, agent-friendly video tooling. **Write HTML. Render video.**

DevMotion turns a directory of HTML files into an animated MP4. Every element
with `data-dm-*` attributes becomes a layer on the timeline. The Studio
(visual editor) and the CLI render share the exact same engine — what you see
in preview is what you get in the MP4.

```bash
npx @devmotion/cli init my-video
cd my-video
devmotion preview   # open the editor in your browser
devmotion render    # produce ./output.mp4
```

---

## Install

```bash
npm i -g @devmotion/cli
# or use it without installing
npx @devmotion/cli <command>
```

### Requirements

Only **Node.js ≥ 20**. Everything else (ffmpeg, Playwright Chromium) is
installed automatically:

- `@ffmpeg-installer/ffmpeg` ships a platform-specific ffmpeg binary as a
  regular dependency — no `brew`, `apt`, or `winget` needed.
- A `postinstall` script downloads Playwright Chromium (~150 MB, one-time).
  Skip it with `DEVMOTION_SKIP_POSTINSTALL=1` if you don't intend to render
  (preview still works).

Run `devmotion doctor` to verify both are wired up.

---

## Commands

| Command                             | Purpose                                                    |
| ----------------------------------- | ---------------------------------------------------------- |
| `devmotion init <name>`             | Scaffold a new project (`devmotion.json` + `scenes/`)      |
| `devmotion preview [--port 5173]`   | Open the Studio in the browser, hot-reloads on file change |
| `devmotion render [--output X.mp4]` | Render to MP4 (auto-spawns Studio if not running)          |
| `devmotion add-scene <name>`        | Append a new scene, `--with gsap`/`lottie`/`bare`          |
| `devmotion mcp`                     | Run the local MCP server over stdio                        |
| `devmotion mcp --print-config`      | Print a stdio MCP config snippet                           |
| `devmotion doctor`                  | Check ffmpeg & Playwright are installed                    |

---

## Project shape

```
my-video/
├── devmotion.json    # project config (size, fps, scenes)
├── scenes/
│   ├── intro.html    # one HTML file per scene
│   └── outro.html
└── assets/           # images, videos, fonts, lottie JSON
```

### `devmotion.json`

```json
{
  "version": 1,
  "name": "my-video",
  "width": 1920,
  "height": 1080,
  "fps": 30,
  "duration": 10,
  "background": { "type": "solid", "color": "#0a0a0a" },
  "scenes": [{ "id": "intro", "file": "scenes/intro.html", "start": 0, "duration": 10 }]
}
```

### Scene HTML — `data-dm-*` protocol

Every element annotated with `data-dm-*` becomes a layer:

```html
<div
  data-dm-id="title"
  data-dm-enter="fade-in"
  data-dm-enter-time="0.5"
  data-dm-duration="0.8"
  data-dm-easing="ease-out"
  data-dm-keyframe-opacity="0:0@ease-out; 0.5:1@ease-out; 9:1; 10:0@ease-in"
  style="color: white; font-size: 48px"
>
  Hello DevMotion
</div>
```

| Attribute                | Description                                         |
| ------------------------ | --------------------------------------------------- |
| `data-dm-id`             | Unique layer id (referenced by mutations)           |
| `data-dm-enter`          | Entry preset (`fade-in`, `slide-in-left`…)          |
| `data-dm-exit`           | Exit preset                                         |
| `data-dm-enter-time`     | Start time (seconds)                                |
| `data-dm-exit-time`      | End time (seconds)                                  |
| `data-dm-duration`       | Preset duration                                     |
| `data-dm-easing`         | Easing function                                     |
| `data-dm-keyframe-*`     | Per-property keyframes: `"time:value@strategy"`     |
| `data-dm-word-separator` | Optional separator for `word-reveal` text keyframes |
| `data-dm-grid-increment` | Grid step for `snap-grid` quantized keyframes       |
| `data-dm-track`          | Timeline track (z-order)                            |
| `data-dm-locked`         | Lock layer from edits                               |
| `data-dm-hidden`         | Hide layer                                          |

Keyframe strategies map to interpolation families automatically:

- Continuous easing: `linear`, `ease-out`, `ease-in-out`, `ease-out-quad`, etc.
- Discrete jumps: `step-start`, `step-end`, `step-mid`
- Quantized values: `integer`, `snap-grid` (set `data-dm-grid-increment`)
- Text reveals for `props.content`: `char-reveal`, `word-reveal`

```html
<dm-text
  data-dm-id="headline"
  transition-effects="fade,slide-up,blur"
  transition-duration="350"
  transition-easing="ease-in-quad"
  slide-distance="2.7"
  blur-amount="0.78"
  data-dm-keyframe-props-content="0:@char-reveal; 1.4:Welcome to DevMotion@char-reveal"
>
  Welcome to DevMotion
</dm-text>
```

For `dm-text`, `transition-effects` is a comma-separated list applied to each
new character/word as it appears. Useful effects include `fade`, `blur`,
`scale`, `slide-up`, `slide-down`, `slide-left`, and `slide-right`.

### Premium `<dm-*>` elements

For richer visuals, use the built-in custom elements:
`dm-phone`, `dm-laptop`, `dm-browser`, `dm-terminal`, `dm-captions`,
`dm-code`, `dm-video`, `dm-audio`, `dm-text`, `dm-image`, `dm-button`,
`dm-icon`, `dm-shape`, `dm-html`, `dm-mouse`, `dm-group`.

```html
<dm-phone
  data-dm-id="demo"
  data-dm-enter="slide-in-right"
  data-dm-enter-time="1.5"
  src="./assets/screen.mp4"
></dm-phone>
```

---

## Animation framework support

Scenes can include `<script>` blocks driving GSAP, Lottie, or any custom
animation library. DevMotion auto-detects the library, pauses its internal
clock, and drives it frame-by-frame from the timeline.

| Framework          | Detected via                 | How it's driven                              |
| ------------------ | ---------------------------- | -------------------------------------------- |
| GSAP               | `window.gsap.globalTimeline` | `globalTimeline.seek(t, false)`              |
| Lottie / bodymovin | `window.lottie`              | `goToAndStop(t * 1000, false)` per animation |

Detection is automatic — your scene HTML stays idiomatic, no DevMotion hooks
or boilerplate. Multiple frameworks coexist on the same scene (e.g. GSAP for
layout + Lottie for a logo).

Scaffold a scene with a framework template:

```bash
devmotion add-scene intro --with gsap     # GSAP CDN + sample tween
devmotion add-scene logo  --with lottie   # bodymovin player + sample load
devmotion add-scene blank --with bare     # empty body
```

Need support for another framework? Adapters live in
[`src/lib/layers/components/HtmlLayer.svelte`](../../src/lib/layers/components/HtmlLayer.svelte)
(`FRAMEWORK_ADAPTERS`) — a new adapter is ~10 lines and applies to every
project automatically once shipped.

---

## MCP — let an agent edit your project

`devmotion mcp` runs a local MCP server over **stdio**. Agents (Claude Code,
Cursor, Windsurf, …) spawn it inside your project directory to create/edit/remove
layers, configure the project, group layers, and apply animation presets —
every mutation writes back to your HTML files surgically (preserving formatting,
comments, and `<script>` blocks). It does not require `devmotion preview`,
network access, an account, or an API key.

```bash
devmotion mcp --print-config   # print the JSON config snippet to paste into your agent
```

The CLI MCP and the SaaS MCP share the same `mutations.ts` code path, so an
agent that knows how to drive one knows how to drive the other.

Install the Agent Skill and MCP configuration for Claude Code, Codex, or both:

```bash
npx @devmotion/cli setup
# Non-interactive:
npx @devmotion/cli setup --agent both --scope global
```

Global skills are installed to `~/.claude/skills/devmotion/SKILL.md` and
`~/.agents/skills/devmotion/SKILL.md`. Use `--scope project` for repository-local
configuration. The skill prefers the type-safe MCP operations over editing scene
HTML by hand.

---

## Two ways to use DevMotion

|             | **CLI / OSS** (this package)               | **SaaS** (devmotion.app) |
| ----------- | ------------------------------------------ | ------------------------ |
| Source      | Local filesystem (`devmotion.json` + HTML) | Cloud database           |
| Editor      | `devmotion preview` (browser)              | Hosted Studio            |
| Render      | Local ffmpeg + Playwright                  | Hosted GPU farm          |
| Auth        | None — all local                           | Account + plans          |
| Agent (MCP) | Local stdio (`devmotion mcp`)              | Remote HTTP              |

The OSS path is meant for **agents, devs, CI pipelines, and offline work**.
The SaaS path is the same engine with managed infrastructure.

---

## License

Apache-2.0. See [`LICENSE`](../../LICENSE).
