feat(design): M70 默认色候选 —— 浅冷天蓝落成两行常量 + 三档候选色卡

默认色从官方紫 `#6750A4` 换成「浅冷天蓝」,并把「换默认只改哪一行」做成常量:
- `palettes::DEFAULT_SEED` = `#87CEEB`(CSS skyblue)+ `palettes::DEFAULT_NEUTRAL_CHROMA` = 12
- `Palettes::baseline()` / `Scheme::baseline()` = 产品默认(消费方拿到的就是它)
- 官方口径锚点独立保留:`Palettes::official_baseline()` / `Scheme::official_baseline()`
  (种子 `#6750A4` + 中性 6),官方对齐测试改指向它,98 项仍每通道误差 0
- 新增 `Palettes::from_seed_with_neutral_chroma(seed, neutral_chroma)`:中性彩度从写死
  常数变成入参(neutral-variant 按官方 +2 跟随),算法、tone 表、gamut 映射一行未动

有意偏离登记(已写进 color 模块文档):中性彩度 6 → 12 是对官方 Tonal Spot 的偏离,
理由=产品要冷调表面;primary 的 tone 被官方钉在 40,种子再浅也变不成浅蓝,
「浅」只能落在中性色上。

三档候选(同一条 HCT 管道,只差种子与中性彩度)逐个 pin 在 tests/skyseed_candidates.rs:
① 保守蓝 `#2196F3`/6、② 冷调蓝 `#2196F3`/12、③ 浅冷蓝 `#87CEEB`/12(临时默认,待用户确认)。
WCAG AA 扩到候选档:26 组 × 3 档 × 2 模式 = 156 项全绿,最紧 4.99:1。
This commit is contained in:
AskaEth committed 2026-11-01 18:09:12 +08:00
1 parent c20c742b60
commit 79404fa9d1
6 files changed
+476 -34

No files matched your search

+55
View File
@@ -157,6 +157,61 @@ fn baseline_light_and_dark_both_pass() {
}
}
#[test]
fn sky_seed_candidates_meet_wcag_aa() {
// M70:三档默认色候选(种子 + 中性彩度)必须过同一条 26 组门禁。
// 中性彩度改变只影响色相/彩度,不影响 tone 轴,所以理论上恒过——这里就是要**证明**它恒过,
// 而不是相信它。任何一档不达标,该档直接判为不可用(不许为了好看放宽阈值)。
let candidates = [
("① 保守蓝", "#2196F3", 6.0_f64),
("② 冷调蓝", "#2196F3", 12.0),
("③ 浅冷蓝", "#87CEEB", 12.0),
];
let mut failures = Vec::new();
let mut worst = (f32::MAX, String::new());
let mut checked = 0;
for (title, seed_hex, neutral_chroma) in candidates {
let seed = Color::from_hex(seed_hex).expect("候选种子");
let palettes =
unlucky_design::color::Palettes::from_seed_with_neutral_chroma(seed, neutral_chroma);
for flavor in [SchemeFlavor::Light, SchemeFlavor::Dark] {
let scheme = Scheme::from_palettes(&palettes, flavor);
for (fg, bg) in TEXT_PAIRS {
let ratio = scheme.contrast(fg, bg);
checked += 1;
if ratio < worst.0 {
worst = (
ratio,
format!(
"{title}/{} 的 {} on {}",
flavor.name(),
fg.name(),
bg.name()
),
);
}
if ratio < AA_TEXT {
failures.push(format!(
"{title}({seed_hex} / 中性 {neutral_chroma})/ {} / {} on {} = {ratio:.2}",
flavor.name(),
fg.name(),
bg.name()
));
}
}
}
}
println!(
"候选 WCAG:{checked} 项,最紧的一对 {} = {:.2}:1(阈值 {AA_TEXT})",
worst.1, worst.0
);
assert!(
failures.is_empty(),
"以下候选未达 WCAG AA(4.5:1),该档不可用:\n{}",
failures.join("\n")
);
}
#[test]
fn accent_override_cannot_break_contrast() {
// 换了强调色之后,primary 族仍必须过 AA——这是「tone 轴固定」带来的结构性保证。