init repo
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
.DS_Store
|
||||||
|
node_modules/
|
||||||
|
repos/
|
||||||
|
*.log
|
||||||
3
.memory/worklog.json
Normal file
3
.memory/worklog.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"entries": []
|
||||||
|
}
|
||||||
30
.project.json
Normal file
30
.project.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "Vibe Motion",
|
||||||
|
"description": "Remotion 动效视频项目 — 用 AI 写代码生成专业动画视频",
|
||||||
|
"status": "active",
|
||||||
|
"kind": "app",
|
||||||
|
"created": "2026-03-19",
|
||||||
|
"ports": [
|
||||||
|
{
|
||||||
|
"port": 4062,
|
||||||
|
"label": "dev",
|
||||||
|
"fixed": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stack": [
|
||||||
|
"Remotion",
|
||||||
|
"React",
|
||||||
|
"TypeScript"
|
||||||
|
],
|
||||||
|
"urls": [
|
||||||
|
{
|
||||||
|
"url": "http://localhost:4062",
|
||||||
|
"type": "app",
|
||||||
|
"label": "local"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"worklog": {
|
||||||
|
"path": ".memory/worklog.json",
|
||||||
|
"auto": true
|
||||||
|
}
|
||||||
|
}
|
||||||
21
AGENTS.md
Normal file
21
AGENTS.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Vibe Motion Agent Rules
|
||||||
|
|
||||||
|
## Must Read First
|
||||||
|
|
||||||
|
- `.project.json` 是机器真源:公网链接、快捷登录、凭证引用都以它为准
|
||||||
|
- `RULES.md` 是人工规则和部署事实:启动命令、平台、域名、注意事项都写这里
|
||||||
|
- 不允许编造不存在的域名、账号、密码;未知就保持空白并明确标记待补充
|
||||||
|
|
||||||
|
## Deployment Metadata Contract
|
||||||
|
|
||||||
|
- 任何任务只要新增、删除或修改公网地址,必须在同一次任务里更新 `.project.json`
|
||||||
|
- `urls[]` 推荐显式写 `type`:`app`、`backend`、`docs`、`admin`、`repo`
|
||||||
|
- 项目专属的网页登录信息,如果允许放进仓库,就写 `.project.json.quick_login`
|
||||||
|
- 不能直接入库的敏感登录,不要伪造 `quick_login`,改为写 `.project.json.credentials` 引用
|
||||||
|
- 数据库密码、API Key、服务器 root 密码,不属于 `quick_login`
|
||||||
|
|
||||||
|
## Completion Gate
|
||||||
|
|
||||||
|
- 部署完成后,不允许在 `.project.json` 缺少最新公网链接的状态下结束任务
|
||||||
|
- 部署完成后,必须同步更新 `RULES.md` 的部署事实
|
||||||
|
- 如果只更新了代码但没回写部署元数据,这个任务不算完成
|
||||||
21
CLAUDE.md
Normal file
21
CLAUDE.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Vibe Motion Agent Rules
|
||||||
|
|
||||||
|
## Must Read First
|
||||||
|
|
||||||
|
- `.project.json` 是机器真源:公网链接、快捷登录、凭证引用都以它为准
|
||||||
|
- `RULES.md` 是人工规则和部署事实:启动命令、平台、域名、注意事项都写这里
|
||||||
|
- 不允许编造不存在的域名、账号、密码;未知就保持空白并明确标记待补充
|
||||||
|
|
||||||
|
## Deployment Metadata Contract
|
||||||
|
|
||||||
|
- 任何任务只要新增、删除或修改公网地址,必须在同一次任务里更新 `.project.json`
|
||||||
|
- `urls[]` 推荐显式写 `type`:`app`、`backend`、`docs`、`admin`、`repo`
|
||||||
|
- 项目专属的网页登录信息,如果允许放进仓库,就写 `.project.json.quick_login`
|
||||||
|
- 不能直接入库的敏感登录,不要伪造 `quick_login`,改为写 `.project.json.credentials` 引用
|
||||||
|
- 数据库密码、API Key、服务器 root 密码,不属于 `quick_login`
|
||||||
|
|
||||||
|
## Completion Gate
|
||||||
|
|
||||||
|
- 部署完成后,不允许在 `.project.json` 缺少最新公网链接的状态下结束任务
|
||||||
|
- 部署完成后,必须同步更新 `RULES.md` 的部署事实
|
||||||
|
- 如果只更新了代码但没回写部署元数据,这个任务不算完成
|
||||||
37
RULES.md
Normal file
37
RULES.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# Vibe Motion
|
||||||
|
|
||||||
|
## 启动
|
||||||
|
- `dev` — 端口 4062
|
||||||
|
|
||||||
|
## 部署事实
|
||||||
|
- 平台:待定
|
||||||
|
- 发布状态:已部署
|
||||||
|
- 主站 / 前端:http://localhost:4062
|
||||||
|
- API / 后端:待定
|
||||||
|
- 文档 / 解析:待定
|
||||||
|
- 管理后台:待定
|
||||||
|
- 代码仓:待定
|
||||||
|
|
||||||
|
## 快捷登录
|
||||||
|
- 登录地址:待补充
|
||||||
|
- 用户名:待补充
|
||||||
|
- 密码:待补充
|
||||||
|
- 说明:这里只写项目专属网页登录;数据库密码、API Key、服务器 root 密码不要写这里
|
||||||
|
|
||||||
|
## 元数据回写清单
|
||||||
|
- 新增或变更公网地址后,必须同步更新 `.project.json.urls`
|
||||||
|
- 如果有网页后台登录:
|
||||||
|
- 可直接入库:写 `.project.json.quick_login`
|
||||||
|
- 不应入库:写 `.project.json.credentials` 引用
|
||||||
|
- 部署完成后,`RULES.md` 和 `.project.json` 必须同一次任务一起更新
|
||||||
|
|
||||||
|
## 环境变量
|
||||||
|
- 待补充
|
||||||
|
|
||||||
|
## 规则
|
||||||
|
- 不允许编造不存在的部署域名、账号、密码
|
||||||
|
- 没有公网地址时,`.project.json.urls` 保持空数组
|
||||||
|
- 任何部署或域名变化,都要先改元数据,再视为任务完成
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
- 待补充
|
||||||
857
index.html
Normal file
857
index.html
Normal file
@@ -0,0 +1,857 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Vibe Motion — AI 动效革命深度解析</title>
|
||||||
|
<style>
|
||||||
|
/* ===== Reset & Base ===== */
|
||||||
|
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
:root {
|
||||||
|
--bg: #08090d;
|
||||||
|
--bg2: #0d0f15;
|
||||||
|
--surface: rgba(255,255,255,0.04);
|
||||||
|
--surface2: rgba(255,255,255,0.07);
|
||||||
|
--border: rgba(255,255,255,0.08);
|
||||||
|
--text: #e8e8ec;
|
||||||
|
--text2: rgba(255,255,255,0.55);
|
||||||
|
--accent: #00ff8c;
|
||||||
|
--accent2: #00ccff;
|
||||||
|
--purple: #a855f7;
|
||||||
|
--pink: #ff44aa;
|
||||||
|
--orange: #ff9500;
|
||||||
|
--glow: 0 0 60px rgba(0,255,140,0.15);
|
||||||
|
}
|
||||||
|
html { scroll-behavior: smooth; }
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, 'SF Pro Display', 'Inter', system-ui, sans-serif;
|
||||||
|
background: var(--bg);
|
||||||
|
color: var(--text);
|
||||||
|
line-height: 1.7;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
a { color: var(--accent); text-decoration: none; transition: opacity .2s; }
|
||||||
|
a:hover { opacity: .8; }
|
||||||
|
|
||||||
|
/* ===== Ambient Background ===== */
|
||||||
|
.ambient {
|
||||||
|
position: fixed; inset: 0; z-index: 0; pointer-events: none;
|
||||||
|
background:
|
||||||
|
radial-gradient(ellipse 800px 600px at 20% 30%, rgba(0,255,140,0.04) 0%, transparent 70%),
|
||||||
|
radial-gradient(ellipse 600px 500px at 80% 60%, rgba(0,200,255,0.03) 0%, transparent 70%),
|
||||||
|
radial-gradient(ellipse 500px 400px at 50% 80%, rgba(168,85,247,0.03) 0%, transparent 70%);
|
||||||
|
}
|
||||||
|
.grid-bg {
|
||||||
|
position: fixed; inset: 0; z-index: 0; pointer-events: none;
|
||||||
|
background-image:
|
||||||
|
linear-gradient(rgba(255,255,255,0.02) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(255,255,255,0.02) 1px, transparent 1px);
|
||||||
|
background-size: 60px 60px;
|
||||||
|
mask-image: radial-gradient(ellipse 80% 60% at 50% 40%, black, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Layout ===== */
|
||||||
|
.container { max-width: 1200px; margin: 0 auto; padding: 0 24px; position: relative; z-index: 1; }
|
||||||
|
section { padding: 100px 0; }
|
||||||
|
|
||||||
|
/* ===== Hero ===== */
|
||||||
|
.hero {
|
||||||
|
min-height: 100vh; display: flex; flex-direction: column;
|
||||||
|
align-items: center; justify-content: center; text-align: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.hero-badge {
|
||||||
|
display: inline-flex; align-items: center; gap: 8px;
|
||||||
|
padding: 6px 16px; border-radius: 100px;
|
||||||
|
background: rgba(0,255,140,0.08); border: 1px solid rgba(0,255,140,0.2);
|
||||||
|
font-size: 13px; color: var(--accent); letter-spacing: 2px;
|
||||||
|
text-transform: uppercase; margin-bottom: 32px;
|
||||||
|
animation: fadeInUp .8s ease both;
|
||||||
|
}
|
||||||
|
.hero-badge::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); animation: pulse 2s infinite; }
|
||||||
|
.hero h1 {
|
||||||
|
font-size: clamp(48px, 8vw, 96px); font-weight: 800;
|
||||||
|
letter-spacing: -3px; line-height: 1.05;
|
||||||
|
background: linear-gradient(135deg, #fff 0%, var(--accent) 50%, var(--accent2) 100%);
|
||||||
|
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
|
||||||
|
animation: fadeInUp .8s .1s ease both;
|
||||||
|
}
|
||||||
|
.hero p {
|
||||||
|
font-size: clamp(16px, 2vw, 22px); color: var(--text2);
|
||||||
|
max-width: 680px; margin: 24px auto 0;
|
||||||
|
animation: fadeInUp .8s .2s ease both;
|
||||||
|
}
|
||||||
|
.hero-cta {
|
||||||
|
display: flex; gap: 16px; margin-top: 48px;
|
||||||
|
animation: fadeInUp .8s .3s ease both;
|
||||||
|
}
|
||||||
|
.btn {
|
||||||
|
padding: 14px 32px; border-radius: 12px; font-size: 15px; font-weight: 600;
|
||||||
|
cursor: pointer; border: none; transition: all .3s;
|
||||||
|
}
|
||||||
|
.btn-primary {
|
||||||
|
background: var(--accent); color: #000;
|
||||||
|
box-shadow: 0 0 30px rgba(0,255,140,0.3);
|
||||||
|
}
|
||||||
|
.btn-primary:hover { box-shadow: 0 0 50px rgba(0,255,140,0.5); transform: translateY(-2px); }
|
||||||
|
.btn-ghost {
|
||||||
|
background: var(--surface2); color: var(--text);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
.btn-ghost:hover { background: rgba(255,255,255,0.1); transform: translateY(-2px); }
|
||||||
|
|
||||||
|
.scroll-hint {
|
||||||
|
position: absolute; bottom: 40px;
|
||||||
|
display: flex; flex-direction: column; align-items: center; gap: 8px;
|
||||||
|
color: var(--text2); font-size: 12px; letter-spacing: 2px;
|
||||||
|
animation: bounce 2s infinite;
|
||||||
|
}
|
||||||
|
.scroll-hint svg { width: 20px; height: 20px; stroke: var(--text2); }
|
||||||
|
|
||||||
|
/* ===== Section Headers ===== */
|
||||||
|
.section-tag {
|
||||||
|
display: inline-flex; align-items: center; gap: 8px;
|
||||||
|
font-size: 12px; letter-spacing: 3px; text-transform: uppercase;
|
||||||
|
color: var(--accent); margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.section-tag::before { content: ''; width: 24px; height: 1px; background: var(--accent); }
|
||||||
|
.section-title {
|
||||||
|
font-size: clamp(32px, 4vw, 52px); font-weight: 800;
|
||||||
|
letter-spacing: -1.5px; margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.section-desc { color: var(--text2); font-size: 17px; max-width: 640px; margin-bottom: 48px; }
|
||||||
|
|
||||||
|
/* ===== Paradigm Shift Section ===== */
|
||||||
|
.paradigm-grid {
|
||||||
|
display: grid; grid-template-columns: 1fr 80px 1fr; gap: 24px; align-items: stretch;
|
||||||
|
}
|
||||||
|
.paradigm-card {
|
||||||
|
background: var(--surface); border: 1px solid var(--border);
|
||||||
|
border-radius: 20px; padding: 36px; position: relative; overflow: hidden;
|
||||||
|
}
|
||||||
|
.paradigm-card::before {
|
||||||
|
content: ''; position: absolute; inset: 0; opacity: 0;
|
||||||
|
transition: opacity .4s;
|
||||||
|
}
|
||||||
|
.paradigm-card:hover::before { opacity: 1; }
|
||||||
|
.paradigm-card.old::before { background: radial-gradient(circle at 50% 0, rgba(255,68,68,0.06), transparent 60%); }
|
||||||
|
.paradigm-card.new::before { background: radial-gradient(circle at 50% 0, rgba(0,255,140,0.08), transparent 60%); }
|
||||||
|
.paradigm-card h3 { font-size: 22px; margin-bottom: 20px; display: flex; align-items: center; gap: 12px; }
|
||||||
|
.paradigm-card ul { list-style: none; }
|
||||||
|
.paradigm-card li {
|
||||||
|
padding: 10px 0; border-bottom: 1px solid var(--border);
|
||||||
|
font-size: 14px; color: var(--text2); display: flex; align-items: center; gap: 10px;
|
||||||
|
}
|
||||||
|
.paradigm-card li:last-child { border-bottom: none; }
|
||||||
|
.paradigm-card.old li::before { content: '✕'; color: #ff4444; font-size: 12px; font-weight: 700; }
|
||||||
|
.paradigm-card.new li::before { content: '✓'; color: var(--accent); font-size: 14px; font-weight: 700; }
|
||||||
|
.vs-divider {
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
font-size: 18px; font-weight: 900; color: var(--text2);
|
||||||
|
background: var(--surface); border-radius: 50%;
|
||||||
|
width: 56px; height: 56px; margin: auto;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== How It Works ===== */
|
||||||
|
.flow-steps {
|
||||||
|
display: grid; grid-template-columns: repeat(4, 1fr); gap: 2px;
|
||||||
|
}
|
||||||
|
.flow-step {
|
||||||
|
background: var(--surface); padding: 32px 24px; position: relative;
|
||||||
|
border: 1px solid var(--border); overflow: hidden;
|
||||||
|
transition: all .3s;
|
||||||
|
}
|
||||||
|
.flow-step:first-child { border-radius: 16px 0 0 16px; }
|
||||||
|
.flow-step:last-child { border-radius: 0 16px 16px 0; }
|
||||||
|
.flow-step:hover { background: var(--surface2); transform: translateY(-4px); border-color: rgba(0,255,140,0.2); }
|
||||||
|
.flow-step .step-num {
|
||||||
|
font-size: 48px; font-weight: 900;
|
||||||
|
background: linear-gradient(135deg, var(--accent), var(--accent2));
|
||||||
|
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
|
||||||
|
opacity: .3; position: absolute; top: 16px; right: 16px;
|
||||||
|
}
|
||||||
|
.flow-step h4 { font-size: 16px; margin-bottom: 8px; }
|
||||||
|
.flow-step p { font-size: 13px; color: var(--text2); line-height: 1.6; }
|
||||||
|
.flow-arrow { color: var(--accent); font-size: 20px; margin: 0 -8px; z-index: 1; align-self: center; }
|
||||||
|
|
||||||
|
/* ===== Ecosystem ===== */
|
||||||
|
.eco-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
|
||||||
|
.eco-card {
|
||||||
|
background: var(--surface); border: 1px solid var(--border);
|
||||||
|
border-radius: 16px; padding: 28px; transition: all .4s;
|
||||||
|
position: relative; overflow: hidden;
|
||||||
|
}
|
||||||
|
.eco-card:hover {
|
||||||
|
transform: translateY(-6px);
|
||||||
|
border-color: rgba(0,255,140,0.25);
|
||||||
|
box-shadow: var(--glow);
|
||||||
|
}
|
||||||
|
.eco-card .eco-icon {
|
||||||
|
width: 48px; height: 48px; border-radius: 12px;
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
font-size: 22px; margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
.eco-card h3 { font-size: 18px; margin-bottom: 4px; }
|
||||||
|
.eco-card .eco-tag {
|
||||||
|
font-size: 11px; color: var(--accent); letter-spacing: 1px;
|
||||||
|
text-transform: uppercase; margin-bottom: 12px; display: block;
|
||||||
|
}
|
||||||
|
.eco-card p { font-size: 13px; color: var(--text2); line-height: 1.6; margin-bottom: 16px; }
|
||||||
|
.eco-card .eco-meta {
|
||||||
|
display: flex; gap: 16px; font-size: 12px; color: var(--text2);
|
||||||
|
border-top: 1px solid var(--border); padding-top: 12px;
|
||||||
|
}
|
||||||
|
.eco-card .eco-meta span { display: flex; align-items: center; gap: 4px; }
|
||||||
|
.eco-card .eco-meta .stars { color: var(--orange); }
|
||||||
|
|
||||||
|
/* ===== Comparison Table ===== */
|
||||||
|
.compare-table {
|
||||||
|
width: 100%; border-collapse: separate; border-spacing: 0;
|
||||||
|
background: var(--surface); border-radius: 16px; overflow: hidden;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
.compare-table th, .compare-table td {
|
||||||
|
padding: 16px 20px; text-align: left; border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
.compare-table th {
|
||||||
|
font-size: 12px; text-transform: uppercase; letter-spacing: 2px;
|
||||||
|
color: var(--text2); background: rgba(255,255,255,0.02);
|
||||||
|
}
|
||||||
|
.compare-table td { font-size: 14px; color: var(--text2); }
|
||||||
|
.compare-table tr:last-child td { border-bottom: none; }
|
||||||
|
.compare-table td:first-child { color: var(--text); font-weight: 600; }
|
||||||
|
.compare-table .check { color: var(--accent); }
|
||||||
|
.compare-table .cross { color: rgba(255,255,255,0.2); }
|
||||||
|
.highlight-row { background: rgba(0,255,140,0.03); }
|
||||||
|
|
||||||
|
/* ===== Use Cases ===== */
|
||||||
|
.use-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; }
|
||||||
|
.use-card {
|
||||||
|
background: var(--surface); border: 1px solid var(--border);
|
||||||
|
border-radius: 16px; padding: 28px; transition: all .3s;
|
||||||
|
display: flex; gap: 20px;
|
||||||
|
}
|
||||||
|
.use-card:hover { border-color: rgba(0,255,140,0.2); transform: translateY(-3px); }
|
||||||
|
.use-icon {
|
||||||
|
width: 52px; height: 52px; border-radius: 14px; flex-shrink: 0;
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
.use-card h4 { font-size: 16px; margin-bottom: 6px; }
|
||||||
|
.use-card p { font-size: 13px; color: var(--text2); }
|
||||||
|
|
||||||
|
/* ===== Timeline ===== */
|
||||||
|
.timeline { position: relative; padding-left: 40px; }
|
||||||
|
.timeline::before {
|
||||||
|
content: ''; position: absolute; left: 14px; top: 0; bottom: 0;
|
||||||
|
width: 2px; background: linear-gradient(to bottom, var(--accent), var(--purple), transparent);
|
||||||
|
}
|
||||||
|
.timeline-item {
|
||||||
|
position: relative; margin-bottom: 36px; padding: 20px 24px;
|
||||||
|
background: var(--surface); border: 1px solid var(--border);
|
||||||
|
border-radius: 14px;
|
||||||
|
}
|
||||||
|
.timeline-item::before {
|
||||||
|
content: ''; position: absolute; left: -33px; top: 24px;
|
||||||
|
width: 10px; height: 10px; border-radius: 50%;
|
||||||
|
background: var(--accent); box-shadow: 0 0 12px rgba(0,255,140,0.5);
|
||||||
|
}
|
||||||
|
.timeline-item .date {
|
||||||
|
font-size: 12px; color: var(--accent); letter-spacing: 1px;
|
||||||
|
text-transform: uppercase; margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
.timeline-item h4 { font-size: 16px; margin-bottom: 6px; }
|
||||||
|
.timeline-item p { font-size: 13px; color: var(--text2); }
|
||||||
|
|
||||||
|
/* ===== Code Demo ===== */
|
||||||
|
.code-block {
|
||||||
|
background: #0a0c12; border: 1px solid var(--border);
|
||||||
|
border-radius: 14px; overflow: hidden; margin: 32px 0;
|
||||||
|
}
|
||||||
|
.code-header {
|
||||||
|
display: flex; align-items: center; gap: 8px; padding: 14px 20px;
|
||||||
|
background: rgba(255,255,255,0.02); border-bottom: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
.code-dot { width: 12px; height: 12px; border-radius: 50%; }
|
||||||
|
.code-dot.r { background: #ff5f57; }
|
||||||
|
.code-dot.y { background: #febc2e; }
|
||||||
|
.code-dot.g { background: #28c840; }
|
||||||
|
.code-filename { margin-left: 12px; font-size: 13px; color: var(--text2); font-family: 'SF Mono', monospace; }
|
||||||
|
.code-content {
|
||||||
|
padding: 20px 24px; font-family: 'SF Mono', 'Fira Code', monospace;
|
||||||
|
font-size: 13px; line-height: 1.8; overflow-x: auto;
|
||||||
|
color: #abb2bf;
|
||||||
|
}
|
||||||
|
.code-content .kw { color: #c678dd; }
|
||||||
|
.code-content .fn { color: #61afef; }
|
||||||
|
.code-content .str { color: #98c379; }
|
||||||
|
.code-content .num { color: #d19a66; }
|
||||||
|
.code-content .cm { color: #5c6370; font-style: italic; }
|
||||||
|
.code-content .tag { color: #e06c75; }
|
||||||
|
.code-content .attr { color: #d19a66; }
|
||||||
|
|
||||||
|
/* ===== Quick Start ===== */
|
||||||
|
.quickstart-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
|
||||||
|
.qs-card {
|
||||||
|
background: var(--surface); border: 1px solid var(--border);
|
||||||
|
border-radius: 16px; padding: 28px; text-align: center;
|
||||||
|
transition: all .3s;
|
||||||
|
}
|
||||||
|
.qs-card:hover { border-color: rgba(0,255,140,0.25); transform: translateY(-4px); }
|
||||||
|
.qs-card .qs-num {
|
||||||
|
width: 40px; height: 40px; border-radius: 50%;
|
||||||
|
background: rgba(0,255,140,0.1); border: 1px solid rgba(0,255,140,0.2);
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
font-size: 16px; font-weight: 800; color: var(--accent);
|
||||||
|
margin: 0 auto 16px;
|
||||||
|
}
|
||||||
|
.qs-card h4 { font-size: 16px; margin-bottom: 8px; }
|
||||||
|
.qs-card code {
|
||||||
|
display: inline-block; padding: 8px 16px; border-radius: 8px;
|
||||||
|
background: rgba(0,0,0,0.4); border: 1px solid var(--border);
|
||||||
|
font-family: 'SF Mono', monospace; font-size: 13px; color: var(--accent);
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Footer ===== */
|
||||||
|
footer {
|
||||||
|
border-top: 1px solid var(--border); padding: 48px 0;
|
||||||
|
text-align: center; color: var(--text2); font-size: 13px;
|
||||||
|
}
|
||||||
|
footer .footer-links { display: flex; justify-content: center; gap: 32px; margin-bottom: 24px; }
|
||||||
|
|
||||||
|
/* ===== Animations ===== */
|
||||||
|
@keyframes fadeInUp {
|
||||||
|
from { opacity: 0; transform: translateY(30px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .4; } }
|
||||||
|
@keyframes bounce {
|
||||||
|
0%, 100% { transform: translateY(0); }
|
||||||
|
50% { transform: translateY(8px); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IntersectionObserver reveal */
|
||||||
|
.reveal { opacity: 0; transform: translateY(40px); transition: all .7s cubic-bezier(.22,1,.36,1); }
|
||||||
|
.reveal.visible { opacity: 1; transform: translateY(0); }
|
||||||
|
|
||||||
|
/* ===== Responsive ===== */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.paradigm-grid { grid-template-columns: 1fr; }
|
||||||
|
.vs-divider { margin: -8px auto; }
|
||||||
|
.flow-steps { grid-template-columns: 1fr; }
|
||||||
|
.flow-step { border-radius: 12px !important; }
|
||||||
|
.eco-grid, .quickstart-grid { grid-template-columns: 1fr; }
|
||||||
|
.use-grid { grid-template-columns: 1fr; }
|
||||||
|
.compare-table { font-size: 12px; }
|
||||||
|
.compare-table th, .compare-table td { padding: 10px 12px; }
|
||||||
|
section { padding: 60px 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Floating Lizard ===== */
|
||||||
|
.float-lizard {
|
||||||
|
position: fixed; bottom: 24px; right: 24px; z-index: 100;
|
||||||
|
width: 60px; height: 60px; border-radius: 50%;
|
||||||
|
background: rgba(0,255,140,0.1); border: 1px solid rgba(0,255,140,0.3);
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
font-size: 28px; cursor: pointer; transition: all .3s;
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
|
}
|
||||||
|
.float-lizard:hover {
|
||||||
|
transform: scale(1.1); box-shadow: 0 0 30px rgba(0,255,140,0.3);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="ambient"></div>
|
||||||
|
<div class="grid-bg"></div>
|
||||||
|
|
||||||
|
<!-- ===== HERO ===== -->
|
||||||
|
<section class="hero">
|
||||||
|
<div class="hero-badge">2026 新范式</div>
|
||||||
|
<h1>Vibe Motion</h1>
|
||||||
|
<p>不再逐帧调关键帧,不再等 AI 生成模糊像素。用自然语言描述动画意图,AI 生成确定性代码,渲染出 4K/60fps 专业级动效视频。</p>
|
||||||
|
<div class="hero-cta">
|
||||||
|
<a href="#ecosystem" class="btn btn-primary">开源生态 ↓</a>
|
||||||
|
<a href="#quickstart" class="btn btn-ghost">快速开始</a>
|
||||||
|
</div>
|
||||||
|
<div class="scroll-hint">
|
||||||
|
<svg viewBox="0 0 24 24" fill="none" stroke-width="2"><path d="M12 5v14M19 12l-7 7-7-7"/></svg>
|
||||||
|
SCROLL
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ===== PARADIGM SHIFT ===== -->
|
||||||
|
<section id="paradigm">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-tag">范式转移</div>
|
||||||
|
<h2 class="section-title reveal">从像素预测到代码生成</h2>
|
||||||
|
<p class="section-desc reveal">传统 AI 视频逐帧预测像素,文字会糊、元素会飘、不可编辑。<br>Vibe Motion 让 AI 生成 Remotion 代码——数学定义运动,确定性渲染,每一帧都精确。</p>
|
||||||
|
|
||||||
|
<div class="paradigm-grid reveal">
|
||||||
|
<!-- Old Way -->
|
||||||
|
<div class="paradigm-card old">
|
||||||
|
<h3><span style="font-size:28px">🎬</span> 传统方式</h3>
|
||||||
|
<ul>
|
||||||
|
<li>After Effects 手动调关键帧,学习曲线陡峭</li>
|
||||||
|
<li>AI 视频生成器(Sora/Kling)预测像素,文字变形</li>
|
||||||
|
<li>输出不可编辑,修改需重新生成</li>
|
||||||
|
<li>分辨率受限,放大即模糊</li>
|
||||||
|
<li>数万元 + 数周制作周期</li>
|
||||||
|
<li>品牌一致性难以保证</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="vs-divider">VS</div>
|
||||||
|
|
||||||
|
<!-- New Way -->
|
||||||
|
<div class="paradigm-card new">
|
||||||
|
<h3><span style="font-size:28px">⚡</span> Vibe Motion</h3>
|
||||||
|
<ul>
|
||||||
|
<li>自然语言描述 → AI 生成 React 动画代码</li>
|
||||||
|
<li>确定性渲染,文字永远清晰锐利</li>
|
||||||
|
<li>代码可编辑,迭代只需追加对话</li>
|
||||||
|
<li>原生支持 4K UHD / 60fps</li>
|
||||||
|
<li>10 分钟完成,成本趋近于零</li>
|
||||||
|
<li>代码即品牌规范,100% 一致</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ===== HOW IT WORKS ===== -->
|
||||||
|
<section id="howitworks" style="background: var(--bg2);">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-tag">工作原理</div>
|
||||||
|
<h2 class="section-title reveal">四步生成专业动效</h2>
|
||||||
|
<p class="section-desc reveal">从自然语言到 MP4 视频,中间是可审查、可编辑、可版本控制的代码。</p>
|
||||||
|
|
||||||
|
<div class="flow-steps reveal">
|
||||||
|
<div class="flow-step">
|
||||||
|
<div class="step-num">01</div>
|
||||||
|
<h4>描述意图</h4>
|
||||||
|
<p>用自然语言描述你想要的动画效果。"一只绿色蜥蜴从左侧滑入,尾巴摆动,舌头弹射捕捉萤火虫"</p>
|
||||||
|
</div>
|
||||||
|
<div class="flow-step">
|
||||||
|
<div class="step-num">02</div>
|
||||||
|
<h4>AI 生成代码</h4>
|
||||||
|
<p>Claude / GPT 将创意意图翻译为 Remotion React 组件代码,包含 spring 动画、插值、序列编排</p>
|
||||||
|
</div>
|
||||||
|
<div class="flow-step">
|
||||||
|
<div class="step-num">03</div>
|
||||||
|
<h4>实时预览</h4>
|
||||||
|
<p>Remotion Studio 在浏览器中实时预览,可拖拽时间轴、逐帧检查、热更新代码修改</p>
|
||||||
|
</div>
|
||||||
|
<div class="flow-step">
|
||||||
|
<div class="step-num">04</div>
|
||||||
|
<h4>渲染输出</h4>
|
||||||
|
<p>一行命令渲染为 MP4/GIF/WebM,支持 4K 分辨率、60fps、透明通道,可批量生成万级变体</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ===== CODE DEMO ===== -->
|
||||||
|
<section id="code">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-tag">代码即动画</div>
|
||||||
|
<h2 class="section-title reveal">一段对话,一个动画</h2>
|
||||||
|
<p class="section-desc reveal">你说"蜥蜴摆尾",AI 生成这样的代码——数学精确、完全可控。</p>
|
||||||
|
|
||||||
|
<div class="code-block reveal">
|
||||||
|
<div class="code-header">
|
||||||
|
<span class="code-dot r"></span>
|
||||||
|
<span class="code-dot y"></span>
|
||||||
|
<span class="code-dot g"></span>
|
||||||
|
<span class="code-filename">LizardScene.tsx</span>
|
||||||
|
</div>
|
||||||
|
<div class="code-content">
|
||||||
|
<span class="cm">// 弹簧物理入场</span>
|
||||||
|
<span class="kw">const</span> scaleSpring = <span class="fn">spring</span>({
|
||||||
|
fps, frame: localFrame,
|
||||||
|
config: { damping: <span class="num">12</span>, stiffness: <span class="num">80</span> }
|
||||||
|
});
|
||||||
|
|
||||||
|
<span class="cm">// 尾巴正弦摆动</span>
|
||||||
|
<span class="kw">const</span> tailWag = Math.<span class="fn">sin</span>(localFrame * <span class="num">0.15</span>) * <span class="num">8</span>;
|
||||||
|
|
||||||
|
<span class="cm">// 舌头弹射 — 每80帧触发一次</span>
|
||||||
|
<span class="kw">const</span> tonguePhase = (localFrame % <span class="num">80</span>) / <span class="num">80</span>;
|
||||||
|
<span class="kw">const</span> tongueOut = tonguePhase > <span class="num">0.3</span> && tonguePhase < <span class="num">0.5</span>
|
||||||
|
? <span class="fn">interpolate</span>(tonguePhase, [<span class="num">0.3</span>, <span class="num">0.4</span>, <span class="num">0.5</span>], [<span class="num">0</span>, <span class="num">1</span>, <span class="num">0</span>])
|
||||||
|
: <span class="num">0</span>;
|
||||||
|
|
||||||
|
<span class="cm">// SVG 路径 + 渐变 + 发光</span>
|
||||||
|
<<span class="tag">path</span> <span class="attr">d</span>=<span class="str">{LIZARD_TAIL}</span>
|
||||||
|
<span class="attr">transform</span>=<span class="str">{`rotate(${tailWag}, 200, 33)`}</span>
|
||||||
|
<span class="attr">filter</span>=<span class="str">{`drop-shadow(0 0 ${glow}px ${color})`}</span> />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ===== ECOSYSTEM ===== -->
|
||||||
|
<section id="ecosystem" style="background: var(--bg2);">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-tag">开源生态</div>
|
||||||
|
<h2 class="section-title reveal">六大核心项目</h2>
|
||||||
|
<p class="section-desc reveal">Vibe Motion 不是一个工具,而是一个由开源项目构成的创作范式。以下是你需要关注的核心项目。</p>
|
||||||
|
|
||||||
|
<div class="eco-grid">
|
||||||
|
<!-- Remotion -->
|
||||||
|
<div class="eco-card reveal">
|
||||||
|
<div class="eco-icon" style="background: rgba(0,255,140,0.1); color: var(--accent);">🎥</div>
|
||||||
|
<h3>Remotion</h3>
|
||||||
|
<span class="eco-tag">核心引擎 · Vibe Motion 底层</span>
|
||||||
|
<p>用 React 编程式生成视频。支持 CSS/Canvas/SVG/WebGL,确定性逐帧渲染,可本地或云端批量生成。Higgsfield Vibe Motion 就是基于它。</p>
|
||||||
|
<div class="eco-meta">
|
||||||
|
<span class="stars">★ 25,000+</span>
|
||||||
|
<span>TypeScript</span>
|
||||||
|
<span><a href="https://github.com/remotion-dev/remotion">GitHub ↗</a></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Motion -->
|
||||||
|
<div class="eco-card reveal">
|
||||||
|
<div class="eco-icon" style="background: rgba(168,85,247,0.1); color: var(--purple);">✨</div>
|
||||||
|
<h3>Motion (Framer Motion)</h3>
|
||||||
|
<span class="eco-tag">网页动画之王</span>
|
||||||
|
<p>npm 月下载 3000万+,最主流的 React 动画库。已官方支持 AI Vibe Coding 工作流,Motion Studio 插件可在 VS Code 中实时编辑动画。</p>
|
||||||
|
<div class="eco-meta">
|
||||||
|
<span class="stars">★ 26,000+</span>
|
||||||
|
<span>TypeScript</span>
|
||||||
|
<span><a href="https://github.com/motiondivision/motion">GitHub ↗</a></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Motion Canvas -->
|
||||||
|
<div class="eco-card reveal">
|
||||||
|
<div class="eco-icon" style="background: rgba(0,200,255,0.1); color: var(--accent2);">🎨</div>
|
||||||
|
<h3>Motion Canvas</h3>
|
||||||
|
<span class="eco-tag">TypeScript 版 Manim</span>
|
||||||
|
<p>用 TypeScript 创建教育动画和解释视频,类似 3Blue1Brown 的 Manim 但基于 Web 技术栈。内置可视化编辑器和时间轴。</p>
|
||||||
|
<div class="eco-meta">
|
||||||
|
<span class="stars">★ 16,000+</span>
|
||||||
|
<span>TypeScript</span>
|
||||||
|
<span><a href="https://github.com/motion-canvas/motion-canvas">GitHub ↗</a></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Open-Sora -->
|
||||||
|
<div class="eco-card reveal">
|
||||||
|
<div class="eco-icon" style="background: rgba(255,149,0,0.1); color: var(--orange);">🎞️</div>
|
||||||
|
<h3>Open-Sora</h3>
|
||||||
|
<span class="eco-tag">像素级 AI 视频生成</span>
|
||||||
|
<p>开源复现 OpenAI Sora,11B 参数,支持 text/image/video-to-video。与 Vibe Motion 代码生成互补——适合真实场景视频,不适合精确图形动画。</p>
|
||||||
|
<div class="eco-meta">
|
||||||
|
<span class="stars">★ 25,000+</span>
|
||||||
|
<span>Python</span>
|
||||||
|
<span><a href="https://github.com/hpcaitech/Open-Sora">GitHub ↗</a></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Manim -->
|
||||||
|
<div class="eco-card reveal">
|
||||||
|
<div class="eco-icon" style="background: rgba(255,68,170,0.1); color: var(--pink);">∑</div>
|
||||||
|
<h3>Manim</h3>
|
||||||
|
<span class="eco-tag">数学动画传奇</span>
|
||||||
|
<p>3Blue1Brown 创造的数学动画引擎,Python 编写。适合数学公式推导、数据可视化、教育内容。社区版 MIT 协议。</p>
|
||||||
|
<div class="eco-meta">
|
||||||
|
<span class="stars">★ 70,000+</span>
|
||||||
|
<span>Python</span>
|
||||||
|
<span><a href="https://github.com/3b1b/manim">GitHub ↗</a></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Rive -->
|
||||||
|
<div class="eco-card reveal">
|
||||||
|
<div class="eco-icon" style="background: rgba(255,255,255,0.06); color: #fff;">◆</div>
|
||||||
|
<h3>Rive</h3>
|
||||||
|
<span class="eco-tag">交互式状态机动画</span>
|
||||||
|
<p>可视化编辑器 + 状态机驱动,适合做 App 内交互动画(按钮微动效、加载动画、游戏 UI)。运行时开源,编辑器免费使用。</p>
|
||||||
|
<div class="eco-meta">
|
||||||
|
<span>跨平台</span>
|
||||||
|
<span><a href="https://rive.app">rive.app ↗</a></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ===== COMPARISON ===== -->
|
||||||
|
<section id="compare">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-tag">对比分析</div>
|
||||||
|
<h2 class="section-title reveal">选择适合你的工具</h2>
|
||||||
|
<p class="section-desc reveal">不同场景用不同工具,以下是核心维度对比。</p>
|
||||||
|
|
||||||
|
<div class="reveal" style="overflow-x: auto;">
|
||||||
|
<table class="compare-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>维度</th>
|
||||||
|
<th>Remotion</th>
|
||||||
|
<th>Motion Canvas</th>
|
||||||
|
<th>Motion (Framer)</th>
|
||||||
|
<th>Open-Sora</th>
|
||||||
|
<th>After Effects</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr class="highlight-row">
|
||||||
|
<td>AI Vibe Coding</td>
|
||||||
|
<td><span class="check">★★★</span></td>
|
||||||
|
<td><span class="check">★★☆</span></td>
|
||||||
|
<td><span class="check">★★★</span></td>
|
||||||
|
<td><span class="check">★☆☆</span></td>
|
||||||
|
<td><span class="cross">—</span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>输出格式</td>
|
||||||
|
<td>MP4/GIF/WebM</td>
|
||||||
|
<td>MP4</td>
|
||||||
|
<td>网页动画</td>
|
||||||
|
<td>MP4</td>
|
||||||
|
<td>全格式</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>分辨率</td>
|
||||||
|
<td>无限制 (4K+)</td>
|
||||||
|
<td>无限制</td>
|
||||||
|
<td>N/A (实时)</td>
|
||||||
|
<td>720p</td>
|
||||||
|
<td>无限制</td>
|
||||||
|
</tr>
|
||||||
|
<tr class="highlight-row">
|
||||||
|
<td>文字精度</td>
|
||||||
|
<td><span class="check">像素级精确</span></td>
|
||||||
|
<td><span class="check">像素级精确</span></td>
|
||||||
|
<td><span class="check">像素级精确</span></td>
|
||||||
|
<td><span class="cross">模糊/变形</span></td>
|
||||||
|
<td><span class="check">精确</span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>学习曲线</td>
|
||||||
|
<td>React 基础</td>
|
||||||
|
<td>TypeScript</td>
|
||||||
|
<td>React 基础</td>
|
||||||
|
<td>Python/GPU</td>
|
||||||
|
<td>数月~年</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>批量生成</td>
|
||||||
|
<td><span class="check">✓ 参数化</span></td>
|
||||||
|
<td><span class="check">✓</span></td>
|
||||||
|
<td><span class="cross">✕</span></td>
|
||||||
|
<td><span class="check">✓</span></td>
|
||||||
|
<td><span class="cross">手动</span></td>
|
||||||
|
</tr>
|
||||||
|
<tr class="highlight-row">
|
||||||
|
<td>GPU 需求</td>
|
||||||
|
<td>不需要</td>
|
||||||
|
<td>不需要</td>
|
||||||
|
<td>不需要</td>
|
||||||
|
<td>A100 级</td>
|
||||||
|
<td>推荐有</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>开源协议</td>
|
||||||
|
<td>个人免费</td>
|
||||||
|
<td>MIT</td>
|
||||||
|
<td>MIT</td>
|
||||||
|
<td>Apache 2.0</td>
|
||||||
|
<td>商业</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ===== USE CASES ===== -->
|
||||||
|
<section id="usecases" style="background: var(--bg2);">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-tag">应用场景</div>
|
||||||
|
<h2 class="section-title reveal">从营销视频到教育内容</h2>
|
||||||
|
<p class="section-desc reveal">Vibe Motion 的代码生成模式在以下场景尤其强大:</p>
|
||||||
|
|
||||||
|
<div class="use-grid">
|
||||||
|
<div class="use-card reveal">
|
||||||
|
<div class="use-icon" style="background: rgba(0,255,140,0.1);">📱</div>
|
||||||
|
<div>
|
||||||
|
<h4>社交媒体营销</h4>
|
||||||
|
<p>10 分钟生成品牌一致的动效视频,支持批量生成万级个性化变体。传统制作需数万元 + 数周。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="use-card reveal">
|
||||||
|
<div class="use-icon" style="background: rgba(168,85,247,0.1);">🎓</div>
|
||||||
|
<div>
|
||||||
|
<h4>教育解释视频</h4>
|
||||||
|
<p>类似 3Blue1Brown 的数学动画,用 Remotion/Manim + AI 快速生成算法可视化、物理模拟、概念讲解。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="use-card reveal">
|
||||||
|
<div class="use-icon" style="background: rgba(0,200,255,0.1);">📊</div>
|
||||||
|
<div>
|
||||||
|
<h4>数据可视化</h4>
|
||||||
|
<p>将报表数据转化为动态图表视频,支持 API 驱动自动更新。年报、季度汇报、实时仪表盘录制。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="use-card reveal">
|
||||||
|
<div class="use-icon" style="background: rgba(255,149,0,0.1);">🚀</div>
|
||||||
|
<div>
|
||||||
|
<h4>产品发布视频</h4>
|
||||||
|
<p>Replit 等公司已用 Vibe Motion 制作产品 launch 视频。终端打字动画、代码高亮、截图飞入——10 分钟搞定。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="use-card reveal">
|
||||||
|
<div class="use-icon" style="background: rgba(255,68,170,0.1);">🎮</div>
|
||||||
|
<div>
|
||||||
|
<h4>游戏 UI & App 微动效</h4>
|
||||||
|
<p>Rive 状态机 + Motion 弹簧动画,做按钮反馈、加载指示器、成就解锁动画。运行时开源跨平台。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="use-card reveal">
|
||||||
|
<div class="use-icon" style="background: rgba(255,255,255,0.06);">🔄</div>
|
||||||
|
<div>
|
||||||
|
<h4>CI/CD 自动化视频</h4>
|
||||||
|
<p>代码即视频——纳入 Git 版本控制,PR review 审查动画变更,CI 自动渲染输出。视频生产变成 git commit。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ===== TIMELINE ===== -->
|
||||||
|
<section id="timeline">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-tag">发展脉络</div>
|
||||||
|
<h2 class="section-title reveal">Vibe Motion 简史</h2>
|
||||||
|
|
||||||
|
<div class="timeline reveal">
|
||||||
|
<div class="timeline-item">
|
||||||
|
<div class="date">2021</div>
|
||||||
|
<h4>Remotion 1.0 发布</h4>
|
||||||
|
<p>Jonny Burger 在苏黎世创建 Remotion,提出"用 React 写视频"的理念。开源社区开始关注代码生成视频的可能性。</p>
|
||||||
|
</div>
|
||||||
|
<div class="timeline-item">
|
||||||
|
<div class="date">2023</div>
|
||||||
|
<h4>Motion Canvas 开源</h4>
|
||||||
|
<p>TypeScript 版的 Manim 问世,填补了 Web 开发者制作教育动画的空白。</p>
|
||||||
|
</div>
|
||||||
|
<div class="timeline-item">
|
||||||
|
<div class="date">2025.02</div>
|
||||||
|
<h4>Andrej Karpathy 提出 "Vibe Coding"</h4>
|
||||||
|
<p>OpenAI 联合创始人定义了这个概念:用自然语言和 AI 协作写代码,而不是手动逐行编写。</p>
|
||||||
|
</div>
|
||||||
|
<div class="timeline-item">
|
||||||
|
<div class="date">2025.12</div>
|
||||||
|
<h4>Remotion Claude Skill 爆发</h4>
|
||||||
|
<p>Remotion Agent Skill 上线 8 周达到 15 万安装量,成为 skills.sh 上 #1 视频技能。视频制作变成了 "git commit"。</p>
|
||||||
|
</div>
|
||||||
|
<div class="timeline-item">
|
||||||
|
<div class="date">2026.02</div>
|
||||||
|
<h4>Higgsfield 发布 Vibe Motion</h4>
|
||||||
|
<p>将 Claude + Remotion 包装成无代码产品,$17.4/月起。正式定义了 "Vibe Motion" 这个品类——AI 驱动的代码生成动效。</p>
|
||||||
|
</div>
|
||||||
|
<div class="timeline-item">
|
||||||
|
<div class="date">2026.03</div>
|
||||||
|
<h4>生态爆发</h4>
|
||||||
|
<p>Replit 推出 Vibe Code Videos、Motion.dev 集成 AI Vibe Coding、Cursor 内置 Motion Studio。代码生成动效从小众走向主流。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ===== QUICK START ===== -->
|
||||||
|
<section id="quickstart" style="background: var(--bg2);">
|
||||||
|
<div class="container">
|
||||||
|
<div class="section-tag">快速开始</div>
|
||||||
|
<h2 class="section-title reveal">三步在你的电脑上运行</h2>
|
||||||
|
<p class="section-desc reveal">不需要 GPU,不需要 After Effects,只需要 Node.js + 你的想象力。</p>
|
||||||
|
|
||||||
|
<div class="quickstart-grid reveal">
|
||||||
|
<div class="qs-card">
|
||||||
|
<div class="qs-num">1</div>
|
||||||
|
<h4>创建项目</h4>
|
||||||
|
<p style="color: var(--text2); font-size: 13px;">一行命令初始化 Remotion 项目</p>
|
||||||
|
<code>pnpm create video@latest</code>
|
||||||
|
</div>
|
||||||
|
<div class="qs-card">
|
||||||
|
<div class="qs-num">2</div>
|
||||||
|
<h4>让 AI 写动画</h4>
|
||||||
|
<p style="color: var(--text2); font-size: 13px;">用 Claude Code 描述你想要的效果</p>
|
||||||
|
<code>"做一只蜥蜴摆尾动画"</code>
|
||||||
|
</div>
|
||||||
|
<div class="qs-card">
|
||||||
|
<div class="qs-num">3</div>
|
||||||
|
<h4>预览 & 渲染</h4>
|
||||||
|
<p style="color: var(--text2); font-size: 13px;">浏览器预览,一键导出 MP4</p>
|
||||||
|
<code>pnpm build → out/video.mp4</code>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="code-block reveal" style="margin-top: 40px;">
|
||||||
|
<div class="code-header">
|
||||||
|
<span class="code-dot r"></span>
|
||||||
|
<span class="code-dot y"></span>
|
||||||
|
<span class="code-dot g"></span>
|
||||||
|
<span class="code-filename">Terminal</span>
|
||||||
|
</div>
|
||||||
|
<div class="code-content">
|
||||||
|
<span class="cm"># 安装依赖</span>
|
||||||
|
pnpm add remotion @remotion/cli @remotion/player react react-dom
|
||||||
|
|
||||||
|
<span class="cm"># 启动 Studio(浏览器实时预览)</span>
|
||||||
|
pnpm remotion studio src/index.ts
|
||||||
|
|
||||||
|
<span class="cm"># 渲染为 MP4</span>
|
||||||
|
pnpm remotion render src/index.ts MyAnimation out/video.mp4
|
||||||
|
|
||||||
|
<span class="cm"># 渲染为 GIF</span>
|
||||||
|
pnpm remotion render src/index.ts MyAnimation out/video.gif --image-format png
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- ===== FOOTER ===== -->
|
||||||
|
<footer>
|
||||||
|
<div class="container">
|
||||||
|
<div class="footer-links">
|
||||||
|
<a href="https://github.com/remotion-dev/remotion">Remotion</a>
|
||||||
|
<a href="https://github.com/motiondivision/motion">Motion</a>
|
||||||
|
<a href="https://github.com/motion-canvas/motion-canvas">Motion Canvas</a>
|
||||||
|
<a href="https://higgsfield.ai/vibe-motion">Higgsfield</a>
|
||||||
|
<a href="https://www.remotion.dev/docs/ai/claude-code">Remotion × Claude</a>
|
||||||
|
</div>
|
||||||
|
<p>Built with Remotion + Claude Code · 2026</p>
|
||||||
|
<p style="margin-top: 8px; opacity: .4;">源码已下载至 repos/ — Remotion / Motion / Motion Canvas</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<!-- Floating lizard -->
|
||||||
|
<a href="#" class="float-lizard" title="回到顶部">🦎</a>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// IntersectionObserver for reveal animations
|
||||||
|
const observer = new IntersectionObserver((entries) => {
|
||||||
|
entries.forEach(entry => {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
entry.target.classList.add('visible');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, { threshold: 0.1, rootMargin: '0px 0px -40px 0px' });
|
||||||
|
|
||||||
|
document.querySelectorAll('.reveal').forEach(el => observer.observe(el));
|
||||||
|
|
||||||
|
// Smooth scroll for float lizard
|
||||||
|
document.querySelector('.float-lizard').addEventListener('click', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
26
package.json
Normal file
26
package.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"name": "20260319-vibe-motion",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "remotion studio src/index.ts",
|
||||||
|
"build": "remotion render src/index.ts LizardAnimation out/lizard.mp4",
|
||||||
|
"preview": "remotion preview src/index.ts"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"description": "",
|
||||||
|
"dependencies": {
|
||||||
|
"@remotion/cli": "^4.0.437",
|
||||||
|
"@remotion/player": "^4.0.437",
|
||||||
|
"react": "^19.2.4",
|
||||||
|
"react-dom": "^19.2.4",
|
||||||
|
"remotion": "^4.0.437"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react": "^19.2.14",
|
||||||
|
"@types/react-dom": "^19.2.3",
|
||||||
|
"typescript": "^5.9.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
2195
pnpm-lock.yaml
generated
Normal file
2195
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
3
remotion.config.ts
Normal file
3
remotion.config.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { Config } from "@remotion/cli/config";
|
||||||
|
|
||||||
|
Config.setPort(4062);
|
||||||
407
src/LizardScene.tsx
Normal file
407
src/LizardScene.tsx
Normal file
@@ -0,0 +1,407 @@
|
|||||||
|
import {
|
||||||
|
AbsoluteFill,
|
||||||
|
interpolate,
|
||||||
|
spring,
|
||||||
|
useCurrentFrame,
|
||||||
|
useVideoConfig,
|
||||||
|
Sequence,
|
||||||
|
} from "remotion";
|
||||||
|
|
||||||
|
// SVG path for a stylized lizard silhouette
|
||||||
|
const LIZARD_BODY =
|
||||||
|
"M60,25 Q70,10 85,15 Q100,18 110,25 L140,28 Q160,30 175,25 Q190,20 200,25 Q210,35 200,42 Q195,48 185,45 L170,40 Q160,38 150,42 L130,50 Q120,55 110,50 L100,42 Q90,38 80,42 Q70,48 60,42 Q50,35 60,25Z";
|
||||||
|
const LIZARD_TAIL =
|
||||||
|
"M200,33 Q230,28 260,35 Q290,45 310,35 Q330,22 350,30 Q365,38 360,45";
|
||||||
|
const LIZARD_EYE = "M78,28 A4,4 0 1,1 78,28.01";
|
||||||
|
const LIZARD_FRONT_LEG_L = "M95,42 Q85,58 75,68 Q70,72 65,68";
|
||||||
|
const LIZARD_FRONT_LEG_R = "M95,25 Q85,12 78,5 Q74,0 70,4";
|
||||||
|
const LIZARD_BACK_LEG_L = "M165,42 Q175,58 185,65 Q190,70 195,66";
|
||||||
|
const LIZARD_BACK_LEG_R = "M165,25 Q175,10 182,3 Q186,-2 190,2";
|
||||||
|
|
||||||
|
const TONGUE = "M60,32 Q40,30 25,38 Q20,42 22,35";
|
||||||
|
|
||||||
|
// Particle burst
|
||||||
|
const Particle: React.FC<{
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
delay: number;
|
||||||
|
color: string;
|
||||||
|
size: number;
|
||||||
|
angle: number;
|
||||||
|
}> = ({ x, y, delay, color, size, angle }) => {
|
||||||
|
const frame = useCurrentFrame();
|
||||||
|
const { fps } = useVideoConfig();
|
||||||
|
const life = Math.max(0, frame - delay);
|
||||||
|
const progress = Math.min(life / 40, 1);
|
||||||
|
const dist = interpolate(progress, [0, 1], [0, 200 + Math.random() * 100]);
|
||||||
|
const opacity = interpolate(progress, [0, 0.2, 0.8, 1], [0, 1, 1, 0]);
|
||||||
|
const rad = (angle * Math.PI) / 180;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
left: x + Math.cos(rad) * dist,
|
||||||
|
top: y + Math.sin(rad) * dist,
|
||||||
|
width: size,
|
||||||
|
height: size,
|
||||||
|
borderRadius: "50%",
|
||||||
|
background: color,
|
||||||
|
opacity,
|
||||||
|
filter: `blur(${size * 0.3}px)`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Animated grid background
|
||||||
|
const GridBG: React.FC = () => {
|
||||||
|
const frame = useCurrentFrame();
|
||||||
|
const offset = (frame * 0.5) % 60;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AbsoluteFill>
|
||||||
|
<svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<pattern
|
||||||
|
id="grid"
|
||||||
|
width="60"
|
||||||
|
height="60"
|
||||||
|
patternUnits="userSpaceOnUse"
|
||||||
|
patternTransform={`translate(${offset}, ${offset})`}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M 60 0 L 0 0 0 60"
|
||||||
|
fill="none"
|
||||||
|
stroke="rgba(0,255,140,0.08)"
|
||||||
|
strokeWidth="1"
|
||||||
|
/>
|
||||||
|
</pattern>
|
||||||
|
</defs>
|
||||||
|
<rect width="100%" height="100%" fill="url(#grid)" />
|
||||||
|
</svg>
|
||||||
|
</AbsoluteFill>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Animated lizard component
|
||||||
|
const Lizard: React.FC<{
|
||||||
|
enterFrame: number;
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
scale: number;
|
||||||
|
hue: number;
|
||||||
|
}> = ({ enterFrame, x, y, scale, hue }) => {
|
||||||
|
const frame = useCurrentFrame();
|
||||||
|
const { fps } = useVideoConfig();
|
||||||
|
const localFrame = frame - enterFrame;
|
||||||
|
|
||||||
|
// Spring entrance
|
||||||
|
const scaleSpring = spring({
|
||||||
|
fps,
|
||||||
|
frame: localFrame,
|
||||||
|
config: { damping: 12, stiffness: 80 },
|
||||||
|
});
|
||||||
|
|
||||||
|
// Breathing / idle animation
|
||||||
|
const breathe = Math.sin(localFrame * 0.08) * 2;
|
||||||
|
|
||||||
|
// Tail wag
|
||||||
|
const tailWag = Math.sin(localFrame * 0.15) * 8;
|
||||||
|
|
||||||
|
// Tongue flick (every ~60 frames)
|
||||||
|
const tonguePhase = (localFrame % 80) / 80;
|
||||||
|
const tongueOut =
|
||||||
|
tonguePhase > 0.3 && tonguePhase < 0.5
|
||||||
|
? interpolate(tonguePhase, [0.3, 0.4, 0.5], [0, 1, 0])
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
// Leg walk cycle
|
||||||
|
const legCycle = Math.sin(localFrame * 0.12) * 6;
|
||||||
|
|
||||||
|
// Glow pulse
|
||||||
|
const glowIntensity = interpolate(
|
||||||
|
Math.sin(localFrame * 0.06),
|
||||||
|
[-1, 1],
|
||||||
|
[10, 25]
|
||||||
|
);
|
||||||
|
|
||||||
|
const color1 = `hsl(${hue}, 90%, 55%)`;
|
||||||
|
const color2 = `hsl(${hue + 30}, 85%, 45%)`;
|
||||||
|
const glowColor = `hsla(${hue}, 100%, 60%, 0.6)`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
left: x,
|
||||||
|
top: y + breathe,
|
||||||
|
transform: `scale(${scale * scaleSpring})`,
|
||||||
|
transformOrigin: "center center",
|
||||||
|
filter: `drop-shadow(0 0 ${glowIntensity}px ${glowColor})`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
width="400"
|
||||||
|
height="80"
|
||||||
|
viewBox="0 0 400 80"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id={`grad-${hue}`} x1="0%" y1="0%" x2="100%" y2="0%">
|
||||||
|
<stop offset="0%" stopColor={color1} />
|
||||||
|
<stop offset="100%" stopColor={color2} />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
{/* Legs with walk cycle */}
|
||||||
|
<g>
|
||||||
|
<path
|
||||||
|
d={LIZARD_FRONT_LEG_L}
|
||||||
|
stroke={color2}
|
||||||
|
strokeWidth="4"
|
||||||
|
fill="none"
|
||||||
|
strokeLinecap="round"
|
||||||
|
transform={`rotate(${legCycle}, 95, 42)`}
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d={LIZARD_FRONT_LEG_R}
|
||||||
|
stroke={color2}
|
||||||
|
strokeWidth="4"
|
||||||
|
fill="none"
|
||||||
|
strokeLinecap="round"
|
||||||
|
transform={`rotate(${-legCycle}, 95, 25)`}
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d={LIZARD_BACK_LEG_L}
|
||||||
|
stroke={color2}
|
||||||
|
strokeWidth="4"
|
||||||
|
fill="none"
|
||||||
|
strokeLinecap="round"
|
||||||
|
transform={`rotate(${-legCycle}, 165, 42)`}
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d={LIZARD_BACK_LEG_R}
|
||||||
|
stroke={color2}
|
||||||
|
strokeWidth="4"
|
||||||
|
fill="none"
|
||||||
|
strokeLinecap="round"
|
||||||
|
transform={`rotate(${legCycle}, 165, 25)`}
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
{/* Body */}
|
||||||
|
<path
|
||||||
|
d={LIZARD_BODY}
|
||||||
|
fill={`url(#grad-${hue})`}
|
||||||
|
stroke={color1}
|
||||||
|
strokeWidth="1.5"
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Scales pattern */}
|
||||||
|
{Array.from({ length: 8 }).map((_, i) => (
|
||||||
|
<circle
|
||||||
|
key={i}
|
||||||
|
cx={90 + i * 14}
|
||||||
|
cy={33 + Math.sin(i * 1.2 + localFrame * 0.05) * 3}
|
||||||
|
r={2.5}
|
||||||
|
fill={`hsla(${hue + 60}, 80%, 70%, 0.5)`}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{/* Tail with wag */}
|
||||||
|
<path
|
||||||
|
d={LIZARD_TAIL}
|
||||||
|
stroke={`url(#grad-${hue})`}
|
||||||
|
strokeWidth="6"
|
||||||
|
fill="none"
|
||||||
|
strokeLinecap="round"
|
||||||
|
transform={`rotate(${tailWag}, 200, 33)`}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Eye */}
|
||||||
|
<circle cx={78} cy={28} r={5} fill="white" />
|
||||||
|
<circle cx={76} cy={28} r={3} fill="#111" />
|
||||||
|
<circle cx={75} cy={27} r={1} fill="white" />
|
||||||
|
|
||||||
|
{/* Tongue */}
|
||||||
|
<path
|
||||||
|
d={TONGUE}
|
||||||
|
stroke="#ff4466"
|
||||||
|
strokeWidth="2.5"
|
||||||
|
fill="none"
|
||||||
|
strokeLinecap="round"
|
||||||
|
opacity={tongueOut}
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Title text with reveal
|
||||||
|
const Title: React.FC = () => {
|
||||||
|
const frame = useCurrentFrame();
|
||||||
|
const { fps } = useVideoConfig();
|
||||||
|
|
||||||
|
const titleSpring = spring({
|
||||||
|
fps,
|
||||||
|
frame: frame - 20,
|
||||||
|
config: { damping: 15, stiffness: 60 },
|
||||||
|
});
|
||||||
|
|
||||||
|
const subtitleSpring = spring({
|
||||||
|
fps,
|
||||||
|
frame: frame - 45,
|
||||||
|
config: { damping: 15, stiffness: 60 },
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
top: 80,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
textAlign: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: 72,
|
||||||
|
fontWeight: 900,
|
||||||
|
fontFamily: "system-ui, -apple-system, sans-serif",
|
||||||
|
color: "white",
|
||||||
|
letterSpacing: -2,
|
||||||
|
opacity: titleSpring,
|
||||||
|
transform: `translateY(${interpolate(titleSpring, [0, 1], [40, 0])}px)`,
|
||||||
|
textShadow: "0 0 40px rgba(0,255,140,0.5), 0 0 80px rgba(0,255,140,0.2)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
VIBE MOTION
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: 400,
|
||||||
|
fontFamily: "system-ui, -apple-system, sans-serif",
|
||||||
|
color: "rgba(0,255,140,0.8)",
|
||||||
|
letterSpacing: 8,
|
||||||
|
marginTop: 12,
|
||||||
|
opacity: subtitleSpring,
|
||||||
|
transform: `translateY(${interpolate(subtitleSpring, [0, 1], [20, 0])}px)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
AI-POWERED ANIMATION
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Main scene composition
|
||||||
|
export const LizardScene: React.FC = () => {
|
||||||
|
const frame = useCurrentFrame();
|
||||||
|
const { fps, width, height } = useVideoConfig();
|
||||||
|
|
||||||
|
// Background color shift
|
||||||
|
const bgHue = interpolate(frame, [0, 300], [220, 260]);
|
||||||
|
|
||||||
|
// Particle colors
|
||||||
|
const particleColors = ["#00ff8c", "#00ccff", "#ff44aa", "#ffcc00", "#8844ff"];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AbsoluteFill
|
||||||
|
style={{
|
||||||
|
background: `radial-gradient(ellipse at 50% 50%, hsl(${bgHue}, 30%, 12%) 0%, hsl(${bgHue}, 40%, 4%) 100%)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Animated grid */}
|
||||||
|
<GridBG />
|
||||||
|
|
||||||
|
{/* Title */}
|
||||||
|
<Sequence from={10}>
|
||||||
|
<Title />
|
||||||
|
</Sequence>
|
||||||
|
|
||||||
|
{/* Main lizard - center stage */}
|
||||||
|
<Sequence from={30}>
|
||||||
|
<Lizard enterFrame={30} x={700} y={420} scale={2.8} hue={140} />
|
||||||
|
</Sequence>
|
||||||
|
|
||||||
|
{/* Second lizard - smaller, different color */}
|
||||||
|
<Sequence from={80}>
|
||||||
|
<Lizard enterFrame={80} x={200} y={600} scale={1.8} hue={280} />
|
||||||
|
</Sequence>
|
||||||
|
|
||||||
|
{/* Third lizard */}
|
||||||
|
<Sequence from={120}>
|
||||||
|
<Lizard enterFrame={120} x={1200} y={550} scale={2.0} hue={30} />
|
||||||
|
</Sequence>
|
||||||
|
|
||||||
|
{/* Particle burst at entrance */}
|
||||||
|
<Sequence from={30}>
|
||||||
|
{Array.from({ length: 30 }).map((_, i) => (
|
||||||
|
<Particle
|
||||||
|
key={i}
|
||||||
|
x={width / 2}
|
||||||
|
y={height / 2}
|
||||||
|
delay={30 + i * 0.5}
|
||||||
|
color={particleColors[i % particleColors.length]}
|
||||||
|
size={4 + Math.random() * 6}
|
||||||
|
angle={(360 / 30) * i}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Sequence>
|
||||||
|
|
||||||
|
{/* Bottom text */}
|
||||||
|
<Sequence from={150}>
|
||||||
|
<BottomBar />
|
||||||
|
</Sequence>
|
||||||
|
</AbsoluteFill>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const BottomBar: React.FC = () => {
|
||||||
|
const frame = useCurrentFrame();
|
||||||
|
const { fps } = useVideoConfig();
|
||||||
|
|
||||||
|
const barSpring = spring({
|
||||||
|
fps,
|
||||||
|
frame: frame - 150,
|
||||||
|
config: { damping: 20, stiffness: 80 },
|
||||||
|
});
|
||||||
|
|
||||||
|
const lineWidth = interpolate(barSpring, [0, 1], [0, 600]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
bottom: 80,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
textAlign: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Decorative line */}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: lineWidth,
|
||||||
|
height: 2,
|
||||||
|
background: "linear-gradient(90deg, transparent, #00ff8c, transparent)",
|
||||||
|
margin: "0 auto 20px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: 18,
|
||||||
|
fontFamily: "system-ui, -apple-system, sans-serif",
|
||||||
|
color: "rgba(255,255,255,0.6)",
|
||||||
|
letterSpacing: 4,
|
||||||
|
opacity: barSpring,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
BUILT WITH REMOTION + CLAUDE CODE
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
17
src/Root.tsx
Normal file
17
src/Root.tsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { Composition } from "remotion";
|
||||||
|
import { LizardScene } from "./LizardScene";
|
||||||
|
|
||||||
|
export const RemotionRoot: React.FC = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Composition
|
||||||
|
id="LizardAnimation"
|
||||||
|
component={LizardScene}
|
||||||
|
durationInFrames={300}
|
||||||
|
fps={30}
|
||||||
|
width={1920}
|
||||||
|
height={1080}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
4
src/index.ts
Normal file
4
src/index.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
import { registerRoot } from "remotion";
|
||||||
|
import { RemotionRoot } from "./Root";
|
||||||
|
|
||||||
|
registerRoot(RemotionRoot);
|
||||||
15
tsconfig.json
Normal file
15
tsconfig.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "ES2022",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "."
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts", "src/**/*.tsx", "remotion.config.ts"]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user