这不是一张卡片。

这是一台机器。
在你读到任何一条规则之前,先把它拆开

↓ 往下
第一章

先认清它是什么

把鼠标放到右边任意一行上。左边那个部件会亮起来。

部件,不是样式
  • 推杆有刻度因为推杆有刻度。
  • 杆帽上有一道压痕因为你要用拇指推它。
  • 四个键播放、停止、后退、快进。deck 就是四个键 —— 少两个不是「精简」,是缺件。
  • 两个转盘在转因为磁带在走。它压到 20% 不透明度, 是机芯,不是插图。
  • 灯亮着而且它自己发光 —— 熄灭时它沉在孔里。
  • 播放头是个三角它指着「现在」。

这六条里,没有一条是「设计决定」。它们是承认

设计动作只发生过一次:决定这是一台机器。
在那之后就没有选择了,只有忠实。
第二章

可是「一次授权」不是机器

上一章太容易了。deck 是 deck,没得选。
但界面里绝大部分东西没有实物 —— 一次 OAuth 授权是什么形状?一组权限是什么形状?

You
N
Nightcord
两个端子,一根通着电的线
profile READ
email READ
面板上凿出来的托盘

授权被当成两个端子加一根通电的线; 权限被当成凿进面板的托盘; 黑幕被当成贴在字上的胶带; 引用被当成手册页边的变更条

所以真正的方法不是「承认它是什么」—— 抽象的东西没有可承认的本性。 是这个:

找一个物理对象,
能做的事和这个抽象物能做的事一一对应;
然后忠实于那个物理对象。

决定只做一次,就是选这个对应。选完之后形态、光照、状态、 交互全都被那个实物决定了,一个都不用再想。 walkman 之所以让人觉得压根没做过决定,不是因为没决定 —— 是「放音频 ↔ 磁带走带机构」这个对应太完美, 决定本身变得看不见了

对应好不好,可以判:
实物给了抽象物没有的操作 → 媚俗(皮革缝线的日历)。
抽象物有操作而实物给不了 → 牢笼(你被自己的比喻卡住)。

transport 只给两个键,就是后一种:脑子里的「它」是「一个播放器控件」 (两个操作),而不是「音频」(播放、停止、退、进、音量、定位)。 隐喻没错,是对事物的模型太穷。

第三章

东西是真的,所以有光

按住左边这个键,别松手。看它的上边缘

按住它
按下时

抬起时上边缘有一道亮线(inset 0 1px 0 rgb(255 255 255 / .08))。按下去,那道亮线翻转成了阴影。 这不是两个状态的两套样式 —— 是同一个面从凸变凹。

关掉之后它还是能按,还是会变色。只是它不再是个键了 —— 它是一个会变色的圆角矩形。

整个 SEKAI 只有一个光源,在左上偏上。
凸起的顶边受光,凹陷的顶边背光,抬起的东西向右下投影 —— 包括投到旁边的元素身上

最后半句不是修辞。简单播放器的播放键,把影子投在了它右边的屏幕区上: inset 4px 0 8px -4px rgb(0 0 0 / .1)。 自称「扁平 + 阴影」的系统不会写这一行。写了,就说明作者脑子里是 一个统一打光的场景,不是一张阴影表。

第四章

所以阴影不能乱给

两张一模一样的卡片。哪一张在撒谎?

OAuth 应用

nightcord · 三个 scope

A
OAuth 应用

nightcord · 三个 scope

B

B 看起来更「精致」,对吧。但它在宣称一个它没有的高度 —— 它就躺在页面上,和周围是同一个平面。 那圈发丝线已经把话说完了:这里是它的边,仅此而已。

1px 发丝线 = 物体的边。它一直都在。
阴影 = 这个物体离开了它所在的平面。
所以共面的东西只有边;抬起来的东西 边和影都有 —— 抬起来了也还是有边的。

再往下想一层:一个面没有绝对高度。 你说不出某个位置的势能是多少, 只能说出两点之间差多少。所以「抬起」从来不是颜色的属性, 是它和底下那层的差。

于是有件事就顺过来了 —— 模态背后那层遮罩不是为了压暗气氛,它是在重设零点。 它把画布压到近黑,模态不用改自己的颜色就成了抬起的。 撤掉遮罩,同一个值立刻变回一口井。它是承重结构。

源文件里零例外:.app-card.sekai-file-card.permission-box 全都只有发丝线; 只有真的离开了平面的东西才投影 —— 模态浮在遮罩上、吐司浮在一切之上、 主面板装在仪器面上。

