# Orbit ring title opening

Eight content cards orbit a 700×375 ellipse at constant speed while a centered title resolves into focus and settles.

- Category: intro · Tags: shotcraft, remotion, intro, opening, ui-entrance
- Spec: 1920×1080 @ 30 fps · 4.33s (16:9)
- License: Apache-2.0 · Tier: free
- JSON: https://gimgs.net/motion/orbit-ring-title-open.json
- Kind: remotion
- Source (TSX): https://gimgs.net/motion/orbit-ring-title-open/template.html
- Repo: https://github.com/Vincentwei1021/video-shotcraft
- Credits: video-shotcraft (Vincent Wei) — https://github.com/Vincentwei1021/video-shotcraft
- Page: https://gimgs.net/motion/orbit-ring-title-open.html

## Params

_No params._

Default params (base64url for `?p=`): `e30`

## Prompt

## When to use

Opening shot #1 = "this product is a whole system"; the showcase shot for asset libraries/template libraries/feature matrices/case studies; when a real moving product visual needs to carry a claim instead of a static grid of screenshots

## Intention

Opening with "we have a whole system" is usually done as a grid of screenshots — but a grid is static, and viewers read "a pile of images," not "a moving product." This card turns the display into a **ring tour**: eight cards orbit an ellipse at constant speed, always one entering and one exiting frame, the picture carries its own "there's more" implication, while the title stays locked dead-center, unaffected. The key trade-off is that **the card content has to actually be playing**. Static screenshots on the ring just read as a "carousel"; real motion inside the cards instantly turns the same ring into "the product at work." But if all eight cards start playing at once, eight animations fight for attention and none of them reads — so during the entrance the card content is **frozen on its first frame**, and only after the ring opens up and the title starts do they all begin playing together. The viewer's attention order is therefore: recognize this is a ring of product shots → read the title → then notice the cards are all moving.

## Duration & energy

