0%
Back to Blog
Oneko Hero

Oneko: A Pixelated Friend from the 90s Returns

ยท4 min readยทBy Rahul Mistry

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:

typescript
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:

typescript
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)
typescript
// 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:

typescript
// 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:

typescript
// 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

typescript
const isReducedMotion = window.matchMedia(
  "(prefers-reduced-motion: reduce)"
).matches;
 
if (isReducedMotion) return null; // No cat for motion-sensitive users

If someone has vestibular disorders or simply prefers less movement, Oneko politely stays hidden. No judgment, just respect.

Screen Reader Friendly

jsx
<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... ๐Ÿ˜‰

Share: