`app-icon.png` is a 120KB bitmap, and the seven `.svg` files beside it under
docs/images are 193 bytes each — an `<image>` tag wrapping that bitmap. So the
mark carried its own blue/cyan/orange through all six palettes while everything
around it moved, and there was nothing to recolor.
Measured the bitmap back into geometry rather than redrawing it: connected
components to separate the elements, algebraic circle fits for the arcs, angular
histograms for the openings and stroke widths. Big C is center (415,566) r=131
stroke=60, opening 160°; the second C is center (615,576) r=117 cut into two 68°
arcs; the cursor is a four-point polygon with one notch. The slight ellipticity
and unequal stroke ends were raster artifacts, so they were rounded out. The
shape is otherwise unchanged — differencing a render against the original leaves
only antialiasing.
Color maps the original's three layers onto the palette's own three: the C's take
墨 `--cc-t1`, the bar and cursor and sparkles take 朱 `--cc-ac`.
Six themes do not need six icons. Their accent resolves to two values — #96442B
across the four light palettes, #D07B52 across the two dark ones, which is the
same ochre lightened. Only the ink varies, and ink should follow body text
anyway.
The app icon stays one fixed artwork. Dock and taskbar are drawn by the OS, which
knows nothing about the in-app theme, so paper ground with ink C's ships to every
platform. Inside the app the mark is a vector on tokens and repaints per theme.
Four ideas — two C's, the bar, the cursor, two sparkles — collapse below 24px, so
every consumer sheds parts as it shrinks: sparkles above 40px, cursor above 24px,
C's and bar always. That applies inside icon.icns and icon.ico as much as in
BrandSeal.
BrandSeal was the 「哈」 glyph in a terracotta square; it is now the CC mark drawn
inline on `--color-text-primary` and `--color-brand`. Its five call sites — the
sidebar, both empty states, the H5 connect view, the gallery — follow, and the
about pane drops its `<img>` for the same component.
README leads with the horizontal lockup inside a `<picture>` so GitHub serves the
dark cut in dark mode.
The generated logo asset carried both an opaque square canvas and an inner rounded tile, so the desktop empty state and sidebar rendered a visible nested background. Rebuilt the canonical app icon with transparent outside corners, one white rounded badge, and a centered mark, then regenerated the Tauri icon set and docs raster assets from that source.
Constraint: Existing desktop views consume /app-icon.png directly with no wrapper background to remove.
Rejected: Add CSS masking around each img usage | would leave native app icons and docs assets with the same nested canvas problem.
Confidence: high
Scope-risk: narrow
Directive: Keep desktop/src-tauri/app-icon.png as the canonical 1024 RGBA source before regenerating platform icons.
Tested: cd desktop && bun run build; npm run --loglevel=error docs:build; git diff --check; sips alpha and size checks; iconutil icns size ladder; Chrome DevTools light and forced-dark screenshots.
Not-tested: full bun run verify gate, per prior instruction to skip local gate for this logo pass.
The desktop app and documentation need to present the new logo consistently, so the canonical 1024px source icon now feeds the Tauri icon family, desktop public assets, README images, and VitePress brand imagery.
Constraint: Tauri bundle icons are generated assets and must be refreshed from the source icon rather than relying on README or public image replacement alone
Rejected: Rename logo paths | existing README, desktop, and docs references can keep stable paths and pick up the new files directly
Confidence: high
Scope-risk: moderate
Directive: Regenerate desktop/src-tauri/icons whenever desktop/src-tauri/app-icon.png changes
Tested: cd desktop && bun run build; npm run --loglevel=error docs:build; git diff --check; iconutil expanded icon.icns size ladder
Not-tested: full local quality gate per request
Desktop sessions can switch provider and model while a CLI subprocess is already alive, so the server now serializes runtime restarts and marks provider-managed launches to prevent stale settings env from overriding the selected provider. Provider settings also write API key env consistently and clear stale managed keys before syncing.
This includes the related desktop/docs brand asset refresh and keeps the desktop locale default in Chinese, with tests updated to match the current provider semantics.
Constraint: Session-scoped model selection must win over cc-haha/settings.json and inherited ANTHROPIC_* values.
Rejected: Store the selected model as a global provider activeModel | chat runtime selection is per session.
Confidence: high
Scope-risk: moderate
Directive: Do not remove CLAUDE_CODE_PROVIDER_MANAGED_BY_HOST without validating Desktop provider switching against stale settings env.
Tested: bun test src/server/__tests__/conversation-service.test.ts src/server/__tests__/conversations.test.ts src/server/__tests__/providers.test.ts src/server/__tests__/providers-real.test.ts
Tested: cd desktop && bun run test src/stores/settingsStore.test.ts
Tested: cd desktop && bun run lint
Tested: git diff --check
Not-tested: Full desktop production package/signing.