TABLES. next-mdx-remote had no remark plugins, so GFM tables rendered as literal
pipe characters in a paragraph. Four published posts were affected, not just the
new one: bauhaus-echo-launch, flutter-3d-physics-dice, vegan-iq-data-pipeline
and smirk-v0-3-0. remark-gfm is now wired into MDXRemote's mdxOptions.
BACKTICKS. @tailwindcss/typography wraps every inline <code> in literal backtick
characters via code::before / code::after. The served HTML was already clean;
the marks were injected by CSS. Monospace already marks code as code, so the
backticks were a redundant second marker that reads as a typo in running prose.
Suppressed across .prose.
TRANSPORT. The previous version's "transports" section covered only Grin slate
channels. Tor is a separate mechanism and was undocumented: the wallet accepts a
.onion backend origin over plain http, alongside private ranges and .local,
because onion services carry their own transport authentication and no CA issues
for them. The onion pattern matches the label immediately before .onion, so an
onion-lookalike public host is refused. On the backend, the admin plane binds to
loopback and TOR_ADMIN_ONION adds exactly one onion host to its Host allowlist
as a DNS-rebinding guard.
There is no bundled Tor daemon and no I2P support anywhere in either repo. The
post now says so rather than leaving it implied.
COPY. Removed the editorial voice throughout: no more "the part worth
explaining", "the instructive one", "worth dwelling on". A technical report
states what a thing does and lets the reader decide what matters. Headings are
now descriptive rather than argumentative.
Subtle and half-transparent, per the brief. Four blobs, one per monogram cell,
each in that letter's own colour, thrown outward from where the letter was: the
mark comes apart into its own palette rather than flashing something unrelated.
The peak opacity is 0.42 light / 0.5 dark and the gradients never reach full
alpha, so it stays a wash rather than a curtain.
Only transform and opacity animate. Both are compositor properties, so this
does not repaint per frame. That is deliberate: animating a filter is what
pegged a core on the matrix animation, because a filter change re-renders the
whole filter graph every frame. Soft edges come from a static radial-gradient
that is painted once and only ever transformed.
The overlay could no longer fade as one piece. Ground and mark fade in 260ms
while the burst runs 420ms plus a 25ms per-blob stagger, so fading the
container would have taken the burst down with it halfway through. They fade
independently now and the shell unmounts at 540ms instead of 300ms, which is
the burst's real length rather than the cross-fade's.
Hidden entirely under prefers-reduced-motion, though those visitors never
reach the splash anyway.
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.
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.
- 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.
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).
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.
- 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.
- 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.
- 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).
- 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.
- 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.)
- 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).
- 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.
- 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.
- 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