Skip to content

Integrate Liquid Parchment design language#2

Open
pauljunsukhan wants to merge 19 commits into
mainfrom
claude/awesome-jones-ed48cc
Open

Integrate Liquid Parchment design language#2
pauljunsukhan wants to merge 19 commits into
mainfrom
claude/awesome-jones-ed48cc

Conversation

@pauljunsukhan

Copy link
Copy Markdown
Member

Summary

  • Adds GlassSurface primitive (tint / intensity / radius / shadow / bloom / pressed) and a Liquid Parchment design system with ambient sun, device tilt, afterglow press feedback, and a breathing OwlLight halo.
  • Refactors ChatComposer to a plain Glass card with directional dispersion (warm coral rim + cool blue tint) and removes the browser focus outline on web.
  • Restores the warm radial halo behind the empty-state owl on both (drawer)/index.tsx and (drawer)/chat/[id].tsx.
  • Adds a /gallery route with frozen reference stamps so chrome compositions stay in lock-step with the running app.
  • Adds a viz suite (HeatGrid, Sparkline, RingStat, StatBar, EventDot) and Storybook scaffolding.

Note on conflicts

This branch is ~4 commits behind origin/main. There is significant overlap with recent chat / dashboard / design-token work on main, so this needs a careful review and rebase before merge.

Test plan

  • npx tsc --noEmit passes
  • / (new chat) renders empty-state owl with warm halo and plain-card composer
  • /chat/[id] empty state renders the same halo
  • /gallery chrome-composition stamps match the running app
  • Reanimated breathing animation runs on the OwlLight (web + native)

🤖 Generated with Claude Code

Paul Han and others added 19 commits May 2, 2026 08:09
Adopts a parchment-and-glass material vocabulary across chrome:
GlassSurface primitive (tint/intensity/radius/shadow/bloom/pressed),
ambient sun + device tilt physics, and a press-leaves-warmth afterglow.
Composer becomes a plain Glass card with directional dispersion;
empty-state owl gains a breathing radial halo (OwlLight) on web and
native. Adds a /gallery route with frozen reference stamps, a viz
suite (HeatGrid, Sparkline, RingStat, StatBar, EventDot), and
Storybook scaffolding for primitive isolation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removes the toolbar pencil button (long-press a tile enters global edit
mode instead), the tap-to-open-chat shortcut, and per-tile resize/move/
refresh handles. In edit mode tiles shake gently, gain a center pencil
(edit prompt), a delete X corner, and the banner offers a Done button.
Field-note tiles flatten to plain parchment Glass — no more category
tints or left-edge accent stripes — keeping the focus on the content
the prompt produced.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Top of board now breathes (paddingTop 18) so the heatmap card no longer
kisses the chrome capsule. Small status tiles tighten — display font
17pt with negative tracking so "now" / "91%" / "5" fit without clipping;
captions drop to 9pt with shortened mappings (src, ppl, mood, fresh).
Mood mini limits to three days at medium so the pill stack no longer
spills into the next tile. The back-of-card now renders a clean
"guardian read" commentary line keyed off the tile kind, replacing the
generic ASCII "what to inspect" frame — placeholder for the assistant
streaming this back in production.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The prompt composer used to render as a card at the top of the scroll
content. If you long-pressed a tile far down the board and tapped the
center pencil, the editor opened off-screen and you had to scroll up to
reach it. Now the composer is a backdrop+sheet overlay anchored to the
screen, slid in from below the chrome capsule, with the parchment
behind dimmed. The web focus outline on the textarea is suppressed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Anchored to viewport center with justifyContent: 'center' so the editor
sits naturally where the eye lands when you tap a pencil, regardless
of where the tile lives on the board.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Old curve swung opacity 0.78 -> 1.00, a 22% sliver of an already
half-transparent halo — easy to miss as static. Widen to 0.55 -> 1.00
with a synchronized 0.94 -> 1.06 scale pulse so the halo physically
expands as it brightens. Cycle drops to 4.5s for a more breath-like
cadence than the previous 6s drift. Reads as lung, not flicker.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previous swing (0.55-1.00 opacity, 0.94-1.06 scale) was correct in DOM
but invisible to the eye — warm peach overlay on warm parchment with
small modulation reads as static. Bump to a 5x opacity swing and a 40%
scale pulse, sync them, drop cycle to 3.6s. Halo now visibly inhales
from a faint glow up to full saturation and back, like a slow lung.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two design fixes that move the halo from "clipped sticker" toward
ambient light:

1. CSS radial-gradient defaults to farthest-corner extent — fades to 0
   at the diagonal of the bounding box, leaving a visible rectangular
   shoulder at edge midpoints. Switch to `closest-side` so the gradient
   ends at an inscribed circle; corners are simply transparent. Native
   SVG path uses r=0.5 for the same effect.

