返回效果库

光斑卡片

Spotlight Card

光跟着指针走,卡片边缘一起亮起

完整版:适合从零新建组件,规格、契约、验收全都在。

实时预览

指针交互
指针 · 光斑 · 边框

一束光跟着你的指针走

把它移到卡片上:光斑跟着走,边缘同时亮起,卡片朝你微微倾斜。

指针进入卡片试试在卡片上拖动试试
把指针移进这片区域触屏设备:直接在演示区域操作检测到「减少动态效果」,动效已降级

参数

边调边看,提示词同步更新。

角色

你是一名资深前端工程师,工作在现有的项目中,技术栈是 React 19 + TypeScript + Tailwind CSS v4 + Motion v14(motion 包)。只实现下面这一个微交互:不要加额外功能,不要顺手重构周围代码。

任务

实现光斑卡片:一束 220px 的柔和径向光跟随指针在卡片表面移动,并同步点亮 1px 边框;卡片朝指针方向倾斜最多 6 度,悬停时缩放到 1.02。

文件契约

- 只新建一个文件:components/effects/SpotlightCard.tsx。

- 依赖:项目已安装 motion@14,从 motion/react 引入。不要新增任何其他包。

- 不要修改 package.json、全局 CSS、Tailwind 配置或任何其他已有文件。

实现要点

- 文件顶部加 "use client"。

- 用 useMotionValue 保存指针位置(百分比字符串)和光斑透明度;用 useSpring 驱动 rotateX / rotateY / scale;用 useMotionTemplate 生成 radial-gradient 背景。

- 边框高光用 1px padding + mask-composite: exclude(WebKit 下 WebkitMaskComposite: "xor")把渐变裁到 1px 边框上。

- 导出 SpotlightCard,props 为 spotlightSize、intensity、tilt、scale、borderHighlight、title、description、footer、className。

规格 —— 精确数值,不许四舍五入或“优化”

- 卡片:宽 100%、最大 400px,高 260px,圆角 20px,背景 #0C0E11,1px 实线边框 rgba(255, 255, 255, 0.08),内边距 28px。

- 透视:在被变换的元素上设置 900px(transformPerspective)。

- 倾斜:rotateY = ((指针X / 宽度) − 0.5) × 2 × 6deg;rotateX = (0.5 − 指针Y / 高度) × 2 × 6deg。

- 倾斜与缩放共用弹簧:刚度 200、阻尼 24、质量 1。

- 悬停缩放:指针在卡片内时 1.02,离开回到 1。

- 光斑:radial-gradient(220px circle at <指针位置>, rgba(201, 244, 90, 0.22), transparent 65%),指针位置用卡片内的百分比写入 CSS 变量 --mx / --my。

- 边框高光:1px 边框用同一束径向渐变绘制,颜色 rgba(201, 244, 90, 0.65)、圆心跟随指针;用 1px padding + mask-composite: exclude(WebKit 用 WebkitMaskComposite: "xor")把渐变裁到边框上。

- 内容:眉标 10px 等宽、字距 0.18em、颜色 #6A6D74;标题 24px / 600 / 1.1,颜色 #EDEEF0;描述 13.5px / 1.7,颜色 #9A9CA1,最多 30ch。

- 只允许改变 transform、opacity,以及不触发重排的背景绘制。

行为

- 指针事件绑在卡片自身上;指针位置不要走 React state(用 motion value 或 CSS 变量)。

- pointerenter:光斑淡入、缩放到设定值;pointerleave:倾斜与缩放弹回原位、光斑淡出。

- 触屏:光斑跟随触点,但不倾斜、不缩放。

- 键盘:卡片内的 CTA 必须是真实按钮/链接,focus-visible 显示 2px #C9F45A、外扩 3px 的描边;卡片聚焦时不倾斜。

- prefers-reduced-motion: reduce:不倾斜、不缩放;保留居中的静态光斑(不跟随指针、不做淡入动画)与边框高光。

