Instead of trusting my memory that "I've gotten better", I went back through two of my own repos a year apart: GeekMate and CodePersona. The differences turned out to be more specific than "my code is cleaner now."

1. Commit messages. GeekMate's commits say things like fixed handling, ui and ... They made sense that day and mean nothing now. CodePersona's commits say what changed and why. They're not longer for the sake of it; they're written for someone who wasn't in my head at the time, which is usually me, months later.
2. The project root. GeekMate's root is a package.json and a src folder. Nothing tells you how it's linted, typed or built. CodePersona's root has ESLint and TypeScript configs, so anyone opening it knows the rules before writing a line.
3. Comments. GeekMate has comments like // this is a readymade middleware, which helps us read the JSON data, narrating code that couldn't explain itself. CodePersona barely has comments, and doesn't need them: typed props and components named for what they render say the same thing. Fewer comments turned out to mean better names, not less care.
4. Folder structure. In GeekMate I knew where things lived because I'd put them there. In CodePersona, hooks are in hooks/, shared logic is in lib/ and integrations get their own folder, so the layout explains the architecture before you open a file.
GeekMate wasn't bad. It shipped and people used it. But every change above is the same idea at a different layer: write for someone who doesn't have your context. Most of the time, that someone is future you.