2. Single sin-pulse reads as mechanical. Layer two phases at 7s and
   12s — incommensurate periods whose interference pattern never quite
   repeats. Caustics' trick applied to a single light source. Pull the
   loud channel back to opacity 0.55-1.00 and scale 0.95-1.06; the
   restraint plus the multi-frequency wander is what sells "alive at
   rest" rather than the swing magnitude.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Four small fixes that all read as "designed", not "happens to render":

* Chromatic rim opacities pulled down ~60% (top 0.96 → 0.42, bottom
  0.46 → 0.18, sides 0.46 → 0.18) and stroke 1.6 → 1.0. The rim was
  meant to be a refraction hint half-cropped to a hairline; at the
  previous saturations it landed as a visible coral stripe on small
  surfaces. Now it's a faint warm/cool edge that reads as a real
  bevel rather than a stray line.

* ShellHeader switches tint="amber" radius=999 → tint="plain" radius="lg".
  Pulls the chrome capsule into the same vocabulary as composer + tiles
  so the whole app speaks one curve language instead of "pill on top,
  cards on bottom".

* Drawer's bottom-nav border-top removed. The line above "Field Notes"
  read as an accidental separator, not an intentional rule.

* Chat markdown's code_inline overrides the library default's box —
  transparent background, no border, just deepAccent + underline so a
  filename or path renders as a plain link instead of a boxed sticker.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The header was using tint="plain" which flattens the directional tint,
specular sheen, and chromatic rim — the very effects that make Liquid
Parchment surfaces feel alive. Switch to tint="gold" radius="xl"
intensity="medium": the chrome capsule now actively reads sun
direction (warm left, cool right), catches a diagonal specular
streak, and keeps a soft chromatic edge. xl (18) instead of lg (14)
gives the chrome a different curve from cards — hierarchy by radius.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… artifact

The gold/xl/strong header looked active but violated three of Apple's
HIG principles for Liquid Glass (iOS 26):

1. Tint should feel like ONE colored wash, not a gradient with bright/
   dark halves. Gold's hot rgba(248,196,72,0.26) -> cold rgba(120,84,28,
   0.16) span had enough contrast that the cool stop on the right edge
   read as a *separate surface* — what looked like an "inner pill"
   around the edit icon was actually the cold side of the directional
   tint.

2. Hierarchy comes from blur depth, not tint contrast. Apple's larger
   surfaces are MORE opaque, smaller surfaces clearer; here the chrome
   capsule is the largest single surface so it should lean opaque.
   Kept radius="xl" but bumped intensity to "strong" for that real
   frosted-glass body.

3. Buttons sit ON the glass, not in their own backdrop. The IconButton
   children already have no background, so the visible "pill" was
   purely from #1; eliminating directional tint contrast removes it.

Switched to:
  tint="plain"           — uniform warm-cream wash, no hot/cold split
  intensity="strong"     — heavier blur, more material presence
  rim={false}            — no chromatic edge fighting the body
  specular={false}       — no diagonal sheen creating visible regions

Result: a single, restful glass capsule that elevates the content
underneath instead of competing with it.

Sources consulted:
- Apple HIG navigation bars + tab bars (iOS 26 / Liquid Glass)
- Hierarchy/Harmony/Consistency principles (createwithswift)
- Tab bar anti-patterns ("don't design junk", Bootcamp/Medium)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Critical: every <Svg> inside GlassSurface (directional tint, specular
sheen, chromatic rim) was rendering at 300x150 — react-native-svg's
default size when no explicit width/height attrs are set. The
StyleSheet.absoluteFill style positions the element to fill the parent
but does not cascade dimensions into the SVG attribute layer; the
parent's CSS sizes the box but the SVG paints into its own viewBox.

On surfaces ≤300x150 (every tile in field notes, the composer, button
pills) this happened to be invisible because the SVG already covered
the whole surface. On the ShellHeader (336x48), the tint and rim
clipped at x=312, leaving the right ~24px of the capsule unpainted —
which read as a separate "inner pill" around the edit icon. The
exact UX bug Apple's HIG warns about.

Adding width="100%" height="100%" forces the SVG to fill its parent
in pixels, not the implicit 300x150 default. Verified via DOM probe:
all four SVGs (tint, specular, two rim Rects) now report 336x48 to
match the header.

