← 返回桌面

个人主页实现

个人主页实现|Build in Public

把一个普通个人主页逐步做成可玩的 3D 电脑桌面,并把每次判断、修改和验证留下来。

状态
持续迭代
当前阶段
发布候选
最近更新
2026.07.31

为什么做这个主页

我不想再做一页换了头像和文案的通用个人主页。这里的起点是我的真实电脑桌面:左侧副屏负责入口,中间主屏负责阅读,键盘、鼠标、便利贴和洞洞板负责让人愿意动手。

页面首先要好玩,但“好玩”不能建立在内容不可读、修改不可控或只能看一次的基础上。所以这段实现过程同时在解决三件事:

  • 让桌面本身成为界面,而不是给普通网页套一张背景。
  • 让文章、活动和项目可以持续增加,不继续把代码堆进一个文件。
  • 让每次视觉判断、失败修改和技术验证都有证据,可以被以后的人接着做。

当前做到哪里

桌面版已经有一套通过本地验收的构图和交互。场景代码完成模块化,首屏图片负载明显下降,复杂物件也有了程序化模型与 GLB 候选并存的入口。

“最近在做”已经接成真实项目,而不是一段占位文案。当前版本进一步把测试、构建、资源预算、断链、敏感内容和外链安全收敛成一条发布候选 Gate。完整开发记录放在这个项目页,3D 主屏仍只保留摘要和入口。

两条并行路线

Astro 主站继续负责可长期维护的 3D 个人主页。秒哒参赛版则是独立的原生 2.5D 实验,用同一套桌面想法验证另一种实现方式。两条路线共享设计判断,但不互相冒充代码来源。

公开边界

这里记录公开可验证的需求变化、代码结构、资源体积、测试结果和设计判断。账号信息、凭据、服务器细节以及没有确认过的个人经历不会进入页面。

场景入口
1412 → 366 行
首屏图片
6.24 MB → 366 KB
当前测试
107 项通过
模型默认预加载
0

Build in Public

开发记录

10 次可追溯更新,最新的排在前面。

实现

作品集重做

让作品集先展示项目,而不是展示一张海报

移除遮住项目的整屏暗色人像,把真实项目截图、状态、结果和档案入口放回首屏。

  • 修复宽屏下文案被左右内边距挤成一字一行的问题
  • 作品集改为读取公开项目 collection,不再维护一套静态项目名单
  • 首屏使用 56,326 字节的真实桌面截图,并保持 16:9 原始比例
  • 1440、1920、2048 和 1024 横屏均无横向溢出,视觉评审为 94/100

原来的作品集首先展示一张暗色人像海报,项目列表被推到首屏之外。更具体的问题出现在宽屏:文案容器有固定最大宽度,同时左右内边距会随视口增加,最终正文可用宽度接近零,标题和说明都变成一字一行。

这一轮没有继续给旧海报补装饰,而是重新确定作品集的职责。首页的 3D 桌面负责让人愿意探索,作品集负责把真实项目说清楚。因此页面改成短介绍、重点项目和项目索引三段,打开后可以直接看到项目截图、状态、阶段、结果和详情入口。

项目数据也不再来自单独的静态数组。作品集现在读取与“最近在做”和项目档案相同的公开项目 collection,草稿不会出现,推荐项目优先,其余按更新时间排列。以后增加一个公开项目,只需要补项目内容与档案,不需要再改作品集页面。

重点项目封面来自当前真实 3D 首页,压缩后为 56,326 字节。图片的自然尺寸与渲染比例一致,没有拉伸。作品集在常见横屏下完成截图和溢出检查,详情入口可以进入现有 Build in Public 档案;首页则继续使用原来的桌面实现。

实现

模型接入准备

先把真实物件的照片与模型入口定下来

在继续替换键盘、机箱和台灯之前,先把照片隐私、模型来源、授权、坐标、体积、预览和回退规则做成可执行 Gate。

  • 现有游戏鼠标成为第一条完整模型资产记录,仍然只在显式预览参数下加载
  • 新增模型清单检查,拒绝路径逃逸、未登记 GLB、超预算资产和未经确认的默认切换
  • 原始实物照片默认不进入公开仓库,先检查屏幕内容、序列号、二维码和镜面倒影
  • 拿到照片后每轮只替换一个物件,程序化版本永久保留为回退

