Communitygithub.com

3D 个人作品集

构建带有 3D 英雄区、每个兴趣的动效对象、可视化案例研究和可工作的联系表单(tRPC、Resend、Turnstile、Postgres)的个人作品集网站,然后部署到 Vercel。适用于当有人想要一个比模板更具特色的作品集、个人网站或“3D 作品集”时。

3D 个人作品集 是什么?

该技能旨在帮助开发者和 AI 代理构建一个独特、高度个性化的一页式 3D 作品集网站。它强调通过一个能反映个人世界真实特征的 3D 对象(如 DJ 的唱片箱、攀岩者的岩点墙)来展示项目,从而创造出具有独特视觉冲击力的英雄区。该技能支持 Vite、React、TypeScript、three.js、tRPC、Resend、Cloudflare Turnstile 和 Neon Postgres 等现代技术栈,并内置了联系表单和邮件订阅功能。其核心工作流程包括:先收集用户的真实内容(项目、经历、技能、兴趣爱好等),然后构思一个核心概念,最后构建一个包含 3D 场景、案例研究、时间线和联系表单的完整单页网站。该技能还提供了详细的实施指南、常见问题避免方法以及建后检查和部署流程,确保最终产品质量。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/walenso/3d-portfolio-skill/tree/HEAD/skills/3d-portfolio

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

3D 作品集

构建一个只属于这个人的一页式作品集。产生这个技能的网站是围绕一位 DJ 的唱片箱搭建的:每个项目都是一个可以翻阅的唱片封套,当唱片在面前时它会旋转。示例:https://alessio-simoya.vercel.app

不要复制那个概念。遵循流程,找到属于他们的概念。

1. 首先收集所有输入

在设计之前先询问这些信息。从一开始就用真实的内容构建。

  • 项目: 每个项目提供一份简短的事实摘要:它是什么、你的角色、日期、它实现了什么、技术栈、在线链接,以及一份绝对不能声称的清单。
  • 经历: 公司、职位、日期、地点,以及每份工作的一个成果。
  • 技能: 分组列出,并注明每项技能在何处得到验证。
  • 工作之外的生活: 爱好、团队、他们擅长烹饪什么、去过哪里。概念就来源于此,所以要问得比他们主动提供的更多。
  • 素材: 标志、产品截图、视频、Rive 或 Lottie 文件。询问项目文件夹的位置并搜索它们。
  • 链接: LinkedIn、GitHub 等。除非对方明确要求,否则永远不要公开他们的电子邮件地址。

2. 找到核心概念

选择对方世界中最具特色的事物,将其做成英雄区,作为一个用户可以与之互动的真实 3D 对象。DJ 会有一个唱片箱。攀岩者可能会有一面岩点墙;面包师会有一盘面包。每个项目都成为该对象中的一个物品。

把大胆放在那里。页面的其余部分保持简洁:纯色色块、一种有个性的展示字体、一种普通的正文字体、四到五种命名颜色。

