Oneko: A Pixelated Friend from the 90s Returns
A Purr-fect Blast from the Past ๐ฑ
Close your eyes. It's 1995. Your Windows 95 desktop is adorned with a teal background, and a tiny pixelated cat chases your cursor around the screen. That was Neko โ the original desktop pet that captured hearts before we knew what viral meant.
Fast forward to 2025, and I've brought this digital companion back to life on my portfolio. Meet Oneko โ not just a nostalgic gimmick, but a masterclass in combining whimsy with modern web engineering.
Why Resurrect a 90s Desktop Pet?
In an age of AI assistants and complex interactions, there's something beautifully simple about a cat that just... follows your cursor. No agenda, no notifications, no data collection. Just pure, pixelated joy.
But here's the twist โ this isn't your grandfather's desktop pet. This Oneko is:
- Theme-aware ๐จ (matches your color preference)
- Performance-optimized โก (won't slow your browsing)
- Accessibility-conscious โฟ (respects user preferences)
- Behaviorally rich ๐ง (8 unique animations!)
The Technical Magic Behind the Meow
Sprite-Based Animation System
Remember sprite sheets from game development? Oneko uses a classic 32x32 pixel sprite sheet with 8 different animation states:
const spriteSets: Record<string, SpritePosition[]> = {
idle: [{ x: -3, y: -3 }],
sleeping: [
{ x: -2, y: 0 },
{ x: -2, y: -1 },
],
scratchSelf: [
{ x: -5, y: 0 },
{ x: -6, y: 0 },
{ x: -7, y: 0 },
],
// Plus directional sprites for N, NE, E, SE, S, SW, W, NW
};Each animation is carefully timed โ the cat scratches for exactly 9 frames, sleeps for 192 frames, and transitions smoothly between states.
Theme-Aware Color Filters
Here's where it gets interesting. Instead of creating separate sprite sheets for each theme, I use CSS filters to dynamically colorize our feline friend:
const getThemeFilter = (theme: Theme): string => {
switch (theme) {
case "light":
return "none"; // Original orange tabby
case "dark":
return "brightness(0.7) contrast(1.2)"; // Mysterious shadow cat
case "pink":
return "hue-rotate(300deg) saturate(1.5) brightness(1.1)"; // Kawaii pink kitty
case "pink-dark":
return "hue-rotate(300deg) saturate(1.3) brightness(0.8)"; // Cyberpunk neon cat
}
};One sprite sheet. Four personalities. Zero additional assets. ๐ญ
Intelligent Idle Behavior
Oneko doesn't just follow โ it has a personality. After ~20 seconds of inactivity, the cat might:
- Fall asleep ๐ด (if you stop moving)
- Scratch itself ๐พ (random grooming)
- Scratch the walls ๐ช (when near screen edges)
// Every ~20 seconds, random chance of idle animation
if (idleTime > 10 && Math.floor(Math.random() * 200) === 0) {
// Check position and add wall-scratching options
if (nekoPosX < 32) availableAnimations.push("scratchWallW");
if (nekoPosY < 32) availableAnimations.push("scratchWallN");
// ... more boundary checks
}Performance: Smooth as Butter, Light as a Feather
Frame Rate Management
Instead of updating every frame (60-144fps), Oneko updates at a cinematic 10fps โ enough for smooth movement without hogging resources:
// Only update every 100ms (10fps)
if (timestamp - lastFrameTimestamp > 100) {
lastFrameTimestamp = timestamp;
updateCatPosition();
}Smart Rendering
The cat only renders when:
- โ Page is fully loaded (no competition with critical resources)
- โ User hasn't requested reduced motion
- โ Component is actually connected to the DOM
Graceful Entrance
Rather than jarring pop-in, Oneko fades in smoothly 800ms after the loading screen disappears:
// Smooth 600ms fade-in animation
const fadeInterval = setInterval(() => {
currentStep++;
setOpacity(currentStep / fadeInSteps);
if (currentStep >= fadeInSteps) clearInterval(fadeInterval);
}, 30);Accessibility: Fun for Everyone
Respecting User Preferences
const isReducedMotion = window.matchMedia(
"(prefers-reduced-motion: reduce)"
).matches;
if (isReducedMotion) return null; // No cat for motion-sensitive usersIf someone has vestibular disorders or simply prefers less movement, Oneko politely stays hidden. No judgment, just respect.
Screen Reader Friendly
<div
id="oneko"
aria-hidden="true" // Invisible to screen readers
className="pointer-events-none" // Can't interfere with clicks
/>Oneko is purely decorative โ it won't confuse assistive technologies or interfere with navigation.
The Little Details That Spark Joy
- Boundary Awareness: The cat never gets stuck outside the viewport
- Theme Transitions: Smooth color shifts when switching themes
- Alert State: Cat perks up before chasing โ just like real cats!
- Speed Limits: Moves at exactly 10 pixels per frame for that authentic 90s feel
Try It Yourself!
Move your cursor around this page. Watch as your new pixelated companion springs to life. Leave it still for a moment โ maybe you'll catch Oneko taking a nap or grooming itself.
This little cat represents something bigger: the web should be fun. Not everything needs to be optimized for conversion rates or engagement metrics. Sometimes, a tiny pixel cat following your cursor is reason enough.
The Code Philosophy
Building Oneko taught me that nostalgia and modern development aren't mutually exclusive. You can honor the past while embracing the present:
- Old-school sprites meet modern React hooks
- Retro pixel art adapts to contemporary theme systems
- 90s whimsy respects 2025 accessibility standards
- Simple joy powered by sophisticated engineering
P.S. Fun fact: The original Neko was created in 1989 for the NEC PC-9801. That's 36 years of cats chasing cursors across screens. Here's to 36 more! ๐ฑ
P.P.S. If you leave Oneko alone long enough, you might discover some secret animations. But I'm not telling which walls are the scratchiest... ๐