Side effect: the ShellHeader can drop its `rim={false} specular={false}`
overrides — the previous "we're disabling these because they look
broken" was actually just the clipping bug. The full Liquid Glass
material physics now read correctly across the whole capsule.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
shellInner row used alignItems: 'center' which floated the buttons to
the vertical middle of an expanding composer — when the textarea grew
to 6+ lines the + and send sat halfway up the message body, away from
where the eye expects controls. Switch to alignItems: 'flex-end' so the
buttons stick to the bottom of the capsule regardless of text height.
Same pattern as iMessage / Slack / GitHub. Drop the now-redundant
alignSelf: 'center' on leadingBtn and sendBtn so they inherit the
parent's flex-end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous flex-end change made buttons hug the bottom of a 44px
input area, leaving them visibly low in the empty/single-line state
(button bottom at row bottom, not row center). Lower MIN_INPUT_HEIGHT
to layout.iconHit (36) so the input's natural single-line height
matches the button height — flex-end then renders identical to
alignItems: 'center' in that state. Multi-line behavior is unchanged:
text grows up, buttons stay anchored to the bottom.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The home screen IS the new-chat surface; the SquarePen "new chat"
button in the right slot was a noop in context — same screen, same
empty composer. Removing it leaves the header with just the menu
button, matching the visual restraint of the rest of the chrome.

The header itself is already consistent across screens (same
ShellHeader component on /, /dashboard, /chat/[id], /settings); each
screen contributes its own right-slot actions, no longer shadowed
by a useless self-link on the home screen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ng pulse

The previous +/send buttons were Lucide icons (three stroked lines)
on flat colored circles — two off-the-shelf pieces stuck together.
Replaced with a single integrated control that earns its place in
the Liquid Parchment system:

* Each disc is a real <GlassSurface> (radius=999 pill), so the same
  ambient sun + directional tint + chromatic rim machinery the rest
  of the app uses applies to the buttons too. Not a flat fill colored
  disc anymore.

* Glyphs are designed FILLED paths, not stroked icon-set imports:
    - Send: pointed tip, weighted shoulders, 6-unit stem, drawn into
      a 36-viewBox so it sits cleanly in the disc.
    - Stop: rounded square at the same scale.
    - Plus: two overlapping rounded rects so the caps feel cut, not
      stroked.

* Three states for the trailing button (idle / send / thinking) drive
  the disc tint: plain → gold → teal. When the agent is responding
  ("thinking"), a soft halo ring expands outward and fades in a 1.4s
  loop, while the disc itself breathes a subtle 4% scale at half that
  period. The same stop-square glyph stays put so the affordance
  doesn't change — only the motion tells you guardian is working.

* AttachmentButton is the leading-edge sibling: same GlassSurface
  recipe, plain tint, weak intensity, designed plus glyph. The two
  buttons read as one designed pair instead of "icon set on a circle".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…edit

The previous send/+ design used solid filled discs with custom SVG
glyphs — fine in isolation, but next to the menu / share / edit icons
in the top capsule it read as "default messaging app", not "guardian's
quiet notebook". The chrome icons are stroked Lucide at ~1.6-1.8;
filled discs clash with that serif-refined language.

Replaced both buttons with stroked Lucide icons at 2.0 stroke (slightly
bolder than the menu chrome — these are primary controls in the
composer's row, the family is the same but with a bit more weight).
No background disc, no GlassSurface — just the icon on the chrome.
Color follows state:
  idle     → placeholder muted (low contrast: "can't send")
  send     → text full (full contrast: "press me")
  thinking → deepAccent + slow opacity breath (in progress)
The thinking state swaps the arrow for a filled stop square so the
affordance changes too, not just the color.

Dashboard edit-mode also gets tap-to-dismiss: tapping a tile body in
edit mode now exits edit mode (pencil + delete X intercept first since
they're nested pressables), and a backdrop pressable on the empty
board area dismisses too. Drag-to-rearrange still pending.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The top capsule was reading as heavy on every flat-parchment screen.
On a backdrop with no atmospheric content for the BlurView to refract,
even weak intensity left a visible plain-tinted pill that competed with
the page rather than receding into it. The user-facing fix is what
should have been the structural one all along: there is no capsule.

The header is now just menu / title / right-slot floating directly on
the parchment. Same content, same layout — just no glass pane behind
it. Page is the material; chrome is the icons. The composer at the
bottom keeps its capsule because there it WRAPS an editable surface
where the capsule has a job (hosting the input). Up top there was no
input to host — just three icons and a title — so the capsule was
ornament that had become noise.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…lass

plain tint has a low-saturation cool-paper cold stop (rgba(212,222,232,
0.22)) that reads as a graphite-pencil smudge on parchment — the
mid-tone grays drag the surface from "glass" toward "paper with
shadow". cool tint anchors the cold stop in a lighter blue and the
hot stop in a pale daylight cast; combined with intensity="weak" (the
StatusPill primitive's recipe — the cleanest glass elsewhere in the
system) the chrome reads as a crystalline pane rather than a smudged
sheet. The rim and specular still fire so the bevel + sun-catch keep
the surface alive without the muddy mid-tones.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant