DEV Community

Cover image for AI Duel on Building Retro RPG Quest Journal
YASHWANTH REDDY K
YASHWANTH REDDY K

Posted on

AI Duel on Building Retro RPG Quest Journal

There’s a version of this challenge that feels complete in minutes.

You click a quest.
It turns yellow.
Click again → green, strikethrough.
XP bar fills.
“LEVEL UP!” flashes.

It’s responsive. It’s clean. It works.

And yet… if you sit with it for a second, something starts to feel off.

Not visually.

Structurally.

The break doesn’t happen when something fails.

It happens when you ask a slightly annoying question:

“What actually controls this system?”

Because if the honest answer is “the DOM”… you’ve already lost.

Where the illusion begins

Most implementations don’t explicitly choose a bad approach.

They just drift into it.

A click handler like this:

el.classList.toggle("active");
Enter fullscreen mode Exit fullscreen mode

feels harmless.

Then you stack another:

if (el.classList.contains("active")) {
  xp += 33;
}
Enter fullscreen mode Exit fullscreen mode

Now your logic is reading from the UI.

And just like that, the direction flips:

UI → Logic

Instead of:

State → UI

Nothing breaks immediately.

Which is why this pattern survives longer than it should.

The moment things get weird

Try this mentally:

  • Click Quest 1 → Completed
  • Click Quest 2 → Completed
  • Refresh your understanding (not the page)

Now ask:

“How much XP do I have?”

If your system needs to inspect the DOM to answer that…

It doesn’t know its own state.

It’s guessing.

The version that feels different (and you can’t unsee it)

At some point, you stop touching the DOM entirely.

Not physically — but conceptually.

You start from something like this:

const game = {
  quests: [
    { id: 1, state: "locked" },
    { id: 2, state: "locked" },
    { id: 3, state: "locked" }
  ],
  clicks: 0
};
Enter fullscreen mode Exit fullscreen mode

Nothing fancy.

But now there’s a single place where truth exists.

And that changes everything downstream.

Clicking a quest is no longer:

“change how this looks”

It becomes:

quest.state = nextState(quest.state);
Enter fullscreen mode Exit fullscreen mode

A mutation of meaning, not appearance.

And then something subtle happens

You stop “updating” the XP bar.

You remove that code entirely.

Because XP is no longer something you store.

It becomes something you derive.

const completed = game.quests.filter(q => q.state === "completed").length;
const xp = (completed / game.quests.length) * 100;
Enter fullscreen mode Exit fullscreen mode

No syncing.

No edge cases.

No “what if we forgot to update it?”

It just… exists.

This is where AI models start to split

On Vibe Code Arena, this challenge creates a really interesting pattern.

Not in who gets it working.

Everyone does.

But in how stable the system feels when you push it.

One model tends to scatter logic:

  • click handler updates class
  • another updates XP
  • another checks for level-up

It’s like three mini-systems loosely cooperating.

And it holds… until you stress it.

Another model centralizes everything:

  • state changes in one place
  • rendering happens in one pass
  • UI is always regenerated

Something like:

function render() {
  // read state
  // compute derived values
  // output UI
}
Enter fullscreen mode Exit fullscreen mode

That function becomes the entire app.

Not because it’s elegant.

Because it’s predictable.

The “LEVEL UP!” moment is not about animation

It’s where your system gets audited.

Because now you need to answer:

  • When exactly does level-up happen?
  • What resets?
  • What persists?
  • What triggers the animation?

If your logic is scattered, you end up with defensive code:

if (xp === 100 && !alreadyLeveled) {
  // do something
}
Enter fullscreen mode Exit fullscreen mode

If your logic is grounded in state, it’s almost boring:

if (xp === 100) {
  level++;
  resetQuests();
}
Enter fullscreen mode Exit fullscreen mode

No guards. No hacks.

Just consequence.

The part that sneaks up on you

At some point, you stop thinking about:

  • quests
  • XP bars
  • retro UI

And start thinking in transitions.

locked  active  completed  locked
Enter fullscreen mode Exit fullscreen mode

That’s not UI logic.

That’s a state machine.

And once you see it that way…

Everything simplifies.

The UI becomes… replaceable

This is the weirdest shift.

You realize the visual layer doesn’t matter anymore.

Pixel font? Doesn’t matter.
Green vs yellow? Cosmetic.
Animation timing? Secondary.

Because the real system is already stable.

The UI is just a skin.

And this is where most people miss the actual challenge

They think they’re building:

“a retro quest tracker”

They’re actually being asked:

“Can you build a system where every visual outcome is inevitable?”

That’s a very different problem.

If you want to feel the difference, not just understand it

Open the challenge.

But don’t rush to finish it.

Break it a little.

Add one more quest.
Click things out of order.
Try to reason about your own system.

That’s where the gaps show up.

👉 https://vibecodearena.ai/share/6bf96add-8e8b-45de-ab7f-43a1124e9d12

Top comments (0)