🕉️ Devlog — गुरु-दीक्षा: Teaching Karma Without Breaking Immersion
"गुरु बिना ज्ञान नहीं।"
Without a Guru, there is no knowledge.
The Problem
Moksha is a game rooted in Sanatan Shastra — Vedic Karma mechanics, Sanskrit concepts, rebirth cycles. It's intentionally deep. And that depth was quietly becoming its biggest barrier.
New players would start the game and immediately face naama-jaap, vairaagya, prarabdha, chetana-jagriti — all at once, with no guidance. Within the first 30 seconds, most had no idea what they were doing or why.
The game needed a tutorial. But it needed one that didn't betray what Moksha is.
Why a Normal Tutorial Wouldn't Work
The obvious solution — pause the game, show a tooltip, unpause — felt completely wrong for Moksha. Spiritually, a hard pause breaks the flow of consciousness. Mechanically, isPaused = true is deeply wired into audio ducking, gamepad state, and ambient layers. Hijacking it for tutorial logic would have introduced subtle bugs across every system.
An earlier attempt at a tutorial (Issue #30) tried to live inside engine.js itself. That was worse — the engine is already the heaviest file in the codebase, and embedding tutorial step state there violated the entire modular architecture we'd been building toward.
So I scrapped both approaches and started over.
The Solution: गुरु-दीक्षा (Guru's Initiation)
The new system is built around one philosophical reframe: a Guru doesn't stop the world to teach. They walk alongside you.
This became the technical foundation too.
A New Module — src/tutorial.js
TutorialManager is a self-contained ES6 class. It doesn't import from engine.js or touch any game state directly. Instead, main.js passes it an engine state snapshot every frame via checkCompletion(state). The tutorial reads — never writes.
engine.js ──(no connection)──> tutorial.js
main.js ──(snapshot feed)──> tutorial.js
Enter fullscreen mode Exit fullscreen mode
Zero coupling. Zero risk to existing systems.
Slow Motion, Not Hard Pause
When a tutorial card is visible, the game doesn't stop. Instead, dt is multiplied by 0.3 in the game loop:
const dt = tutorial.isSlowMode() ? rawDt * 0.3 : rawDt;
Enter fullscreen mode Exit fullscreen mode
The world keeps moving — entities drift, the cosmos breathes — but at a contemplative pace. It feels like the Guru has slowed time itself to let you absorb the teaching. As soon as you dismiss the card, full speed resumes instantly.
Forced Spawns — _forceSpawnMaya(type, x, y)
Some tutorial steps require specific entities to appear — a naama (ॐ) to collect, a specific Maya type to encounter. Random spawning can't be trusted for this.
A new method was added to KarmaMixin in karma.js:
_forceSpawnMaya(type, x, y) {
// Deterministic pool slot allocation — no random, no push/splice
for (let i = 0; i < this.mayaPool.length; i++) {
if (!this.mayaPool[i].active) {
// assign type + position directly
break;
}
}
}
Enter fullscreen mode Exit fullscreen mode
It follows the same fixed-size object pool pattern used everywhere in the engine — no heap allocation, no GC pressure.
The 5 Steps
| Step | What You Do | Shaastra |
|---|---|---|
| 1 | Move your Pankhudi (सारथी) | "उद्धरेदात्मनात्मानं" — Gita 6.5 |
| 2 | Collect a Naama (ॐ) | "मायाजालमिदं विश्वं" — Yogavasishtha |
| 3 | Perform Naama-Jaap | "नाम जपत मंगल" — Ramcharitmanas |
| 4 | Enter the Bhakti-Maarg | "भक्त्या मामभिजानाति" — Gita 18.55 |
| 5 | Learn about Prarabdha | "भोगेन क्षीयते पापं" — Skanda Purana |
Each card shows the relevant Sanskrit shloka with attribution — scripture style, not tooltip style. The last step is information-only (Prarabdha cannot be "completed," only endured — which is the point).
Scripture-Style Card Rendering
drawTutorialCard() in render.js renders a full overlay card:
- Dark semi-transparent backdrop (game remains visible beneath)
- Saffron accent line at the top
- Gold 🕉️ header
- Sanskrit shloka in italic serif
- Source attribution (Gita, Upanishad, Purana)
- Task text with multi-line support
- Dismiss button: ENTER / TAP / Gamepad START
- ESC skips the entire initiation
The card is visually distinct from the existing alert system — bigger, centered, designed to be read slowly.
Persistence
Once completed or skipped, localStorage records it:
localStorage.setItem('moksha_tutorial_seen', '1');
Enter fullscreen mode Exit fullscreen mode
The tutorial never shows again. Players who know what they're doing aren't forced to sit through it.
What This Closes
This implementation resolves Issue #37 and supersedes the earlier attempt in Issue #30. The checklist from the issue spec:
- ✅
src/tutorial.js— TutorialManager - ✅ Slow-motion
dt × 0.3(notisPaused) - ✅
_forceSpawnMaya(type, x, y)inkarma.js - ✅ Scripture-style dismissible card in
render.js - ✅
localStoragepersistence - ✅ ESC to skip
- ✅ ENTER / click / Gamepad START to dismiss
- ✅ Engine fully decoupled —
engine.jsuntouched
Commit:
https://github.com/weirdcodesofficial/MOKSHA/commit/dca7f3e13d654644d61231233002b4e851bd42ac
What's Next
The tutorial lays the foundation for v0.1.0 — Pankhudi Directional Mechanics, where active pankhudi direction will drive power shoot, Maya pull, and Indriya pull. That's a significant gameplay overhaul and deserves its own devlog when the time comes.
For now — if you've played Moksha before and found it confusing, try it again. The Guru is waiting.
Moksha is a solo-developed browser game rooted in Sanatan Shastra.
Play it at weirdcodes.itch.io/moksha
Support the project at ko-fi.com/weirdcodes
0 Comments
Log in to join the conversation.No comments yet. Be the first to share your thoughts.