Platform Changelog

Updates, design decisions, and milestones for this portfolio.

21

Sidequest page mobile crash fixes — one demo at a time, no eager iframes

v1.0.20
May 18, 2026 · 03:24·↗ frozen snapshot
fixnewrefactordesign
  • fix: mobile OOM crashes on sidequest page
  • feat: status dot in whispers callout — green on, grey off
  • fix: StatusRow px-4 spacing from left border, DeadCard lighter on dark
  • fix: StatusRow py-5, DeadCard uses danger-muted for reliable dark mode
  • fix: StatusRow padding + DeadCard dark mode via inline CSS vars
  • fix: remove stale html2canvas patch — build was failing in postinstall

Design note

The root crash was four full-app iframes loading simultaneously on mobile. The fix activates only the most-visible demo at a time via IntersectionObserver — so the renderer holds at most two iframes. Three.js never loads on mobile (desktop-only note instead), and YouTube only loads on click. Three independent memory ceilings, all dropped.

Mobile polish — commands scroll, decisions collapse, tablet view removed

v1.0.19
May 18, 2026 · 00:58·↗ frozen snapshot
refactordecision
  • session: tablet view removed, decisions collapsed, article mobile polish
  • changelog: v1.0.18 — ShipLock article facts corrected, tweet queue fully imaged and scheduled

Design note

Commands on mobile now scroll horizontally rather than wrapping — the whole row becomes the copy target, the icon disappears. Cleaner than truncating or shrinking the font.

ShipLock article facts corrected, tweet queue fully imaged and scheduled

v1.0.18
May 16, 2026 · 19:17·↗ frozen snapshot
fixnew
  • session: fix ShipLock article scope figures, tweet queue images + schedule
  • feat: add apple-icon.png for iOS/Apple link preview icon
  • feat: OG image — static screenshot of homepage
  • feat: OG image — headshot + name + availability chips on dark grid background
  • fix: add patch-package to devDependencies — postinstall was failing on Vercel
  • changelog: v1.0.17 — Two experiment articles and an honest postmortem on Alpine World's sourcing log

Two experiment articles and an honest postmortem on Alpine World's sourcing log

v1.0.17
May 14, 2026 · 19:45·↗ frozen snapshot
new
  • session: two experiment articles + alpine sourcing log + corrected closing paragraph
  • changelog: v1.0.16 — Domain expansion that writhes from the iframe's own toggle

Design note

The closing paragraph in the alpine-sourcing article had to be fully rewritten — it described the current build as "simpler, without PBR splatting, without spatial audio, procedural terrain" when all of that is false. v2 has the real SRTM heightmap, full PBR shader, HRTF spatial audio, and instanced foliage. The trees still float because the CPU and GPU height pipelines produce different Y values from the same heightmap. Accuracy matters most when the article is literally about what failed.

Domain expansion that writhes from the iframe's own toggle

v1.0.16
May 14, 2026 · 15:15·↗ frozen snapshot
newdesignrefactorfix
  • session: domain expansion playground demo + organic blob clip-path
  • revert: restore 720px max-width on homepage, about, header, footer
  • experiment: bump max-width to 936px across homepage, about, header, footer
  • fix: match ShipLock page max-width to Varmply (936px)
  • polish: restore original GitHub button style on ShipLock page
  • polish: skeuomorphic Button for ShipLock live CTA, full-width description on both project pages
  • revert: restore original homepage and about bios
  • refine: remove tagline tag, bake 48hr line into both bios, restore body length
  • refine: bio metrics baked in, about cut down, ShipLock CTAs on project page, How I work moved, Changelog removed from nav
  • feat: portfolio pre-application pass — positioning, metrics, ShipLock CTAs, how I work
  • feat: OG image, tighter description, Twitter card metadata
  • session: swap valley video — nocookie embed, autoplay, playlist
  • session: playground UX — audio control pill, headphones modal, zone label, about collapsed
  • changelog: v1.0.15 — Playground as inline card with expand, controls, and headphone hint

Design note

A smooth circle clip-path felt sterile — a domain expansion should writhe. Swapped CSS transitions for a rAF-driven path() blob with three layered sine frequencies, each at different phase speeds, so the boundary undulates while it grows. The trigger also moved off the chrome bar and onto the iframe's own ThemeToggle — embed-mode detection makes the in-iframe button postMessage `{type, x, y}` to the parent, which translates the coords by the iframe's scale factor and runs the animation from that exact spot. The demo now feels owned by the live homepage inside it, not by a fake browser frame around it.

