Commit Graph
108 Commits
Author SHA1 Message Date
jwinterm 1dc0c5f06a fix(lint): make the linter run again, and finish the em dash sweep
The linter had two faults stacked on top of each other.

First, the global `ajv: ^8.17.1` override starved @eslint/eslintrc, which
needs ajv 6 and passes it `missingRefs`; ajv 8 rejects that option, so ESLint
died before loading a single rule. Scoped overrides give eslint and
@eslint/eslintrc ajv 6.12.6 and leave the audit override in place everywhere
else.

Second, underneath that, `extends: ["@repo/config/eslint-preset.js"]` could
never resolve: ESLint's shareable-config naming convention rewrites it to
`@repo/eslint-config-config/...`. require.resolve hands ESLint a real path.

With the linter running it reported 35 react/no-unescaped-entities errors
across 7 files. Those are escaped rather than silenced, using ESLint's own
coordinates so only flagged text nodes were touched. Lint now exits 0. Two
@next/next/no-img-element warnings remain on the splash logos, which are
deliberate: theme-paired and fetchPriority="high".

Em dashes are also gone from the six blog posts and the README (105
occurrences), same rules as the site copy: colons for definition labels,
commas for appositives, semicolons for independent clauses.
2026-08-17 05:53:16 -04:00
jwinterm 0848fcabde feat(site): the tagline takes the title, and the em dashes go
The hero h1 is now "Precision Engineering for Everyone". The concrete offer
moves into the supporting line, which keeps the search terms the h1 gives up
and no longer restates the splash's opening sentence.

The title's gradient drifts instead of sweeping: a 300% ramp over 18s with
symmetric easing, so there is no hard turnaround at either end of the travel.

Em dashes are gone from every tsx/ts file (87 lines, 104 occurrences), per
AGENTS.md rule 9. Label lists and titles take a colon; appositives take
commas; independent clauses take a semicolon or a period. A few sentences
were restructured where no single mark read well.

Metadata keeps "Crypto" deliberately: it is a real service line and a real
search term, and it is no longer in the visible headline.
2026-08-17 04:18:18 -04:00
jwinterm 261cb04667 feat(site): one voice, brand gradients, a lighter splash gate, denser portfolio
- 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.
2026-08-16 00:04:28 -04:00
jwinterm c73b9f1c04 feat(brand): regenerate every mark and animation from the such-graphics pack
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.
2026-08-15 23:18:44 -04:00
jw b6fb6b743d fix(moonlaunch): disclose the telemetry and analytics the game actually sends
The policy described leaderboards and cloud save as the only things that leave
the device, and stated outright: "This data is not transmitted to our servers
unless you use the leaderboard or cloud save features." That is not true.

- Gameplay telemetry POSTs to api.such.software on every platform, automatically
  rather than opt-in, tagged with the anonymous device ID, display name and
  platform. It carries level starts and completions with times and stars, how a
  run ended (cause, hazard, speed, fuel, progress through the level), rewarded-ad
  and share actions, purchase attempts, and error messages. None of it was
  disclosed.
- Google Firebase (Analytics and Crashlytics) ships in the mobile builds and
  receives the same device ID as a user property alongside app version, device
  model, OS version and language. It was not mentioned anywhere, including in the
  third-party recipients table.
- Cloud save uploads automatically on every save, not only on an explicit action,
  and its payload now also carries store purchase receipts (the ledger that stops
  a purchase being credited twice).
- The page claimed Google AdSense serves ads on the web build. It does not:
  web/custom_shell.html records that the AdSense placeholders were removed and
  web monetization is handled in-game. Removed the claim and the AdSense row from
  the recipients table.

