An immersive, interactive developer portfolio built with Next.js 16, React Three Fiber, and Tailwind CSS v4. Features a 3D mechanical keyboard hero scene, seasonal themes, smooth scroll animations, bilingual support (ES/EN), and a fully responsive design.
Live Demo | Built by Txema Albero
- Interactive 3D Keyboard — A full mechanical keyboard rendered with React Three Fiber and Three.js. Keys react to real keypresses with physics-based animations and sound effects.
- Seasonal Themes — Four complete visual themes (Winter, Spring, Summer, Autumn) that re-skin the entire UI — colours, gradients, and 3D scene lighting — with a single click.
- Project Showcases — Modal dialogs with image carousels, tech stack chips, and links to live demos and source code.
- Bilingual (ES/EN) — Lightweight custom i18n layer with zero external dependencies. Language toggle persists across sections.
- Smooth Scroll & Reveal Animations — Powered by Lenis for buttery smooth scrolling with intersection-observer-based reveal effects.
- Custom Cursor & Magnetic Targets — A custom cursor that morphs on interactive elements, with magnetic snap behaviour on buttons.
- Responsive & Mobile-First — Optimised for recruiters reviewing on phones. WebGL performance and touch interactions are first-class concerns.
- Security Headers — HSTS, X-Frame-Options, Content-Type-Options, Referrer-Policy, and Permissions-Policy configured out of the box.
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router, Turbopack) |
| 3D | React Three Fiber + @react-three/drei + Three.js |
| Styling | Tailwind CSS v4 |
| Scroll | Lenis |
| Icons | Simple Icons (tech logos on 3D keycaps) |
| Language | TypeScript |
| Deploy | Vercel / Docker |
- Node.js 20+
- npm 10+
# Clone the repository
git clone https://github.com/Txemalon/3d-portfolio.git
cd 3d-portfolio
# Install dependencies
npm install
# Start the development server
npm run devOpen http://localhost:3000 in your browser.
npm run build
npm startThe project includes a multi-stage Dockerfile optimised for production (standalone output, ~100 MB final image):
docker build -t 3d-portfolio .
docker run -p 3000:3000 3d-portfolio├── app/
│ ├── globals.css # Tailwind + CSS custom properties (seasonal themes)
│ ├── layout.tsx # Root layout with providers
│ └── page.tsx # Home page with all sections
├── components/
│ ├── FrozenKeyboard.tsx # 3D keyboard scene (R3F)
│ ├── FrozenBackground.tsx # Animated background particles
│ ├── Carousel.tsx # Image carousel for project modals
│ ├── ProjectModal.tsx # Fullscreen project detail dialog
│ ├── SeasonProvider.tsx # Seasonal theme context
│ ├── SeasonPicker.tsx # Theme switcher UI
│ ├── LanguageProvider.tsx # i18n context
│ ├── LanguagePicker.tsx # Language toggle
│ ├── CustomCursor.tsx # Custom cursor with hover states
│ ├── MagneticTargets.tsx# Magnetic snap on interactive elements
│ ├── Reveal.tsx # Scroll-triggered reveal animations
│ ├── SectionNav.tsx # Dot navigation sidebar
│ ├── ScrollProgress.tsx # Scroll progress indicator
│ ├── CopyEmail.tsx # Copy-to-clipboard button
│ └── smooth-scroll.tsx # Lenis smooth scroll wrapper
├── lib/
│ ├── i18n.ts # Bilingual dictionary (ES/EN)
│ └── seasons.ts # Season theme definitions
├── public/
│ ├── fonts/ # 3D text typefaces
│ ├── projects/ # Project screenshots
│ └── sounds/ # Keyboard sound effects
├── Dockerfile # Multi-stage production build
├── next.config.ts # Standalone output + security headers
└── package.json
Projects are defined in app/page.tsx in the projects array. Each entry supports:
{
num: "05",
name: { es: "Mi Proyecto", en: "My Project" },
stack: ["Next.js", "TypeScript"],
desc: { es: "Descripción corta", en: "Short description" },
details: { es: "Descripción larga...", en: "Long description..." },
url: "https://myproject.com", // optional — adds "View Site" button
github: "https://github.com/user/repo", // optional — adds "View Code" button
media: ["/projects/my-project/1.png"], // optional — carousel screenshots
highlights: ["nextdotjs", "typescript"], // simple-icons slugs for 3D keyboard
badge: { es: "En desarrollo", en: "In progress" }, // optional status badge
align: "left", // card alignment
section: "project5", // data attribute for scroll nav
}Seasonal colour tokens are defined as CSS custom properties in app/globals.css under [data-season="..."] selectors. Edit or add new seasons there.
All UI strings live in lib/i18n.ts as a flat dictionary with { es, en } leaves. Add new keys or languages by extending the structure.
The included Dockerfile produces a standalone Next.js image. Works with any container platform (Railway, Fly.io, Coolify, etc.):
docker build -t 3d-portfolio .
docker run -p 3000:3000 3d-portfolio- Standalone output — No
node_modulesin production; the Docker image is ~100 MB. - Lazy loading — Project screenshots use native lazy loading.
- Font optimisation — Uses
next/fontfor zero-layout-shift web fonts. - Turbopack — Sub-300ms dev server cold starts.
This project is open source and available under the MIT License.
Jose Maria Albero Belamendia (Txema)