Playground as inline card with expand, controls, and headphone hint

v1.0.15
May 13, 2026 · 01:13·↗ frozen snapshot
designfeature
  • session: playground as card — inline layout, controls fix, expand/shrink
  • session: playground redesign — scrollable, compressing scene, apology + valley video
  • changelog: v1.0.14 — Whispers hidden interstitials, riddle, footer easter egg

Design note

Removed the full-screen scroll illusion entirely — the playground now lives as a proper card in the page layout, matching the project/tool card pattern. The 3D canvas stays mounted when expanding to full screen (position:fixed trick), so the scene never resets.

Whispers — hidden interstitials, riddle, and footer easter egg

v1.0.14
May 13, 2026 · 00:35·↗ frozen snapshot
fixdesign
  • session: Whispers system — first-visit quote, riddle, footer toggle
  • session: ShipLock project page, about image fixes, footer redesign
  • changelog: v1.0.13 — no-flash transitions, TransitionLink

Design note

First-visit quote is SSR-rendered via cookie detection so it is in the initial HTML at full opacity — zero flash possible. Riddle fires via a custom event dispatched before router.push(), matching the same no-flash pattern as the regular quote system. The footer toggle is intentionally unlabelled — hover only — as part of the footnoters joke.

No-flash page transitions — interstitial fires before the next page loads

v1.0.13
May 12, 2026 · 00:23·↗ frozen snapshot
fixfeature

Design note

The fix required intercepting navigation at the link level rather than reacting to pathname changes. TransitionLink fires the overlay on click, then calls router.push two animation frames later — by which point the overlay is already rendering and covers the page mount completely.

Page transitions that think — contextual interstitial quotes

v1.0.12
May 11, 2026 · 23:48·↗ frozen snapshot
featuredesign

Design note

The overlay fires independently of how fast the destination page loads — the 1600ms timer runs regardless. This prevents the subconscious association of "quote = slow page." The destination finishes loading under the overlay; it's revealed when the thought passes.

ClipSync tool, writing hub, persistent footer, and favicon

v1.0.11
May 11, 2026 · 22:12·↗ frozen snapshot
newdesignimproved
  • ClipSync added as a tool page with origin story, 4 feature cards, and live app link
  • ClipSync article: "A free weekend, a real problem, and forty-eight hours to ship."
  • ShipLock added to Featured Work with dark indigo gradient card
  • Standalone /writing page: featured article (ShipLock), all articles list, RSS feed
  • Recent Writing section added to homepage
  • Persistent Footer component extracted and applied across all pages (hidden on /playground)
  • Favicon updated from Vercel logo to cursor avatar circle (dark circle, hatch, blue arrow)
  • Global spacing rule applied: heading+body pairs tightly grouped, wider gap to next element
  • Font size bumped to 17px root; article and project card body text bumped to text-sm
  • Light mode nested containers now use --bg-subtle (near-white) instead of dark grey
  • About page: social links 2x2 grid, Recognition section removed, Building updated to Varmply
  • Theme toggle double-click bug fixed (state now initializes from DOM)
  • Writing nav link updated to /writing (standalone page)
  • Butler and Relay tool pages added with section spacing and typography improvements

Design note

Spacing rule formalized this session: title + body = one tight unit (gap-1 to gap-1.5 inside), with a wider gap to the next element. Applied globally across cards, sections, and article pages. Also distinguished nested containers (--bg-subtle, near-white) from top-level containers (--surface, white) to restore visual hierarchy that was lost when bg-subtle was set too dark.

Working contact form, Varmply-only projects, and real social links

v1.0.10
May 10, 2026 · 14:47·↗ frozen snapshot
decision
  • session: working contact form, Varmply-only projects, real social links, success state
  • changelog: v1.0.9 — varmply block viewer, live iframes, scroll lock, decisions log

Varmply block viewer — live iframes, scroll lock, and 18-entry decisions log

