Skip to content

Commit 6e5c0b2

Browse files
committed
feat(windows): sync pet glow with active theme
1 parent 5fd8af5 commit 6e5c0b2

10 files changed

Lines changed: 220 additions & 23 deletions

File tree

windows/CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# Windows Changelog
22

3+
## Unreleased
4+
5+
### 改进
6+
7+
- 桌面宠物的精确 `/avatar-overlay` 辅助窗口现在可跟随活动主题显示柔和强调色光晕;默认从主题显式 `palette.accent` 或本地图像分析结果取色,主题热更新时同步刷新,并始终保持窗口透明与官方宠物交互不变。
8+
- 主题可用 `pet.mode: accent | off` 控制联动,并用 `pet.glow``0..1`)调整光晕强度;缺省值分别为 `accent``0.45`
9+
10+
### 测试
11+
12+
- 增加宠物目标 URL 白名单、主题联动、关闭模式、清理和非宠物辅助窗口隔离回归测试。
13+
314
## 1.2.0 — 2026-07-17
415

516
### 新增

windows/SKILL.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Apply a reversible renderer skin through Chromium DevTools Protocol while launch
1818
## Guardrails
1919

2020
- Preserve the official executable, package signature, user threads, pets, plugins, and authentication state.
21+
- Pet theming is limited to a non-interactive accent glow on the exact `app://codex/avatar-overlay` renderer. Keep the auxiliary window transparent, do not replace official pet assets or animation, and use `pet.mode: off` to disable the effect.
2122
- Theme images must be UI-free wallpapers. Never import a README screenshot, fake window, sidebar, card, composer, logo, or text baked into the bitmap.
2223
- Paint one continuous 16:9 wallpaper across the full Codex window. Let the sidebar, main area, header, and composer act as coordinated readability layers; keep the home route expressive and task routes quieter.
2324
- `appearance: auto` follows the native computed `color-scheme` first and the system appearance only as a fallback. Image brightness may tune color and composition, but must not flip the user's shell mode; explicit `light` and `dark` remain authoritative.
@@ -29,7 +30,7 @@ Apply a reversible renderer skin through Chromium DevTools Protocol while launch
2930
- The watcher registers a generation-checked early payload for connected renderers so reload/navigation can paint the skin before the normal load-event fallback; unsupported CDP targets fall back safely.
3031
- The active theme, saved themes, imported images, pause marker, and tray controls live under `%LOCALAPPDATA%\CodexDreamSkin`. Reject empty or over-16 MB images before copying or encoding them.
3132
- Every managed-store write rejects junctions and other reparse points in every existing path component. Imports also use the bundled Node metadata parser before copying to reject dimensions above 16384px or 50MP.
32-
- CDP targets must use a same-port loopback WebSocket, belong to the current Store package, retain the launch-time Browser ID, and expose expected Codex renderer markers.
33+
- CDP targets must use a same-port loopback WebSocket, belong to the current Store package, retain the launch-time Browser ID, and expose either the expected Codex shell markers or the exact pet-overlay URL and structure.
3334
- Loopback prevents LAN exposure, but Chromium CDP has no same-user authentication. Run only trusted local software while the skin is active, and use restore to close the debug session when it is no longer needed.
3435
- Preserve `config.toml` as strict UTF-8. Never use encoding-dependent whole-file PowerShell reads/writes, silently transcode UTF-16, or overwrite a file that changed after it was read. Ambiguous TOML shapes must fail before writing rather than receive a best-effort rewrite.
3536
- Keep install/start/restore/verify serialized with the per-user operation lock in `common-windows.ps1`.
@@ -50,7 +51,7 @@ node --check assets\renderer-inject.js
5051
- `assets/dream-skin.css`: full visual layer.
5152
- `assets/renderer-inject.js`: idempotent DOM integration and cleanup.
5253
- `assets/dream-reference.jpg`: pure 2560 × 1440 Arina Hashimoto wallpaper seeded as the default and as a saved theme; it contains no Codex UI.
53-
- `assets/theme.json`: shared adaptive theme contract for the seeded preset.
54+
- `assets/theme.json`: shared adaptive theme contract for the seeded preset, including optional `pet.mode` and `pet.glow` controls.
5455
- `scripts/theme-windows.ps1`: persistent active/saved theme store, safe image import, pause state, and preset seeding.
5556
- `scripts/tray-dream-skin.ps1`: Windows Forms tray for apply, pause, import, save, switch, and complete restore.
5657
- `references/qa-inventory.md`: required functional and visual signoff coverage.

