// ===== demos/effects/spotlight-sweep-moves/CornerSpotlightReveal.tsx =====
// corner-spotlight-reveal —— 对标 clickup-30.mp4 41.5–44.6s:
// 黑场上,左上角径向聚光从小到大扩张,把白色 Inbox 界面逐步"点亮",
// 照到的区域显影、照不到的沉黑,最终全屏亮起。光即转场。
import React from 'react';
import { AbsoluteFill, useCurrentFrame, interpolate, Easing } from 'remotion';
const FONT = '"Avenir Next", "Helvetica Neue", Helvetica, sans-serif';
// 灰阶 Inbox 界面(自绘,替代真 UI)
const InboxPanel: React.FC = () => (
All
Tasks
Docs
People
Chat
{[0, 1, 2].map((row) => (
))}
);
export const CornerSpotlightReveal: React.FC = () => {
const frame = useCurrentFrame();
// 聚光半径扩张:全程匀速(用户裁决"整个过程要匀速"——严格 linear,无缓动)
// r+feather=1.85r 是光前沿;1.85*1300≈2400 恰在片尾盖满全屏对角,
// 保证扩张动作占满全片时长而不是前 1/3 就饱和
const r = interpolate(frame, [0, 100], [160, 1300], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
// 光心沿左上角匀速游移(linear)
const cx = interpolate(frame, [0, 96], [140, 420], { extrapolateRight: 'clamp' });
const cy = interpolate(frame, [0, 96], [90, 260], { extrapolateRight: 'clamp' });
// 软边宽度:扩张时边缘更羽化
const feather = r * 0.85;
// UI 轻微透视漂移(原片相机贴着界面缓推)
const drift = interpolate(frame, [0, 100], [0, 1]);
const scale = 1.75 - 0.28 * drift;
const tx = -40 + 70 * drift;
const ty = -30 + 50 * drift;
const mask = `radial-gradient(circle ${r + feather}px at ${cx}px ${cy}px, rgba(255,255,255,1) ${Math.max(
0,
((r - feather * 0.25) / (r + feather)) * 100,
)}%, rgba(255,255,255,0) 100%)`;
return (
{/* 聚光自身的白热光晕(叠在界面上方,光心最亮) */}
);
};
// ===== demos/effects/spotlight-sweep-moves/GlowWakeSleepPanel.tsx =====
// glow-wake-sleep-panel v3 —— 扫光方向改为从左向右(用户裁决):
// 聚光灯从左向右"扫过"斜置面板;一条带辉光的紫色光线贴着 UI 顶边/边框/
// logo 划过,光到即亮、光走即暗,尾段沉回黑暗(右缘残留蓝紫)。
import React from 'react';
import { AbsoluteFill, useCurrentFrame, interpolate } from 'remotion';
const W = 1250;
const H = 860;
const R = 26;
const ink = '#3a3a3a';
const mid = '#9a9a98';
const line = '#e2e2e0';
const Row: React.FC<{ w: number; icon?: boolean }> = ({ w, icon = true }) => (
);
const TaskCard: React.FC<{ seed: number }> = ({ seed }) => (
);
// 灰阶斜置面板(ClickUp 布局形:侧栏 + Review/Shipped 两列)
const Panel: React.FC = () => (
{[0, 1].map((col) => (
))}
);
// 贴边紫色光线(多层辉光:宽糊层+中层+亮芯),水平段,中心在 cx
const EdgeStreak: React.FC<{ cx: number; y: number; len: number; opacity: number; vertical?: boolean }> =
({ cx, y, len, opacity, vertical = false }) => {
const long = { position: 'absolute' as const, left: 0, top: 0, opacity };
const grad = (c: string) => vertical
? `linear-gradient(180deg, rgba(0,0,0,0) 0%, ${c} 45%, ${c} 55%, rgba(0,0,0,0) 100%)`
: `linear-gradient(90deg, rgba(0,0,0,0) 0%, ${c} 45%, ${c} 55%, rgba(0,0,0,0) 100%)`;
if (vertical) {
return (
);
}
return (
);
};
export const GlowWakeSleepPanel: React.FC = () => {
const frame = useCurrentFrame();
// 聚光沿面板顶边从左向右匀速扫过(面板本地座标)
const sx = interpolate(frame, [4, 120], [-260, W + 260], {
extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
});
const sy = 150; // 聚光照在面板上部
// 全局明暗包络:醒 → 展示 → 睡
const env = interpolate(frame, [0, 16, 100, 130], [0, 1, 1, 0], {
extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
});
// 尾段右缘残光:最后只剩右缘一线蓝紫
const rightNear = Math.max(0, Math.min(1, (sx - (W - 420)) / 420));
const tailBlue = interpolate(frame, [100, 116, 132], [0, 0.8, 0.25], {
extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
});
// logo 描光:聚光经过 logo(本地 x≈60)时点亮
const logoGlow = Math.exp(-((sx - 60) ** 2) / (2 * 230 ** 2)) * env;
// 摄影机慢漂移:面板随扫光从左上往右下走(对应扫光方向)
const drift = interpolate(frame, [0, 132], [-150, 150]);
const driftY = interpolate(frame, [0, 132], [-36, 36]);
return (
{/* 聚光环境雾光:跟随光头,泛在面板后黑场 */}
{/* 后层重影面板(截图④⑤双层) */}
{/* 面板本体:聚光范围内显影,范围外沉黑 */}
{/* 贴顶边划过的紫色光线(本体) */}
{/* 右缘竖直光线:聚光接近右侧时点亮,尾段转蓝紫 */}
{/* logo 一圈描光(截图⑤:光经过 logo 时) */}
{/* 光头本体眩光:贴着顶边的亮团 */}
);
};
// ===== demos/effects/spotlight-sweep-moves/SlideSpotlightPan.tsx =====
// slide-spotlight-pan v2 —— 按用户截图 clickup03 重做:
// 紫色光线贴着 UI 面板边缘泛光(先绕左上角竖缘、再沿顶边横走),
// 聚光头匀速右移,照到处显影、离开处沉暗;面板匀速左滑(相机右摇感)。
// 用户裁决:"紫色的光线是贴着ui界面泛光的,聚光的移动是匀速的"。
import React from 'react';
import { AbsoluteFill, useCurrentFrame, interpolate } from 'remotion';
const ink = '#3c3c3a';
const mid = '#98989a';
const line = '#e4e4e2';
const PW = 3000;
const PH = 1400;
const TOP = 150; // 面板顶边在屏幕座标的 y
const CR = 60; // 面板圆角
const SideRow: React.FC<{ w: number }> = ({ w }) => (
);
const Task: React.FC<{ seed: number }> = ({ seed }) => (
);
const Col: React.FC<{ accent: string; seed: number; w: number }> = ({ accent, seed, w }) => (
);
// 超宽面板内容(放大特写级别):侧栏 + 顶栏 + 三列看板
const WidePanel: React.FC = () => (
);
export const SlideSpotlightPan: React.FC = () => {
const frame = useCurrentFrame();
// 面板匀速左滑(相机右摇)——严格 linear
const slide = interpolate(frame, [0, 132], [180, -1100]);
// 聚光头在面板本地座标沿顶边匀速右移——严格 linear
// 起点在左上角竖缘(负值=还在左缘竖直段),随后转过角沿顶边走
const head = interpolate(frame, [0, 132], [-360, 2600]);
const onTop = Math.max(0, head); // 顶边段进度
const cornerT = Math.min(1, Math.max(0, (head + 360) / 360)); // 竖缘段 0→1
const vertHeadY = TOP + 620 - cornerT * 620; // 左缘光头从下往上爬到角
// 屏幕座标的光头位置
const headScreenX = slide + onTop;
// 光头在竖缘阶段贴着面板左缘
const leftEdgeX = slide;
// 竖缘光线强度:角前满、转角后衰减
const vGlow = head < 0 ? 1 : Math.max(0, 1 - head / 900);
// 顶边光线强度:转角后满
const hGlow = Math.min(1, Math.max(0, (head + 120) / 240));
const grad = (dir: string, c: string) =>
`linear-gradient(${dir}, rgba(0,0,0,0) 0%, ${c} 42%, ${c} 58%, rgba(0,0,0,0) 100%)`;
return (
{/* 面板层:聚光范围内显影 */}
{/* 贴面泛光:光头下方的紫光晕染进 UI 顶部(贴着界面泛光的关键层) */}
{/* 左缘贴面泛光(竖缘阶段) */}
{/* 聚光范围外压暗:以光头为中心的显影罩(面板本地座标,跟光头走) */}
{/* ===== 贴边紫色光线本体(屏幕层,贴着面板边缘) ===== */}
{/* 顶边横向光线:三层辉光 + 亮芯,中心=光头 */}
{/* 左上角竖缘光线(起始阶段,贴面板左缘) */}
{/* 顶上方黑檐:光带以上纯黑(截图里顶边之上是黑场) */}
);
};