Skip to content // StreakField — signal simulation
const GRID = 128; // flow potential lattice
let phase = 0; // A→B morph, ~14s per epoch
const curl = (x, y) => {
const dx = sample(x + h, y) - sample(x - h, y);
const dy = sample(x, y + h) - sample(x, y - h);
return [dy * FLOW, -dx * FLOW]; // divergence-free: pure swirl
};
for (let i = 0; i < P; i++) {
const [u, v] = curl(px[i], py[i]);
px[i] += (u + vortex.x + scatter.x) * dt * rush;
py[i] += (v + vortex.y + scatter.y) * dt * rush;
// cursor crush: flash teal, kick outward, spring home
if (d2(ptr, i) < R && ptr.speed > MIN) {
flash[i] = 1;
kick(i, ptr, (1 - d2 / R) * ptr.speed * IMPULSE);
}
charge[i] = Math.max(flash[i] *= COOL, trailGlow(px[i], py[i]));
}
// trails: fade pass 4.5% → filaments persist ~25 frames
fade(fbo, 0.045); draw(points, ADDITIVE); composite(fbo, screen);
// StreakField — signal simulation
const GRID = 128; // flow potential lattice
let phase = 0; // A→B morph, ~14s per epoch
const curl = (x, y) => {
const dx = sample(x + h, y) - sample(x - h, y);
const dy = sample(x, y + h) - sample(x, y - h);
return [dy * FLOW, -dx * FLOW]; // divergence-free: pure swirl
};
for (let i = 0; i < P; i++) {
const [u, v] = curl(px[i], py[i]);
px[i] += (u + vortex.x + scatter.x) * dt * rush;
py[i] += (v + vortex.y + scatter.y) * dt * rush;
// cursor crush: flash teal, kick outward, spring home
if (d2(ptr, i) < R && ptr.speed > MIN) {
flash[i] = 1;
kick(i, ptr, (1 - d2 / R) * ptr.speed * IMPULSE);
}
charge[i] = Math.max(flash[i] *= COOL, trailGlow(px[i], py[i]));
}
// trails: fade pass 4.5% → filaments persist ~25 frames
fade(fbo, 0.045); draw(points, ADDITIVE); composite(fbo, screen);
// StreakField — signal simulation
const GRID = 128; // flow potential lattice
let phase = 0; // A→B morph, ~14s per epoch
const curl = (x, y) => {
const dx = sample(x + h, y) - sample(x - h, y);
const dy = sample(x, y + h) - sample(x, y - h);
return [dy * FLOW, -dx * FLOW]; // divergence-free: pure swirl
};
for (let i = 0; i < P; i++) {
const [u, v] = curl(px[i], py[i]);
px[i] += (u + vortex.x + scatter.x) * dt * rush;
py[i] += (v + vortex.y + scatter.y) * dt * rush;
// cursor crush: flash teal, kick outward, spring home
if (d2(ptr, i) < R && ptr.speed > MIN) {
flash[i] = 1;
kick(i, ptr, (1 - d2 / R) * ptr.speed * IMPULSE);
}
charge[i] = Math.max(flash[i] *= COOL, trailGlow(px[i], py[i]));
}
// trails: fade pass 4.5% → filaments persist ~25 frames
fade(fbo, 0.045); draw(points, ADDITIVE); composite(fbo, screen);
// StreakField — signal simulation
const GRID = 128; // flow potential lattice
let phase = 0; // A→B morph, ~14s per epoch
const curl = (x, y) => {
const dx = sample(x + h, y) - sample(x - h, y);
const dy = sample(x, y + h) - sample(x, y - h);
return [dy * FLOW, -dx * FLOW]; // divergence-free: pure swirl
};
for (let i = 0; i < P; i++) {
const [u, v] = curl(px[i], py[i]);
px[i] += (u + vortex.x + scatter.x) * dt * rush;
py[i] += (v + vortex.y + scatter.y) * dt * rush;
// cursor crush: flash teal, kick outward, spring home
if (d2(ptr, i) < R && ptr.speed > MIN) {
flash[i] = 1;
kick(i, ptr, (1 - d2 / R) * ptr.speed * IMPULSE);
}
charge[i] = Math.max(flash[i] *= COOL, trailGlow(px[i], py[i]));
}
// trails: fade pass 4.5% → filaments persist ~25 frames
fade(fbo, 0.045); draw(points, ADDITIVE); composite(fbo, screen);
// StreakField — signal simulation
const GRID = 128; // flow potential lattice
let phase = 0; // A→B morph, ~14s per epoch
const curl = (x, y) => {
const dx = sample(x + h, y) - sample(x - h, y);
const dy = sample(x, y + h) - sample(x, y - h);
return [dy * FLOW, -dx * FLOW]; // divergence-free: pure swirl
};
for (let i = 0; i < P; i++) {
const [u, v] = curl(px[i], py[i]);
px[i] += (u + vortex.x + scatter.x) * dt * rush;
py[i] += (v + vortex.y + scatter.y) * dt * rush;
// cursor crush: flash teal, kick outward, spring home
if (d2(ptr, i) < R && ptr.speed > MIN) {
flash[i] = 1;
kick(i, ptr, (1 - d2 / R) * ptr.speed * IMPULSE);
}
charge[i] = Math.max(flash[i] *= COOL, trailGlow(px[i], py[i]));
}
// trails: fade pass 4.5% → filaments persist ~25 frames
fade(fbo, 0.045); draw(points, ADDITIVE); composite(fbo, screen);
// StreakField — signal simulation
const GRID = 128; // flow potential lattice
let phase = 0; // A→B morph, ~14s per epoch
const curl = (x, y) => {
const dx = sample(x + h, y) - sample(x - h, y);
const dy = sample(x, y + h) - sample(x, y - h);
return [dy * FLOW, -dx * FLOW]; // divergence-free: pure swirl
};
for (let i = 0; i < P; i++) {
const [u, v] = curl(px[i], py[i]);
px[i] += (u + vortex.x + scatter.x) * dt * rush;
py[i] += (v + vortex.y + scatter.y) * dt * rush;
// cursor crush: flash teal, kick outward, spring home
if (d2(ptr, i) < R && ptr.speed > MIN) {
flash[i] = 1;
kick(i, ptr, (1 - d2 / R) * ptr.speed * IMPULSE);
}
charge[i] = Math.max(flash[i] *= COOL, trailGlow(px[i], py[i]));
}
// trails: fade pass 4.5% → filaments persist ~25 frames
fade(fbo, 0.045); draw(points, ADDITIVE); composite(fbo, screen);
// StreakField — signal simulation
const GRID = 128; // flow potential lattice
let phase = 0; // A→B morph, ~14s per epoch
const curl = (x, y) => {
const dx = sample(x + h, y) - sample(x - h, y);
const dy = sample(x, y + h) - sample(x, y - h);
return [dy * FLOW, -dx * FLOW]; // divergence-free: pure swirl
};
for (let i = 0; i < P; i++) {
const [u, v] = curl(px[i], py[i]);
px[i] += (u + vortex.x + scatter.x) * dt * rush;
py[i] += (v + vortex.y + scatter.y) * dt * rush;
// cursor crush: flash teal, kick outward, spring home
if (d2(ptr, i) < R && ptr.speed > MIN) {
flash[i] = 1;
kick(i, ptr, (1 - d2 / R) * ptr.speed * IMPULSE);
}
charge[i] = Math.max(flash[i] *= COOL, trailGlow(px[i], py[i]));
}
// trails: fade pass 4.5% → filaments persist ~25 frames
fade(fbo, 0.045); draw(points, ADDITIVE); composite(fbo, screen);
// StreakField — signal simulation
const GRID = 128; // flow potential lattice
let phase = 0; // A→B morph, ~14s per epoch
const curl = (x, y) => {
const dx = sample(x + h, y) - sample(x - h, y);
const dy = sample(x, y + h) - sample(x, y - h);
return [dy * FLOW, -dx * FLOW]; // divergence-free: pure swirl
};
for (let i = 0; i < P; i++) {
const [u, v] = curl(px[i], py[i]);
px[i] += (u + vortex.x + scatter.x) * dt * rush;
py[i] += (v + vortex.y + scatter.y) * dt * rush;
// cursor crush: flash teal, kick outward, spring home
if (d2(ptr, i) < R && ptr.speed > MIN) {
flash[i] = 1;
kick(i, ptr, (1 - d2 / R) * ptr.speed * IMPULSE);
}
charge[i] = Math.max(flash[i] *= COOL, trailGlow(px[i], py[i]));
}
// trails: fade pass 4.5% → filaments persist ~25 frames
fade(fbo, 0.045); draw(points, ADDITIVE); composite(fbo, screen);
// StreakField — signal simulation
const GRID = 128; // flow potential lattice
let phase = 0; // A→B morph, ~14s per epoch
const curl = (x, y) => {
const dx = sample(x + h, y) - sample(x - h, y);
const dy = sample(x, y + h) - sample(x, y - h);
return [dy * FLOW, -dx * FLOW]; // divergence-free: pure swirl
};
for (let i = 0; i < P; i++) {
const [u, v] = curl(px[i], py[i]);
px[i] += (u + vortex.x + scatter.x) * dt * rush;
py[i] += (v + vortex.y + scatter.y) * dt * rush;
// cursor crush: flash teal, kick outward, spring home
if (d2(ptr, i) < R && ptr.speed > MIN) {
flash[i] = 1;
kick(i, ptr, (1 - d2 / R) * ptr.speed * IMPULSE);
}
charge[i] = Math.max(flash[i] *= COOL, trailGlow(px[i], py[i]));
}
// trails: fade pass 4.5% → filaments persist ~25 frames
fade(fbo, 0.045); draw(points, ADDITIVE); composite(fbo, screen);
VM
2026
Commitfolio I developed Commitfolio as a full-stack web application that automatically generates professional portfolio websites by analyzing developers' GitHub commit history and repository data. I built the backend API to fetch and process Git data, parse project details, and dynamically generate portfolio content, while creating a responsive frontend interface that allows users to customize their generated portfolios before deployment. I implemented the complete user flow from GitHub authentication through portfolio generation to final export, delivering a tool that transforms raw development activity into polished professional showcases.
The Brief
Many professionals struggle to maintain visibility into their ongoing commitments while simultaneously needing to present their work professionally to potential clients. I identified the need for a unified solution that could serve both personal project management and professional showcase purposes.
01
Commitment without accountability fails. Many professionals struggle to maintain visibility into their ongoing commitments while simultaneously needing to present their work professionally to potential clients. I identified the need for a unified solution that could serve both personal project management and professional showcase purposes.
02
Portfolio tracking meets social proof. I architected a dual-interface system with a private dashboard for commitment tracking and a public-facing portfolio view. I implemented real-time progress tracking, automated status updates, and customizable presentation templates to bridge the gap between personal productivity and professional presentation.
03
Building trust through transparency. I followed an agile development approach, starting with user research and wireframing before moving into full-stack development. I designed the database schema to support both private project data and public portfolio content, then built responsive interfaces that could seamlessly transition between management and presentation modes.
04
Actions speak louder than words. The application successfully streamlined my own project management workflow while providing a professional showcase platform that adapts to different client needs. I gained valuable experience in building dual-purpose applications and learned how to balance feature complexity with user experience across different use cases.
Do Not Touch