Skip to content
+x 0.000 y 0.000
料金予約
Back to blog

Building This Portfolio

|

Why Another Portfolio

Most developer portfolios feel interchangeable—dark mode, gradient blobs, and scroll-triggered fade-ins. I wanted something that felt intentional. Something closer to architecture than web design.

The direction: Japanese Brutalist. Raw structure, visible grids, generous negative space (ma/間), kanji as visual weight, and a warm, earthy palette instead of the usual dark-on-dark aesthetic.


The Globe: 3D Math in a 2D World

The centerpiece is a wireframe sphere rendered on a 2D canvas. No Three.js. No WebGL. Just fillRect calls for each point to maintain a raw, low-fi aesthetic.

The Mathematics

The sphere uses a Fibonacci spiral to distribute 900 points evenly across the surface. Latitude and longitude rings add structural wireframe lines. The entire system rotates via manual rotation matrices applied to every point, every frame.

function rotateYAxis(x, y, z, angle) {
  const cos = Math.cos(angle);
  const sin = Math.sin(angle);
  return [x * cos + z * sin, y, -x * sin + z * cos];
}

Audio Reactivity

When audio is playing, the globe responds to real-time frequency analysis:

  • Bass frequencies expand the sphere's radius.
  • Treble frequencies increase individual point sizes.
  • Beat detection spawns ripple waves that propagate across the surface.

Note: The AudioContext only initializes after explicit user interaction to comply with modern browser autoplay policies.


Instead of standard scroll-based sections, the portfolio uses a robust slide system with GSAP-powered transitions. Each slide occupies the full viewport, creating a "spatial" feel.

Navigation Methods:

  • Keyboard: Arrow keys for precise jumping.
  • Mouse: Wheel interaction with a "dwell-at-boundary" pattern to prevent accidental rapid-fire slides.
  • Touch: Swipe gestures for mobile parity.

The globe smoothly interpolates (lerps) between positions for each slide — large and centered for the Hero (67% x, 50% y, 32% radius), small and top-right for About (88%, 18%, 14%), bottom-left for Experience (15%, 82%, 16%), and pinned to the right half for Projects, where it becomes a planetarium: each project orbits the sphere as a clickable planet.


Design System in Practice

Color & Typography

The palette is intentionally muted. Background is a warm clay (#f5f0eb), foreground is a soft near-black (#1a1a1a), and the accent is a terracotta (#a35b42) reserved for active states.

ElementTypefaceStyle
Kanji DisplayNoto Sans JP900 weight, Massive scale
Editorial HeadingsGeist600 weight, Semi-bold
Structural LabelsGeist MonoUppercase, tracking-widest

The Grid

A persistent architectural grid overlays every slide—vertical lines at 8%, 25%, 50%, 75%, and 92% width; horizontal lines at 12%, 38%, 72%, and 88% height. These aren't decorative; they provide the structural rhythm that makes the negative space feel intentional rather than empty.


Lessons Learned

  1. Canvas Performance: 900 points at 60fps is manageable, but per-point wave displacement calculations pushed the limits. Minimizing trigonometry and avoiding expensive operations per point was essential.
  2. Embracing "Ma": The hardest design decision was leaving gaps empty. Resisting the impulse to fill every space is what makes the design work.
  3. Fragile APIs: The Web Audio API is temperamental. Browser policies and suspended states required defensive handling and graceful degradation.

Technical Stack

  • Framework: Next.js 16 (App Router)
  • Animation: GSAP 3.14
  • Styling: Tailwind CSS 4
  • Typography: Noto Sans JP (kanji + body), Geist (editorial headings), Geist Mono (labels)
  • State: React 19 Server Components

Update — August 2026

Six months on, the slide deck is no longer the whole site. It's the front door to a set of standalone routes, all sharing the same grid, palette, and page-transition loader:

RouteWhat it is
/blogThis. File-system MDX, fully static at build time
/changelogGit log parsed at build time, grouped by month
/marketLive crypto watchlist via a CoinGecko proxy route
/paymeQRIS + Ethereum payment page
/ratecardFreelance scoping wizard
/pokedex図鑑 — a PokéAPI browser, built for the fun of it
/booking予約 — a themed Cal.com embed, wired to the ratecard result

Two structural things changed to make that work. PageOverlays became the shared layer wrapper so every route gets the grid, crosshair, globe, and audio player without duplicating them. And the navbar grew a More dropdown — on mobile and desktop — because seven routes will not fit in a bar designed for four.

The globe follows along: on non-slide routes it drops into an ambient position (88% x, 15% y, 12% radius), decorative and out of the way.