Guide

Vibe coding hobby projects: the two shapes that actually survive the loop

Most articles on this topic are 10-item lists of project ideas. They are useless, not because the ideas are bad, but because they pretend every hobby project fits the same iteration shape. It does not. There are exactly two shapes a vibe-coded hobby project can take without stalling inside the first hour. Everything else is wishful.

M
Matthew Diakonov
7 min read

Direct answer (verified 2026-05-18)

Two shapes survive. Shape one: single-file HTML toys with no persistence. Timers, calculators, generators, visualizers, one-screen games, custom widgets you want for yourself. Shape two: small React apps with at most one screen of meaningful state. A tracker, a configurator, a sketchpad, a tiny tool that outputs JSON for something else. Anything that needs real auth, a shared database, or three screens of state fights the iteration loop and stalls inside the 60 minute sandbox (E2B_TIMEOUT_MS = 3_600_000 in src/core/e2b.ts at line 33). Pick a project that fits one of the two shapes. The shape is the spec.

The taxonomy is the spec

A hobby project has a different optimization curve than a startup. The startup wants to ship and scale. The hobby wants to scratch an itch on a Saturday, and probably never think about again. A tool that treats both the same forces the hobby project through founder shaped friction: a signup form, a project dashboard, an environment setup, a meter. By the third screen the maker has lost the thread and closed the tab.

The shape that wins for hobby projects is the shape that closes the loop fastest. Idea, prompt, see the thing, change one detail, see the thing again. If the loop fits inside one focused hour, the project gets made. If it does not, the project becomes a tab that never closes. So the taxonomy is not a list of cool ideas. It is two constraints on the iteration loop: state and screens. Both can be small. Neither can be zero or you have nothing. Neither can be real-database-real-auth or the hour disappears into config.

The two shapes, side by side

Quick mode is built for the first shape. VM mode is built for the second. Picking the wrong mode for the project shape is the most common stall.

FeatureShape 1: single-file HTML toyShape 2: small React app
Mental modelSingle file. Open it in a browser and it just runs.One screen, a few components, some state in React.
Tool that fitsQuick mode (Claude Haiku streams HTML straight to the preview).VM mode (Vite + React + TypeScript + Tailwind in a sandbox).
Time-to-first-renderSeconds. The prompt itself is the loading bar.Under a minute. A real Linux sandbox spins up and a dev server boots.
Iteration costReprompt. The HTML rerenders. No state survives.Reprompt. The agent edits files, runs the dev server, opens Chromium, screenshots it back.
What it can holdA timer, a calculator, a generator, a visualizer, a single-page game.A tiny tracker, a tool with a list and a form, a configurator with state, a small canvas app.
Where it breaksThe moment you want state to survive a refresh.The moment you need real auth, a real database, or a second meaningful screen.

Why 60 minutes is not arbitrary

The number that enforces this taxonomy is in source. Open src/core/e2b.ts and look at line 33:

const E2B_TIMEOUT_MS = 3_600_000; // 1 hour

That is the maximum life of a single sandbox session. When the timer fires, the Linux VM tears itself down. No reminder, no warm tab, no zombie process holding a meter open. The hour was not chosen because cloud VMs cost a fortune. It was chosen because hobby attention spans cluster around it. You can draft, prompt five or six times, see the result, change three details, and walk away inside that window. A project that genuinely needs three uninterrupted hours of work to reach a first render is not a hobby project; it is a founder project pretending to be one.

The corollary: every minute the loop spends on configuration, auth, database setup, or environment plumbing comes out of the same hour. The two surviving shapes both spend zero minutes on those things. Shape one runs in a browser. Shape two runs on a preconfigured Vite + React + Tailwind stack the agent boots without asking. The hour is for the idea, not the scaffolding.

Same idea, two project shapes, only one survives the hour

A small social board for my climbing gym so we can share new routes. Sounds tiny on the surface. Underneath: real signup, a database that survives between visits, a moderation flow when someone posts garbage, image hosting, and shared state across users. The first prompt boots a sandbox. The next forty minutes are spent on auth provider config, database schema, and login UI. By minute 55 there are three screens and none of them work end to end. The hour ends mid-debug. The session expires. The repo exists, untouched.

  • Needs real auth
  • Needs persistence other users can read and write
  • Three or more screens that share state
  • Loop never closes in one hour

