加载中…
创作者 · MotionSites
查看原始来源 ↗Prompt
### 概述
为名为 "prmpt" 的品牌构建一个全屏、由滚动驱动的时尚/档案落地页。页面分为两个主要阶段:
1. **Hero 阶段**(滚动的前 100vh):全视口视频背景,上方叠加 UI(logo、导航、产品信息、自定义光标)。一个黑色面板从下方向上滑动并覆盖视频。
2. **Gallery 阶段**(继续滚动):黑色面板中包含一个错落排列的产品图片网格,图片进入/离开视口时会放大/缩小。最后,一个白色叠层淡入,并显示 "view" CTA 按钮。
---
### 技术栈
- **React 19** + **TypeScript**
- **Vite 6**,使用 `@vitejs/plugin-react`
- **Tailwind CSS v4**,通过 `@tailwindcss/vite` 插件使用
- **GSAP 3.15** + `@gsap/react`(ScrollTrigger)
- **Motion (Framer Motion) 12**(`motion/react`)
- **字体**:"Inter Tight"(Google Fonts,字重 500)-- 通过 `<link>` 或 import 加载
---
### 资源 URL
**视频(CloudFront):**
- LEFT 视频:`https://d8j0ntlcm91z4.cloudfront.net/user_39ca84eAE1ODL9hbR5VhoEj8tBf/hf_20260625_154433_532a85d3-dabf-4265-b8bd-19ac6af31842.mp4`
- RIGHT 视频:`https://d8j0ntlcm91z4.cloudfront.net/user_39ca84eAE1ODL9hbR5VhoEj8tBf/hf_20260625_154401_a664f076-b971-4557-8728-40ef9ea4c49b.mp4`
**Gallery 图片(共 10 张,按顺序):**
1. `https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20260629_104530_521b2f85-c0f3-4d0e-9704-b578315b4cb9.png&w=1920&q=85`
2. `https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20260629_103711_76ccdb8b-5043-4f47-9c54-4379713393ea.png&w=1920&q=85`
3. `https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20260629_103728_394f6a1b-85e2-4386-a4f6-408472a0a5b7.png&w=1920&q=85`
4. `https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20260629_103739_86743e0e-16a7-4bee-bf38-dd67985344dc.png&w=1920&q=85`
5. `https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20260629_103748_b2215dc8-a3a7-470d-b19a-5b87fa7d0c37.png&w=1920&q=85`
6. `https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20260629_103758_e919ce72-5c9d-4b87-9be6-d7647b34825c.png&w=1920&q=85`
7. `https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20260629_103808_013583d0-3386-4547-9832-37c7d8edb3ac.png&w=1920&q=85`
8. `https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20260629_103937_a0c49d0a-33eb-4ead-aea6-c1baf241acbc.png&w=1920&q=85`
9. `https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20260629_103956_d18ed8fd-7b6f-4b86-91f9-20010fe38670.png&w=1920&q=85`
10. `https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20260629_104034_ba5a9963-87ff-4008-a545-6bd686c088b5.png&w=1920&q=85`
---
### SECTION 1:Hero(视频背景 + 叠加 UI)
#### 根容器
- `id="scroll-spacer"`、`position: relative`、`user-select: none`、`background: white`
- 高度动态计算(初始为 `500vh`,随后由 GSAP 覆盖为 `vh + maxScroll + 2*vh`)
- 桌面端隐藏默认光标(`cursor: none`),触摸设备使用默认光标
#### 1A. 自定义光标(仅桌面端)
- 在移动端/平板端隐藏(< 1024px)
- 一个跟随 `mousemove` 的 `fixed`、`pointer-events-none`、`z-index: 50` div
- 通过直接操作 DOM 定位(`style.left/top = clientX/clientY`)
- 使用 `transform: translate(-50%, -50%)` 将其中心对准指针
- `mix-blend-mode: exclusion`
- 包含一个 48x48 SVG:一个带描边的圆(r=22.75,strokeWidth=2.5),内部包含自定义日文/装饰性字形 path,全部填充为白色
#### 1B. Logo(左上角)
- `position: fixed`、`pointer-events-none`、`z-index: 20`
- `mix-blend-mode: exclusion`
- 响应式宽度:124px(移动端 < 640)、266px(平板端 640-1024)、355px(桌面端)
- 位置:移动端为 `top: 16px, left: 16px`,桌面端为 `top: 32px, left: 32px`
- Motion 动画:淡入 + 向上滑动(`opacity: 0->1, y: 12->0`),时长 0.6s,ease `[0.25, 0.1, 0.25, 1]`,延迟 0s
- SVG viewBox `0 0 355 110`,包含 "prmpt" wordmark + 带圆圈的 "R" 标记,所有 path 均填充为白色
#### 1C. 说明文字(Logo 下方,左侧)
- `position: fixed`、`pointer-events-none`、`z-index: 20`
- `mix-blend-mode: exclusion`
- 位置:桌面端 `left: 32px`,移动端 `left: 16px`
- Top:桌面端 244px、平板端 180px、移动端 118px
- 宽度:桌面端 692px、平板端 `calc(50vw - 48px)`、移动端 `calc(100vw - 32px)`
- 字体:Inter Tight,字重 500,字号 12px,line-height 140%,letter-spacing -0.04em,颜色 #FFFFFF
- Motion 动画:与 logo 相同,但延迟 0.3s
- 文本内容:"在中心附近切换视频时,不要突然将 currentTime 重置为 0。添加一个小型死区:如果光标位于中心 +/-50px 范围内,则让两个视频都保持 currentTime = 0,并显示上一次处于激活状态的视频。"
#### 1D. Header 导航(右上角)
- `position: fixed`、`z-index: 20`、`pointer-events-none`
- `mix-blend-mode: exclusion`
- 位置:桌面端为 `top: 32px, right: 32px`,移动端为 `top: 16px, right: 16px`
- 宽度:桌面端 330px,移动端 auto
- 高度:30px
- Flex row,justify-content: space-between,align-items: center
- Motion 动画:相同 easing,延迟 0.15s
- 包含:
- "关于" 文本(移动端隐藏):Inter Tight,500,15px,大写,白色
- 一个 gap 为 50px(桌面端)/ 20px(移动端)的 flex row:
- Hamburger SVG 图标:viewBox `0 0 40 40`,两条水平线(`M0 14H40` 和 `M0 26H40`),描边为白色,strokeWidth 2.5。尺寸:桌面端 30x30,移动端 24x24
- "[ 购物车 ]" 文本:Inter Tight,500,桌面端 15px / 移动端 13px,白色
#### 1E. 产品信息(右下角)
- `id="outro-info"`、`position: fixed`、`pointer-events-none`、`z-index: 20`
- `mix-blend-mode: exclusion`
- **桌面端**:right: 32px,bottom: 80px,width: 330px,flex-column,居中对齐
- **移动端**:left: 0,right: 0,bottom: 48px,flex-column,居中对齐
- Motion 动画:opacity 0->1,延迟 0.45s
- `data-outro-offset`:桌面端 166,移动端 132 -- 用于滚动动画
- 包含:
- 顶部区块(flex-column、align flex-start,桌面端宽度 100% / 移动端 252px,桌面端 margin-bottom 32px / 移动端 12px):
- 圆形图标:relative div(桌面端 30x30,移动端 20x20),包含:
- SVG 圆形(cx=20,cy=20,r=18.75,描边为白色,桌面端 strokeWidth 2.5 / 移动端 2)
- `<span id="circle-symbol">` 在内部居中,初始显示 "8",滚动时变为 `['8', '$', '^^', '%', '/']` 中的随机符号(节流 80ms)
- 字体:Inter Tight,500,桌面端 15px / 移动端 10px,letter-spacing -0.04em,大写,白色
- 系列标签:Inter Tight,500,桌面端 30px / 移动端 20px,line-height 100%,文本居中,letter-spacing -0.04em,大写,白色。内容:`档案系列` + 换行 + `"PROMPT"`
- 价格:Inter Tight,500,桌面端 80px / 移动端 60px,line-height 100%,文本居中,letter-spacing -0.04em,白色。内容:`$97,33`
#### 1F. "view" 按钮(右下角,初始隐藏)
- `id="outro-buy"`、`position: fixed`、`pointer-events-none`、`z-index: 20`
- `mix-blend-mode: exclusion`
- **桌面端**:right: 32px,bottom: 32px,width: 330px,height: 174px
- **移动端**:left: 16px,right: 16px,bottom: 60px,height: 100px
- `transform-origin: right bottom`、`transform: scale(0)`(初始隐藏,通过滚动缩放至 1)
- 背景:#fff,border-radius: 1335px(胶囊形)
- Flex 居中
- 文本 "view":Inter Tight,500,桌面端 110px / 移动端 72px,letter-spacing -0.04em,颜色 #fff,`mix-blend-mode: exclusion`
#### 1G. 视频容器
- `id="main-canvas"`、`pointer-events-none`
- **桌面端**:`position: fixed, inset: 0, width: 100%, height: 100%, z-index: 0`
- **移动端**:`position: fixed, left: 0, top: 220px, width: 100vw, height: calc(100vh - 220px), z-index: 0`
- 两个视频都加载完成后,透明度从 0 过渡至 1(`opacity 0.3s ease`)
- `overflow: hidden`
- 包含两个 `<video>` 元素(muted、playsInline、preload="auto"),使用绝对定位填满容器,`object-fit: cover`
- Left 视频初始为 `display: none`,right 视频初始为 `display: block`
**桌面端(非触摸):**
- 视频不会自动播放。通过 `requestAnimationFrame` 根据光标的 X 位置进行拖动播放。
- 死区:距中心 `Math.max(30, width * 0.05)` 像素
- 如果光标位于死区内,让当前视频保持 `currentTime = 0`
- 如果光标移动到死区左侧:显示 RIGHT 视频,根据从中心左侧死区边缘到左边缘的距离拖动播放
- 如果光标移动到死区右侧:显示 LEFT 视频,根据从中心右侧死区边缘到右边缘的距离拖动播放
- `activeSideRef` 跟踪上一次激活的是哪一侧,仅当光标越过死区时才改变
- 进度计算:`(distance from dead zone edge) / (available range)` 映射至 `0...video.duration`
关键要求:仅在 !video.seeking 时更新 currentTime -- 这样会等待浏览器完成上一次跳转的渲染,再请求新的跳转,从而避免播放抖动。
#### 1H. 视频交互逻辑
**移动端/平板端(触摸):**
- 视频交替自动播放:先播放 left,触发 `ended` 事件时切换至 right,right 触发 `ended` 时再切换回 left
- 遵循 `prefers-reduced-motion`
#### 1I. 白色叠层
- `id="outro-overlay"`、`position: fixed, inset: 0`、`pointer-events-none`、`z-index: 12`
- 背景:#fff,opacity: 0(由滚动控制)
#### 1J. Footer
- `id="outro-footer"`、`position: fixed`、`pointer-events-none`
- Left: 16px,桌面端 bottom: 32px / 移动端 24px
- `mix-blend-mode: exclusion`,opacity: 0(由滚动控制)
- Flex row,桌面端 gap: 80px / 移动端 space-between
- 两个 span:"PRMPT (R) 2026" 和 "隐私政策"
- 字体:Inter Tight,500,桌面端 13px / 移动端 11px,letter-spacing -0.02em,大写,白色
---
### SECTION 2:黑色面板(Gallery)
#### 容器
- `position: fixed, inset: 0`,背景为黑色,`z-index: 10`
- 初始向下平移 `translateY(100vh)`(位于屏幕下方)
- 通过 GSAP ScrollTrigger 在滚动的前 100vh 内向上滑动至 `translateY(0)`(scrub: true,ease: none)
#### 内层 Wrapper
- `width: 100%`、`padding-top: min(400px, 40vh)`
#### 网格布局算法
- 响应式列数:2(< 640px)、3(640-1024px)、4(>= 1024px)
- 每个单元格使用 `aspect-ratio: 2/3`
- 布局函数 `buildLayout(count, cols)` 创建各行:
- 对每一行 `r`,计算主列:`a = (r * 2 + (r % 2)) % cols`
- 在 `a` 列放置一张图片
- 每第 3 行(`r % 3 === 0`),在 `b = (a + 2) % cols` 放置第二张图片(如果与 a 相同,则使用 `(a+1)%cols`)
- 空单元格填入 `-1`(渲染为空白 spacer div)
#### 卡片行为
- 每张卡片都使用 class `bp-card`、`will-change: transform`
- 初始为 `transform: scale(0)`
- `transform-origin`:网格左半部分的卡片使用 `right bottom`,右半部分使用 `left bottom`
- 每一帧都根据卡片的垂直位置在 RAF 中计算缩放:
- **进入**:`Math.min(1, (vh - top) / (vh * 0.6))` -- 进入视口时从 0 缩放至 1
- **退出**:`Math.min(1, bottom / (vh * 0.4))` -- 从顶部退出时从 1 缩放至 0
- 最终缩放值:`Math.min(enter, exit)`
- 如果卡片完全位于屏幕外(bottom <= 0 或 top >= vh):`scale(0)`
#### 滚动阶段(基于 RAF,而非 scroll 事件)
- **Phase 1**(scrollY 0 至 vh):面板向上滑动。使用 panelOffset = `vh - scrollY` 计算卡片
- **Phase 2**(scrollY > vh):面板固定在顶部。内层 wrapper 向上平移:`translateY(-(scrollY - vh))`。使用 phase2 offset 重新计算卡片
- **Outro**(scrollY > vh + maxScroll):白色叠层淡入,产品信息向上滑动 `outroOffset` px,"view" 按钮从 0 缩放至 1,footer 淡入。进度:`(scrollY - vh - maxScroll) / (vh - 100)`
#### Spacer 高度计算
- 动态设置为:`vh + maxScroll + 2 * vh`,其中 `maxScroll = wrapScrollHeight - vh`
---
### CSS(index.css)
```css
@import "tailwindcss";
.bp-card {
will-change: transform;
}
@media (prefers-reduced-motion: reduce) {
.bp-card {
will-change: auto;
}
}
```
---
### 响应式断点
- **移动端**:< 640px
- **平板端**:640px - 1024px
- **桌面端**:>= 1024px
---
### 核心设计原则
- 所有文本叠层均使用 `mix-blend-mode: exclusion`,以便在浅色和深色背景上都保持可见
- 没有可见的滚动条交互 -- 位置跟踪完全由 RAF 驱动
- 所有叠加 UI 元素均使用 `pointer-events-none`
- 根容器使用 `user-select: none`
- 滚动超过第一个视口高度后隐藏视频(`visibility: hidden`)
- 滚动时随机改变圆形符号(节流至 80ms)
- 入场动画依次错开:logo(0s)、nav(0.15s)、说明文字(0.3s)、产品信息(0.45s)适用模型与稳定度
建议模型
继续探索
@Oluwaphilemon1 使用 Claude Fable 5 · Three.js · Blender · GSAP完成的网页案例,包含公开结果、完整 Prompt 与原始来源。
提示语
Claude Fable 5 和 GPT-5.6 很强🥵🥵🥵 下面是我如何使用 Claude 构建的 👇 提示词:「设计一个机构网站,把服务以 3D 超市商品包装的形式呈现」 使用 Three.js 和 WebGL 在浏览器中实时渲染所有产品 使用 Blender 制作包装模型,然后导出为 GLTF 以加载到 Three.js 中 使用 GSAP 实现流畅的产品旋转和悬停交互 如果你想做一个让客户感觉像是在购买高级商品的作品集,请保存这条 🛒
复制这段 TSX 组件源码,交给 Cursor、v0、Claude 等 AI 编程工具,说明这是「3D Animated Pin」的 Aceternity UI 组件实现,即可让它接入你的 React 项目,再按需替换文案、配色与触发参数复用。
提示语
// components/ui/3d-pin.tsx "use client"; import React, { useState } from "react"; import { motion } from "motion/react"; import { cn } from "@/lib/utils"; export const PinContainer = ({ children, title, href, className, containerClassName…

提示语
首先搜索 "/unlazy" skill,完整阅读它,并在整个任务中持续使用。 将此视为一项至少持续 {argument name="minimum duration" default="5 小时"} 的大型视觉构建。如果环境允许,最好进行 {argument name="optimal duration" default="8–24 小时"} 有实质意义的实现和迭代。不要在制作出一个还不错的场景后就停下。 在浏览器中创建一个细节极其丰富的实时 {argument nam