THE GREY BOX. The decorative animations were embedded with <object>, which
creates a nested browsing context that paints its own canvas. On the dark pages
that canvas showed as a light grey square behind the mark. The SVG's own baked
tile had been hiding most of it, so only the rounded corners leaked, which is
why it read as "grey corners" rather than "grey box": removing the tile exposed
the whole thing and made the real cause obvious.
<img> has a transparent canvas and still runs CSS animations inside an SVG, as
the splash morph and the Hash Bags icon already demonstrate. Swapped on all
three pages that used the pattern, not just the one that was reported: /apps,
/products and /blog all had it. Verified on the rendered dark page, where the
pixels outside the mark, inside the old tile, and the page background are now
the same colour.
The marks themselves are now the tileless variants from such-graphics f457c37,
so nothing bakes a background colour that has to match ours.
COPY. "crypto payment tools" -> "cryptocurrency tools", and the supporting line
now names both ways of working with us rather than only the products.
I shipped it upright. It is a typographic monospace hash and it leans, which is
how it renders across hash.boats (hero and every feature card) and how
hash.boats/splash.svg draws it by hand: "verticals lean right".
Where the upright one came from, because the wallet repo disagrees with itself.
assets/images/hash_wallet_app_icon_source.svg rebuilt the glyph as paths to
remove a font dependency and flattened the lean while doing it, and
store/play-icon-512.png is upright too: its verticals measure x=206 and x=306
on every row, no lean at all. I took those as canonical and explicitly rejected
the slanted splash.svg as wrong. That was backwards. The brand's own site is
the authority on the mark; an app-store export is downstream of it.
Both icons are now rebuilt from splash.svg's glyph, mapped onto a full-bleed
1024 canvas preserving its proportions exactly (glyph spans 57.5% of the tile,
stroke is 8.75%). The static PNG is rendered from the same geometry as the
animated SVG rather than being a separate export, so the two cannot drift: the
animation ends on precisely the still icon. Measured after: the left bar's
centre runs 225 -> 204 -> 182 down the tile, where the old one sat at 206 on
every row.
Still full-bleed, not splash.svg's inset rounded box, because the site rounds
icons with a 22% CSS radius and a built-in transparent margin would show card
background at the corners.
An animated icon has to still BE the icon, so the geometry is copied verbatim
from the app's own icon source (hash-wallet
assets/images/hash_wallet_app_icon_source.svg): full-bleed #1a5c38, four white
lines at stroke-width 80 with square caps, horizontals at y=412/612, verticals
at x=412/612, all spanning 212..812. It draws on in 850ms and settles into a
frame that is pixel-for-pixel the static PNG.
Not hash.boats/splash.svg, which was the obvious candidate and is wrong twice:
its # is slanted where the shipped icon is upright, and it insets its green box
inside a transparent margin. The site rounds icons with a 22% CSS radius, so
that margin would have shown card background at the corners, which is the exact
artifact we just finished removing from the icon set.
CSS rather than SMIL, for the reason the brand pack already documents:
prefers-reduced-motion is a media query and cannot reach inside a SMIL
<animate>. Under reduced motion this is just the finished icon.
Draws once and holds, rather than looping. Five icons looping forever on a
directory page is a distraction, and an app icon's resting state should be an
app icon.
`animatedIcon` is optional per app and `unoptimized` is set only when it is
used, because the image optimizer would rasterise the SVG and throw the
animation away.
Live on Google Play (com.suchsoftware.hashwallet); the iOS build is in review
and desktop follows, so both render through StoreButtons' existing null-href
"Coming Soon" state rather than claiming availability we do not have.
Content is taken from the project's own README and store-listing draft rather
than invented: open-source, non-custodial, Wownero-first, twelve chains, and
Ledger/Trezor/BitBox support. The "why it exists" section is the real reason,
which is the interesting part of this product: Cake Wallet ended Wownero
support in early 2026 and this fork keeps it first-class.
Icon is the shipped play-icon-512, already square and opaque, so it takes the
site's rounded-[22%] cleanly and cannot show a transparent corner wedge.
Also linked out to hash.boats, listed on /products, and added to the sitemap.
Two separate problems, one of them a real bug.
THE FLASH. The splash is server-rendered, so on a refresh the browser painted
it and only then did hydration read sessionStorage, decide this visitor had
already entered, and remove it. That one painted frame is the flash, and React
cannot prevent it: even useLayoutEffect runs after the server HTML is painted.
So the decision moved before paint. A tiny synchronous script in <head> reads
the session flag and prefers-reduced-motion and stamps the root element; a
plain CSS rule hides the overlay in the frame it would otherwise appear in.
The overlay is `fixed`, so hiding it shifts no layout. Verified with a
Playwright run: after reload the root is already stamped at readyState
"interactive", the overlay computes to display:none, and the splash is not
visible in any of twelve sampled frames.
THE SPLASH ITSELF. It is now only the pillar signature: four dots become the
four pillar symbols -- commerce, crypto, games, education -- become the word
SUCH, then the page takes over. One generated asset (morph_splash*.svg) whose
CSS timeline is scaled to land exactly on 1337ms, from such-graphics 628fcc1.
SPLASH_MS here and motion.splash.ms there are the same number by construction:
a gate that closes early cuts the last letter mid-draw.
Everything else on the splash is gone -- tagline, supporting line, the four
corner nav links, the chevron, the water-refraction filter and its pre-warm.
The corner links were unreachable inside a gate this short anyway, and the
header carries them. splash-logo-data.ts goes with them, now orphaned.
Perf, measured on a local production build: mobile 97, desktop 98, unchanged
from what production scores today. CLS stays ~0. LCP moves 0.9s -> 1.2s on
mobile, because the mark is now a 12KB request where the old logo was an
inlined data URI. Both theme variants are fetched (3.7KB each gzipped) since
`dark:hidden` hides but does not prevent the download, so half of that is
waste. Fixable by inlining as data URIs the way splash-logo-data.ts did, at
the cost of ~30KB in the bundle; not done here because the score did not move.
New store icons from bauhaus-echo/assets/store/app_icon_512.png and
suchoice/assets/icon_1024.png, both resampled to 512 and both square and fully
opaque. Bauhaus drops 320KB -> 72KB, Suchoice 259KB -> 142KB.
The corner artifact had a measurable cause. Five icons bake their own rounded
corners as transparency (suchoice 20.5%, smirk-wallet 20.1%, vegan-iq 19.3%,
mushroom-capital 17.0%, such-moon-launch 15.2% of their width); the rest are
square. CSS then rounded them again, at a radius that differed per page:
21.4% on /apps at 56px, 25% at 64px, and 20% at 80px.
20% is BELOW suchoice's 20.5% baked corner, so on /products/suchoice the CSS
clip fell inside the transparent corner and a wedge of card background showed
through at each corner. That is the "different coloured stuff next to the
rounded corners": not a rendering bug, an arithmetic one.
Every square app icon now uses one percentage radius, rounded-[22%]. It is
above every baked radius in the set, so no transparent corner can ever be
exposed, and being a percentage it stays identical at 56, 64 and 80px instead
of drifting with the pixel size. The two new icons are square, so they cannot
produce the artifact at any radius.
The non-square occupy-wallets banner keeps a fixed radius: a percentage on a
non-square box goes elliptical.
Copied through from such-graphics db616f8. The launch arc's feet ran to y=178,
inside the frame's corner arcs (centred (26,174) and (174,174), r=12), so on
/apps the leg, its cap and its node dot all sat on the corner and the mark read
as broken. The feet now stop at the glyph baseline, y=164.
Generated, not hand-edited: the pack is canonical and a regen would have
overwritten a local fix.
- Voice unified on the title-tag register: the homepage h1 now says what we
sell (Custom E-commerce, Apps & Crypto Tools); 'Precision engineering for
everyone' is demoted to the supporting line. The structured-data and
manifest descriptions now match the OG description instead of carrying
their own registers.
- The off-palette cyan/blue gradients are gone: .hero-title and the new
.brand-gradient-text use the four-colour system (light palette on light,
dark palette on dark, per the pack). Splash cover text, services and
portfolio headings, the hero aura, and button shadows all follow.
- The splash now dismisses once 40% scrolled past instead of requiring the
whole screen to leave the viewport (it was already once-per-session and
reduced-motion-skipping).
- Portfolio: heading 'Portfolio', subtitle 'Products & projects', meta title
to match; grid grows to three columns on xl in a max-w-6xl container.
- anim3_matrix slimmed: single-layer glow, unfiltered crackle and orbs, and
the border cycles stroke colour instead of animating filter:hue-rotate --
the filter animation forced a full filter re-render per frame and pegged a
core on the page hosting it.
All branding and animation assets now come from packs/such-software/pack.json
(such-graphics feat/brand-full-blast) instead of hand-maintained files:
- anim1_pulse / anim3_matrix / anim_type_v4 (both themes): regenerated with
the corrected U bowl, measured pulse timing (the hand-authored node delays
ran ~17% fast), and CSS animation with real prefers-reduced-motion support.
- clean marks, lockups (clean_*_w_text), favicons (svg + 192px png), and the
OG banner: regenerated; the OG card is the pack's 1200x630 projection.
- splash-such: rebuilt from the pack -- the old one carried the divergent U,
an off-palette cyan frame, and the pre-correction radius. Now theme-aware:
two inlined data URIs (hero-splash shows the light palette on light, the
dark palette on dark) since the pack's dark hues are tuned for near-black.
- new assets available: games_pulse (the launch arch with the rocket, wired
into /apps), morph, ambient_{atom,mesh,leaf}, favicon_dots, favicon_live,
icon-192/512 + maskable-512 (wired into manifest.json), /favicon.ico.
- animation embeds switched <img> -> <object>: Chrome freezes CSS animations
inside SVG-as-img (the old files animated because they were SMIL); an
object hosts a real SVG document where CSS animation and the
reduced-motion query both work. Verified live in Chrome.
Swaps /images/products/bloomword.svg for bloomword.png across the apps
index, the products index, the Bloomword product page, the bento grid,
and both services.ts proof lists (games + education), so the icon
matches what actually ships on the App Store and Play listings.
The SVG is now unreferenced; leaving it in place for now.
The five demo storefronts were re-themed to look like different companies
(distinct hero styles, card styles, density, grid, and homepage composition),
so re-snap the hero cards and regenerate the theming-morph reel from the
fresh shots.
Add a "Every surface, not just the homepage" gallery: six live surfaces
across different shops (yoga + coaching booking calendars, an editorial
product page, a dense catalog grid, a crypto product, a themed cart) so the
page shows platform depth the homepage crops hide.
Call out booking/scheduling explicitly: a new "Booking & Scheduling" feature
card, a booking FAQ (feeds FAQ JSON-LD), and a booking-calendar line in the
surfaces lead.
Demo images downsized to lean 1280w JPGs (png -> jpg).
- /products/webshops: lead with per-tenant theming; add the real platform
features (Printful POD, non-custodial crypto to own wallet, Stripe Connect
with item-margin-only fee framing, SIWE/wallet login, Telegram + email
notifications, automated tax); fix the incorrect "Vercel/Railway" hosting
line to fully-managed self-hosting; remove PayPal/Coinbase (not live).
- Live Demos gallery (new component) with real screenshots of the 5 themed
demo storefronts.
- Add three projects to the portfolio: Bloomword (now live, bloomword.earth),
Meatspace (in dev, meatspace.place), Mushroom Capital (coming soon,
mushroom.capital) with an icon, a detail page (VideoGame + FAQ JSON-LD),
and a sitemap entry each.
- Copy: avoid em dashes (colon/semicolon/comma) across the products area.
Verified: tsc clean, next build green (50/50 static pages).
- Cap the two wildly oversized bento source PNGs so Next can't serve giant variants:
occupy-wallets 1200x837/393K -> 700x488/167K, neroswap 1584x672/1.8M -> 700x297/404K.
(bauhaus/vegan are already 512px and self-cap; privacy-labs was already small.)
- Fix the bento <Image> sizes: object-contain height-constrains the image so it renders
~360px wide in either span; 66vw/100vw made Next serve up to ~750-1200w. Now
'(max-width:768px) 90vw, 33vw'.
- Bump turbo 2.7.4 -> 2.9.16 (GHSA-hcf7-66rw-9f5r, GHSA-3qcw-2rhx-2726). pnpm audit
now clean.
- Monitor terminal: ~4 blinks, type 'such', backspace, ~4 blinks, fade.
- Rewrite the blog post so it tells the accurate story end to end (not an update):
the LCP breakdown showed render delay with TTFB 0 and a free main thread, so it
was neither the network nor JavaScript. It was render-blocking CSS, fixed by
inlining the stylesheet. Server components / dropping framer are kept as honest
supporting steps, not the gate. Swap the architecture figure for a CSS
critical-path figure; mobile now a steady 100.
- New post 'My Animated Splash Was Tanking Our Mobile PageSpeed Score' (draft:false):
the LCP investigation, the data-URI diagnostic, and the real fix (shrink the
use-client boundary / server-render the static parts). Two SVG diagrams.
- Such Moon Launch now live on iOS: App Store link wired on the apps and product
pages.
- Inline <svg> is not an LCP candidate; on mobile the tagline is hidden so the
logo was the only large element -> NO_LCP. Serve the mark as
/images/branding/splash-such.svg and render it via <img> (a valid LCP
candidate, painted from SSR HTML).
- Transition: start the cross-fade on click (shimmer plays as the splash fades
into the content) and shorten durations 1.2s -> 0.8s; snappier and blended.
- Tracer target back to the midpoint (computerX+0.5, computerY+0.5).
- Splash: full-viewport animated SUCH logo cover with four corner nav
buttons; reveals the site once "entered" (scroll-through or Explore) and
does not resurrect on scroll-up. Original hero restored beneath it
(title-anchored monitor pulse + Cherenkov-blue background).
- Logo: traveling Cherenkov glow ring + gentle letter breath (SVG/Framer,
reduced-motion safe); beveled glass corner buttons.
- Services: new "Nuclear & Radiation Modeling" section + "Consulting"
umbrella (payments, crypto, nuclear), MCNP Google Scholar link, and a
not-a-licensed-PE clarification.
- About/founder bio: LLNL credibility + accessibility, art101.io link.
- Products: add Barns & Neutrons, Alpha Doc, Decay Theory (detail pages,
OG cards, SVG icons); client-side sortable grid with coming-soon at the
bottom. New Neroswap + Custom Websites icons (de-duplicated).
- SEO: game pages added to sitemap.
- Copy: dial back em-dashes to colons/commas/parens on home + services.
Rework the per-product OG cards to a single template with a graphic slot: real
app icons for the apps that have one (Bauhaus Echo, Suchoice, Vegan IQ, Such Moon
Launch, Smirk), and thematic SVG glyphs for the rest (Wownerogue dungeon glyphs,
Neroswap candlesticks, a shopping bag for Webshops, a browser window for Custom
Websites). Same layout and accent system so the set reads as one family. Paths
are unchanged, so the page metadata already points at these.
- Add FAQPage structured data + visible FAQ sections to Wownerogue, Webshops,
Neroswap, and Services (covers high-intent 'provably fair', 'no-KYC', and
'revenue share' style queries; visible Q&A matches the schema).
- Generate branded 1200x630 OG cards per product and wire them into each
product page's openGraph + twitter (summary_large_image), replacing the
square app icons that previously got cropped in social previews.
- Sitemap: stop stamping every static page with new Date() on each build; use
a single content-update date so freshness signals are not diluted.
- New /products/wownerogue page (SEO metadata + VideoGame JSON-LD) and
wownerogue-launch blog post covering the fairness, block-timing, and payout design.
- Drop the retired r/CryptoCurrency and MoonPlace references from the portfolio grid,
products index, and custom-websites page; feature Wownerogue + Neroswap instead.
- Add WownerogueLinks component (live instances + GitHub source) and wire it into MDX.
- Remove now-orphaned r-cryptocurrency and moonplace images; add product page to sitemap.
- Home hero subhead rewritten to name commerce/websites/apps/consulting
plus in-house mobile apps and games; primary CTA points to /products
- Portfolio page (/products) title renamed and each product card now shows
a 56px icon beside the title
- Favicon served inverse to the browser color scheme so the tile contrasts
with the chrome instead of blending into it
Product page: added Dice Roll and Decision Duel to features grid (now
6 features), updated meta description and hero text, broadened Snap &
Decide description to include ingredients/labels.
Blog post: published 3D Physics in Flutter article covering three_js +
cannon_physics integration, framebuffer cache bug, quaternion convention
issue, vertex clustering for face detection, and settle mechanics.
- Fix homepage heading hierarchy (h2 -> h1)
- Add page-specific metadata to services and about pages
- Fix outline-none on form inputs for keyboard accessibility
- Delete sync conflict files
- Add group class back to bento cards for hover animations
- Use raw CSS for glassmorphism to fix Tailwind opacity errors
- Add TODO.md with production checklist
- Add semantic CSS classes (.section-container, .glass-card)
- Update Tailwind config for opacity modifier support