v1.0.9
Apr 23, 2026 · 13:23·↗ frozen snapshot
fixnewrefactordesigndecision
  • session: varmply block viewer — iframe isolation, scroll lock, decisions log
  • feat: replace placeholder decisions log with full 18-entry build history
  • fix: smooth height transition on block-wrapper iframe container
  • feat: dynamic iframe height via postMessage, remove creator hero block
  • feat: section isolation — all blocks use ?section= params, scrolling=no on iframes
  • feat: curated block selection with section isolation
  • changelog: v1.0.8 — varmply block viewer expands across three pages and footer

Design note

Iframe section isolation required removing CSS !important injection from the layout inline script — it was hiding sections that had no matching id attribute. Lenis proved to be the real blocker for scroll prevention since it intercepts wheel/touch events before CSS overflow:hidden can act. Both were fixed independently, then ResizeObserver replaced one-shot rAF height reporting so iframes self-size as 3D and animated content settles.

Varmply block viewer expands across three pages and footer

v1.0.8
Apr 22, 2026 · 23:01·↗ frozen snapshot
new
  • session: varmply block viewer — sponsors, creators, footer sections
  • chore: track *.glb files with Git LFS
  • changelog: v1.0.7 — alpine world goes alive, free camera, weather, day cycle

Design note

Blocks grouped into labelled page sections (Home / Sponsors / Creators / Footer) using a SectionDivider component. The divider uses a hairline border + mono uppercase label rather than a full heading — keeps the information density high without competing with the block labels themselves. iframes are now fully interactive: pointer events on, scrolling enabled, so you can click and scroll within each embedded section to see the real responsive behaviour.

Alpine world goes alive — free camera, weather, and a full day cycle

v1.0.7
Apr 15, 2026 · 22:46·↗ frozen snapshot
new
  • [playground/terrain] fixed transparent floor — DoubleSide material + displacementBias: -3 to prevent camera clipping underground
  • [playground/terrain] added envMapIntensity: 0.15 and base color #5a4a2e to kill glassy HDR washout on the ground
  • [playground/camera] FreeCamera — PointerLockControls + WASD/Space/Shift movement; 1–6 digit keys teleport to zone viewpoints
  • [playground/snow] SnowSystem — 1800 falling particles with horizontal drift; resets above camera, follows player position
  • [playground/road] DirtRoad — ribbon geometry pinned to terrain height along camera spline, dark earthy color
  • [playground/clouds] CloudDrift — 18 puff-sprite clouds (canvas CanvasTexture), slow eastward drift, boundary reset
  • [playground/birds] BirdSystem — 6 flocks × 5 birds, canvas V-wing sprite, sine-wave orbit paths at altitude 16–38
  • [playground/time] TimeOfDay — AmbientLight + DirectionalLight driven by an 8-min day cycle; fog color shifts dawn→noon→dusk→night
  • [playground/hud] alive-mode controls hint added (click to capture / WASD / Esc)
  • [playground/canvas] FreeCamera, SnowSystem, DirtRoad wired into PlaygroundCanvas
  • [playground] Step 8 (Spotify) permanently removed per decision — world atmosphere replaces audio player

Design note

The playground shifted from a passive scroll-diorama to a first-person explorable space. The key decision was keeping weather and time as ambient systems — SnowSystem, CloudDrift, BirdSystem, and TimeOfDay all run silently in the background, not as UI features. They exist to reward players who actually enter alive mode and look around. The 8-minute day cycle length was tuned to feel perceptible without feeling like a clock. Spotify (Step 8) was permanently dropped — it was the right call; the world speaks through atmosphere, not a player.

Terrain splat, HRTF spatial audio, and ghost HUD for the alpine world

