I Hid My Portfolio in Pitch Darkness. Google Gemini Helped Me Build the Torch.
Source: Dev.to
This is a submission for the Built with Google Gemini: Writing Challenge
What I Built with Google Gemini
Portfolios are supposed to showcase who you are as an engineer. Yet, somewhere along the line, we all started building the exact same thing: a clean header, a bouncy CSS grid of project cards, and a massive “Contact Me” button. I realized that the best part of discovering an engineer’s work isn’t just reading it, it’s the act of discovery itself.
So, I decided to plunge my entire CV into pitch darkness.
I built the Interactive Torch Portfolio – an experimental, mobile‑first single‑page application (SPA) where the screen is completely black. The only way to read my bio, skills, or see my projects is by physically dragging a virtual, flickering “torch” around the screen to carve a hole of light into the darkness.
I chose not to use React, Next.js, or any massive libraries. I wanted to build this purely with HTML, CSS, and vanilla DOM manipulation. Calculating the physics of a moving torch and handling complex HTML5 Canvas blend modes would have been a massive headache—until Google Gemini stepped in as my mathematical pair‑programmer.
Demo
You can experience the portfolio live on a Google Cloud Run deployment (containerized with a lightweight nginx:alpine image). No extra setup is required—just open the link and start dragging the torch.
What I Learned
Advanced Canvas Blend Modes (Technical Depth)
I deepened my understanding of the HTML5 Canvas API, especially globalCompositeOperation. The goal was to render total darkness and “cut out” a transparent hole where the mouse moved. Gemini helped me implement this logic without hurting the browser’s framerate:
// Fill the screen with darkness
ctx.fillStyle = '#050505';
ctx.globalCompositeOperation = 'source-over';
ctx.fillRect(0, 0, width, height);
// "Cut out" the darkness using the glowing gradient
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = gradient; // radial gradient for soft edges
ctx.beginPath();
ctx.arc(startX, startY, maxRadius, 0, Math.PI * 2);
ctx.fill();
Mastering how to stack destination-out for the flashlight beam and screen/lighter for the ambient fire glow on a single <canvas> element was incredibly rewarding.
Translating Physical Mechanics
A standard custom cursor feels weightless. I wanted my torch to feel heavy. Working with Gemini taught me how to articulate visual physics into actionable prompts. I described the logic “make the torch tilt like a heavy pendulum based on mouse movement speed,” and Gemini generated the necessary Math.cos and Math.sin rotation matrices to swing the SVG torch realistically on its pivot.
The Power of Vanilla Performance
By relying purely on requestAnimationFrame and a Canvas context instead of virtual‑DOM diffing, the application loads instantaneously and maintains a buttery‑smooth 60 FPS even while rendering hundreds of animated, math‑driven fire particles.
Google Gemini Feedback
What worked beautifully
Gemini’s ability to retain context over a long architectural discussion is unmatched. When I pivoted from a modern flashlight to a medieval‑style wooden torch, I simply asked Gemini to “change the flashlight element to a sputtering wooden torch, but keep the noise overlay and the physics we discussed earlier.” It generated new SVG coordinates while respecting existing z‑index layers. Translating concepts like friction, gravity, and pendulum swings into JavaScript mathematics saved me hours of digging through MDN docs.
Where I ran into friction
I had to explicitly prompt Gemini to optimize for mobile touch events. The torch effect initially worked on desktop mousemove but not on touchmove/touchstart, causing erratic scrolling. Gemini eventually provided the correct code (adding { passive: true }), but I needed to recognize the issue first. It also occasionally needed nudging toward vanilla CSS Flexbox solutions rather than immediate JavaScript viewport calculations for the hidden‑content grid layout.
