{
  "slug": "steep-tilt-glide",
  "title": "Steep-tilt page glide",
  "tagline": "A fixed camera holds an upright page in a strong 60° perspective tilt (near right, far left); the page glides sideways across the lens on its own (the object moves, not the camera), with speed-streak afterimages and floating text settling as it lifts from dark to light.",
  "description": "A fixed camera holds an upright page in a strong 60° perspective tilt (near right, far left); the page glides sideways across the lens on its own (the object ",
  "category": "camera",
  "tags": [
    "shotcraft",
    "remotion",
    "camera",
    "ui-entrance"
  ],
  "tier": "free",
  "license": "Apache-2.0",
  "spec": {
    "width": 1920,
    "height": 1080,
    "fps": 30,
    "duration": 4.05,
    "aspect": "16:9"
  },
  "kind": "remotion",
  "params_schema": {
    "type": "object",
    "properties": {}
  },
  "default_params": {},
  "preview": {
    "poster": "https://gimgs.net/motion/media/steep-tilt-glide/poster-81e384885644.jpg",
    "video": "https://gimgs.net/motion/media/steep-tilt-glide/video-7162216ba5db.mp4"
  },
  "variants": [
    {
      "key": "steep-tilt-glide",
      "label": "steep-tilt-glide",
      "description": "A fixed camera holds an upright page in a strong 60° perspective tilt (near right, far left); the page glides sideways across the lens on its own (the object moves, not the camera), with speed-streak afterimages and floating text settling as it lifts from dark to light",
      "use": "",
      "video": "https://gimgs.net/motion/media/steep-tilt-glide/video-7162216ba5db.mp4",
      "poster": "https://gimgs.net/motion/media/steep-tilt-glide/poster-81e384885644.jpg"
    }
  ],
  "credits": {
    "author": "video-shotcraft (Vincent Wei)",
    "url": "https://github.com/Vincentwei1021/video-shotcraft"
  },
  "page_url": "https://gimgs.net/motion/steep-tilt-glide.html",
  "json_url": "https://gimgs.net/motion/steep-tilt-glide.json",
  "template_url": "https://gimgs.net/motion/steep-tilt-glide/template.html",
  "play_url": null,
  "markdown_url": "https://gimgs.net/motion/steep-tilt-glide.md",
  "updated_at": "2026-09-24T07:40:25.247Z",
  "prompt": "## When to use\n\nA showcase glide through long pages/multi-section UI (content passes the fixed camera in sequence); dark neon tone; a \"lateral sweep\" shot that complements the surface-hugging camera card\n\n## Intention\n\nThe page becomes a slanted wall: the camera is locked down, a strong 60° perspective pins the right edge close to the lens and lets the left edge vanish toward the vanishing point, while the page glides sideways along its own plane — content passes by in sequence like train cars. The linchpin is **the object moves, the camera doesn't**: perspective/origin/rotY stay constant throughout; the only thing that moves is the page's local translateX — moving the camera would turn this into camera-move flair, when the point here is \"the page showing itself off.\" The angle converged on exactly 60° over three rounds (-45° \"not quite\" → -53° \"a bit more\" → -60° chosen).\n\n## Duration & energy\n\n- Duration: 4s (120f) single shot; can extend as the page gets wider\n- Energy: Medium-high (perspective flair plus sustained motion, but the pace stays even)\n\n## Shot recipe (original Chinese — timing, easing, parameter table, known pitfalls)\n\n## 意图\n把页面立成一堵斜墙：镜头钉死不动，60° 强透视让右缘贴脸、左缘\n消失在灭点，页面自己沿自身平面横向滑移——内容像列车车厢一样\n依次掠过。命门是**物动镜不动**：perspective/origin/rotY 全程常数，\n唯一动的量是页面局部 translateX——镜头一动语义就变成运镜炫技，\n这里的戏是\"页面在自我展示\"。角度经三轮收敛为精确 60°\n（-45°\"不对\"→-53°\"再大一点\"→-60°选中）。\n\n## 动效核心\n- 镜头常数：perspective 1100、origin 30% 58%、rotateY(-60°)+\n  rotateZ(-2°)，transformOrigin left top，全程一个数不变\n- 页面：超宽面板（6200×2400@内容坐标），沿局部 X 轴 +60→-4100\n  滑移，bezier(0.3,0.12,0.72,0.9)——起步柔和后近匀速，尾段斜率\n  不归零（不安定停死）\n- 速度重影：拖尾层=过去时刻（f-2.5/f-5）的局部位置重投影，\n  透明度 ∝ 滑移速度（快时重影浓）\n- 悬空贴落：页面元素 FloatWrap 悬浮 230–280px 带同形软影，随\n  滑移进程错峰贴落（巡礼语法）\n- 揭亮：起始面板压暗 0.7，~1.4s 揭到全亮；左缘额外渐变阴影同退\n\n## 参数表\n| 参数 | 典型值 | 调节手感 |\n|------|--------|----------|\n| 倾斜角 | rotateY **-60°**（用户精确定值） | -45° 被裁\"角度不对\"、-53°\"再大一点\"；>-70° 内容读不清 |\n| 运动模型 | 镜头全常数、页面自移 | **命门**——镜头横移版被裁\"镜头是固定的，页面本身往其3d空间的横面方向移动\" |\n| 滑移曲线 | 尾段斜率不归零的 bezier | 中途停死被抓（v4 返工）；全 linear 少了起步呼吸 |\n| 重影 | 透明度∝速度，双层 f-2.5/f-5 | 恒定重影读作重像故障 |\n| 页面宽度 | ≥3 屏内容 | 太窄滑两秒就完，撑不起一镜 |\n| 悬空贴落 | 错峰（巡礼语法）+ 影随高度 | 语义判例见 graze-face-tour/orbit-drop 三卡族 |\n\n## 已知坑\n- demo 在灰阶/占位素材上调校通过——参数是调校起点非实战定稿，\n  首次实战须以真实素材回验\n- 角度判例：透视角是本卡身份，实战微调范围建议 55–65°，出这个\n  区间等于换手法\n- 与 graze-face-tour 分工：那张镜头动（贴面游走）、页面静；本卡\n  镜头静、页面动。同段落二选一\n- 与 runway-ground-skim 分工：那张是俯角平躺+垂直贴落+立起；\n  本卡是侧立+横向滑移，轴向正交\n- 超宽页面手绘成本高；实战可用真实长截图代替（滑移逻辑不变）\n\n## 参考实现\ndemos/camera/steep-tilt-glide/\n（SteepTiltGlide.tsx）\n原片出处：clickup-30.mp4\n\n## Reference implementation (Remotion)\n\n- demos/camera/steep-tilt-glide/SteepTiltGlide.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/camera/steep-tilt-glide/SteepTiltGlide.tsx\n\nThe component imports shared fixtures from `demos/_fixtures` and helpers from `assets/lib` in the repo; SKILL.md there documents the render workflow.\n",
  "flow": [
    {
      "step": "Read the recipe",
      "note": "Prompt = when to use, intention, parameter table with typical values and how each one feels, known pitfalls. Treat values as calibrated starting points."
    },
    {
      "step": "Get the code",
      "tool": "git",
      "cmd": "git clone https://github.com/Vincentwei1021/video-shotcraft && cd video-shotcraft && npm install"
    },
    {
      "step": "Register + render",
      "tool": "remotion",
      "cmd": "npx remotion render <CompositionId> out.mp4   # component: demos/camera/steep-tilt-glide/SteepTiltGlide.tsx"
    },
    {
      "step": "Or re-implement",
      "note": "Port the timing/easing from the recipe to HTML + WAAPI (gimgs motion contract) or any engine; keep the same segment windows and easing."
    }
  ],
  "files": [
    {
      "path": "demos/camera/steep-tilt-glide/SteepTiltGlide.tsx",
      "url": "https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/camera/steep-tilt-glide/SteepTiltGlide.tsx"
    }
  ],
  "contract": "React/Remotion composition (TSX) from the open-source video-shotcraft library (Apache-2.0). It is not a browser-playable template: clone the repo, register the component in a Remotion project and render with `npx remotion render`. The recipe (prompt) describes timing, easing and parameters so you can also re-implement the shot in any engine.",
  "render": {
    "engine": "remotion",
    "frames": 122,
    "repo": "https://github.com/Vincentwei1021/video-shotcraft",
    "files": [
      "https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/camera/steep-tilt-glide/SteepTiltGlide.tsx"
    ],
    "note": "Clone https://github.com/Vincentwei1021/video-shotcraft (npm install). The component lives under demos/{category}/{name}/ and imports shared fixtures from demos/_fixtures and helpers from assets/lib. Copy it (with those imports) into a Remotion project, register a <Composition> with the template's width/height/fps/duration in Root.tsx, then `npx remotion render <CompositionId> out.mp4`. SKILL.md in the repo documents the full Claude Code / Codex workflow. The prompt below is the shot recipe (timing, easing, parameter table, pitfalls) — enough to re-implement the shot in HTML/WAAPI or another engine if you prefer."
  },
  "source": "// ===== demos/camera/steep-tilt-glide/SteepTiltGlide.tsx =====\n// steep-tilt-glide v5（批次 14 #2）。用户意见（逐字）：\n// \"角度不对，你看看原片这个镜头的角度；以及镜头是固定的，但是页面本身\n// 往其3d空间的横面方向移动的效果\"\n// ——两点落实：①角度对照原片密帧校准（右缘近、左缘远的陡峭 rotateY，\n// 顶缘向右上扬、透视灭点在左中下）；②运动模型改\"物动镜不动\"：\n// perspective / perspectiveOrigin / rotateY / rotateZ 全程一个常数不动，\n// 动的只有页面自身沿其 3D 平面横向（局部 X 轴）的滑移 translateX。\n// v4 的悬空贴落（FloatWrap 同形软影）保留。\nimport React, { useId } from 'react';\nimport { AbsoluteFill, interpolate, useCurrentFrame, Easing } from 'remotion';\n\nconst FONT = 'Helvetica, Arial, sans-serif';\nconst INK = '#2f2f36';\n\nconst easeFall = Easing.bezier(0.5, 0.05, 0.6, 1); // 加速贴落、末端软着陆\n\n/* 悬浮 + 同形软影（GrazeFaceTour FloatWrap 模式） */\nconst FloatWrap: React.FC<{ h: number; children: React.ReactNode }> = ({ h, children }) => (\n  <div style={{ position: 'relative' }}>\n    {h > 2 && (\n      <div style={{\n        position: 'absolute', inset: 0,\n        transform: `translate(${h * 0.24}px, ${h * 0.46}px) scale(${1 + h * 0.0009})`,\n        filter: `blur(${5 + h * 0.075}px) brightness(0.35) saturate(0.4)`,\n        opacity: Math.min(0.38, 0.15 + h * 0.0016),\n        pointerEvents: 'none',\n      }}>{children}</div>\n    )}\n    <div style={{ transform: `translate(${-h * 0.34}px, ${-h * 0.8}px)` }}>{children}</div>\n  </div>\n);\n\n/* land=贴合完成时刻(0..1)，之前从 H 高度加速贴落 */\nconst liftOf = (t: number, land: number, H = 230) => {\n  const FALL = 0.32;\n  const p = Math.min(1, Math.max(0, (t - (land - FALL)) / FALL));\n  return (1 - easeFall(p)) * H;\n};\n\n/* ClickUp 彩色小 logo（双 V 叠形近似） */\nconst CULogo: React.FC<{ size: number }> = ({ size }) => {\n  // 渐变 ID 按实例生成，多实例同场不串引（useId 的 «:» 在 url() 里非法，需清洗）\n  const uid = useId().replace(/[^a-zA-Z0-9]/g, '');\n  return (\n    <svg width={size} height={size} viewBox=\"0 0 100 100\">\n      <defs>\n        <linearGradient id={`cu1-${uid}`} x1=\"0\" y1=\"0\" x2=\"1\" y2=\"0\">\n          <stop offset=\"0\" stopColor=\"#8930fd\" />\n          <stop offset=\"1\" stopColor=\"#49ccf9\" />\n        </linearGradient>\n        <linearGradient id={`cu2-${uid}`} x1=\"0\" y1=\"0\" x2=\"1\" y2=\"0\">\n          <stop offset=\"0\" stopColor=\"#ff02f0\" />\n          <stop offset=\"1\" stopColor=\"#ffc800\" />\n        </linearGradient>\n      </defs>\n      <path d=\"M 14 62 L 50 30 L 86 62\" fill=\"none\" stroke={`url(#cu1-${uid})`} strokeWidth=\"16\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n      <path d=\"M 22 84 L 50 62 L 78 84\" fill=\"none\" stroke={`url(#cu2-${uid})`} strokeWidth=\"16\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n    </svg>\n  );\n};\n\n/* Dropbox 蓝四菱形 glyph（原片 f45/f60 主区圆角灰砖里的图标） */\nconst DropboxGlyph: React.FC<{ size: number }> = ({ size }) => (\n  <svg width={size} height={size} viewBox=\"0 0 100 100\">\n    {[[50, 8, 27, 22], [50, 8, 73, 22], [50, 36, 27, 50], [50, 36, 73, 50]].map(() => null)}\n    <g fill=\"#0061fe\">\n      <path d=\"M 27 10 L 50 25 L 27 40 L 4 25 Z\" />\n      <path d=\"M 73 10 L 96 25 L 73 40 L 50 25 Z\" />\n      <path d=\"M 27 40 L 50 55 L 27 70 L 4 55 Z\" />\n      <path d=\"M 73 40 L 96 55 L 73 70 L 50 55 Z\" />\n      <path d=\"M 27 74 L 50 89 L 73 74 L 50 62 Z\" />\n    </g>\n  </svg>\n);\n\n/* 页面：宽 6200 —— 左段=ClickUp3.0 顶栏+侧栏（用户截图三张全在此段），\n   右段=原片后程滑入的 Dropbox 砖、大 W 字、Product Management 列表 */\nconst PW = 6200;\nconst PH = 2400;\n\nconst Panel: React.FC<{ shade: number; t?: number }> = ({ shade, t = 1 }) => (\n  <div style={{\n    width: PW, height: PH, background: '#f4f4f6', borderRadius: 64,\n    position: 'relative', overflow: 'hidden',\n    boxShadow: '0 0 220px rgba(220,210,255,0.35)',\n    fontFamily: FONT,\n  }}>\n    {/* 顶部 tab 条（贯穿整页；文字悬空贴落） */}\n    <div style={{\n      position: 'absolute', top: 0, left: 0, width: PW, height: 230,\n      borderBottom: '4px solid #dcdce2', display: 'flex', alignItems: 'center', paddingLeft: 130,\n    }}>\n      <FloatWrap h={liftOf(t, 0.3)}>\n        <div style={{ display: 'flex', alignItems: 'center' }}>\n          <svg width={58} height={58} viewBox=\"0 0 40 40\" style={{ marginRight: 34 }}>\n            {[[4, 4], [23, 4], [4, 23], [23, 23]].map(([x, y], i) => (\n              <rect key={i} x={x} y={y} width={13} height={13} rx={3} fill=\"none\" stroke=\"#4a4a52\" strokeWidth={3.5} />\n            ))}\n          </svg>\n          <div style={{ fontSize: 66, color: INK, fontWeight: 500 }}>Product analytics</div>\n        </div>\n      </FloatWrap>\n      <FloatWrap h={liftOf(t, 0.42, 280)}>\n        <div style={{ display: 'flex', alignItems: 'center' }}>\n          <div style={{ width: 72, height: 72, borderRadius: 20, background: '#4147f5', marginLeft: 150, flexShrink: 0 }} />\n          <div style={{ fontSize: 165, color: '#26262c', fontWeight: 550, marginLeft: 110, letterSpacing: 1, whiteSpace: 'nowrap' }}>ClickUp 3.0</div>\n        </div>\n      </FloatWrap>\n      {/* 顶栏右延的淡 tab（对齐 clickup04 顶栏 Widget brainstorm / Design system） */}\n      {[['Widget brainstorm', 3050], ['Design system', 3900], ['Design', 4650]].map(([tb, x]) => (\n        <div key={tb as string} style={{ position: 'absolute', left: x as number, top: 88, fontSize: 58, color: '#8d8d96' }}>{tb}</div>\n      ))}\n    </div>\n    {/* ClickUp logo 行 */}\n    <div style={{ position: 'absolute', left: 120, top: 560 }}>\n      <FloatWrap h={liftOf(t, 0.54, 250)}>\n        <div style={{ display: 'flex', alignItems: 'center', gap: 26 }}>\n          <CULogo size={104} />\n          <div style={{ fontSize: 92, fontWeight: 800, color: '#222228', letterSpacing: -1 }}>ClickUp</div>\n        </div>\n      </FloatWrap>\n    </div>\n    {/* 主区圆角灰砖：Dropbox 图标 + 下拉 chevron（原片 f45–f60） */}\n    <div style={{ position: 'absolute', left: 1330, top: 440 }}>\n      <FloatWrap h={liftOf(t, 0.62, 260)}>\n        <div style={{\n          width: 620, height: 350, background: '#ebebef', borderRadius: 56,\n          display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 60,\n        }}>\n          <div style={{\n            width: 210, height: 210, background: '#fdfdfe', borderRadius: 44,\n            boxShadow: '0 6px 60px rgba(180,180,200,0.35)',\n            display: 'flex', alignItems: 'center', justifyContent: 'center',\n          }}>\n            <DropboxGlyph size={130} />\n          </div>\n          <svg width={90} height={90} viewBox=\"0 0 40 40\">\n            <path d=\"M 10 15 L 20 26 L 30 15\" fill=\"none\" stroke=\"#6a6a74\" strokeWidth={3.6} strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n          </svg>\n        </div>\n      </FloatWrap>\n    </div>\n    {/* Home 宽药丸（紫边细线横贯面板） */}\n    <div style={{ position: 'absolute', left: 110, top: 830, width: 2900 }}>\n      <FloatWrap h={liftOf(t, 0.68, 260)}>\n        <div style={{\n          width: 2900, height: 168,\n          borderRadius: 34, border: '3.5px solid rgba(118,108,238,0.75)',\n          background: 'rgba(122,110,240,0.09)', display: 'flex', alignItems: 'center',\n          gap: 40, paddingLeft: 56, boxSizing: 'border-box',\n        }}>\n          <svg width={66} height={66} viewBox=\"0 0 40 40\">\n            <path d=\"M 6 20 L 20 7 L 34 20 M 11 17 V 33 H 29 V 17\" fill=\"none\" stroke=\"#5a5ad2\" strokeWidth={3.4} strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n          </svg>\n          <div style={{ fontSize: 70, color: '#5353cf', fontWeight: 550 }}>Home</div>\n        </div>\n      </FloatWrap>\n    </div>\n    {/* Inbox 行 */}\n    <div style={{ position: 'absolute', left: 166, top: 1070 }}>\n      <FloatWrap h={liftOf(t, 0.8, 240)}>\n        <div style={{ display: 'flex', alignItems: 'center', gap: 40 }}>\n          <svg width={64} height={64} viewBox=\"0 0 40 40\">\n            <path d=\"M 20 5 C 13 5 10 10 10 16 V 24 L 6 30 H 34 L 30 24 V 16 C 30 10 27 5 20 5 Z M 16 33 C 16 36 24 36 24 33\"\n              fill=\"none\" stroke=\"#3a3a42\" strokeWidth={3} strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n          </svg>\n          <div style={{ fontSize: 70, color: INK }}>Inbox</div>\n        </div>\n      </FloatWrap>\n    </div>\n    {/* 更多侧栏行 */}\n    {['Docs', 'Dashboards'].map((tb, i) => (\n      <div key={tb} style={{ position: 'absolute', left: 166, top: 1310 + i * 240 }}>\n        <FloatWrap h={liftOf(t, 0.86 + i * 0.06, 230)}>\n          <div style={{ display: 'flex', alignItems: 'center', gap: 40 }}>\n            <div style={{ width: 58, height: 58, border: '6px solid #8f8f98', borderRadius: 14 }} />\n            <div style={{ fontSize: 70, color: INK }}>{tb}</div>\n          </div>\n        </FloatWrap>\n      </div>\n    ))}\n    {/* 主区轮播左箭头（原片 f60 中景的 \"<\"） */}\n    <div style={{ position: 'absolute', left: 2440, top: 1060 }}>\n      <svg width={120} height={120} viewBox=\"0 0 40 40\">\n        <path d=\"M 26 6 L 12 20 L 26 34\" fill=\"none\" stroke=\"#2c2c33\" strokeWidth={4.4} strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n      </svg>\n    </div>\n    {/* 大 W 字形（原片中程右上滑入的大字残段） */}\n    <div style={{ position: 'absolute', left: 3050, top: 300, fontSize: 430, fontWeight: 700, color: '#26262c', letterSpacing: -6 }}>W</div>\n    {/* 主区白色圆角卡群（右下淡白砖） */}\n    {[[2620, 620, 640, 380], [2740, 1360, 720, 420], [2620, 1900, 560, 330]].map(([x, y, w, h], i) => (\n      <div key={i} style={{\n        position: 'absolute', left: x, top: y, width: w, height: h,\n        background: '#fbfbfd', borderRadius: 56, boxShadow: '0 6px 60px rgba(190,190,205,0.3)',\n      }} />\n    ))}\n    {/* —— 右段：Product Management 列表（原片尾程满幅白页） —— */}\n    <div style={{\n      position: 'absolute', left: 3560, top: 230, width: PW - 3560, height: PH - 230,\n      background: '#fbfbfd',\n    }}>\n      <div style={{ position: 'absolute', left: 220, top: 200, fontSize: 150, fontWeight: 750, color: '#232329', letterSpacing: -2, whiteSpace: 'nowrap' }}>Product Management</div>\n      {/* List / Board tabs */}\n      <div style={{ position: 'absolute', left: 240, top: 480, display: 'flex', gap: 110, alignItems: 'center' }}>\n        <div style={{\n          display: 'flex', alignItems: 'center', gap: 26, background: '#ececf1',\n          borderRadius: 22, padding: '20px 40px',\n        }}>\n          <svg width={56} height={56} viewBox=\"0 0 40 40\">\n            {[9, 20, 31].map((y) => (\n              <g key={y}>\n                <rect x={5} y={y - 1.6} width={4} height={4} fill=\"#3a3a42\" />\n                <rect x={14} y={y - 1.4} width={20} height={3.4} rx={1.6} fill=\"#3a3a42\" />\n              </g>\n            ))}\n          </svg>\n          <div style={{ fontSize: 62, fontWeight: 600, color: '#2c2c33' }}>List</div>\n        </div>\n        <div style={{ display: 'flex', alignItems: 'center', gap: 26 }}>\n          <svg width={56} height={56} viewBox=\"0 0 40 40\">\n            <rect x={5} y={7} width={12} height={26} rx={3} fill=\"none\" stroke=\"#3a3a42\" strokeWidth={3} />\n            <rect x={23} y={7} width={12} height={18} rx={3} fill=\"none\" stroke=\"#3a3a42\" strokeWidth={3} />\n          </svg>\n          <div style={{ fontSize: 62, fontWeight: 500, color: '#2c2c33' }}>Board</div>\n        </div>\n        <div style={{ fontSize: 56, color: '#9a9aa4', marginLeft: -40 }}>11</div>\n      </div>\n      <div style={{ position: 'absolute', left: 900, top: 620, width: 1500, height: 3, background: '#e4e4ea' }} />\n      {/* IN PROGRESS chip */}\n      <div style={{\n        position: 'absolute', left: 240, top: 850, background: '#fce4f5', color: '#c93bb0',\n        fontSize: 46, fontWeight: 650, letterSpacing: 2, padding: '14px 30px', borderRadius: 14,\n      }}>IN PROGRESS</div>\n      <div style={{ position: 'absolute', left: 244, top: 1030, fontSize: 44, fontWeight: 600, color: '#8f8f98', letterSpacing: 1 }}>TASK NAME</div>\n      {/* 任务行 */}\n      {[['New Feature Launch', '#3a3a42'], ['Roadmap Q3', '#55555e'], ['User Testing', '#83838d'], ['Bug Triage', '#b3b3bc']].map(([name, col], i) => (\n        <div key={name as string} style={{ position: 'absolute', left: 280, top: 1180 + i * 210, display: 'flex', alignItems: 'center', gap: 56 }}>\n          <div style={{ width: 42, height: 42, borderRadius: 12, background: '#e33bc6' }} />\n          <div style={{ fontSize: 64, fontWeight: 550, color: col as string, whiteSpace: 'nowrap' }}>{name}</div>\n        </div>\n      ))}\n    </div>\n    {/* 亮度：面板内黑罩（随进度揭亮） */}\n    <div style={{ position: 'absolute', inset: 0, background: '#050409', opacity: shade }} />\n    {/* 左缘额外阴影（起始更暗，随亮度一同退去） */}\n    <div style={{\n      position: 'absolute', inset: 0,\n      background: 'linear-gradient(90deg, rgba(5,4,9,0.9), rgba(5,4,9,0) 42%)',\n      opacity: Math.min(1, shade * 1.6),\n    }} />\n  </div>\n);\n\n/* 固定镜头 + 页面沿自身平面横向滑移。\n * 镜头常数（对照原片密帧校准）：perspective 1150、origin 24% 62%、\n * rotateY(-38°)（右缘近、左缘远，顶缘向右上扬）+ rotateZ(-2°)。\n * lx = 页面局部 X 平移（页面自己的横面方向），全程唯一动的量 */\n// v7（批次 16）：用户意见\"改成60度吧\"——rotY -53 → -60（精确定值）\nconst CAM = { persp: 1100, origin: '30% 58%', rotY: -60, rotZ: -2, left: '40%', top: '15%', scale: 0.62 };\n\nconst PanelLayer: React.FC<{ lx: number; shade: number; opacity: number; t: number }> = ({ lx, shade, opacity, t }) => (\n  <AbsoluteFill style={{ opacity }}>\n    <AbsoluteFill style={{ perspective: CAM.persp, perspectiveOrigin: CAM.origin }}>\n      <div style={{\n        position: 'absolute', left: CAM.left, top: CAM.top,\n        transform: `rotateY(${CAM.rotY}deg) rotateZ(${CAM.rotZ}deg)`, transformOrigin: 'left top',\n      }}>\n        {/* 页面自身在其 3D 平面内横移（局部 X 轴） */}\n        <div style={{ transform: `scale(${CAM.scale}) translateX(${lx}px)`, transformOrigin: 'left top' }}>\n          <Panel shade={shade} t={t} />\n        </div>\n      </div>\n    </AbsoluteFill>\n  </AbsoluteFill>\n);\n\nexport const SteepTiltGlide: React.FC = () => {\n  const frame = useCurrentFrame();\n\n  // 页面滑移（物动镜不动）：局部 X 从 +140 → -2680，起步柔和后近匀速，\n  // 全程不安定停死（bezier 尾段斜率不归零）\n  const glide = Easing.bezier(0.3, 0.12, 0.72, 0.9);\n  const lxAt = (f: number) => {\n    const p = interpolate(f, [0, 120], [0, 1], { easing: glide, extrapolateLeft: 'clamp', extrapolateRight: 'clamp' });\n    return interpolate(p, [0, 1], [60, -4100]);\n  };\n\n  const lx = lxAt(frame);\n  // 面板黑罩：起始暗 → 约 1.4s 全亮（对齐原片节奏）\n  const shade = interpolate(frame, [0, 18, 44], [0.7, 0.4, 0], { extrapolateRight: 'clamp' });\n  // 重影强度 ∝ 滑移速度（拖尾=过去时刻的局部位置，同一固定镜头下重投影）\n  const speed = Math.abs(lxAt(frame - 1) - lxAt(frame + 1)) / 2;\n  const g1 = Math.min(0.42, speed * 0.03);\n  const g2 = Math.min(0.22, speed * 0.016);\n  // 文字悬空贴落进程（v4 保留）\n  const drop = interpolate(frame, [4, 100], [0, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' });\n  // 紫晕随亮度浮现\n  const glow = interpolate(frame, [14, 70], [0.15, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' });\n\n  return (\n    <AbsoluteFill style={{ background: '#060409' }}>\n      {/* 左侧紫晕 */}\n      <AbsoluteFill style={{\n        opacity: glow,\n        background: 'radial-gradient(ellipse 40% 50% at 20% 66%, rgba(118,58,190,0.30), transparent 70%)',\n      }} />\n      {/* 重影（先画，垫在本体后面；位置=过去时刻的页面局部位移） */}\n      {g2 > 0.02 && <PanelLayer lx={lxAt(frame - 5)} shade={shade} opacity={g2} t={drop} />}\n      {g1 > 0.02 && <PanelLayer lx={lxAt(frame - 2.5)} shade={shade} opacity={g1} t={drop} />}\n      {/* 本体 */}\n      <PanelLayer lx={lx} shade={shade} opacity={1} t={drop} />\n      {/* 暗角 */}\n      <AbsoluteFill style={{\n        background: 'radial-gradient(ellipse 105% 95% at 55% 42%, transparent 60%, rgba(3,2,8,0.25) 85%, rgba(2,1,6,0.5) 100%)',\n        pointerEvents: 'none',\n      }} />\n    </AbsoluteFill>\n  );\n};\n\n\n"
}