The design and the engineering problem
The page combines oversized serif headings, a cream background, a curved black statement section and a lime footer. The interactive centerpiece needs a browser and a graphics context, but the introduction, project links and contact information should be readable before that scene finishes loading.
The implementation uses Next.js App Router, TypeScript and reusable React components. The homepage, project collection, contact information and legal pages are generated as HTML. Interactive components handle the project preview and contact form. A Node.js route processes contact requests.
Keeping Three.js separate from the page content
The hero dynamically imports its graphics component with server rendering disabled for that component. The surrounding heading and page content still appear in the server response. React Three Fiber manages the canvas, while Drei supplies the distorted material, studio environment and contact shadow.
The sculpture combines a subtly deformed icosahedron with three torus rings. A metallic material reflects the studio environment, and damped pointer input adjusts the group’s rotation. These are actual meshes rendered through WebGL, rather than a pre-recorded video.
Putting limits on the animation
An IntersectionObserver pauses the canvas frame loop when the scene leaves the viewport. Device pixel ratio is capped at 1.25, the sphere uses reduced mesh detail, and the contact shadow is captured once instead of recomputed continuously. These choices reduce ongoing graphics work; they do not establish a measured frame rate for every device.
The component subscribes to the browser’s reduced-motion preference. In that mode, floating and material motion stop and the canvas uses on-demand rendering. A static fallback is provided for browsers that cannot create the graphics context. GSAP controls the page’s section reveals and checks the same motion preference.
A small contact endpoint with clear boundaries
The form sends name, email, topic and message fields to a Next.js route. Server-side validation checks required fields, the email format and minimum message length. Inputs have bounded lengths, and text is escaped before it is inserted into an HTML email. The endpoint uses Resend for delivery.
A hidden honeypot and an in-memory rate limiter provide basic abuse controls. The limiter is process-local: it is not a shared limit across serverless instances. Client validation focuses the first invalid field, and status messages are associated with the inputs. The privacy page explains the message handling; no visitor database or analytics tracker is required for the portfolio.
Making the content discoverable
Every public page has its own title, description and canonical URL. Metadata, sitemap entries and structured data use the www hostname that the production domain redirects to. Person, WebSite and breadcrumb data describe the visible identity and navigation without adding invented ratings or credentials.
The same display and handwriting fonts are bundled with next/font and served locally. A dependency-free check requests production HTML and verifies titles, canonicals, descriptions, one H1 per page, social images, JSON-LD syntax and internal links. These checks catch implementation errors; Google still decides which URLs and queries appear in search.