而它们的影子还各不相同,因为影子是尺寸的函数: 32px 的回复键几乎没有面积可投影,要 .3 才看得出离地;一整块面板要的是又宽又软的那种。重要性一样、尺寸不同的两个东西, 影子必须不同。

第五章

颜色不是用来好看的

下面这块面板顶上有一条 3px 的主色。它在干什么?

SEKAI Pass

它在说:这一块是主体。看这里。

转完之后它还在,还是紫的,还是 3px。但它不再指向任何地方了 —— 它变成了装饰。

90deg(沿阅读轴)= 引导 —— 顶栏、扫光、连接线上跑的数据包、进度条的生长方向。
其它角度 = 拟物 —— 描述一个面朝哪、哪边受光。
源文件里零例外。

所以主色从不做大面积填充。它做 3px 顶栏(「这块是主体」)、 做 4px 左脊(「这段来自别处,从这里读」)、做播放头三角(指着「现在」)、 做 (指向外部)。 每一处主色都在回答「往哪看」。

第六章

有两种字,因为有两种东西

下面这个字段。点一下开关,看那个发生了什么。

锁定之后,值自己换成了等宽字。不是「禁用态的样式」—— 是这个值换了身份:它不再是你能写进去的内容, 它变成了印在上面的铭牌。

等宽 = 印在机壳上的丝印字,厂家印的,你改不了。
无衬线 = 设备屏幕里显示的内容,会变。

SEKAI PASS // SYSTEMEDITABLE DATASTEREO、字节数、时间码、 scope 上的 READ —— 全是印上去的。昵称、消息正文、应用名 —— 全是显示出来的。 分界从来没模糊过。

第七章

于是就有了这些

下面每一个都不是「设计出来的组件」,是前五章的后果

按下时落回原位 · 第三章
AUTH_INVALID_GRANT — code expired
左脊指向 · 第五章 · 丝印 · 第六章
profile READ 读取昵称与头像
凿进面板的托盘 · 第四章
语音 → 时域波形,不是频谱柱

上面这台和封面那台是两种东西。封面那台放音乐, 所以它给你 32 段频谱 —— 你想看的是各频段怎么配比。 这台是一条语音,语音没有值得看的频谱,它有的是包络, 所以这里是示波器。互换一下,两台都会开始对自己的用途撒谎。

H
houtar 02:47
把鼠标移上来 —— 回复键会升起来,然后落回去
32px 的芯片,需要更深的影子才离得开地
第八章

同一个场景,两种环境光

按右下角切换。注意:token 的名字一个都没变。

canvas
surface
surface-card
accent
accent-deep
signal

world-night 是 nightcord:紫罗兰的桌面, 侧栏是挖出来的槽,聊天卡躺在桌上。
world-system 是 SEKAI Pass:暗室里的一块仪器面, 面板装上去受光,输入框是面板上凿的井。

两个世界遵守同一条规则 —— 相对它所在的那一层,抬起就更亮,凹陷就更暗。 它们不是两套配色,是两个零点

唯一不跟着变的是封面那台机器。它不吃任何一个世界的画布和主色, 因为它不是这个界面的一个面,它是有人把一台硬件放了进来。 反差就是它的设计。

本就应该如此

如果你读到这里没觉得学到了什么规则,
那就对了。

这里没有一条是「为了好看而定的」。每一条都只是: 找到它对应的那个实物,然后不撒谎。

所以真正会失手的地方,是你以为某个东西没有对应实物的时候 —— 那一刻你会开始发明,而发明出来的东西一定像别人的。 这套设计里唯一直接搬了外部调色板的地方,就是身份色; 因为「一个人的颜色」看起来纯粹是约定。

它不是。一个人的颜色是彩色标签牌 —— 鲜亮的底、同色相的深字,因为那样才能隔着距离一眼认出来, 而「一眼认出来」正是它唯一的功能。

「没有对应实物」从来不是事实,
只是还没找到

找不到的时候,正确的动作是继续找,
不是开始发明。

SEKAI DESIGN SYSTEM // 完整规范见 DESIGN_SYSTEM.md

继续

读完之后

规则在规范里,取值在令牌页,样子在组件页。源码和讨论在外面。

工具 令牌查询 两个 world 的色板、字号、阴影与语义色,可切换对照。 工具 组件一览 按钮、表单、卡片、提示、头像与签名装置的活样本。 源码 GitHub 25-ji-code-de/sekai-design · Apache-2.0 规范 DESIGN_SYSTEM.md 完整设计规范,与本页导读同源。 频道 Bilibili @bili_47177171806 生态 文档站 docs.nightcord.de5.net 生态 SEKAI Hub 门户与用户中心 组织 25-ji-code-de 全部公开仓库