windows/assets/renderer-inject.js

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
const STATE_KEY = "__CODEX_DREAM_SKIN_STATE__";
33
const STYLE_ID = "codex-dream-skin-style";
44
const CHROME_ID = "codex-dream-skin-chrome";
5+
const PET_STYLE_ID = "codex-dream-skin-pet-style";
6+
const PET_ROOT_CLASS = "codex-dream-skin-pet";
57
const ROOT_CLASSES = [
68
"codex-dream-skin",
79
"dream-theme-light",
@@ -28,6 +30,7 @@
2830
"--dream-accent-ink",
2931
"--dream-image-luma",
3032
];
33+
const PET_PROPERTIES = ["--dream-pet-accent", "--dream-pet-glow-blur"];
3134
const HOME_UTILITY_CLASS = "dream-home-utility";
3235
const installToken = {};
3336
let samplingNativeShell = false;
@@ -55,6 +58,7 @@
5558
const normalizeConfig = (value) => {
5659
const config = value && typeof value === "object" ? value : {};
5760
const art = config.art && typeof config.art === "object" ? config.art : {};
61+
const pet = config.pet && typeof config.pet === "object" ? config.pet : {};
5862
const hasNumber = (candidate) =>
5963
(typeof candidate === "number" || (typeof candidate === "string" && candidate.trim() !== "")) &&
6064
Number.isFinite(Number(candidate));
@@ -74,13 +78,16 @@
7478
? art.taskMode
7579
: "auto";
7680
const metadataRatio = Number(config?.artMetadata?.ratio);
81+
const petMode = ["accent", "off"].includes(pet.mode) ? pet.mode : "accent";
7782
return {
7883
appearance,
7984
safeArea,
8085
taskMode,
8186
focusX: hasNumber(art.focusX) ? clamp(art.focusX) : null,
8287
focusY: hasNumber(art.focusY) ? clamp(art.focusY) : null,
8388
accent: safeAccent,
89+
petMode,
90+
petGlow: hasNumber(pet.glow) ? clamp(pet.glow) : .45,
8491
initialAspect: Number.isFinite(metadataRatio) && metadataRatio > 0 ? metadataRatio : null,
8592
};
8693
};
@@ -275,7 +282,14 @@
275282
return "light";
276283
};
277284

278-
const clearSkinDom = () => {
285+
const clearPetDom = () => {
286+
const root = document.documentElement;
287+
root?.classList.remove(PET_ROOT_CLASS);
288+
for (const property of PET_PROPERTIES) root?.style.removeProperty(property);
289+
document.getElementById(PET_STYLE_ID)?.remove();
290+
};
291+
292+
const clearShellSkinDom = () => {
279293
const root = document.documentElement;
280294
root?.classList.remove(...ROOT_CLASSES);
281295
for (const property of ROOT_PROPERTIES) root?.style.removeProperty(property);
@@ -287,6 +301,41 @@
287301
document.getElementById(CHROME_ID)?.remove();
288302
};
289303

304+
const clearSkinDom = () => {
305+
clearShellSkinDom();
306+
clearPetDom();
307+
};
308+
309+
const applyPetProfile = (root) => {
310+
const accent = config.accent || `rgb(${profile.accent.join(" ")})`;
311+
const blur = 4 + config.petGlow * 12;
312+
root.classList.add(PET_ROOT_CLASS);
313+
root.style.setProperty("--dream-pet-accent", accent);
314+
root.style.setProperty("--dream-pet-glow-blur", `${blur.toFixed(1).replace(/\.0$/, "")}px`);
315+
316+
let style = document.getElementById(PET_STYLE_ID);
317+
if (!style) {
318+
style = document.createElement("style");
319+
style.id = PET_STYLE_ID;
320+
(document.head || root).appendChild(style);
321+
}
322+
if (style.dataset.dreamVersion !== "1") {
323+
style.textContent = `
324+
html.${PET_ROOT_CLASS},
325+
html.${PET_ROOT_CLASS} body {
326+
background: transparent !important;
327+
}
328+
html.${PET_ROOT_CLASS} body {
329+
filter: drop-shadow(
330+
0 0 var(--dream-pet-glow-blur)
331+
color-mix(in srgb, var(--dream-pet-accent) 62%, transparent)
332+
);
333+
}
334+
`;
335+
style.dataset.dreamVersion = "1";
336+
}
337+
};
338+
290339
const applyProfile = (root) => {
291340
const focusX = config.focusX ?? profile.focusX;
292341
const focusY = config.focusY ?? profile.focusY;
@@ -329,10 +378,15 @@
329378
const shellMain = document.querySelector("main.main-surface");
330379
const shellSidebar = document.querySelector("aside.app-shell-left-panel");
331380
if (!shellMain || !shellSidebar) {
332-
clearSkinDom();
381+
clearShellSkinDom();
382+
const petOverlay = location.protocol === "app:" && location.hostname === "codex" &&
383+
location.pathname === "/avatar-overlay" && !location.search && !location.hash;
384+
if (petOverlay && config.petMode === "accent") applyPetProfile(root);
385+
else clearPetDom();
333386
return;
334387
}
335388

389+
clearPetDom();
336390
root.classList.add("codex-dream-skin");
337391
applyProfile(root);
338392

windows/assets/theme.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,9 @@
1515
"focusY": 0.45,
1616
"safeArea": "left",
1717
"taskMode": "ambient"
18+
},
19+
"pet": {
20+
"mode": "accent",
21+
"glow": 0.45
1822
}
1923
}

windows/references/qa-inventory.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
- Sidebar: open a real task, then return to New Task.
1818
- Composer: type text, verify caret/readability, then clear it without sending.
1919
- Reload: use CDP `Page.reload`, wait, and confirm the injection marker returns.
20-
- Pet overlay: open a desktop pet and confirm its auxiliary window stays transparent with no skin background or decoration layer behind it.
20+
- Pet overlay: open a desktop pet and confirm its exact `/avatar-overlay` window stays transparent, retains native animation and interaction, and receives only the active theme's accent glow. Change themes and confirm the glow updates; pause or restore and confirm it is removed. Set `pet.mode` to `off` and confirm no pet style remains.
2121
- Restore/reapply cycle: remove live skin, verify marker absent, apply again, verify marker present.
2222
- Update resilience: resolve the current `OpenAI.Codex` Appx location dynamically for launch. A versioned path saved for cleanup must be revalidated against the registered package full/family identity before any process is stopped.
2323
- Restart consent: an existing normal Codex window is never force-closed without explicit CLI authorization or shortcut confirmation.

0 commit comments

Comments
 (0)