原来的生成器只能配「背景 + 人物 + 道具」三件套,预览还是自己画的仿制页面 —— 跟真实页面不像,也没法给不同页面配不同内容。 机制层: - internal/context.pageScope() 按路径归类,输出 <html data-page-scope>: box / question / admin / profile / vote(首页与 /explore 不加载主题,不列) - /user/questions 单独归为 admin:题目列表信息密,和设置表单的装饰诉求不同 - base.css 装饰槽位 6 -> 10,背景 8 层 -> 12 层;主题按作用域覆盖时同样写满 10 个 - 新增 TestDecoSlotCount:逐文件逐声明检查 10 个值。少写一个不报错, 只会让图层与 size/position 错位(整页重复同一张图 / 人物跑到左上角),注释守不住 生成器: - 画板改成 iframe 加载 outputs/preview-*.html(真实模板渲染),配 serve.py 起本地服务 解决 file:// 下父页面读不到 iframe DOM 的问题 - 八个页面作用域(去掉不生效的首页/探索),每个可独立配背景与最多 10 层装饰 - 图层类型:图片 / 径向光斑 / 线性光;9 宫格锚点 + 像素偏移,可在画板上直接拖 - 位置统一写 calc(0%|50%|100% ± Npx):百分比是相对 (容器-图片), 不用 left/bottom 关键字混搭,避免三值语法非法导致整条声明作废 - 配色只填 6 个基础色,其余 4 个必需令牌按方向派生(surface-2 往 text 靠, 浅色变深、深色变亮,方向自动正确) 配套: - zz_preview_test.go 增加单题页 / 题目列表 / 投票页预览,作为生成器画板 - docs/theme-page-scope.md 记录作用域取值、选择器特异性与 10 槽位约束 - StaticVersion 20261020e(base.css 变了) 验证:生成器导出的 CSS 通过 TestThemeCSSComplete + TestDecoSlotCount; 真实箱主页计算样式为 12 层对齐;临时主题验证「question 覆盖为 none」生效、 未覆盖时回退全局。
216 lines
12 KiB
Markdown
216 lines
12 KiB
Markdown
# 主题「砂狼白子」(shiroko)
|
||
|
||
阿拜多斯学园风格的灰蓝/银白配色,附带 Q 版人物插画。启用方式:
|
||
|
||
```ini
|
||
[theme]
|
||
available = default,sakura,shiroko
|
||
```
|
||
|
||
箱主在「账号设置 → 主题外观」里选择即可。作用范围与其他主题一致:提问箱页面、本人投票页、`/user` 后台。
|
||
|
||
## 配色
|
||
|
||
| 令牌 | 浅色 | 深色 |
|
||
| --- | --- | --- |
|
||
| `--tb-bg` / `--tb-navbar` | `#edf2f8` | `#141a22` |
|
||
| `--tb-surface` | `#ffffff` | `#1d2530` |
|
||
| `--tb-surface-2` | `#e5ecf5` | `#273140` |
|
||
| `--tb-border` | `#d6e0ec` | `#334052` |
|
||
| `--tb-text` | `#222d3b` | `#e3eaf4` |
|
||
| `--tb-primary` | `#4a7fc1` | `#6fa3e0` |
|
||
|
||
## 视觉构图
|
||
|
||
参考对象:**蔚蓝档案 JP 官网首页**(`https://bluearchive.jp/`)。它的做法不是"白底 + 留白里贴几个人物",
|
||
而是 **整个视口是一张场景插画,UI 浮在场景之上**。本主题照这个结构重排:
|
||
|
||
| 层 | 内容 | 实现 |
|
||
| --- | --- | --- |
|
||
| 底层 | 教室场景插画(压白 38%、轻度虚化) | `--tb-page-image`,16:9 桌面 / 9:16 移动两张 |
|
||
| 中层 | 卡片与顶栏:半透明白 + `backdrop-filter` 磨砂 | `--tb-surface: rgba(255,255,255,.86)` / `--tb-navbar` |
|
||
| 上层 | 人物站在场景左侧地面(400px 高)+ 椭圆接触阴影 | `--tb-deco` 前两个槽位 |
|
||
| 道具 | 她的自行车(车头朝右、与人同向)斜靠一把步枪 | `--tb-deco` 第 3 槽位 |
|
||
| 空气层 | 左窗光柱 / 右侧暖散景 / 脚下地面光斑 / 底部压深 | `--tb-deco` 第 4~7 槽位(全是渐变) |
|
||
|
||
> 装饰层共 10 个槽位(见 `internal/theme/slots_test.go`),本主题用前 7 个,其余留空。
|
||
> 想给某一页换装饰(例如问题页让人物退场),见 [theme-page-scope.md](theme-page-scope.md)。
|
||
| 深色 | 不用场景(白天教室压在深底上会脏),回到深色渐变 + 极淡纹样 | 深色块单独覆盖 |
|
||
|
||
摆位经验(都是踩过的):
|
||
|
||
- **不要四角各摆一个人**。人物之间、人物与内容之间都没有关系,读起来就是贴纸墙纸;
|
||
人物必须"站在场景里"——有地面、有阴影、有环境,才不像贴纸。
|
||
- **右下角不能放人**。页脚文案右对齐(社区规则 / 备案号 / 存活时长),会和人物挤在一起。
|
||
- **离底边留 36px**。脚踩在窗口最后一行像素上会被读成"被裁切",抬高之后必须配接触阴影,否则变成悬空。
|
||
- **纹样不要压在实景上**。平铺纹样叠在教室插画上会变成噪点,只在深色(无场景)时使用。
|
||
- **背景图会被 `cover` 裁切**,所以场景里不能有必须完整露出的元素:教室的黑板和窗户都在中部,裁掉两头不影响。
|
||
- **人物比例要跟场景对得上**。400px 是相对"站在前景"的尺度;缩到 240px 以下会显得像贴纸浮在半空。
|
||
|
||
### 空气层(2026-10-20 加)
|
||
|
||
场景压白 38% 之后整页亮度都在 235~246 之间,"再加点东西"直接摆物件一定会突兀。加了四层**纯渐变**:
|
||
|
||
| 槽位 | 作用 | 值 |
|
||
| --- | --- | --- |
|
||
| 3 | 左窗光柱(从左上斜下) | `linear-gradient(112deg, rgba(255,250,236,.50), transparent 44%)` |
|
||
| 4 | 右侧一朵暖散景(有体积感) | `radial-gradient(circle 120px at 88% 30%, rgba(255,252,240,.42), transparent 75%)` |
|
||
| 5 | 人物脚下的地面光斑(把她"钉"在地上) | `radial-gradient(ellipse 560px 170px at 28% 94%, rgba(255,248,228,.80), transparent 72%)` |
|
||
| 6 | 底部轻压深(下沿不飘) | `linear-gradient(0deg, rgba(110,128,156,.10), transparent 24%)` |
|
||
|
||
经验:
|
||
|
||
- 亮度差 **3~9 级**刚好能看出"有光"又不像打了聚光灯;超过 15 级就会读成一块脏。
|
||
- 白色散景压在已经压白的场景上等于没做(实测差异 0.14 级,肉眼不可见)——**要提亮就得先有暗部**,
|
||
所以真正起作用的是"压深 + 暖色光斑"的组合,不是加白。
|
||
- 所有槽位必须是单张图,**不能在一个槽位里塞逗号列表**(会让层数与 size/position 错位)。
|
||
- 8bit 渐变要检查阶梯:横向扫描线的相邻像素差应 ≤2~3;本次实测 max 4,无可见色阶。
|
||
|
||
> 尺寸 / 比例 / 雾度等可直接拿去外部工具复用的参数,见 [theme-shiroko-assets-spec.md](theme-shiroko-assets-spec.md)。
|
||
|
||
## 素材清单
|
||
|
||
位于 `static/images/themes/shiroko/`,已随二进制嵌入(`static/fs.go` 的 `images/themes`)。
|
||
|
||
| 文件 | 用途 | 尺寸 | 体积 |
|
||
| --- | --- | --- | --- |
|
||
| `chibi/window.webp` | **当前使用**:侧后方视角、双手背在身后望向箱内,压白 16% | 135×460 | 13KB |
|
||
| `props/bike.webp` | 自行车 + 步枪(镜像后车头朝右),压白 26%,自带接触阴影 | 397×259 | 22KB |
|
||
| `chibi/wave.webp` | 备用:正面挥手 | 324×620 | 27KB |
|
||
| `chibi/cheer.webp` | 双手欢呼 | 354×620 | 27KB |
|
||
| `chibi/think.webp` | 托腮 | 283×620 | 26KB |
|
||
| `chibi/doze.webp` | 打瞌睡 | 274×620 | 26KB |
|
||
| `scene-desktop.webp` | 教室场景(16:9,前景是空地,便于人物站立) | 1920×1080 | 19KB |
|
||
| `scene-mobile.webp` | 同一张场景的竖版裁切 | 720×1003 | 10KB |
|
||
| `pattern-dark.svg` | 深色模式平铺纹样(雪花 + 光环) | 240×240 | 0.7KB |
|
||
|
||
## 来源与授权
|
||
|
||
| 素材 | 来源 |
|
||
| --- | --- |
|
||
| `static/images/shiroko-cutout.png` | **用户自行用 AI 生成**的立绘,仅作生成参考图,不再上页面 |
|
||
| `chibi/window.webp` | WorkBuddy ImageGen 生成(文生图 → image-to-image 转平涂),再抠白底 |
|
||
| `chibi/wave.webp` 等 | WorkBuddy ImageGen **以用户立绘为参考图**(image-to-image)生成,再抠白底 |
|
||
| `scene-desktop.webp` / `scene-mobile.webp` | WorkBuddy ImageGen 生成(提示词见下),未使用任何外部素材 |
|
||
| `pattern-dark.svg` | 手写 SVG,纯几何,无外部素材 |
|
||
|
||
### 生成与抠图参数
|
||
|
||
- 参考图:`static/images/shiroko-cutout.png`,`input_fidelity: high`,保证角色造型与平涂风格一致;
|
||
- 提示词骨架(四个姿态共用,只改动作句):
|
||
|
||
> Same character, same art style as the reference image: flat vector illustration, no outlines,
|
||
> simple shapes, soft pastel colors, minimal detail. A chibi anime girl with short fluffy
|
||
> silver-grey bob hair, pointed grey wolf ears, a small tilted cyan halo ring above her head,
|
||
> pale blue dot eyes, cyan scarf, dark navy blazer, light grey pleated skirt, cyan and black
|
||
> sneakers. { 动作 } Plain pure white background (#FFFFFF), no shadow, no ground, no text, no watermark.
|
||
|
||
- 动作句:`Standing full body, front view, one arm raised waving hello with a small smile` /
|
||
`both arms raised up cheering happily, big smile` /
|
||
`one hand resting on her cheek thinking, head slightly tilted` /
|
||
`eyes closed sleeping peacefully, head drooping slightly to one side`;
|
||
- 抠图:从四角 + 四边中点共 8 点做 floodfill(容差 16),再对 alpha 做 1px MinFilter 收边去白边,
|
||
裁 bbox 后统一缩放到高 620、WebP q90。
|
||
|
||
### 当前人像(window.webp)的两步做法
|
||
|
||
正面立绘站在空教室里像贴纸(无环境、直视访客、饱和度高)。改成**侧后方视角 + 二次转平涂**:
|
||
|
||
1. 文生图先出姿势与角色:`flat vector chibi, three-quarter back view, hands clasped behind back,
|
||
short silver-grey bob, grey wolf ears, pale aqua fish-shaped halo, teal scarf, navy blazer,
|
||
grey pleated skirt, black and teal sneakers`(第一版带了教室窗框,背景处理不掉);
|
||
2. 再把这张图扔回 image-to-image(`input_fidelity: high`)转成"纯色块、无描边、去掉窗框与场景,
|
||
纯白背景",这样既保住姿势,又能拿到和立绘一致的平涂风格;
|
||
3. 光环单独重画:AI 给的光环不但形状歪,环内还是一块**封闭的白孔**——floodfill 只从四边漫水,
|
||
闭合区域进水不进去,抠完就是"环里糊着一团白"。做法是先把这个连通域(非白像素从环上一点漫水,
|
||
bbox 291,93–584,232,与头发不连通)整块抹白,抠完 alpha 后再用 PIL 画一个 -7° 倾斜的椭圆环
|
||
(4 倍超采样 + LANCZOS 缩小求平滑 + 一层 45% 的模糊柔光),环心天然是透明的;
|
||
4. 抠白底后把 RGB 压白 **16%**(`v*(1-k)+255*k`,alpha 不动)——场景本身压白 38%,
|
||
人像不压白就是全页对比度最高的一块,必然"突兀";
|
||
5. 裁 bbox、缩到高 460,WebP q86(约 14KB)。
|
||
|
||
### 人物与道具必须用「同一套定位公式」
|
||
|
||
`background-position` 里的百分比**不是相对视口宽度**,而是相对 `(定位区宽 - 图片宽)`。
|
||
所以人物和自行车即使写同样的 `calc(50% - Npx)`,两者也会因为图宽不同而错位——
|
||
实测把车按人的公式放,车直接跑出屏幕,只剩一片轮圈。
|
||
|
||
正确做法是按各自宽度反解:设人物宽 `wc`、车宽 `wb`,要让车的右沿贴住人的左沿(留 gap):
|
||
|
||
```
|
||
人的 left = (W - wc)/2 + Bc
|
||
车的 left = (W - wb)/2 + Bc - gap - wb + wc/2 - wc/2 ... 直接解 B 更省事
|
||
```
|
||
|
||
本主题实测:人物 `calc(50% - 524px)`、车 `calc(50% - 612px)`。
|
||
|
||
另外**道具不要烘焙进背景图**:背景是 `cover`,视口一变裁切量就变,
|
||
而人物是固定 px 定位的,两者必然分家。烘焙只适合「和人无关的背景物件」。
|
||
|
||
关键经验:**必须是"平涂无描边"**。先试过用手写 SVG 线稿,风格和用户那张立绘(色块、无描边)冲突,
|
||
而且没有真人手感会画得很抽象;用参考图 + image-to-image 出来的四张,角色特征和画风都稳。
|
||
|
||
**版权说明**:砂狼白子(砂狼シロコ)是《蔚蓝档案》的角色,版权归 NEXON Games / Yostar。
|
||
本主题为**非商用同人装饰**,仅作个人站点外观使用;若站点转为商业用途,请自行取得授权或换成原创素材。
|
||
|
||
## 替换 / 扩素材
|
||
|
||
1. 加姿态:按上面的提示词骨架换动作句生成,白底 → 抠图 → 存 `chibi/<name>.webp`(高 620),
|
||
再塞进 `shiroko.css` 的 `--tb-deco`(记得保持 6 个值,并按上面的摆位原则定位)。
|
||
换 `<img>` 时别忘了给 URL 带 `?v=`——图片不走 `StaticVersion` 缓存键,`max-age` 是 1 天。
|
||
2. 换立绘:透明 PNG 覆盖 `static/images/shiroko-cutout.png`,再按同一提示词骨架重新生成姿态。
|
||
3. 换配色:改 `shiroko.css` 的令牌即可,插画是位图,换色需重新生成。
|
||
4. 新增素材不需要改 `static/fs.go`(已嵌整个 `images/themes` 目录);但改了 CSS 必须把
|
||
`conf.StaticVersion` +1,否则老访客吃缓存看不到变化。
|
||
|
||
## 部署后设置页看不到这个主题?
|
||
|
||
先分两步确认,不要一上来就怀疑缓存:
|
||
|
||
1. **文件是否随二进制发布了** —— 直接取一次静态资源:
|
||
|
||
```bash
|
||
curl -o /dev/null -w "%{http_code}\n" \
|
||
https://<你的域名>/static/css/themes/shiroko.css?v=<StaticVersion>
|
||
```
|
||
|
||
返回 200 说明 css 已经嵌进去了;返回 404 说明部署的是旧二进制。
|
||
|
||
2. **是否登记进 `[theme] available`** —— 主题列表是启动时按白名单构建的,
|
||
css 在但没登记,设置页就看不到它。检查 `conf/app.ini`:
|
||
|
||
```ini
|
||
[theme]
|
||
default = default
|
||
available = default,sakura,shiroko
|
||
```
|
||
|
||
改完**重启**进程(`[theme]` 只在启动时读)。
|
||
|
||
启动日志会直接告诉你缺哪一行:
|
||
|
||
```
|
||
level=info msg="主题注册表已加载" enabled="default,sakura"
|
||
level=warning msg="[theme] available 未登记以下主题,它们不会出现在设置页"
|
||
available="default,sakura,shiroko" themes=shiroko
|
||
```
|
||
|
||
## 场景图的生成
|
||
|
||
整页背景是一张生成的教室插画,提示词:
|
||
|
||
```
|
||
Empty Japanese high school classroom in the afternoon, flat pastel anime background art,
|
||
very light and airy, pale blue-grey and warm cream palette, rows of desks softly out of focus,
|
||
big windows with soft daylight, thin clean shapes, low contrast, minimal detail,
|
||
large calm empty area in the center, no characters, no text, no watermark,
|
||
wide scene suitable as a website background
|
||
```
|
||
|
||
生成后处理(PIL,脚本未入库,参数记在这里):
|
||
|
||
1. 裁掉图片底部 160px —— 生成器会在右下角打 `AI生成 WORKBUDDY` 水印,不裁会出现在页面上;
|
||
2. 按 16:9 取顶部 864px,整体混白 38%(`v*0.62 + 255*0.38`)—— 保证白卡片放上去仍有足够对比度;
|
||
3. 高斯模糊 1.4px,让桌椅不抢正文;
|
||
4. 导出 WebP q80(1920×1080,22KB);移动端从同一张按 9:16 中裁 620px 宽,导出 720×1003。
|