Turn the element-selection -> composer flow into reproducible guidance after
user reproductions surfaced three gaps: raw XML in the composer / sent bubble,
pills outside the composer box, and a separate PNG attachment.
- 5.7.7 Visual spec + state matrix (controlled-replay): inject client CSS into
headless Chrome 157, read computed styles for all three pill variants in
light/dark plus forced hover/focus. Covers the double 0.5px hairline,
hover-only remove button (opacity .15s cubic-bezier(.4,0,.2,1)), blue focus
shadow, 320px/10px popover, 360px scroll body, two-column dl, 12px mono Props,
ring inner/outer inversion in dark, and a tokenized CSS skeleton. Documents
two repo token mismatches (--cds-pad-md 12px vs client 8px, --cds-radius-card
12px vs client 10px) and the overridden legacy clay focus-shadow.
- 5.6.1 Three-layer separation + reproduction guide: L1 object-array store,
L2 attachment row inside the composer, L3 wire payload assembled only at
submit. Adds ⑤ layout spec ([data-cds-composer-attachments-clip] inside the
rounded composer, hover card as a body portal, no standalone PNG) and
⑥ send form (XML is the hidden prefix of the first text block; message keeps
text/displayText/typedText/hadElementContexts; Oe/fK/pK stripping and
elementContext chip rendering mean the bubble never shows code). Includes
explicit do/don't tables and submit/render pseudo-code.
- 5.7.8 Hover direction: placement top-start, strategy fixed, offset(8),
flip only as fallback, shift, autoUpdate + ResizeObserver, zIndex 30,
isPositioned first-frame guard, and why portal+fixed is required to escape
the composer's overflow-hidden clip when opening upward.
- Extend the evidence index with byte offsets; regenerate merged .full.md.
Evidence: shipped-artifact byte offsets, controlled-replay (Chrome 157 CDP),
and user-supplied reproduction screenshots. No code or token changes.
Gates: typecheck / check:tokens / build all 0; entry-point links 0 broken.
- AGENTS.md §4 DON'T: never open or update a Pull Request without explicit
user approval; local edits/commits are fine, but gh pr create/edit and
pushing to a branch with an open PR require approval first.
- Part 2 §2.5.1: dynamic default-browser name (Open in {browserName} with
generic fallback, refreshed on window focus via getDefaultBrowserName()),
menu item state matrix (checkbox/radio/hint/danger/disabledReason/keepOpen),
and field-by-field mapping of the settings-menu screenshot.
- Part 2 §2.5.2: four-layer menu implementation —
cf550b864 xe() pure-data {sections} model (177 memo slots, prop-existence
conditional rendering, fully controlled checked state, stable callbacks),
c58115fda assembly + labels injection, c4db265df pane header Tn() passing
menuSections, ca5db7aaf H() generic renderer (DotsHorizontal trigger,
side=bottom/align=end Popup, unroll single-item optimization, U()/Z()
section+item expansion), and the shared shared-frame Vs primitive set used
by settings, sketch dropdowns, dev-server and pane-layout menus.
Includes item schema, onSelect landing points, a11y and motion notes.
- Part 6 §6.1.1-6.1.3: sketch toolbar structure (select / pen / Shapes
dropdown / text / separator / X), we() re-click-to-select, shape memory
defaulting to rect, mutually exclusive pinnedOpen dropdowns, minimal layout
attributes, text tool Esc/Cmd-Enter interaction, and the shared Vs primitives
(side=top vs side=bottom).
- Extend both evidence indexes with byte offsets; regenerate merged .full.md.
Gates: typecheck / check:tokens / build all exit 0; entry-point links 0 broken.
Local commit only — no push and no PR operation (per the new approval rule).
Follow-up to the 5.8-5.11 file-drop work, driven by a second user screenshot showing
the detail card that appears when hovering an injected <AppNavigation /> composer pill:
"Included with your message" + screenshot thumbnail + Element / Component / Props / Source.
Expands 5.7 with six implementation-level subsections:
- 5.7.1 Hover intent state machine: _c=600ms open delay, vc=200ms close grace,
Pt "warm" latch (zero-delay switching after the first card in an interaction),
pinned state via "Show what this sends" (opens immediately, role=dialog, survives
mouseleave), hover/click/keyboard/menu openedVia telemetry gating.
- 5.7.2 Floating layer: useFloating placement top-start / strategy fixed /
transform false, middleware offset(8)+flip+shift, autoUpdate + ResizeObserver on
.epitaxy-attachment-shelf, maxWidth clamp, Uc=320 card width, zIndex 30, portal to
body, isPositioned first-frame guard, blur/relatedTarget guards.
- 5.7.3 Data chain: captureElementContext -> Xn(ctx) -> Gd/Hd/Rd/Ud in c06cf64bb;
full section table (element/component/props/source/definedIn/renderedAt/text/
attributes/path/styles/html/siblings/raw) with exact field provenance, Bd/Ld/H
truncation, and the unsafeDisplay hidden/bidi-character filter shared with 5.5.
- 5.7.4 Rendering: Co 7 primary sections, Do collapsible "Show N more details",
wo <dl> two-column layout, mo entries/code/text kinds, "in {owners}" (3exxNrWVG9)
and the clipPath+translateX WAAPI expand animation.
- 5.7.5 Field-by-field mapping of the screenshot (including why [functio n] wraps:
overflow-wrap:anywhere, not data truncation; [object]/[function] come from 5.4's
summarizeProp; 4 owners matches MAX_OWNERS=4; source path from VLQ sourcemap).
- 5.7.6 Accessibility: role=group scroll region, role=dialog when pinned, focus
handoff to adjacent attachments, restored chips, unsafe-display notice.
Evidence index extended with c0a74d72b/c06cf64bb offsets and the second screenshot;
docs/README.md focus line and merged .full.md regenerated. No code/token changes.
Gates: typecheck / check:tokens / build all 0; entry-point links 0 broken.
Deep-dive into the side-browser volume's 5th part, driven by a user screenshot showing
a blue 2px ring + blue pill over the chat pane while the Preview pane stays untouched.
New sections 5.8 - 5.11 (evidence index renumbered to 5.12):
- 5.8 Three coexisting drop overlays in 4.16336.0: global screen-level DropZoneProvider
(shared-9 xh), dframe badge/label (c4c113f6f + shared-styles - the screenshot), and
ring/dashed/three-icon area overlay (cc63499d2 / cc17a11d9). Full computed-style spec
for badge + label, pixel verification (2 CSS px ring, 143x30 CSS px pill, RGB 31/101/216
vs computed #2a78d6), data-hint / RTL / reduced-motion variants, and the fact that the
same badge class is reused by split-pane session dragging (shared-23).
- 5.9 Two independent drag state machines: four-state DropZoneProvider with mixed
capture/bubble listeners, 500ms DROPPED hold and enableScreenDrop; and useDragZone's
Set<Element> enter/leave counter with dragend/drop/pointerdown capture cleanup.
Documents the fileHint branch, __gb__4088364908 hint key (semantics marked inferred)
and why only the chat/composer column gets the blue ring.
- 5.10 Post-drop pipeline: dataTransfer.items -> getAsFile / webkitGetAsEntry folder split,
FileSystemHandle wait, limit constants, 13-item i18n error matrix and the 967 B
pending upload queue (push/take/restore/drain/staging probes).
- 5.11 Attachment entrance/exit: startViewTransition({types:['cds-attachments']})
capability gates and fallbacks, @starting-style, match-element + view-transition-group
contain, cds-attachment-out, and cds-chip-in stagger (50/80/110/140ms measured via
sibling-index()). Full motion table for all drop keyframes.
Evidence: shipped-artifact byte offsets, controlled-replay (client CSS injected into
headless Chrome 157, computed styles + animation timings + pixel comparison), and the
user screenshot. 9229 inspector was not reachable this round and SIGUSR1 did not re-arm
it, so no live app state was touched; REA static graph recording hit the session
retention cap, so byte offsets are used in place of a new Evidence ID.
Volume README index, docs/README.md focus line and the merged .full.md regenerated.
No code/token changes: client-only --cds-* / --df-* variables are kept in var(...) form
so check:tokens stays clean.
Gates: typecheck / check:tokens / build all 0; all entry-point links verified.
- Replace the obsolete project tree (it still listed a non-existent
docs/Claude Design System (CDS).md and no version volumes) with the real layout:
4 version-named doc volumes, current v4.16336.0 volume, scripts/, src/types.d.ts,
AGENTS.md / CLAUDE.md / CHANGELOG.md and the 37 code-examples files
- Correct counts: 30 -> 37 files, 7 parts -> 8 parts, 31 -> 41 sections,
3,000+ -> 4,600+ lines, 242 -> 261 design tokens (matches check:tokens)
- Re-anchor the forensic baseline to docs/v4.16336.0; mark 4.4212.0 / v3 wording historical
- Keep the v1 30-module inventory wording accurate by scoping it to the v1 baseline
Gates: typecheck / check:tokens / build all exit 0; all four entry-point link sets verified.
- Append a "支持与关注 / Support & Follow" section after Star History in README.md and README-en.md
- Links: X @BystAnd3rs, Xiaohongshu 企鹅AI指南 profile, WeChat Official Account 企鹅AI指南 (text search hint; no QR asset yet)
- Add Star / Issue / PR call-to-action line; replace dead /stargazers deep links with the repo homepage
- Layout follows common GitHub README CTA patterns (llm-course / MoneyPrinter X line,
AI-Media2Doc support section, mall-swarm WeChat section): plain Markdown table, no external badge service
Gates: typecheck / check:tokens / build all exit 0; all external links verified reachable.
- Add docs/v4.16336.0/: 8 feature-oriented chapters (v1 format) + README index + merged edition
* architecture/tokens, navigation/address bar/tabs, preview/dev servers,
permissions/security/browsing data, element inspect/component context,
annotation/screenshot/agent cursor, motion physics/frame-by-frame, host/runtime/reproduction
* backed by REA static analysis, 9229 live read-only observation (519 frames),
controlled replay and pixel verification; every claim carries an offset or Evidence ID
- Add code-examples/ElementInspectHighlight.ts (headless overlay + Fiber name reader), exported from src/index.ts
- Establish the version-named volume rule in README.md, README-en.md, docs/README.md and AGENTS.md §7
(version directory, chapters by feature point, four registration points, quality gates)
- Mark docs/v4.29.0-4.4212.0/ as historical baseline; fix 4 stale v1 merged-manual links
Gates: npm run typecheck / check:tokens / build all exit 0.
The directory now names the span it covers rather than a single
version: v4.29.0 is where the delta work started, 4.4212.0 is the
latest re-verified build. The merged edition follows the same naming
(Claude-Desktop-4.29.0-4.4212.0-全量分析.full.md).
The README naming convention now documents both forms: a single version
(docs/v5.0.0/) or a covered range (docs/v4.29.0-4.4212.0/, primary
forensics on the first version plus incremental re-checks on later
ones). v1 and v2 stay untouched as historical snapshots.
All cross-links in README, README-en, AGENTS and inside the manual are
updated; link check and check:tokens pass.
Claude Desktop moved 4.29.0 -> 4.4212.0 (ASAR ce90267c..., stylesheet
MainWindowPage-BoMeyaMm.css, 707 entries). Full delta scan:
CSS structure is otherwise unchanged - 45 data-cds namespaces and 90
@property entries identical, all 1,109 tokens identical (zero added,
removed or changed). Two additions:
1. cds-progress-sweep, the first indeterminate-progress primitive:
@keyframes cds-progress-sweep {
0% { transform: translateX(calc(var(--_progress-dir, -1) * 100%)); }
100% { transform: translateX(calc(var(--_progress-dir, -1) * -166.67%)); }
}
.cds-root .cds-progress-sweep {
opacity: .5; width: 60%;
animation: 1.6s cubic-bezier(.65, 0, .35, 1) infinite cds-progress-sweep;
mask-image: linear-gradient(90deg, #0000, #000 40% 60%, #0000);
}
--_progress-dir flips direction (default -1); the 166.67% travel
against a 60% width makes the loop seamless. Both degradation paths
ported: reduced-motion parks it at margin-inline-start 20%, and
forced-colors switches to opacity 1 with Highlight. Verified in
headless Chrome against the extracted values.
2. Font weight role chain: .font-medium now resolves through
--cds-font-weight-control before falling back to the literal 500, and
.font-semibold through --cds-font-axis-wght-header. So weight follows
the control/header semantic role rather than jumping straight to a
numeric weight. Eight role tokens added to :root (all initial by
default, per the client).
JS is untouched: same 6 Sentry IPC channels, 0 ipcMain.handle, same 2
BrowserWindow/3 utilityProcess mentions, same 25 exposeInMainWorld calls
and 14 literal bridge names, 7 renderer entries, 7 resources, 8 deps.
cds-progress-sweep has zero references across all 512 build JS files -
it is a pure CSS utility for the host to apply.
Docs: new section 6.12 records the delta; README, README-en, chapter 7
and the merged edition note 4.4212.0 as the current aligned version.
Gates: check:tokens (15 keyframes), typecheck, and the 8-point Chrome
regression all pass.
The forensic manual directory now tracks the Claude Desktop version it
was extracted from. docs/v3 becomes docs/v4.29.0 (primary forensics on
3.6556.2 with the 4.29.0 delta appendix inside), and the merged edition
is renamed to Claude-Desktop-4.29.0-全量分析.full.md.
README.md and README-en.md document the convention: from this release
on, new forensic reports get a directory named after the Claude version
they cover; docs/v1 and docs/v2 keep their names as historical
snapshots, with v2 values superseded by v4.29.0. The forensic-baseline
callouts in both files now cite @ant/desktop 4.29.0 as the aligned
version and link to the renamed directory.
AGENTS.md's pointer to the official-skill corroboration and all
cross-links inside the manual are updated; link check passes and
check:tokens stays green.
Re-audit of the 4.29.0 delta for full coverage:
1. resources/ actually holds 7 entries, not 4+separates. New to the
asar: i18n/ (43 locale JSONs, 3.5MB, 947-key ICU message catalog) -
a genuine 4.29.0 addition - plus claude-browser-shim.js and
quick-actions/ absorbed from disk into the archive. On disk outside
the asar, ion-dist/ became ion-dist.asar (191MB, 4,532 entries),
the claude.ai web shell now packaged independently with its own
12-locale i18n and a module dependency graph (scc.json: 3,925
chunks / 52,735 edges).
2. Official CDS doc diffed verbatim: it moved chunks (CbnfBP-3 ->
JNXX2nzx) and the only substantive change in all 668 lines is the
build toolchain rename yarn -> bun (gen:tokens, gen:cds-skill).
Token model, elevation table, motion vocabulary and every design
rule are unchanged - our extracted spec carries over intact.
3. Build shape: 551 JS files -> 501 at the same total size (chunk
merging; largest chunk 4.4MB -> 6.8MB). Entry index.js now carries
a SENTRY_RELEASE id. Evidence citations should use content
features (e.g. the gen-cds-skill marker) rather than chunk
filenames, since those do not survive repackaging.
Section 6.11.7 records all three; merged edition regenerated. Also
verified no new update has landed since the 4.29.0 scan (ASAR digest
fea39d03... unchanged; ShipIt log's last action was the 10/28 install).
The client jumped from 3.6556.2 to 4.29.0 during this engagement (ASAR
digest fea39d03..., stylesheet renamed to
MainWindowPage-BIxm3NVN.css, 696 entries vs 629). Full delta scan:
CSS: structure essentially unchanged - 55 keyframes, 90 @property and
all token values identical, with exactly two substantive changes:
1. data-cds=Heatmap renamed to data-cds=CellChartContainer (same
rule slot, message-embedded chart container)
2. window-inactive desaturation extended: the existing
[data-window-active=false] gray remap of role-accent-* now also
covers Button/ButtonGroup/SplitDropdownButton fill-brand /
fill-primary / fill-accent-hover, so inactive windows render
buttons fully desaturated
Our fix list (text ramp, blue accent, brand pair, density, skeleton,
shadows, alpha expression) re-verified item by item against 4.29.0 -
every value holds, no changes needed.
JS: mainView.js exposes 2 new bridge APIs (25 exposeInMainWorld calls,
14 literal names): desktopNoFlushBytecode (a --js-flags=
--no-flush-bytecode probe, companion to the compile-cache V8 prewarm)
and desktopHomePath. main process grew ~20KB; electron fuse state
unchanged.
Ported to cds-theme.css:
- [data-window-active=false] desaturation block for fill-brand /
fill-primary / fill-accent-hover
- --cds-fill-primary / -hover tokens (neutral-900 / neutral-750)
- --cds-neutral-750 added to both light (gray-750) and dark
(gray-150) ramp halves
Docs v3: new section 6.11 records the delta with the version-strategy
note that the forensic method (repro commands) outlives any snapshot;
chapter 7 and both READMEs note the 4.29.0 re-check.
Gates: check:tokens, typecheck, and the 7-point Chrome regression all
pass.
The top-level docs still described the v2.37337.1 era. This aligns them
with the v3 forensic baseline and the token fixes on this branch.
README.md / README-en.md:
- new forensic-baseline callout in the intro: aligned to
@ant/desktop 3.6556.2 (ASAR digest b2dfbbb4...), verified via REA
v6.8.0 static extraction plus live Main Process Debugger
measurement, linking docs/v3
- documentation index gains a v3 section describing all seven
chapters; the v2 entry is annotated as a historical snapshot
- token count 183 -> 242 (the count after aligning with the client)
AGENTS.md:
- text token table corrected to the ramp chain (neutral-900/600/400
with the live light/dark resolutions, text-muted identical in both
modes) and text-accent marked as the blue accent role
- skeleton base/sheen corrected to the official equal-value form
(hsl(from neutral-900 ...), 5% light / 7.5% white dark)
- Brand Clay Palette cites the bundled frontend-design skill naming
#D97757 as "Anthropic's own Claude-interaction accent", documents
the brand-vs-accent role split, and the blue focus-shadow
- the 7-stop fade mask record carries a v3 note: the client drives
scroll fading via @property + animation-timeline with no hardcoded
multi-stop mask; the stops remain as a static fallback
CHANGELOG.md:
- Unreleased gains a comprehensive v3 re-anchor entry covering the
text/accent/brand/shadow/density corrections, skeleton overhaul,
attachment view transitions, alpha single expression, CI gate
hardening, and doc updates
Gates: check:tokens and typecheck pass; docs/v3 links verified.
Completes the remaining P1/P2 items from the v3 audit plus the
attachment-reorder animation found in the 6.10 survey.
Attachment shared-element transitions (new, ported verbatim):
The client animates composer attachment add/remove/reorder through
View Transitions. Three layers ported from MainWindowPage:
- container [data-cds-composer-attachments] opacity/transform
transitions (.2s cubic-bezier(.215,.61,.355,1))
- per-card [data-cds-attachment]: view-transition-class +
--cds-attachment-vt-name set per card via the id prop; RTL
transform-origin through the official :lang list
- :active-view-transition-type(cds-attachments) routing: root gets
zero animation, only the attachment group animates (.18s)
New-Chromium path behind @supports (match-element +
view-transition-group: contain + group-children overflow), old path
via per-card names. @starting-style gives entering cards
scale(.92) translateY(4px); removals animate the old snapshot with
cds-attachment-out (scale .5, .13s cubic-bezier(.55,.055,.675,.19))
via ::view-transition-old:only-child. AttachmentCard exports
withAttachmentTransition() wrapping document.startViewTransition.
Alpha ramp single expression:
--cds-alpha-* now reads hsl(from var(--cds-neutral-900) ...) so the
light/dark flip happens through the neutral ramp, matching the
official vanilla tokens. The dark-mode block's white hardcodes are
deleted; they disagreed with the light percentages by 1/2/5 points
(0.09/0.18/0.30 vs 10/20/35%).
fill-secondary is white at 10% in light mode:
var(--cds-alpha-2) (black 10%) -> hsl(0 0% 100% / 0.1) with hover at
var(--cds-alpha-1), matching the live reading rgba(255,255,255,0.1).
Official corroboration recorded in AGENTS.md:
The frontend-design skill bundled with the client states #D97757 is
"Anthropic's own Claude-interaction accent". The Brand Clay Palette
section now cites it, documents the brand-vs-accent role split
(clay for Claude-initiated actions, blue #184f95/#86b6ef for
accent), and the focus-shadow fact (blue ring + glow, verified
live).
Gate: check:tokens passes (14 keyframes incl. cds-attachment-out with
its consumer), typecheck passes, and the 8-point regression suite in
headless Chrome is all green.
A whole-archive survey beyond CSS turns up five significant findings:
1. The desktop app ships a Linux microVM for Cowork.
Resources/smol-bin.arm64.img (24MB, DOS/MBR boot sector) pairs with VM
management code in index.chunk-jPKPzV-P.js: smol-bin.vhdx on Windows,
efivars.fd, VMDownloadError/VMConnectionTimeoutError, vmCpuCount,
memory GB, vm_shutdown on app quit. The feature family is the
CoworkVM* export group (Download/Running status, Spaces, Storage,
UserFiles, Memory, ScheduledTasks, RewindRefusal, HipaaCrashDumps).
Cowork is a third surface beside chat and code (coworkSurface /
codeSurface / chatSurface gates), with its own permission-mode flags.
Whether its UI is local CSS or the claude.ai web layer is unverified -
no Cowork-specific data-cds components exist among the 45.
2. Six bundled Agent Skills, and one of them names us.
resources/bundled-skills holds docx/pdf/pdf-reading/pptx/xlsx/
frontend-design as .skill files (1-byte-prefixed zips) plus a
manifest. The official frontend-design SKILL.md lists the tells of
AI-generated design, and item 1 says verbatim: "a terracotta or
warm-clay accent (often near #D97757 - Anthropic's own
Claude-interaction accent...)". That is Anthropic confirming, in its
own shipped doc, the exact clay value our forensic work derived - now
citable as official corroboration for --cds-clay. The skill's
generic-default checklist is also directly relevant if the project
ever ships custom themes.
3. Four bundled MCP servers.
github-mcp-server (19MB Go binary), a full office365-mcp (stdio
server + pdf extractor + MSAL runtime dylib/node, explaining the
enterprise OAuth UI), plus @ant/computer-use-mcp and
@ant/claude-for-chrome-mcp inlined into the vite build. package.json
declares 8 dependencies but only 4 exist in the asar (claude-native,
claude-swift, node-pty, ws) - the rest are build-inlined, which is
why "imagine-server" appears nowhere in the 551 JS files.
4. V8 compile cache.
compile-cache/*.jsc (arm64) for index.pre.js and the two largest
chunks - startup-path optimization, 6.9MB for the biggest chunk.
5. Modern CSS the docs had not recorded.
@starting-style x3 and view-transition-name x3: message actions use
starting-style for hover/focus reveal, and composer attachment
reordering uses the new Chromium shape
view-transition-name: match-element with view-transition-group:
contain behind a @supports probe. Not implemented on our side; filed
as P2. Also clawdQuestEngine (1.2MB JS + --cq-* namespace, quest/XP
gamification) is fully isolated from CDS, and claude-ios-sim hosts an
iOS simulator toolchain (xcodebuild/xcrun/plutil allowlist).
Chapter 6 gains section 6.10 with all of the above; chapter 7 gains a
new-pending-questions table (Cowork UI carrier, worker type of the three
bundled workers, quest engine triggers, VM specs) and records the new
A-grade facts. 98 cai_*/ccr_*/cowork_* feature flag names are noted as
extractable. Merged edition regenerated; 0 broken links.
Every value below was verified against the running app over the
main-process debugger (webContents.debugger over CDP, reading
getComputedStyle from the live main_window renderer), then re-verified
locally in headless Chrome against cds-theme.css. 9/9 resolved colors now
match the client exactly.
Text colors (all three were wrong):
text-primary #151515 -> var(--cds-neutral-900) #0b0b0b
text-secondary #525252 -> var(--cds-neutral-600) #52514e
text-muted #8a8a8a -> var(--cds-neutral-400) #898781
neutral-N is the official theme ramp: gray-N in light, gray-(900-N) in
dark. New --cds-neutral-* block defines the flip, so dark mode now
yields #f0efec / #c3c2b7 / #898781 exactly as the client does.
Accent is blue, not clay (the root misreading):
The official spec separates the accent role (blue) from the brand role
(clay). Verified live:
border-accent light #86b6ef (blue-250) / dark #0d366b
text-accent light #184f95 (blue-600) / dark #6da7ec
fill-accent #2a78d6 (blue-450)
focus-shadow 1px #2a78d6 ring + #cde2fb glow, was clay
Added --cds-blue-100/250/450/600 and --cds-role-accent-{250,450,600},
--cds-bg-accent; border-accent/text-accent/focus-shadow now resolve
through the role chain.
Brand hover direction fixed:
fill-brand #c6613f (clay-emphasized, both modes)
fill-brand-hover #d97757 (clay) - the client hovers upward, we had
--cds-clay-hover #cc5a36/#e08264 which went darker. clay-emphasized is
now a literal #c6613f, no dark override, matching the single
declaration in the client's stylesheet.
Skeleton dark values:
base and sheen are the same value in the client:
hsl(from neutral-900 / 7.5%), i.e. a darkening white wash. Ours were
white alphas at two different strengths (0.06/0.08).
Shadow system:
shadow-popover is a pure two-layer drop shadow officially
(0 8px 24px/0.12, 0 2px 6px/0.08); the inset ring we mixed in is gone.
shadow-sm/md/lg and shadow-color now use hsl(from gray-900 ...) for
the offset layer so they follow dark mode; dark shadow-color is
rgba(0,0,0,0.24) per the live reading.
Sizing and density:
radius-composer 20px -> calc(.75rem * scale) = 12px, with
[data-density=comfortable] overriding to 14px (the live app reports
data-density=comfortable and resolves 14px). gap-xl 1.5rem -> 40px,
h-control-nested 24px -> 22px, and the full sizing family (radius,
h-control*, icon, pad-*, gap-*) is now written as
calc(N * var(--cds-rem-scale, 1)) instead of fixed px, so a host can
actually drive density. keycap-radius 4px and checkbox-radius 5px per
the official vanilla tokens.
Skeleton structure:
.cds-skeleton-sweep is removed from the ::after selector list that also
carried position:absolute - as a standalone class it pushed the element
out of the viewport (the bug reproduced in issue #25). The official
shape is a .cds-skel-sweep-band child inside a .cds-skel-sweep-clip;
both are now provided. The base class border-radius moves to
:where() so rounded-full survives on avatar skeletons. data-hold
three-state reveal timing, the wave/lockstep breathe bindings, the
RTL :lang() list with animation-direction:reverse, and dual reduced-
motion guards (prefers-reduced-motion + data-reduce-motion) are added
per the extracted rules; cds-placeholder-reveal keyframe added.
Tooling:
check-tokens.mjs strips CSS comments before the orphan-keyframe check;
a keyframe named only inside a comment used to pass as consumed.
Gate: check:tokens passes (242 tokens, 13 keyframes), typecheck passes,
and the 9-value comparison table against the live client is all-green.
Section 6.7 gains the definitive reference tables extracted from the
running main_window renderer over the main-process debugger, forced
through both data-mode values:
- light/dark resolved values for text-primary/secondary/muted,
text-accent, border-accent, clay-emphasized, fill-brand(+hover),
alpha-1..4, skeleton base/sheen, shadow-color/popover, focus-shadow,
fill-secondary and page-bg
- resolved sizes under data-density=comfortable: radius 8px,
composer 14px, h-control 32px, h-control-nested 22px, gap-xl 40px,
icon 20px, radius--xs/sm/lg 6/7/10px, plus the dur/ease values
- --cds-rem-scale reads as an empty string, confirming 6.6.1
Notable confirmations: text-muted is identical in both modes
(gray-400), clay-emphasized and the brand fill pair never reload in
dark, alpha flips to white with the same percentages, and the dark
skeleton is a 7.5% white wash equal for base and sheen.
Section 6.7.6 records the fix verification: after the token alignment
commit, headless Chrome against cds-theme.css reproduces 9/9 resolved
colors exactly, and the structural fixes are confirmed (the standalone
sweep class no longer displaces its element, rounded-full survives on
avatar skeletons, RTL reverses direction, data-hold=none collapses the
animation). The fix also widens official-token alignment from 131 to
154 shared names (neutral ramp, missing gray stops, the accent chain,
pad-*), noted in the same section.
Merged single-file edition regenerated. No code changes in this commit.
The node CLI inspector fuse is disabled, so --inspect does nothing:
npx @electron/fuses read --app /Applications/Claude.app
EnableNodeCliInspectArguments is Disabled
But the app ships its own escape hatch. The "Enable Main Process
Debugger" menu item calls node:inspector open() with no port, so it
listens on 9229 bound to 127.0.0.1. Source extracted from
index.chunk-jPKPzV-P.js:
function aX(){ return ce.url() !== undefined } // ce = node:inspector
async function y7r(){ ... ce.open(); await S7r() }
Attaching over CDP settles both remaining items.
1. The preload entry points were never missing, only unnamed.
webContents._getPreloadScript() returns:
main_window -> .vite/build/mainWindow.js
about:blank -> .vite/build/mainView.js
So the preload is the window script itself. Chapter 2 already analysed
both files without knowing they also serve as preload. This corrects
the earlier reading of REA's preload_entrypoints = 0: it means "no
file named preload", not "no preload mechanism". Chapter 2 now says so
at the point where it made the wrong claim.
The registration path is also clearer than the static picture:
app.registerPreloadScript is undefined, session.registerPreloadScript
exists but session.getPreloadScripts() returns [], and
getLastWebPreferences() omits preload because sandbox is true. The
windows pass preload through webPreferences at construction instead.
2. The app layer forks no utility process.
app.getAppMetrics() reports three Utility processes, all Chromium
built-ins: network.mojom.NetworkService, audio.mojom.AudioService,
video_capture.mojom.VideoCaptureService. A runtime hook on
utilityProcess.fork recorded zero calls.
Combined with the static finding that index.pre.js only wraps fork in
a Proxy for Sentry's MessageChannelMain bridge, this rules out reading
REA's utility_processes = 1 as a count of app-level processes. Recorded
as the third and last answer to that question; whether the bundled
pty-host, file-index-worker or heavy-work-worker scripts use
worker_threads rather than utilityProcess is left open because this
session never triggered them.
Runtime environment recorded alongside: Electron 44.9.3, Node v24.22.0,
app path pointing straight at the asar, sandbox and contextIsolation both
true with nodeIntegration false.
Chapter 6 gains section 6.7 for the runtime evidence, 6.8 and 6.9 shift
down, chapter 2 gets a correction note, chapter 7's unknown tables are
rewritten, and the merged edition is regenerated. Verified: 7 chapters,
0 broken links.
No runtime code, tokens or components are changed.
Chapter 7 listed five items as unknown. Three of them never needed a
running app; static extraction settles them, and the remaining two do
need a debugger.
1. --cds-rem-scale is never assigned.
Zero declarations in CSS, zero assignment sites in any JS. All 306
references take the var() fallback of 1. The official px-to-rem helper
in FindInPage-BDboRkUg.js confirms the intent:
lt = "--cds-rem-scale"
H = e => `calc(${e/16}rem * var(${lt}, 1))`
So it is a host-side density hook that the desktop app leaves unset.
Writing fixed px is still wrong: the value would not follow the hook.
2. The 12px vs 14px composer radius switches on data-density.
.cds-root -> calc(.75rem * scale) = 12px (compact)
.cds-root[data-density=comfortable] -> calc(.875rem * scale) = 14px
Only comfortable has an explicit block (3 of them); compact is the
default and never appears. The same switch covers radius--xs/sm/lg,
h-control*, icon, pad-*, gap-* and font-size/leading.
3. The "seven-stop non-linear mask" does not exist.
Nine mask-image declarations total, none with more than two stops:
four radial gradients for the Pulse dot knockout, one
linear-gradient(#000 0 0) for the shimmer clone's mask-clip:text, and
four single-edge hard cuts. Gradients with six or more stops: zero.
Two further findings along the way:
- The skeleton is also runtime-free. Across 551 JS files, SkeletonGroup,
placeholder-reveal-delay and skel-settled appear zero times, so
--cds-skel-reveal-end is always calc(.5s + .15s) = 0.65s. The only
data-hold hit in JS is data-hold-open, an unrelated Artifact menu.
- The scroll-fade token layer is registered but has no consumer in CSS.
Seventeen @property entries and eight keyframes exist, while the
.scroll-fade-y utility the find_in_page menu JS references is defined
in none of the nine CSS files, and no @utility or @custom-variant
exists to generate it. Reference without definition is recorded as a
fact; the cause is not guessed.
Two unknowns remain and genuinely need a debugger: the runtime filePath
passed to registerPreloadScript, and the utilityProcess.fork call sites.
Chapter 6 gains section 6.6 for these rulings, 6.7 and 6.8 shift down,
chapter 7's unknown table is updated, and the merged edition is
regenerated. Verified: 7 chapters, 0 broken links.
No runtime code, tokens or components are changed.
Completes the items left open in chapter 6 (was 6.3.1). Two results:
1. All 17 CSS files in the ASAR are now scanned.
17 files collapse to 9 unique contents (window-shared.css x4,
window-legacy-pins.css x4 and main-CiwjW8Wn.css x3 are duplicates
across windows). The keyframes union across all of them is 59, against
55 in the main stylesheet alone. The 4 extras are cq-fadeIn, cq-slipIn
(clawdQuestEngine, its own --cq-* namespace), shimmer (third-party
grid.js mermaid theme) and turn (file_viewer window).
So none of the 44 keyframes the repo is missing lives outside
MainWindowPage-BjVtjJFx.css. They are genuinely missing and must be
ported from the main stylesheet.
window-shared.css turns out to be a Tailwind v4 CSS-first entry that
imports "@ant/cds/theme.css", which has zero entries in the ASAR - it
is a build-time import already inlined into the main stylesheet. It
also documents a second, independent dark-mode path (--claude-* vars
plus .darkTheme) used only to prevent a light flash on first paint.
2. An official CDS spec document was recovered from the bundle.
index.chunk-CbnfBP-3.js embeds a 58,354-character markdown doc
generated by apps/cds-docs/scripts/gen-cds-skill.mjs from
packages/cds/{CLAUDE.md,docs/**}. It defines the six-layer token model,
the elevation table, the motion vocabulary, and the design rules.
The critical detail: official tokens are unprefixed (--surface-1),
while this repo uses a --cds- prefix. Stripping the prefix gives 131
names in common with our 210 --cds-* tokens.
Comparing those 131: 90 differ only by the prefix, 4 by unit spelling,
and 37 are real semantic differences. The ones that matter:
- text-primary/secondary/muted all resolve to the wrong values; the
official chain is neutral-N, which flips in dark mode, so
text-muted is darker (#6d6b67) in dark than in light (#898781)
- border-accent and text-accent are blue in the official spec,
because accent and brand(clay) are different roles; we use clay for
both
- shadow-popover is a pure two-layer drop shadow officially; we mixed
an inset ring into it
- radius-composer is 14px officially, we still ship the v1-era 20px
- gap-xl is 40px, h-control-nested is 22px, and five sizing tokens
are missing the --cds-rem-scale multiplier
This also corrects two earlier claims: v2 was right about
h-control-nested (22px) and gap-xl (40px), so the blanket rejection of
v2 in chapter 3 was too broad. And our --cds-alpha-* does flip to
white in dark mode, but alpha-2/3/4 opacity is off by 1/2/5 points.
Chapter files are renumbered so 06 is the new scan chapter and 07 is the
summary. README TOC, cross-links and the merged single-file edition are
regenerated and verified: 7 chapters, 0 broken links.
No runtime code, tokens or components are changed.
Re-anchor the CDS baseline from v2.37337.1 to the currently installed
@ant/desktop 3.6556.2, based on byte-level extraction from
/Applications/Claude.app/Contents/Resources/app.asar
(sha256 b2dfbbb40325d978dcb7561ad12a6f9bc199f8f46b7d3d2899af74ce8965d68a).
The v2 baseline is no longer valid: the version jumped a major, and both
files v2 cites (MainWindowPage-BD9CWQ83.css, index.chunk-BWk6pVUt.js) are
absent from the ASAR. The current main stylesheet is
MainWindowPage-BjVtjJFx.css (237,153 bytes).
Six chapters plus README, written to v2's chapter logic:
01 version boundary, forensic coverage, v2 -> v3 migration surface
02 Electron architecture (main/renderer, window topology, integrity)
03 skeleton, pill and scroll-fade mechanics
04 full manifests: 55 keyframes, 45 data-cds, 24 @property, color/time/radius
05 open-claude-ui diff audit and issue #25 rulings
06 certainty tiers, unknowns, REA tool feedback
Every claim carries code evidence: ASAR entry path plus byte offset, or an
exact CSS/JS excerpt, with a reproducible command. Items that static
analysis cannot resolve are marked unknown with the reason, not filled in.
Verified facts that change existing conclusions:
- skeleton sweep ground truth is 2s / linear / 105deg, confirming the
issue #25 direction; total keyframes are 55, not the 47 v2 claimed
- --cds-clay-emphasized is #c6613f in 2 declarations with no dark
override; v2 recorded #cc5a36 and the current code derives it from
--cds-clay-hover (#cc5a36 / #e08264)
- dark skeleton base and sheen are both
hsl(from var(--cds-neutral-900) h s l / 7.5%), i.e. a darkening,
while the current code uses white alphas at different strengths
- skeleton is a two-layer data-cds component (SkeletonGroup/Skeleton)
with a .cds-skel-sweep-band child element, not a ::after pseudo
- data-hold has three states (absent, none, delayed) and collapses
animation to .01ms plus display:none once revealed; neither the v2
docs nor the issue #25 branch implements this
- the main process registers 0 ipcMain.handle and only 6 ipcMain.on,
all in the Sentry SDK namespace; 0 new BrowserWindow
- 12 literal exposeInMainWorld API names exist in mainView.js
Truthfulness caveats recorded in the docs:
- REA 6.8.0 truncated semantic analysis for 532 files, so REA's own
summary fields are not used as primary evidence in chapter 02
- set-theory counts are self-checked (32 = 11 + 21, 55 = 11 + 44,
22 = 18 + 4, 45 = 18 + 27, 19 = 17 + 2, 24 = 17 + 7)
- v2 and v1 docs are not modified here; marking them historical is a
separate change
No runtime code, tokens or components are changed.
Token closure (code-examples/cds-theme.css)
- Define the five `--cds-dur-*` tokens (60ms/.12s/.2s/.3s/.45s) extracted from
`c6a992d55-sXiDGMFQ.css`. Undefined, `transition: transform var(--cds-dur-slow)
var(--cds-btn-spring)` was dropped wholesale by the browser and computed to
`all 0s`, so `.cds-btn-squish` never sprang back. Measured before/after:
`all / 0s` -> `transform / 0.45s`.
- Add `--cds-bg-neutral` and `--cds-bg-neutral-hover` (`.cds-root`, aliases of
`--cds-alpha-1/2`) so the user-bubble background chain resolves.
- Add the `--cds-fill-accent` alias chain down to `--cds-blue-450: #2a78d6`.
- Re-declare the bubble chain inside the dark block. `:root` resolves its own
`var()` bindings, so overriding `--cds-alpha-*` alone left dark bubbles at the
light value; dark is now `rgba(255,255,255,.05)`.
- `SegmentedControl` drops hard-coded `duration-120` for `var(--cds-dur-snap)`.
Scroll-edge fade (rewritten to the shipped implementation)
- Replace the local 8-stop/`animation-range: 0 48px` variant with the client's
three-layer model: `*-raw` carries geometry, `*-on` and `*-active` gate
visibility, and `--cds-scroll-fade-{top,bottom,left,right}` are the product.
Mask is the 15-stop gradient with the client's exact alpha ladder.
- Drop 17 duplicate `@property` declarations that shadowed the section above.
Motion presets (code-examples/ClaudeMotionPresets.ts, AGENTS.md)
- Correct `Observed use` from the bundle: 600/30 drives the mic/voice bar,
320/28 is a drag-release rebound (not an entrance), 1200/80/0.1 is the
`file_viewer` panel width. Exported constants are unchanged.
- Document `SPRING_GENTLE` as project-local: no client release contains
380/18, and `duration .32 / bounce .15` resolves to 244/26.6/zeta 0.85.
- Add the three client presets missing from this matrix (420/28, 260/16,
300/35) and record the v1.28 vs 2.42304.2 call-site drift.
docs/v2 gains 4.4 (spring matrix and the linear()/duration-token coupling).
docs/v1 is untouched: it is the v1.28 record, and the call-site drift is a
newer-release fact rather than an error in that volume.
- Scope WebKit 500ms post-composition guard in RichComposerWithMentions to Enter key only (fixes#20)
- Reset lastCompositionEndTimeRef on intercepted phantom Enter to avoid swallowing rapid follow-up typing
- Reset isRightCollapsed to false when Escape is pressed during pane drag in ArtifactsSplitPaneResizer (fixes#21)
- Restore previousRatioRef on collapsed wake-up button rather than hard-coded 0.5
- Update chapter 8 documentation and full specification to reflect scoped WebKit guard
- Update CHANGELOG.md under Unreleased
- Implement Chromium 115+ zero-JS @property scroll-fade engine in cds-theme.css
- Add code-examples/cds-pure.css standalone entrypoint and ./pure.css exports
- Add data-cds-scroll-fade attribute support to ScrollFadeContainer.tsx
- Document full 33-module catalog with runtime portability column in Chapter 7
- Add Section 7.5.3 Zero-JS Scroll-Fade Engine with measured performance in Chapter 7
- Update README and README-en with pure CSS architecture statement and token imports