Doop
Doop: 오픈소스 멀티플레이어 디자인 캔버스 및 AI 에이전트용 MCP
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기CSS to Lottie converter: turn HTML + CSS animations (keyframes, transitions) and inline SVG into Lottie JSON. No After Effects needed.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Write animations in HTML + CSS, get a Lottie file. No After Effects needed.
Live demo: see every example as CSS and Lottie, side by side
css2lottie converts CSS @keyframes, transitions and inline SVG into Lottie JSON (Bodymovin 5.7+). The output plays in lottie-web, lottie-ios, lottie-android and Flutter.
npx css2lottie spinner.html -o spinner.json
ease, ease-in-out, cubic-bezier(...)) can be reproduced exactly, you get one Lottie keyframe with matching bezier handles instead of 60 keyframes per second. It falls back to per-frame sampling only where needed.box-shadow, filters or gradients.npm install --save-dev css2lottie
npx css2lottie install-browser # one-time: downloads the headless Chromium used for sampling
Requires Node.js 18.17+. If you already have Chrome/Chromium, you can skip install-browser and pass --executable-path (or set CSS2LOTTIE_CHROMIUM_PATH).
npx css2lottie input.html -o output.json --width 400 --height 400 --fps 60
| Flag | Description |
|---|---|
-o, --output <file> | Output file (default <input>.json, - for stdout). A .lottie name writes dotLottie |
--width, --height | Composition size in px (default: the root element's size with --selector, else 512) |
--fps <n> | Frame rate (default 60) |
-d, --duration <ms|s> | Duration (default: auto-detected from the longest animation; one loop for infinite) |
-s, --selector <css> | Convert only this root element (centered in the composition) |
--report | Print unsupported / approximated features |
--report-json <file> | Write the report as JSON |
--preview | Open a local page that plays the CSS original and the Lottie side by side |
-w, --watch | Re-convert on every save; with --preview the page reloads by itself |
--no-optimize | Disable easing optimization (per-frame keys, simplified) |
--font <family=file> | Font file used to convert text to outlines (repeatable) |
--background | Include the page background color as a layer |
--pretty | Pretty-print the JSON |
--executable-path <path> | Chromium/Chrome binary to use |
--preview starts a small local server and opens a comparison page. It has a shared scrubber, so you can step both versions to the same frame.
import { convert } from "css2lottie";
const lottie = await convert({ html, width: 400, height: 400, fps: 60 });
To get the report as well:
import { convertWithReport, formatReport } from "css2lottie";
const { lottie, report } = await convertWithReport({
file: "./animations/logo.html", // or `html` (string) / `url`
selector: "#logo", // optional: one root element
duration: 2000, // optional: ms (auto-detected by default)
fonts: { Inter: "./fonts/Inter-Bold.ttf" }, // optional: text → outlines
});
console.log(formatReport(report));
| Option | Default | Description |
|---|---|---|
html / file / url | — | Source document (one is required) |
baseUrl | — | Resolves relative URLs when passing an html string |
width, height | root size or 512 | Composition size |
fps | 60 | Frame rate |
duration | auto | Duration in ms |
selector | body | Root element to convert |
optimizeKeyframes | true | Emit bezier-eased keyframes when they reproduce the samples exactly |
fonts | {} | family → file map for text outlines |
background | false | Add the page background as a layer |
browser | launched per call | Reuse a Playwright Browser for batch conversions |
executablePath | Playwright's Chromium | Custom Chromium/Chrome binary |
Batch conversions can reuse one browser:
import { convert, launchBrowser } from "css2lottie";
const browser = await launchBrowser();
for (const file of files) await convert({ file, browser });
await browser.close();
Write a dotLottie (.lottie) file instead of JSON. It is a zip that the LottieFiles players and the mobile runtimes load directly; embedded images are stored as files, so it is usually much smaller:
import { writeFile } from "node:fs/promises";
import { convert, toDotLottie } from "css2lottie";
const lottie = await convert({ file: "./spinner.html" });
await writeFile("spinner.lottie", toDotLottie(lottie, { id: "spinner", loop: true }));
From the CLI, just pick a .lottie output name: npx css2lottie spinner.html -o spinner.lottie.
npx css2lottie anim.html --watch --preview converts on every save (of the HTML or any CSS, image or font next to it) and reloads the side-by-side preview, so you can tweak keyframes and see the Lottie update right away.
| CSS / SVG | Lottie output | Notes |
|---|---|---|
transform (translate, rotate, scale, skew, matrix), translate / rotate / scale | Layer position / rotation / scale / skew, anchor = transform-origin | 3D transforms are flattened to 2D, and backface-visibility is respected |
opacity, visibility | Layer opacity | Multiplied down the tree (Lottie parents don't pass opacity on) |
background-color | Fill | |
border (width, color per side) | Stroke, trimmed strokes (circles), or trapezoid fills | Rounded boxes with different sides are approximated |
border-radius | Rect roundness, ellipse, or a per-corner path | Elliptical and per-corner radii supported |
width / height / layout (left, top, margin, …) | Rect size + layer position | |
SVG <rect>, <circle>, <ellipse>, <path>, <polygon>, <polyline>, <line>, <g> | Shape layers with bezier paths, parented to the <svg> viewBox | Arcs, quadratics and relative commands are converted to cubics |
SVG fill, stroke, stroke-width, *-opacity, stroke-linecap/join, fill-rule | Fill / stroke | |
d: path(...) animation | Animated path | Needs the same number of points on every frame |
| Nested elements | Layer parenting | |
::before / ::after | Shape layers | Need to be absolutely positioned in a positioned host |
<img> | Image layer + base64 asset | |
| Text | Glyph outlines (shapes) | Needs a TTF/OTF/WOFF font file via @font-face or |
Some CSS has no Lottie equivalent yet. These features are ignored or approximated, and each one is listed in the report:
box-shadow, filter, backdrop-filter, mix-blend-mode, text-shadowlinear-gradient / radial-gradient and background images; SVG gradients and patternsclip-path, masks, and overflow: hidden clippingstroke-dasharray / stroke-dashoffset, so the "path drawing" effect doesn't carry overperspective: 3D is flattened to 2DrequestAnimationFrame, timers, scroll) and transitions triggered later than page loadSee ROADMAP.md for what's next. If the converter gets something wrong, please open an "Unsupported animation" issue and attach your HTML.
document.getAnimations() (CSS animations, transitions and Web Animations) are paused. Their timing and keyframes are recorded.animation.currentTime. The sampler records computed styles, the composed transform matrix, transform-origin and the untransformed layout box.src/converters/ map property families to Lottie data.examples/ contains 11 animations: spinner, bouncing ball, pulse, logo reveal, loading dots, checkmark, card flip, progress bar, heart beat, notification bell and text wave. Regenerate their Lottie files with npm run build && npm run examples. They also play on the live demo site, which npm run build && npm run site:serve builds and serves locally. The test suite converts each one, validates it against the Lottie JSON schema, checks it against a snapshot and compares lottie-web renders with the CSS renders.
css2lottie is free and MIT-licensed. If it saves you an After Effects license or a designer round-trip, please become a sponsor on GitHub. Our goal is $5,000 a month so css2lottie can be maintained full time and ship gradients, masks and path drawing sooner.
github.com/sponsors/99proteam (monthly or one-time) · One-off coffees are welcome too: buymeacoffee.com/99proteam
PRs are welcome. CONTRIBUTING.md explains how to add support for a new CSS property; each converter is one small file with a test.
MIT. Example font: Instrument Sans (SIL Open Font License, see examples/fonts/).
fonts@keyframes, transitions triggered on load, element.animate() | Keyframes | delay, iteration-count, direction, fill-mode and playback rate |
ease, ease-in, ease-out, ease-in-out, cubic-bezier(), linear | Bezier keyframe easing | steps() and linear(...) stops are sampled per frame |
animation-iteration-count: infinite | A seamless loop | The duration is the LCM of the loop periods, starting from the steady state |