3. 技术栈

  • Vite、React 和 TypeScript(严格模式)
  • three.js 用于 3D,直接编写(不需要场景框架)
  • 仅当对方已有 .riv 文件时才使用 Rive;延迟加载其 wasm
  • tRPC 和 zod 用于 API,作为 Vercel 函数位于 api/trpc/[trpc].ts
  • Resend 用于电子邮件,Cloudflare Turnstile 用于反垃圾,Neon Postgres 用于记录
  • 通过 @fontsource-variable/* 自托管可变字体

4. 3D 搭建方式

使用一个固定的、全屏的 WebGL 画布,设置 pointer-events: none,并将每个 3D 视图绘制到一个 DOM 占位元素的矩形区域内:

const r = el.getBoundingClientRect();
renderer.setViewport(r.left, innerHeight - r.bottom, r.width, r.height);
renderer.setScissor(r.left, innerHeight - r.bottom, r.width, r.height);
renderer.render(scene, camera);

每帧清除一次,开启裁剪测试,并跳过任何屏幕外的元素。这样只需一个上下文就能在页面下方提供多个 3D 对象,并且它们会随布局滚动。

为每个小对象创建一个“骨架”:一个组、一个相机位置、一个注视点和一个由共享时钟驱动的 tick(t) 函数。延迟构建骨架,一次只显示一个。在 2D 画布上绘制纹理(标志、标签、图案),这样就不需要加载模型文件。

曾出现问题及避免方法:

  • 比元素大的地面阴影平面会显示为一个硬边矩形。将其大小调整到视图内。
  • 当你需要“绕自身轴旋转”时,先旋转组,再旋转子元素。
  • 精灵和透明平面在实体网格之后绘制;对象下方的发光效果应是其下面的一个平面,而不是面向相机的精灵。

5. 已证明有效的区域

  1. 英雄区: 名字设置得很大,一个循环显示其角色的贴纸,一句话介绍,以及交互式对象。其背后的彩色圆盘会随着焦点项目变化。
  2. 工作: 每个案例研究以该品牌颜色的条带打开,带有其真实标志,然后是横向滚动的图片、视频和动画卷轴,三个简短亮点,几个大数字,以及技术栈标签。长文本放在“阅读完整故事”后面。
  3. 经历: 每份工作一行,每行附带一个大数字。
  4. 旅程: 学校或里程碑,每个都有自己的动画对象。
  5. 技能: 行进的文字行,而不是表格。
  6. 下班时间: 每个兴趣一个动画对象。
  7. 旅行: 地点作为冰箱磁铁展示在钢门上,可以拖动。
  8. 打个招呼: 联系表单。

一个浮动的小标题栏通过 IntersectionObserver 标记当前区域。

6. 规则

  • 仅限事实。 使用对方提供的内容。如果某个区域需要对方没有提供的信息,就省略它。在每个项目的“不得声称”列表前添加注释,放在内容文件中。
  • 不要虚荣计数。 提交次数、代码行数、页面数或模型数显得不成熟。展示产品和它实现的功能。
  • 减少文字。 如果屏幕大部分是段落,就将其转化为视觉效果。
  • 尊重他人工作。 不要从预览中重建付费模板,也不要复制品牌的产品设计(例如,知名比赛用球);要用同样的精神创作原创内容。仅使用自由许可的图片,并在页面上注明出处。
  • 截图 不得显示真实客户的姓名、金额或面部。
  • 动效要有关闭开关。 尊重 prefers-reduced-motion,添加一个“暂停动效”按钮,并在 WebGL 不可用时提供静态回退。
  • 将所有内容放在一个类型文件中 (src/content/portfolio.ts),以便对方无需接触组件即可编辑文字。

7. 联系表单

一个 tRPC 过程,contact.send,输入由 zod 校验。按顺序,它:

  1. 如果隐藏的蜜罐字段被填写,则静默返回成功;
  2. 对每个地址应用一个小的速率限制;
  3. 用 Cloudflare 验证 Turnstile 令牌,失败则拒绝;
  4. 通过 Resend 给所有者发送邮件,发件人设为 reply_to;
  5. 将每条消息保存到 messages 表;
  6. 仅当访客勾选了默认未勾选的“让我了解最新动态”复选框时,才将其保存到 subscribers 表(同时记录同意措辞和时间)并添加到 Resend 受众列表。

没有那个勾选,永远不要将任何人添加到邮件列表。

环境变量:RESEND_API_KEY、ENQUIRY_TO_EMAIL、ENQUIRY_FROM_EMAIL、RESEND_AUDIENCE_ID、DATABASE_URL、TURNSTILE_SECRET,以及浏览器使用的公开站点密钥。

曾出现问题:

  • from 值可能已经是 姓名 <地址> 格式。再次包装会导致 Resend 返回 422。当它包含 < 时,直接使用。
  • Vite 只暴露以 envPrefix 中某个前缀开头的变量。如果站点密钥以其他名称到达,请添加该前缀。
  • Turnstile 小部件仅在其在 Cloudflare 中配置的主机名上有效。
  • 在生产环境中,如果没有 Turnstile 密钥,则拒绝发送。仅在本地开发中使用 Cloudflare 发布的测试密钥。
  • 添加一个 CONTACT_DRY_RUN=1 开关,在生产环境中忽略,以便可以在不发送电子邮件的情况下测试整个路径。
  • 要在 vite dev 下运行相同的处理程序,添加一个小插件,使用 server.ssrLoadModule 加载函数并传递一个 Request。
  • 使用表格和内联样式构建电子邮件 HTML,并对每个字段进行转义。

8. 边工作边检查

每轮更改后:

  • 运行构建;
  • 在 1440 像素和 390 像素宽度下,为每个区域截取 Playwright 屏幕截图(启动 Chromium 时使用 --use-gl=swiftshader 以便 WebGL 在无头模式下渲染);
  • 确认 document.documentElement.scrollWidth - innerWidth 为 0;
  • 在说明完成之前,自己查看屏幕截图。

明确说明未检查的内容:真实手机、Safari、动效的感觉、真实邮件投递。

9. 发布

  • git init,并忽略 .env* 和 .vercel。在首次提交前扫描暂存文件中的密钥。
  • vercel link,添加环境变量,vercel --prod。
  • 检查在线页面是否加载成功且没有失败请求,以及 API 是否拒绝没有 Turnstile 令牌的请求。
  • 请所有者通过在线表单发送一条真实消息。

初始提示

给用户填写以下内容:

使用 3d-portfolio 技能构建我的 3D 作品集。

我的姓名和一行描述:
在英雄区循环显示的角色(4 到 6 个):
项目(每个项目提供:事实、我的角色、日期、链接、不得声称的内容):
经历(公司、职位、日期、每个一个成果):
技能分组:
学校或里程碑:
工作之外的兴趣(请具体说明):
我去过的地方:
我的标志、截图和动画在此电脑上的位置:
要展示的链接(LinkedIn、GitHub 等):
我永远不希望出现在网站上的东西:

相关技能