// ===== demos/ui-entrance/integration-hub-map/IntegrationHubMap.tsx =====
// integration-hub-map v5 —— 批次 14 单点节奏修正:
// 用户意见(逐字)"动作对了,但是需要翻的时候很快,最后快完成的时候变慢下来"
// → rotateY 0→180° 改为快翻+尾段减速:强 ease-out(cubic),前 ~40% 时间
// 完成 ~80% 角度,尾段明显减速缓着陆;仍一次连贯完成、无分段停顿
// (判例:"匀速"=无停顿≠字面 linear,本条已被用户亲自纠正为快翻尾缓)。
// 90° 侧棱时刻随之提前到 ~f28,白热爆发峰值同步前移对齐。其余全保留。
// —— 以下为 v3 说明(结构沿用):
// ① 开头不是"转一个角度",而是页面整个 rotateY 翻转 180° 翻到背面,
// 得到一张新的页面(双面卡:正面=近景旧页,背面=翻正后的新中枢页),
// 翻到侧棱(~90°)时白热爆发吞没画面(对应截图 3/4)。
// ② 五图标光管连上后有"输送感":亮脉冲沿管线方向(图标→中枢)持续
// 循环流动,直到片尾不停。
// 运动结构对照截图:S1 近景正视可读 → S2 翻转中+拉远+泛光起 →
// S3/S4 侧棱白热爆发+图标浮现 → S5/S6 新页转正、光管连入 → S7/S8 稳定输送。
import React, { useId } from 'react';
import { AbsoluteFill, useCurrentFrame, interpolate, Easing } from 'remotion';
const mulberry32 = (a: number) => () => {
let t = (a += 0x6d2b79f5);
t = Math.imul(t ^ (t >>> 15), t | 1);
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
const rand = mulberry32(20260718);
const NOISE: number[] = Array.from({ length: 200 }, () => rand());
const FONT = '"Avenir Next", "Helvetica Neue", Helvetica, sans-serif';
// ---------- 中枢面板(Enterprise MQLs,内容对照截图 1/7) ----------
const LIST: { icon: string; title: string; sub: string }[] = [
{ icon: '#4a9fd8', title: 'Q3 Enterprise Deal', sub: 'Revenue · Pipeline · Q3 Quota' },
{ icon: '#4a9fd8', title: 'Major Enterprise Account - UK', sub: 'Revenue · MQL · International' },
{ icon: '#34a853', title: 'Enterprise Pitch Deck', sub: 'Open in GDrive' },
{ icon: '#a259ff', title: 'MQL Lead Form Design', sub: 'Figma File · Last Edited' },
{ icon: '#f2c744', title: 'Enterprise Sales', sub: 'ClickUp Space' },
{ icon: '#9a9a98', title: 'Enterprise Closed Archive', sub: 'Archived · In Enterprise Sales' },
{ icon: '#c8c8c6', title: 'Open Enterprise Lead - Follow up', sub: 'In Progress · In Enterprise Sales · Yesterday' },
];
const HubPanel: React.FC<{ glow: number }> = ({ glow }) => (
Enterprise MQLs
{['All', 'Tasks', 'Docs', 'Whiteboards', 'Dashboards', 'Files', 'Chat', 'People'].map((t, i) => (
{t}
))}
Recent
{LIST.map((it, i) => (
))}
+ Add Location Filter
QUICK FILTERS
{['Assigned to Me', 'Created by Me'].map((t) => (
{t}
))}
TASK FILTERS
{['Open', 'Closed', 'Archived'].map((t) => (
{t}
))}
);
// ---------- 翻转前的旧页面(正面):另一张页面,翻面后才得到中枢页 ----------
const FrontPanel: React.FC<{ glow: number }> = ({ glow }) => (
{['Revenue', 'Pipeline', 'Q3 Quota'].map((t) => (
{t}
))}
{/* 文档灰条段落 */}
{[420, 700, 660, 540, 0, 690, 630, 380, 0, 580, 640, 460].map((w, i) =>
w === 0 ? (
) : (
),
)}
);
// ---------- 品牌图标瓷贴 ----------
const Tile: React.FC<{ kind: string; on: number }> = ({ kind, on }) => {
const glyph = (() => {
switch (kind) {
case 'figma':
return (
);
case 'github':
return ;
case 'salesforce':
return (
);
case 'gdrive':
return (
);
default: // dropbox
return (
);
}
})();
return (
{glyph}
);
};
// ---------- 光管(彩虹渐变霓虹管) ----------
type Pipe = { kind: string; icon: [number, number]; path: string; len: number; tIcon: number; tPipe: number };
const PIPES: Pipe[] = [
{ kind: 'figma', icon: [452, 262], path: 'M 452 322 L 452 440 Q 452 480 492 480 L 552 480', len: 300, tIcon: 52, tPipe: 62 },
{ kind: 'github', icon: [252, 612], path: 'M 316 612 L 552 612', len: 240, tIcon: 52, tPipe: 62 },
{ kind: 'salesforce', icon: [992, 178], path: 'M 992 240 L 992 332', len: 92, tIcon: 52, tPipe: 62 },
{ kind: 'gdrive', icon: [1512, 272], path: 'M 1512 332 L 1512 440 Q 1512 480 1472 480 L 1372 480', len: 290, tIcon: 52, tPipe: 62 },
{ kind: 'dropbox', icon: [1702, 618], path: 'M 1640 618 L 1372 618', len: 270, tIcon: 52, tPipe: 62 },
];
const GROW = 9; // v8(批次 17):用户意见"翻转过来后,5个app同时出现,然后同时连接"——两拍制:五图标 tIcon 统一 52 同帧出现,五管 tPipe 统一 62 同帧连接
// ---------- 背景霓虹矩形轮廓 ----------
const RECTS = Array.from({ length: 9 }, (_, i) => ({
x: [150, 660, 1740, 250, 1150, 700, 1660, 90, 1330][i],
y: [255, 355, 545, 850, 935, 985, 830, 555, 760][i],
w: 90 + NOISE[i * 3] * 160,
h: 60 + NOISE[i * 3 + 1] * 70,
hue: [265, 285, 300, 255, 275, 210, 320, 240, 40][i],
ph: NOISE[i * 3 + 2] * Math.PI * 2,
}));
export const IntegrationHubMap: React.FC = () => {
const frame = useCurrentFrame();
// 滤镜/渐变 ID 按实例生成,多实例同场不串引(useId 的 «:» 在 url() 里非法,需清洗)
const uid = useId().replace(/[^a-zA-Z0-9]/g, '');
// --- 相机/面板轨迹:近景正视旧页 → 整体翻转 180°(翻到背面=新页)+ 拉远落定 ---
const zoom = interpolate(frame, [0, 14, 58, 96], [2.05, 1.95, 1.1, 1.0], {
extrapolateRight: 'clamp',
easing: Easing.inOut(Easing.cubic),
});
// v6(批次 15):用户意见"翻转再快1倍"——翻面窗口 f14–84(70 帧)
// 压半到 f14–49(35 帧),快翻+尾段减速曲线形状保持;
// 90° 侧棱相应提前到 ~f21.2(easeOut=0.5 → t≈0.206)。
const rotY = interpolate(frame, [14, 49], [0, 180], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
easing: Easing.out(Easing.cubic),
});
const panX = interpolate(frame, [0, 18, 55, 96], [130, 120, 30, 0], {
extrapolateRight: 'clamp',
easing: Easing.inOut(Easing.cubic),
});
const panY = interpolate(frame, [0, 18, 55, 96], [120, 110, 30, 25], {
extrapolateRight: 'clamp',
easing: Easing.inOut(Easing.cubic),
});
// v6:用户意见"中间不需要长时间的光晕,翻到中间闪一下就行"——
// 长光晕平台删除,改为 90° 侧棱时刻(~f21)2 帧脉冲亮闪即回落
const bloom = interpolate(frame, [19, 21, 23, 27], [0, 1, 0.25, 0], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
const noise = NOISE[Math.min(frame, NOISE.length - 1)];
// 全连通后呼吸
const allOn = Math.max(...PIPES.map((p) => p.tPipe)) + GROW;
const breathe = frame > allOn ? 0.5 + 0.5 * Math.sin((frame - allOn) * 0.16) : 0;
const panelGlow = bloom * 1.1 + breathe * 0.2;
// 星图元素(图标/光管/矩形)整体可见度
const mapIn = interpolate(frame, [34, 60], [0, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' });
return (
{/* 暗紫底噪 */}
{/* 背景霓虹矩形轮廓 */}
{RECTS.map((r, i) => {
const on = interpolate(frame, [36 + i * 4, 52 + i * 4], [0, 1], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
const settle = frame > 100 ? 0.55 : 1;
const flick = 0.65 + 0.35 * Math.sin(frame * 0.11 + r.ph);
return (
);
})}
{/* 光管层 */}
{/* 图标瓷贴 */}
{PIPES.map((p, i) => {
const appear = interpolate(frame, [p.tIcon, p.tIcon + 12], [0, 1], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
easing: Easing.out(Easing.cubic),
});
const on = interpolate(frame, [p.tPipe, p.tPipe + 10], [0.15, 1], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
if (appear <= 0) return null;
return (
allOn ? 0.8 + 0.2 * breathe : 1)} />
);
})}
{/* 中枢面板:双面卡整体翻转 180°(正面旧页 → 背面新中枢页) */}
{/* 正面:翻转前的旧页面 */}
{/* 背面:翻正后得到的新中枢页(预转 180° 使翻完时朝向镜头且不镜像) */}
{/* 面板过曝罩:爆发期盖白 */}
90 ? 'rotateY(180deg) translateZ(1px)' : 'translateZ(1px)',
backfaceVisibility: 'hidden',
}}
/>
{/* 全屏白热眩光(S3/S4):白核+品红/粉翼+青蓝斑 */}
{bloom > 0.02 && (
{/* 横向紫白光条(S2 左侧光痕) */}
)}
);
};