Left as-is: the statement that iOS serves non-personalized ads and does not
access the IDFA. No code path presents the ATT prompt, so the identifier stays
zeroed and that claim holds.
2026-08-15 11:17:50 -04:00
jw a6ad27b3e2 fix(moonlaunch): stop advertising paid desktop builds as free
The product page claimed "Free on iOS, Android, web, desktop" in its meta
description, OpenGraph description, and SoftwareApplication JSON-LD, and backed
that with operatingSystem "Android, iOS, Web, Windows, macOS, Linux" alongside
price "0".

Desktop is not free. The Windows/macOS/Linux builds are itch.io downloads behind
a $1.99 minimum purchase; only iOS, Android, and the embedded browser build are
free. Declaring price 0 across an OS list that includes the paid desktop targets
misstates the offer to search engines, which consume the JSON-LD for rich results.

Scope the free-offer structured data to the platforms that are actually free. The
visible Cross-Platform card still lists all six targets, which is accurate: those
builds do exist, they are simply not all free.
2026-08-14 07:47:13 -04:00
jw c50f4d29f6 fix(bloomword): stop claiming browser play
The site said Bloomword was "playable free in the browser at bloomword.earth"
in four places. It is not: bloomword.earth is the marketing and transparency
site, and iOS and Android are the only platforms you can play on.

This is the full-surface release standard's web-app gate -- marketing copy
flips from "learn more" to "play" only after play.<domain> passes a parity
proof against the mobile core loop -- and that surface does not exist yet
(play.bloomword.earth does not resolve). Every claim becomes "learn more at
bloomword.earth" with iOS/Android named as the only playable platforms, per
the standing item in the Bloomword roadmap.

The VideoGame structured data already declared gamePlatform [iOS, Android]
and needed no change; the footer link carries no play claim and is untouched.

