[{"data":1,"prerenderedAt":270},["ShallowReactive",2],{"post-picking-a-side-project-stack":3,"blog-posts":14},{"_path":4,"title":5,"description":6,"date":7,"tags":8,"readingTime":12,"body":13},"\u002Fblog\u002Fpicking-a-side-project-stack\u002F","Picking a Side Project Stack Without Overthinking It","How to choose tools for a personal project when the goal is shipping, not building the perfect architecture.","2025-09-18",[9,10,11],"productivity","frontend","best-practices",5,"# Picking a Side Project Stack Without Overthinking It\n\nSide projects die in the setup phase more often than in the build phase. The stack should get out of your way fast—familiar tools, simple hosting, and a clear path to something you can show.\n\n## Start from what you already know\n\nIf you ship Vue at work, use Vue. If you are fastest in plain HTML and CSS, that is a valid stack. Learning three new frameworks on the same repo is a hobby tax, not a shortcut.\n\nFamiliarity compounds. You already know how to debug your usual tools, where the docs live, and which patterns fail quietly. That means more of your evening goes into the product idea instead of fighting a new bundler config. Side projects are already short on time; spending the first weekend on “hello world in a language I do not know yet” is how unfinished folders accumulate.\n\nI still make room for learning—but I isolate it. A portfolio site is a bad place to learn Rust, GraphQL, and a new CSS methodology at once. Pick one learning goal per project, or none. Shipping with tools you know is not stagnation; it is how you build a body of finished work that later makes ambitious experiments feel grounded.\n\nA quick check I use: can I sketch the first page and have it running locally in under an hour with this stack? If the honest answer is “after I finish the tutorial series,” the stack is too new for *this* project. Save that energy for a dedicated spike.\n\n## Match hosting to the project\n\nA portfolio or blog belongs on Cloudflare Pages, Netlify, or similar—low ops, edge delivery, and room for small API routes when you need them. Reach for a heavier backend only when the idea genuinely needs auth, persistence, or real-time features you cannot fake locally.\n\nHosting decisions often sneak in as architecture decisions. People spin up a VPS “just in case,” then spend nights patching and renewing certificates instead of writing features. For content sites and marketing pages, static (or statically generated) hosting is almost always enough. You get HTTPS, previews on pull requests, and a deploy that is basically “push to main.”\n\nWhen the idea *does* need a server, still prefer the lightest option that fits:\n\n- Form submissions → a form provider or a tiny edge function\n- Auth → a managed auth service instead of rolling sessions from scratch\n- Database → a hosted DB with a simple SDK, not a self-managed cluster\n\nI ask one question before adding infrastructure: what breaks if this service is down for an hour? If the answer is “nothing critical,” keep it static. If the answer is “users cannot complete the core action,” then earn the ops cost.\n\nFor this site, Nuxt plus Cloudflare Pages is enough: markdown content, prerendered routes, and occasional server routes without running a long-lived Node process myself. That match of project shape to hosting shape matters more than chasing the newest platform blog post.\n\n## Boring defaults win\n\nFor most personal sites, a short list of boring defaults beats a custom architecture diagram:\n\n- A static site generator or SPA you are comfortable with\n- Markdown or JSON for content\n- Git for version control\n- One deploy command (or one CI job that runs that command)\n\nThat is enough to publish for years. Content in files means reviews happen in pull requests. Git means you can revert a bad post. One deploy command means you are not the only person who knows the release ritual—future you counts as “people.”\n\nI also keep dependencies thin on purpose. Every package is something that can break on upgrade day. Prefer the platform’s built-ins and a few libraries you already trust. A side project does not need a design system monorepo, a state-management framework, and three CSS abstraction layers before the first page ships.\n\nExample of a stack that stays boring and shippable:\n\n```text\nNuxt (or Vite + Vue)\nMarkdown in \u002Fcontent\nnpm run build → static output\nCloudflare Pages on push to main\n```\n\nIf you need a CMS later, you can add one. Starting with markdown does not lock you out of that path; it just lets you publish before you invent editorial workflow.\n\n## When to experiment\n\nSave new tools for a throwaway branch or a tiny spike repo. Prove the idea in a weekend with familiar tools first. Swap pieces later if a real constraint shows up—not because a blog post said you should.\n\nExperimentation is healthy when it has a boundary. Timebox a spike: “two evenings to see if this library solves X.” Write down the success criteria before you start. If the spike fails, delete the branch without guilt. If it succeeds, migrate deliberately—one piece at a time—rather than rewriting the whole app mid-feature.\n\nWhat counts as a real constraint worth swapping for:\n\n- Build times that make iteration painful\n- A missing capability you cannot fake (offline sync, realtime collaboration)\n- A security or compliance need you cannot meet with the current host\n\nWhat does *not* count: boredom with your current stack, fear of missing a trend, or the urge to rebuild because the README looks too simple. Simple READMEs are a feature.\n\nWhen you do adopt something new, keep the public surface of the project stable. Users do not care that you switched CSS tools; they care that links still work. Migrate behind the same routes and content shapes so the experiment does not become an accidental redesign.\n\n## Wrap-up\n\nPick familiar tools, host simply, and ship something small. You can always refactor once the project has a reason to exist beyond the README—and by then, the constraints that matter will be obvious instead of imaginary.",[15,23,32,41,48,56,63,71,78,85,92,100,107,114,120,128,134,142,151,159,165,172,178,186,194,201,207,209,216,222,228,234,241,248,255,263],{"_path":16,"title":17,"description":18,"date":19,"tags":20,"readingTime":12},"\u002Fblog\u002Fclient-side-tools-that-earn-trust\u002F","Client-Side Tools That Earn Trust","How to design browser tools that feel private by default—local processing, clear data boundaries, and UX that never asks people to guess where their files go.","2026-07-20",[21,10,22],"privacy","tools",{"_path":24,"title":25,"description":26,"date":27,"tags":28,"readingTime":31},"\u002Fblog\u002Fusb-c-cables-that-actually-matter\u002F","USB-C Cables That Actually Matter","How to buy USB-C cables by wattage and data speed so you stop guessing which cord charges slowly or fails a file transfer.","2026-07-14",[29,30,9],"gadgets","hardware",4,{"_path":33,"title":34,"description":35,"date":36,"tags":37,"readingTime":12},"\u002Fblog\u002Fcolor-contrast-people-can-read\u002F","Color Contrast People Can Actually Read","Quick checks for text and UI colors that stay legible in light mode, dark mode, and on mediocre displays.","2026-07-07",[38,39,40],"accessibility","css","design",{"_path":42,"title":43,"description":44,"date":45,"tags":46,"readingTime":12},"\u002Fblog\u002Fportable-ssds-worth-carrying\u002F","Portable SSDs Worth Carrying","When a pocket SSD beats cloud sync for travel, backups, and large media—and how to pick one that stays fast and durable.","2026-06-26",[29,47,9],"storage",{"_path":49,"title":50,"description":51,"date":52,"tags":53,"readingTime":12},"\u002Fblog\u002Fwireless-earbuds-that-last-the-day\u002F","Wireless Earbuds That Last the Day","Simple charging and fit habits that stretch earbud battery life without babysitting the case every few hours.","2026-06-18",[29,54,55],"audio","habits",{"_path":57,"title":58,"description":59,"date":60,"tags":61,"readingTime":31},"\u002Fblog\u002Fwhen-a-second-monitor-helps\u002F","When a Second Monitor Actually Helps","A practical take on dual screens for coding, writing, and research—plus when a single good display is still the better desk.","2026-06-10",[29,9,62],"workspace",{"_path":64,"title":65,"description":66,"date":67,"tags":68,"readingTime":31},"\u002Fblog\u002Fshort-session-game-picks\u002F","Short-Session Games That Respect Your Evening","Genres and design patterns that fit a 30-minute window without the “one more hour” trap.","2026-06-04",[69,55,70],"gaming","indie",{"_path":72,"title":73,"description":74,"date":75,"tags":76,"readingTime":12},"\u002Fblog\u002Fphone-charging-habits-that-age-better\u002F","Phone Charging Habits That Age Better","Practical charging routines that keep a phone useful longer—without obsessing over the perfect battery percentage.","2026-05-23",[29,77,55],"mobile",{"_path":79,"title":80,"description":81,"date":82,"tags":83,"readingTime":12},"\u002Fblog\u002Ffinishing-side-projects-without-burning-out\u002F","Finishing Side Projects Without Burning Out","A practical playbook for shrinking scope, shipping thin vertical slices, and keeping personal projects fun long enough to actually launch.","2026-05-14",[9,84,55],"side-projects",{"_path":86,"title":87,"description":88,"date":89,"tags":90,"readingTime":12},"\u002Fblog\u002Faccessible-forms-people-finish\u002F","Accessible Forms That People Actually Finish","Practical accessibility checks for labels, errors, and focus so your forms work for more users.","2026-05-07",[38,91,10],"html",{"_path":93,"title":94,"description":95,"date":96,"tags":97,"readingTime":12},"\u002Fblog\u002Fvue-composition-api-patterns\u002F","Practical Vue Composition API Patterns","Reusable patterns for composables, shared state, and cleaner component logic in Vue 3.","2026-04-27",[98,99,10],"vue","javascript",{"_path":101,"title":102,"description":103,"date":104,"tags":105,"readingTime":12},"\u002Fblog\u002Fdesigning-empty-states-that-teach\u002F","Designing Empty States That Teach the Product","Empty screens are not placeholders—they are onboarding. How to write, layout, and sequence first-run UI so people know what to do next.","2026-04-19",[106,10,40],"ux",{"_path":108,"title":109,"description":110,"date":111,"tags":112,"readingTime":12},"\u002Fblog\u002Fwhy-indie-games-keep-winning\u002F","Why Indie Games Keep Winning Attention","How small teams punch above their weight with focused design, personality, and smart scope.","2026-04-13",[69,70,113],"industry",{"_path":115,"title":116,"description":117,"date":118,"tags":119,"readingTime":12},"\u002Fblog\u002Fkeeping-component-props-simple\u002F","Keeping Component Props Simple","When to split a component, when to use slots, and how to avoid prop objects that grow forever.","2026-04-03",[98,10,11],{"_path":121,"title":122,"description":123,"date":124,"tags":125,"readingTime":12},"\u002Fblog\u002Fcalm-frontend-performance\u002F","A Calm Approach to Frontend Performance","Performance work that sticks: measure what users feel, fix the critical path first, and avoid optimization theater on personal and portfolio sites.","2026-03-26",[126,10,127],"performance","web",{"_path":129,"title":130,"description":131,"date":132,"tags":133,"readingTime":12},"\u002Fblog\u002Fcss-layout-without-the-hacks\u002F","CSS Layout Without the Hacks","Modern Flexbox and Grid techniques that replace brittle floats, magic numbers, and overflow tricks.","2026-03-17",[39,10,40],{"_path":135,"title":136,"description":137,"date":138,"tags":139,"readingTime":12},"\u002Fblog\u002Fcloud-gaming-what-gets-in-the-way\u002F","Cloud Gaming: What Still Gets in the Way","Latency, input feel, and library lock-in—why streaming games is impressive and still uneven.","2026-03-10",[69,140,141],"cloud-gaming","tech",{"_path":143,"title":144,"description":145,"date":146,"tags":147,"readingTime":12},"\u002Fblog\u002Fshipping-static-sites-with-nuxt\u002F","Shipping Static Sites with Nuxt","How I build and deploy a Nuxt site to Cloudflare Pages with predictable routes and content.","2026-03-02",[148,149,150],"nuxt","ssg","devops",{"_path":152,"title":153,"description":154,"date":155,"tags":156,"readingTime":12},"\u002Fblog\u002Fdebugging-faster-in-the-browser\u002F","Debugging Faster in the Browser","A short toolkit of DevTools habits—breakpoints, network filters, and DOM inspection—that cut debug time.","2026-02-24",[99,157,158],"devtools","debugging",{"_path":160,"title":161,"description":162,"date":163,"tags":164,"readingTime":12},"\u002Fblog\u002Fsmall-javascript-habits-that-scale\u002F","Small JavaScript Habits That Scale","Everyday habits—naming, early returns, and clearer async flow—that keep front-end codebases maintainable.","2026-02-18",[99,11,10],{"_path":166,"title":167,"description":168,"date":169,"tags":170,"readingTime":31},"\u002Fblog\u002Fhealthier-gaming-routine\u002F","Building a Healthier Gaming Routine","Simple habits for sessions that stay fun—breaks, goals, and knowing when to stop.","2026-02-02",[69,55,171],"wellness",{"_path":173,"title":174,"description":175,"date":176,"tags":177,"readingTime":12},"\u002Fblog\u002Fresponsive-images-without-layout-shift\u002F","Responsive Images Without Layout Shift","Width, height, srcset, and lazy loading patterns that keep pages stable while images load.","2026-01-22",[91,126,10],{"_path":179,"title":180,"description":181,"date":182,"tags":183,"readingTime":12},"\u002Fblog\u002Fgit-habits-for-small-teams\u002F","Git Habits for Solo and Small Teams","Branch naming, commit messages, and PR hygiene that keep history useful without slowing you down.","2026-01-09",[184,185,9],"git","workflow",{"_path":187,"title":188,"description":189,"date":190,"tags":191,"readingTime":12},"\u002Fblog\u002Fwhat-makes-a-game-stream-worth-watching\u002F","What Makes a Game Stream Worth Watching","Commentary, pacing, and community—why some streams click even when the gameplay is messy.","2025-12-14",[69,192,193],"streaming","content",{"_path":195,"title":196,"description":197,"date":198,"tags":199,"readingTime":12},"\u002Fblog\u002Fwhen-to-reach-for-typescript-vue\u002F","When to Reach for TypeScript on a Vue App","A pragmatic take on where TypeScript pays off in Vue—and where plain JS is still fine.","2025-11-30",[200,98,10],"typescript",{"_path":202,"title":203,"description":204,"date":205,"tags":206,"readingTime":12},"\u002Fblog\u002Fenvironment-variables-for-static-sites\u002F","Environment Variables for Static Sites","How to use build-time env vars in Nuxt and other static generators without leaking secrets or breaking CI.","2025-10-05",[148,150,10],{"_path":4,"title":5,"description":6,"date":7,"tags":208,"readingTime":12},[9,10,11],{"_path":210,"title":211,"description":212,"date":213,"tags":214,"readingTime":31},"\u002Fblog\u002Fco-op-games-for-busy-friends\u002F","Co-op Games That Work When Everyone Is Busy","Async-friendly and drop-in co-op picks for friend groups that rarely share the same free evening.","2025-08-22",[69,215,55],"co-op",{"_path":217,"title":218,"description":219,"date":220,"tags":221,"readingTime":12},"\u002Fblog\u002Fsemantic-html-still-matters\u002F","Semantic HTML Still Matters","Landmarks, headings, and native elements that make pages easier to use, style, and maintain.","2025-07-06",[91,38,10],{"_path":223,"title":224,"description":225,"date":226,"tags":227,"readingTime":12},"\u002Fblog\u002Fgit-without-the-jargon\u002F","Learning Git Without the Jargon","A plain-language mental model for commits, branches, and merges when tutorials assume you already know Git.","2025-05-14",[184,185,9],{"_path":229,"title":230,"description":231,"date":232,"tags":233,"readingTime":12},"\u002Fblog\u002Fwhy-loading-states-matter\u002F","Why Loading States Matter More Than Animations","Skeletons, disabled buttons, and honest feedback beat flashy spinners when data takes time to arrive.","2025-03-28",[106,10,40],{"_path":235,"title":236,"description":237,"date":238,"tags":239,"readingTime":12},"\u002Fblog\u002Fnaming-things-so-future-you-survives\u002F","Naming Things So Future You Survives","Practical rules for naming variables, components, and files so a codebase stays readable months after the clever jokes fade.","2025-03-10",[99,11,240],"maintainability",{"_path":242,"title":243,"description":244,"date":245,"tags":246,"readingTime":12},"\u002Fblog\u002Fsave-systems-that-respect-time\u002F","Save Systems That Respect the Player’s Time","Checkpoints, autosaves, and manual slots are design choices. How thoughtful saving reduces rage-quits without deleting tension from the game.","2025-02-28",[69,247,106],"game-design",{"_path":249,"title":250,"description":251,"date":252,"tags":253,"readingTime":12},"\u002Fblog\u002Fmicrocopy-that-makes-interfaces-human\u002F","Microcopy That Makes Interfaces Feel Human","Button labels, error lines, and helper text are product design. How to write UI words that reduce hesitation without sounding like a chatbot.","2025-01-22",[106,254,40],"writing",{"_path":256,"title":257,"description":258,"date":259,"tags":260,"readingTime":12},"\u002Fblog\u002Freadmes-that-get-projects-running\u002F","READMEs That Get Projects Running","How to write a README that helps someone—including future you—install, run, and understand a project without opening a support chat.","2024-12-18",[261,262,55],"documentation","open-source",{"_path":264,"title":265,"description":266,"date":267,"tags":268,"readingTime":12},"\u002Fblog\u002Fprogressive-enhancement-still-pays-off\u002F","Progressive Enhancement Still Pays Off","Build the core experience in HTML first, then layer CSS and JavaScript so your site stays useful when networks, scripts, or devices misbehave.","2024-11-05",[91,10,269],"architecture",1784620505029]