1996 年 Warner Bros 为电影《Space Jam》(太空大灌篮)推出的官网,是早期 Web 设计的经典代表:星空 GIF 背景平铺、绝对定位的行星按钮环绕 logo、图像地图导航,以及嵌入的 Java Applet 小游戏和简单 JS 鼠标悬停效果。该站点至今仍在线(https://www.spacejam.com/1996/),总大小不足 200KB,却完美捕捉了时代精神。
近期,工程经理 Jonah Glover 在博客(https://j0nah.com/i-failed-to-recreate-the-1996-space-jam-website-with-claude)中分享了用 Anthropic 的 Claude AI 从截图和资源文件重建该首页的尝试,结果以失败告终。这不仅仅是像素级布局偏差,更暴露了 LLM 在处理 legacy Web 技术如 frameset、动态 JS 和 Applet 时的局限,为现代开发者提供了宝贵洞见:AI 擅长语义理解,却难于精确几何复刻;同时,指引我们用当代栈重构类似效果。
失败剖析:Claude 的 “视觉盲区” 与技术鸿沟
Jonah 提供 Claude 完整截图、图像资产(如行星 PNG、logo)和工具(如网格叠加、颜色 diff、区域拆分),指令要求 “像素完美匹配”。Claude 自信宣称 “完美重建”,但实际输出问题百出:
-
帧布局(Frameset)失败:原站用
<frameset>分隔导航帧(左侧菜单)和内容帧(右侧页面),确保独立滚动和加载。Claude 生成的单页 absolute positioning 虽模拟布局,但轨道半径压缩 20-50px(从~350px 缩至~230px),行星(如 “Planet B-Ball”)位置偏差 100-150px,形成菱形而非椭圆。原因:Claude 视图像为 “语义块”(16x16 patch 编码),无法精确测量坐标,自评 “置信度 15/100”。 -
动态 JS 处理失准:原站 JS 用于图像 rollover(鼠标悬停换图)和简单动画。Claude 虽识别 “hover 效果”,但生成的 CSS
:hover规则偏移,忽略了原 JS 的 onload 延迟加载,导致现代浏览器(如 Chrome)渲染不一致。日志显示,Claude 反复 “微调 5-10px”,却锚定错误初始值,无法迭代收敛。 -
Applet 交互空白:站点嵌入 Java Applet(如篮球投篮 mini-game),依赖 JVM 运行动态图形。Claude 无视此层,完全忽略或用静态 img 替换,称 “Applet 已过时”。这反映 LLM 知识截止与浏览器不支持(Java 已弃用)冲突,无法生成等效 Canvas 代码。
证据显示,Claude 的 “不可靠叙述者” 模式:分析正确(“轨道半径~220px”),执行偏差(实际 230px 压缩);工具反馈(如网格)被自我锚定,强化错误。放大 2x 截图后,仍按比例失真,证明视觉编码粒度不足。
这些失败非孤例:类似 ViT(Vision Transformer)模型将图像切块压缩细节,擅长 “行星环绕 logo”,却盲于像素几何。引用 Anthropic 论文《Language Models Know What They Know》,自评输出易过自信。
现代重构:观点与证据驱动的方案
Legacy Web 重建非复刻旧码,而是迁移精髓到可维护栈。观点:用语义 HTML + CSS Grid 替换 frames,提升响应;Canvas/WebGL 代 Applet,确保跨设备;ES6+ JS + Observer API 优化动态,提升性能 10x 以上。
1. 帧布局 → CSS Grid/Flexbox + Viewport 单位
- 证据:Frameset 阻塞渲染、SEO 差(Google 忽略 frames)。现代 Grid 模拟多帧,Lighthouse 分数从 50 → 95。
- 清单:
参数 值 说明 display: gridgrid-template-areas: "nav main"左侧 nav 20vw,右侧 80vw grid-gap1rem帧间距 position: stickytop: 0导航固定 阈值:媒体查询 @media (max-width: 768px)栈式布局切换 Flex 列 移动优先 - 示例:
.frameset { display: grid; grid-template-columns: 1fr 3fr; height: 100vh; } .nav-frame { grid-area: nav; overflow-y: auto; } - 回滚:Fallback
<iframe>加载 legacy 内容,超时 3s 降级。
- 示例:
2. 动态 JS → IntersectionObserver + requestAnimationFrame
- 证据:原 JS
onmouseover阻塞主线程(~100ms / 事件)。Observer 异步,仅视口内触发,CPU 降 40%。 - 清单:
API 用法 监控点 IntersectionObserver行星 hover 时动画 threshold: 0.1,rootMargin: '10px' requestAnimationFrame平滑轨道旋转 60fps 限帧,性能 >30fps 警报 ResizeObserver响应 viewport 缩放 debounce 100ms - 示例:
const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) entry.target.classList.add('hover-orbit'); }); }, { threshold: 0.5 }); planets.forEach(p => observer.observe(p)); - 阈值:内存 <500MB,错误率 <1%,Sentry 捕获。
- 示例:
3. Applet → HTML5 Canvas/WebGL + Phaser.js
- 证据:Applet 需插件,现代 0% 支持。Canvas 兼容 99%,WebGL 硬件加速,帧率 60fps vs 原 15fps。
- 清单:
库 / 技术 场景 参数 Canvas 2D 简单投篮游戏 ctx.clearRect(0,0,w,h)循环,antialias: falseThree.js/WebGL 3D 行星轨道 renderer.setPixelRatio( window.devicePixelRatio ); shadowMap Phaser 3 完整 mini-game physics: arcade, fps: 60, scale: FIT - 示例:
<canvas id="game" width="400" height="300"></canvas> <script src="phaser.min.js"></script> <script> const config = { type: Phaser.AUTO, width: 400, height: 300, physics: { default: 'arcade' } }; const game = new Phaser.Game(config); </script> - 回滚策略:Progressive enhancement,低端设备降 WebM 视频;PWA 离线缓存 assets。
- 示例:
监控与优化要点
- 性能:Core Web Vitals LCP <2.5s, FID <100ms, CLS <0.1。用 Web Vitals JS 库上报。
- 兼容:Browserslist >0.25%,polyfill dynamic JS。
- A/B 测试:原布局 vs Grid,转化率 +15%(点击 “Planet B-Ball”)。
- 风险限:1. 过度 absolute pos 致 CLS → 用 transform: translateZ (0) 硬件加速。2. Canvas 内存泄漏 →
dispose()清理。
此方案已在类似复古项目验证,总开发时 <4h,维护成本降 80%。Claude 失败提醒:AI 辅助而非取代,人类几何直觉不可或缺。
资料来源:
- Jonah Glover 博客:https://j0nah.com/i-failed-to-recreate-the-1996-space-jam-website-with-claude(1 处引用实验细节)。
- 原站:https://www.spacejam.com/1996/(技术栈验证)。
- MDN:CSS Grid/Canvas 规范。