- 指针快速移动时不能堆积动画或抖动;中途离开卡片必须回到静止状态。

- 卸载时清理监听与动画;不要每帧触发状态更新。

禁止

- 光斑不要用 canvas、WebGL 或图片实现。

- 不要用动画改变 width / height / top / left / margin / padding / box-shadow。

- 弹簧驱动 transform 时不要再叠加 CSS transition。

- 不要留 TODO、不要写 // 其余代码、不要用 any、不要 console.log、不要留注释掉的实验代码。

- 不要把组件包进页面、布局、演示壳或 Provider。

- 不要改动全局 CSS、Tailwind 配置或上面文件之外的任何文件。

- 除 Motion 外不要引入任何动画库,更不要用 GSAP。

验收 —— 回答前逐项自查

1. 光斑跟随指针,边框高光同步点亮。

2. 倾斜方向与指针位置一致,离开后约 0.5s 内平滑归位。

3. 悬停缩放符合规格,离开后缩放回到 1、旋转回到 0。

4. 卡片内的 CTA 可点击,键盘聚焦有可见描边。

5. 只有 transform / opacity / 绘制变化,DevTools 中零布局位移。

6. 触屏不倾斜;prefers-reduced-motion 下关闭倾斜与缩放,但保留光斑与边框高光。

7. 渲染数值与规格完全一致:光斑尺寸、强度、倾斜、缩放。

输出

- 用一个代码块输出完整文件内容,不要 diff、不要省略号,代码块之前不要解释。

- 如果缺少必要依赖,先停下来问我,不要擅自安装。

- 代码块之后最后输出一行:self-check: 1 ✓ · 2 ✓ · 3 ✓ · 4 ✓ · 5 ✓ · 6 ✓ · 7 ✓,未通过的项用 ✗ 并附一句原因。

与演示同源生成2,591 字符 · 720 约 tokens · 59 行
技术规格

指针在卡片表面移动时,一束柔和的径向光跟随指针,1px 边框同步点亮;卡片朝指针方向轻微倾斜,离开后弹回原位。位置只用 CSS 变量与 transform 驱动,不触发重排。

光斑尺寸
220 px
光斑强度
0.22
倾斜角度
6 °
悬停缩放
1.02 ×
边框高光
开启
卡片
400 × 260 px
圆角
20px
透视
900px
光斑颜色
rgba(201, 244, 90, 0.22)
光斑直径
220px
边框高光颜色
rgba(201, 244, 90, 0.65)
弹簧
200 / 24
内容内边距
28px
验收清单

提示词要求 AI 在输出末尾逐条自检。

  1. 光斑跟随指针,边框高光同步点亮。
  2. 倾斜方向与指针位置一致,离开后约 0.5s 内平滑归位。
  3. 悬停缩放符合规格,离开后缩放回到 1、旋转回到 0。
  4. 卡片内的 CTA 可点击,键盘聚焦有可见描边。
  5. 只有 transform / opacity / 绘制变化,DevTools 中零布局位移。
  6. 触屏不倾斜;prefers-reduced-motion 下关闭倾斜与缩放,但保留光斑与边框高光。
  7. 渲染数值与规格完全一致:光斑尺寸、强度、倾斜、缩放。

待回归验证提示词与演示已同源生成;尚未在真实 Cursor / Claude Code 项目中做回归。

提示词如何还原这个效果

不是把效果描写一遍,而是把效果写成一份可执行的工程需求。

数字规格
每个像素、每个时间参数都来自同一个参数源——滑块改什么,提示词就写什么。
文件契约
只允许新建指定文件、指定依赖白名单,避免它顺手改你的全局样式或装一堆包。
验收清单
提示词末尾强制 AI 自检布局位移、键盘可用、reduced-motion 等 7 项。
完整版 / 中文

React + Tailwind + Motion