开发
设计规范
检测网站、文档站和预览图片的页面构图、字体与颜色、动效、文案格式和可用原语,供修改界面时对照。
修改设计规范时编辑仓库里的 web/design.md,本页会显示它的内容。规范按项目里的 ikadesign3 skill(.agents/skills/ikadesign3/)编写,只规定呈现方式;功能、字段和阈值以代码为准。[MUST] 是硬性要求;[SHOULD] 是默认做法,标有“决策”的条目附有依据;[UNCONFIRMED] 是尚未确认的推断,附有来源。
范围与优先级
- [MUST] 本文件约束
web/的全部页面与浮层、浏览器导出的结果图片、docs/文档站,以及文档构建生成的链接预览图。 - [MUST] 本文件不约束 CLI 的终端输出、README 和 GitHub 仓库页面。
- [MUST] 不参考旧站点的视觉外观。
- [MUST] 冲突时按以下顺序取舍:真实数据与用户要求、无障碍与可用性、读者当前的任务、本项目已有约定、品牌表达、装饰细节。
- [MUST] 页面的功能、字段、状态条件和阈值以任务需求和代码为准;本文件只规定它们的呈现方式。
品牌与读者
读者在桌面上连续比较数字、模型标识符和百分比,也会在手机上查看结论;熟悉 API 术语;界面会出现中英文混排的标识符和原文。
- [SHOULD] 中性工具感:表面、文字和边框只用零彩度灰阶 token;
--primary蓝色只出现在主要操作、焦点环、当前导航下划线、链接和置信度条上。(决策:突出检测任务,不复制已有产品界面。来源:项目初版设计决策。) - [MUST] 像素指纹是唯一的品牌装饰:品牌标识、加载、等待和空状态使用
PixelShader的像素效果,颜色取 muted-foreground。 - [MUST] 动效是空间连续、无回弹的弹簧:卡片在原位伸缩,导航下划线和列表项平移到新位置。
- [SHOULD] 工具页高度由内容决定,不放全屏宣传区或插画。(决策:这是工具页,不是营销页。来源:项目初版设计决策。)
- [MUST] 文案语气直接、克制:陈述结果和限制,推断性的结论写成“候选”“最接近”“排名”,不写成“已确认”。
- [MUST] 状态同时用文字和颜色表达,不只靠颜色。
页面结构与构图
应用外壳
- [MUST] 工具页和文档页共用顶栏
fp-topbar:桌面高 56px,三栏网格,左侧品牌标识,中间主导航,右侧仓库入口、Star 入口、语言切换和主题菜单。 - [SHOULD] 640px 以下顶栏改为 88px 双行(56px 加 32px),主导航排在第二行,仓库入口隐藏,由指向同一仓库的 Star 入口代替;1024px 以下仓库入口和 Star 入口只显示图标。
- [SHOULD] Star 入口
fp-repository-star高 32px,star色图标与text-meta500 字重文字,边框为 35%star混入border,底色为 8%star。(决策:在仓库入口旁给出一个低调的 Star 入口。来源:2026-10-06 用户要求。) - [MUST] 768px 以下,顶栏右侧的图标按钮(仓库入口除外)至少 44×44px;Star 入口在这一宽度去掉边框和底色,只保留
star色图标。 - [MUST] 品牌标识
fp-brand:左侧 32px 像素指纹fp-brand-mark(muted-foreground),右侧两行文字,上行fp-brand-title,下行fp-brand-byline。 - [SHOULD] 检测站顶栏左栏
fp-topbar-start依次放品牌标识和检测器下载进度DetectorProgress,间隔 16px。下载开始 300ms 后仍未完成才显示进度,缓存命中时不显示。1280px 起:94px 宽的ProgressCells,后接text-metamuted 文字“检测器 已下载 / 总量 MB”。完成后格子全满,后接 success 色CircleCheck和“检测器已就绪”,1.6 秒后淡出。失败时去掉格子,显示 destructive 色CircleAlert、失败文字和 ghostxs重试按钮。1280px 以下,进度改为顶栏上边缘的 2px muted-foreground 横线,按已下载比例scaleX;失败时不显示。检查方法:1280px 下五种语言的加载、就绪、失败三种状态,进度右缘都在主导航左缘以左。(来源:2026-10-11 用户要求进入网页时在品牌旁异步显示检测器下载进度。) - [SHOULD] 当前导航项用 2px primary 下划线
fp-nav-indicator标出,下划线只在导航容器内横移。指向另一个站点的导航项是普通整页链接,不参与下划线动画。 - [MUST] 主题菜单是“浅色 / 深色 / 跟随系统”三项单选,标出当前项,默认跟随系统;切换主题或语言不清除页面上已输入的内容。
- [SHOULD] 顶栏右侧图标:仓库入口用 lucide
GitBranch,Star 入口用填充的Star,语言切换用Languages,主题按钮显示当前选项对应的Sun、Moon或Monitor;图标 16px,按钮带可读名称。 - [MUST] 页脚居中,使用
text-metamuted 文字,不放像素装饰。
多卡片工作台
用于一次处理多份同类输入并在同一页给出结论的页面。
- [SHOULD] 使用
fp-page。首屏自上而下:页头(唯一的 h1,右侧为Segmented模式切换)、一行紧凑提示条fp-cli-promo、可选的整行配置卡片、卡片网格fp-grid-samples、操作行fp-detect-footer。 - [SHOULD] 提示条只占一行高度:命令片段用
fp-cli-command,其中的可执行名和参数为 primary 600 字重;点击命令复制全文并用 toast 反馈;行末是 primary 文字链接。 - [SHOULD] 卡片网格 1024px 起为三列等宽,1024px 以下为一列。
- [SHOULD] 输入卡片
SampleCard自上而下:标题行(text-card-title编号标题、状态徽标、更多菜单)、参考原文(默认显示四行,可展开全文)、输入区、底部text-meta计数。 - [SHOULD] 输入区
fp-reply固定 12rem 高,保留原始换行,内容超出时在区内滚动,不随内容增高,不可拖拽改变大小;空白等待区保持同一高度。流式追加文本时滚到底部,手动编辑时跟随光标。 - [SHOULD] 操作行左侧是次要链接
fp-star-link,右侧是操作栏fp-actionbar,两端与网格左右边缘对齐,同高 36px。 - [SHOULD] 768px 以下操作栏固定在视口底部(最小高 64px,避开 safe-area-inset-bottom),页面底部留出同样的空间;次要链接留在内容流末尾。
- [SHOULD] 结果状态:卡片网格收为一行摘要条
SampleStrip;点击一项在摘要条下方展开它的详情,一次只展开一项;再次点击该项或点详情右上角的“收起”关闭。640px 以下摘要条隐藏计数,不缩小文字。 - [MUST] 计算要等检测器下载时明确说明:计算状态行改为两行,上行依次为
PixelSpinner、text-bodymuted 的“正在等待检测器下载完成”、行尾text-meta已下载量;下行是整行ProgressCells。主按钮文字改为“等待检测器”,后接percent格式的进度。下载完成后恢复为普通计算状态行。(来源:2026-10-11 用户要求检测器阻塞计算时明确显示,检测按钮也要显示。) - [SHOULD] 结果区
ResultPanel自上而下:text-section-title区块标题、摘要卡片、整行警告、text-bodymuted 说明、候选列表、限制说明。区块间隔 24px。 - [SHOULD] 摘要卡片分左右两栏。左栏依次为
text-meta标签、text-display名称(overflow-wrap:anywhere)、text-bodymuted 次级信息,名称旁放logo像素标识。右栏右对齐,依次为text-display-number主百分比、text-meta标签和来源行,整组相对卡片垂直居中。窄屏保留两栏,名称和来源可以换行。 - [SHOULD] 候选列表放在一张
fp-card里,每行用fp-result-row:24px 序号列、名称列(font-medium)、120px 次要标签列(muted,单行省略)、ConfidenceBar、64px 右对齐百分比列,最小行高 48px,行间 1px 分隔线。默认显示前 8 行,末行用 ghost 小按钮展开全部。 - [SHOULD] 768px 以下候选行改为序号、名称、百分比三列,置信度条移到第二行,隐藏次要标签列。
- [MUST] 置信度不可用时显示破折号或“不可用”,不显示 0%,也不画空置信度条(该行加
data-unscored)。 - [SHOULD] 结果区操作:主操作在右,次要操作在左,低频操作收进更多菜单。
- [SHOULD] 需要警示的卡片和它的详情使用
fp-card[data-warning],卡片标题旁加警告图标;结果区同时用Alert variant="warning"说明原因,并排在其他警告之前。 - [SHOULD] 可折叠配置卡片
ApiConfigPanel:收起时为一行 48px 等宽摘要fp-api-summary,长值单行省略,完整值放在title,不显示密钥;展开后为表单,桌面两列,窄屏一列。展开和收起用 220ms 高度与透明度过渡,摘要位置不动。 - [SHOULD] 表单中的开关组之后用分隔线开始下一组。
Segmented下方用一行text-metamuted 文字,只说明当前选中的选项。 - [SHOULD]
Segmented选项可以在文字前放 16px 图标(icon),在文字后放推荐标记RecommendMark(recommended,传字符串时作为标记文字)。(来源:2026-10-06 用户要求为推荐选项加标记。) - [SHOULD] 选项图标是协议或厂商的标识时,用
BrandIcon画平面 SVG:取web/src/lib/brand-logos.ts的同一份标识,有彩色版用彩色版,单色部分用 currentColor;不做像素化。(来源:2026-10-06 用户要求用标识区分接口协议。) - [SHOULD] 提交时有缺项:展开缺项所在的区域,聚焦第一个缺失字段,字段下方用
FieldError说明。 - [SHOULD] 推荐标记
RecommendMark(fp-recommend)高 18px、--radius-badge圆角、primary 文字和 10% primary 底色、text-meta500 字重,放在推荐选项的文字后、推荐设置的标题后或推荐取值下方,文字计入该项的可访问名称或取值文本;一组选项最多一个推荐标记。标记文字默认是“推荐”,需要给出理由时换成一句短句。(来源:2026-10-06 用户要求为推荐选项和推荐设置加标记,并为 API 模式写明推荐理由。) - [SHOULD] 带检查动作的输入框:右侧放 outline 按钮;检查结果写在输入框下方
role="status"的text-meta文字中,成功用 success 色。
两列证据详情
工作台里展示一组判定、核对和逐条记录的展开详情,当前实现为 TokenizerDetails。
- [SHOULD] 头部与卡片详情相同:左侧标题;右侧依次为“收起”按钮、状态徽标、更多菜单;标题下一行
text-metamuted 说明;其下为分隔线,进行中时分隔线改为march像素效果。 - [SHOULD] 正文网格 1024px 起为
minmax(0,3fr) minmax(0,2fr)两列、一个列间距;DOM 顺序为摘要块、核对块、候选列表、记录列表,前两项为第一行。1024px 以下排成一列,顺序不变,所有块左右边缘相同。 - [SHOULD] 摘要块和核对块各三行,字号相同:
text-meta标签、text-section-title主值、text-bodymuted 次行;摘要块的百分比用fp-mono右对齐。核对块的状态行左侧放 16px 语义色 lucide 图标,不用Alert框。 - [SHOULD] 候选列表和记录列表没有边框,不嵌套卡片。两者以 44px 头部行开始(左侧
text-bodyfont-medium 标题,右侧text-metamuted 数量,底部分隔线),行高 48px。候选列表复用fp-result-row;fp-custom-tokenizer-candidates在 768px 起为名称列保留 8rem。 - [SHOULD] 记录列表 1024px 起最多显示 7 行(336px),超出部分在列表内滚动,列表可以用键盘聚焦;长原文单行省略,完整原文放在
title。 - [MUST] 详情网格共享边缘和行线:上下相邻的块左边缘相同;摘要块的百分比与候选列表的百分比列右边缘相同;摘要块与核对块三行基线相同;两个列表的头部行同 y、同高,前 7 条行线同 y。检查方法:1440px 下用
getBoundingClientRect比较,误差不超过 1px。 - [SHOULD] 整行
Alert放在分隔线与网格之间,左右与卡片内容边缘对齐;操作只放在更多菜单和底部行,正文里不另放按钮。 - [SHOULD] 底部行左侧为
text-metamuted 统计,右侧为 ghost primary 小按钮;其下为整行Collapsible折叠项。折叠项里的数值表格:文本列左对齐,数值列右对齐。
数据长列表
- [SHOULD] 使用
fp-page-wide。首屏自上而下:页头行、工具行、列表;列表下方以一行text-metamuted 的数据日期与显示数量结束。 - [SHOULD] 页头行:h1 在左,
text-bodymuted 的总量在右,两者基线对齐;宽度不足时总量换到 h1 下方(flex flex-wrap items-baseline justify-between gap-3)。 - [SHOULD] 工具行是一行
flex flex-wrap items-center gap-2:288px 搜索框(w-72 max-w-full)、outline 筛选菜单按钮(文字后加ChevronDown,已选时在文字后追加“ · 数量”)、Segmented排序依次排列;导出等次要操作用ms-auto靠右,是文字前带图标的 outline 菜单按钮。控件同高 36px(h-9);宽度不足时按顺序换行。 - [SHOULD] 768px 起用
Table,放在fp-card里:表头行高 44px,数据行高 48px,单元格左右内边距 16px,数值列右对齐,次要列用 muted 文字。 - [SHOULD] 768px 以下改为
fp-card里的两层信息列表:每项是一个整块链接,最小高 56px,左右内边距 16px、上下 8px,项之间 1px 分隔线,悬停为 muted 底色,焦点为内收 2px ring 轮廓。第一层是text-bodyfont-medium 名称,第二层是text-metamuted 的次要信息,两层间隔 4px;长名称和标识符换行,不压缩字号。 - [SHOULD] 名称是真实链接;桌面上整行普通点击进入详情,键盘聚焦行时整行显示 muted 底色。
- [SHOULD] 载入时显示
blocks骨架;载入失败显示static(destructive/35)和重试按钮;没有数据和搜索无结果分别用Empty显示。
主从浏览
- [SHOULD] 1024px 起页面锁定在视口可用高度内:左侧 288px 导航列表,右侧内容,两侧分别滚动。1024px 以下导航改为横向
Tabs,页面整体滚动。 - [SHOULD] 导航列表使用虚拟滚动,只渲染可见项、预加载项和当前选中项;方向键、Home、End 切换选中项,焦点随选中项移动。
- [SHOULD] 内容区的每条记录是一张
fp-card:标题行为text-metamuted 的序号与元数据,右侧为状态徽标;原文用fp-reply原样显示;参考原文放在text-card-title的折叠项里。
长文文档
- [SHOULD] 顶栏下为 1440px 框架:1024px 起左侧为页面树侧栏(顶部是搜索框),中间为正文,1280px 起右侧为本页目录。1024px 以下页面树改为抽屉,顶栏下方 44px 的
DocsBar放目录和搜索按钮,本页目录收为可展开的条。 - [SHOULD] 页面标题用
text-h1;描述、侧栏、目录用text-body;h2 用text-section-title,h3 用text-card-title;正文段落 14px、行高 1.75,颜色为 90% 前景色;行内代码和代码块 13px 等宽。(决策:长文行高高于工具页的 1.5,只用于文档正文。来源:2026-10-01 文档站按本文件实现时确定。) - [SHOULD]
Card为 12px 圆角、1px 边框、16px 内边距、无阴影,卡片间隔 16px;图标用 muted-foreground 放在标题左侧,不放图标底板。 - [SHOULD]
Callout沿用Alert的外观:8px 圆角;info 与 idea 用 primary 图标;warn 用 warning 底色和边框;error 用 destructive;success 用 success 图标。 - [SHOULD] 代码块为 8px 圆角、细边框;Tabs 的标签栏和面板是同一张 12px 圆角卡片,面板内不再嵌套卡片。
- [SHOULD] 表格撑满正文宽度,表头为 600 字重、muted 底色;列宽之和超过正文时,表格在外层容器内横向滚动,字号不变;同一列的 th 与 td 对齐方式相同。(决策:表格保持表格布局,宽表交给外层容器滚动。来源:2026-10-02 用户指出文档表格没有撑满外框。)
- [SHOULD] 表头不换行;某列所有正文单元格都不超过 8 个汉字或 16 个拉丁字符时,整列
whitespace-nowrap。(决策:自动表格布局把剩余宽度分给最长的列,中文可在任意两字之间断行,短表头会被挤成一字一行。来源:2026-10-02 用户指出“位置”表头竖排。) - [SHOULD] Mermaid 图居中,过宽时横向滚动;渲染完成前显示 13px muted 源码。
导出图片
- [SHOULD] 用浏览器 Canvas 绘制:逻辑宽度 1200px,按 2 倍像素密度导出 PNG;使用当前语言和主题配色,等待字体加载完成后绘制。
- [MUST] 导出图片不包含凭据、请求地址和用户输入的原文。
- [MUST] 零置信度的条形宽度为零;不可用的置信度显示破折号。
链接预览图
- [MUST] 1200×630,深色主题。顶部一行:左侧品牌,右侧主机名(22px,muted-foreground)。中间垂直居中依次为分组行、标题、描述。底部为 128px 高的数字雨像素带,上边 2px border 分隔:
rain效果,每格 8px,muted-foreground/30,mask-image: linear-gradient(90deg, transparent 25%, #000 70%)向左渐隐。 - [SHOULD] 字号只用于预览图:品牌为顶栏尺寸的 1.5 倍(指纹 48px、标题 21px、署名 18px);分组行 24px、行高 1.4、muted;标题 68px、行高 1.12、600 字重、
text-balance,最多 2 行;描述 30px、行高 1.5、muted、text-pretty,最多 2 行。(决策:预览图在链接卡片里约缩小到 0.4 倍,字号需要放大。来源:2026-10-02 预览图改版时确定。) - [MUST] 限制行数的文字同时使用
line-clamp-*和text-ellipsis,截断处显示省略号。 - [MUST] 文字框离左右边缘至少 48px、离上下边缘至少 20px,文字框之间不重叠,装饰不压在文字上。检查方法:对全部预览图用 Takumi
measure()比较文字框与装饰框。 - [SHOULD] 分组行显示页面所在的上级分组,用“ / ”连接;末级分组与标题相同时不显示它;没有分组或没有描述时,不输出对应的行。
- [SHOULD] 颜色只用
fd-*类(如bg-fd-background、text-fd-muted-foreground);像素图案是对应效果减少动效时的静帧(3.7 秒、固定种子),用 currentColor 的方格绘制。
视觉规则
字体与颜色
- [SHOULD] 界面文字用
--font-sans(Geist Variable 加 CJK 系统回退);列表、表格和结论中作为条目名称的标识符也用--font-sans。fp-mono只用于输入框里的地址、标识符和密钥,命令片段,名称下方的次级原始标识符(text-metamuted),以及证据详情中逐位比较的数值。 - [MUST] 品牌标题用
--font-brand-title(Noto Serif SC Variable),署名用--font-brand-byline(Noto Sans SC Variable)。 - [SHOULD] 字号只用以下角色。例外:按钮的
sm/xs尺寸自带字号;代码片段与提示条用 13px。
| 角色 | 用途 |
|---|---|
text-display | 结论中的主名称、不可评分时的结论 |
text-display-number | 结论中的主百分比 |
text-h1 | 页面标题,每页一个 |
text-section-title | 区块标题、证据块的主值、文档 h2 |
text-card-title | 卡片标题、折叠项标题、文档 h3 |
text-body | 正文、控件、表格、列表行 |
text-meta | 计数、日期、标签、次要说明 |
- [MUST]
text-meta不承载主要操作、结论和限制说明。 - [SHOULD] 768px 以下输入框字号为 1rem,避免移动浏览器自动缩放。
- [SHOULD] 数值使用 tabular-nums(全局已开启)。
- [SHOULD] 颜色只用
web/src/tokens.css的 token,浅色与深色各一套;页面不写色值字面量。语义如下:
| token | 含义 |
|---|---|
primary | 主要操作、焦点环、当前导航、链接、置信度条 |
success | 完成、一致、可用 |
warning | 进行中、不足、需要注意 |
destructive | 失败、错误、不一致 |
muted-foreground | 次要文字、像素装饰 |
star | 只用于 Star 入口(fp-star-link、fp-repository-star),不作状态色 |
- [MUST] 置信度条只用 primary,不按候选所属的分组分配颜色。
布局与表面
- [SHOULD] 页面容器左右内边距:640px 以下 16px,640px 起 24px,1024px 起 32px;顶栏内容区相同。最大宽度 1440px。
- [SHOULD] 区块间隔 24px;卡片间隔和卡片内边距 16px;卡片内的组间隔 12px;行内元素间隔 8px。
- [SHOULD] 卡片用
--radius-card,控件、代码块和提示框用--radius,徽标用--radius-badge;边框为 1px--border。普通卡片不加阴影,只有浮层使用--shadow-overlay。 - [SHOULD] 只为真实的对象或数据集合设置表面;卡片里不再嵌套卡片,详情中的列表不加边框。
- [MUST] 页面不横向溢出:长文本先换行(标识符用
overflow-wrap:anywhere)或在自身区域内滚动,不隐藏整页溢出。 - [MUST] 全局预留滚动条空间(
scrollbar-gutter: stable),内容不随滚动条出现而横移。 - [SHOULD] 断点只用以下四个:640px(容器内边距、顶栏双行)、768px(固定操作栏、候选行两行、列表与表格切换、触控尺寸)、1024px(三列网格、文档侧栏、主从分栏、证据两列)、1280px(文档本页目录、顶栏下载进度的方格与横线切换)。文档站 Fumadocs 的
md断点设为 1024px。
控件与状态
- [SHOULD] 按钮
Button:每个操作区只有一个default(primary)主按钮,放在最右;次要操作用outline;工具栏和行内低优先级操作用ghost;危险操作用destructive。操作栏用默认尺寸(36px),行内用sm,图标按钮用icon-*。 - [SHOULD] 状态徽标:
Badge高 22px、--radius-badge、text-metafont-medium,色调取toneClass的 muted、success、warning、destructive;进行中时在文字前加旋转的 lucideLoader2。 - [MUST] 进行中的徽标和按钮用 lucide
Loader2旋转图标,不用像素 spinner。 - [SHOULD] 等待与载入:计算状态行用
scan加PixelSpinner;列表载入用blocks;尚无内容的输入区用rain;等待开始的区域背景用dither。 - [SHOULD] 已知总量的下载进度用
ProgressCells:6×6px 方格,间隔 2px,格数随宿主宽度变化,两端与宿主对齐。已下载的格用 muted-foreground,未下载的格用 22% muted-foreground,下载中的下一格按 1 秒两步闪烁到 foreground。不用 primary。它是承载数据的进度条,带role="progressbar",不属于像素装饰。(决策:方格与品牌指纹的像素颗粒一致,灰阶保持中性工具感。来源:2026-10-11 实现检测器下载进度时确定。) - [SHOULD] 空状态、未找到、无法评分:
Empty加static像素效果;载入失败时改用 destructive/35,并给出重试按钮。 - [SHOULD] 错误:字段错误用
FieldError;区块级错误用Alert variant="destructive";需要注意的整行提示用Alert variant="warning";原始错误详情放在用户主动打开的Dialog里。 - [SHOULD] 禁用:50% 不透明度、
not-allowed光标;运行中被锁定的区域整体禁用,不隐藏。 - [SHOULD] 复制、保存等即时操作用
Sonnertoast 反馈结果。 - [SHOULD] 请求读者行动的 toast 用
toastWithStar的fp-star-toast:外观与 Sonner 默认 toast 相同(popover表面、1px 边框、--radius、13px 文字,成功时标题前加CircleCheck);文字下方右对齐一行操作,依次为 muted ghostsm的拒绝、ghostsm的忽略,最右为fp-star-link[data-size="sm"]。拒绝和忽略的文案写明各自的隐藏时长(一周、一次)。读者点过 Star 入口后,同一操作只显示普通 toast;拒绝后一周内也是如此。(来源:2026-10-06 用户要求 Star 请求带忽略和拒绝按钮,并给出两者的文案。) - [SHOULD] toast 停在右下角:600px 以上右缘与 1440px 内容栏的右缘对齐(离视口右边至少等于页面左右内边距),离底边 32px;600px 及以下左右各 16px、离底边 16px。768px 以下的检测页再抬高 64px,停在固定操作栏上方。(来源:2026-10-06 用户要求 toast 离右下角留出更多距离。)
- [MUST] 每个可聚焦元素有可见的焦点样式:控件原语用 3px
ring-ring/50加border-ring;链接和其他元素用全局 2px--ringoutline、偏移 2px;第三方控件去掉 outline 时补 2px ring。可滚动区域可以用键盘聚焦。
动效
- [MUST] 弹簧参数只来自
web/src/lib/motion.ts的spring:snappy用于短控件反馈和局部高度展开;smooth用于导航容器内的位置变化和列表重排;gentle用于数值和置信度条。 - [MUST] 弹簧阻尼足够,元素不越过目标位置再回弹。
- [SHOULD] 置信度条用
scaleX做动画,不逐帧修改宽度;按钮、徽标和 Tabs 不用transition-all。 - [SHOULD] 工具页之间切换用原生 View Transition 横向平移 300ms:前进向左,返回向右,顶栏不动;切换后回到顶部;浏览器不支持时直接切换。
- [SHOULD] 列表首批最多 8 项,每项错开 60ms(
listStagger、listItem);展开的后续项不错开。 - [SHOULD] 卡片和它的详情不共享
layoutId,详情只在原位做高度展开。 - [SHOULD] 卡片里的参考原文被替换时,卡片按位置保留,原文在原位用
smooth交叉淡入:旧文字上移 8px、模糊 4px 后淡出,新文字从下方 8px、模糊 4px 进入;多张卡片按顺序错开 60ms。触发替换的按钮图标每次用smooth转半圈。(来源:2026-10-06 用户要求替换提示词时加过渡动画。) - [SHOULD] 流式文本不做逐字动画,末尾用
fp-caret闪烁光标。 - [SHOULD] 成功确认的庆祝效果:从视口左下角和右下角同时向中间喷出一次彩带,每侧 220 片、扩散角 32°,主体射程为视口宽度的 75%;同一结果只播放一次。
- [MUST] 减少动效时:取消错开与位移,数值直接显示目标值,浮层、加载和 CSS 过渡立即完成,像素装饰只画一帧,不播放庆祝效果。
- [MUST] 动效不阻挡取消、输入和键盘导航。
像素装饰
- [MUST] 只用
PixelShader和PixelSpinner;全站共享web/src/lib/pixel-renderer.ts的一个 WebGL 上下文,不为单个装饰新建上下文。 - [SHOULD] 宿主元素决定尺寸,画布按
cell整格放大,image-rendering: pixelated。 - [MUST] 颜色取宿主的 currentColor(含透明度),按下表使用 muted-foreground 及其透明度,不用蓝色或黄色粒子。例外:主按钮内的 spinner 跟随按钮文字色;载入失败用 destructive/35。
- [MUST] 装饰设
aria-hidden,不接收指针事件,不承载数据含义;背景装饰放在isolate容器的-z-10层,不遮挡文字。 - [MUST] 只绘制进入视口的装饰,最高 24fps,时间按 0.5 倍速推进(
PLAYBACK_RATE);不支持 WebGL 时保持透明。
| 效果 | 使用位置 | 颜色 |
|---|---|---|
fingerprint | 品牌标识,2px 格;预览图品牌标识的静帧 | muted-foreground |
rain | 提示条背景(向左渐隐);尚无内容的输入区;预览图底部像素带的静帧 | muted-foreground/30 |
dither | 等待开始的区域背景 | muted-foreground/20 |
march | 进行中卡片标题下的分隔线 | muted-foreground/60 |
scan | 计算状态行 | muted-foreground/60 |
spinner | 计算中的主按钮、计算状态行、详情载入 | currentColor |
blocks | 列表与详情的载入骨架 | muted-foreground/25 |
logo | 结论名称旁的品牌像素标识 | 品牌色;单色部分用 foreground |
static | 空状态、未找到、无法评分、载入失败 | muted-foreground/40–45;失败用 destructive/35 |
- [MUST]
logo效果画成像素画:24×24 网格,覆盖过半的格子画成实心像素并沿用品牌色,无抗锯齿,轮廓压暗,右下方一格半透明黑色阴影。黑色或白色的单色标识用 currentColor,随主题重绘。宽屏 72px,放在名称右侧;窄屏 48px,放在标签上方。web/src/lib/brand-logos.ts没有对应 SVG 时不显示。
可用原语
| 角色 | 实现名称 | 路径 | 使用条件 | 状态 |
|---|---|---|---|---|
| 颜色与主题 | background foreground card popover primary secondary muted muted-foreground accent border input ring success warning destructive star | web/src/tokens.css、web/src/index.css | 所有颜色 | 已实现 |
| 圆角与阴影 | --radius --radius-card --radius-badge --shadow-overlay | web/src/tokens.css | 控件、卡片、徽标、浮层 | 已实现 |
| 字号角色 | text-display text-display-number text-h1 text-section-title text-card-title text-body text-meta | web/src/tokens.css | 所有文字 | 已实现 |
| 应用外壳 | fp-topbar fp-topbar-inner fp-topbar-start fp-topbar-actions fp-brand fp-brand-mark fp-brand-text fp-brand-title fp-brand-byline fp-nav fp-nav-indicator fp-repository-link fp-repository-star;--fp-topbar-height | web/src/shell.css | 工具页和文档页顶栏 | 已实现 |
| 页面容器 | fp-shell fp-page fp-page-wide fp-footer | web/src/index.css | 工具页 | 已实现 |
| 工作台布局 | fp-grid-samples fp-detect-footer fp-actionbar fp-cli-promo fp-cli-command fp-cli-link fp-star-link(data-size="sm") | web/src/index.css | 多卡片工作台 | 已实现 |
| 表面与数据 | fp-card(data-warning) fp-bar fp-reply fp-mono fp-caret fp-api-summary fp-result-summary fp-result-score fp-result-row(data-unscored) | web/src/index.css | 卡片、置信度条、原文、标识符、候选行 | 已实现 |
| 控件 | Button Input Textarea Field FieldError Switch ToggleGroup Segmented(选项 icon recommended) Tabs Collapsible | web/src/components/ui/、web/src/components/segmented.tsx | 表单与操作 | 已实现 |
| 品牌标识 | BrandIcon | web/src/components/brand-icon.tsx | Segmented 选项 | 已实现 |
| 浮层 | Dialog DropdownMenu Tooltip Sonner toastWithStar(fp-star-toast) | web/src/components/ui/、web/src/components/star-prompt.tsx | 详情、菜单、提示、toast | 已实现 |
| 数据反馈 | Table Badge Empty Skeleton Alert(default warning destructive) Separator | web/src/components/ui/ | 表格、状态、空状态、警告 | 已实现 |
| 工作台组件 | SampleCard SampleStrip StateBadge toneClass ResultPanel ConfidenceBar AnimatedPercent ApiConfigPanel ProxySettings | web/src/components/ | 多卡片工作台 | 已实现 |
| 证据详情 | TokenizerCard TokenizerStripButton TokenizerDetails ModelCheck;fp-custom-tokenizer-candidates | web/src/components/tokenizer-panel.tsx、web/src/components/tokenizer-claim.tsx、web/src/index.css | 两列证据详情 | 已实现 |
| 动效 | spring useMotionPreset listStagger listItem | web/src/lib/motion.ts | 所有动画 | 已实现 |
| 推荐标记 | RecommendMark(fp-recommend) | web/src/components/recommend-mark.tsx、web/src/index.css | 推荐选项、推荐设置、推荐取值 | 已实现 |
| 下载进度 | DetectorProgress ProgressCells(value active label) downloadFraction downloadBytes;fp-progress-cells fp-detector-progress | web/src/components/detector-progress.tsx、web/src/index.css | 顶栏检测器下载、计算等待下载 | 已实现 |
| 像素装饰 | PixelShader(effect cell image) PixelSpinner fp-pixel | web/src/components/pixel-shader.tsx、web/src/lib/pixel-effects.ts、web/src/lib/pixel-renderer.ts、web/src/shell.css | 品牌、加载、等待、空状态 | 已实现 |
| 文档组件 | SiteHeader DocsBar Card Callout Mermaid TokenizerClasses | docs/app/components/ | 文档站 | 已实现 |
| 预览图 | OgImage ogResponse ogRenderer ogFontFamilies | docs/app/lib/og-image.tsx、docs/app/lib/og-response.ts、docs/app/lib/og.server.ts | 链接预览图 | 已实现 |
| 图标 | lucide-react | web/package.json、docs/package.json | 所有图标 | 已实现 |
- [MUST] 公开原语是本表列出的 token、类、组件和 prop;页面只使用这些名称,使用前确认 API 存在,不猜测未列出的名称。
- [SHOULD] 页面专用样式使用
fp-custom-*名称,可以使用 Tailwind 的布局和间距工具。(决策:区分共享原语与页面例外,保留 shadcn 的组合方式。来源:项目初版设计决策。) - [MUST] 页面专用样式只调整位置、尺寸和间距,不改变已发布原语的字号、边框、圆角和表面;新的跨页面视觉变体先加入共享组件或类。
背景装饰需要 isolate 容器:
<div className="relative isolate overflow-hidden rounded-xl border">
<PixelShader effect="dither" className="absolute inset-0 -z-10 text-muted-foreground/20" />
<p className="text-body">等待开始</p>
</div>整行警告带图标与可选操作:
<Alert variant="warning" className="p-4">
<TriangleAlert aria-hidden="true" />
<AlertTitle>标题</AlertTitle>
<AlertDescription>说明</AlertDescription>
</Alert>文案与数字格式
- [MUST] 界面文案按读者选择的语言显示;用户输入的文本、生成的文本、标识符和原始记录保持原文,不翻译。
- [SHOULD] 标题用名词短语;按钮用动词开头的短语;说明文字用一句话写条件或后果,不重复标题。
- [SHOULD] 第三方协议和 API 名称使用官方写法。
- [MUST] 结果文案只复述数据给出的结论、排名和限制说明,不补写解释、原因或数据之外的阈值判断;排名不写成身份确认。
- [MUST] 错误提示用读者能操作的语言列出可能的原因和检查项,不断言单一原因;原始错误详情只在用户打开的对话框里显示。
- [MUST] 界面、导出图片、错误详情和日志不显示密钥和 Authorization 值;原始详情先脱敏。
- [MUST] 缺失的日期、来源和原文写明缺失,不补造;记录里不存在的元数据项不显示占位值。
- [SHOULD] 百分比保留一位小数,按读者语言格式化(i18n 的
percent);计数使用读者语言的千位分隔(number);日期显示为年、月、日,月和日补足两位(date)。 - [SHOULD] 单行省略的长值(标识符、地址、原文)把完整值放在
title中。
反模式
- [SHOULD] 不默认采用居中宣传标题加卡片网格的页面结构。
- [SHOULD] 不在卡片里嵌套卡片。
- [SHOULD] 不放装饰性图标底板或彩色图标背景;
EmptyMedia只放像素装饰。 - [SHOULD] 不使用原语之外的字号、字重或色值字面量。
- [SHOULD] 主要信息不用小号、低对比度的文字。
- [SHOULD] 普通元数据不用胶囊徽标;徽标只表示状态。
- [SHOULD] 不使用渐变;预览图像素带的渐隐遮罩除外。
- [MUST] 不用蓝色或黄色像素粒子装饰非强调区域。
- [MUST] 不把未知或不可用的数值显示为 0。
- [MUST] 不把推断性的结论写成确认。
实现与接入
- [MUST] 颜色 token、字号角色和品牌字体只在
web/src/tokens.css定义;顶栏外壳类和像素装饰宿主.fp-pixel只在web/src/shell.css定义。检测站由web/src/index.css在@import "tailwindcss"之后导入两者;文档站由docs/app/app.css直接导入两者,再由 Fumadocs 的shadcn.css把颜色映射为fd-*。修改 token 或外壳类时同时检查两处和预览图。 - [SHOULD] 预览图由
docs/app/lib/og-response.ts把web/src/tokens.css和 Fumadocs 的shadcn.css原文交给 Takumi;docs/app/lib/og.server.ts用 tokens.css 中的族名注册 Geist Variable、Noto Sans SC Variable 和 Noto Serif SC Variable 的 Latin 子集,没有指定字体的文字按 Geist、Noto Sans SC 回退(Takumi 不读系统字体)。 - [SHOULD] 字体加载:Geist 来自
@fontsource-variable/geist;品牌字体在web/src/tokens.css用@font-face引用@fontsource-variable/noto-serif-sc与@fontsource-variable/noto-sans-sc的 Latin WOFF2,随站点构建加载。 - [MUST] 主题由 next-themes 在
html上切换dark类;web/index.html在页面加载前读取偏好,避免闪烁。偏好保存在fp-theme,文档站通过 Fumadocs RootProvider 的storageKey使用同一个键,两站的主题选择互相同步。存储不可用时按系统外观显示;原生控件和滚动条使用当前主题的 color-scheme。 - [SHOULD] 组件来自 shadcn 的 base-nova(Base UI),位于
web/src/components/ui/;动画使用 framer-motion;图标使用 lucide-react。不切换到另一套组件系统。 - [SHOULD] 文档站的 MDX 组件映射在
docs/app/components/mdx.tsx。Markdown 表格使用 Fumadocs 的滚动外层,表头与短列由docs/app/lib/remark-label-columns.ts标记为不换行;由数据生成的表格使用同一个外层,表头同样不换行。文档顶栏通过相对路径导入web/src/components/pixel-shader.tsx,只在浏览器中懒加载。 - [SHOULD] 公式样式来自
katex/dist/katex.css;docs/package.json中katex的版本与 rehype-katex 依赖的版本保持一致,否则公式失去排版规则。
词汇表
| 概念 | 名称 |
|---|---|
| 工具页和文档页共用的顶部条 | 顶栏 fp-topbar |
| 顶栏左侧的像素指纹与两行文字 | 品牌标识 fp-brand |
| 一次处理多份同类输入并给出结论的页面类型 | 多卡片工作台 |
| 工作台里的一份输入及其参考原文 | 输入卡片 SampleCard |
| 结果状态下收起的卡片行 | 摘要条 SampleStrip |
| 页头下方一行的命令与入口 | 提示条 fp-cli-promo |
| 页面末尾的主次操作 | 操作栏 fp-actionbar |
| 结论卡片与候选列表 | 结果区 ResultPanel |
| 候选列表中的一行 | 候选行 fp-result-row |
| 表示匹配程度的横条 | 置信度条 ConfidenceBar |
| 收起为一行摘要的表单卡片 | 配置卡片 ApiConfigPanel |
| 判定、核对和逐条记录的展开详情 | 两列证据详情 TokenizerDetails |
| 表格或两层列表形式的数据页 | 数据长列表 |
| 左侧导航、右侧内容的页面类型 | 主从浏览 |
| 侧栏、正文、本页目录组成的页面类型 | 长文文档 |
| 浏览器生成的结果 PNG | 导出图片 |
| 文档构建生成的 Open Graph 图片 | 链接预览图 OgImage |
| GLSL 像素动画 | 像素装饰 PixelShader |
| 表示状态的小标签 | 状态徽标 Badge、StateBadge |
待定事项
- [UNCONFIRMED] 数据记录卡片和主从浏览的分组小标题使用 h2 语义,但视觉为
text-meta;区块标题的语义层级与视觉层级是否应一致,尚未确认。(来源:2026-10-02 测量记录,主从浏览页“Closest fingerprints”与记录卡片标题。) - [UNCONFIRMED] 768px 以下,32px 高的输入框行高为 22.857px,其他输入框为 24px;高度与行高是否应统一,尚未确认。(来源:2026-10-02 测量记录,配置卡片在 390px 宽度下。)
最后更新于