After launching Void Blocks and Snake Game on my portfolio, I discovered several UX issues that needed immediate attention. Mobile users were experiencing overlapping controls, non-functional buttons, and bland dropdown menus that didn't match the terminal aesthetic. Here's how I fixed everything while maintaining the cyberpunk vibe.
The Problems
Void Blocks Mobile View
- Overlapping Controls: Fixed mobile touch controls were overlapping with the instruction panels, making the interface cluttered and hard to use
- Broken Rotate Button: The rotate button (๐) wasn't working at all - clicking it did nothing
- Insufficient Spacing: The game panels were too close to the fixed controls at the bottom
Snake Game Dropdowns
- Generic Appearance: The speed and mode dropdowns looked like standard HTML selects - boring and not fitting the terminal theme
- Poor Mobile Experience: Dropdowns were cramped on mobile with inadequate touch targets
- No Visual Feedback: Hover and focus states were minimal
Void Blocks: Fixing Mobile Controls
The Overlap Issue
The root cause was insufficient bottom padding. The mobile controls were fixed at bottom: 20px, but the body only had padding-bottom: 180px. This created a scenario where scrollable content would collide with fixed controls.
The Fix:
@media (max-width: 768px) { body { /* Increased from 180px to 220px */ padding-bottom: 220px; } .panels { width: 100%; max-width: 400px; display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 20px; /* Added breathing room */ } }The combination of increased body padding and panel margin creates a safe zone where fixed controls never overlap with scrollable content.
The Rotate Button Bug
This was a classic case of calling a non-existent function. The mobile rotate button handler was calling rotatePiece(current), but this function didn't exist in the codebase.
Before (Broken):
document.getElementById('mobileRotate').addEventListener('click', () => { if (current && gameStarted && !gameOver && !paused) { const rotatedPiece = rotatePiece(current); // โ Function doesn't exist if (isValidMove(rotatedPiece, 0, 0)) { current.shape = rotatedPiece.shape; } } });After (Fixed):
document.getElementById('mobileRotate').addEventListener('click', () => { if (current && gameStarted && !gameOver && !paused) { const rotated = rotate(current.shape, true); // โ
Use existing rotate() if (isValidMove(current, 0, 0, rotated)) { current.shape = rotated; } } });The fix uses the existing rotate() function that's already used by keyboard controls, ensuring consistent behavior across input methods.
Snake Game: Lookmaxxing the Dropdowns
The term "lookmaxxing" perfectly describes taking something basic and elevating it to its maximum visual potential. The default HTML select elements needed a complete terminal-aesthetic transformation.
Custom Dropdown Styling
Key Features:
- Gradient background with terminal green tint
- Custom SVG arrow icon
- Multi-layer box shadows for glow effects
- Smooth state transitions
- Removed default browser styling
.controls select, .hud select { background: linear-gradient(135deg, rgba(0, 0, 0, 0.9) 0%, rgba(17, 34, 17, 0.8) 100%); color: var(--terminal-green); border: 2px solid var(--terminal-green); padding: 10px 35px 10px 12px; font-family: inherit; font-size: 13px; font-weight: bold; cursor: pointer; text-transform: uppercase; transition: all 0.3s ease; border-radius: 4px; box-shadow: 0 0 10px rgba(85, 255, 85, 0.2), inset 0 1px 0 rgba(85, 255, 85, 0.1); appearance: none; -webkit-appearance: none; -moz-appearance: none; }Custom Arrow Icon
The secret to terminal-aesthetic dropdowns is a custom SVG arrow that changes color based on state:
background-image: linear-gradient(135deg, rgba(0, 0, 0, 0.9) 0%, rgba(17, 34, 17, 0.8) 100%), url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2355ff55' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e"); background-repeat: no-repeat, no-repeat; background-position: center, right 8px center; background-size: auto, 16px;The SVG is embedded as a data URI, and the stroke color changes from #55ff55 (terminal green) to #00ff00 (bright green) on hover, and #55ffff (cyan) on focus.
Interactive States
Hover Effect:
.controls select:hover, .hud select:hover { background: linear-gradient(135deg, rgba(17, 34, 17, 0.9) 0%, rgba(34, 51, 34, 0.8) 100%); color: var(--terminal-bright-green); border-color: var(--terminal-bright-green); box-shadow: 0 0 20px rgba(85, 255, 85, 0.4), inset 0 1px 0 rgba(85, 255, 85, 0.2); transform: translateY(-1px); }Focus State (Accessibility):
.controls select:focus, .hud select:focus { outline: none; border-color: var(--terminal-cyan); box-shadow: 0 0 25px rgba(85, 255, 255, 0.5), inset 0 0 10px rgba(85, 255, 255, 0.1); color: var(--terminal-cyan); }The focus state uses cyan to differentiate keyboard navigation from mouse hover, improving accessibility.
Mobile Optimization Strategy
Touch Target Sizing
Mobile devices require larger touch targets for comfortable interaction. Apple's Human Interface Guidelines recommend 44pt minimum, Google suggests 48dp. I implemented 48px minimum heights:
@media (max-width: 768px) { .controls select, .hud select { width: 100%; padding: 12px 40px 12px 15px; font-size: 14px; min-height: 48px; /* Touch-friendly */ } }Layout Restructuring
On mobile, the Snake game HUD switches from a multi-column grid to a single-column layout:
Desktop:
.hud { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; }Mobile:
@media (max-width: 768px) { .hud { grid-template-columns: 1fr; gap: 12px; } }This prevents cramped layouts and ensures each stat/control has adequate space.
Disabling Hover on Touch Devices
Hover effects don't work well on touch devices and can cause confusion. I disabled the transform on mobile:
@media (max-width: 768px) { .controls select:hover, .hud select:hover { transform: none; /* No lift animation on touch */ } }The glow and color changes remain, but the translateY is removed to prevent visual glitches.
Performance Considerations
CSS Transitions Over JavaScript
All animations use CSS transitions instead of JavaScript, ensuring:
- Hardware acceleration via GPU
- Smooth 60fps animations
- Better battery life on mobile
- Simpler code maintenance
Box Shadow Optimization
Multiple box shadows can be expensive. I kept them minimal and used will-change implicitly through transitions:
transition: all 0.3s ease;This hints to the browser to optimize rendering for the changing properties.
Testing Approach
- Desktop Testing: Chrome DevTools responsive mode
- Tablet Testing: iPad Safari (both portrait and landscape)
- Mobile Testing: iPhone Safari, Android Chrome
- Accessibility: Keyboard navigation, screen reader compatibility
- Cross-browser: Safari, Chrome, Firefox
Results
Void Blocks
- โ No more overlapping controls on any device
- โ Rotate button works perfectly
- โ Clean visual hierarchy maintained
- โ Desktop view completely unaffected
Snake Game
- โ Dropdowns match terminal aesthetic
- โ Smooth animations and glow effects
- โ Touch-friendly on all mobile devices
- โ Accessible keyboard navigation
- โ Consistent visual language
Key Takeaways
- Always test on real devices - Emulators don't catch everything
- Function naming matters -
rotatePiece()vsrotate()caused hours of debugging - Spacing is critical - Insufficient padding creates overlap issues
- Touch targets need 48px+ - Smaller targets frustrate mobile users
- Terminal aesthetic requires custom styling - Default HTML elements break the immersion
- Progressive enhancement works - Desktop-first, then enhance for mobile
Technical Debt Avoided
By fixing these issues early, I avoided:
- Accumulating user complaints
- Emergency hotfixes
- Inconsistent mobile experiences
- Abandoned game sessions due to frustration
Next Steps
Future improvements could include:
- Custom sound effects for button interactions
- Haptic feedback on mobile devices
- Progressive Web App capabilities
- Offline mode support
- Game state persistence
The games now provide a polished, terminal-aesthetic experience across all devices while maintaining the cyberpunk vibe that defines my portfolio.
Tech Stack: HTML5 Canvas, Vanilla JavaScript, CSS Grid, CSS Custom Properties Repository: jeffreyjose07.github.io Live Demos: Void Blocks โข Snake Game