引言
上篇文章 介绍了 @tldraw 的 make-real 功能,这是一个能将草图快速转化为前端代码的强大工具。通过几个实例,如计算器、仪表盘等界面,展示了这一工具的实用性,并详细介绍了使用方法。
接下来,分享一下我在具体实践中的体验。经过多种工具的对比测试、原理解析,总结出了一套当前认为的最佳实践。对于想深入了解 tldraw 、 v0 与 GPTs 的朋友,请耐心阅读;而想直接了解结论的朋友,请跳转到“最佳实践”部分。
案例研究:复刻Airbnb界面
最近我在尝试用 React 复刻 Airbnb 的界面,其代表了现代、美观的to c页面,故选择的截图主要来自于它。
生成完整页面时,tldraw与v0的对比
比较火的代码生成工具还有 v0.dev,这是另一个可视化页面生成工具,它使用 Tailwind CSS 输出 HTML,而对于 React 则采用 shadcn UI 输出。不同于 tldraw 的直观生成,v0 更依赖于文字描述,虽然初始生成可以通过输入文字或图片,但后续的页面调整只能通过文字描述或者直接选中特定的 div
来完成,这在一定程度上限制了其灵活性。可能是因为面向客户是独立开发者,想用一个idea快速建站的,对ui的小差别不敏感,毕竟v0+nextjs+vercel一套操作行云流水,就直接发布上线。
tldraw的表现
如下图所示,左图是我准备实现的页面,图中右侧的浮窗想使用position:sticky
的效果,就写在注释中了。首先把整个截图和注释选中生成。右边即为生成效果:
生成的原型基本保持了结构,UI 也相当现代,自动添加了如边框旁边的阴影等细节。还具备一定的响应式设计,这主要使用了 Tailwind CSS,特别是给侧边栏设置了 <div class="w-full md:w-1/3">
,实现了在较小的屏幕上(小于 md
尺寸),这个 div
会占满整个父容器的宽度,在Main的下方。而在中等或更大尺寸的屏幕上,它的宽度会调整为父容器的 1/3,显示在Main的右侧。
虽然基本结构和样式都实现了,但在一些细节上还是存在差异,比如部分小模块和文字的省略、颜色错误等。此外,我特别要求的 position:sticky
效果也没有实现。一开始我询问了 ChatGPT 的支持,但它让我排查了一堆可能性,并没有说到点上。又让ChatGPT直接帮我改,也和原来的没区别,放弃让它帮我。后来我自己查看了代码,发现问题出在 sticky
被应用在了整个占据三分之一屏幕的侧边栏上,这部分由于占满了高度而无法滚动,自然也就没有 sticky
效果。解决方法是在三分之一区域内再添加一个 div
,并将 sticky
应用在它上面。
<style>
.sticky-sidebar {
position: -webkit-sticky;
position: sticky;
top: 0;
}
</style>
// 原代码
<div class="w-full md:w-1/3 p-4 sticky-sidebar">
<!-- Sticky Sidebar Content -->
</div>
// 修改后
<div class="w-full md:w-1/3 p-4 sticky-sidebar">
<div class="sticky-sidebar">
<!-- Sticky Sidebar Content -->
</div>
</div>
这说明,直接让不熟悉 CSS 的人使用 tldraw 可能会存在问题,尤其是在排查 bug 方面。
v0的表现
v0的话,首次生成,直接把截图上传即可,等待后就能看到三个结果:
两个平台在使用过程中都遇到了一些问题。例如,我尝试利用position: sticky
实现元素的粘性定位,但在两者中都未能达到预期效果,因为这一属性被错误地应用在了外层元素上,见v1。
相比tldraw,它就没有响应式了。
此外,“入住日期”使用的是button
标签,当我希望将其改为input
标签时,第一次尝试用文字描述 v2 未能成功,第二次尝试选中 div
+文字描述 v3 不仅失败,还导致了整个页面结构的混乱,后续不论是通过文字描述还是直接操作元素,都难以进行有效修改。详细过程见v0生成效果。
而且,v0.dev在生成代码时的体验相对被动,用户需等待较长时间以生成新版本,过程显得缺乏交互性。相比之下,tldraw在代码生成过程中允许用户在白板上进行实时修改,增强了操作的互动性和灵活性。
在用户界面的互动操作方面,tldraw通过直接绘制矩形选择和修改元素的方式,为用户提供了便捷的交互体验。而v0.dev不论是通过文字描述还是直接选择特定的div
进行操作,都显得相对复杂,提高了用户的操作难度。
综合评估
综上所述,尽管v0.dev和tldraw各有特点和优势,但在响应式设计、用户交互性以及操作流畅性方面,tldraw提供了更加出色的用户体验。这些体验上的差异为选择最适合自己项目需求的工具提供了重要的参考依据。
tldraw 似乎更适合那些具有一定基础的开发者,对ui、后端要求高一点,开发者自行解决前后端分离和部署等问题。对于基础较浅且不打算深入学习的人来说,v0 提供了一个快速建站的便利途径。因此,我决定在后续的测试中继续使用 tldraw。
在处理小模块时tldraw与GPTs的对比
为了简化tldraw的生成难度,我从页面中截取了一些小模块进行测试,看看是否能获得更好的生成结果。
如 前文 的tldraw使用方法所述,它使用的还是OpenAI API,那和直接使用GPT4有什么区别呢?
我首先尝试直接用GPT生成代码,但由于prompt过于简单,生成的代码与tldraw的结果相差甚远。于是转变思路,尝试使用一个非常强大的GPTs(Grimoire),这个GPTs已经产生了超过50万的对话,其生成效果非常出色。因此,下文将对比tldraw与GPTs的生成效果。
测试一:侧边栏
tldraw 的使用相当直观,只需选中截图即可生成代码。
使用 GPTs 时,则需要根据自己的项目需求(例如,我的项目使用 React 和 styled-components)给出具体要求,从而获取相应的 React 代码(如下图左侧)(目前prompt比较简单,主要为测试,实际使用时应该更详细)。手动把代码粘贴就能看到效果了(如下图右侧):
我们具体对比下生成效果,左原图,中tldraw,右gpts:
两者都成功实现了浮窗的阴影效果,基本设计元素也都有。但是,tldraw的效果明显更佳,更接近原图,除了价格下方少了一条水平线外,其他方面tldraw都表现得更好:
- “价格”更加突出,吸引注意
- 日期选择器更接近原图,尽管细节处理存在问题,例如框体超出
- 间距与原图更为接近,视觉效果更舒适
- 实现了鼠标悬停hover效果
在静态页面效果方面,tldraw的表现优于GPTs,但GPTs在生成代码时有一个突出的优点,即能够满足更多定制化需求。例如,如果项目中使用了React和styled-components,想要使用Material-UI的Rating组件,或者使用React的memo等,GPTs可以很好地满足这些需求,而tldraw目前只支持前端三件套(HTML、CSS、JavaScript)加上Tailwind CSS。
测试二:标题栏
进一步对标题模块进行了测试,测试流程与上述相同。结果如下,上为原图,中为tldraw生成的效果,下为GPTs生成的效果:
结果显示,tldraw的表现依然更佳,GPTs生成的代码中缺少了导航栏和下方的水平线,标题与原图的差异较大。虽然 badge 的形状不太相似,但通过调整border-radius
属性也比较容易修正。
结论
综合考虑,tldraw 在还原设计细节方面表现更佳,而 GPTs 在满足特定编码需求和定制化方面具有优势。选择哪一种工具应根据具体需求和项目背景决定。
tldraw原理探究
tldraw的静态页面生成效果明显好,其原理是什么呢?
得益于 tldraw 是一个开源项目,我们可以hack进去看看。从其源代码中可以知道,当用户绘制一幅草稿并选中后,Make Real 会加上之前的系统prompt、选中的注释与标签、旧设计的HTML,创建一个完整的消息,发送给OpenAI的GPT4模型。一旦AI模型处理完毕并返回了HTML代码作为答案,代码就会用这个答案更新之前创建的iframe区域,让用户看到生成的网页原型。
这个过程中,它的系统prompt就很值得品鉴:
You are an expert web developer who specializes in building working website prototypes from low-fidelity wireframes.
Your job is to accept low-fidelity wireframes, then create a working prototype using HTML, CSS, and JavaScript, and finally send back the results.
The results should be a single HTML file.
Use tailwind to style the website.
Put any additional CSS styles in a style tag and any JavaScript in a script tag.
Use unpkg or skypack to import any required dependencies.
Use Google fonts to pull in any open source fonts you require.
If you have any images, load them from Unsplash or use solid colored rectangles.
The wireframes may include flow charts, diagrams, labels, arrows, sticky notes, and other features that should inform your work.
If there are screenshots or images, use them to inform the colors, fonts, and layout of your website.
Use your best judgement to determine whether what you see should be part of the user interface, or else is just an annotation.
Use what you know about applications and user experience to fill in any implicit business logic in the wireframes. Flesh it out, make it real!
The user may also provide you with the html of a previous design that they want you to iterate from.
In the wireframe, the previous design's html will appear as a white rectangle.
Use their notes, together with the previous design, to inform your next result.
Sometimes it's hard for you to read the writing in the wireframes.
For this reason, all text from the wireframes will be provided to you as a list of strings, separated by newlines.
Use the provided list of text from the wireframes as a reference if any text is hard to read.
You love your designers and want them to be happy. Incorporating their feedback and notes and producing working websites makes them happy.
When sent new wireframes, respond ONLY with the contents of the html file.
可以看到有很多魔法叠加,借助 Meta 官方的prompt攻略,我们就分析下这个prompt:
- 角色(Role) :Prompt给模型设定为一个专业的网页开发者,明确了角色,帮助理解任务的专业需求。
- 明确指示(Explicit Instructions) :Prompt详细说明了任务,包括接受线框图、使用特定技术栈(HTML, CSS, JavaScript)创建原型,并以HTML文件的形式提交结果。这种明确的指示有助于确保模型能够按照预期完成任务。
- 限制(Limitations) :Prompt规定了使用Tailwind进行样式设计,以及如何组织CSS和JavaScript代码。这些限制有助于专注于任务的关键部分,避免不必要的复杂性。
- 风格化(Stylization) :Prompt建议使用Google Fonts和Unsplash图片,这为设计提供了风格化的指导,确保了原型的视觉一致性和专业性。
- 检索增强的生成(Retrieval-Augmented Generation, RAG) :Prompt提到可能会有旧设计的HTML提供,需要根据这些信息和线框图上的注释来迭代设计。这涉及到从外部资源中检索信息并整合到新原型中。
- 限制多余的token(Limiting Extra Tokens) :Prompt要求回应新线框图时只提供HTML文件内容,这避免了不必要的信息,确保了输出的简洁性。
那么,也可以将这个系统prompt复制到ChatGPT中,将生成的代码复制到Tailwind CSS的playground 中查看视觉效果,这样就不用花费API的费用了。这种方法还可以满足一些定制化需求,也是我在实际工作中采用的解决方案。有些问题也可以在prompt部分解决,比如变量名、代码片段,甚至让它帮我找UI组件。比如,找Material UI的小图标可能需要仔细查找很久,而AI可以快速找到并且非常贴合需求。
运用tldraw原理的GPTs
这里提供一个GPTs,Make It Real,里面内置了tldraw的prompt,直接把草图、截图放进去就能拿到代码。
代码如下:
最佳实践
最终,我选择了借鉴tldraw的prompt来定制GPTs,并将其融入工作流中。这样不仅可以保留框架和代码偏好,还可以根据需要向其提出其他要求,继续探询,而且不需要额外花费API费用。对我来说,将截图放入ChatGPT中并粘贴代码的小麻烦是可接受的。
对于常用的场景,比如上文中的支付表单,效果非常好。对于过于复杂的场景,还是建议自己编写代码,或者进行一些拆解。编写一些小游戏,如贪吃蛇、打砖块、Flappy Bird都是不错的选择,但写超级玛丽就不太行了。毕竟“AI 的视觉能力仍然建立在过往的学习素材之上,素材越丰富的场景 AI 理解的就会越好,但未曾包含在学习素材之中的内容 AI 也无法理解。”原文见:AI 版“神笔马良” make-real 工作原理揭秘 - 掘金 (juejin.cn)
在这个过程中,被安利到了Tailwind CSS,不论是与AI工具的适配(原子化CSS可以大幅减少token的使用),还是自己使用React手写代码,都能看到效率的提升。
总结与思考
从去年3月看到GPT4大会上的演示,到现在真的能够亲手体验,并见证了不断的优化,真是令人兴奋。期待未来会有更多的发展,也期待解决工程化的问题,比如将一张大图分割成多个小模块、引入常用的UI库、适配多种语言等。对于还没尝试过的朋友们,可以都去体验一下,欢迎在评论区交流,分享更多有趣的使用方式。
最近也注意到了一篇关于GitHub Copilot生成代码使用影响的研究,表达了对AI辅助编程工具在实际应用中可能带来的一些担忧。GitHub Copilot等工具的普及确实提高了开发效率,但同时也可能引入了代码质量和可维护性的问题。这些问题包括:
- 代码变动率增大:AI辅助工具可能导致开发者快速提交代码,但这些代码可能很快就会被修改或撤销,反映出代码稳定性和质量的问题。
- 代码重用和维护问题:AI工具可能促使开发者更多地复制粘贴代码,而不是进行有效的重构,这减少了代码的可维护性和可重用性,增加了未来的维护负担。
这违反了软件开发中的“不要重复自己”(DRY)原则。不过,如果将来这些任务都由AI完成,而AI的推理成本大幅下降,那么这些问题还会存在吗?
参考资料
- 实例,用 AI 搭建博客网站——GPTs、Tldraw、v0.dev 的综合运用
- X 上的 Nicolas Kruchten: The @tldraw "make real" demo
- X 上的 Giacomo Patella: I started exploring @tldraw's new feature 'Make real'
- X 上的 linear uncle: 这个将截图变成代码的项目很火,hack下,关键就是它的prompt
- AI 版“神笔马良” make-real 工作原理揭秘 - 掘金 (juejin.cn)
- 看了宝玉老师翻译的copilot生成代码的调研,使用 AI 编程 - 即刻App