Hi everyone! It's Creator X here. I wanted to share my experience transitioning my cyberpunk RPG Black Market Protocol from Ink.js to Phaser.js, and the technical challenges I faced along the way.
Why I Migrated from Ink.js
When I started Black Market Protocol, Ink.js seemed perfect for a text-based narrative game. But as the game grew more complex, I hit some major limitations:
The Function Integration Problem: Every game mechanic required:
- An Ink function in the story file
- A JavaScript bridge function
- Manual state synchronization between both
This worked fine for simple story choices, but became a nightmare when trying to implement complex systems like dynamic combat, inventory management, and realistic hacking mechanics. As the story progressed deeper, managing these connections became exponentially harder.
Challenge 1: From Quiz to Real Hacking Simulation
The Ink.js Approach: Simple but Static
Here's what my hacking terminal looked like in Ink.js this was using inky as the base:
=== enhancement_app ===
QuickHack 101 module. Pattern: 1, 4, 7, ?
* [Enter 10]
# notification: Pattern Matched!
Pattern matched! Hacking skills improved.
~ hacking += 2
-> docks
* [Enter 7]
# notification: Incorrect Pattern
Basic training completed.
~ hacking += 1
-> docks
* [Skip Training]
# notification: Skipping Training...
~ hacking += 1
-> docks
And the JavaScript side:
function handleSubmitPattern() {
const answer = patternAnswerInput.value.trim();
let choiceTextToSelect = null;
if (answer === '10') {
hackResultDiv.innerHTML = '<p class="success">Pattern matched! Hacking skills improved significantly.</p>';
choiceTextToSelect = "APP_HACKING_CORRECT";
playSoundEffect("app_success");
} else {
hackResultDiv.innerHTML = '<p class="failure">Incorrect pattern. Basic training completed.</p>';
choiceTextToSelect = "APP_HACKING_INCORRECT";
playSoundEffect("app_fail");
}
}
The Problem: This was just a quiz with predetermined outcomes. Players quickly realized they weren't actually "hacking" anything - just answering pattern questions.
The Phaser.js Solution: Dynamic Defense Systems
Now I have real-time defensive monitoring:
startDefenseMonitoring() {
// Simulate defensive systems monitoring and responding
setInterval(() => {
if (this.currentSystem !== 'local' && this.systems[this.currentSystem].aiDefense) {
this.processDefensiveActions();
}
}, 3000 + Math.random() * 5000); // Random intervals to keep it unpredictable
}
And actual counter-attack consequences:
resolveCounterAttack(system) {
const severity = system.defenseLevel / 100;
if (Math.random() < severity) {
// Counter-attack succeeded
this.printLine('COUNTER-ATTACK SUCCESSFUL! Severe consequences:', 'error');
this.stealth = Math.max(0, this.stealth - 30);
this.skill = Math.max(0, this.skill - 10);
this.credits = Math.max(0, this.credits - 50);
if (this.stealth <= 0) {
this.printLine('CRITICAL: Complete stealth failure! Force disconnecting...', 'error');
setTimeout(() => {
this.forceDisconnect();
}, 2000);
}
}
}
Now players face real stakes based on their tech abilities, the target's defense systems, and their own stealth management.
Challenge 2: Building Interconnected Systems
The Stats Foundation
In Ink.js, stats were just numbers that incremented. In Phaser.js, they drive actual gameplay mechanics:
// Character Stats - everyone starts at zero
stats: {
giftOfGab: 0, // Talking, charm, manipulation (0-100)
charisma: 0, // General influence and perception (0-100)
fightingAura: 0, // Physical presence, intimidation (0-100)
streetKnowledge: 0, // Understanding streets, spotting scams (0-100)
reputation: 0, // How the world views Cipher (0-100)
health: 100, // Physical wellbeing (0-100)
stamina: 100, // Daily action capacity (0-100)
tech: 0 // Digital skills, hacking ability (0-100)
}
The key insight: Your tech stat directly affects your hacking stealth ability. Starting at zero means every stat point you earn has real mechanical impact.
Equipment-Gated Progression
I couldn't create meaningful equipment systems in Ink.js. Now I have:
this.equipmentCosts = {
'Basic Laptop': { cost: 1500, description: 'Unlocks basic hacking jobs (5 new jobs)' },
'Encrypted Router': { cost: 2800, description: 'Unlocks data theft jobs (7 new jobs)' }
};
This creates a progression loop: Stats → Equipment Access → Job Availability → Better Pay → Better Equipment.
Challenge 3: Preventing Exploitation with Smart Gating
To prevent players from grinding high-level jobs immediately, I implemented multi-layered requirements:
// Initialize available jobs based on current stats and equipment
this.updateAvailableJobs(); // Matches your stats against job requirements
Players need both the right equipment AND sufficient stats to access higher-paying jobs. Plus, the AI defense system scales with the target - some companies are just inherently harder to hack regardless of your abilities.
The Results
The migration was challenging, but worth it. I went from a simple choose-your-own-adventure with fake progression to a complex cyberpunk job market simulator with:
- Real consequences for player actions
- Interconnected systems where stats, equipment, and jobs all affect each other
- Dynamic opposition that responds to player behavior
- Meaningful progression that can't be easily exploited
The Phaser.js framework gave me the flexibility to build the complex, interconnected systems that Ink.js simply couldn't handle elegantly.
What's Next
I'm still refining the counter-attack defense system and plan to add more sophisticated AI behavior based on different corporation types. The demo is live now if you want to experience these systems firsthand!
You can check out the updated Black Market Protocol demo at: https://creator-xi.itch.io/the-black-market-protocol
What challenges have you faced when outgrowing a framework? I'd love to hear about your migration experiences!
Black Market Protocol is a cyberpunk text-based RPG focusing on realistic hacking mechanics and meaningful player progression. Follow the development journey for more technical deep-dives like this one.
Top comments (0)