v1.0.6
Apr 14, 2026 · 02:40·↗ frozen snapshot
newrefactor
  • [shader] TerrainMesh — MeshStandardMaterial extended via onBeforeCompile; fragment shader blends grass/rock/dirt/snow by normalised height and finite-difference slope; tiling at 32×; snow peaks above h=0.58, rock on steep slopes, dirt at mid-altitude, grass elsewhere
  • [shader] WaterPlane — custom ShaderMaterial at lake zone (x=-2, y=2.2, z=52), 55×40 world units; 2-octave FBM wave function, shore fade via smoothstep edge mask, depth tint, shimmer highlight; uTime updated each frame
  • [shader] Wind foliage — makeWindMaterial() clones MeshStandardMaterial, injects vertex sway proportional to local Y (roots stay planted); applied to Flower_1–5_Clump, Grass_Large, Grass_Large_Extruded via InstancedModel wind prop
  • [audio] AudioEngine class — Web Audio API HRTF PannerNode per source (panningModel: HRTF, distanceModel: inverse); per-zone GainNode crossfade via linearRampToValueAtTime (2s); synthetic reverb from exponentially-decayed noise impulse response
  • [audio] 8D orbiting sources — field birds, insects, forest wind, mountain wind, frogs rotate at 0.2 rad/s around listener XZ at radius 14wu; reverb wet scales 0.10→0.40 with normalised camera altitude
  • [audio] AudioSystem.tsx — R3F component inside Canvas; boots AudioEngine on audioStarted; drives listener pose, orbit tick, zone crossfades, reverb each useFrame
  • [page] AudioPrompt — bottom-left "tap for audio" mono button; sets audioStarted on click or first keydown; respects browser autoplay policy
  • [component] PlaygroundHUD — ghost overlay; Framer Motion fade+slide on mousemove, 3s auto-hide; journey/alive mode toggle, speed slider (0.5–2×), volume slider + mute toggle, Spotify placeholder (greyed, Step 8 deferred)
  • [design] Headphone nudge — "use headphones" appears bottom-right for 4s after first audio unlock, then fades; mono 10px, 0.25 opacity — invites but doesn't demand

Design note

The three systems in this session are about making the world feel real without any single obvious trick. Texture splatting means the terrain reads as actual geography — snow caps, rocky slopes, grassy valley floor — without a single UV-painted texture. The audio system is the one detail most visitors won't consciously notice but will feel: HRTF panning means sounds have genuine left/right/behind positioning in 3D space, and orbiting sources create the "8D" movement without any fake stereo tricks. The HUD is invisible until you need it — ghost-mode by design, so the landscape isn't cluttered with controls. The "use headphones" nudge is the one moment of explicit invitation.

Hand-crafted brand icons and a first essay on designing systems

v1.0.5
Apr 2, 2026 · 09:23·↗ frozen snapshot
new
  • [ui] Redesigned the Toolkit section on the about page — switched from text abbreviations to native SVG brand marks, matching the visual pattern of the design system page
  • [ui] Hand-sourced all SVG paths from Simple Icons, Wikimedia Commons, and official brand assets — covers Claude (Anthropic "A" mark), OpenAI (interlocking rings), Gemini (4-pointed star), Figma (5-shape logo), Cursor (hexagon), Photoshop and Lightroom (Adobe app tile), DaVinci Resolve (3-circle mark), Google (G shape), Lovable (L-path), v0 (Vercel wordmark), CapCut (inner cut symbol)
  • [content] Published first writing post at /writing/designing-systems — "On designing systems before they were needed" — covers the four internal systems built for this portfolio: changelog pipeline, design token architecture, git automation, and content engine
  • [content] Writing post includes rich Framer Motion animations — reading progress bar, scroll-triggered section reveals, animated system diagrams (dual-track changelog flow, token cascade, git timeline, content pipeline), pull quotes with animated left-border accent, and animated stat counters
  • [infra] Linked first writing post from about page Writing section; remaining posts stay "Coming soon" until ready

Design note

Each toolkit SVG was sourced from Simple Icons, Wikimedia Commons, and official brand assets — no icon library. The goal was pixel-accurate brand marks rather than generic approximations. The first writing post was written before any project case studies shipped deliberately — the systems (changelog pipeline, token architecture, git workflow, content engine) were the actual first work, and documenting them first was honest sequencing, not filler.

Homepage rebuilt: bio, bento stats, timezone quips, and identity update