What the agent actually does while you sip coffee

In VM mode (shape two) the agent does not just write code and hope. Chromium runs headfully inside the sandbox on an Xvfb display, with DevTools on port 9222. A Playwright MCP server is attached over CDP. The agent's instructions at src/core/vm-claude-md.ts lines 275 to 285 are explicit:

After UI changes:
1. Navigate to http://localhost:5173 via Playwright MCP
2. Take a snapshot to verify the DOM rendered correctly
3. Check browser_console_messages for runtime errors
4. If the page is blank, verify the component is imported in App.tsx
5. Do not report completion until the browser shows the expected result

For a hobby project this changes the loop in a specific way. You do not become the QA team for the AI. If the agent breaks an import, it sees that the screen is blank, fixes it, and tries again, all before handing the turn back. The five prompts you have time for in your hour are five real iterations on the idea, not five rounds of "hey it crashed" followed by paste-the-error into chat.

There is a second piece: the agent is told to actively remember you across the session. The CLAUDE.md injected at /root/.claude/CLAUDE.md tells it to save memories the moment it learns your skill level, what the project is for, color preferences, components you have rejected, or constraints you have stated. So if in prompt one you said "this is for me, no emoji please", prompt seven still avoids emoji. If in prompt three you mentioned the climbing gym context, prompt nine still treats it like a tool for climbers. That memory does not survive the sandbox tearing down, but it survives within the hour, which is the window that matters.

