Pages Hard
AI Engineer Portfolio
Terminal-aesthetic portfolio with typing animations, neural network canvas visualization, and scroll-driven project reveals.
Open in Lab
MCP
canvas-2d gsap scrambletext lenis scrolltrigger
Targets: JS HTML
Code
:root {
--page-bg: #0c0c0c;
--page-surface: #161616;
--page-border: #2a2a2a;
--page-text: #e0e0e0;
--page-muted: #707070;
--page-green: #00ff87;
--page-amber: #ffb800;
--page-blue: #4a9eff;
--page-red: #ff4444;
}
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: var(--page-bg);
color: var(--page-text);
font-family: "SF Mono", "Fira Code", "JetBrains Mono", "Cascadia Code", "Consolas", monospace;
line-height: 1.6;
overflow-x: hidden;
}
/* โโ Neural canvas background โโ */
#neural-canvas {
position: fixed;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 0;
}
.reduced-motion #neural-canvas {
opacity: 0.3;
}
/* โโ Sections โโ */
.section {
position: relative;
z-index: 1;
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
padding: 6rem 2rem;
}
.section-label {
font-size: 0.75rem;
color: var(--page-green);
text-transform: uppercase;
letter-spacing: 0.15em;
margin-bottom: 2rem;
font-weight: 400;
}
/* โโ Hero section โโ */
.hero-section {
align-items: center;
justify-content: center;
position: relative;
}
/* โโ Terminal block โโ */
.terminal-block {
background: rgba(22, 22, 22, 0.92);
border: 1px solid var(--page-border);
border-radius: 10px;
max-width: 600px;
width: 100%;
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
overflow: hidden;
}
.terminal-header {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.75rem 1rem;
background: rgba(30, 30, 30, 0.8);
border-bottom: 1px solid var(--page-border);
}
.terminal-dot {
width: 12px;
height: 12px;
border-radius: 50%;
}
.terminal-dot.red {
background: var(--page-red);
}
.terminal-dot.yellow {
background: var(--page-amber);
}
.terminal-dot.green {
background: var(--page-green);
}
.terminal-title {
font-size: 0.7rem;
color: var(--page-muted);
margin-left: 0.5rem;
}
.terminal-body {
padding: 1.25rem;
font-size: clamp(0.85rem, 2vw, 1rem);
line-height: 1.8;
}
.terminal-line {
min-height: 1.6em;
white-space: pre-wrap;
}
.terminal-blank {
height: 0.8em;
}
.prompt {
color: var(--page-green);
font-weight: 700;
}
.cmd-text,
.name-text,
.role-text,
.tagline1-text,
.tagline2-text,
.contact-cmd,
.contact-line {
color: var(--page-text);
}
.name-text {
font-size: 1.4em;
font-weight: 700;
color: var(--page-green);
}
.role-text {
color: var(--page-muted);
}
.cursor {
display: inline-block;
color: var(--page-green);
animation: blink 1s step-end infinite;
}
@keyframes blink {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0;
}
}
.reduced-motion .cursor {
animation: none;
opacity: 1;
}
/* โโ Scroll hint โโ */
.scroll-hint {
position: absolute;
bottom: 3rem;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
color: var(--page-muted);
font-size: 0.7rem;
letter-spacing: 0.1em;
text-transform: uppercase;
opacity: 0;
}
.scroll-dot {
animation: scroll-bounce 2s ease-in-out infinite;
}
@keyframes scroll-bounce {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(8px);
opacity: 0.3;
}
}
.reduced-motion .scroll-dot {
animation: none;
}
/* โโ About section โโ */
.about-section {
padding: 8rem 2rem;
}
.about-grid {
max-width: 1000px;
margin: 0 auto;
display: grid;
grid-template-columns: 1.2fr 0.8fr;
gap: 4rem;
align-items: start;
}
.bio-text {
font-size: clamp(0.9rem, 1.8vw, 1.05rem);
color: var(--page-muted);
line-height: 1.8;
font-family: "Inter", "SF Pro Display", system-ui, sans-serif;
}
.about-stats {
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.stat-card {
padding: 1.25rem 1.5rem;
background: var(--page-surface);
border: 1px solid var(--page-border);
border-left: 3px solid var(--page-green);
border-radius: 6px;
}
.stat-number {
display: block;
font-size: 2rem;
font-weight: 700;
color: var(--page-green);
line-height: 1.2;
}
.stat-label {
display: block;
font-size: 0.75rem;
color: var(--page-muted);
margin-top: 0.25rem;
text-transform: uppercase;
letter-spacing: 0.08em;
}
/* โโ Projects section โโ */
.projects-section {
padding: 8rem 2rem;
min-height: auto;
}
.projects-section .section-label {
max-width: 1000px;
margin-left: auto;
margin-right: auto;
width: 100%;
}
.project-card {
max-width: 1000px;
margin: 0 auto 3rem;
background: var(--page-surface);
border: 1px solid var(--page-border);
border-radius: 10px;
display: grid;
grid-template-columns: 1fr 1fr;
overflow: hidden;
opacity: 0;
transform: translateY(60px);
}
.reduced-motion .project-card {
opacity: 1;
transform: none;
}
.project-content {
padding: 2rem;
display: flex;
flex-direction: column;
justify-content: center;
}
.project-title {
font-size: 1.5rem;
font-weight: 700;
color: var(--page-text);
margin-bottom: 0.75rem;
}
.project-card[data-project="neurovox"] .project-title {
color: var(--page-green);
}
.project-card[data-project="deepsight"] .project-title {
color: var(--page-amber);
}
.project-card[data-project="synthmind"] .project-title {
color: var(--page-blue);
}
.project-desc {
font-size: 0.85rem;
color: var(--page-muted);
line-height: 1.7;
font-family: "Inter", "SF Pro Display", system-ui, sans-serif;
margin-bottom: 1.25rem;
}
.project-tags {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
}
.tech-tag {
padding: 0.2rem 0.6rem;
border-radius: 4px;
font-size: 0.65rem;
background: rgba(255, 255, 255, 0.06);
color: var(--page-muted);
text-transform: uppercase;
letter-spacing: 0.04em;
}
.project-viz {
position: relative;
min-height: 250px;
background: rgba(12, 12, 12, 0.6);
}
.viz-canvas {
width: 100%;
height: 100%;
display: block;
}
/* โโ Contact section โโ */
.contact-section {
align-items: center;
}
.contact-terminal {
max-width: 480px;
}
.contact-cursor {
margin-left: 0.3rem;
}
/* โโ Responsive โโ */
@media (max-width: 768px) {
.about-grid {
grid-template-columns: 1fr;
gap: 3rem;
}
.project-card {
grid-template-columns: 1fr;
}
.project-viz {
min-height: 200px;
}
.section {
padding: 4rem 1.25rem;
}
.terminal-block {
max-width: 100%;
}
}
@media (max-width: 480px) {
.terminal-body {
font-size: 0.8rem;
padding: 1rem;
}
.name-text {
font-size: 1.2em;
}
}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 { ScrambleTextPlugin } from "gsap/ScrambleTextPlugin";
import { TextPlugin } from "gsap/TextPlugin";
import Lenis from "lenis";
gsap.registerPlugin(ScrollTrigger, SplitText, ScrambleTextPlugin, TextPlugin);
// โโ Demo Shell โโ
initDemoShell({
title: "AI Engineer Portfolio",
category: "pages",
tech: ["canvas-2d", "gsap", "scrambletext", "lenis"],
});
// โโ 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);
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);
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// SECTION 1: Neural Network Canvas Background
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const neuralCanvas = document.getElementById("neural-canvas");
const nCtx = neuralCanvas.getContext("2d");
let nodes = [];
let connections = [];
let pulses = [];
let mouseX = -1000,
mouseY = -1000;
let neuralRAF = 0;
function resizeNeuralCanvas() {
const dpr = Math.min(window.devicePixelRatio || 1, 2);
neuralCanvas.width = Math.floor(window.innerWidth * dpr);
neuralCanvas.height = Math.floor(window.innerHeight * dpr);
neuralCanvas.style.width = window.innerWidth + "px";
neuralCanvas.style.height = window.innerHeight + "px";
nCtx.setTransform(dpr, 0, 0, dpr, 0, 0);
initNetwork();
}
function initNetwork() {
nodes = [];
connections = [];
const w = window.innerWidth;
const h = window.innerHeight;
const layers = 5;
const nodesPerLayer = Math.floor(w < 600 ? 8 : 14);
for (let l = 0; l < layers; l++) {
const x = (w / (layers + 1)) * (l + 1);
for (let n = 0; n < nodesPerLayer; n++) {
const y = (h / (nodesPerLayer + 1)) * (n + 1);
nodes.push({
x: x + (Math.random() - 0.5) * 40,
y: y + (Math.random() - 0.5) * 30,
layer: l,
baseAlpha: 0.15 + Math.random() * 0.15,
alpha: 0.15,
radius: 2 + Math.random() * 2,
});
}
}
// Connect adjacent layers
for (let i = 0; i < nodes.length; i++) {
for (let j = 0; j < nodes.length; j++) {
if (nodes[j].layer === nodes[i].layer + 1) {
if (Math.random() < 0.3) {
connections.push({ from: i, to: j, alpha: 0.04 + Math.random() * 0.06 });
}
}
}
}
}
function spawnPulse() {
if (connections.length === 0) return;
const conn = connections[Math.floor(Math.random() * connections.length)];
pulses.push({ conn, progress: 0, speed: 0.008 + Math.random() * 0.012 });
}
function renderNeural() {
const w = window.innerWidth;
const h = window.innerHeight;
nCtx.clearRect(0, 0, w, h);
// Connections
for (const c of connections) {
const a = nodes[c.from];
const b = nodes[c.to];
nCtx.strokeStyle = `rgba(0, 255, 135, ${c.alpha})`;
nCtx.lineWidth = 0.5;
nCtx.beginPath();
nCtx.moveTo(a.x, a.y);
nCtx.lineTo(b.x, b.y);
nCtx.stroke();
}
// Pulses
if (!reduced) {
if (Math.random() < 0.03) spawnPulse();
for (let i = pulses.length - 1; i >= 0; i--) {
const p = pulses[i];
p.progress += p.speed;
if (p.progress > 1) {
pulses.splice(i, 1);
continue;
}
const a = nodes[p.conn.from];
const b = nodes[p.conn.to];
const px = a.x + (b.x - a.x) * p.progress;
const py = a.y + (b.y - a.y) * p.progress;
const grad = nCtx.createRadialGradient(px, py, 0, px, py, 8);
grad.addColorStop(0, "rgba(0, 255, 135, 0.8)");
grad.addColorStop(1, "rgba(0, 255, 135, 0)");
nCtx.fillStyle = grad;
nCtx.beginPath();
nCtx.arc(px, py, 8, 0, Math.PI * 2);
nCtx.fill();
}
}
// Nodes
for (const node of nodes) {
const dx = mouseX - node.x;
const dy = mouseY - node.y;
const dist = Math.sqrt(dx * dx + dy * dy);
const mouseInfluence = dist < 150 ? (1 - dist / 150) * 0.65 : 0;
node.alpha = node.baseAlpha + mouseInfluence;
nCtx.fillStyle = `rgba(0, 255, 135, ${node.alpha})`;
nCtx.beginPath();
nCtx.arc(node.x, node.y, node.radius, 0, Math.PI * 2);
nCtx.fill();
if (mouseInfluence > 0.1) {
const glowGrad = nCtx.createRadialGradient(
node.x,
node.y,
0,
node.x,
node.y,
node.radius * 4
);
glowGrad.addColorStop(0, `rgba(0, 255, 135, ${mouseInfluence * 0.3})`);
glowGrad.addColorStop(1, "rgba(0, 255, 135, 0)");
nCtx.fillStyle = glowGrad;
nCtx.beginPath();
nCtx.arc(node.x, node.y, node.radius * 4, 0, Math.PI * 2);
nCtx.fill();
}
}
neuralRAF = requestAnimationFrame(renderNeural);
}
resizeNeuralCanvas();
window.addEventListener("resize", resizeNeuralCanvas);
neuralRAF = requestAnimationFrame(renderNeural);
document.addEventListener("mousemove", (e) => {
mouseX = e.clientX;
mouseY = e.clientY;
});
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// SECTION 2: Hero Terminal ScrambleText
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const scrambleChars = "01!<>-_\\/[]{}=+*^?#";
if (reduced) {
// Show text immediately in reduced motion
document.querySelector(".cmd-text").textContent = "kai.init()";
document.querySelector(".name-text").textContent = "Kai Nomura";
document.querySelector(".role-text").textContent = "AI/ML Engineer";
document.querySelector(".tagline1-text").textContent = "Building intelligent systems";
document.querySelector(".tagline2-text").textContent = "that understand the world.";
document.getElementById("cursor").style.display = "none";
gsap.set("#scroll-hint", { opacity: 1 });
} else {
const heroTl = gsap.timeline({ delay: 0.5 });
heroTl
.to(".cmd-text", {
duration: 0.8,
scrambleText: { text: "kai.init()", chars: scrambleChars, speed: 0.4 },
})
.to(
".name-text",
{
duration: 0.6,
scrambleText: { text: "Kai Nomura", chars: scrambleChars, speed: 0.3 },
},
"+=0.3"
)
.to(
".role-text",
{
duration: 0.5,
scrambleText: { text: "AI/ML Engineer", chars: scrambleChars, speed: 0.3 },
},
"+=0.1"
)
.to(
".tagline1-text",
{
duration: 0.8,
scrambleText: { text: "Building intelligent systems", chars: scrambleChars, speed: 0.3 },
},
"+=0.4"
)
.to(
".tagline2-text",
{
duration: 0.7,
scrambleText: { text: "that understand the world.", chars: scrambleChars, speed: 0.3 },
},
"+=0.1"
)
.to("#scroll-hint", { opacity: 1, duration: 0.6, ease: "expo.out" }, "+=0.5");
}
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// SECTION 3: About โ Bio Text Reveal + Stat Counters
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// Bio text โ line reveal
const bioText = document.querySelector(".bio-text");
if (bioText) {
const bioSplit = new SplitText(bioText, { type: "lines", linesClass: "line" });
gsap.set(bioSplit.lines, { opacity: 0, x: reduced ? 0 : -40 });
gsap.to(bioSplit.lines, {
opacity: 1,
x: 0,
duration: dur(0.7),
ease: "expo.out",
stagger: { each: 0.1 },
scrollTrigger: {
trigger: ".about-section",
start: "top 70%",
toggleActions: "play none none reverse",
},
});
}
// Section label
const aboutLabel = document.querySelector(".about-section .section-label");
if (aboutLabel) {
gsap.set(aboutLabel, { opacity: 0, y: reduced ? 0 : 15 });
gsap.to(aboutLabel, {
opacity: 1,
y: 0,
duration: dur(0.5),
ease: "expo.out",
scrollTrigger: {
trigger: ".about-section",
start: "top 80%",
toggleActions: "play none none reverse",
},
});
}
// Stat counters
document.querySelectorAll(".stat-card").forEach((card, i) => {
gsap.set(card, { opacity: 0, x: reduced ? 0 : 40 });
gsap.to(card, {
opacity: 1,
x: 0,
duration: dur(0.6),
ease: "expo.out",
scrollTrigger: {
trigger: ".about-section",
start: "top 65%",
toggleActions: "play none none reverse",
},
delay: i * 0.15,
});
// Counter animation
const numberEl = card.querySelector(".stat-number");
const target = parseInt(numberEl.dataset.target, 10);
const suffix = numberEl.dataset.suffix || "";
const counter = { val: 0 };
ScrollTrigger.create({
trigger: card,
start: "top 80%",
once: true,
onEnter: () => {
if (reduced) {
numberEl.textContent = target + suffix;
return;
}
gsap.to(counter, {
val: target,
duration: 1.5,
ease: "power2.out",
onUpdate: () => {
numberEl.textContent = Math.round(counter.val) + suffix;
},
});
},
});
});
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// SECTION 4: Projects โ Card Entrance + Canvas Visualizations
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// Projects section label
const projLabel = document.querySelector(".projects-section .section-label");
if (projLabel) {
gsap.set(projLabel, { opacity: 0, y: reduced ? 0 : 15 });
gsap.to(projLabel, {
opacity: 1,
y: 0,
duration: dur(0.5),
ease: "expo.out",
scrollTrigger: {
trigger: ".projects-section",
start: "top 80%",
toggleActions: "play none none reverse",
},
});
}
// Card entrance animations
document.querySelectorAll(".project-card").forEach((card) => {
gsap.to(card, {
opacity: 1,
y: 0,
duration: dur(0.8),
ease: "expo.out",
scrollTrigger: {
trigger: card,
start: "top 80%",
toggleActions: "play none none reverse",
},
});
});
// โโ Project Visualizations โโ
function setupVizCanvas(id) {
const canvas = document.getElementById(id);
if (!canvas) return null;
const ctx = canvas.getContext("2d");
let animating = false;
let raf = 0;
function resize() {
const rect = canvas.parentElement.getBoundingClientRect();
const dpr = Math.min(window.devicePixelRatio || 1, 2);
canvas.width = Math.floor(rect.width * dpr);
canvas.height = Math.floor(rect.height * dpr);
canvas.style.width = rect.width + "px";
canvas.style.height = rect.height + "px";
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
}
resize();
window.addEventListener("resize", resize);
return {
canvas,
ctx,
resize,
get w() {
return canvas.parentElement.getBoundingClientRect().width;
},
get h() {
return canvas.parentElement.getBoundingClientRect().height;
},
start(renderFn) {
if (animating) return;
animating = true;
const loop = () => {
if (!animating) return;
renderFn();
raf = requestAnimationFrame(loop);
};
raf = requestAnimationFrame(loop);
},
stop() {
animating = false;
cancelAnimationFrame(raf);
},
};
}
// โโ Viz 1: NeuroVox โ Audio Waveform โโ
const vizNV = setupVizCanvas("viz-neurovox");
if (vizNV) {
let nvTime = 0;
function renderNeurovox() {
const { ctx, w, h } = vizNV;
ctx.clearRect(0, 0, w, h);
nvTime += 0.03;
const centerY = h / 2;
const barCount = Math.floor(w / 6);
for (let i = 0; i < barCount; i++) {
const x = (i / barCount) * w;
const freq1 = Math.sin(i * 0.15 + nvTime * 2) * 0.6;
const freq2 = Math.sin(i * 0.08 + nvTime * 1.3) * 0.3;
const freq3 = Math.cos(i * 0.22 + nvTime * 0.7) * 0.1;
const amplitude = (freq1 + freq2 + freq3) * (h * 0.35);
const barHeight = Math.abs(amplitude);
const alpha = 0.3 + Math.abs(freq1) * 0.7;
ctx.fillStyle = `rgba(0, 255, 135, ${alpha})`;
ctx.fillRect(x, centerY - barHeight / 2, 3, barHeight);
}
}
ScrollTrigger.create({
trigger: "#viz-neurovox",
start: "top 90%",
end: "bottom 10%",
onEnter: () => {
vizNV.resize();
vizNV.start(renderNeurovox);
},
onLeave: () => vizNV.stop(),
onEnterBack: () => {
vizNV.resize();
vizNV.start(renderNeurovox);
},
onLeaveBack: () => vizNV.stop(),
});
if (reduced) {
// Render a single static frame
vizNV.resize();
renderNeurovox();
}
}
// โโ Viz 2: DeepSight โ Particle Eye Cluster โโ
const vizDS = setupVizCanvas("viz-deepsight");
if (vizDS) {
let dsTime = 0;
const dsParticles = [];
const particleCount = 200;
for (let i = 0; i < particleCount; i++) {
const angle = Math.random() * Math.PI * 2;
const radius = 20 + Math.random() * 80;
dsParticles.push({
baseAngle: angle,
baseRadius: radius,
speed: 0.002 + Math.random() * 0.008,
size: 1 + Math.random() * 2.5,
phase: Math.random() * Math.PI * 2,
});
}
function renderDeepsight() {
const { ctx, w, h } = vizDS;
ctx.clearRect(0, 0, w, h);
dsTime += 0.02;
const cx = w / 2;
const cy = h / 2;
const scale = Math.min(w, h) / 250;
for (const p of dsParticles) {
// Eye shape: elliptical orbit squashed vertically
const angle = p.baseAngle + dsTime * p.speed;
const r = p.baseRadius * scale;
const eyeSquash = 0.4 + Math.sin(angle * 2) * 0.15;
const x = cx + Math.cos(angle) * r;
const y = cy + Math.sin(angle) * r * eyeSquash;
const pulse = 0.5 + Math.sin(dsTime * 2 + p.phase) * 0.3;
ctx.fillStyle = `rgba(255, 184, 0, ${pulse})`;
ctx.beginPath();
ctx.arc(x, y, p.size * scale * 0.5, 0, Math.PI * 2);
ctx.fill();
}
// Central "pupil" glow
const pupilGrad = ctx.createRadialGradient(cx, cy, 0, cx, cy, 15 * scale);
pupilGrad.addColorStop(0, "rgba(255, 184, 0, 0.6)");
pupilGrad.addColorStop(0.5, "rgba(255, 184, 0, 0.15)");
pupilGrad.addColorStop(1, "rgba(255, 184, 0, 0)");
ctx.fillStyle = pupilGrad;
ctx.beginPath();
ctx.arc(cx, cy, 15 * scale, 0, Math.PI * 2);
ctx.fill();
}
ScrollTrigger.create({
trigger: "#viz-deepsight",
start: "top 90%",
end: "bottom 10%",
onEnter: () => {
vizDS.resize();
vizDS.start(renderDeepsight);
},
onLeave: () => vizDS.stop(),
onEnterBack: () => {
vizDS.resize();
vizDS.start(renderDeepsight);
},
onLeaveBack: () => vizDS.stop(),
});
if (reduced) {
vizDS.resize();
renderDeepsight();
}
}
// โโ Viz 3: SynthMind โ Cellular Automata Grid โโ
const vizSM = setupVizCanvas("viz-synthmind");
if (vizSM) {
let smTime = 0;
function renderSynthmind() {
const { ctx, w, h } = vizSM;
ctx.clearRect(0, 0, w, h);
smTime += 0.04;
const cellSize = 12;
const cols = Math.ceil(w / cellSize);
const rows = Math.ceil(h / cellSize);
for (let col = 0; col < cols; col++) {
for (let row = 0; row < rows; row++) {
const x = col * cellSize;
const y = row * cellSize;
// Wave pattern across the grid
const wave1 = Math.sin(col * 0.3 + smTime) * 0.5 + 0.5;
const wave2 = Math.cos(row * 0.25 + smTime * 0.7) * 0.5 + 0.5;
const wave3 = Math.sin((col + row) * 0.15 + smTime * 1.3) * 0.5 + 0.5;
const intensity = (wave1 * wave2 + wave3) / 2;
const alpha = intensity * 0.5;
if (alpha > 0.08) {
ctx.fillStyle = `rgba(74, 158, 255, ${alpha})`;
ctx.fillRect(x + 1, y + 1, cellSize - 2, cellSize - 2);
}
}
}
}
ScrollTrigger.create({
trigger: "#viz-synthmind",
start: "top 90%",
end: "bottom 10%",
onEnter: () => {
vizSM.resize();
vizSM.start(renderSynthmind);
},
onLeave: () => vizSM.stop(),
onEnterBack: () => {
vizSM.resize();
vizSM.start(renderSynthmind);
},
onLeaveBack: () => vizSM.stop(),
});
if (reduced) {
vizSM.resize();
renderSynthmind();
}
}
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
// SECTION 5: Contact Terminal
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const contactLines = ["Email: kai@example.dev", "GitHub: @kai-nomura", "Twitter: @kai_ml"];
if (reduced) {
const cmdEl = document.querySelector(".contact-cmd");
if (cmdEl) cmdEl.textContent = "kai.contact()";
document.querySelectorAll(".contact-line").forEach((el, i) => {
el.textContent = contactLines[i];
});
} else {
ScrollTrigger.create({
trigger: ".contact-section",
start: "top 60%",
once: true,
onEnter: () => {
const contactTl = gsap.timeline();
contactTl.to(".contact-cmd", {
duration: 0.6,
scrambleText: { text: "kai.contact()", chars: scrambleChars, speed: 0.4 },
});
document.querySelectorAll(".contact-line").forEach((el, i) => {
contactTl.to(
el,
{
duration: 0.5,
scrambleText: { text: contactLines[i], chars: scrambleChars, speed: 0.3 },
},
`+=${i === 0 ? 0.3 : 0.1}`
);
});
},
});
}<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Engineer Portfolio โ stealthisdesign</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>
<style>html.lenis,
html.lenis body {
height: auto;
}
.lenis:not(.lenis-autoToggle).lenis-stopped {
overflow: clip;
}
.lenis [data-lenis-prevent],
.lenis [data-lenis-prevent-wheel],
.lenis [data-lenis-prevent-touch] {
overscroll-behavior: contain;
}
.lenis.lenis-smooth iframe {
pointer-events: none;
}
.lenis.lenis-autoToggle {
transition-property: overflow;
transition-duration: 1ms;
transition-behavior: allow-discrete;
}</style>
</head>
<body>
<!-- Neural network canvas background -->
<canvas id="neural-canvas" aria-hidden="true"></canvas>
<!-- Hero: Terminal intro -->
<section class="section hero-section" id="hero">
<div class="terminal-block">
<div class="terminal-header">
<span class="terminal-dot red"></span>
<span class="terminal-dot yellow"></span>
<span class="terminal-dot green"></span>
<span class="terminal-title">kai@portfolio ~ %</span>
</div>
<div class="terminal-body">
<div class="terminal-line" id="line-cmd"><span class="prompt">></span> <span class="cmd-text"></span></div>
<div class="terminal-line terminal-blank" id="line-blank"></div>
<div class="terminal-line" id="line-name"><span class="name-text"></span></div>
<div class="terminal-line" id="line-role"><span class="role-text"></span></div>
<div class="terminal-line terminal-blank" id="line-blank2"></div>
<div class="terminal-line" id="line-tagline1"><span class="tagline1-text"></span></div>
<div class="terminal-line" id="line-tagline2"><span class="tagline2-text"></span></div>
<span class="cursor" id="cursor">_</span>
</div>
</div>
<div class="scroll-hint" id="scroll-hint">
<span>scroll to explore</span>
<svg width="16" height="24" viewBox="0 0 16 24" fill="none">
<rect x="1" y="1" width="14" height="22" rx="7" stroke="currentColor" stroke-width="1.5"/>
<circle cx="8" cy="7" r="2" fill="currentColor" class="scroll-dot"/>
</svg>
</div>
</section>
<!-- About + Stats -->
<section class="section about-section" id="about">
<div class="about-grid">
<div class="about-bio">
<h2 class="section-label">// about</h2>
<p class="bio-text">I'm a machine learning engineer focused on building production-grade AI systems. From transformer architectures to deployment pipelines, I bridge the gap between research papers and real-world applications. Currently exploring multimodal reasoning and efficient inference at scale.</p>
</div>
<div class="about-stats">
<div class="stat-card">
<span class="stat-number" data-target="7" data-suffix="+">0</span>
<span class="stat-label">Years Experience</span>
</div>
<div class="stat-card">
<span class="stat-number" data-target="23" data-suffix="">0</span>
<span class="stat-label">Published Papers</span>
</div>
<div class="stat-card">
<span class="stat-number" data-target="12" data-suffix="M+">0</span>
<span class="stat-label">Model Parameters</span>
</div>
</div>
</div>
</section>
<!-- Projects -->
<section class="section projects-section" id="projects">
<h2 class="section-label">// projects</h2>
<div class="project-card" data-project="neurovox">
<div class="project-content">
<h3 class="project-title">NeuroVox</h3>
<p class="project-desc">Real-time speech-to-intent engine built on a custom transformer architecture. Processes audio streams at 50ms latency with 97.3% accuracy on domain-specific vocabularies.</p>
<div class="project-tags">
<span class="tech-tag">PyTorch</span>
<span class="tech-tag">ONNX Runtime</span>
<span class="tech-tag">WebSocket</span>
<span class="tech-tag">Rust</span>
</div>
</div>
<div class="project-viz">
<canvas class="viz-canvas" id="viz-neurovox" aria-hidden="true"></canvas>
</div>
</div>
<div class="project-card" data-project="deepsight">
<div class="project-content">
<h3 class="project-title">DeepSight</h3>
<p class="project-desc">Multimodal vision system that fuses LiDAR point clouds with camera feeds for autonomous navigation. Deployed across 200+ edge devices with real-time obstacle detection.</p>
<div class="project-tags">
<span class="tech-tag">TensorRT</span>
<span class="tech-tag">CUDA</span>
<span class="tech-tag">ROS2</span>
<span class="tech-tag">C++</span>
</div>
</div>
<div class="project-viz">
<canvas class="viz-canvas" id="viz-deepsight" aria-hidden="true"></canvas>
</div>
</div>
<div class="project-card" data-project="synthmind">
<div class="project-content">
<h3 class="project-title">SynthMind</h3>
<p class="project-desc">A neuro-symbolic reasoning framework that combines neural language understanding with symbolic logic engines. Enables complex multi-step reasoning over structured knowledge graphs.</p>
<div class="project-tags">
<span class="tech-tag">JAX</span>
<span class="tech-tag">Prolog</span>
<span class="tech-tag">GraphQL</span>
<span class="tech-tag">Neo4j</span>
</div>
</div>
<div class="project-viz">
<canvas class="viz-canvas" id="viz-synthmind" aria-hidden="true"></canvas>
</div>
</div>
</section>
<!-- Contact terminal -->
<section class="section contact-section" id="contact">
<div class="terminal-block contact-terminal">
<div class="terminal-header">
<span class="terminal-dot red"></span>
<span class="terminal-dot yellow"></span>
<span class="terminal-dot green"></span>
<span class="terminal-title">kai@contact ~ %</span>
</div>
<div class="terminal-body">
<div class="terminal-line"><span class="prompt">></span> <span class="contact-cmd"></span></div>
<div class="terminal-line terminal-blank"></div>
<div class="contact-lines">
<div class="terminal-line"><span class="contact-line" data-line="0"></span></div>
<div class="terminal-line"><span class="contact-line" data-line="1"></span></div>
<div class="terminal-line"><span class="contact-line" data-line="2"></span></div>
</div>
<div class="terminal-line terminal-blank"></div>
<div class="terminal-line"><span class="prompt">></span> <span class="cursor contact-cursor">_</span></div>
</div>
</div>
</section>
<script type="module" src="script.js"></script>
</body>
</html>AI Engineer Portfolio
Terminal-aesthetic portfolio with typing animations, neural network canvas visualization, and scroll-driven project reveals.
Source
- Repository:
libs-genclaude - Original demo id:
24-ai-portfolio
Notes
Terminal-aesthetic portfolio with typing animations, neural network canvas visualization, and scroll-driven project reveals.