v1.0.4
Mar 30, 2026 · 08:08·↗ frozen snapshot
fixnewdesign
  • [content] Rewrote homepage bio from generic copy to experience-grounded copy — 5+ years, fintech/SaaS/cybersecurity context, building with AI as a core practice
  • [identity] Updated title from "Design Engineer" to "Product Designer × Builder" across homepage hero, about page badge, and experience entry — reflects the actual shape of the work
  • [ui] Replaced flat info rows on homepage with a bento-style stats grid — pulsing availability dot, experience count, current role, and live clock with animated hands
  • [ui] Added Starfire as the hero project card on homepage; updated portfolio card gradient to blue; replaced placeholder card with a styled "Something new" entry
  • [ui] Added per-project hover cards on homepage (Divverse Labs inline link with animated tooltip showing company context on hover)
  • [ui] Built timezone quip system — detects visitor's UTC offset vs Abuja (GMT+1) and shows a context-aware typewriter-animated string (e.g. "YOU'RE 6H BEHIND — ALREADY ON TASK 10 :)"), with quips that vary by time of day (morning / evening / night)
  • [ui] Increased homepage top padding from 150px to 186px to give the floating header more breathing room
  • [ui] Added social links section to about page with icon badges, handle labels, and arrow-out affordance
  • [ui] Added info grid to about page (location, experience, current project) matching homepage bento pattern
  • [ui] Added Writing section stub to about page — links to first post, remaining entries show "Coming soon"

Design note

The identity shift from "Design Engineer" to "Product Designer × Builder" was intentional — the portfolio needed copy that reflects the actual shape of the work (designing and building with AI) rather than a job title that implies backend engineering. The bento stats grid was chosen over flat info rows because it lets the page communicate availability, experience, and current focus at a glance without needing the visitor to scroll into the bio.

Glassmorphism header, animated signature, and homepage polish

v1.0.3
Mar 29, 2026 · 17:06
new
  • session: glassmorphism header, animated signature, homepage + changelog polish

Headshot hover, About & Contact pages, homepage depth

v1.0.2
Mar 28, 2026 · 00:00
newdesignagent
  • Built /about page with personal story, 4 How I Work principles, Toolkit grid, Experience timeline, and Currently section
  • Built /contact page with availability badges, service cards, contact form with success state, and FAQ
  • Added avatar hover interaction on hero — cursor icon fades out as headshot photo fades and scales in
  • Extracted CursorIconSkeuo and CursorAvatar to shared component; added iconOffset prop for per-instance optical centering
  • Added "Now" section to homepage (building/learning/reading/thinking rows)
  • Added "Writing" section to homepage with 3 article teasers ready for real content
  • Simplified header: removed ⌘K search, nav text-xs for better pill proportion, theme toggle stays right

Design note

The CursorAvatar iconOffset prop solves a recurring problem — optical centering differs by size. The hero needs 2px, the 28px header slot only needs 1px. Making it a prop keeps the component honest rather than hard-coding a compromise.

Changelog page, floating header, and build pipeline

v1.0.1
Mar 27, 2026 · 00:00
newdesign
  • Changelog page built at /changelog — server component reads index.json, client component handles filtering and staggered animations
  • Every changelog entry card gets a permanent CardFooter strip for version, date, tags, and source metadata
  • Changelog build pipeline wired up — prebuild hook runs changelog:build before every next build automatically
  • Draft script updated to auto-generate entry titles from commit messages
  • CLAUDE.md created — documents design system tokens, card patterns, and hands-off changelog workflow
  • Header converted to floating pill with borderRadius 300px, surface fill, and double-ring outline
  • Scroll-triggered avatar added to header — slides in after 20px scroll, links back to home on click
  • Fixed Framer Motion v12 type conflicts in Button, page.tsx, and design-system page

Design note

The header was redesigned from a full-width sticky bar to a floating pill. Centering it with the same max-w-[640px] mx-auto px-6 wrapper as the page content — rather than a flex justify-center approach — is what keeps it from extending beyond the content column on wide screens. The double-ring treatment (border-strong + outline at outlineOffset 2px) matches the IconBadge chrome, making the header feel like a first-class design system element.

Initial portfolio foundation

v1.0.0
Mar 27, 2025 · 00:00
new
  • Next.js + TypeScript project scaffolded with App Router
  • Design system page created at /design-system
  • Core UI component library built: Avatar, Badge, Button, Card, CodeBlock, IconBadge, Input, Separator, Tag, ThemeToggle, Toggle
  • Header component implemented with sticky nav, ⌘K trigger, and theme toggle
  • Global styles, design tokens, and layout established — light and dark mode
  • Homepage built with hero, featured projects, newsletter, and footer sections
  • Changelog infrastructure scaffolded — platform + per-project surfaces

A portfolio should not be a scaffold for work. The work starts from the portfolio.

Overheard somewherea thought while you wait