Not built or typechecked: this workstation has no node. The changes are
string literals inside existing quoted copy, with one JSX text edit that
keeps its {" "} separator and closes the sentence after the anchor.
2026-08-13 10:20:04 -04:00
jwinterm d3916fd0e8 bloomword: use the real app-icon PNG everywhere (was the flat SVG)
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.
2026-07-28 21:04:19 -04:00
jwinterm c7c3cb26eb fix(vegan-iq): rewrite privacy policy to match v1.4.6
The policy was stale (March) and materially inaccurate: it claimed data never
leaves the device and there are no leaderboards (false — device_id + display_name
sync to the backend), described AdMob ads + a Remove Ads purchase (the app shows
no ads as of v1.4), and omitted Firebase Analytics/Crashlytics/Messaging. Rewrite
to reflect actual data practices. Needs deploy for the in-app link to be accurate.
2026-07-26 05:08:26 -04:00
jwinterm 274b0d82f5 services hub: rework hero + de-sparse the middle sections
Hero: 'Four things, done well' -> 'What we build' (add pb-3 so the gradient-clip descenders
aren't cropped), and drop 'PhD-led radiation-science education' from the subtitle for
'education from radiation science to word games' (education now spans well past nuclear:
ZDD, Numchangers, Bloomword, Vegan IQ).

Middle: the near-empty 'Partnership-first' and 'Recent work' section-container cards (a
heading + one line inside p-20 padding) read sparse. Partnership-first is now a dense 3-step
row (Scope / Build / Run it together); Recent work drops its empty header box for a compact
heading above the Occupy Wallets card.
2026-07-13 12:16:55 -04:00
jwinterm 1fc2cce0e0 bloomword live on stores; add Zero-Day Defender + edutainment to education pillar
Bloomword is out on iOS + Android: added it to /apps (featured first) with store links,
put StoreButtons on /products/bloomword, and flipped all 'coming/launching' copy to 'free
on iOS and Android' (product page, products index, services games blurb, FAQ).

Education pillar: added Zero-Day Defender (cybersecurity edutainment, Coming soon) and
cross-listed Bloomword + Vegan IQ from Games & Apps — they're genuinely both a game we ship
and a game that teaches. Broadened the pillar lead + card to frame the edutainment shelf
(science, math, vocabulary, nutrition, cyber-safety) alongside the PhD radiation-science work.
2026-07-13 12:03:24 -04:00
jwinterm 87586eddd7 copy: Chart of Nuclides, not Table (correct term) — barns tile + all barns copy/SEO/OG 2026-07-12 14:21:21 -04:00
jwinterm 651be20100 home: drop Selected Works card + juice hero; per-pillar OG cards; sitemap freshness
Home: the big empty 'Selected Works' section-container card is gone in favour of a compact
centered heading, pulling the bento up ~300px so the work leads directly under the hero.
Hero juice (all LCP-safe + motion-safe): the H1 gets an animated gradient sheen (only the
gradient POSITION animates, so the largest paint is never delayed; verified opacity stays 1),
a soft breathing cyan aura sits behind it (aria-hidden), and the CTAs get a cyan glow + hover
lift.

Services: each pillar page (and the hub) now generates its own OG social card via the shared
gameOgImage helper with a 'Services' badge and the pillar accent, so sharing a pillar shows
a distinct card instead of the generic banner. Verified: distinct per-slug image URLs, valid
1200x630 PNGs.

Sitemap: bump lastModified 2026-06-01 -> 2026-07-12 (we've meaningfully changed the site).
2026-07-12 14:15:46 -04:00
jwinterm 1e5719a1da services: split the four pillars into dedicated subpages
/services becomes a hub (hero, four linked pillar cards, philosophy, recent work, FAQ,
CTA) and each pillar gets its own statically-generated page at /services/[pillar]
(commerce/games/crypto/education) with distinct SEO title+description+canonical, its own
H1, the products behind it, a pillar-scoped FAQ + FAQ JSON-LD, breadcrumb JSON-LD, and
'the other pillars' cross-links. dynamicParams=false so unknown slugs are a static 404.

The pillar/proof/FAQ data + colour maps move to lib/services.ts (single source of truth),
ProofCard/PillarCards/ServicesCta/EducationCredentials to components/services, so the hub,
subpages, home 'What We Do' preview, and sitemap can't drift. Home preview cards now link
to their pillar; sitemap gains the four subpage URLs. All pillar copy kept verbatim.

Verified: 4 subpages prebuilt, distinct titles/canonicals, right products per page,
click-through nav, education credentials block, bad slug -> 404.
2026-07-12 13:47:19 -04:00
jwinterm 62fee8b83a home: bento above What We Do; splash enters on scroll intent; pre-warm the water filter
The page after the splash was two screens of text before the first image. Selected
Works (the bento, with the live barns vignette) now leads and the services copy
supports it below, wrapped in the same scroll-reveal.

Splash: the first wheel tick, 24px touch drag, or scroll key now plays the SAME
water-ripple enter as a tap (scrolling past used to hard-cut after a full screen).
Listeners are passive, the entering guard dedupes, reduced-motion still gets the
instant dismiss.

Pre-warm: on requestIdleCallback (post-LCP, invisible to Lighthouse) a 1px element
paints through the splash-water filter so the graph compiles before first use (the
first-tap stutter), and the logo layer gets will-change ahead of the zoom.

Verified with Playwright against the production build: wheel/key/touch all enter,
session flag set, bento renders above What We Do.
2026-07-11 10:45:50 -04:00
jwinterm a238412103 feat(bento): quiet tiles at rest — chrome fades, title + render float
At rest the card chrome (opaque bg, 64px frost, border, shadow) is now nearly
invisible so tiles read as just the title + the 3D render/image floating on the
page (especially clean on mobile, where every tile is 'at rest'). The glass
lights up + the colour tint paints on hover / focus / tap. Title and image keep
their visibility.
2026-07-08 11:15:01 -04:00
jwinterm a5647735d4 feat(services): restructure into 4 pillars + seamless morph loop
Services page was a long undifferentiated scroll of six ad-hoc sections.
Reframe it as four clear pillars, each led by an intro and backed by the
real products behind it:
- Commerce & web: Webshops, custom builds, Grin BTCPay plugin, Evaluetron
- Games & apps: Suchoice, Vegan IQ, Bloomword, Bauhaus Echo, Such Moon Launch
- Crypto & payments: consulting, Smirk Wallet, Hash Bags, Evaluetron
- Education & science: Barns & Neutrons, nuclear training, Numchangers, creds

Add a pillar jump-nav so the page reads as four areas, and a ProofCard that
links shipped products to their detail pages (image tile) and shows
pre-release ones as informational tiles with a status pill.

Also refresh the theming-morph reel with the seamless-loop build (crossfades
the last shop back to shop #1 instead of hard-cutting at the <video loop>).
2026-07-07 09:02:39 -04:00
jwinterm c41c7f28ee feat(webshops): refresh demo shots (now genuinely distinct) + varied surfaces gallery + booking callout
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).
2026-07-06 12:35:46 -04:00
jwinterm 99ce876cdd feat(site): theming-morph showcase hero on /products/webshops
The 'render once, serve cheap pixels' showcase, live. A 7s reel of the same
platform themed as five real demo brands (artisan -> merch -> crypto -> yoga
-> coaching), inside a decorative browser frame, at the top of the webshops
page.

- ShowcaseVideo: poster-first, preload='none' (no download until played),
  plays only while in the viewport (IntersectionObserver), pauses offscreen,
  and prefers-reduced-motion -> poster only (video never loads). muted +
  playsInline for mobile autoplay-on-view.
- BrowserFrame: static decorative chrome so the reel reads as a real shop.
- 16:9 assets ~330-355KB (webm/mp4) + 50KB poster, all within the motion budget.
2026-07-06 10:39:40 -04:00
jwinterm 3391c7cc6c fix(site): services polish — FAQ containment, /contact CTA, drop "for-hire" line
- Remove the "not controlled modeling for hire" framing from the homepage
  services preview + both services-page occurrences (FAQ answer + education
  section).
- Wrap the services FAQ in a section-container so it stops breaking out of the
  section rhythm; constrain answer width to max-w-3xl.
- Point "Request a Consultation" at /contact (the contact-form shortcut page)
  instead of the fragile /#contact cross-page hash.
2026-07-06 09:08:25 -04:00
jwinterm cbc8906715 feat(site): webshops rewrite + demo gallery + Bloomword/Meatspace/Mushroom Capital
- /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).
2026-07-06 08:28:39 -04:00
jwinterm c15dd74a8d Legal: umbrella Terms + Privacy refresh; align Such Moon Launch to PA
Umbrella terms/privacy on the shared skeleton (DMCA agent, PA/hybrid disputes,
product cross-refs); internal commerce/consulting sections removed. Such Moon
Launch terms switched Delaware -> PA/hybrid to match.
2026-07-02 15:19:45 -04:00
jwinterm 22b383b391 Leaderboard: High Score board (unified score) in place of Most Moonrocks 2026-06-28 19:58:01 -04:00
jwinterm b96224e287 Such Moon Launch: global leaderboard page
Server-rendered /products/such-moon-launch/leaderboard backed by the public
scores API. Level tabs (1-12), Fastest / Most Moonrocks boards, Endless Mode
wave board, responsive table with graceful empty/error states. Linked from
the product page. Ships with the 1.1 release.
2026-06-28 17:38:03 -04:00
jwinterm 468eaa1d60 analytics: config-driven Umami tag + accurate privacy disclosure; fix @types/react v18/v19 dup that broke the build at HEAD 2026-06-12 13:24:54 -04:00
jwinterm e3cc38bded Site copy: education-only nuclear (no for-hire controlled modeling), software-only/no-custody crypto, accessibility as capability not warranty, studio voice; fix support privacy link + terms consulting scope clarifier 2026-06-08 14:26:11 -04:00
jwinterm 21c2d227dd terms: add Multi-Tenant Commerce Platform section
The marketing ToS predates the multi-tenant Medusa platform launch
and didn't mention it. Visitors arriving at /terms after viewing a
client storefront have no way to find the legal relationship clearly
spelled out.

- Section 2 (Description of Services): add the platform + custom dev /
  consulting line items so the list reflects what we actually do today
- New Section 6 (Multi-Tenant Commerce Platform): states clearly that
  Such Software is NOT the merchant of record for purchases made on
  Merchant Client storefronts, that each Merchant Client has their
  own signed Platform Services Agreement, that card payments route
  through Stripe Connect with the Merchant Client holding their own
  Stripe account, and that crypto payments are non-custodial (we
  never take possession of customer funds). Directs customers with
  purchase questions to contact the Merchant Client directly.
- Renumbered sections 7-12 (now 8-13). Last-updated date bumped to
  2026-06-08.

Verified consistent with the operator-side documentation in the
medusa-multi-tenant-platform repo: doc/legal_model.md, doc/architecture.md
"Liability Model" section, and doc/tenant_guide.md "Refunds &
Chargebacks" section all match this language.
2026-06-08 10:50:23 -04:00
jwinterm d2d4ff997f Cursor timing (~4 blinks each side); rewrite perf post to the real fix
- 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.
2026-06-07 17:32:21 -04:00
jwinterm 128d154b0e Trim homepage JS: drop framer-motion from the first load; cursor lead-in blinks
- Remove framer-motion from the two components that pulled it into the homepage's
  initial bundle: HeroSplash (click-to-enter wash -> CSS keyframe; reduced-motion
  check moved into the handler) and ScrollReveal (whileInView -> IntersectionObserver
  + CSS transition). framer now only lives in the lazy nebula chunk, which never loads
  during the splash. First Load JS on / : 174 kB -> 138 kB.
- Monitor terminal: blink ~7 times before typing 'such' (so it's catchable even when
  the splash is skipped on refresh), then type/hold/backspace/blink/fade as before.

Desktop behavior unchanged; both converted components still respect reduced-motion.
2026-06-07 16:12:17 -04:00
jwinterm a2955b4102 Nebula: fatten mobile streamers (undo aspect-squish), fade out the cursor
- Streamers were rendering and hitting the monitor but invisible on phones:
  preserveAspectRatio=none squishes the stroke horizontally on a narrow viewport,
  so 0.12 went sub-pixel. Fatten 2.5x on mobile so they actually show.
- Terminal cursor now types 'such', backspaces, blinks ~6 times, then fades out
  completely instead of blinking forever (it was distracting).
2026-06-07 15:44:09 -04:00
jwinterm f3607a28d1 Nebula monitor: typing terminal cursor, stronger impact, tame pointer, restore mobile streamers
- Replace the centered dash with a tiny CSS terminal in the screen: types 'such'
  once, backspaces, then the caret blinks on the left (steps() width typewriter).
- Impact pulse is snappier and brighter (0.9s ping, scale 1.14, bright cyan glow)
  so streamer hits actually read; the screen color shifts with it.
- Pointer parallax dialed down to a subtle 6px with a gentler spring, fixing the
  desktop 'shift up-left after load' (it was easing toward the cursor on first move).
- Revert the mobile streamer thinning/density cut from the prior commit: it made
  them too sparse to see. Mobile now gets the full set at full weight, like desktop.
2026-06-07 15:20:34 -04:00
jwinterm 4b21928dc4 Nebula: fix mobile jump + pointer parallax, live cursor, lighter mobile field
- Mobile jump fix: compute the monitor anchor from the title's document-absolute top
  (scroll-independent) and only recompute on a real width change, so the address-bar
  resize that fires mid-scroll no longer snaps it. Mobile parallax now lifts the field
  up and away (faster than scroll) instead of drifting down over the text.
- Pointer parallax (desktop only): the field nudges toward the cursor, spring-damped
  so it can never move abruptly. No mousemove on touch, so no mobile cost.
- Live monitor: a CSS blinking terminal cursor inside the screen (opacity only =
  compositor); it shifts color on each streamer hit, reinforcing the impact pulse.
- Lighter mobile field: streamer density 8->5 and lines ~15% thinner on phones.

Desktop motion unchanged. (CSS/SMIL streamer rewrite deferred to its own commit.)
2026-06-07 14:01:31 -04:00
jwinterm 673d07a00e Mobile nebula: keep left monitor + parallax, glide-and-fade with the hero
A phone has no left gutter like desktop, and the nebula was position:fixed, so
scrolling slid the text up into the pinned monitor (overlap + jumps). Keep the
monitor to the left of the title and keep the parallax, but on mobile the field
glides up and out with the hero (slower-than-scroll lag for depth) and fades as it
leaves, so it never crosses the content below. Only the monitor/streamer layer
fades; the base gradient stays. Extra top room (pt-44) keeps it clear of the header
at rest. Desktop unchanged.

Dials: yRangeMobile (parallax), heroOpacity range (fade), pt-44 (top room).
2026-06-07 08:05:34 -04:00
jwinterm 33400c5879 Publish perf blog post + Such Moon Launch iOS links
- 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.
2026-06-06 20:41:31 -04:00
jwinterm b43c9d851b Homepage: Server Component + client splash island (cut hydration render-delay)
The data-URI logo still had LCP ~5s with zero network request, proving the
bottleneck is render delay (JS), not the image. So:
- page.tsx is now a Server Component. The hero, tagline, buttons, ServicesPreview,
  PortfolioGrid, and FounderSignature render as static server HTML (they had no
  client features, so they now hydrate to nothing).
- Splash state machine + header/nav/background gating + nebula position + scroll
  restoration moved into a small client island (home-shell.tsx) that takes the
  static content as children. Nebula reads the title via getElementById.
- Dedupe @types/react to 19 across the workspace (pnpm override) so the
  server->client children boundary type-checks.
2026-06-06 19:52:11 -04:00
jwinterm 065cabc38c Mobile LCP: inline splash logo as data URI; revert harmful image preload
- The high-priority <link rel=preload as=image> stole bandwidth from render-
  blocking CSS on 4G, pushing FCP 1.1s -> 2.2s and the score 82 -> 70. Removed.
- TBT is ~30ms (not main-thread bound), so the FCP->LCP gap was the logo's
  network fetch. Inline the mark as a data URI: zero request, paints with FCP.
  LCP should drop toward FCP and stop swinging run-to-run.
2026-06-06 19:03:38 -04:00
jwinterm 945529af33 Splash only on fresh visit (sessionStorage); preload LCP logo; draft perf blog post
- Splash is now a one-time intro per session: once entered (scroll or click) a
  refresh skips it, so you can't scroll back up into it mid-page.
- Preload the splash logo <img> (the mobile LCP element) at high priority.
- Draft blog post on keeping an animated hero without tanking Core Web Vitals
  (draft: true, for review).
2026-06-06 18:49:50 -04:00
jwinterm 980bd963fc Splash logo: drop framer wrapper + CSS filter (cleaner LCP); nudge tracer
- Logo is a plain <img fetchPriority=high> in a plain div (no framer-motion,
  no drop-shadow filter) so it is a clean, statically-painted LCP candidate.
  Water filter + a CSS zoom apply only on enter.
- Tracer target nudged to computerX/Y +1.5 (between the low-right +2.5 and the
  high-left +0.5).
2026-06-06 18:36:58 -04:00
jwinterm ea012b63fe Splash: remove non-composited glow rings (fix mobile NO_LCP); cross-fade to content; nudge tracer target
- Drop the two animated glow rings: stroke-dashoffset is non-composited, so
  they repainted every frame next to the logo and prevented Lighthouse from
  settling on an LCP (mobile NO_LCP). The static box + pulsing glow remain.
- Splash now cross-fades into the content: on enter it becomes a fixed overlay
  and fades opacity to 0 over the revealed page, instead of a hard cut.
- Nebula tracer target moved up-and-left (computerX-1, computerY-1.5) so the
  streamers converge on the monitor screen, not below-right of it.
- Removed the now-unused splash-* keyframes.
2026-06-06 17:50:42 -04:00
jwinterm a5815e20ee Cut desktop TBT: splash idle animations framer-motion -> CSS; lighten nebula
- The splash's always-on animations (logo float/breath, the two traveling
  glow rings) move from framer-motion (JS rAF every frame on the main thread)
  to CSS keyframes (browser/compositor). framer now only drives the one-shot
  click-to-enter water exit.