- Duration: About 4.3s (130f@30fps; a 1.9s steady orbit between the title settling at f50 and exiting at f108)
- Energy: Medium (the only continuous motion is the constant orbit; the marker-block sweep is the film's single impact moment)

## Shot recipe (original Chinese — timing, easing, parameter table, known pitfalls)

## 意图
开场想说"我们有一整套东西"，最常见的做法是把截图排成网格——但网格是静止的，观众
读到的是"一堆图片"，不是"一套会动的产品"。这张卡把陈列改成**环形巡回**：八张卡沿
椭圆匀速公转，永远有卡在进画、有卡在出画，画面自带"还有更多"的暗示，而标题稳稳
钉在正中间不受影响。

关键的取舍是**卡内容要真的在播**。静态截图上环，观众只会认出"轮播图"；卡里跑着真
动效，同一个环立刻变成"产品在工作"。但八张卡同时开播会八个动效抢戏，谁也读不进去
——所以入场期把卡内容**冻结在首帧**，等环撑开、标题起手之后再统一开播。观众的注意
力顺序因此是：先认出这是一圈产品画面 → 读标题 → 才注意到卡里都在动。

## 动效核心
- **环上定位**：`θ = -π/2 + i·2π/8 + t·0.3`，`x = 960 + cos θ·RX·ringScale`、
  `y = 540 + sin θ·RY·ringScale`。RY/RX ≈ 0.54 的椭圆读作"俯视的环"；正圆会读作转盘
- **卡身永不倾斜**：卡只跟着 θ 换位置，自身 transform 只有缩放，没有任何旋转。
  纵深完全交给 `depth = sin θ`（+1 = 画面下方，近；−1 = 上方，远）：
  `scale = 1 + 0.09·depth`、`zIndex = 10 + round(depth·5)`。缩放和 z 序必须由同一个
  depth 驱动，否则会出现"远处的卡压住近处的卡"
- **环入场**：f0–21 `ringScale 0.62→1`（outCubic）从中心撑开；同时逐卡淡入，
  第 i 张的窗口是 `[0.06+0.05i, 0.42+0.05i]s`，最后一张 f23 才满。撑开与淡入叠在
  一起，读作"环长出来"而不是"卡片一张张贴上来"
- **冻结首帧再开播**：卡内容包在 `<Freeze frame={max(0, frame - 24)}>` 里。f24 之前
  八张卡都停在自己的第 0 帧，f24 起同时进入正常时间轴。24f = 环撑开(21f) + 一点余量
- **卡内坐标解耦**：卡内容按 960×540 作画，外层用 `scale((CW·s)/960)` 缩到卡宽 +
  `transform-origin: top left`。内容组件不需要知道自己被缩小了，落地换成真实截图或
  库内其他镜头卡组件时不用改一行
- **标题 blur-slide 逐字**：每字两条通道同起不同终——解糊走满 0.9s
  （`blur (1-p)·fontSize/6`），下沉只占前 0.3s（`translateY (1-p)·fontSize·0.22`）。
  字间错峰 1 帧（0.0333s），缓动 `cubic-bezier(.22,1,.36,1)`。位移先停、模糊后停，
  字才有"落定后继续对上焦"的手感
- **马克块横扫**：`spring(frame-40, damping 14)` 驱动 `scaleX`，
  `transform-origin: left center`，色块 `position:absolute; inset:.06em -.08em; zIndex:0`
  垫在高亮词组底下，词自身 `position:relative; zIndex:1`。缓动前载，f40（1.33s）时末
  字的 ease 值已 ≈0.95，感知上"字全到位了才扫"，实际不必等到 f50 数学收敛
- **退场**：f108–118 整行 `opacity 1→0` + `blur 0→6.5px`，副行同窗同曲线。之后 12f
  只有环在转——这段空档就是交棒位，接 crash-zoom / 穿浅场直切都不用额外铺垫

## 参数表
| 参数 | 典型值 | 调节手感 |
|------|--------|----------|
| 椭圆半径 | RX=700 / RY=375（卡 380×214） | RY/RX≈0.54 是"俯视环"的甜点；比值 →1 读作正圆转盘，→0.3 卡会在上下缘挤成一条 |
| 卡数 | 8（方位角间隔 45°） | 8 张在这个半径上任意转角互不遮挡；≥10 张必须同步加大 RX/RY，否则近处卡压边 |
| 公转速度 | 0.3 rad/s（4.3s 转约 74°） | **别因为"看起来慢"就调快**：>0.5 rad/s 时卡扫过画面边缘会有频闪感，且喧宾夺主 |
| 环入场 | f0–21，scale .62→1，outCubic | <15f 像弹窗；>30f 标题起手时环还在长，两件事互相盖 |
| 逐卡淡入 | 窗口 `[0.06+0.05i, 0.42+0.05i]`s | 步长 0.05s 刚够读出"依次"；>0.1s 最后一张会晚到标题之后 |
| 开播帧 | PLAY_START=24f | 必须 ≥ 环撑开结束帧；提前会让八个动效在入场期一起抢戏 |
| 纵深缩放 | ±9% | >15% 顶部卡会缩成图标，环读作"透视隧道"；=0 则整环扁平，失去前后关系 |
| 标题 | 64px / 600 字重 / 字距 −0.05em | 环一直在动，标题必须够重才压得住；<48px 或 400 字重会被环吃掉 |
| 逐字节奏 | lead .35s，解糊 .9s，下沉 .3s，错峰 1f | 错峰 1f 是"整体解糊"的手感；≥3f 会读成逐字打字机 |
| 马克块 | f40 起，spring damping 14，#facc15 | damping <10 会回弹出色块边缘；起扫早于末字 ease 0.9 时读作"色块追着字跑" |
| 副行 | mono 28px，字距 0.35em，1.0–1.5s 淡入 | 大字距 mono 是"产品代号"的读法；跟标题同字体会读作第二行标题 |
| 退场 | f108–118，blur 0→6.5px | 整行统一失焦；**逐字退场会读作第二次入场** |

## 已知坑
- **卡不能跟着 θ 倾斜**。给卡加 `rotate(θ)` 后环立刻从"陈列"变成"过山车"，而且卡内
  文字会歪，可读性直接归零。卡只换位置，不换角度
- 卡内容首帧必须自带静态骨架（底色/边框/标签/灰底轨迹）。冻结期显示的就是第 0 帧，
  如果卡的动效是"从零画出来"，入场那 24f 就是八张空白卡。demo 里每个占位卡都补了
  灰底 sparkline / 淡稿线 / 常驻提示符，就是为了让首帧不空
- `zIndex` 必须跟着 depth 走。只做缩放不排 z 序时，DOM 顺序会让后面的卡压住前面的，
  近大远小的立体感当场作废
- 马克色块和字的层级是一对：色块 `zIndex:0` + 字 `position:relative; zIndex:1`。漏掉
  字上的 relative，色块会盖住字（stacking context 里 static 元素排在 positioned 之后）
- 标题 `white-space: nowrap` 是马克块的前提——`inset:.06em -.08em` 假设高亮词组在同
  一行盒里。换行后色块会跨行断裂成两截
- 环是背景层但它一直在动，所以**不要在环上再叠第二个动的东西**（粒子、扫光、渐变
  呼吸）。已经有一个持续运动在场，第二个会让画面读不出主次
- 与 `carousel-3d` 的分工：那张卡是真 3D（`rotateY + translateZ` + backface-hidden），
  卡会转到环背面，适合无缝 loop 的纯陈列；这张卡是 2D 椭圆伪纵深，卡永远正面朝观众，
  适合"环托底 + 前景标题"的开场。要卡片翻面用前者，要标题压得住用后者
- demo 的八张卡是原创通用 DOM 占位（灰阶骨架 + 一条强调色），不含任何产品截图；
  落地时整块替换成你自己的镜头卡组件或真实页面截图即可，环的语法一行都不用改

## 参考实现
demos/opening/orbit-ring-title-open/
（OrbitRingTitleOpen.tsx）

## Reference implementation (Remotion)

- demos/opening/orbit-ring-title-open/OrbitRingTitleOpen.tsx — https://raw.githubusercontent.com/Vincentwei1021/video-shotcraft/main/demos/opening/orbit-ring-title-open/OrbitRingTitleOpen.tsx

The component imports shared fixtures from `demos/_fixtures` and helpers from `assets/lib` in the repo; SKILL.md there documents the render workflow.


## Flow

1. **Read the recipe**
   Prompt = when to use, intention, parameter table with typical values and how each one feels, known pitfalls. Treat values as calibrated starting points.
2. **Get the code** — tool: git
   `git clone https://github.com/Vincentwei1021/video-shotcraft && cd video-shotcraft && npm install`
3. **Register + render** — tool: remotion
   `npx remotion render <CompositionId> out.mp4   # component: demos/opening/orbit-ring-title-open/OrbitRingTitleOpen.tsx`
4. **Or re-implement**
   Port the timing/easing from the recipe to HTML + WAAPI (gimgs motion contract) or any engine; keep the same segment windows and easing.

## Render

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.

## 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.