Quick mode output (HTML, in seconds)
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width,initial-scale=1" />
  <title>Sourdough hydration</title>
  <style>
    body { font: 16px system-ui; max-width: 360px; margin: 2rem auto; }
    input, output { font-size: 2rem; width: 100%; }
    label { display:block; margin-top: 1rem; color:#475569; }
  </style>
</head>
<body>
  <h1>Sourdough hydration %</h1>
  <label>Flour (g) <input id="f" type="number" value="500" /></label>
  <label>Water (g) <input id="w" type="number" value="350" /></label>
  <output id="o">70%</output>
  <script>
    const f = document.getElementById('f');
    const w = document.getElementById('w');
    const o = document.getElementById('o');
    const u = () => o.textContent =
      Math.round((+w.value / +f.value) * 100) + '%';
    f.oninput = w.oninput = u;
  </script>
</body>
</html>
VM mode output (React, with persistence)
// /app/src/App.tsx
import { useState } from "react";

export default function App() {
  const [bakes, setBakes] = useState<{ flour: number; water: number; note: string }[]>(
    () => JSON.parse(localStorage.getItem("bakes") || "[]")
  );
  const [flour, setFlour] = useState(500);
  const [water, setWater] = useState(350);
  const [note, setNote] = useState("");

  const save = () => {
    const next = [...bakes, { flour, water, note }];
    setBakes(next);
    localStorage.setItem("bakes", JSON.stringify(next));
    setNote("");
  };

  const hydration = Math.round((water / flour) * 100);
  return (
    <main className="mx-auto max-w-sm p-6 space-y-4">
      <h1 className="text-2xl font-bold">Sourdough log</h1>
      <p className="text-4xl font-mono">{hydration}%</p>
      <input type="number" value={flour} onChange={(e) => setFlour(+e.target.value)} />
      <input type="number" value={water} onChange={(e) => setWater(+e.target.value)} />
      <input value={note} onChange={(e) => setNote(e.target.value)} placeholder="note" />
      <button onClick={save} className="rounded bg-teal-600 px-3 py-2 text-white">
        log bake
      </button>
      <ul>{bakes.map((b, i) => <li key={i}>{b.flour}g / {b.water}g, {b.note}</li>)}</ul>
    </main>
  );
}

The hobby projects that quietly do not survive

Worth naming explicitly, because the failure mode looks identical up front. The idea sounds small. It is not. These are the shapes where the hour disappears and the maker walks away frustrated:

  • A tiny thing "just for me and my three friends" that needs login. Multi-user means real auth, real persistence, and a real moderation surface. The smallest version of that is still a 6 hour build, not a 1 hour one.
  • A side blog with a comment section. Single-author blog is fine as a static site. The comment box drags in storage, spam handling, identity, and email. Use a hosted comment system, do not vibe code one in an hour.
  • A "simple" CRM for freelance clients. The simplest version still has a list, a detail screen, a form, persistence across sessions, and at least one filter. Five screens minimum once you stop pretending. Build it in a notes app first; vibe code only the one screen you actually look at daily.
  • Anything multiplayer. Real-time state across users is not a hobby project shape at the current state of vibe coding. Pick a single-player version first.
  • A mobile app, native. Vibe coding here means web. Generated HTML/JS/React, viewed in a mobile browser. If the project must live in the App Store, that is a different tooling conversation.

None of these are impossible to build with AI assistance. They are wrong for the hobby loop specifically. The hour expires before any of them reach a first end-to-end render. The maker concludes that vibe coding is a toy, when the truer conclusion is that the project chosen was the wrong shape for the loop.

A list of hobby projects that fit, with the shape labeled

Not aspirational. Each of these is shape-checked: zero auth, zero multi-user state, fits in one focused hour. Pick by domain you already care about; the loop is the same.

Shape 1 (single-file HTML toys)
  • A focus timer matched to one specific song length.
  • A unit converter for a hobby you have (climbing grades, brewing gravity).
  • A name generator for a tabletop campaign.
  • A custom dice roller for a homebrew system.
  • A breath pacing visualizer.
  • A color palette generator with a seed phrase.
  • A one-screen reaction game for a kid.
  • A regex tester that highlights matches inline.
  • A small SVG visualizer for data you paste in.
  • A sourdough hydration calculator (see the code block above).
Shape 2 (small React apps)
  • A mood tracker that saves to localStorage.
  • A Pomodoro you actually like the look of.
  • A configurator that outputs Tailwind classes or CSS.
  • A sketchpad with one undo and a downloadable PNG.
  • A tiny note app with markdown and one tag dimension.
  • A workout logger for one specific exercise you do.
  • A media queue for a side hobby (books, films) with one filter.
  • A custom expense tracker with three categories.
  • A reading speed estimator on pasted text.
  • A keyboard layout visualizer for your own ergonomic build.

The honest answer if you came here from a thread

Pick a real itch you have, today, that someone could explain in one sentence. If the explanation does not include the words "account", "login", "everyone", or "sync", you have a shape one or shape two project. Open mk0r.com on whatever device you are reading this on. Type the sentence in. Pick Quick if there is no persistence needed, VM if there is even a hint of one. You will know within five prompts whether the shape is right. If it is, the loop closes inside the hour. If it is not, that is also a useful answer; come back with a smaller version of the idea.

Want me to look at the shape of your hobby project?

Bring the idea, I will tell you whether it fits shape one, shape two, or whether the loop will stall on you. Free call, no pitch.

Frequently asked questions

What hobby projects actually survive vibe coding right now?

Two shapes. The first is single-file HTML toys you can sketch from one sentence: a kitchen timer for a specific recipe, a custom unit converter, a name generator, a habit ticker, a fidget widget, a one-screen reaction game, a tiny visualizer for some data you have in mind. The second is small React apps with at most one screen of meaningful state: a quick mood tracker, a Pomodoro you actually like the look of, a configurator that outputs JSON or CSS for something else, a sketchpad. Both fit inside one focused hour. The shapes that quietly do not survive: anything with login, anything that has to remember state across days for many users, anything with three or more screens that share state.

Why a 60 minute window specifically?

Not a marketing number. Look at src/core/e2b.ts line 33. The sandbox running your app sets `E2B_TIMEOUT_MS = 3_600_000` (one hour). That is the maximum lifespan of one session before the VM tears itself down. The number was picked because hobby attention spans cluster around that window: long enough to draft, prompt, see it, change three things, and walk away; short enough that an abandoned session does not haunt a billing meter. A hobby project that needs three sessions of an hour each is fine. A hobby project that needs one session of three hours is the wrong shape for this tooling.

What is the difference between the two modes in practice?

Quick mode uses Claude Haiku to stream HTML straight back to the preview pane. You see characters arrive. There is no file system, no terminal, no real build step. The output is one HTML file with inline styles and inline JavaScript. It is perfect for sketches, single-screen toys, and anything where state in memory is fine. VM mode boots a real Linux sandbox with Vite, React, TypeScript, Tailwind, and a Playwright-controlled Chromium. The agent edits real files in /app, runs the dev server, opens its own browser to verify the result, and reports back. It is what you switch to once a project crosses the line from sketch to thing.

Can the agent actually tell whether the thing it built works?

Yes, in VM mode. Chromium runs headfully inside the sandbox on an Xvfb display, with DevTools on port 9222 and a Playwright MCP server attached. The agent's instructions at src/core/vm-claude-md.ts lines 275 to 285 say after every UI change: navigate to http://localhost:5173, take a DOM snapshot, check browser_console_messages for runtime errors, verify the component is imported in App.tsx, and do not report completion until the browser shows the expected result. So if a hobby tweak breaks a render, the agent sees it and fixes it before handing the turn back. You are not the QA team for your weekend.

Does the AI remember what I'm building between prompts?

Inside a session, yes. The CLAUDE.md injected into the VM at /root/.claude/CLAUDE.md tells the agent to save memories about you immediately when it learns your name, your skill level, what you are building, color preferences, components you have rejected, and the why behind decisions. Those memories stay loaded while the session lives. So if you say in prompt one 'I do not want emoji', prompt seven does not ship emoji. If you say in prompt two 'this is a kitchen timer for sourdough', prompt nine still treats it like a kitchen timer for sourdough. The catch is that the memory lives in the sandbox; when the one hour timer fires, the sandbox is gone and that context dissolves with it. The git history of the session persists. The memory does not.

What about persistence for a hobby project I want to keep?

Every session generates a private GitHub repo via the GitHub API in src/core/service-provisioning.ts. The repo gets a slug like mk0r-<twelve-char-session-id> under the m13v org, and its URL is written to /app/.env inside the sandbox so the agent can push to it. Each prompt becomes a real git commit on that repo via commitTurn(). If you abandon the project, the repo sits there unobtrusively. If you want it back, you fork it and keep going on your own machine. Nothing is locked inside a no-code editor.

What about the projects that look like they should work but don't?

The honest ones to flag. Anything that needs real login (Google, GitHub, magic links) is not the right shape; the auth provider configuration alone eats a full hour. Anything that needs a real database your users edit (a community board, a list everyone adds to) needs persistence that lives outside the sandbox; that is a different tool. Anything with three or more screens that share state pushes the agent into multi-file refactors that drift inside one session. Multiplayer real-time anything. Native iOS or Android. Production payments. If you start there you will walk away frustrated; if you start with a single-screen utility you will finish.

What is the difference between this and Bolt, v0, Lovable, or Replit Agent?

Those tools are excellent at the founder loop: sign up, get a dashboard, build, deploy, scale. They assume forward motion. They cost a meter that ticks while you decide whether to come back. For hobby projects the meter is the problem; it imports the founder lens onto the maker lens. mk0r drops every signup screen: no account, anonymous UUID in localStorage, the session URL is your only handle. The sandbox auto-expires. There is no dashboard to feel guilty about. Forward motion is not the assumption. You can vibe code a kitchen timer at midnight and forget about it. Six months later the URL is in your history; the code is in a github repo you forgot you owned.

Are the hobby projects people actually build on this any good?

Some are surprisingly good for the shape they fit. Specific custom dashboards (sourdough hydration calculator, climbing grade converter, a focus timer that matches your music) are dense one-screen tools that polish well in five prompts. Tiny generators (band name, dungeon room, color palette) are textbook Quick mode. The pattern that fails most often is when someone tries to vibe code 'a small CRM for my freelance clients' or 'a tiny social network for my friends'. Both have invisible complexity: auth, persistence, multi-user state. They look like one-screen apps and are not. The taxonomy in this article is the lesson I would want before starting one.

How do I know which mode to pick before I start?

Ask one question: does the project need state to survive a browser refresh? If no, Quick mode. Streaming HTML, single file, fastest loop, runs in 5 seconds. If yes, even slightly (a list the user adds to, a saved theme, a configuration that persists in localStorage), VM mode. You get real React, real files, a dev server, and an agent that can verify its own work. The mode picker lives at the top of the prompt input on the homepage; you can switch mid-session but most hobby projects want one and stay there.

mk0r.AI app builder
© 2026 mk0r. All rights reserved.

How did this page land for you?

React to reveal totals

Comments ()

Leave a comment to see what others are saying.

Public and anonymous. No signup.