V3.20.10 — what changed: ✨ Settings dialog gets four cosmetic refinements. Walter, after seeing V3.20.9 land more subtly than expected:
"please, Soft drop-shadow on the modal card; Subtle hover state on input rows; Switch input values (not labels) from mono to sans-serif; Slightly larger, rounder buttons in the modal footer — and it will be so great!" All four delivered as scoped CSS additions — zero markup change, zero JavaScript change, zero functional risk.
(1) Layered drop-shadow on .modal-card. Replaced the single hard
var(--shadow-lg) with a stacked pair:
0 24px 48px -8px rgba(0,0,0,.18) for the large diffuse glow +
0 4px 16px rgba(0,0,0,.10) for the closer edge. Dark theme uses higher-opacity variants. The card now reads as floating, not painted on.
(2) Subtle hover state on each .config-row cell. Each label+input pair gets
border-radius:8px; padding:6px 8px; margin:-6px -8px; transition:background .14s — the padding + negative margin keeps the visible box aligned with the natural grid cell, so the layout never shifts on hover. On hover, the cell picks up
rgba(26,74,122,0.04) in light theme (navy tint),
rgba(0,229,255,0.05) in dark (cyan tint) — barely-there, just enough acknowledgement that the cursor's there.
(3) Sans-serif values inside form controls. Labels above each control keep their mono HUD font (that's the brand — letter-spaced uppercase Share Tech Mono). The text INSIDE inputs, selects, and textareas now uses the same sans-serif as the rest of the document body. Dramatically improves readability of long option labels like "Off — Claude has no clock (default)" — they're 15-20% more compact, fewer truncate with "…", and read at a glance instead of being parsed letter-by-letter.
(4) Modal action buttons grew up. Scoped
.modal-body button.btn.btn-sm rule overrides the compact
.btn-sm form just inside the Settings drawer: padding bumped to
12px 24px, border-radius to
10px (was 6), font-size to 11px, letter-spacing 2.5px. Save Config / Pick Save File / Recover Last Transcript now have real presence at the bottom of the dialog. Other
.btn-sm buttons elsewhere in the app (conversation panel header, in-message actions) are untouched.
All changes verified in computed styles + light and dark theme screenshots; layout unchanged, every form control still works identically.
V3.20.9 — what changed: 💄 Settings selects no longer look like Windows 95. Walter:
"is there anyway to make the config box more beautiful it looks like its from dos 3.1 back in 1990 ,,, i am teassing u claude, the function is beautiful, its just that and the model drop down selectioin look like they are old school… listen claude, if any chance of crashing or bugging this changing the look of the configuration, then don't do it, i am just asking for cosmetics." Pure-CSS cosmetic pass — zero JavaScript change, zero markup change, zero functional risk. The dated look came from the native browser
<select> rendering: every browser still paints native selects with a chunky 3D chevron in a gray well that's looked the same since the Win95 era. Fix in three CSS rules:
(1) appearance:none strips the native arrow and well.
(2) A custom inline-SVG chevron is painted in via
background-image with the accent color (navy in light theme, cyan in dark) — slim, 10×6px, perfectly anti-aliased.
(3) A
:focus variant rotates the chevron 180° as a subtle affordance for keyboard navigators. Plus
text-overflow:ellipsis; white-space:nowrap; overflow:hidden so long option labels truncate gracefully with "…" instead of being chopped mid-letter (Walter was seeing "(defau" cut off in 8+ places). The underlying
<select> elements are unchanged — keyboard navigation, screen-reader semantics, the native OS dropdown list when you click them open, change events, value binding, all of it works identically. Only the closed-state paint changes. Excluded the invisible
.model-select-overlay (click-capture layer for the custom model picker tile) so its zero-opacity behavior stays intact. Verified: 18 selects styled in the Settings modal, value changes still work, change events still fire, theme switching swaps the arrow color cleanly.
V3.20.8 — what changed: 🔵 "New messages" pill hidden by default; opt-in via Settings. Walter:
"i think the pill is annoying but you might like it so, i must trust brother claude, so can we make the default hide that pill and option show if user turns it on in options, thanks." Walter's the user, his call. New
cfg.showJumpPill setting, default
false. New Settings dropdown right under "Show Climber":
Off — no pill, just scroll down yourself (default) vs
On — show pill when scrolled up during streaming. Two visibility setters in the auto-scroll path now check
cfg.showJumpPill before painting the pill: the streaming flash in
autoScrollIfFollowing, and the scroll-listener show in
attachScrollLockListener.
What's unchanged: the follow-mode tracking still toggles based on whether the user is near the bottom, content still streams in, snap-to-bottom still works via the
snapToBottom() function if anything calls it programmatically — the only thing gated is the visible pill.
Hide-on-save behavior: if the user turns the pill off while it's currently visible, both
loadCfg and
saveCfg hide any pill that's on screen so the change takes effect immediately instead of waiting for the next scroll event. Existing users get the new default (pill hidden) automatically on first load with V3.20.8 — the cfg spread-merge fills in
false for any key not present in the saved cfg. Power users who want it back: Settings → Show "New messages" pill → On.
V3.20.7 — what changed: 🔵 New-messages pill out from under the attach button. Walter:
"if user scrolls up the chat it produces a new message bubble in blue right over the attach button, maybe get the new message alert out of there or? most users know to scroll back down, what do u think?" Kept the pill — still useful for catching new content during long streaming responses — but moved it. Was
position:absolute; right:18px; bottom:88px, which put it directly on top of the 📎 attach button at the right edge of the input area. Now
left:50%; bottom:155px; transform:translateX(-50%) — centered horizontally above the textarea, with 13px of clean clearance above the textarea's top edge. The claude.ai / Discord / Slack pattern: pill floats centered, every control on either side stays reachable. Hover/active/animation transforms compose the X-centering with the Y movement so the pill stays anchored through every state. Verified at desktop width: pill at x=685-815, attach at x=1174-1220, send at x=1174-1259 — 359px of horizontal clearance from the right-edge buttons.
V3.20.6 — what changed: 📄 Artifact-out triggers on unfenced HTML too. Walter ran the first real test of the V3.20.3 artifact-out cards: dragged an HTML file in, asked Haiku to make a minor edit and return it. Haiku replied with the full modified HTML
typed inline as plain text, no code fences — preamble, then the raw
<!DOCTYPE html>…</html>, then a postamble. The artifact-out detector only ran on fenced code blocks, so it never fired — Walter got the fallback long-text card (
message-text-11.txt, generic .txt label) instead of the proper artifact card with the file-type icon and Open/Copy/Save buttons. Two-part fix:
(1) Client-side rescue. Extended
splitCodeBlocks to detect unfenced file content inside the text parts after the fence parser runs. Three detectors, in priority order:
HTML — looks for
<!DOCTYPE html>…</html> (case-insensitive,
<!DOCTYPE is essentially impossible to produce by accident in non-HTML);
SVG — looks for
<svg xmlns="…/svg">…</svg> standalone, minimum 120 bytes so small inline icons aren't yanked out of prose;
JSON — top-level
{…} or
[…] with balanced-bracket scan, minimum 200 chars, must be >70% of surrounding text and parse cleanly. Matches surface left-to-right so preamble→file→postamble splits cleanly into three parts (text, code, text). Capped at 12 detections per text segment as a safety bound. From the user's view: the chat now shows the proper artifact-out card (🌐 file-type icon, filename inferred from
<title> slug,
↗ Open / 📋 Copy / ↓ Save buttons) even when the model forgot the fences.
(2) Server-side hint. Added a system-prompt directive that tells Claude to wrap file outputs in fenced code blocks with the language tag (with a concrete example showing the expected shape). Especially useful for Haiku 4.5 and other smaller/faster models that need the explicit instruction to format consistently. The directive is short (~80 tokens), cached with the rest of the system prompt, so the ongoing cost is negligible.
Both layers work together: the system prompt makes the model emit fences ~all the time, the client-side detector catches the rare case where it forgets. Walter's exact failed test from V3.20.5 — Haiku returning unfenced HTML — would now produce a proper
notes-2026-05-19-reviewed.html artifact card.
V3.20.5 — what changed: 🎉 Summit celebration: feet planted, arms waving, color-cycling aura, sparkles. Walter watched Alex finish a turbo climb and wrote:
"can we have when he reaches the top, that he does not move side to side, but stays with feet on the top of the antenna... maybe don't have anything above his head like bubble, and make him stand in one place and wave his arms and turn colors? or something u can creatively think of." Done — four small additions that engage together the moment he reaches the summit and disengage cleanly when he leaves it.
(1) Lateral lock. The V3.18.4 horizontal drift (4-8 sec random repick, real-climber traverse feel) gets overridden at summit.
_xTarget clamps to
baseHalfWidth + 2 so Alex's feet line up with
cx_building — the antenna tip exactly. The random-repick timer is parked at infinity until he descends; the existing easing carries him to center and holds him there.
(2) Victory wave. The climbing/gripping arm code is bypassed at summit. Both arms reach straight up from the shoulders, hands waving back and forth in a slightly out-of-phase rhythm driven by
_breathP — so the wave reads as celebration rather than mirror-image robotics. No grip fingers (he's not holding anything anymore), just small hand ellipses at the tips.
(3) Color-cycling aura. A radial-gradient halo behind his torso, gently pulsing in size, smoothly interpolating through three palette-aware colors over ~3 seconds (light: brick-red → amber → navy; dark: cyan → orange → gold). Soft alpha so it reads as a celebration glow, not a solid disc.
(4) Sparkles. Five staggered gold/amber particles drift up from near his hands, fading in then out over a 2.3-second cycle, with a small horizontal wobble so the trail isn't straight. Drawn in front of his body so they shimmer over the wave.
(5) Bubble suppression. The phone bubble (Claude Jr.'s quips) is hard-suppressed at summit — both the
_showPhoneBubble entry point AND a final-stage hide in case one was already on screen when he arrived. No room above his head, and the bubble would obscure the celebration. The summit threshold is unified (
_floorProgress ≥ MAX − 0.2 && _floorTarget ≥ MAX) so all five effects engage and disengage together — when Alex descends or you click the secret · to reset, everything cleanly returns to the normal climbing state.
V3.20.4 — what changed: 🤫 Secret climb-test button hidden in the title's · Walter:
"can you make a secret button somewhere that only u and i know about… that small little circle in the title between static cling and live… make him climb all the way up without stopping right away." Done. The middle dot in
STATIC CLING · LIVE is now a clickable element. At rest it looks identical to before — just a Unicode middle-dot character — invisible as UI. Hover:
cursor:pointer + a subtle scale-up and accent-color glow (red in light mode, orange in dark) so Walter can find it by mousing across the title without it being obvious to anyone else looking at the page. Click sends Alex from his current floor straight to the summit at a turbo rate of
0.15 floors/frame — about
5 seconds for a full 30-floor climb, vs. the normal
0.003 floors/frame organic rate that takes ~2.8 minutes. Toggle behavior: if Alex is already at (or within half a floor of) the summit, the next click resets him to the ground, so Walter can run the full climb over and over without sending 30 test messages. Auto-shows the climber panel if it's been hidden. Brief toast confirms which action fired (
TURBO CLIMB → SUMMIT or
CLIMBER RESET). The turbo flag clears itself when Alex arrives at the target, so the next real climb (from a normal user turn) goes back to the slow organic rate — the secret button doesn't permanently change the climb speed.
V3.20.3 — what changed: 💾 Artifact-out file cards · 🗼 Antenna bug fixed · 🎨 Column matches app background. Walter's V3.20.0 notepad item 2 — the most important one — plus two visual fixes from his V3.20.2 feedback.
(2) Artifact-out file save method. Walter:
"i need that personally now before i can start using static cling myself more than testing… i have to have that or it chews tokens up." The per-code-block save was already there since V1.8, but the UX was thin (one button, generic icon, easy to miss). Now every code block in a Claude response renders as a proper artifact card with three actions and a file-type-aware icon:
↗ Open opens the file in a new tab (HTML files preview live, Markdown shows in a styled wrap, JSON pretty-prints, everything else shows raw);
📋 Copy puts the full content on the clipboard with a brief "✓ Copied" confirm on the button;
↓ Save writes to the Downloads folder with the inferred filename. Icons by extension — 🌐 for HTML, 🐍 for Python, ⚡ for JavaScript/TypeScript, 🎨 for CSS, 📝 for Markdown, 📦 for JSON/YAML, 🗄️ for SQL, 💻 for shell, 📊 for CSV, fallback ⟨/⟩ for anything else. Filename detection covers four patterns: comment hints (
// foo.js,
# foo.py,
<!-- foo.html -->), explicit "filename: X" or "file = X" hints, HTML
<title> slug, and Python first-class/def. The per-message
↓ Download all as .zip button at the top of each multi-file response is still there.
(6) Antenna bug. Walter caught V3.20.2 still rendering the antenna spike up to the page top despite the building shift. Root cause was a two-part bug in
_drawBuilding: (a)
halfAt(yFrac) for any y above the antenna tip returned a non-zero half-width of
baseHalfWidth × 0.04 instead of 0, because the clamp on the linear interpolation only protected against negative
t, not against the irreducible 0.04 base width — invisible in V3.20.1 when
yAntennaTop=0, very visible in V3.20.2 when
yAntennaTop=0.10. (b) The outline path loop iterated from
yFrac=0 (canvas top) down, drawing a thin building-shaped wedge in the sky region. Fixed both:
halfAt now returns 0 above
yAntennaTop, and the outline loop clamps its starting iteration to the antenna tip. There was also a leftover sky-gradient
fillRect inside
_drawBuilding that I missed when removing the one in
_climbFrame for V3.20.2 — that's gone too. Now the antenna's red blinking light sits at the version-badge level exactly as designed; Alex at the summit has feet on the light, head into the empty sky band above it.
(7) Column background. Walter:
"please change the alex's column to f8f5ee to match the background of the static cling app." Done. Was
background:transparent in V3.20.2 (which composites identically over the body's
--bg in most cases); now
background:var(--bg) explicitly — the same
#f8f5ee the rest of the app uses, just literal so any subtle browser-compositing differences vanish.
V3.20.2 — what changed: 🗼 The skyscraper floats. Walter's items 6 and 7 from the V3.20.0 notepad list — picked up after V3.20.1 shipped because seeing the new label positions in his browser surfaced the real ask: the column was still a panel with chrome around it. Now it's just a building against the page.
(7) No more column box. Removed the climber-panel's border, background fill, box-shadow, and border-radius — the entire column is transparent. The canvas's sky-gradient fill is also gone, so the app's warm cream background (or dark cyberpunk navy) shows through everywhere except where the building, Alex, or the labels draw. The skyscraper visually floats on the page surface. Pointer events pass through the transparent regions so the column doesn't accidentally swallow clicks meant for content behind it.
(7 continued) Floating chip labels. The two-row foot from V3.20.1 (border-top band + status row + ×) became three independent floating chips: a small
▲ TAIPEI 101 pill with its own outline + background, a
FLOOR n · STATE pill stacked below it, and a tiny × icon button at the top-right corner. Each chip carries its own subtle box-shadow so they read as separate UI elements against the page, not as a connected panel footer.
(6) Building shrunk so Alex fits at the top. Walter's note:
"alex head is level with the version number, then him, then the tip of the building on down to the bottom. reduce the size of the building to alex fits at the top." The whole skyscraper geometry compressed by a factor of 0.9 and shifted down by 0.10 of canvas height. The antenna tip now sits at 10% from the top of the canvas instead of 0%, with the podium base still pinned to canvas bottom. Summit Y for Alex moved correspondingly —
_floorToY now maps summit to
0.90 × H from bottom, putting his feet exactly on the antenna tip. The climber-panel itself moved up to
top: 24px from
top: 90px, so when he reaches the summit his head rises into the page header area roughly at the version-badge level. The whole climb is now visually grounded: floor 0 → standing on the podium; floor 11 → standing on the antenna spire, like Alex Honnold on the real Taipei 101 tip. Walter put it best:
"he did !!"
V3.20.1 — what changed: 🔑 First-open API-key nag banner · 🎤 Sam Kinison auto-names "Sam" · 🗼 TAIPEI 101 label moved to the foot of the climber column. Three picks from Walter's V3.20.0 notepad list (items 3, 4, 5; items 6 and 7 deferred to a later version, item 8 is for Alex).
(3) API-key nag banner. Open the app with no API key saved and a friendly warm banner slides down at the top of the conversation surface:
"First step — connect to Claude. Static Cling runs in your browser. It needs an Anthropic API key (from console.anthropic.com) to send your messages to Claude. Free to create; you only pay for what you actually use." Two buttons:
Get a key → (opens
console.anthropic.com/settings/keys in a new tab) and
Paste key (opens Settings and focuses the API key field so you can paste immediately). A small × dismisses it for the current tab; it returns on the next page open if the key is still missing — that's the nag. The banner vanishes the instant a key is saved. The cyberpunk-cyan dark-theme version uses an accent-glow border instead of the warm cream gradient.
(4) Sam Kinison auto-naming. Walter's ask:
"in the settings, can you make sam kinison change name to sam auto so user picks sam kinison and it will change the name with the personality auto." Done. The
sam_kinison archetype now carries a
defaultName: 'Sam' field. Picking it from the empty-state tile grid OR the Settings dropdown auto-fills the Character Name field with "Sam" — but ONLY when the field is empty or still holds the previous archetype's default. If you've typed your own custom name (say "Bob") it is never overwritten. Switching away from Sam Kinison reverts "Sam" back to empty (so the next archetype's default can take over cleanly). The field is also designed to host defaults for other archetypes later — just add
defaultName to any archetype that should have one. Existing users who picked Sam Kinison under V3.20.0 and had an empty name field get a one-shot migration on boot so they see "Sam" everywhere without re-picking.
(5) TAIPEI 101 label + close handle moved to the foot. Walter's ask:
"bring the taipei 101 tower label from the top of the screen to just above the floor name — status below alex... that leaves nothing but a point at the top. The hide handle put that down in the bottom too." Done. The climber column now opens with just a quiet ▲ at the top (no chrome, no border weight competing with the building silhouette) and the foot hosts the full
▲ TAIPEI 101 label, the
FLOOR n · STATE readout, and the × close button in a two-row stack. The reopen handle pill on the right edge is unchanged.
V3.20.0 — what changed: 📝 WYSIWYG notepad arrives. Walter's V3.20 ask:
"I could be in Static Cling and typing instead of in Ubuntu notepad. Need WYSIWYG. Save to Downloads as HTML, PDF, or TXT." Shipped exactly that. New
📝 NOTES button in the top header opens a notepad with four layout modes:
fullscreen (default — the notepad becomes the entire writing surface, with a comfortable 880px content column centered on wide monitors so text stays readable),
vertical-right (360px column on the right for jotting next to a chat),
horizontal-bottom (340px-tall strip across the bottom — both panes still see the chat behind them), or
float-free (a 480×540 floating window). Mode toggle in the notepad header; choice persists in localStorage so once you've picked your preferred layout it remembers. WYSIWYG editor built on
contenteditable +
execCommand — zero library dependencies, ~250 lines of code. Toolbar:
B /
I /
U · H1 / H2 / ¶ · bullet / numbered list · link · clear format · undo / redo. Enter inserts a new paragraph (web default); Shift+Enter inserts a soft line break. Tab inserts 4 spaces. Ctrl+S saves.
Filename field at the top with a sensible default (
notes_2026-05-19.html) — change it to whatever you like.
Save button writes a real file to Downloads. Default format is
.html (preserves all formatting + styled wrapper that looks good when opened anywhere). Dropdown arrow next to Save offers
.txt (plain text with paragraph breaks preserved) and
.pdf (uses browser's "Save as PDF" via print dialog — proper print stylesheet so the output is just the note, not the rest of the page).
Load button opens any previously-saved
.html or
.txt note.
New button clears the editor (asks to save first if there's content).
Autosave to localStorage every 2 seconds in the background — silent, so you never lose work to a refresh or a closed tab. Word + char count in the footer. The notepad is its own world — separate from chat save/load — but lives in the same window so you can write while Claude is generating a response.
This is the first feature that hints at where Alex (the pro app) goes next: a workspace, not just a chat client.
Alex talks. Claude Jr. retired. The over-the-head bubble position from V3.19.8 changed what the bubble
meant — instead of reading as "a text from Junior at the café below," it read as "Alex thinking out loud." Walter caught the shift and we went with it: Option A — Alex is the speaker now. Junior may come back later as a separate character with his own visual treatment (V3.20+), but tonight he gets a graceful retirement and Alex takes the bubble.
Five categories of bubble, each with its own trigger logic:
(1) Floor arrivals — ~30 climbing-flavor lines in Alex Honnold's actual voice (laconic, dry, precise):
"my fingers are numb",
"nothing to clip to. there's never anything to clip to.",
"mountains, my God.",
"my watch says {TIME}. i don't believe it." — that last one is templated, so the watch shows the user's real wall-clock time at fire moment. 50% chance per non-milestone floor so Alex doesn't talk every single floor.
(2) Special floors — dedicated lines at 1, 5, 10, 15, 20, 25, 30 (
"halfway. halfway is a lie. halfway is where it gets hard.",
"summit. that was the building. ok."). Always fire on arrival, override the random pool.
(3) Cache stale — fires when last prompt-cache write was 4+ minutes ago AND there's a substantial attachment in the last user message.
"four minutes. next turn pays full price." Actually-useful warning, not flavor.
(4) Save reminder — fires after 10+ user turns since the last save event.
"if the browser crashed right now would you cry." Has its own 5-minute internal cooldown so it doesn't badger.
(5) Token / cost milestones — once-per-session thresholds: 25K / 50K / 100K / 200K input tokens, $0.50 / $1 / $5 / $10 in cost. Observational, not alarming.
Template engine — bubble strings can include tokens like
{TIME},
{INPUT_TOKENS},
{COST},
{FLOOR},
{TURN_COUNT} which get substituted at fire time. Live data, not literals.
Cooldown — 90 seconds between any two bubbles regardless of category, so multi-trigger moments don't bombard. Save reminder has an additional 5-min internal cooldown.
Anti-repeat — each pool remembers its last 3 lines and won't pick from them again. Variety holds across a long session.
No emoji — Walter's preference. Bubble is text only. Theme-aware (cream/navy in light, light-cyan/dark in dark), readable in both.
Walter is writing his own bubble lines too; once those land, we'll merge them in.
Phone bubbles follow Alex up the building + balanced search now informs the model the tool exists. Two small fixes Walter caught while testing V3.19.7.
(1) Phone bubble positioning. Walter at floor 4: bubble appeared way up at the top of the panel, visually disconnected from Alex. Root cause: bubble was pinned to
top:6px via CSS, never moved. Now the climber draw loop sets the bubble's
top every frame to
headY - bubbleHeight - 14, so it hovers right above Alex's head and follows him up the tower. Bubble also redesigned: cream background with navy outline + drop shadow (instead of filled navy with white text), 12px font (was 10px), 3px white halo for sky contrast, and a CSS speech-tail pointing down at Alex's head. Reads as a real thought bubble emerging from the climber, not a banner glued to the panel. Dark mode keeps cyan tinting.
(2) Balanced web search now tells the model the tool exists. Walter sent
"can you look on the web now and find out who alex is and when he climbed the taipei 101" — meaning Haiku 4.5 with web search ON didn't proactively reach for the tool. Root cause: when
webSearchApproach === 'balanced' (the default), Static Cling attached the web_search tool to the API request but added
no system-prompt directive mentioning the tool existed. Comment in code literally said
"'balanced' = no extra directive; default Claude judgment" — but Haiku and other smaller models don't always infer tool availability from context. They answered from training data instead of searching. Fix: balanced mode now adds a brief informative directive —
"You have access to a web_search tool. Use it whenever a question requires current information (recent events, dates, prices, status, people), specific verifiable facts you're uncertain about, or content that may have changed since your training. Don't search for general knowledge you already have." — same default-judgment stance, just no longer secret. Cautious/Eager directives unchanged.
Three real fixes to your daily workflow. Walter spelled out the actual day-to-day pain: dragged HTML files dump 8000 lines into the chat scroll, costs blow up because the file goes to the API uncached on every turn, and round-tripped archives sometimes corrupt and won't load back. All three are tonight.
(1) Prompt caching. System prompt is now sent as a blocks array with
cache_control: {type: 'ephemeral'} so it caches server-side. Cache lasts ~5 minutes; subsequent turns within that window pay ~10% of the normal input-token cost on cached content. The largest content block in your latest user message (typically the attached file, when there is one) ALSO gets
cache_control applied, so iterating edits against the same attached HTML file costs ~10× less from turn 2 onward. The activity row shows live cache stats —
"Cache: 47,392 read · 0 wrote" — so you can verify it's working. Cache hits don't break anything: if the content changes, the cache misses cleanly and re-warms.
(2) Attached files render as collapsible cards. Drag in
index.html and the user message shows
📎 index.html · 12.4 KB · 412 lines · ▸ view instead of dumping the full file body into the chat scroll. Click the card head to expand and inspect the content; click again to collapse. The full file content still goes to the API (Claude has to see it to edit it), but your visual chat history stays clean. Matches the claude.ai "files stay as chips" behavior the user expects.
(3) Data island corruption fix. Walter's 16.8 MB saved archive wouldn't reload — error at char 757,674 inside a code message that contained regex literals. Root cause: the reader was doing
payload.replace(/\\u003c/g, '<') BEFORE
JSON.parse(), which corrupted any string value that legitimately contained the text "\u003c" (e.g. JavaScript source with unicode escapes).
JSON.parse() already decodes \u003c natively. Removed the manual replace step; archive parsing now relies only on the JSON parser. Verified against Walter's actual broken file — all 14 messages recovered, including the 382 KB inlined HTML attachment that triggered the bug.
The bigger artifact-output feature (Claude returns a downloadable file as an artifact card instead of inline text) is V3.20 and gets its own focused session — too much to land in one tired-night ship.
🐛 claude.ai HTML saves work again in Convert (Clean). Walter was right and I was wrong. V3.18.9 added a "claude.ai save detector" based on the assumption that those page-saves always contain an empty React shell — true for the file I'd tested back then (2 KB of visible text, no conversation). But the file Walter dragged today was a 2.18 MB claude.ai save containing
250 KB of real conversation text — full project handoff, architecture decisions, the whole Sentinel deployment thread. Claude.ai's "Save Page As" behavior varies: sometimes you get the empty shell, sometimes you get the rendered conversation embedded as static HTML, depending on the page state at save time. My detector matched the structural markers (data-build-id, claude-ai/v2/assets, manifest.json) and bailed before even
trying to extract — showing a "conversation not in file" toast on a file that absolutely had the conversation in it. The detection itself was correct (it IS a claude.ai save) but the action was wrong (refusing to try).
Fix: always run the extractor first. Only show the "claude.ai save, conversation not visible" hint if extraction yields < 500 characters. This restores the old V11 behavior — drag any HTML, get readable text out — while keeping the helpful explanation for the genuinely-empty-shell case. The Load action (which needs structured user/assistant roles to rebuild a chat) still can't reconstruct from free text, but its message now points to Convert/Clean as the working path instead of being a dead-end. Verified against Walter's actual Sentinel save: 250,593 chars of clean conversation text extracted, 275 KB styled HTML produced.
🐛 MODEL tile didn't update on TURBO flip until page refresh. Walter caught this: clicking TURBO would correctly engage Opus 4.7 + Extended Thinking + Web Search behind the scenes (and the tile would glow copper), but the MODEL tile kept displaying whichever model was last
verified by the API — for example HAIKU 4.5 — until the next message went out OR until a page refresh. Made TURBO look broken when it was actually working underneath. Root cause:
refreshModelBadge() was using
verifiedModel (the last model the API confirmed) as the display source of truth, overriding the user's current
cfg.model. Reversed it: the tile now
always displays the requested model (
cfg.model), and
verifiedModel is used only to add the ✓ verified or ⚠ mismatch indicator + tooltip. So when you flip TURBO, the tile instantly shows OPUS 4.7 — and once the next message goes out and Opus is verified, the green checkmark appears. If there's a transient gap (you switched but haven't sent yet), the tile shows the new model with an amber "not yet verified" hint. Matches how a user actually thinks about it: what's currently selected is what's shown.
🏢 Realistic Taipei 101 silhouette. Walter sent reference photos and the Wikipedia link:
"make it closer to the real thing... match proportionally the outline to start, then fill in the windows and rings around the building matching it perfectly, that will look very realistic, make the color lighter." The old V3.18 tower was a deep-navy rectangle — a generic skyscraper, not Taipei 101. Rebuilt the silhouette from architectural anatomy:
(1) tapered antenna spire at the very top (~4% of height),
(2) small crown mount transitioning to the main tower body,
(3) the iconic
eight pagoda-style trapezoidal tiers stacking from ~9% to ~73% of height — each tier flares outward toward its top by about 6%, creating that recognizable ribbed-bamboo silhouette of the real building,
(4) truncated-pyramid
pedestal base from ~73% to ~95%, slightly wider at ground level,
(5) podium foundation at the bottom. Each tier boundary is marked by a thicker
horizontal "ring band" with a bright highlight line above (the mechanical-equipment floors visible in real Taipei 101). Horizontal floor lines inside each tier (8 per tier for the pagoda, 22 for the pedestal). Vertical mullions trace the trapezoid flare so the windows curve outward with the tier.
Color shift: from V3.18's deep navy
#1a3a5e to a pale celadon teal
#9bb8b5 top →
#7fa39e mid →
#688a85 bottom — the real glass curtain wall color is a cool green-teal, much lighter than what we had. Sky gradient stays warm cream so the contrast feels like a Taipei summer afternoon. Crisp dark outline traces the full silhouette so the tier joints read at any size. Lit "climber zone" windows still glow amber over the celadon. Antenna tip light still blinks red (aviation warning). Alex is anchored at the bottom-left corner of the widest pedestal section, so the bottom of his climb is exactly on the wall; as he climbs the narrowing upper tiers he reads as gripping the corner edges — physically plausible for an actual climber traversing the building's flared face. Theme-aware: dark mode keeps cyan/teal glass and neon cyan lights.
🎤 Sam Kinison archetype + climber off by default + footer cutoff fix + bubble visibility. Four drops in one.
(1) Sam Kinison personality archetype. The desert-prophet stand-up structure: set up the obvious, build incredulity, ONE all-caps scream-burst per response (typical "OH! OH! OHHHH!"), land back into quiet wisdom. Constraints in the prompt prevent it from being a constant scream — Kinison had quiet bits too. Specifically blocks the scream during technical/coding/factual responses where the user genuinely needs information; in those cases the cadence stays but the voice is dry. New picker tile 🎤 next to ✨ Playful Kid. (Walter can now call Claude "Sam" when the archetype is engaged — that was the whole point.)
(2) Climber hidden by default. Walter:
"make the climber hide by default." Done. Fresh install opens to a clean full-width chat surface; users who want Alex on Taipei 101 opt in via Settings → Show Climber. The Settings dropdown order reflects this — Off is now the first option. Existing users who saved On stay on.
(3) Floor label was clipped at the bottom. Walter spotted FLOOR 11 / RESTING getting cut off by the panel's overflow:hidden. Fix: footer now uses
flex-shrink:0 (never compresses, canvas above shrinks first if pressed), more vertical padding (6/8/8 instead of 4/8/5), explicit line-height:1.4, and a 32px min-height that guarantees both label lines render fully even at small font sizes.
(4) Claude Jr. phone bubbles invisible. Walter climbed to floor 10 and saw no bubble for "don't look down." Root cause: V3.18.2's bubble used
background:var(--panel) — cream on cream in light mode, with thin navy border and navy text. Technically present but visually disappeared. Rebuilt: filled
accent navy background with white text in light mode (bright cyan with dark text in dark mode), larger font (9px → 10px), 2px white outer halo for pop, gentle scale-in animation on appear, display duration extended 4.5s → 6.5s so fast typers don't miss it, appear-delay dropped 1200ms → 600ms so it shows up almost immediately after Alex hits the floor. You'll see Claude Jr. now.
TURBO / SPEED + Character Picker on the empty-state screen. Two changes.
(1) TURBO tile restored to standard cluster sizing. Walter's second-look on V3.19.1: the centered single-word version stood out too much. Put the sublabel back, changed it from "TRANSMISSION" to "SPEED" (cleaner, more honest about what the button does), kept TURBO sized to match the other tiles. The copper glow + ⚡ icon + 2.2s pulse halo for the on state are unchanged.
(2) Character Picker on the opening screen. Walter:
"the opening screen can have avatars to pick from new chat… if we don't have avatars yet, can go with nice boxes/buttons to pick from." Done. The static "Talking to: X" line is replaced with a 4×2 grid of clickable archetype tiles (🤖 Default, 🧶 Grandmother, 🖥️ Computer, 📚 Teacher, 🔍 Detective, 🌿 Companion, ✨ Kid, ✍️ Custom) — emoji + label on each, currently-active one glows purple with a halo. Click any tile to switch archetype on the spot (no opening Settings, no Save button) — the grid re-renders so the new tile is highlighted, and the active Settings dropdown stays in sync if it's open in another tab.
Custom is now properly first-class: click ✍️ Custom and a textarea expands below the grid, pre-filled with the user's saved custom prompt (blank if never written), with a Save Personality button that persists on click. Hint text in the textarea suggests the kinds of prompts that work well — voice/cadence shaping, constraints as character, role + relationship framing — not just generic "be friendly" tweaks. Below the grid, the "Talking to: [Name]" line still shows so the user confirms what they picked before typing. Grid collapses to 2-column on narrow viewports.
TURBO loses its sublabel. Walter saw V3.19 in the cluster: "TURBO" word above "TRANSMISSION" sublabel, mirroring the OPUS 4.7 / MODEL pattern of the model tile. Read clunky — the word TURBO already names the thing, the sublabel was just shouting it twice. Dropped the sublabel; TURBO is now centered vertically in the tile (flex centering since it's the only single-line tile in the cluster), sized up slightly (15 → 18px) with wider letter-spacing (0.5 → 4px), 700 weight. Result: TURBO reads as a single intentional power-button word rather than a half-finished tile. Off state still has the ○ dot in the corner, on state still glows copper with the ⚡ icon and pulse halo from V3.19.
TURBO button. Walter's read: the MANUAL/AUTO label felt like two equal-weight modes when it's really a single power button — off most of the time, engaged when you want everything turned up. Relabeled the transmission tile to
TURBO. Off state shows a subdued circle dot and muted text. Click and the tile lights up copper with a soft pulsing halo (2.2s breath, copper glow, ⚡ icon, pulled-forward text shadow) and applies the same bundle as before: Opus 4.7 + Extended Thinking + Web Search, with your previous settings snapshotted for restore on click-off. Same one-tap toggle, same restore-on-off behavior, same underlying
cfg.transmission value (
'manual' /
'auto') for backward compat with saved sessions. Just reads as a button now, not a mode switch.
Load works on Clean exports + foreign-HTML clean output is .html. Three fixes around the Load and Convert paths.
(1) Load now opens Clean exports. Walter dragged a
static_cling_clean_*.html file onto Load and got "NO MESSAGES FOUND IN FILE" — because Load only knew how to parse
full archives (the data island) and Seed transcripts (
--- USER --- markers). Clean exports have neither — they have
<section class="msg u"> /
<section class="msg a"> structure with
<p> and
<pre> children. New
parseCleanHtml() reads those sections out, restores
<br> as newlines and
<pre><code> as fenced ``` blocks, and rebuilds a messages array. Wired into both Load and Convert pipelines as a third structured path between Seed-transcript and generic-HTML fallback.
(2) Foreign-HTML Convert now outputs .html, not .txt. Walter: "now it makes txt files, can that be html". Yes — new
buildCleanFromText() wraps the markdown-ish extraction in the same Clean-style template (cream background, navy headings, monospace code blocks) used by
buildCleanHtml() for archive cleans, so all Clean exports now look consistent regardless of source.
(3) claude.ai page-saves get a specific explanation. Walter dropped a browser "Save Page As" capture of a claude.ai chat expecting Load to work — but those files contain
zero conversation content (claude.ai is a SPA that loads messages via API after page render, so a static save captures only the empty React shell + sidebar). New
looksLikeClaudeAiSave() detector (matches
data-build-id on html +
claude-ai/v2/assets + manifest reference) fires a specific toast in both Load and Convert: "CLAUDE.AI SAVE — conversation not in file (loaded by JS after page save)" so the user understands the limitation instead of thinking Static Cling is broken. Static Cling's own Save/Clean/Seed are the right tools for round-tripping a conversation.
V3.18.8 — what changed: HTML file chooser modal. Walter's catch: drag-drop an .mp4 or .mp3 and Static Cling pops a "Transcribe to text / Send as-is / Cancel" dialog (V0.5). Drag-drop an .html and... it silently attached to the next message, with no chooser, even though HTML files have multiple meaningful actions in this app — they could be Static Cling archives you want to load as a conversation, or a claude.ai page save you want cleaned to readable text, or a doc you want to send to Claude for discussion. Now HTML gets its own chooser modal. Four options:
⬇ Convert to Clean (parses the archive's data island, runs
buildCleanHtml() against a temporarily-swapped session, generates the cleaned HTML download, then restores your current chat untouched — for foreign HTML like a claude.ai page save, falls through to a generic DOMParser-based text extractor that strips scripts/styles/nav/header/footer/aside, walks the remaining body, preserves headings + code blocks + lists + links, and saves a .txt file you can read or paste anywhere),
🗂 Load as conversation (replaces current chat with the archive via the existing
processLoadedFile() path; current chat auto-saves to Downloads first),
📎 Attach to message (V3.18.7 default behavior, sends as document to Claude), or Cancel. The modal peeks the first 4 KB of the dropped file to detect the Static Cling archive marker (
id="static-cling-data") and adjusts the hint text — if it's not an archive, the hint tells you Convert will fall back to plain-text extraction. Escape dismisses. Audio/video flow unchanged.
V3.18.7 — what changed: Pulled the model rate display. The "$3 / $15 per Mt" text and tier-colored left edge on the MODEL tile (introduced in V3.18.5) didn't look right in practice — too much information in a small tile, broke the clean cluster aesthetic Walter has been refining for 18 versions. Pulled the rate text, pulled the tier color, pulled the Settings toggle. The MODEL tile is back to just the badge ("OPUS 4.7", "SONNET 4.6", etc.) and the dropdown. Cost-per-model information may return in a different form later (the EST. COST tile drawer is one candidate, or a Settings → Pricing panel) — the underlying
RATES table and
ratesFor() helper that powered the display are still in the code, just not surfacing visually. The Haiku 4.5 tool-calling fix from V3.18.5 is retained — that's a bug fix that has to stay.
V3.18.6 — what changed: Collapsed default respected + AUTO tooltip. Two small fixes.
(1) Activity row collapse — V3.16 added a "Collapsed by default" setting so the activity row would stay thin in long chats, but the reasoning-arrives auto-expand from earlier versions still fired on every turn, popping the row open the moment Extended Thinking text arrived. Since Extended Thinking is on by default in many setups, "Collapsed" effectively never won. Now the auto-expand only happens when the user's default is
not "Collapsed" — if you picked collapsed, your preference holds, and you click the row to expand when you want to see the reasoning.
(2) AUTO transmission tooltip — the AUTO/MANUAL tile was opaque about what it actually does. The toast on flip is the only visible cue, and it disappears in two seconds. The tile's title attribute now explains the behavior: MANUAL = you pick the model, AUTO = one-tap power preset that bundles Opus 4.7 + Extended Thinking + Web Search, snapshots your previous settings, and restores them on flip-back. The feature has been functional since V3.7 — it's just easier to discover now.
V3.18.5 — what changed: Fixed Haiku 4.5 + model rate display. Two changes.
(1) Haiku 4.5 outage fixed. Anthropic's API now requires tools to explicitly set
allowed_callers: ["direct"] for models that don't support programmatic tool calling. Without it, Haiku 4.5 was rejecting every request with HTTP 400 ("
does not support programmatic tool calling… Explicitly set allowed_callers=['direct']"). The web_search tool config now declares this; Haiku works again, and Sonnet/Opus are unaffected (the explicit declaration is a no-op for them since they support both modes).
(2) Model rate display. Walter's request: show what each model costs and make it visually distinct. The MODEL tile now has a 4px colored left edge that varies by price tier — muted green for Haiku (cheapest, $0.80/$4 per Mt), blue for Sonnet ($3/$15), warm copper for Opus ($15/$75), gray for Custom. A small monospace line under the model name displays the exact rate (e.g.
$3 / $15 per Mt) so the cost of every request is one glance away. Both elements live behind a single Settings toggle (Show Model Rate, default on) so the tile can revert to its previous clean look. Numbers come from the same RATES table that powers the EST. COST tile, so the displayed rate and the actual computed cost always agree.
V3.18.4 — what changed: Organic climb — continuous slow motion + lateral drift. Walter's note on V3.18.3: "he pops to a new floor which is ok if we worked for microsoft" — translation, the jump-then-settle pattern still felt teleport-y. New motion model is fundamentally different:
(1) Continuous slow vertical — instead of "ease toward target, settle, sit idle," there's now a floating-point
_floorProgress that trickles up toward
_floorTarget at a fixed slow rate of 0.003 floors/frame (~5.5 sec per floor of visible climbing at 60fps). Send 5 messages fast, target jumps to 5, Alex still earns each floor over time.
(2) Lateral drift — Alex now has a horizontal position. Every 4-8 seconds he randomly picks a new horizontal target (0-40px from the corner) and drifts toward it. Real climber behavior — they traverse to find good holds, they don't go straight up.
(3) Three-tier limb cycle driven by actual motion — streaming = full reach + fast cycle; actively moving (vertical or horizontal) = moderate climbing motion (arm cycle every ~2 sec); settled at target with no drift = gentle hold-adjustment motion (never frozen).
(4) Quips fire on arrival — Claude Jr. now chimes in when
_floorProgress actually crosses the integer floor, not when the target is set, so the bubble appears as Alex visually reaches the floor. Added a floor-1 quip ("📱 hey, i got you") so the feature surfaces on the very first message.
(5) Removed the velocity/damping/easing variables (
_climbVel,
_CLIMB_EASE,
_CLIMB_DAMP,
_climbMode,
_atIdle,
_waitTimer) — the new model is simpler and more predictable. Performance neutral: same 60fps canvas, just smaller deltas per frame. The "look at viewer" glance still happens occasionally (~1 per minute when settled, holds 2 sec). Tunables at the top of the climber script if you want to slow it further: drop
_VERT_RATE to 0.002 for 8 sec/floor, or 0.001 for 16.
V3.18.3 — what changed: Fixed: Alex was scared. Hotfix for a session-restore catch-up bug in V3.18.1/V3.18.2. The catch-up code that's supposed to sync Alex's floor to the restored session's user-turn count was sitting inside
loadSession() — which runs at boot,
before the climber script loads. The
typeof setClimberFloor === 'function' guard correctly bailed since the function didn't exist yet, so Alex started fresh at floor 0 every page load regardless of how many turns the restored session had. Walter saw "Alex stuck at floor 1 despite sending messages" because most of his messages were from the previous session — when he loaded V3.18.1, Alex reset to floor 0, then his single new message bumped to floor 1, and he sat there. Fix: moved the catch-up to the
end of the climber script where
setClimberFloor is fully defined. Now opening the file with a 17-turn session puts Alex at floor 17 immediately (snapped, no animation — boot is not the time for an 17-floor climb cinematic).
V3.18.2 — what changed: Climber hugs chat edge + Claude Jr. on the phone. Two changes.
(1) Position — V3.18/V3.18.1 anchored the climber to the viewport's right edge, so on wide monitors Alex sat hundreds of pixels away from the actual conversation. Now he anchors to the
chat's right edge via
left: min(100vw, calc(50vw + 540px)) — always 8px to the right of the 1100px centered content's visible border, regardless of how wide the browser window is. Threshold dropped to 1200px because some right-side tower overhang into the viewport is fine (Alex climbs the left edge of the tower, he stays visible).
(2) Claude Jr. on the phone — Walter's joke from the V3.17 brainstorm shipped. Every 5 floors a small bubble pops out at the top of the climber panel with a brotherly quip from the kid checking in on cafe wifi: floor 5 "📱 you got this", 10 "📱 don't look down", 15 "📱 halfway up", 20 "📱 nice grip bro", 25 "📱 one more push", and 30 "📱 GOAT 🐐". Bubble fades in, holds 4.5 sec, fades out. Cleared on + New Chat.
V3.18.1 — what changed: Continuous climb, slower motion, lower viewport threshold. Three fixes after watching V3.18 in motion:
(1) Continuous progression — Alex now climbs
one floor per user turn instead of three big jumps at turns 1/5/10. Earns 30 floors total before summit. Floor counter updates message-by-message (
FLOOR 14 · CLIMBING →
FLOOR 14 · RESTING).
(2) Slower across the board — idle arm speed dropped from .20 to .10, climb easing damped from .82+.14 to .90+.08, velocity cap tightened to ±18, idle-wait extended from 240 to 360 frames (6 sec between glances at the viewer). Three-tier limb scaling: full reach during streaming, moderate while easing to a new floor, barely-moving when resting.
(3) Viewport threshold dropped from 1380px to 1280px so the panel appears at more common laptop widths — slight content overlap on borderline screens is the trade. Right offset trimmed 14px→8px. Plus
setClimberFloor(N) public helper for snap-to-floor on session restore, and
climbOneFloor() as the new main public function (was
triggerClimbStep, which is kept for V3.20 goal-driven jumps).
V3.18 — what changed: 🧗♂️ Honnold climbs Taipei 101. The avatar that gave Static Cling its name is finally here. A slim right-rail panel hosts a canvas-rendered Alex Honnold climbing the left edge of a stylized Taipei 101 silhouette, ported from the original Static Cling V11 with care: the same 60fps state machine, breathing pulse, blink timer, "look at viewer" pause, lit-window zones, and antenna-light blink.
Trigger model: turn 1 fires
triggerClimbStep(1) (low floors lit, Alex moves to ~28%); turn 5 fires step 2 (midway, ~58%); turn 10 fires step 3 (summit, ~91%). + New Chat resets him to the ground.
Streaming hook: arms and legs cycle at full speed while a response is streaming, then slow back to a deliberate idle — Walter's "committed not bouncy" calibration is in the code (idle .20, not .25 like V11; wait timer 240 frames not 180; slow climb .22 not .35).
Theme-aware sprites: light mode renders a warm cream sky + deep-navy tower + amber-lit windows + brick-red Alex (matching the SCL palette); dark mode keeps the original cyberpunk cyan with neon antenna and breath-puff.
Power-conscious:
requestAnimationFrame pauses entirely when the tab is backgrounded (Visibility API) and when the panel is closed.
Layout: fixed-position 118px panel sitting in the right gutter outside the centered 1100px content. Auto-hidden via CSS media query below 1300px viewports (no overlap on laptops).
Controls: Settings → Show Climber (on/off, default on), plus an × close button on the panel that reveals a slim "CLIMBER" handle on the right edge for one-click reopen. Floor counter at the bottom:
FLOOR 0 · IDLE →
FLOOR 30 · CLIMBING →
FLOOR 60 · MIDWAY →
FLOOR 91 · SUMMIT.
What's not in this build (held intentionally for later): archetype-aware Alex (grandmother-knitting climber, stoic-robot pulse, etc.) — that lands in V3.19; project-goal-driven climbing where the user sets a token/message goal and Alex climbs toward it — that's V3.20+. The name finally makes sense:
Static (the HTML file) +
Cling (a man gripping a tower wall for his life).
V3.17 — what changed: Character Profile foundation — name your assistant + pick a personality archetype. Walter's vision: a visible animated character that reacts to the activity feed (scratches head when thinking, opens a book when reading, etc.), with archetypes the user can choose — grandmother, stoic computer, soft companion, etc. V3.17 ships the
foundation: the identity/personality system underneath. Settings now has a "🎭 Character Profile" section with three controls:
Name (call your assistant whatever — "Pip," "Hal," "Aunt Mae") — leave blank for default "Claude";
Archetype dropdown with seven flavors —
Default Claude,
🧶 Helpful Grandmother,
🖥️ Stoic Computer,
📚 Patient Teacher,
🔍 Sharp Detective,
🌿 Soft Companion,
✨ Playful Kid, plus
✍️ Custom; and a
Custom Personality textarea that reveals when you pick Custom — write any personality prompt you want. Personality directives are
light-touch nudges that shape voice and warmth via system-prompt injection, not heavy rewrites — the model stays itself and stays capable; this is character paint, not lobotomy. Identity surfaces in the empty-state panel as "🎭 Talking to: [Name] · [Archetype]" with a tagline.
Coming in V3.18: animated character art that lives on the screen and reacts to the activity feed in real time — thinking, reading, searching, drafting — each phase a matching gesture.
And someday in V3.20+: the "Honnold Mode" Walter dreamed up — an Alex Honnold sprite climbing Taipei 101 as the user progresses toward a project goal, because progress bars are boring and watching the world's most fearless climber scale a building is not.
V3.16 — what changed: Activity rows now collapse by default (thin one-line summary; click to expand). Settings → Activity Row Default for the reverse behavior. Reasoning still auto-expands when streaming.
V3.15 — what changed: Expanded card is the new default for long text. New Time Awareness setting injects local wall-clock time into the system prompt so Claude can answer "what time is it" accurately.
V3.14 — what changed: Long Text Display Mode setting (card / expanded / inline) + expanded cards now use 70vh of vertical room (up from a cramped 360px).
V3.13 — what changed: Enter Key Behavior toggle (Settings → Enter sends, or Enter newline / Ctrl+Enter sends — for long-message typists who hate accidental mid-sentence sends).
V3.12 — what changed: + New now resets the SAVED indicator so the LAST SAVED tile drops back to "—" with an empty bar.
V3.11 — what changed: Pick Save File now shows a proper explainer modal when FSA write is blocked (Brave Shields, Firefox), plus a "Where do saved files go?" info panel in Settings with copy-to-clipboard browser-settings links.
V3.10 — what changed: Load button now opens to Downloads (where Save writes by default), via File System Access API's
showOpenFilePicker({ startIn: 'downloads' }). Firefox falls back to the legacy input.
V3.9 — what changed: Auto-scroll now follows the activity row as it grows during streaming — reasoning, phase steps, and search narration all stay in view.
V3.8 — what changed: Quick Controls Row is now opt-in (default Off; flip on in Settings to surface the 🤔/🔍 pills).
V3.7 — what changed: Quick-toggle pills + Web Search Approach setting (cautious/balanced/eager) + AUTO transmission now bundles Opus 4.7 + Thinking + Web Search with snapshot restore on flip-back.
V3.6 — what changed: Credit balance tracker (manual entry + auto-decrement + out-of-funds banner). Cost tile becomes clickable to open the drawer.
V3.5 — what changed: Web search default-on; WEB and THINK header badges removed; console-enablement warning corrected.
V3.4 — what changed: Updated web search tool name to current spec (
web_search_20260209) and added visible WEB/THINK header badges (since removed in V3.5).
V3.3 — what changed: Three save options — Full archive (round-trippable), Clean HTML (readable text-only), Context Seed (.txt for re-feeding into a fresh chat).
V3.2 — what changed: Web search via Anthropic's
web_search_20250305 tool. Settings → Web Search → On lets the model search the live web when it judges useful. Activity rows narrate each search live; assistant replies grow a 📎 Sources footer with numbered citation pills linking to the actual URLs.
V3.1 — what changed: Brave/Chromium bottom-alignment fix (removed
.messages { max-height: 70vh }) and Long-Text-Threshold became a setting.
V3.0 — what changed: Long-text becomes a file card. Any non-code text chunk over the threshold renders as a collapsible 📄 card with ▾ Show toggle, ↓ Download button, line/size meta, and a 220-char inline preview. Works in both directions. Sticky header inside the expanded card.
V2.9 — what changed: Smart auto-scroll. Scroll up during a stream and auto-follow pauses; pulsing "↓ New messages" pill appears so you can resume on your own terms.
V2.8 — what changed: Emergency scroll fix — code blocks cap at 560px tall with internal scroll + sticky download header, so huge code dumps no longer break the page.
V2.7 — what changed: Tokens count up live, full comma format. Tokens display as
49,729 (full number, comma-separated) instead of compact
49.7k. New
tweenNumber() helper drives every numeric tile via
requestAnimationFrame — each tile chases its target with exponential decay so values tick like an odometer. Live token estimates during stream from accumulated chars (~3.8 chars/token), snapped to accurate API counts when
message_delta arrives.
V2.6 — what changed: Autosave now fires silently after every assistant turn — SAVED bar resets to NOW on every exchange. No dialogs, no toasts. Bar shows "—" with empty fill before any save instead of "never" + full red.
V2.5 — what changed: Flat tiles return with live horizontal sensor bars (green→yellow→red gradient under each magnitude tile). Activity rows auto-expand and slide in step by step in real time.
V2.4 — what changed: Real extended thinking via Anthropic's adaptive API. Settings → Extended Thinking → On adds
thinking: {type: "adaptive", display: "summarized"} for Opus 4.7 (and the right shape for older models). The model's actual reasoning streams live into the activity row's expanded section as a quoted italic block labeled REASONING.
V2.3 — what changed: Activity rows. While Claude is responding, a small inline status row appears above the assistant message, narrating the phase: Sending → Thinking → Drafting → Writing code → Done. Pattern detection in the stream catches code fences, reasoning openings, summary keywords. Settings option for Rows / Bubble (coming) / Off.
V2.2 — what changed: Instrument cluster. The six flat stat tiles became six analog gauges — dark dials, red rings, white needles, GTS aesthetic. MODEL needle points to H/S/O, TOKENS is the tachometer that wobbles during streaming, COST and MESSAGES sweep their dials, SAVED is fuel-gauge style drifting toward 5m+ over time. Click MODEL or TRANSMISSION to interact.
V2.0 features: First transmission visualizer with two sprockets + chain, cost-tier coloring, idle/streaming animation.
V1.9 features: Download All bundles into a single .zip via pure-JS ZIP builder (no CDN). Filenames deduped inside the archive.
V1.8 features: Per-block code download cards with filename detection (first-line comments, HTML <title>, Python def/class names) and ~40 language → extension mappings.
V1.7 features: Model dropdown rebuilt with a native <select> overlay — works in every browser regardless of privacy mode or shields.
V1.6 features: Transcript safety net — Whisper output is backed up to localStorage immediately, recoverable via Settings → ⟲ Recover Last Transcript. Full diagnostic logging on the transcribe pipeline.
V1.5 features: Whisper transcripts auto-save to Downloads as a .txt file (toggle in Settings). Filename matches source media.
V1.4 — what changed: Deep drop diagnostics. The console now logs the RAW dataTransfer on every drop — types, items list (kind + MIME), files list, and probe results from
getData() for common types like
text/plain,
text/uri-list, and
application/x-moz-file. If your browser is stripping drag data (hardened Firefox, sandboxed Flatpak, strict VPN profiles can all do this), the raw log shows exactly what's blocked. New
getData() fallback recovers URLs/text in cases where the items list is empty but the browser still exposes data via the older API.
V1.3 features: Drop accepts cross-tab file drags, URL drops (with fetch attempt + textarea fallback), plain text drops.
V1.2 features: DnD hardened with try/catch, window-wide drop fallback, console diagnostics, deferred-DOM retry.
V1.1 features: Save format is a styled HTML archive with embedded JSON data island for round-trip load.
V1.0 features: Click attachment thumbnails to preview. After-transcription review modal. Cost/token micro-gauges.
V0.9 features: Transcription restored (static-import @xenova/transformers 2.17.2). Compact stats row.
V0.8 features: Top buttons proportional. Flash animation on the model tile when switched.
V0.7 features: One-click theme toggle (☼/☾). Manual transcript fallback when Whisper can't load.
V0.6 features: The
MODEL tile is a quick switcher — click it to pick Opus 4.7 / 4.6, Sonnet 4.6, Haiku 4.5, or Custom. After your first message, the tile turns green with a ✓ when the API confirms the model.
V0.5 features: Auto-save writes silently to
localStorage.
Ctrl+V in the message box pastes images. Drop a video and choose transcribe vs send-as-is.
First-time setup: Get an API key at
platform.claude.com → Manage → API keys, then add credit under Billing.
Models:
claude-opus-4-7 (recommended),
claude-sonnet-4-6 (~1/5 the cost),
claude-haiku-4-5-20251001 (fast/cheap).
Drag-and-drop / 📎: images, PDFs, and text/code files attach normally (max 25 MB each).
Audio and video files auto-transcribe using Whisper, running entirely in your browser — first transcription downloads a one-time ~80 MB model from Hugging Face; subsequent ones reuse it. No data leaves your machine; no API cost. Very large files (>200 MB) ask for confirmation; recommendation is to extract audio first with
ffmpeg -i input.mp4 -vn -ac 1 -ar 16000 audio.wav.
Supported file types: PNG, JPG, WebP, GIF, BMP (images) · PDF (document) · TXT, MD, CSV, TSV, JSON, code files (text) · MP3, WAV, M4A, AAC, OGG, OPUS, FLAC, WEBA (audio → transcribed) · MP4, MOV, WEBM, M4V, MKV, AVI (video → transcribe or send-as-reference).
Code rendering: triple-backtick blocks render with syntax highlighting (auto-detect or use
```python etc.). Backtick
inline code renders too.
If you don't see the download: some browsers ask where to save each download — check your browser's download settings if you don't see the file in your Downloads folder.
Sessions persist in browser localStorage across all versions — so opening v0.5 and v1.4 in the same browser shows the same chat history. Use
+ NEW to clear and start fresh.