老婆天天吵吵要买塔罗牌,我直接用 AI 2 小时写了个在线塔罗牌

43 阅读9分钟

🔗 开源仓库MysticTarot
🌐 在线预览liuxinyea.github.io/mystic-taro…

事情是这样的。

老婆最近迷上了塔罗牌,购物车里存了好几副设计精美的实体牌,价格都在两三百上下。做技术的我,心里先算了一笔账:这些东西买回来很可能热乎几天就收进抽屉,搬家时还得费力打包。可我又不忍心直接浇灭她的热情,于是主动说:“给我两个小时,我送你一个全宇宙独一无二的线上塔罗牌。”

她白了我一眼,但嘴角分明在说:“你倒是弄出来啊。”

于是,一个叫 MysticTarot 的项目诞生了——基于 Nuxt 3、Three.js 和 AI 的在线占卜应用。回头一算,从动手到能玩,差不多真的就是两个小时。

首页截图

牌阵效果

下面就把这个过程完整复盘一下,看看 AI 是怎么帮我在这么短时间里,从想法到部署,做出一个带 3D 翻牌、AI 解读、多语言和响应式适配的暗黑风塔罗应用。


1. 先让 AI 出一份“技术 & UI 方案”

我的第一步很简单:把需求告诉大语言模型。当时用的是 Gemini,因为它对多模态和多轮对话的支持更好。我给它的提示词大概是这样的:

我要做一个 Web 端塔罗牌占卜应用,要求:
- 沉浸式体验,3D 翻牌、洗牌动画
- 78 张牌完整数据(正逆位释义)
- 集成 OpenAI 进行 AI 解读
- 暗黑美学,毛玻璃 UI,星空背景
- 多语言支持(首选中英文)
- 响应式,手机端体验也要好
- 纯前端应用,但可能需要后端代理 API Key

请给我一套完整的技术方案,包括推荐的技术栈、核心组件设计,以及大致的 UI 布局。用 Markdown 输出。

