AI 分不清左右?记一次 CSS 3D 旋转的调优经历
人与 AI 最有趣的交流,往往发生在它犯错的时候。
背景
这个博客的首页英雄区有一个奇门罗盘——由 7 层圆环、八卦符号、天干地支文字层构成的 SVG 3D 罗盘。它通过 CSS 的 perspective() 和 rotateX() / rotateY() 组合实现空间透视效果,让罗盘看起来像是从某个角度悬停在页面中。
最初的效果是 rotateY(-22deg) rotateX(-14deg),视觉上"从左上往右下"俯视。我希望改成"从右上往左下"俯视——也就是 viewer 在右上角,视线投向罗盘的左下角。
就是这个小需求,让 AI 在原地打转了近半个小时。
第一轮:简单直观的 rotate3d
我向 AI 描述了坐标系:
- X 轴:垂直于屏幕(穿屏方向为正)
- Y 轴:水平向右
- Z 轴:竖直向上
- 原点:太极阴阳鱼中心
要求第四象限(右下)和第八象限(左上)呈现"近大"效果,第二象限(右上)和第六象限(左下)呈现"远小"效果——整体看起来像从右上往左下俯视。
AI 的第一反应是 rotate3d(0, 1, -1, 18deg)——绕对角线轴旋转。我试了一下,说"方向反了"。AI 改成了 rotate3d(0, 1, -1, -18deg),我还是说"方向反了"。
到此,AI 已经陷入了困境。
第二轮:回到 rotateX + rotateY
AI 放弃了 rotate3d,回到 rotateX + rotateY 的组合。开始了漫长而混乱的调参之旅:
| 步骤 | Transform | 用户反馈 |
|---|---|---|
| 1 | rotateY(22°) rotateX(-14°) |
仰视,不对 |
| 2 | rotateY(-22°) rotateX(-14°) |
从左上往右下,相反了 |
| 3 | rotateY(22°) rotateX(-14°) |
对的!俯视角度再大一点 |
| 4 | rotateX(-22°)(X 加大) |
又变成从左上往右下了! |
| 5 | rotateX(-18°) |
还是从左上往右下 |
| 6 | rotateY(26°) rotateX(-14°)(改 Y) |
不对 |
| 7 | 改 perspective 值 | 你该干什么?为什么方向不变? |
| 8 | rotateY(-22°) rotateX(-14°)(翻 Y) |
方向没变!再试!(但这次 build 了) |
| 9 | 同样的 rotateY(-22°) rotateX(-14°)(确认已生效) |
这下对了!记住这个方向! |
看着这张表,你会发现一个奇妙的现象:步骤 2 和步骤 9 是同一个 transform 值!
步骤 2 时 AI 说"这是从左上往右下",但同样的值在步骤 9 时却说"这下对了"。发生了什么?
答案很简单:前面几次我都没 reload 页面。
真相大白
在 CSS 3D 变换中,rotateY(负数) 让右边翘向 viewer,rotateX(负数) 让上边翘向 viewer。两者的合效果是 右上角最靠近 viewer——也就是"从右上往左下"俯视。
A 第一次测试 rotateY(-22°) rotateX(-14°) 时,我凭印象说"从左上往右下"——实际上浏览器可能还在显示旧的 cache。AI 相信了我的错误反馈,开始朝错误方向调参,把 Y 翻成正数、调整 X 角度、改 perspective……越调越乱。
真正正确的解从一开始就摆在那里。
教训与反思
1. 调试时一定要先确认状态
这是最核心的教训。AI 修改了代码,但我没有做硬刷新(强制清缓存),就凭视觉印象给出了错误反馈。AI 基于这个反馈继续调整,产生了"负反馈循环"——每次调整都是基于错误的前提,离正确答案越来越远。
正确的流程应该是:
AI 改代码 → 我硬刷新页面 → 确认实际效果 → 反馈
而不是:
AI 改代码 → 我凭印象反馈 → AI 继续改 → …
2. CSS 3D 旋转的方向直觉 vs 数学
CSS 3D 使用右手定则:
rotateX(正数):底部翘向 viewer(仰视)rotateX(负数):顶部翘向 viewer(俯视)rotateY(正数):左边翘向 viewerrotateY(负数):右边翘向 viewer
直觉上你可能认为 rotateY(正数) 会让右边靠近——但根据右手定则,正 Y 旋转(拇指朝下)让左边靠近。这种反直觉是容易出错的根源。
3. 矩阵计算不可少
经过这次折腾,我推导出了 CSS 3D 旋转下任意点的 Z 轴位移公式:
$$z = -x \cdot \sin\theta_y + y \cdot \cos\theta_y \cdot \sin\theta_x$$
对于罗盘 8 卦位置的 z 值(r=1,原点为中心):
| 卦位 | 角度 | x | y | z |
|---|---|---|---|---|
| 乾(上) | -90° | 0 | -1 | +0.22 |
| 兑(右上) | -45° | 0.707 | -0.707 | +0.42 |
| 离(右) | 0° | 1 | 0 | +0.37 |
| 震(右下) | 45° | 0.707 | 0.707 | +0.11 |
| 巽(下) | 90° | 0 | 1 | -0.22 |
| 坎(左下) | 135° | -0.707 | 0.707 | -0.42 |
| 艮(左) | 180° | -1 | 0 | -0.37 |
| 坤(左上) | 225° | -0.707 | -0.707 | -0.11 |
正 z 靠近 viewer。表中可以看到兑(右上)的 z 值最高(+0.42),坎(左下)最低(-0.42)——从右上往左下,完美。
最终效果
transform: perspective(1000px) rotateY(-28deg) rotateX(-22deg) translateX(15%) scale(1.23);
调大旋转角后,右上角更贴近 viewer,透视感更强。配合之前去掉太极重叠和中心金色光点的清理工作,罗盘终于达到了理想的视觉效果。
结尾
这次经历让我意识到:在与 AI 协作调试时,人类提供准确的反馈比 AI 生成正确的代码更重要。一顿错误的反馈,可以让最聪明的 AI 在原地打转十分钟。
当然,话说回来——能分得清左右的人类,也不一定比 AI 多(笑)。