本文作者:刘甲
万字长文带你了解云音乐设计协同的演进之路,干货满满~
序言
前端和设计师一直以来都在致力于为用户提供出色的人机交互体验。在这个过程中,如何为双方提供高效的协同产品,降低设计师与前端的沟通成本,以及提升双方的工作效率,都是非常有价值的探索点。
笔者来自网易云音乐-公共技术部,目前是云音乐设计中台的技术负责人。从 2021 年 7 月入职网易到现在,一直在「前端与设计协同」领域里探索和实践,期间沉淀了若干经验和方法论,希望能和大家一起分享,于是就有了这篇文章。
本文将从问题出发,详细介绍云音乐设计协同的演进之路。按照时间的维度,云音乐设计协同的演进之路为:
- 原始阶段 ➡️ 工程化阶段 1.0
- 工程化阶段 1.0 ➡️ 工程化阶段 2.0
- 工程化阶段 2.0 ➡️ 智能化阶段
PS:本文很长,万字有余,赶时间的同学可在 ChatGPT 的陪同下阅读。
背景
提起「前端与设计协同」(后面简称「设计协同」),相信大家都不陌生。它伴随着互联网精细化的分工而出现,在 PC 互联网时代发展壮大,在移动互联网时代趋于成熟。
而所谓「设计协同」,其主要功能就是在设计师和前端的协同工作下,将产品需求转化成代码的过程。
所以,我们研究「设计协同」的目的,就是设法使协同流程变高效,缩短产品的交付时间。
为此,我们需要解决以下三个问题:
- 降低设计与前端的沟通成本
- 提高设计的工作效率
- 提高前端的工作效率
然而,同时解决这三件事并不容易。
因为,这三件事彼此互为关联,并不独立,在协同上下游上相互影响。如果单纯 Case By Case 地解决,很容易出现【解决了问题 A,但引发了问题 B】的尴尬情况。
所以「设计协同」需要的不是单点方案,而是系统化的解决方案。
原始阶段 ➡️ 工程化阶段 1.0
问题
时间回到 2021 年,彼时云音乐的设计协同还较为初级,我称之为 「原始阶段」。
「原始阶段」存在的问题比较多,可以用下面这张图来说明:
首先,设计资产是通过人肉管理的,设计规范也是人肉同步,而且不同的设计团队之间设计标准不统一,设计资产存在重复建设。
此外,开发作为设计的下游,设计侧存在的问题,也会同步影响到开发侧,具体体现在:
- 对于同一个组件,因为规范的不同而重复开发;
- 类似换肤的三端联动场景,开发需要重复实现三遍;
- 开发侧完全人肉还原 UI,效率低。
思考
分析之后不难得出,以上问题存在的根本原因在于:
- 没有统一的设计规范;
- 缺少工程化的管理和提效手段。
而业界解决此问题的传统思路,一般是采取以 设计系统 为中心的「有损」设计协同。
作为背景知识,在这里容我先简单介绍一下设计系统。
设计系统(Design System)不是系统设计(System Design),前者是关于设计的系统,后者是关于系统的设计 🤣。
具体而言,所谓设计系统,就是一系列遵循严格设计规范的可复用的组件集合,由风格指南、模式库和组件库三部分组成。 而关于它的定义,最早可追溯到 Design Better - Introducing design systems 这篇文章对其的介绍。
而以 设计系统 为中心的「有损」设计协同,具体而言,就是为设计系统提供两套组件实现:
- 一套是给设计师使用的 Sketch 或 Figma 组件库
- 一套是给前端用的 React 或 Vue 组件库
基于此的工作流程一般为:
这种做法能在 一定程度上 解决「沟通成本」和「开发效率」的问题,但同时也会在无形中造成设计意图传递的损耗。
为什么这么说呢?
这是因为,在以设计系统为中心的解决方案之中,设计规范存在两套相互独立的实现:
- 实现一:设计资产
- 实现二:组件代码
这就导致二者并不同源。
因此,设计意图从设计师传递到前端的过程中,不可避免引入「信息损耗」,而这种「损耗」则必须通过人的沟通才能解决,从而导致了不确定性和时间成本的产生。
所以,解决问题的关键在于,能否设法消除这种「信息损耗」?
于是,我们提出了基于 C2D2C 的无损设计协同。其核心思路是:通过工程化的手段,打通设计和前端,统一协作语言。
具体做法为:
- 设计系统的组件实现,有且仅有一套组件代码。
- 设计师使用的设计资产,利用组件代码,通过 C2D(Code to Design)技术动态生成的,以此保证两者的同源。
- C2D 生成设计稿时,自动注入组件元数据,包括组件名、组件参数等开发相关的细节;在 D2C 阶段,自动解析此「元数据」,便可以直接将设计稿翻译成组件代码。
整体如下图所示:
此方案的好处主要有:
- 低维护成本,因为只需在开发侧维护一套组件库即可。
- 降低沟通成本,因为设计细节无损保存在元数据中,免去了双方的反复确认。
- 提高研发效率,因为前端可利用 D2C 一键还原 UI,免去人肉还原 UI 的繁琐过程。
解法
为此,为了实现基于 C2D2C 的无损设计协同,我们构建了三个子产品:
- 海豚设计系统
- Fin 1.0 设计插件
- 海豹 D2C
这个三个子产品共同实现了 C2D2C 的闭环流程:
这里有一个完整的演示,用来说明三者是如何相互联动, C2D2C 闭环的:
海豚设计系统
海豚设计系统是 C2D2C 的基石,但是构建起来并不容易。
技术选型
首先,由于云音乐 App 使用的跨端技术栈有两套:
- 产品功能页面:React Native
- 营销活动页面:H5
所以,海豚组件库需要同时支持 React Native 和 H5。在技术选型上,有两种方案可供选择。
方案一: 分别为 React Native 和 H5 独立实现两套组件库
优势:
- 架构简单
- 不用考虑兼容适配的问题
缺点:
- 开发工作量大
- 维护成本大
方案二:只实现一套 React Native 组件库,利用 react-native-web 实现 H5 的兼容
优势:
- 最大化代码复用,显著减少开发量
- 维护成本低
缺点:
- 在组件架构上会引入复杂度
- 有一定的兼容适配成本
鉴于需要开发的组件数量较多(50 +),且开发资源有限(2 人),综合考虑投入产出比后,最终选用了方案二。
架构设计
好的技术架构决定产品的生命力,特别是像组件库这种生命周期长的产品。在选用了方案二后,摆在我们面前的问题有:
- 虽然 react-native-web 提供了 H5 的兼容方案,但并不是所有的 React Native 组件都可以转成 Web,比如一些业务上的 Native Component;
- react-native-web 无法保证 100% 的 Web 兼容性,考虑到部分组件的兼容性成本,会存在着为同一组件分别提供 React Native 和 H5 两种实现,比如 Form 表单组件;
- 存在着一些平台专有组件,比如 Charts、Table 这种 H5 Only 的组件。
为了解决以上问题,我们设计了海豚组件库的三层架构:
它主要特点有:
- 稳健的底层:提供完全与业务无关的核心能力,包括底层能力、元组件、原子 UI 组件、功能组件和复合 UI 组件等,能够被 RN 和 H5 复用。
- 强大的中层:基于底层能力,提供与业务相关的功能组件,能够被 RN 和 H5 复用。
- 灵活的上层:基于中层提供的业务组件,按照平台特性的不同,灵活地提供不同平台的专用组件包。
配置化方案
换肤是云音乐 App 的重要功能;此外,云音乐还存在着像直播、音街这类不同子品牌的 App。
所以,为了支持以上这些场景,海豚组件库需要:
- 支持全局换肤
- 支持细粒度的品牌定制
那具体要如何实现呢?
我们的核心思路是:抽象变与不变,描述组件的组成关系。
以海豚 Button 为例,决定 Button 样式变化的 4 个属性分别为:
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
type | 类型 | 'surface', 'outline', 'text' | 'surface' |
level | 层级 | 'primary', 'secondary', 'normal' | 'primary' |
ghost | 是否是幽灵按钮 | boolean | false |
size | 大小 | 'xs', 's', 'm', 'l', 'xl', 'xxl' | 'l' |
所以,可以按照这四个维度,将 Button 拆解成 变化的视觉 + 不变的骨架。
变化的视觉为:
- Button 内间距
- 高度
- 圆角
- ...
不变的骨架,是由这四个属性排列组合成的正交变体:
- surfaceSecondaryLight 变体
- surfaceDark 变体
- outlinePrimaryLight 变体
- ...
通过将变化的视觉解构成两类 token:
全局 token:用于更改整体风格
colorPrimary1
colorNeutral4
spaceModule1
spaceComponent1
fontSizeMedium1
- ...
组件 token:对全局 token 的引用或自定义,用于细粒度配置组件
buttonPaddingXS
:theme.spaceComponent5
buttonHeightXS
:18
- ...
最后,只要配置不同的全局 token 和组件 token,就能实现全局换肤和组件粒度的品牌定制。
Fin 1.0 设计插件
Fin 1.0 设计插件的定位是提供给设计师的设计资产管理工具,让设计师可以利用 C2D 技术搭建出设计稿。
鉴于当时(2021 年)Sketch 还是主流设计软件,Figma 在设计团队中的使用也比较多,这就要求我们要同时支持 Sketch 和 Figma。
跨平台的插件架构
为了降低研发成本,我们设计了跨平台的插件架构,其核心思路就是用 Web 来承载 UI 和业务逻辑。
我们可以把插件分成 端容器 Client 和 Webview:
- 容器负责渲染和通信
- Webview 负责 UI 和业务逻辑
这样拆分后,Sketch 和 Figma 便能完全复用 UI,仅需要针对「端容器」和「Webview」通信方式、设计稿渲染逻辑上的不同,在 Client 上做差异化处理即可。
C2D 技术选型
C2D 的本质是代码转设计稿。
在业界,目前做 C2D 一般有两种思路:
思路一: 将 Sketch 或 Figma 作为 React 的一个端,利用类 RN 的语法,渲染出设计稿,比如 airbnb 的 react-sketchapp;
思路二:直接将组件的 html 转设计稿,比如 ant-design 的 html2sketch。
对 Sketch 而言,由于其发布的时间较早,C2D 的生态相对成熟,基于 html 的开源方案有 html-sketchapp、 html2sketch,但是 html2sketch 作为后来者在还原度上更佳,所以最终选用了 html2sketch 作为 Sketch 的 C2D 方案。
而 Figma 是 2016 年发布的,相对年轻,其 C2D 的生态还不够成熟,基于 html 的开源方案有 figma-html,但是其还原度还不够好,所以我们参考了 figma-html 的思路,选择了自研 html2figma。
html2figma 的本质,其实就是 DSL 的转换:将描述网页的 html, 转换成描述 Figma 设计稿的 Schema。
具体而言,就是将 html 的元素,比如 div 标签
、p 标签
、svg 标签
,映射成 figma 的 frame 节点、文字节点和矢量节点。
举个 🌰:我们有一个 div
元素,长和宽为 80px
,圆角为 40px
,背景色为红色。
我们可以将其转换成 Figma Frame Schema:长和宽分别为 80px
,填充色为红色,圆角为 40px
。
转换之后,通过 Figma 的 Plugin API, 就可以将其渲染到画布上,可以看到,二者在视觉上完全一样。
更多转换细节就不再展开了,感兴趣的同学可参考 figma-html 关于此转换的实现。
海豹 D2C
海豹 D2C 是 C2D2C 的最后一步:将设计稿转换成代码。
说到 D2C,想必大家也并不陌生,比如阿里巴巴的 imgcook,或者是京东的 Deco 。特别是 imgcook,由于其率先将基于 AI 的 D2C 用在生产环境,而且取得了不错的效果,这可能就会给大家造成一种误解:认为 D2C 就一定要用到 AI。
其实,不一定。
因为 D2C 的本质是将设计意图还原成代码,所以 D2C 的关键就在于如何让机器理解设计意图。
对于一张图片而言,由于其是非结构化的,它的所有信息完全包含在其二维像素平面内。对于这种场景,用基于 CV 技术的 AI 模型做组件识别,然后基于识别结果做 D2C 是非常合适的,但实现成本会比较高,因为会涉及到大量的数据标记和模型训练工作,整体 ROI 会较低。
但是,对于 Sketch 或 Figma 设计稿而言,因为其本身是结构化的,所以将其转换成代码是完全可行的,社区也有很多插件能做到这点,但真正的难点在于组件识别,也就是如何识别图层,将其与已有的组件库进行关联。
而海豹 D2C 的优势就在于,以较低的成本,实现了基于元数据的组件识别方案。
基于元数据的组件识别方案
在「Fin 1.0 设计插件」的介绍中,我们知道,通过 Fin 1.0 C2D 产出的设计稿,会默认注入组件元数据,所以在 D2C 的过程中,只需要检测当前图层是否包含元数据,便能实现组件识别功能。
具体的处理流程为:
- 若包含元数据,则是识别成海豚组件,解析元数据,然后还原成组件引用;
- 若不包含元数据,但存在子节点,则深度遍历判断是否包含元数据;
- 若不包含元数据,也不存在子节点,则将节点还原成普通的 div、img 等。
布局优化
由于设计稿是设计师在画布上通过拖拉拽搭建出来的,受设计师作图习惯的影响,设计稿中的元素一般都是平铺的。
如果不进行布局优化,那么整个页面将是一个扁平的结构,生成的将是绝对定位的代码,虽然还原度能够保证,但是可读性会比较差,比如:
而布局优化的过程,则是对 ABCD 进行分组,首先将页面分为 ABC 和 D 两行,然后将 ABC 分为 A 和 BC 两列,最后将 BC 分为 B 和 C 两行。
分好组后,通过新增三个布局容器,形成行列嵌套结构,这样最终生成的代码将符合开发者的直觉,具备较好的可读性:
从上面优化的过程可知,布局优化,其实就是在做行列分割,完整的流程如下图所示:
第一步,获取待处理的所有节点坐标。
第二步,对所有节点做节点关系处理,判断它们是处于包含、还是相交还是相离关系。处理逻辑为:
- 如果是包含关系,则将被包含的节点作为其子节点处理;
- 如果是相交关系,则将两者看做一个整体,且其中一个相对于整体作绝对定位处理;
- 如果是相离,则不做额外处理。
第三步,对处理完成的节点做二维空间投影,找到行列分割的依据,例如:
- 通过纵向投影,我们就知道了 ABC 和 D 是属于不同的两行;
- 通过横向投影,我们就知道了 A 和 BC 属于不同的两列。
第四步,依据二维投影得到的信息,对节点做行列分割,然后添加布局节点,进行行列分组。
最后一步,就是计算样式,生成包括 Flex 布局、绝对定位以及 Margin 偏移量等。
由于篇幅有限,关于设计工程化阶段 1.0 更为详细的介绍,可参阅笔者在 GMTC 上的分享:《网易云音乐基于 C2D2C 的无损设计协同》
工程化阶段 1.0 ➡️ 工程化阶段 2.0
工程化阶段 2.0 是对工程化阶段 1.0 的补充和完善。
背景
为什么要做设计工程化阶段 2.0 呢?那肯定是 1.0 存在某些问题。(笑
随着 Fin 1.0(C2D) 和 D2C 落地的深入,一些问题也慢慢暴露出来。
C2D 的问题
在 2022 年中的时候,在线协同类设计软件慢慢崛起,Sketch 已是明日黄花,云音乐的设计团队已基本全面拥抱 Figma / MasterGo 这类在线协同类设计软件。
随着设计师对此类工具了解的加深,他们发现使用 Fin 1.0 C2D 来做设计稿存在以下问题:
- 基于 Fin 1.0 的工作模式不符合设计师的工作习惯,使用成本较大。
- 设计师希望能够直接使用 Figma / MasterGo 的 Library 来做设计。
D2C 的问题
在 D2C 最初的产品设计中,我们将云音乐的页面类型分为两种:
- 产品功能页面
- 营销活动页面
我们的判断是:
- 产品功能页面强调 UI 的一致性,有固定的设计规范,需要识别组件。
- 营销活动页面创意性强,没有固定的设计规范,无需识别组件。
所以,我们认为 C2D2C 非常优雅地解决了组件识别的问题。
但随着业务落地的深入,我们发现,对于营销活动页面而言,虽然没有既定的设计规范,但也会用到一些通用的 UI Pattern,比如弹窗:
对于此类场景,由于弹窗的样式并不稳定,无法沉淀成规范,这就导致:
- 无法通过 C2D2C 进行还原;
- 直接 D2C 还原,出码产物将是 div 等基本元素的组合,只有样式,但是没有弹窗的逻辑。
最后造成前端需要基于已有组件库(比如 antd)进行大量的样式复写,工作量大且低效。
另外,虽然 D2C 在出码阶段进行了布局优化,但是用户反馈生成的代码可读性还是存在一些问题,特别是生成的 className:
总结一下,工程化 2.0 面临的问题主要有 3 个:
- 需要提供一套对设计师友好的 C2D 方案。
- 需要解决营销活动组件 D2C 还原的问题
- 代码的可读性需要优化。
思考
什么是对设计师友好的 C2D?
在回答这个问题前,我们需要做一些拆解。
对设计师友好的 C2D = 对设计师友好的工作方式 + C2D
那什么是对设计师友好的工作方式呢?通过用户调研后发现,对设计师友好的工作方式,有以下几个特点:
- 不引入额外成本,设计软件原生支持
- 简单好用、符合直觉
- 生态繁荣
具体到设计稿生产,就是能利用 Library 来做设计。
那 Library 要如何与 C2D 进行结合呢?通过对 Library 调研后发现,Figma / MasterGo 原生提供的 Library 能力很强大,支持 Component 和 Variant ,能实现设计稿与代码的一一对应:
且通过原生提供的属性配置面板,能非常高效便捷地完成组件的配置!
因此,对设计师友好的 C2D,就是为设计师提供一套海豚组件的 Library,但是这套 Library 是通过 C2D 生成的!
相应地,我们做 C2D 的思路,就从「运行时动态生成并注入元数据」变成了 「预构建 Library 并注入元数据」,由于设计稿元数据的格式没变,所以后续的 D2C 流程完全不受影响,完美!
D2C 要如何还原营销活动类组件?
对于这个问题,现有 D2C 难以解决的原因是:
- 若走 C2D2C 的方案,则要求组件具备稳定的样式规范,但这就满足不了活动 UI 个性化的诉求;
- 若走常规 D2C 方案,能够解决活动 UI 个性化的问题,但只剩下单纯的视觉还原,丢掉了组件的交互逻辑。
那有没有既能解决 UI 定制化的问题,又能保留组件的交互逻辑的方案呢?
于是,我们提出了基于 Headless UI 的 D2C 方案。
作为背景知识,首先简单介绍下 Headless UI。
Headless UI,顾名思义就是没有样式的 UI,只保留了骨架和交互逻辑,样式完全依靠用户自定义。它可以看成「样式与逻辑分离」在组件库上的一种实践。
所以,利用 Headless UI,将「样式与逻辑分离」的思想,应用在 D2C 上,不就可以实现了吗?!
如何做 D2C 产物语义优化?
对于这个问题,若在前 LLM 时代,是非常难解的。
但随着 LLM 时代的到来,GPT 3.5、GPT 4 等大模型的成熟,这个问题变得非常简单了:直接丢给大模型做语义优化即可。
当然,由于大模型的黑盒性质 + 结果不稳定,需要通过一些工程实践来规避由此带来的不确定性。
解法
基于 Library 的 C2D 方案
以海豚的 Button 为例,和样式相关的 API 有:
参数 | 说明 | 类型 | 默认值 | |||||
---|---|---|---|---|---|---|---|---|
type | 按钮类型 | "outline" \ | "text" \ | "surface" | surface | |||
level | 按钮层级 | "primary" \ | "secondary" \ | "normal" | primary | |||
ghost | 是否为幽灵按钮 | boolean | false | |||||
size | 按钮大小 | "m" \ | "xs" \ | "s" \ | "l" \ | "xl" \ | "xxl" | l |
disabled | 是否禁用 | boolean | false | |||||
leftIcon | 左侧图标 | ReactNode | - | |||||
rightIcon | 右侧图标 | ReactNode | - | |||||
loading | 设置按钮载入状态 | boolean | - |
如果要构建 Button 的 Library,则需要为 Button 的每一种不同的样式组合,在 Library 中提供一个对应的变体(Variant)。
我们可以简单估算一下,下面是 8 个与样式相关的参数的枚举值统计:
参数 | 枚举数量 |
---|---|
type | 3 |
level | 3 |
ghost | 2 |
size | 6 |
disabled | 2 |
leftIcon | 7(默认提供 7 种) |
rightIcon | 7(默认提供 7 种) |
loading | 2 |
组合而成的变体数量为: 3 *3*2*6*2*7* 7* 2 = 21168 个。
是不是很震惊?
一个 Button 就有上万个变体,50 多个组件全加在一起,数量将是巨大的。
人工来做完全不现实。
所以,肯定要借助工程化的手段,通过脚本来批量生产。
得益于我们在 Fin 1.0 中 C2D 技术上的积累,我们通过 html2figma 实现了 Library 的自动化生产。
以 Button 为例:
- 首先,通过脚本在网页上渲染出所有的 Button 变体;
- 然后,利用 html2figma 技术,将其批量转换成组件变体,并注入元数据。
- 如果需要支持 MasterGo,利用 MasterGo 「导入 Figma 文件」的功能即可,不用重新实现。
视频演示为:
这是我们采用此方案构建的海豚组件库 Library :
基于 Headless UI 的营销活动类组件 D2C 方案
由于营销活动的组件非常业务化,所以最好是可以将此能力开放出来,让用户自行定义、自行处理。
为此,我们设计了 D2C 的微插件方案,通过为用户暴露 D2C 生命周期各阶段的 Hook,让用户可以实现:
- 自定义标注规范
- 出码产物二次处理
然后,基于微插件,业务开发利用我们提供的 Headless UI 微插件脚手架,适配到自己的业务场景即可,具体的使用流程为:
视频演示:
基于 LLM 的 D2C 产物语义优化方案
如果直接将 D2C 生成的 JSX 和 CSS 输入给 LLM,让其对 className 进行语义化,并输出 JSX 和 CSS,在大部分情况下能正常 work,但是存在两个潜在的问题:
- 输入输出包含全部的 JSX 和 CSS,很容易 token 超限。
- 输出的内容可能是有损的(例如代码片段的丢失,输出的新的 className 名称发生了重复),容错能力差。
为此,我们对此过程进行了改造:
- 只用输入 JSX,不用输入全部代码
- 不再要求其输出完整代码,而是输出「className 优化前后的名称映射」
- 如果遗漏了某个 className 未优化或者发生了重名,将由后续代码逻辑来校验、兜底(只需要判断是否发生了重复,如果重复额外添加后缀,逻辑非常的简单),并不会对 HTML 文档造成破坏。
具体的 Prompt 为:
You are a front-end technologist.
Help me process the incoming JSX code so that the className is well semanticised and overall readable.
Then output the mapping relationship before and after the className to me in JSON (direct JSON output). For example:
Input:
```jsx
import React from 'react';
import '. /index.css';
const App = () => {
return (
<div className="music_1_1">
<div className="music_1_2"> 上一步 </div>
<div className="music_1_3"> 下一步 </div>
</div>
);
};
export default App;
```
Output:
```json
{
"music_1_1": "main",
"music_1_2": "prev",
"music_1_3": "next"
}
```
Understood, please reply 1
这样做的好处是:
- 可最小化输入,节省 token;
- 可基于 LLM 的输出做容错处理,添加兜底逻辑。
在 D2C 上的最终效果为:
工程化阶段 2.0 ➡️ 智能化阶段
背景
时间来到 2023 年。
回顾过往,设计工程化所解决的问题,主要集中在 「降低设计与前端的沟通成本」 和 「提高前端工作效率」 上,然而,在「提高设计工作效率」方面,设计工程化的贡献相对有限。
随着 AIGC 的火爆出圈,在了解到 AIGC 在「提高设计工作效率」上的潜力后,我们决定要利用 AIGC 搞一些事情 👻。
为此,我们对云音乐的设计师进行了多次田野调查,梳理出了当前的设计流程,并按照需求来源的不同,将其分为两种:
1、需求源自策划的设计流程:
2、需求源自运营的设计流程:
通过分析后发现,现有的设计流程存在以下痛点:
- 沟通成本高
- 设计效率低
- AIGC 使用少、门槛高
具体情况如下图所示:
思考
我们都知道,问题能被解决的关键,在于是否能清晰地定义问题。
因此,为了从根本上解决上述问题,我们必须回答:UI 设计的本质是什么?
为此,我们可以对设计流程进行抽象和简化,如下图所示:
可以看到,UI 设计可以抽象成一个输入输出模型:输入是自然语言描述的需求,输出是设计稿。
因此,UI 设计的本质,就是一个「将自然语言描述的需求翻译成设计稿」的过程。
具体而言,就是将「自然语言描述的需求」翻译成由若干由「组件」、「图标」或「图片」组合而成的设计稿,这个过程可以用下面的公式来表达:
那么,造成的「UI 设计低效」的原因,就在于这个「翻译的过程」大部分是由人参与并执行的,这是因为:
- 多人协作引发了沟通问题。
- 技能水平、专业门槛和生理限制导致了效率问题。
所以,如果想从根本上解决 UI 设计的效率问题,就应该利用 AIGC 重构这个「翻译过程」:
- 解放设计生产力,摆脱繁琐的设计细节,转而去关注产品的整体功能和体验。
- 赋能非专业设计师来做设计,突破职能限制,实现一专多能,「人人都是设计师」。
而为了实现以上目标,我们需要解决以下三个「翻译问题」:
- 文生图:如何让 AI 理解设计意图,生成图片?
- 文生 ICON: 如何让 AI 理解设计意图,生成图标?
- 文生稿:如何让 AI 理解设计意图,并用组件和素材(图标、图片)搭建出 UI ?
解法
为此,我们推出了全新的产品——Fin 2.0,提供三大 AIGC 能力矩阵(文生稿、文生图、文生 ICON)+ AIGC 资产共享中心,赋能策划、运营、设计,降低沟通成本,提高设计效率,让业务创新变得简单。
AIGC 能力矩阵
文生稿:
- 赋能产品 / 运营,将「文字需求稿」转换成高保真的设计稿,减少沟通环节。
- 赋能设计师,提供低成本的创意、灵感来源和竞品分析能力。
文生图:
- 赋能设计师,降低插画生产的时间成本。
- 基于 DreamMaker 二次封装,提供易用的文生图功能,降低文生图使用门槛。
- DreamMaker 为内部平台,消除了数据安全的隐患。
文生 ICON:赋能设计师,降低 ICON 生产的时间成本。
AIGC 资产共享中心:对用户 AIGC 过程中产出的设计组件、提示词、图片和 ICON 进行回流沉淀,共享复用。
未来工作模式
1、需求源自策划的设计流程
新流程特点:
- 赋能策划,利用「文生稿」直接将文字需求转为 高保真初稿,避免了设计出多套方案 & 反复对焦,降低沟通成本。
- 设计基于 高保真初稿 进行二次修改,利用 「文生图」和「文生稿」生产物料,提高设计效率。
- AIGC 的产物(图片、ICON、设计组件、提示词),最后都会回流进 DOLA AIGC 资产库,实现共享复用。
2、需求源自运营的设计流程
新流程特点: 赋能运营,基于「文生稿」功能,搭配「文生图」和「文生 ICON」直接出稿,免去了和设计之间沟通协作,提高了设计效率。
产品设计
对于 AI 驱动的应用而言,单纯的 AI 能力(GPT 3.5/4、Stable Diffusion)并不能构成产品的核心竞争力,因为大家都是调包工程师。(笑
所以,核心竞争力在于是否具备产品力,用大白话讲,就是是否能真正解决实际问题。关于这这一点,不管是内部产品还是外部产品,同样适用。
所以,一个好的产品方案至关重要。
为了实现这一目标,Fin 2.0 的产品设计遵循以下原则:
- AI is the UI
- 小而美
AI is the UI
在 LLM 时代,AI 的内涵和外延都应该被重新定义:AI 既是一种技术,也是 UI 本身,是人与机器交互的终极方案。
不管是 ChatUI、 Conversational UI 还是 Dialog UI, 都是 AI 这种全新 UI 的实现。
某大佬曾言:在 LLM 时代,所有应用都值得被 AI 重做一遍。
我的理解是:这句话的本质,讲的其实就是将现有的 GUI 重构成 AI 这种 UI。正如在图形界面时代,所有的 CLI 应用被 GUI 重做一样。
所以,我们基于 AI 这种全新的 UI 来设计产品交互,通过自然语言对话的方式提供一个「超级入口」,轻松触达所有功能,比如:
- 文生稿
- 文生图
- 文生 ICON
- 设计规范问答
- 换肤
- 字高修复
- 位图转矢量图
- ...
小而美
「小而美」也是我们产品设计的一个重要理念。但是,我们需要明确一个事实:小而美是实现路径,而非目标,产品的目标永远是创造价值。
在产品从 0 到 1 的阶段里,小而美是为了控制成本,聚焦产品,是非常必要的:永远是做简单且完整的产品,不是复杂事物的 0.1 版,而是简单事物的 1.0 版。
何为「小」?
1、信息架构简单且清晰
充分利用对话式 AI 的优势,保证整体的信息架构简单且清晰,层级结构尽可能简单,2 层是极限。
2、功能简单但完整
简单且完整的功能,除了能解决问题外,还能带给人秩序感和愉悦感:
3、聚焦
通过聚焦,砍掉不必要的功能,降低研发投入:
何为「美」?
1、精美的图标
2、合理的排版
3、流畅的动效
4、合理的引导和提示
核心功能演示
文生图
文生稿
生成视觉稿
生成线框稿
技术方案
Chat UI
Fin 2.0 Chat UI 的技术架构为:
其基本流程是:
- 用户通过自然语言与 Fin 2.0 对话
- Fin 2.0 利用 Adora(云音乐 LLM 基建)进行意图识别,转换成 Action
Dispatch Action,根据 Action Type 的不同,执行不同的操作:
- 路由跳转
- 渲染图文消息
- 唤起微应用
以上流程中,最核心的部分是意图识别。
在前 LLM 时代,意图识别一般采用 NLP 来实现,其成本高,准确率低。
LLM 时代到来后,意图识别变得非常简单和直接。
比如,我希望用户在输入「文生图」后,可以识别此意图,并自动路由到「文生图」页面上。现在只需利用 GPT 的 Few-shot learning 能力, 给出类似下面的 Prompt 即可:
System:
You need to analyze the content of Inputs based on the information of Resources, follow the constraints of Constraints, and return data that conforms to the Response Format format
Input:
打开文生图
Constraints:
1.According to Inputs, match a most relevant command KEY
2.If there is no suitable match in the preset instructions, "NOOP" is used by default
Resources:
"TEXT_TO_IMG":[STRING]当用户想要打开「文生图」功能时命中,例如输入 「打开文生图」「文生图」「AI 生图」
"TEXT_TO_DESIGN":[STRING]当用户想要打开「文生稿」功能时命中,例如输入 「打开文生稿」「文生稿」「AI 生稿」
"TEXT_TO_ICON":[STRING]当用户想要打开「文生 ICON」功能时命中,例如输入 「打开文生 ICON」「文生 ICON」「文生 icon」「AI 生 ICON」
You should only respond in JSON format as described below
Response Format:
{
"payload": “the matched instruction key",
"type": "route",
}
Ensure the response can be parsed by Javascript JSON.parse();
For example:
Input:
文生图
output:
{
"payload": "TEXT_TO_IMG"
"type":"route"
}
Understood, please reply 1
GPT 经过学习之后,就能充当一个非常好的意图识别器:
文生图
对于「文生图」而言,图片的 AIGC 已比较成熟,不管是闭源的 Midjourney,还是开源的 Stable Diffusion,都能生成效果非常棒的作品。
但正如在上面的「痛点」中所提到的:
- Midjourney 费用开销较大,对于保密项目存在着数据安全的风险。
- 内网部署的 Stable Diffusion(DreamMaker)参数配置复杂,使用门槛高。
所以,综合考虑收益和成本后,最终的方案是:基于内网部署的 Stable Diffusion(DreamMaker)进行二次封装,提供简单易用的「文生图」方案。
更为详细的介绍,可以参考:《如何使用 Fin2.0 文生图登上云音乐首页》
文生 ICON
对于「文生 ICON」 而言,SVG 矢量图标的 AIGC ,业界暂无成熟方案。
但是,学术界已有了相关尝试:借助 Stable Diffusion 和 VectorFusion 技术,可以实现「文生 ICON」。然而,此方案仍处于实验阶段,暂无法用于生产。
所以,考虑到实际情况后,最终的解法是分阶段来实现:
- 第一阶段(本期),整理优质的可商用的图标资源,并提供语义化检索功能,满足用户找图标的诉求;
- 第二阶段,待社区有了相关实践后,基于已有数据集,利用 Stable Diffusion + Lora 训练 ICON 的像素模型,并搭配 VectorFusion,实现生图标的需求。
语义化检索最大的优势,就是根据语义进行检索,不是传统的「关键字匹配」,更好用,更符合人类直觉。
因为图标的数量很大,有接近 2 万个,要怎么用 ChatGPT 实现 语义化搜索呢?如果直接将其作为 ChatGPT 的上下文输入,必然会超限,而且也会存在较大的 IO 性能问题。
为此,我们采用 embedding API 来实现,其基本原理是:
首先,将所有的 ICON 数据标准化成下面的格式:
{
"id": 17246,
"name": "zoom",
"library": "icon-park",
"label": "滑动,侧滑,放大,zoom,Hands,手势动作",
"style": "outlined"
}
然后, 通过 OpenAI 的 embedding API 进行向量化,并存储到向量数据库中,比如 pinecone,或者 chroma。
这里需要注意的是,由于 API 字符数的限制,需要使用文本分词器进行分批向量化。
最后,用户通过关键字进行语义搜索时,首先会对关键字进行向量匹配,向量数据库会按照相似度返回近似结果,然后将此结果连同用户的原始输入,一并提供给 ChatGPT,ChatGPT 就会返回在语义上最匹配的 ICON 了。
文生稿
对于「文生稿」 而言,问题就稍为复杂一点。
大语言模型 LLM 能很好地理解自然语言,但由于其输入输出是基于文本的,所以并不能直接生成设计稿。因此,这中间必然有一个 Text2Design 的过程。
于是,就有了下面两种方案:
方案一:LLM 返回 HTML,通过 C2D 技术转成设计稿。
优势:
- 实现成本低
- HTML 灵活,自由度大
缺点:
- 难以与 Design System 关联,形成统一的样式规范
- C2D(html2figma、html2mastergo) 还原度无法保证 100%
方案二:LLM 返回自定义 DSL,解析 DSL 转成设计稿。
优势:
- DSL 可以做到结构简单、精炼
- 能与 Design System 关联
- 不依赖 C2D 技术,避免了潜在的还原度问题
- 缺点:自行设计和实现 DSL 协议和渲染,有一定的开发成本,但是并不复杂。
考虑到「文生稿」需要与设计系统结合,最终选用了方案二。
DSL 的设计
我们设计的 DSL 结构非常简单,每个节点只有两个属性,componentName 和 props:
interface NodeDSL {
componentName: string;
props?: Record<string, any>;
}
type DSL = NodeDSL[];
但是利用 Figma / MasterGo 的 Component 和 Variant 能力,就能释放强大的表达能力(有点类似前端的可视化搭建):
const page: Page = [
{
componentName: 'StatusBar',
props: {
title: '歌单列表 & 专辑卡片',
},
},
{
componentName: 'List',
props: {
title: '歌单列表',
content: [
{
title: '张杰新歌',
subTitle: '曲风:流行',
icon: '🎵',
},
{
title: '周杰伦经典',
subTitle: '曲风:流行',
icon: '🎧',
},
{
title: 'KTV 最爱',
subTitle: '曲风:流行',
icon: '🎤',
},
{
title: '说唱力 MAX',
subTitle: '曲风:说唱',
icon: '🔥',
},
{
title: '粤语老歌',
subTitle: '曲风:粤语',
icon: '🎵',
},
],
},
},
{
componentName: 'Card',
props: {
title: '推荐专辑',
content: [
{
title: '跨时代',
tag: '周杰伦',
icon: '🎧',
},
{
title: '周杰伦的床边故事',
tag: '周杰伦',
icon: '🎤',
},
{
title: 'Universe',
tag: '杨峰',
icon: '🎵',
},
{
title: 'F.A.M.E.',
tag: '马尔代夫',
icon: '🔥',
},
{
title: '语重心长',
tag: '林宥嘉',
icon: '🎵',
},
{
title: '灿烂人生',
tag: '林忆莲',
icon: '🎧',
},
],
},
},
];
Prompt & 意图识别
为了能让用户用自然语言准确地描述设计需求,我们对 Prompt 进行了规范:
Prompt = 动作 + 主体 + 主题色 + 设计风格 + 布局
比如下面的 Prompt:
设计一个音乐 App 首页,主题色为蓝色,扁平化风格,采用瀑布流
我们利用 ChatGPT 实现了一个简单的意图处理器(和 Chat UI 部分意图识别类似,不再展开),可以将用户的输入转换成下面的结构化数据:
{
"actionType": "add",
"style": "flat",
"main": "一个音乐 App 首页",
"theme": "#0000ff",
"layouts": "flow"
}
有了这样的结构化数据后,用户的意图就变得清晰了,方便后续利用不同风格的组件库、布局模版模仿人类来搭建设计稿。
让 ChatGPT 学会使用组件
通过上面所说的「意图识别」后,我们已经能够明确用户的设计需求了。那怎么让 ChatGPT 利用已有的物料模仿人类完成搭建呢?
问题的关键在于让 ChatGPT 学会使用我们提供的组件库。
因为 ChatGPT 拥有非常强大的文本理解能力,所以我们的做法其实非常简单:直接将组件的 API 文档作为上下文提供给 ChatGPT。
这种做法看似粗暴,但是效果出乎意料的好。下面是一个简化了的小 Demo:
具体的 Prompt 对话可见:https://chat.openai.com/share/69aee90a-101f-4356-87fe-e59729e...
当然,实际在项目中的使用并没有这么简单,需要考虑很多工程上的问题,比如:
- token 超限的问题
- 组件隔离的问题
- 换肤的问题
这些问题解决起来都不难,鉴于本文已经很长了 😅,就不再展开了。
落地效果
截止到今天(2023-12-26),Fin 2.0 已累计生图 11360+,产出设计稿 921+,覆盖云音乐 10+ 业务场景,综合提效 33% ~ 200%。
总结展望
网易云音乐的设计协同经历了原始阶段、工程化阶段 1.0 和 2.0,目前已进入智能化阶段。
尽管智能化刚刚起步,但充满了潜力和想象空间,尤其是近期 AI Agent 技术的蓬勃发展,将彻底重构现有的协同流程。
因此,在未来,我们将持续探索基于 AI Native 的智能化设计协同,打造云音乐设计生产一体化方案——AI2D2C 👏。
鸣谢
筚路蓝缕,以启山林,最后感谢为云音乐设计协同添砖加瓦的每一个人 ❤️,他们是:
- 研发人员:葛星、刘甲、魏慷、李磊、章伟成、张永聪、徐超颖、尤振飞、邵锁
- 设计人员:吕峰、张渝堃、徐晓强、顾容玥、关昊斌、袁安、王孟锴
感谢你们!
相关链接
最后
更多岗位,可进入网易招聘官网查看 https://hr.163.com/
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。