这一轮没有继续猜键盘、机箱或台灯应该长什么样,也没有把新的模型直接塞进默认桌面。真正缺少的是尔玉实际物件的照片,因此先把“照片来了以后怎么做”变成一条不会破坏现有页面的流程。

原始照片默认只作为建模输入,不进入公开仓库。照片先检查屏幕内容、二维码、序列号、快递单、他人面孔和镜面倒影;公开仓库只保留确认后的 GLB、脱敏来源说明和必要参考。

模型目录现在有了机器可检查的清单。每个 GLB 都必须说明来源、生成工具、输入素材权利、授权、坐标、原点、缩放、体积预算、预览参数和默认状态。候选没有明确验收记录时,Gate 不允许把它设成默认。

下一次收到一组真实物件照片后,可以只为该物件建立候选,在独立地址比较默认版和模型版。候选失败、加载失败或最终不采用,都不会影响当前桌面。

验证

发布候选

把本地验收收敛成发布候选 Gate

把测试、构建、资源预算、断链、敏感内容和外链安全合成一条可重复执行的发布前检查。

  • 15 个测试文件、91 项测试全部通过
  • 4 个必需入口、站内资源、相对链接和响应式图片统一进入构建产物审计
  • 双分辨率与 V0.7 保持零像素差,另外 4 个常见横屏尺寸无溢出
  • 依赖审计为 0,真实发现并修复 1 处不安全的新窗口外链

这一步没有再往桌面上增加物件,而是先把“可以发布”变成一组能重复执行的条件。现在一条命令会依次完成单元测试、Astro 诊断、静态构建、资源预算和构建产物审计,并检查必需页面、站内资源、本机路径、常见凭据形态和新窗口外链安全。

检查器先由失败测试驱动,再拿真实构建结果校准。它确实发现了一个静态分享页的新窗口链接缺少安全属性;修复后,又为相对 HTML 与 CSS 资源、无引号属性、Astro 的 404.html 输出以及压缩脚本误报补了回归测试。

依赖更新也经过单独审计。核查时,Astro 7.1.0 的信息存在冲突:官方发布带有已验证签名,一条 OSV 恶意包记录后来被标记为撤回,而 GitHub 安全公告仍保留相关记录。这里采取的是当时的谨慎措施,不对该版本下恶意结论:没有运行它的 CLI,直接改用官方签名发布的 7.1.6;Sharp 更新到 0.35.3。全量与生产依赖审计均为 0。

默认桌面没有借这次收口顺便改样式。两个基准分辨率与 V0.7 保持零像素差,另外四个常见横屏尺寸也完成了非空渲染、溢出和核心交互检查。公网仍未更新,下一步先做本地验收。

实现

内容接入

让“最近在做”开始承载真实项目

把稳定项目概览与逐条开发更新接入站内页面,3D 主屏只负责摘要和入口。

  • 新增项目与项目更新两个独立内容集合
  • 首批接入 7 条可追溯记录和公开证据链接
  • 最近在做可以从列表进入主屏预览,再打开站内项目页
  • 64 个测试通过,两个默认桌面视口与 V0.5 保持零像素差

这一步没有把每天的聊天或终端输出搬到网页上,而是把内容拆成稳定概览和独立更新。项目概览回答“为什么做、现在在哪”,每条更新只记录一次判断或变化。

桌面副屏仍然只有三个入口。访客点开“最近在做”后,先在主屏看简短预览,再决定是否进入完整项目页。这样 3D 场景保持简洁,真实过程也不需要依赖飞书接口才能阅读。

实现

模型实验

用一只鼠标跑通 GLB 替换管线

先让一个小物件支持程序化模型与 GLB 候选并存,验证加载、回退、交互和释放。

  • 默认首页继续使用已经验收的程序化鼠标
  • 只有显式试验参数才下载 435,088 字节的 GLB
  • 模型失败会自动回退,拖拽仍使用独立低复杂度命中代理
  • 58 个测试通过,默认页面的模型预加载为零

第一次模型实验没有直接替换整套桌面,而是选择体积小、交互边界清楚的鼠标。GLB 只替换视觉层,拖动容器、点击代理和主屏光标同步继续沿用稳定逻辑。