Gemini 很快返回了一份要点清晰的方案:

  • 框架:Nuxt 3(Vue 3 + TypeScript),利用其服务端 API 路由代理 OpenAI 请求
  • 3D 渲染:TresJS(Three.js 的 Vue 3 封装)+ GSAP 做动画
  • 样式:Tailwind CSS,配合 bg-black/80backdrop-blur 实现毛玻璃,加上翡翠绿 (#50C878) 作为主色调
  • 状态管理:Pinia,管理抽牌、洗牌、解读状态
  • 多语言:@nuxtjs/i18n
  • AI 解读:OpenAI SDK,流式 SSE 响应,并设计无 API Key 时的本地回退策略
  • 牌面数据:本地 JSON 存储,包含名称、关键词、正逆位描述等
  • 目录结构components/ 下拆出 TarotScene.vueCardDeck.vue

这份方案直接帮我省掉了大量纠结“选什么技术”的时间。更关键的是,它还给出了 UI 布局的骨架描述:中央是 3D 牌阵舞台,底下是操作区(洗牌、抽牌),右侧滑出解读面板,顶部导航放语言切换和设置。

有了这张蓝图,下一步就是把蓝图交给 AI 转换成代码。


2. 用“AI 编辑器提示词”生成组件

我没有一行行手写代码,而是把 Gemini 的方案和具体需求,压缩成一段段给 AI 编辑器(Cursor / Antigravity 这类)的提示词。这里分享几个关键提示词,你可以直接拿去参考。

提示词 1:初始化项目基底

创建一个 Nuxt 3 + TypeScript + Tailwind CSS 项目。
安装以下依赖:@nuxtjs/tailwindcss, @nuxtjs/i18n, pinia, @vueuse/core, tresjs, gsap, openai
配置 tailwind.config.ts 添加自定义颜色:
emerald-glow: '#50C878',背景黑:#0a0a0a, #121212
在 nuxt.config.ts 中注册 tailwindcss 模块和 i18n 模块。
创建 i18n 配置文件,支持 zh-CN 和 en,设置懒加载。
创建基础布局文件 default.vue,包含星空背景(纯 CSS 点阵或 canvas 动画),全屏占满。
请生成所有需要的配置和文件内容。

AI 编辑器执行后,我得到了一个可以直接跑起来的项目框架,甚至已经带上了基础的星空粒子效果(用 CSS box-shadow 做的散点加动画)。

提示词 2:78 张牌的数据结构 & 本地 JSON

这一步我没有让 AI 自己编造牌义,因为我在网上找到了一份开源的中文塔罗解释,是 JSON 格式。我把这份 JSON 内容作为附件丢给 AI,然后说:

这是 78 张塔罗牌的详细数据(文件名:tarot.json),包含名称、英文名、正位关键词、逆位关键词、正位描述、逆位描述等字段。
请根据这份数据,在项目 /assets/ 下创建 tarot.json 文件。
然后在 /types/ 下定义 TypeScript 接口 TarotCard。
并在 /utils/ 中编写一个 loadDeck() 函数,用于读取并解析该 JSON。

AI 完美地生成了类型定义和工具函数,并且提醒我把图片文件放到 /public/cards/ 下,命名直接用牌的 id。这样数据层就扎实了。

提示词 3:TresJS 3D 场景 & 洗牌动画

这是最有挑战的部分,但只要提示词把需求拆解得清楚,AI 就能给出可靠的代码:

请使用 TresJS(Vue 3 的 Three.js 封装)创建一个塔罗牌 3D 场景组件 TarotDeck3D.vue。
- 场景背景透明,叠加在页面中央。
- 牌面使用 PlaneGeometry,正面贴图从 /public/images/tarot/ 加载,背面使用统一卡背图片。
- 初始状态:78 张牌叠成一摞,略微倾斜,展示厚度感。
- 点击「洗牌」按钮后,触发 GSAP 动画:所有牌迅速展开成扇形,并伴有随机微动。
- 点击某张牌时,该牌旋转 180 度翻面,并高亮。
- 组件通过 defineEmits 向外暴露 'card-selected' 事件,传递牌的 id。
- 务必使用 TresCanvas 和正确的灯光设置,使牌面纹理显示清晰。

这段提示词我给了 Cursor,它生成了约 200 行代码。虽然第一次生成的扇形角度有点生硬,但我补充了一句:“扇形弧度调整到约 160 度,牌间距均匀”,它立刻就修正了算法。

这里的核心经验是:把复杂的动画逻辑拆解成明确的小需求,并清楚告诉 AI 你用的库和 API 形态。


3. “多语言”与“智能降级”——花小钱办大事

我老婆是中文用户,可万一外国朋友也想玩呢?这好办。@nuxtjs/i18n 在项目初始化时就配好了,我只要让 AI 把组件里的所有文字都用 $t() 包裹,再生成对应的语言包就行。

提示词示例:

请遍历 components/ 和 pages/ 下的所有 .vue 文件,提取出所有用户可见的中文字符串,
生成完整的 zh-CN.json 和 en.json 语言文件,
并把组件内的文字替换为 {{ $t('key') }} 格式。
Key 使用英文命名,例如 "card.shuffle"、"result.loading"。

AI 很快生成了翻译文件,还贴心地为塔罗术语保留了原文,比如 $t('cards.TheFool.name')

另一个我觉得比较实用的设计是 AI 解读的智能降级。很多同类应用一旦没有 OpenAI Key 就不能用了,而这个应用会在 API 不可用时自动切回本地数据库释义。实现起来其实很巧妙:

  1. /server/api/analyze.post.ts 中,先尝试调用 OpenAI。
  2. 如果请求失败(401、网络错误等),直接 catch 异常。
  3. 在 catch 块里,根据抽到的牌 ID 从本地 JSON 中取出正/逆位描述,返回给前端。

这整个过程也是 AI 帮我做的,我只需要说:“如果 OpenAI 请求失败,返回本地解读,状态码还是 200,前端不用管。” 最终用户完全感觉不到切换,体验很顺畅。


4. 移动端适配与翡翠暗黑美学

因为用了 Tailwind,响应式适配在 AI 帮助下特别简单。我只需要在提示词里加一句:

所有布局元素请使用 Mobile First 策略。
在大屏上,解读面板在右侧侧滑;在小屏上,解读面板从底部上滑,高度占屏幕 70%。

AI 自动给面板加上了 fixed bottom-0 md:right-0 md:top-0 md:w-96 这样的类名,并配上过渡动画。

颜色主题方面,暗黑模式已经通过 Tailwind 的 dark: 变体支持了。但我想让整个界面只使用 翡翠绿 作为强调色。于是在提示词里要求:

主题色只使用 emerald-glow 和它的透明度衍生版本。
提供主题切换按钮,通过 Pinia store 管理 isDark 状态,并用 vueuse 的 useDark 同步到 标签上。

最后呈现出来的效果是:深邃的黑色背景上,翡翠绿色的光感从牌背微微透出,毛玻璃面板边缘晕着一层柔光,整界界面确实有几分“赛博占卜”的味道。


5. 最后的样子,和老婆的反馈

差不多两小时后,我把应用部署到了 GitHub Pages,把链接发给老婆。她没说话,默默试了三次占卜,然后抬头说:“牌面比买的还好看诶,那个背景音是什么?”

——没错,我还悄悄加了一个环境音效。用了免费的白噪音音频,让 AI 写了一个 useAmbientSound 的 composable,进入页面时自动淡入播放,可以随时关闭。仪式感就这么拉满了。

现在项目完全开源,你可以直接克隆下来体验或自己改着玩:

(如果不配置 OpenAI API Key,应用会自动运行在本地解读模式,仍然可以抽牌并看到内置的详细释义。)


6. 被 AI 帮了多少?说点真心话

老实说,如果没有 AI,这两个小时我可能刚搭完 Nuxt 环境,还在跟 TresJS 的类型定义较劲。AI 对我的帮助主要体现在:

  • 加速决策:技术选型、组件划分、UI 风格——这些原本要纠结半小时的事,AI 在几十秒内给出了合理建议。
  • 减少记忆负担:不用记各种的参数顺序,不用查 @nuxtjs/i18n 的配置细节,把脑力留给真正需要判断的地方。
  • 快速纠错:有一次 3D 旋转出现奇怪的倾斜,把代码扔给 AI,它一眼看出是 rotation 属性的应用顺序问题。

当然,AI 不是魔法。整个过程我仍然要不断调整提示词,检查它生成的代码有没有副作用、是否符合最佳实践。但效率的提升是实实在在的——就像拍电影,我只需要讲清楚分镜头,AI 帮我把画面演出来。

如果你也有一个突然冒出来的想法,不妨试试这种“AI 原生”的开发方式。说不定下一个项目,就诞生在某个赌气的瞬间、一个没清空的购物车,和两个小时的专注里。


如果这篇分享对你有用,欢迎去仓库点个 Star,也欢迎直接在线玩一玩~ 🌟