v0.4: point at the word, and a recap that knows when to stop
One new thing you press, and a set of fixes to the thing you already press. The new thing is Feynman. The fixes are mostly about length: a recap that ran to ten points when it was asked for a handful, a retry that returned the same words, and sentences that ran together in Japanese.
Feynman: explain any phrase
Select a word or phrase — anywhere on the page, or inside the recap card itself — and a Feynman pill appears next to it. Press it and the card explains that phrase in one or two plain-language paragraphs.
A recap is bounded by the passage on purpose: inventing detail would be lying about what you scrolled past. But that is also why a recap cannot help when the thing you did not follow is a term the page never defined. It can say “the concerto opens without an orchestral exposition” three times without ever saying what an orchestral exposition is, because the page never said. Rewording that in simpler language changes nothing.
So this lifts that bound. The selected phrase becomes the subject and the prose around it is demoted to context — enough to fix which sense is meant, since “argument” in a logic paper and in a function signature are different words — and the model may supply the definition the writing assumed you already had. That output can be wrong in ways a recap cannot, which is why it is never generated unasked.
A recap could run to ten points when the prompt asked for a handful
Three separate things were wrong.
The prompt asked for a range. “2 to 4 points”
leaves the count to the model, and on a corporate-philosophy page
that says one thing ten ways, it settled that ambiguity by writing
all ten. It now names a ceiling. Chrome’s own Summarizer API
does not offer a range either — key-points
promises exactly 3, 5 or 7 bullets.
The parser accepted whatever arrived. It now keeps at most as many points as the passage earned, and drops any that repeats one already kept, compared by character trigram overlap so it works the same in Japanese as in English. This has to happen after generation because LiteRT-LM’s sampler exposes only topK, topP, temperature and seed — there is no repetition penalty to reach for.
The count is not fixed, because a fixed one is wrong in both directions: three points padded out of a short passage is the filler this was meant to stop, and three points for a four-thousand-pixel flick throws away most of what you skipped. It scales with how full the prompt actually got — 3, then 5, then 7, which are Chrome’s own tiers for short, medium and long.
Counting paragraphs was the first attempt and it fails at both ends. Keyed on the paragraphs that survived the prompt budget, a page of long paragraphs admits two of them and is judged short however far you scrolled. Keyed on the paragraphs you scrolled past, the model is asked for seven points about text it was never given. Two paragraphs of fifteen hundred characters carry as much as twelve of two hundred and fifty. Measured against the prompt budget instead, the question becomes “how much did the model actually receive”, which is the one reading that stays honest when the same character count carries different amounts in different languages.
A recap could stop mid-sentence. Generation now ends when three complete lines have arrived — a point boundary in any language — and the token cap went back to being what its name says: the thing that stops a stuck generation from holding the GPU, not the thing that decides how much you get to read.
Retry now means “say it differently”
Under greedy decoding the same passage produces the same words forever, so a retry that changed nothing about the request would be a button that does nothing. It now sends the previous points back and asks for a different way in — which is also the most direct pressure available against points that all open the same way.
Languages
The Translate button names the language it will give you — English, 日本語, Français — on both sides of the toggle. Gemma writes the recap in the language you picked, which means the button was almost never doing what its name said: there is nothing to translate into your language, because it is already in your language. What it actually offers is the other view, the recap in the language the page itself is written in. Labelling one side Original got that backwards — if either version deserves the word it is the page’s own language, not the one the model was asked to produce.
Japanese recaps ran together in the prose layout. The points
were joined with a space, which is a sentence separator in English and
not one in Japanese, and the model does not emit a trailing 。 of its
own. The result was one undifferentiated run of characters. The
separator is now chosen from the language the recap is in rather than
sniffed from the characters, because sniffing gets the interesting
cases backwards: a Japanese sentence about SamplerConfig
and repetitionPenalty is mostly Latin script and looks
like English, while one quoted kanji compound in an English paragraph
does not make it Japanese.
The card the host page can no longer restyle
The card is now rendered in a shadow root. It used to be a plain
<div> appended to the page, defended only by
all: initial on its outermost element — and that
is a normal declaration, which loses to !important
outright. Any host-page rule matching div,
span or * restyled the card’s
contents: a CSS framework’s preflight, a dark-mode extension, a
site with opinions about letter-spacing. Nothing about
how the card looks changed.
The two fonts now ship with the extension as subset
woff2 files, about 165 KB in a package that already
carries a 3 GB model. Every stack was previously Mac-first and
named Inter without shipping it, so the card fell back
to Segoe UI on Windows and the popup fell all the way to Arial. The
labels are 8.5–9.5 px, uppercase, with 1–2.4 px
letter-spacing, inside boxes of fixed pixel width; there is no
fallback that survives that. The bytes are handed to
FontFace directly rather than given as a
url(), so a page with a strict font-src
cannot refuse them.
The two layouts are no longer the same sentences twice. Each
recap point now arrives as label :: point: Smart shows
the label as a lead-in so the points can be scanned, Focus drops the
labels and runs the points together as prose to be read. It is still
one generation — switching layout regenerates nothing —
but Smart now earns the name instead of being the prose sentences
with numbers in front of them.
And “On this Mac” is now “On this device”, on the card, in the privacy line and in both status lines. It is shown to every user on every platform.
What still does not work
Search-results pages no longer produce a recap. They defeat every structural test in the extractor: result titles are links, which the link-density filter catches, and the snippet beneath each one is ordinary prose of ordinary length, which it does not. What came out was a recap of the search rather than of anything read. The major search hosts are now recognised directly.
Content selection still leans on class names. Boilerplate is
rejected partly by matching words like comment,
ad and related against an element’s
class and id. Hashed, CSS-module and camelCase names
(css-1x9k2p, styles_ad__a8f3,
commentList) match none of them. Prose held in
<div>s rather than <p>s, as
editors like Notion emit, is not extracted at all.
The walkthrough of how the whole thing works is in How Skim Recap works.