加载器采用按需动态导入,并处理并发缓存、失败重试、取消和幂等释放。这个候选是否成为默认视觉仍要单独验收,但以后新增模型已经不需要重新发明加载和回退流程。

判断

黑客松准备

把秒哒参赛版拆成独立实验

同一套桌面想法保留两条实现路线:Astro 主站继续维护,秒哒用原生 2.5D 验证参赛表达。

  • 秒哒参赛版不导入现有 Astro 源码或 Git 历史
  • 首轮只验证构图、主屏可读性、物件关系和关键互动
  • 为生成提示词、参考资产、验收门和止损规则分别建立文档

秒哒路线的目的不是复制当前站点,而是验证:不用完整 Three.js 工程时,卡通化真实桌面是否仍然能成为一个有趣、可读的个人主页入口。

这条路线和主站共享构图判断与个人视觉资产,但实现和验收独立。这样既不会把已有代码伪装成平台原生作品,也不会为了参赛尝试破坏当前已经可运行的主页。

验证

性能基线

先减掉首屏 94.14% 的图片负载

在增加模型之前先压缩现有图片,并让 WebGL 降级图只在真正失败时加载。

  • 首屏图片从 6,235,756 字节降到 365,512 字节
  • 正常 WebGL 首屏不再请求 2,141,964 字节的降级构图图
  • 增加资源预算检查,防止后续模型悄悄放大默认下载
  • 47 个测试、类型检查、构建和双分辨率截图验证通过

图片转模型会自然带来新的资源,因此不能先加模型、最后再猜页面为什么变慢。这里先把人物图和 Q 版摆件改成适合实际显示尺寸的 WebP,并把大尺寸降级图改成失败后才请求。

这一步同时加入自动预算。以后任何模型或脚本让默认入口超过约定体积,构建检查会直接失败,而不是等到发布后才靠体感发现。

主线

代码治理

把分叉的代码主线重新合在一起

确认真实发布源后,把旧主线纳入同一段历史,避免后续修改落到错误仓库状态。

  • 以真实运行版本作为文件树基线
  • 保留旧历史和回退标签,没有强推覆盖
  • main 与 master 后续保持同一提交

一次诊断发现,线上运行代码和原先记录的“唯一代码基线”已经分叉。继续加功能之前,必须先回答一个很朴素的问题:修改到底应该落在哪一条历史上。

处理方式不是删除旧版本,而是保留当前生产文件树、把两段历史合入同一主线,并为合并前状态建立保护点。之后功能分支都从统一主线出发,GitHub 合并和公网发布仍然是两件事。

实现

架构重构

把 1412 行场景拆成可以继续扩展的模块

把屏幕、物件、渲染核心和交互从 scene.ts 中拆开,同时要求默认画面完全不变。

  • scene.ts 从 1412 行收敛到 366 行
  • 屏幕、渲染核心、物件与交互分别进入独立目录
  • 45 个测试通过,1440×900 与 1920×1080 均为零像素差
  • 页面卸载后会停止动画并释放 Canvas、材质、纹理与监听器

原来的场景能运行,但增加一个物件要同时碰建模、坐标、点击、状态和销毁逻辑。真正的成本不是写几十行 Three.js,而是所有东西都挤在同一个函数里,改动很难单独验证。

这轮重构只改变代码边界,不改变画面。所有物件统一返回可交互目标和可选的更新、释放函数;scene.ts 只负责装配。这样后续替换鼠标或键盘时,不需要重新理解整张桌子。

判断

视觉基线

先把满意的桌面固定下来

在继续拆代码之前,先给已经认可的桌面构图建立不可丢失的 Git 基线。

  • 保留已经确认的桌面构图、相机、材质、文案和交互
  • 建立 homepage-desktop-baseline-20260729 标签
  • 后续重构先证明零视觉变化,再讨论新的物件和内容

这一步没有追求“看起来更高级”,而是先解决可逆性。桌面已经经过多轮构图修改,如果直接在同一份代码上继续拆分,一旦画面发生变化,很难判断是有意优化还是重构回归。

因此先保存受保护标签,再把结构调整放到独立分支。后续每一轮都能回到这个版本比较,而不是靠聊天记录回忆“原来大概是什么样”。