跳到主要内容

2026-08-21

页面变体

给同一条页面 URL 声明几种成品渲染,在现有的 ?review=1 HUD 上比较,并把访客分流和写作期挑选分开。

一个页面目录可以在 default layout 旁边放下兄弟版本。同一条 canonical URL。每个版本都是完整的服务端 HTML,在 arc blocklet build / prerender 时生成。

本页是操作合同,2026-08-21 对照 Web Device 在 arc#4548(token delta)和 arc#4557(Split + Select 理由)之后的实现核验。不是设计随笔;动机见介绍文章。

页面内评审是另一项能力,只是共用 HUD。不要把本页当成页面内评审模式的改写。评审把意见写在内容旁(.review/)。变体是在成品渲染里挑选(.experiment/selection.json 加上 variants/ 树)。

什么时候用

适合:

  • agent(或人)能在一轮里为同一条路由做出不止一个成品版本;
  • 需要在渲染后的页面上看这些版本,包括并排,再决定访客看不看得到;
  • 随后想用同一棵树做 cookie 分流。

不要用来:

  • 第二套评审浮层、?experiment=1 模式、或客户端 theme 切换;
  • 单篇文章 / 单篇文档的备选(collection item URL 不是变体页);
  • 单个 slot 或单句实验(这一波没有);
  • 指标或显著性产品(不在范围里)。

怎么声明

只有 pages/<name>/ 会生长变体。control layout 必须存在。

text
pages/index/layout.aup                 # default / control(必须)
pages/index/variants/aurora/layout.aup # 种类 2:整份 layout 树
pages/index/variants/quiet/tokens.json # 种类 1:只改值,继承 default layout
pages/index/variants/_config           # 可选:split= / seed=

种类差什么放进 variants/<name>/继承什么
1 值token / 具体 CSS 变量只有 tokens.jsondefault 的 layout 树
2 结构hero、区块顺序、widget完整 layout.aup 或 layout.json不继承 control 的 layout

声明了目录却既没有 layout 也没有合法 tokens.json,是构建失败。种类 2 若同目录里还有 tokens.json,这一波会忽略它;不要混放还指望 token 生效。

_config 一行一个 key=value。格式坏了是构建失败,不是跳过:

text
split=100,0,0
seed=homepage-choose-2026

split 权重和 [default, ...目录名(列举顺序)] 对齐,必须加总为 100。省略 _config(或省略 split)则在所有已声明版本上均分。

要让访客先都停在 default、多出来的版本只给写作期用:第一个权重 100,其余 0。改 seed 会重排每一个访客。

Agent 配方:一轮,几个版本

agent 应该产出这个形状。不要另发明一套 API。

  1. 先读现有的 pages/<name>/layout.aup(以及它已经绑定的 i18n / sources)。
  2. 分清备选是值还是结构。值 → 只写 tokens.json。结构 → 完整 layout 文件。不要为了改 --accent 整份拷 layout。
  3. 每个备选写进 pages/<name>/variants/<name>/,和 control 同一轮交出来,人只要开一次 review。
  4. 写 _config。访客还不能进实验:split=100,0,0(0 的个数等于非 default 名字数)。
  5. 对站点跑 arc dsl lint / validate / blocklet check。坏的 split 或空变体目录在这里红,不要等到请求期。
  6. 打开渲染页,加 ?review=1。用 Split 比较,用 Select 记下赢家。

目录名必须是普通名字(aurora、b、quiet)。.、..、含 / 的名字会被拒。

/zh/articles/<slug>/ 这类 collection 路由不会长出切换条。实验挂在 pages/index/(或别的 pages/<name>/),不要挂在一篇 markdown 旁边。

在评审 HUD 上比较和选定

注入条件仍然只是 ?review=1(值必须是 1)。没有 ?experiment=1。内层 iframe 走 ?embed=1,所以不会再套一层 HUD。

页面列出至少两个名字(含 default)时:

控件做什么
版本按钮location.assign 同一路径,带 review=1 和 variant=<name>
Splitreview=1&split=1。最多四个 iframe,按声明顺序
格子标题 / chrome退出 split:review=1&variant=<该名>,没有 split
SelectPOST 到 <page>/.experiment/.actions/select,body { selected, reason }

reason 是同一层 HUD 里当前的 Page note。空或省略仍然成功,并且不写这个键。最长 8192。

?variant= 压过访客 cookie,不写 cookie,并且强制 noindex。未知名字回落到 default,不是 404。

首页评审 HUD,带版本条

本站 /zh/?review=1 · 2026-08-21。截取来自 arc#4557 之后的本地 Web Device handler,不是已发布的 CLI 标签。

首页 Split 格子

同一路由上的 ?review=1&split=1。内层没有 HUD。每格按 1280px 桌面宽度布局再缩进格子,所以只在桌面跑的 WebGL hero 仍会画。

匿名 cms-write 调 Select 仍是带原因的 401。Select 从不改写 layout 源文件;记录落在页面旁的 .experiment/selection.json。

访客分配、爬虫、SEO

生产 HTML 按版本静态。被分到某桶的访客拿到的是那一版预渲染文档。输出里不带切换实验的 JavaScript。

角色拿到什么
首次到访的浏览器用 (seed, visitorId) 哈希进桶;种 arc_variant_id cookie
同一访客再来同一桶,直到 seed 改变
可识别的爬虫 UA永远 default,不种 cookie
?variant=(评审 / QA)该名字,noindex,不写 cookie

canonical、sitemap、hreflang 仍指向那一条 URL。给爬虫非 default 版本就是 cloaking。

改 variants/ 或 _config 需要重新构建。没有运行时改配置,没有按地区/设备定向,也没有显著性看板。

限制

主题当前合同
开启标志只有 ?review=1 注入 HUD;单凭 ?split=1 什么都不做
第二套浮层没有;没有 data-arc-experiment 脚本
种类 3(一个 slot / 一句)未实现;用整页 split
种类 2 同目录再放 tokens这一波忽略 tokens
Split 容量最多四个 iframe,声明顺序的前几个名字
Split 格子视口每个 iframe 按 1280×800 CSS px 布局再缩进格子(格子里的 matchMedia(max-width: 760px) 为 false)
Collection item不是变体页
指标不在范围
发布快照.experiment/ 是写作期记录;不要教成公开 widget

检查

bash
arc --version
arc dsl lint blocklets/arcblock
arc dsl validate blocklets/arcblock
arc blocklet check blocklets/arcblock

然后打开本地打印出的 URL:

text
http://<host>:<port>/zh/?review=1
http://<host>:<port>/zh/?review=1&split=1
http://<host>:<port>/zh/?review=1&variant=aurora

确认:首页有版本条;Split 能看出不同的成品 hero;内层 iframe 没有 HUD;没有 variants/ 的页面仍有评审 HUD,但没有版本条。