Projects

From unicorn-filled word games to multilingual agency sites - a journey through code, and questionable design choices

Word Guessing Game: Where It All Began

Every developer has their origin story. This is mine: a word guessing game born from pure determination, late nights, and countless Google searches. What started as a birthday gift for my niece became the foundation of everything I know about JavaScript. Sometimes the most meaningful projects are the ones that change you.

Picture this: pre-AI era development, where every line of code was hard-won through trial, error, and endless Stack Overflow tabs. No ChatGPT to explain concepts, no Copilot to suggest solutions - just me, the browser console, and an unshakeable belief that I could figure this out. Each function was a small victory, each bug a puzzle to solve through sheer persistence.

The original version was in Estonian and had unicorns. Lots of them. Because when you're building for a little niece who believes in magic, unicorns aren't optional - they're essential. That Estonian version, with its glittery backgrounds and whimsical animations, taught me that the best code serves people you love. Later came the English version for the world, but the unicorns will always hold a special place in this project's heart.

I could refactor this code today - make it cleaner, more efficient, more "professional". But I won't. This project is my time capsule, a perfect snapshot of where I started and proof of how far I've traveled. Every beginner-level solution, every verbose function, every "I can't believe this actually works" moment is preserved here, and it's absolutely perfect exactly as it is.

Random Password Generator: Building Confidence

Security meets simplicity in this sleek password generator. Choose your length, click generate, and watch as cryptographically random passwords appear instantly. One click to copy, and you're protected. Clean design, bulletproof security, zero compromises.

Built during my early JavaScript days, this project taught me that elegant solutions often hide in plain sight. The real magic happens in one beautiful line: 'String.fromCharCode(...Array(123).keys()).slice(33)' - a compact spell that conjures every printable ASCII character from space to tilde. Sometimes the most satisfying code is the kind that makes you smile at its cleverness.

The interface speaks the language of modern security: dark themes that don't strain tired eyes during late-night coding sessions, intuitive controls that never leave users guessing, and instant visual feedback that confirms every action. Four password options appear simultaneously because choice is power, and redundancy is wisdom.

Looking back as a more seasoned developer, I'm proud of the fundamentals I got right: modular JavaScript files that each handle their own concerns, smooth clipboard integration that works across browsers, and user experience thoughtfulness that prioritizes both security and usability. Not bad for a JavaScript newbie - sometimes beginner's mind produces surprisingly solid architecture.

ID Code Validator: Taking JavaScript Skills Further

Eleven digits that tell a life story. This precision-engineered validator decodes Estonian ID codes with surgical accuracy, validating everything from birth centuries to leap year calculations. What looks simple on the surface reveals layers of fascinating complexity beneath.

Estonian ID codes are digital DNA - each of the 11 digits carries specific meaning, from gender and birth century to the exact day someone entered this world. But here's the catch: not every 11-digit combination is valid. This app behaves like a detective, systematically investigating each digit to determine its authenticity.

The beauty lies in the architecture: a symphony of single-purpose functions, each one a specialist. One function checks if you were born in the 20th or 21st century. Another validates leap years with mathematical precision. A third ensures February 29th only exists when it should. Each function does one thing perfectly, and together they form an unbreakable validation chain.

The crown jewel? The checksum algorithm - a mathematical fingerprint that turns the first 10 digits into the 11th through a complex dance of weights and remainders. It's the kind of elegant problem-solving that makes you appreciate how much thoughtful engineering goes into something as seemingly simple as an ID number.

Tenzies: Discovering a New Framework

Roll, hold, repeat, win! This addictive dice game challenges you to match all ten dice to the same number - simple rules, endless fun. Built with Svelte 5's pristine reactivity, every roll feels satisfying and every victory well-earned.

My very first Svelte 5 project, and what a way to fall in love with a framework. Coming from React, I expected a learning curve, but what I got was an epiphany. The same game logic that would sprawl across multiple React components condensed into elegant, readable code. Svelte's reactivity didn't just work - it worked beautifully, turning complex state updates into simple, declarative magic.

Here's where I went rogue: instead of Svelte stores, I embraced good old-fashioned classes for state management. Why? Because sometimes the best architecture is the one that fits your mental model perfectly. Encapsulating all the game logic within a class felt natural, organized, and infinitely maintainable. The dice rolls, win conditions, and score tracking all lived in harmony within their class-based home.

This project wasn't just about building a game - it was about discovering that Svelte could make me genuinely excited about frontend development again. Every feature implemented felt like a small victory, every line of code a step toward something beautiful and functional.

Quiz App: Deepening My Svelte Mastery

Knowledge meets elegance in this interactive quiz experience. Built with Svelte 5's cutting-edge reactivity, every click feels instant, every transition smooth, and every question engaging. This isn't just a quiz app - it's a testament to what modern web development can achieve.

My second dance with Svelte 5, and I was already falling deeper in love. There's something addictive about Svelte's approach to building interfaces - it just feels right. Every feature I implemented reinforced my growing conviction that I'd found my new favorite framework.

Plot twist: this started life as a React app. But why settle for good when you can explore greatness? The migration to Svelte 5 wasn't just a technical experiment - it was a revelation. What took dozens of lines in React melted down to elegant, readable code that did more with less. The reactivity felt magical, the bundle size shrank, and my developer experience soared.

State management? Svelte's Writable stores made it almost embarrassingly simple. No complex setup, no boilerplate ceremony - just clean, predictable state that updates exactly when and where you expect it to. Sometimes the best solutions are the ones that make you wonder why other frameworks make things so complicated.

The result is a quiz app that feels alive. Multiple-choice questions flow naturally, the interface responds instantly to every interaction, and the clean design keeps users focused on what matters: learning, competing, and having fun. Built for engagement, optimized for joy.

Hedi Nurme's Recruitment Agency: Real-World Projects

When family dreams meet code, magic happens. This sleek, lightning-fast Next.js 15 website transforms a recruitment agency's vision into digital reality, showcasing expertise with elegance and performance that converts visitors into clients.

"Can you help me build my agency's website?" When my sister asked this question, I knew I was about to embark on something special. This wasn't just another client project - it was the chance to be the technical foundation of someone's entrepreneurial leap. There's something deeply rewarding about watching your code become the digital storefront for someone's dreams.

The real challenge? This agency needed to speak two languages fluently. Estonian and English audiences required seamless switching between languages, and the user experience had to feel natural in both. No jarring transitions, no content gaps - just smooth, intuitive multilingual navigation.

While i18n libraries exist, I chose to craft a custom internationalization solution. Sometimes the best tool is the one you build yourself - lighter, faster, and perfectly tailored to the project's needs. The result? A language switcher so smooth that users barely notice they're experiencing something technically complex. Clean code, zero bloat, maximum impact.