Pages Hard
Tech Lead Portfolio
Corporate tech lead portfolio with Three.js wireframe hero, vertical career timeline, expertise grid, and open source repo showcase.
Open in Lab
MCP
three.js gsap lenis scrolltrigger splittext
Targets: JS HTML
Code
/* โโโ Reset & Base โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--bg: #ffffff;
--dark: #0d1b2a;
--text: #0d1b2a;
--muted: #6b7a8d;
--accent: #2563eb;
--light: #f0f4ff;
--border: #e2e8f0;
--radius: 12px;
--radius-sm: 6px;
--font: -apple-system, BlinkMacSystemFont, "Segoe UI", "Inter", "Helvetica Neue", Arial,
sans-serif;
--font-mono: "SFMono-Regular", "Consolas", "Liberation Mono", "Menlo", monospace;
}
html {
scroll-behavior: smooth;
}
body {
font-family: var(--font);
background: var(--bg);
color: var(--text);
overflow-x: hidden;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
color: inherit;
text-decoration: none;
}
ul {
list-style: none;
}
img {
display: block;
max-width: 100%;
}
/* โโโ Shared Section Layout โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.section {
padding: clamp(5rem, 10vw, 9rem) clamp(1.5rem, 6vw, 7rem);
max-width: 1240px;
margin: 0 auto;
}
.section__header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 2rem;
margin-bottom: clamp(3rem, 6vw, 5rem);
padding-bottom: 2rem;
border-bottom: 1px solid var(--border);
}
.section__label-group {
display: flex;
align-items: baseline;
gap: 1rem;
}
.section-index {
font-size: 0.75rem;
font-weight: 600;
color: var(--accent);
font-family: var(--font-mono);
letter-spacing: 0.05em;
}
.section-label {
font-size: 0.8rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--muted);
}
.section__summary {
font-size: 0.9rem;
color: var(--muted);
max-width: 30ch;
line-height: 1.6;
text-align: right;
}
/* โโโ Hero โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.hero {
position: relative;
min-height: 100svh;
background: var(--dark);
display: flex;
flex-direction: column;
overflow: hidden;
}
.hero__canvas {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 0;
}
.hero__inner {
position: relative;
z-index: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
flex: 1;
padding: clamp(2rem, 4vw, 4rem) clamp(1.5rem, 6vw, 7rem);
padding-bottom: 5rem;
}
.hero__eyebrow {
display: flex;
align-items: center;
gap: 0.75rem;
padding-top: 1rem;
}
.eyebrow-tag {
font-size: 0.75rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: rgba(255, 255, 255, 0.5);
}
.eyebrow-dot {
width: 4px;
height: 4px;
border-radius: 50%;
background: var(--accent);
flex-shrink: 0;
}
.eyebrow-avail {
font-size: 0.75rem;
font-weight: 600;
color: var(--accent);
letter-spacing: 0.04em;
}
.hero__name {
font-size: clamp(4rem, 12vw, 10rem);
font-weight: 900;
line-height: 0.9;
letter-spacing: -0.04em;
color: #ffffff;
margin-top: auto;
padding-top: 2rem;
overflow: hidden;
}
.hero__name .line {
overflow: hidden;
display: block;
}
.hero__foot {
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 2rem;
flex-wrap: wrap;
margin-top: 3rem;
}
.hero__tagline {
font-size: clamp(1rem, 2vw, 1.2rem);
font-weight: 400;
line-height: 1.6;
color: rgba(255, 255, 255, 0.55);
max-width: 36ch;
}
.hero__ctas {
display: flex;
gap: 0.875rem;
flex-shrink: 0;
}
.btn {
display: inline-flex;
align-items: center;
height: 48px;
padding: 0 1.75rem;
border-radius: 6px;
font-size: 0.875rem;
font-weight: 600;
letter-spacing: 0.02em;
transition: transform 0.2s ease, opacity 0.2s ease, background 0.2s ease;
cursor: pointer;
}
.btn--primary {
background: var(--accent);
color: #fff;
}
.btn--primary:hover {
background: #1d4fd8;
transform: translateY(-1px);
}
.btn--ghost {
background: transparent;
color: rgba(255, 255, 255, 0.7);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.btn--ghost:hover {
background: rgba(255, 255, 255, 0.06);
color: #fff;
border-color: rgba(255, 255, 255, 0.35);
}
.hero__scroll-indicator {
position: absolute;
bottom: 2.5rem;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
z-index: 2;
}
.scroll-track {
width: 1px;
height: 48px;
background: rgba(255, 255, 255, 0.12);
border-radius: 1px;
overflow: hidden;
position: relative;
}
.scroll-thumb {
position: absolute;
top: -100%;
left: 0;
width: 100%;
height: 50%;
background: var(--accent);
border-radius: 1px;
animation: scrollThumb 1.8s ease-in-out infinite;
}
@keyframes scrollThumb {
0% {
top: -50%;
}
100% {
top: 100%;
}
}
.scroll-label {
font-size: 0.65rem;
font-weight: 600;
letter-spacing: 0.15em;
text-transform: uppercase;
color: rgba(255, 255, 255, 0.3);
}
/* โโโ Expertise Section โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.expertise {
background: var(--bg);
}
.expertise__grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.5rem;
}
@media (max-width: 900px) {
.expertise__grid {
grid-template-columns: 1fr;
}
}
.expertise-card {
background: var(--light);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 2.5rem 2rem;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.expertise-card:hover {
transform: translateY(-4px);
box-shadow: 0 16px 48px rgba(37, 99, 235, 0.08);
}
/* CSS geometric icons */
.expertise-card__icon {
width: 48px;
height: 48px;
margin-bottom: 1.5rem;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.icon-backend {
width: 36px;
height: 36px;
border: 2.5px solid var(--accent);
border-radius: 6px;
position: relative;
}
.icon-backend::before {
content: "";
position: absolute;
top: 6px;
left: 6px;
right: 6px;
height: 2px;
background: var(--accent);
border-radius: 1px;
box-shadow: 0 6px 0 var(--accent), 0 12px 0 var(--accent);
}
.icon-platform {
width: 36px;
height: 36px;
border-radius: 50%;
border: 2.5px solid var(--accent);
position: relative;
}
.icon-platform::before {
content: "";
position: absolute;
inset: 6px;
border-radius: 50%;
border: 2.5px solid var(--accent);
}
.icon-platform::after {
content: "";
position: absolute;
width: 8px;
height: 8px;
background: var(--accent);
border-radius: 50%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.icon-leadership {
width: 36px;
height: 36px;
position: relative;
}
.icon-leadership::before {
content: "";
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 28px;
height: 18px;
border: 2.5px solid var(--accent);
border-radius: 14px 14px 6px 6px;
border-bottom: none;
}
.icon-leadership::after {
content: "";
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
width: 14px;
height: 14px;
border: 2.5px solid var(--accent);
border-radius: 50%;
}
.expertise-card__title {
font-size: 1.1rem;
font-weight: 700;
letter-spacing: -0.02em;
margin-bottom: 1.25rem;
color: var(--text);
}
.expertise-card__list {
display: flex;
flex-direction: column;
gap: 0.6rem;
}
.expertise-card__list li {
font-size: 0.875rem;
color: var(--muted);
line-height: 1.5;
padding-left: 1rem;
position: relative;
}
.expertise-card__list li::before {
content: "";
position: absolute;
left: 0;
top: 0.55em;
width: 4px;
height: 4px;
border-radius: 50%;
background: var(--accent);
}
/* โโโ Timeline Section โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.timeline {
background: var(--bg);
padding-top: 0;
}
.timeline__track {
position: relative;
display: flex;
flex-direction: column;
gap: 0;
}
.timeline__line {
position: absolute;
left: 50%;
top: 0;
bottom: 0;
width: 1px;
background: var(--border);
transform: translateX(-50%);
z-index: 0;
}
.timeline-item {
display: grid;
grid-template-columns: 1fr auto 1fr;
gap: 0 2.5rem;
align-items: start;
padding: 2.5rem 0;
position: relative;
z-index: 1;
}
/* Year dot on center line */
.timeline-item::after {
content: "";
position: absolute;
left: 50%;
top: 2.9rem;
transform: translateX(-50%);
width: 10px;
height: 10px;
border-radius: 50%;
background: var(--accent);
border: 2px solid var(--bg);
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.2);
z-index: 2;
}
.timeline-item__year {
font-size: 0.8rem;
font-weight: 700;
font-family: var(--font-mono);
color: var(--accent);
letter-spacing: 0.06em;
padding-top: 0.35rem;
}
.timeline-item__card {
background: var(--light);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 1.75rem;
}
.timeline-item__meta {
display: flex;
align-items: baseline;
flex-wrap: wrap;
gap: 0.4rem;
margin-bottom: 0.875rem;
}
.timeline-item__role {
font-size: 0.95rem;
font-weight: 700;
color: var(--text);
letter-spacing: -0.01em;
}
.timeline-item__sep {
color: var(--border);
font-weight: 300;
}
.timeline-item__company {
font-size: 0.875rem;
font-weight: 600;
color: var(--accent);
}
.timeline-item__desc {
font-size: 0.875rem;
color: var(--muted);
line-height: 1.7;
}
/* Left-aligned: year left, empty center col, card right */
.timeline-item--left .timeline-item__year {
text-align: right;
grid-column: 1;
grid-row: 1;
}
.timeline-item--left .timeline-item__card {
grid-column: 3;
grid-row: 1;
}
/* Right-aligned: card left, empty center col, year right */
.timeline-item--right .timeline-item__card {
grid-column: 1;
grid-row: 1;
}
.timeline-item--right .timeline-item__year {
grid-column: 3;
grid-row: 1;
padding-top: 0.35rem;
}
@media (max-width: 768px) {
.timeline__line {
left: 1rem;
}
.timeline-item {
grid-template-columns: 1fr;
padding-left: 3rem;
}
.timeline-item::after {
left: 1rem;
transform: translateX(-50%);
}
.timeline-item--left .timeline-item__year,
.timeline-item--right .timeline-item__year {
grid-column: 1;
grid-row: 1;
text-align: left;
font-size: 0.75rem;
margin-bottom: 0.5rem;
}
.timeline-item--left .timeline-item__card,
.timeline-item--right .timeline-item__card {
grid-column: 1;
grid-row: 2;
}
}
/* โโโ Open Source Section โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.open-source {
background: var(--light);
border-radius: 0;
max-width: unset;
padding-left: 0;
padding-right: 0;
}
.open-source .section__header {
max-width: 1240px;
margin-left: auto;
margin-right: auto;
padding-left: clamp(1.5rem, 6vw, 7rem);
padding-right: clamp(1.5rem, 6vw, 7rem);
}
.repos__grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1.25rem;
max-width: 1240px;
margin: 0 auto;
padding: 0 clamp(1.5rem, 6vw, 7rem);
}
@media (max-width: 900px) {
.repos__grid {
grid-template-columns: 1fr;
}
}
.repo-card {
display: flex;
flex-direction: column;
gap: 0.875rem;
background: var(--bg);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 1.75rem;
cursor: pointer;
transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease;
color: var(--text);
}
.repo-card:hover {
transform: translateY(-3px);
box-shadow: 0 12px 36px rgba(37, 99, 235, 0.1);
border-color: rgba(37, 99, 235, 0.3);
}
.repo-card__top {
display: flex;
align-items: center;
gap: 0.6rem;
}
.repo-card__icon {
color: var(--muted);
flex-shrink: 0;
display: flex;
align-items: center;
}
.repo-card__name {
font-size: 0.9rem;
font-weight: 700;
font-family: var(--font-mono);
color: var(--accent);
flex: 1;
}
.repo-card__stars {
display: flex;
align-items: center;
gap: 0.3rem;
font-size: 0.78rem;
font-weight: 600;
color: var(--muted);
margin-left: auto;
flex-shrink: 0;
}
.repo-card__stars svg {
color: #f59e0b;
}
.repo-card__desc {
font-size: 0.85rem;
color: var(--muted);
line-height: 1.65;
flex: 1;
}
.repo-card__foot {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.75rem;
margin-top: auto;
padding-top: 0.75rem;
border-top: 1px solid var(--border);
}
.lang-pill {
display: inline-flex;
align-items: center;
gap: 0.4rem;
padding: 0.25rem 0.7rem;
border-radius: 100px;
font-size: 0.72rem;
font-weight: 600;
letter-spacing: 0.03em;
}
.lang-pill::before {
content: "";
width: 8px;
height: 8px;
border-radius: 50%;
}
.lang-pill--go {
background: #e0f0ff;
color: #0078d4;
}
.lang-pill--go::before {
background: #0078d4;
}
.lang-pill--ts {
background: #e0e8ff;
color: #3178c6;
}
.lang-pill--ts::before {
background: #3178c6;
}
.lang-pill--rust {
background: #fbe8e0;
color: #b7410e;
}
.lang-pill--rust::before {
background: #b7410e;
}
.repo-card__updated {
font-size: 0.72rem;
color: var(--muted);
}
/* โโโ Contact Section โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.contact {
background: var(--dark);
max-width: unset;
padding-top: clamp(5rem, 10vw, 9rem);
padding-bottom: 0;
padding-left: 0;
padding-right: 0;
}
.contact__inner {
max-width: 1240px;
margin: 0 auto;
padding: 0 clamp(1.5rem, 6vw, 7rem);
padding-bottom: clamp(5rem, 10vw, 9rem);
}
.contact__kicker {
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--accent);
margin-bottom: 1.5rem;
}
.contact__cta {
font-size: clamp(3rem, 8vw, 7rem);
font-weight: 900;
letter-spacing: -0.04em;
line-height: 0.92;
color: #ffffff;
margin-bottom: 3.5rem;
overflow: hidden;
}
.contact__cta .line {
overflow: hidden;
display: block;
}
.contact__links {
display: flex;
align-items: center;
gap: 3rem;
flex-wrap: wrap;
}
.contact__email {
font-size: 1.1rem;
font-weight: 600;
color: rgba(255, 255, 255, 0.85);
border-bottom: 1px solid rgba(255, 255, 255, 0.25);
padding-bottom: 2px;
transition: color 0.2s ease, border-color 0.2s ease;
}
.contact__email:hover {
color: #fff;
border-color: var(--accent);
}
.contact__social {
display: flex;
gap: 1.75rem;
}
.social-link {
font-size: 0.875rem;
font-weight: 600;
color: rgba(255, 255, 255, 0.45);
letter-spacing: 0.03em;
transition: color 0.2s ease;
}
.social-link:hover {
color: rgba(255, 255, 255, 0.9);
}
.contact__foot {
max-width: 1240px;
margin: 0 auto;
padding: 1.75rem clamp(1.5rem, 6vw, 7rem);
border-top: 1px solid rgba(255, 255, 255, 0.08);
display: flex;
justify-content: space-between;
align-items: center;
gap: 1rem;
flex-wrap: wrap;
}
.contact__foot span {
font-size: 0.78rem;
color: rgba(255, 255, 255, 0.28);
font-weight: 500;
}
/* โโโ Reduced Motion โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.reduced-motion *,
.reduced-motion *::before,
.reduced-motion *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
.reduced-motion .scroll-thumb {
animation: none !important;
}if (!window.MotionPreference) {
const __mql = window.matchMedia("(prefers-reduced-motion: reduce)");
const __listeners = new Set();
const MotionPreference = {
prefersReducedMotion() {
return __mql.matches;
},
setOverride(value) {
const reduced = Boolean(value);
document.documentElement.classList.toggle("reduced-motion", reduced);
window.dispatchEvent(new CustomEvent("motion-preference", { detail: { reduced } }));
for (const listener of __listeners) {
try {
listener({ reduced, override: reduced, systemReduced: __mql.matches });
} catch {}
}
},
onChange(listener) {
__listeners.add(listener);
try {
listener({
reduced: __mql.matches,
override: null,
systemReduced: __mql.matches,
});
} catch {}
return () => __listeners.delete(listener);
},
getState() {
return { reduced: __mql.matches, override: null, systemReduced: __mql.matches };
},
};
window.MotionPreference = MotionPreference;
}
function prefersReducedMotion() {
return window.MotionPreference.prefersReducedMotion();
}
function initDemoShell() {
// No-op shim in imported standalone snippets.
}
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import { SplitText } from "gsap/SplitText";
import Lenis from "lenis";
import * as THREE from "three";
gsap.registerPlugin(ScrollTrigger, SplitText);
// โโโ Shell โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
initDemoShell({
title: "Tech Lead Portfolio",
category: "pages",
tech: ["three.js", "gsap", "lenis", "scrolltrigger", "splittext"],
});
// โโโ Reduced Motion โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
let reduced = prefersReducedMotion();
if (reduced) document.documentElement.classList.add("reduced-motion");
window.addEventListener("motion-preference", (e) => {
reduced = e.detail.reduced;
document.documentElement.classList.toggle("reduced-motion", reduced);
ScrollTrigger.refresh();
});
const dur = (d) => (reduced ? 0 : d);
// โโโ Lenis โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const lenis = new Lenis({ lerp: 0.1, smoothWheel: true });
lenis.on("scroll", ScrollTrigger.update);
gsap.ticker.add((time) => lenis.raf(time * 1000));
gsap.ticker.lagSmoothing(0);
// โโโ Three.js Hero Background โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
function initHeroCanvas() {
const canvas = document.getElementById("heroCanvas");
if (!canvas) return;
const hero = document.querySelector(".hero");
const w = hero.offsetWidth;
const h = hero.offsetHeight;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(60, w / h, 0.1, 100);
camera.position.z = 8;
const renderer = new THREE.WebGLRenderer({ canvas, alpha: true, antialias: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(w, h);
renderer.setClearColor(0x000000, 0);
const geos = [
new THREE.IcosahedronGeometry(1, 0),
new THREE.OctahedronGeometry(1, 0),
new THREE.TetrahedronGeometry(1, 0),
];
const mat = new THREE.MeshBasicMaterial({
color: 0x2563eb,
wireframe: true,
opacity: 0.15,
transparent: true,
});
const meshes = [];
for (let i = 0; i < 12; i++) {
const m = new THREE.Mesh(geos[i % 3], mat);
m.position.set(
(Math.random() - 0.5) * 16,
(Math.random() - 0.5) * 10,
(Math.random() - 0.5) * 8
);
m.scale.setScalar(0.4 + Math.random() * 1.2);
m.userData.offset = Math.random() * Math.PI * 2;
meshes.push(m);
scene.add(m);
}
let animId = null;
function animate() {
animId = requestAnimationFrame(animate);
const t = Date.now() * 0.0005;
meshes.forEach((m, i) => {
m.rotation.x += 0.002 + i * 0.0003;
m.rotation.y += 0.003 + i * 0.0002;
m.position.y += Math.sin(t + m.userData.offset) * 0.002;
});
renderer.render(scene, camera);
}
if (!reduced) {
animate();
} else {
renderer.render(scene, camera);
}
function onResize() {
const nw = hero.offsetWidth;
const nh = hero.offsetHeight;
camera.aspect = nw / nh;
camera.updateProjectionMatrix();
renderer.setSize(nw, nh);
}
window.addEventListener("resize", onResize);
// Pause rendering when hero is fully scrolled past
ScrollTrigger.create({
trigger: ".hero",
start: "top top",
end: "bottom top",
onLeave: () => {
if (animId) {
cancelAnimationFrame(animId);
animId = null;
}
},
onEnterBack: () => {
if (!animId && !reduced) animate();
},
});
}
// โโโ Hero Animations โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
function animateHero() {
const nameEl = document.getElementById("heroName");
const taglineEl = document.getElementById("heroTagline");
if (nameEl) {
const splitName = new SplitText(nameEl, { type: "words,lines", linesClass: "line" });
gsap.set(splitName.words, { y: 50, opacity: 0 });
gsap.to(splitName.words, {
y: 0,
opacity: 1,
duration: dur(1),
ease: "expo.out",
stagger: { each: dur(0.06) },
delay: dur(0.3),
});
}
if (taglineEl) {
gsap.from(taglineEl, {
y: reduced ? 0 : 24,
opacity: 0,
duration: dur(0.9),
ease: "expo.out",
delay: dur(0.7),
});
}
gsap.from(".hero__eyebrow", {
opacity: 0,
y: reduced ? 0 : -12,
duration: dur(0.7),
ease: "expo.out",
delay: dur(0.15),
});
gsap.from(".hero__ctas", {
opacity: 0,
y: reduced ? 0 : 18,
duration: dur(0.8),
ease: "expo.out",
delay: dur(0.9),
});
gsap.from(".hero__scroll-indicator", {
opacity: 0,
duration: dur(1),
delay: dur(1.4),
});
}
// โโโ Expertise Cards โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
function animateExpertise() {
const cards = document.querySelectorAll(".expertise-card");
if (!cards.length) return;
gsap.set(cards, { scale: 0.92, opacity: 0 });
gsap.to(cards, {
scale: 1,
opacity: 1,
duration: dur(0.75),
ease: "expo.out",
stagger: { each: dur(0.1) },
scrollTrigger: {
trigger: ".expertise__grid",
start: "top 78%",
toggleActions: "play none none reverse",
},
});
}
// โโโ Timeline Items โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
function animateTimeline() {
document.querySelectorAll(".timeline-item").forEach((item) => {
const isLeft = item.classList.contains("timeline-item--left");
const card = item.querySelector(".timeline-item__card");
const year = item.querySelector(".timeline-item__year");
if (card) {
gsap.set(card, { x: reduced ? 0 : isLeft ? 48 : -48, opacity: 0 });
gsap.to(card, {
x: 0,
opacity: 1,
duration: dur(0.8),
ease: "expo.out",
scrollTrigger: {
trigger: item,
start: "top 80%",
toggleActions: "play none none reverse",
},
});
}
if (year) {
gsap.set(year, { x: reduced ? 0 : isLeft ? -24 : 24, opacity: 0 });
gsap.to(year, {
x: 0,
opacity: 1,
duration: dur(0.7),
ease: "expo.out",
delay: dur(0.08),
scrollTrigger: {
trigger: item,
start: "top 80%",
toggleActions: "play none none reverse",
},
});
}
});
// Grow the center line in from top
gsap.from(".timeline__line", {
scaleY: 0,
transformOrigin: "top center",
duration: dur(1.5),
ease: "expo.out",
scrollTrigger: {
trigger: ".timeline__track",
start: "top 75%",
toggleActions: "play none none reverse",
},
});
}
// โโโ Repo Cards โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
function animateRepos() {
const cards = document.querySelectorAll(".repo-card");
if (!cards.length) return;
gsap.set(cards, { y: reduced ? 0 : 40, opacity: 0 });
gsap.to(cards, {
y: 0,
opacity: 1,
duration: dur(0.75),
ease: "expo.out",
stagger: { each: dur(0.1) },
scrollTrigger: {
trigger: ".repos__grid",
start: "top 78%",
toggleActions: "play none none reverse",
},
});
}
// โโโ Contact CTA โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
function animateContact() {
const ctaEl = document.getElementById("contactCta");
if (ctaEl) {
const splitCta = new SplitText(ctaEl, { type: "words,lines", linesClass: "line" });
gsap.set(splitCta.words, { y: 60, opacity: 0 });
gsap.to(splitCta.words, {
y: 0,
opacity: 1,
duration: dur(0.95),
ease: "expo.out",
stagger: { each: dur(0.06) },
scrollTrigger: {
trigger: ".contact__inner",
start: "top 80%",
toggleActions: "play none none reverse",
},
});
}
gsap.from(".contact__kicker", {
opacity: 0,
y: reduced ? 0 : 16,
duration: dur(0.7),
ease: "expo.out",
scrollTrigger: {
trigger: ".contact__inner",
start: "top 80%",
toggleActions: "play none none reverse",
},
});
gsap.from(".contact__links", {
opacity: 0,
y: reduced ? 0 : 20,
duration: dur(0.8),
ease: "expo.out",
delay: dur(0.35),
scrollTrigger: {
trigger: ".contact__inner",
start: "top 75%",
toggleActions: "play none none reverse",
},
});
}
// โโโ Section Headers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
function animateSectionHeaders() {
document.querySelectorAll(".section__header").forEach((el) => {
gsap.from(el, {
opacity: 0,
y: reduced ? 0 : 16,
duration: dur(0.65),
ease: "expo.out",
scrollTrigger: {
trigger: el,
start: "top 88%",
toggleActions: "play none none reverse",
},
});
});
}
// โโโ Init โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
initHeroCanvas();
animateHero();
animateSectionHeaders();
animateExpertise();
animateTimeline();
animateRepos();
animateContact();<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tech Lead Portfolio โ Marcus Chen</title>
<link rel="stylesheet" href="style.css" />
<script type="importmap">{"imports":{"gsap":"https://esm.sh/gsap@3.13.0","gsap/ScrollTrigger":"https://esm.sh/gsap@3.13.0/ScrollTrigger","gsap/SplitText":"https://esm.sh/gsap@3.13.0/SplitText","gsap/Flip":"https://esm.sh/gsap@3.13.0/Flip","gsap/ScrambleTextPlugin":"https://esm.sh/gsap@3.13.0/ScrambleTextPlugin","gsap/TextPlugin":"https://esm.sh/gsap@3.13.0/TextPlugin","gsap/all":"https://esm.sh/gsap@3.13.0/all","gsap/":"https://esm.sh/gsap@3.13.0/","lenis":"https://esm.sh/lenis@1.1.13/dist/lenis.mjs","three":"https://esm.sh/three@0.171.0","three/addons/":"https://esm.sh/three@0.171.0/examples/jsm/"}}</script>
</head>
<body>
<!-- โโโ HERO โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ -->
<section class="hero" id="hero">
<canvas class="hero__canvas" id="heroCanvas" aria-hidden="true"></canvas>
<div class="hero__inner">
<div class="hero__eyebrow">
<span class="eyebrow-tag">Engineering Lead</span>
<span class="eyebrow-dot" aria-hidden="true"></span>
<span class="eyebrow-avail">Available for new roles</span>
</div>
<h1 class="hero__name" id="heroName">Marcus<br>Chen</h1>
<div class="hero__foot">
<p class="hero__tagline" id="heroTagline">Building teams and systems<br>that compound in value.</p>
<nav class="hero__ctas" aria-label="Hero navigation">
<a class="btn btn--primary" href="#work">View work</a>
<a class="btn btn--ghost" href="#contact">Get in touch</a>
</nav>
</div>
</div>
<div class="hero__scroll-indicator" aria-hidden="true">
<div class="scroll-track"><div class="scroll-thumb"></div></div>
<span class="scroll-label">scroll</span>
</div>
</section>
<!-- โโโ EXPERTISE โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ -->
<section class="section expertise" id="expertise">
<div class="section__header">
<div class="section__label-group">
<span class="section-index">01</span>
<span class="section-label">Core Expertise</span>
</div>
<p class="section__summary">Eight years leading engineering teams at scale.</p>
</div>
<div class="expertise__grid">
<article class="expertise-card">
<div class="expertise-card__icon" aria-hidden="true">
<div class="icon-backend"></div>
</div>
<h3 class="expertise-card__title">Backend Systems</h3>
<ul class="expertise-card__list">
<li>Distributed systems design</li>
<li>High-throughput service mesh</li>
<li>PostgreSQL, Redis, Kafka</li>
<li>Go, Rust, TypeScript</li>
<li>gRPC + REST API design</li>
</ul>
</article>
<article class="expertise-card">
<div class="expertise-card__icon" aria-hidden="true">
<div class="icon-platform"></div>
</div>
<h3 class="expertise-card__title">Platform Engineering</h3>
<ul class="expertise-card__list">
<li>Kubernetes & cloud-native infra</li>
<li>CI/CD pipeline architecture</li>
<li>Developer experience tooling</li>
<li>AWS, GCP multi-region setups</li>
<li>Observability & SLO design</li>
</ul>
</article>
<article class="expertise-card">
<div class="expertise-card__icon" aria-hidden="true">
<div class="icon-leadership"></div>
</div>
<h3 class="expertise-card__title">Team Leadership</h3>
<ul class="expertise-card__list">
<li>Hiring & growing eng teams</li>
<li>Technical roadmap planning</li>
<li>Cross-functional collaboration</li>
<li>Eng culture & process design</li>
<li>Performance management</li>
</ul>
</article>
</div>
</section>
<!-- โโโ TIMELINE โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ -->
<section class="section timeline" id="work">
<div class="section__header">
<div class="section__label-group">
<span class="section-index">02</span>
<span class="section-label">Career Timeline</span>
</div>
<p class="section__summary">A track record of increasing ownership and impact.</p>
</div>
<div class="timeline__track" aria-label="Career history">
<div class="timeline__line" aria-hidden="true"></div>
<div class="timeline-item timeline-item--left">
<div class="timeline-item__year">2024</div>
<div class="timeline-item__card">
<div class="timeline-item__meta">
<span class="timeline-item__role">VP Engineering</span>
<span class="timeline-item__sep" aria-hidden="true">โ</span>
<span class="timeline-item__company">Stratum AI</span>
</div>
<p class="timeline-item__desc">Led a 40-person engineering org through Series B. Rebuilt the core ML inference pipeline, reducing p99 latency from 800ms to 65ms. Grew team from 18 to 40 engineers in 14 months while maintaining culture health scores above 4.6/5.</p>
</div>
</div>
<div class="timeline-item timeline-item--right">
<div class="timeline-item__year">2021</div>
<div class="timeline-item__card">
<div class="timeline-item__meta">
<span class="timeline-item__role">Staff Engineer โ Tech Lead</span>
<span class="timeline-item__sep" aria-hidden="true">โ</span>
<span class="timeline-item__company">Meridian Finance</span>
</div>
<p class="timeline-item__desc">Designed and delivered a real-time transaction processing platform handling 50k TPS. Mentored six engineers to senior level. Defined the technical strategy that led to the company's $200M acquisition.</p>
</div>
</div>
<div class="timeline-item timeline-item--left">
<div class="timeline-item__year">2019</div>
<div class="timeline-item__card">
<div class="timeline-item__meta">
<span class="timeline-item__role">Senior Engineer</span>
<span class="timeline-item__sep" aria-hidden="true">โ</span>
<span class="timeline-item__company">Cloudvault</span>
</div>
<p class="timeline-item__desc">Built the multi-tenant storage abstraction layer now serving 3M+ enterprise customers. Pioneered the company's Rust adoption with an internal migration guide that became an industry reference.</p>
</div>
</div>
<div class="timeline-item timeline-item--right">
<div class="timeline-item__year">2016</div>
<div class="timeline-item__card">
<div class="timeline-item__meta">
<span class="timeline-item__role">Software Engineer</span>
<span class="timeline-item__sep" aria-hidden="true">โ</span>
<span class="timeline-item__company">Nexus Labs</span>
</div>
<p class="timeline-item__desc">First engineering hire. Shipped the core API platform from scratch. Established the testing culture and deployment process that scaled the team from 2 to 25 engineers without a single P0 production incident.</p>
</div>
</div>
</div>
</section>
<!-- โโโ OPEN SOURCE โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ -->
<section class="section open-source" id="open-source">
<div class="section__header">
<div class="section__label-group">
<span class="section-index">03</span>
<span class="section-label">Open Source</span>
</div>
<p class="section__summary">Giving back to the communities that shaped my craft.</p>
</div>
<div class="repos__grid">
<a class="repo-card" href="#" aria-label="riftdb repository">
<div class="repo-card__top">
<span class="repo-card__icon" aria-hidden="true">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
</span>
<span class="repo-card__name">riftdb</span>
<span class="repo-card__stars">
<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg>
2.4k
</span>
</div>
<p class="repo-card__desc">A zero-dependency embedded key-value store for Go with MVCC transactions, range scans, and sub-millisecond write latency.</p>
<div class="repo-card__foot">
<span class="lang-pill lang-pill--go">Go</span>
<span class="repo-card__updated">Updated 2 days ago</span>
</div>
</a>
<a class="repo-card" href="#" aria-label="envi repository">
<div class="repo-card__top">
<span class="repo-card__icon" aria-hidden="true">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
</span>
<span class="repo-card__name">envi</span>
<span class="repo-card__stars">
<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg>
1.1k
</span>
</div>
<p class="repo-card__desc">Typed environment variable validation for TypeScript with schema inference, dot-env loading, and strict mode for CI environments.</p>
<div class="repo-card__foot">
<span class="lang-pill lang-pill--ts">TypeScript</span>
<span class="repo-card__updated">Updated 1 week ago</span>
</div>
</a>
<a class="repo-card" href="#" aria-label="sieve repository">
<div class="repo-card__top">
<span class="repo-card__icon" aria-hidden="true">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"/></svg>
</span>
<span class="repo-card__name">sieve</span>
<span class="repo-card__stars">
<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg>
890
</span>
</div>
<p class="repo-card__desc">A Rust crate for compile-time rate limiting with leaky-bucket and token-bucket implementations. Zero allocations on the hot path.</p>
<div class="repo-card__foot">
<span class="lang-pill lang-pill--rust">Rust</span>
<span class="repo-card__updated">Updated 3 weeks ago</span>
</div>
</a>
</div>
</section>
<!-- โโโ CONTACT โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ -->
<section class="section contact" id="contact">
<div class="contact__inner">
<p class="contact__kicker">Currently open to senior leadership roles</p>
<h2 class="contact__cta" id="contactCta">Let's Build<br>Something.</h2>
<div class="contact__links">
<a class="contact__email" href="mailto:marcus@chen.dev">marcus@chen.dev</a>
<div class="contact__social">
<a class="social-link" href="#" aria-label="GitHub profile">GitHub</a>
<a class="social-link" href="#" aria-label="LinkedIn profile">LinkedIn</a>
<a class="social-link" href="#" aria-label="Download Resume">Resume โ</a>
</div>
</div>
</div>
<div class="contact__foot">
<span>Marcus Chen โ Engineering Lead</span>
<span>2025</span>
</div>
</section>
<script type="module" src="script.js"></script>
</body>
</html>Tech Lead Portfolio
Corporate tech lead portfolio with Three.js wireframe hero, vertical career timeline, expertise grid, and open source repo showcase.
Source
- Repository:
libs-genclaude - Original demo id:
32-tech-portfolio
Notes
Corporate tech lead portfolio with Three.js wireframe hero, vertical career timeline, expertise grid, and open source repo showcase.