- Nebula: density 8 -> 4 and dropped the scroll parallax (the Forced-reflow
  source); reduced-motion still gets the static background.
2026-06-06 17:16:13 -04:00
jwinterm 11381bd1a0 Trim SEO titles to <=60 chars; stop tracking TODO.md
- Shorter, non-truncating <title>/OG titles for products, apps, wownerogue,
  smirk, neroswap, suchoice, barns-and-neutrons, webshops.
- TODO.md removed from the repo and gitignored (internal working notes).
2026-06-06 15:11:33 -04:00
jwinterm 874bc4a2ff Skip the splash entirely for prefers-reduced-motion visitors
Reduced-motion users now land straight on the main hero (desktop and mobile);
the splash is no longer shown to them, not just de-animated. Set before paint
via useIsoLayoutEffect so it never flashes.
2026-06-06 14:37:17 -04:00
jwinterm 62a68f5fd9 Add /contact shortcut to the contact form; reorder + relabel bento
- /contact redirects straight to the home contact form; product CTAs that
  pointed at the broken /about#contact now use /contact.
- Bento: custom e-commerce (Occupy Wallets) top-left, Smirk Wallet top-right,
  Wownerogue + Neroswap in the middle row; 'art brand' -> 'artist'.
2026-06-06 14:09:36 -04:00
jwinterm a11f436502 tweak copy 2026-06-06 11:21:42 -04:00
jwinterm ed07bb5681 Add splash intro, nuclear games + consulting, Cherenkov hero
- 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.
2026-06-05 22:40:14 -04:00
jwinterm 71dec78abe update apps link ordering 2026-06-01 11:13:57 -04:00
jwinterm 254e969c36 Tweak copy and add links 2026-06-01 11:10:31 -04:00
jwinterm 97a8026ed6 SEO: FAQ schema, per-product OG cards, stable sitemap dates
- 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.
2026-06-01 10:39:27 -04:00
jwinterm f51a1257c5 SEO: keyword-led titles/descriptions, structured data, internal linking
- Rewrite title tags + meta descriptions site-wide to front-load search intent
  (home, products index, services, apps, support, about, blog, and every product
  page); keep brand suffix, fix overlong/truncated descriptions, use colons not
  em dashes. Home keeps the visible 'Precision Engineering' hero; only the <title>
  changed. De-jargon Webshops away from leading with 'headless'.
- Add reusable JSON-LD helper (JsonLd + breadcrumb/softwareApp/article builders).
  WebSite schema site-wide; BreadcrumbList on all product + blog pages;
  SoftwareApplication on the apps/games; BlogPosting on posts.
- Cross-link the Monero/Wownero cluster (Neroswap, Smirk, Wownerogue, Such Moon
  Launch) and link products to services.
- Data fixes: Vegan IQ corrected to 1,000+ questions with Daily Challenge and
  Weekly Quiz (page + index); generalize Support page off a single game.
2026-06-01 10:21:06 -04:00
jwinterm d8db411824 Add Wownerogue product page + blog post; remove r/CryptoCurrency and MoonPlace
- 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.
2026-06-01 10:09:11 -04:00