Add an abstract moon face to compare against the lunar photo#261
Merged
Conversation
The moon is the app's only photograph, in a UI that is otherwise gradients and line icons. Its crater detail also gives the eye something to examine on a surface whose whole job is somewhere to rest, and at the sizes the disc actually renders - 80px for a phone intervention, ~42px for the resting companion - that detail falls below the pixel grid and reads as grey noise, i.e. a duller disc rather than a richer one. So: an alternative face built from gradients alone, behind a `.minded-moon-abstract` ancestor. Opt-in only - nothing in the app sets it, only the styleguide, so the shipped moon is untouched until we pick one. What it has to keep is that the moon reads unmistakably as the moon, never a dimmer sun, or the evening cue it carries says nothing. The recognisable cue at a glance is the maria shading, not the craters - but the tidy version of that (a pair of fields up top, one below) becomes a smiley face at 42px, so these are big overlapping asymmetric pools instead, following the real near-side's lopsided look. To compare: - Styleguide > Interactions > "Moon face - photo vs. abstract" puts both at the three sizes the disc really renders, on a fixed night backdrop (a moon can only be judged against a dark sky). - The sun stage below it gains a `face` toggle, since what actually decides this is how each face holds up *through* the morphs, not at rest. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CbXxMDVD22xYwHq5pd4XtR
The gradient moon was the original look, and the history says it lost twice already: #92 replaced it with a photo and was reverted by #93; #95 landed a photo again with a better image, explicitly because the first one "read as a generic gray cratered sphere rather than the recognizable full moon" - the bar the .moon-face comment sets. Rendering all three side by side at 120/80/42px on a night backdrop settles it: the gradient face is a pale blob with soft smudges, and it is no better at the 42px companion size, which was the whole argument for building it. The photo's real structure does work that soft shading cannot fake. So revert b6e892a and spend it on a comment instead, since the reasoning for the photo lived in commit messages and PR history where nobody reading Sun.scss would find it - which is how it got re-proposed in the first place. This reverts commit b6e892a, keeping only the note. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CbXxMDVD22xYwHq5pd4XtR
I reverted this a commit ago after reading "looks like before" as a verdict on the design. It wasn't - the preview build showed no change, which was the actual complaint. Two reasons it showed nothing, both mine: - The revert had already landed, so the preview at that point was a comment and nothing else. - Before that, the gallery was a Subsection buried inside Interactions, with no TOC entry. On a page this long that is easy to miss entirely. So: restore it, and give it its own top-level "Moon face" section with a TOC chip, since the preview root *is* the styleguide and this is the one thing on the branch meant to be looked at. Two changes beyond a plain restore: - Add the pre-#92 gradient moon as a third column (`.legacy-moon`, lifted verbatim from 660d89a^). It is the control this comparison was missing: the photo replaced it, and #95 rejected a gradient-ish photo again for missing the "unmistakably the moon" bar. Anyone proposing a gradient moon should see what lost, at real size, first. The section copy states that history so the page argues its own case. - Lay the gallery out as a matrix - faces across, sizes down - instead of three cards. The styleguide caps at 1100px, so three cards wrap and you end up comparing 120px against 42px a screen apart. In a matrix the comparison that matters reads along one row. Verified against a real `npm run styleguide:build` + headless load, not just the unit tests: section renders, TOC chip present, no page errors. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CbXxMDVD22xYwHq5pd4XtR
Not behind a flag - this is the moon now, on every web surface: the companion at rest, interventions, the breath, urge-surfing, the wind-down. The photo was richer at 120px, but it was the app's only photograph in a UI that is otherwise gradients and line icons - a style seam on the one object meant to read as continuous across every surface - and its crater detail gave the eye something to examine on a surface whose whole job is somewhere to rest. At the size the disc actually spends most of its life (~42px resting on the bottom bar) that detail is below the pixel grid anyway. The face is a body whose light pools up-left and cools into the lower-right limb, under wide overlapping tonal fields where the real near-side's maria sit. Two constraints, both learned by getting them wrong first and recorded in the comment so the next attempt doesn't: - The maria must be big, overlapping and asymmetric. The obvious layout - a pair up top, one below - reads as a smiley face at 42px. That is also what the pre-#92 gradient moon did, where it read as polka dots. - Below roughly 7% luminance contrast the disc stops reading as a moon and just looks like a smudged pearl. Also drops what the photo cost: the ~20KB asset and the module-load preload from #246, which existed only because the first paint was a blank white disc before the texture arrived. Nothing fetches an image for the moon now. Still on the photo: the two home-screen widgets (Android ic_sun_widget_night.webp, iOS MoonWidget). Android's native LittleSun already draws a flat cool disc, so it is unaffected. The widgets need the same gradients ported to a VectorDrawable and SwiftUI to keep one moon everywhere. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CbXxMDVD22xYwHq5pd4XtR
The app's moon stopped being a photograph in the previous commit, which left the two home-screen widgets still shipping the lunar photo - a photo moon on the home screen against a drawn one in the app reads as two different objects, and there is only ever one moon. Android: ic_sun_widget_night.webp -> a vector, ic_sun_widget_night.xml. The maria are ported by mapping Sun.scss's percentages onto the disc's box (x = 18 + pct * 72 in the 108 viewport). A VectorDrawable radial gradient is always circular, so each mare is a circle of radius ry squashed by its group's scaleX about its own centre. No clip-path: every gradient reaches zero inside the rim (the widest, Procellarum, dies at x=19 against the disc edge at 18), so a clip would cost work on every frame and cut nothing. iOS: the same numbers again in SwiftUI, as unit fractions of the disc, using the same squashed-circle trick via scaleEffect. Drops the MoonWidget image set and with it Media.xcassets, which existed only to hold that photo - so the widget now ships no disc images at all, only the card skies. The halo stays cool on both. That is THE HALO RULE's documented exception: the day sun goes amber out here because it floats on the user's wallpaper and has to announce itself, but the moon never warms, on any surface. Also swept up what the photo left behind: - The styleguide's widget preview generator only understood flat <path> lists, so it would have drawn the maria as circles - the one place the preview could silently disagree with the device. It now honours <group> scale/pivot as an SVG transform, and night converts from its vector like day always has. - The content script's asset-URL rewriter is gone. It repointed url(/assets/webp/) at the extension origin so the moon wouldn't render as a see-through hole on host pages; moon.webp was the only webp, so it now rewrites nothing. - Comments that describe the moon as a photograph: the MOON_REST_GLOW rationale in Sun.tsx (the floor is kept deliberately, not inherited by accident), the iOS README and add_widget_target.rb resource list, docs/sun-halo.md and docs/sun-companion-widget.md. Verified by rendering the generated SVG of the real vector on light and dark backdrops, and the styleguide's widget gallery from an actual styleguide:build. The Swift is unverified by a compiler - there is no toolchain here - so it wants one glance from the macOS CI archive. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CbXxMDVD22xYwHq5pd4XtR
The conclusion was right but the stated reason was false, and a comment that asserts a checkable fact wrongly is worse than no comment. It read: "every gradient fades to zero well inside the disc (the widest, Procellarum, dies at x=19 against the disc edge at 18)". That compares two points at different y - at Procellarum's y=50.4 the rim is at x=18.18, not 18 - and the closest approach isn't on the x-axis anyway. Sweeping the whole zero-alpha ellipse (centre 33.12,50.4, semi-axes 14.04 x 21.34) against the r=36 disc, it reaches 36.065 at about 220 degrees: 0.065 units OUTSIDE the rim. Skipping clip-path is still correct - that boundary is alpha 0 by construction, so the overhang is under 0.001 opacity across 0.06% of the tile and cannot render at any size, while a clip-path would cost a saveLayer every frame. Say that instead, and also note two things the old comment left implicit: the mare paths overhang the disc on purpose (hidden only because tileMode clamps past the last stop), and iOS clips where Android doesn't, deliberately. Found by review; no rendering change, comment only. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CbXxMDVD22xYwHq5pd4XtR
Two review passes over the branch. No build-breaking defects and no web regression; the geometry was re-derived independently and all 42 numbers agree across the three platforms. What they did find: Stale comments that still call the moon a photograph. The worst was _variables.scss, where it was load-bearing: --little-sun-bg justified diverging from the in-app moon because craters would hurt the timer number's legibility. That reason is gone, and what is left is two similar gradients on an object the app insists is one continuous thing across the corner hand-off. Recorded as the open question it now is rather than quietly reconciling them - this disc needs a flat field behind a number, which the face's maria are not, so it should be decided on the hand-off, not on either disc alone. Also two "photo disc" lines in Sun.tsx. A mirror test for the moon's face. The change duplicated 7 maria x 6 values into an Android vector and a Swift array under two different mappings, with nothing holding them in step - and this repo already guards exactly that kind of cross-language duplication (sunHaloMirror, widgetPromptsMirror). It pins both ports to Sun.scss, and additionally guards the two constraints that were learned by getting them wrong: no two maria may mirror each other (a symmetric layout reads as a smiley face at companion size) and none may fall under the contrast floor. Verified it fails on a seeded drift, not just that it passes. Generator hardening. Its tokenizer only matched paired <path>...</path>, so a self-closing path would have run on to the next </path>, swallowing any groups between and pairing one path's geometry with another's gradient - silently, as a plausible-looking wrong SVG. Other drawables in this repo already use that form. Also keeps a group stack instead of a single slot (a nested group dropped its parent's transform rather than restoring it) and handles rotation/translate instead of discarding them. Output is byte-identical. Put back a bug the diff erased. The deleted URL-rewriting helper carried the only record that root-relative url(/assets/…) 404s inside the content script's shadow root. That is still live for the two woff2 faces, so Inter and Newsreader fall back to the system stack inside an intervention overlay - and Newsreader is the voice the app speaks in. Pre-existing, not caused here, but the knowledge went with the comment, so it is now recorded at the injection site with the fix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CbXxMDVD22xYwHq5pd4XtR
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The moon is the app's only photograph, in a UI that is otherwise gradients
and line icons. Its crater detail also gives the eye something to examine on
a surface whose whole job is somewhere to rest, and at the sizes the disc
actually renders - 80px for a phone intervention, ~42px for the resting
companion - that detail falls below the pixel grid and reads as grey noise,
i.e. a duller disc rather than a richer one.
So: an alternative face built from gradients alone, behind a
.minded-moon-abstractancestor. Opt-in only - nothing in the app sets it,only the styleguide, so the shipped moon is untouched until we pick one.
What it has to keep is that the moon reads unmistakably as the moon, never a
dimmer sun, or the evening cue it carries says nothing. The recognisable cue
at a glance is the maria shading, not the craters - but the tidy version of
that (a pair of fields up top, one below) becomes a smiley face at 42px, so
these are big overlapping asymmetric pools instead, following the real
near-side's lopsided look.
To compare:
the three sizes the disc really renders, on a fixed night backdrop (a moon
can only be judged against a dark sky).
facetoggle, since what actually decidesthis is how each face holds up through the morphs, not at rest.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01CbXxMDVD22xYwHq5pd4XtR