DEV Community

Cover image for How I Refactored My Developer Portfolio Into a Modular, Secure, and Playfully Destructive Playground (v1.1.0)
freerave
freerave

Posted on

How I Refactored My Developer Portfolio Into a Modular, Secure, and Playfully Destructive Playground (v1.1.0)

A deep dive into refactoring a 1500+ line JS monolith into elegant ES6 modules, boosting performance by 95%, fixing XSS vectors, and adding a treacherous text-based game easter egg.

A developer's portfolio is more than just a resumeโ€”it is a playground. When I built dotUniverse, a cyberpunk-themed portfolio simulating a Kali Linux terminal, it quickly grew into a massive playground. But like many rapid prototypes, it eventually hit a wall: a 1500+ line monolithic script.js file, performance lag on mobile, security warnings, and missing interactive elements.

In this article, I will walk you through how I completed a 1.1.0 Modular Refactor, boosting performance by 95%, hardening security, and adding a highly engaging (and slightly treacherous) easter egg game that lets users "destroy" and restore the site.


๐Ÿ› ๏ธ The Architecture: Breaking the Monolith

Originally, the terminal commands, particle physics, scrolling, and UI triggers lived in a single script. I refactored this into clean, scoped ES6 Modules managed by a single entry point:

js/
โ”œโ”€โ”€ app.js                      # Entry point (initializes modules & defines commands)
โ””โ”€โ”€ modules/
    โ”œโ”€โ”€ particle-system.js       # Custom canvas particles + spatial grid optimization
    โ”œโ”€โ”€ math-eval.js             # Safe mathematical parser (No eval/new Function)
    โ”œโ”€โ”€ terminal-emulator.js     # CLI input handling & tab-completion state
    โ”œโ”€โ”€ challenges.js            # Challenge progress tracking
    โ”œโ”€โ”€ scroll-effects.js        # Lazy-loading scroll reveals
    โ””โ”€โ”€ theme-manager.js         # Color theme manager
Enter fullscreen mode Exit fullscreen mode

VS Code Folder Structure of ES6 modules

The Terminal State Controller

To allow interactive sub-prompts (like confirmations or games), I introduced a promptHook mechanism in the terminal. When a command sets promptHook, all subsequent keypresses are redirected to that function instead of being parsed as new terminal commands.

Here is the key logic in terminal-emulator.js:

// Inside TerminalEmulator
async executeCommand() {
  const cmd = this.state.inputEl.value.trim();
  this.state.inputEl.value = '';

  if(!cmd) return;

  this.addPromptLine(cmd);
  this.state.history.push(cmd);
  this.state.histIdx = this.state.history.length;

  // Intercept input if an active game/prompt hook is set
  if (this.state.promptHook) {
    await this.state.promptHook(cmd);
    return;
  }

  const parts = cmd.split(/\s+/);
  const command = parts[0].toLowerCase();
  const args = cmd.slice(command.length).trim();

  if(this.COMMANDS[command]) {
    await this.COMMANDS[command].call(this, args);
  } else {
    this.addLine(`  <span class="t-error">Error: ${command}: command not found</span>`);
    this.addLine('');
  }
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ”’ Hardening Security: Banishing new Function

The terminal calculator (calc) originally used new Function() to execute math operations. While convenient, parsing unsanitized input is a dangerous vector for Cross-Site Scripting (XSS).

I replaced it with a safe evaluation parsing engine in math-eval.js using strict whitelist validation:

// Whitelist pattern allowing numbers, basic math operators, parentheses, and letters
if(!/^[\d\s+\-*/%().^a-zA-Z]*$/.test(expr)) {
  throw new Error('Invalid characters');
}
Enter fullscreen mode Exit fullscreen mode

โšก Performance: 95% CPU Savings

Rendering dozens of floating particles that connect with lines is notoriously heavy. An $O(n^2)$ double-loop checking distances between every particle leads to massive lag at 60 FPS.

I implemented a Spatial Grid Algorithm in particle-system.js:

  1. The canvas is divided into grid cells of 150px.
  2. Each particle is registered in its corresponding cell.
  3. Instead of checking against all particles, a particle only checks the 9 cells surrounding it.

This optimized the complexity from a heavy $O(n^2)$ to an average of $O(n)$ using a Spatial Grid (specifically $O(n \cdot k)$ where $k$ is the average number of particles in neighboring cells).

Additionally, I integrated Mobile Optimizations:

  • Touch Device Detection: Automatically halves the particle count.
  • FPS Cap: Capped mobile frames at 30 FPS instead of 60 FPS, reducing CPU usage by over 90% while keeping animations smooth.

Particle System Connected Nodes Background


๐ŸŽฎ The Fun Part: The Quantum Root Key Betrayal

In Kali Linux, typing rm -rf / --no-preserve-root is the ultimate destructive command. To pay homage to this, I built an interactive easter egg game called game.

The Set Up

When the user types game, they enter the "Quantum Key" mini-game. The terminal generates a secret number between 1 and 100 and gives them 3 attempts to guess it, providing Too high ๐Ÿ‘† or Too low ๐Ÿ‘‡ feedback.

The Betrayal

No matter what happens, the game is rigged to betray them:

  • If they lose: Access is denied, and the system executes rm -rf / --no-preserve-root as a penalty.
  • If they win: It announces success, loads reward.exe... and then triggers a fake XSS exploit, executing rm -rf / --no-preserve-root anyway!

CLI Guess the Number Game and Purge sequence

Here is the implementation inside app.js:

// game command definition in app.js
game: () => {
  T.addLine('');
  T.addLine('  <span class="t-accent2">๐ŸŽฎ  MINIGAME: GUESS THE SECRET NUMBER  ๐ŸŽฎ</span>');
  T.addLine('  <span class="t-info">I have chosen a secret number between 1 and 100.</span>');
  T.addLine('  <span class="t-info">You have 3 attempts to guess it. Good luck!</span>');
  T.addLine('');
  T.addLine('  <span class="t-prompt">Enter your first guess [1-100]:</span>');
  T.addLine('');

  const targetNum = Math.floor(Math.random() * 100) + 1;
  let attempts = 3;

  T.state.promptHook = async (input) => {
    const guess = parseInt(input.trim(), 10);
    if (isNaN(guess) || guess < 1 || guess > 100) {
      T.addLine('  <span class="t-error">โœ– Invalid input! Please enter a number between 1 and 100:</span>');
      T.addLine('');
      return;
    }

    if (guess === targetNum) {
      T.state.promptHook = null;
      T.addLine(`  <span class="t-success">๐ŸŽ‰ CORRECT! The secret number was indeed ${targetNum}!</span>`);
      T.addLine('  <span class="t-info">Loading your reward.exe...</span>');
      await sleep(1000);
      T.addLine('  <span class="t-error">โš ๏ธ  ERROR: Unexpected token in reward.exe!</span>');
      await sleep(500);
      T.addLine('  <span class="t-error">Wait, what is this...? Root payload detected: rm -rf /</span>');
      await sleep(500);
      T.addLine('  <span class="t-accent2">Pranked! Total betrayal! ๐Ÿ˜‚ Execute self-destruction:</span>');
      T.addLine('');
      triggerPurge();
    } else {
      attempts--;
      if (attempts > 0) {
        const hint = guess < targetNum ? 'Too low ๐Ÿ‘‡' : 'Too high ๐Ÿ‘†';
        T.addLine(`  <span class="t-error">โŒ Incorrect! ${guess} is ${hint}.</span>`);
        T.addLine(`  <span class="t-accent2">${attempts} attempt(s) remaining. Enter guess:</span>`);
        T.addLine('');
      } else {
        T.state.promptHook = null;
        T.addLine(`  <span class="t-error">โŒ GAME OVER! The secret number was ${targetNum}.</span>`);
        T.addLine('  <span class="t-info">Penalty authorized: rm -rf /hope --no-preserve-root</span>');
        T.addLine('  <span class="t-error">Executing purge... ๐Ÿ’€</span>');
        T.addLine('');
        triggerPurge();
      }
    }
  };

  function triggerPurge() {
    const errors = [
      'removing /tools/DotGhostBoard... <span class="t-error">โœ– GONE</span>',
      'removing /tools/dotcommand...    <span class="t-error">โœ– GONE</span>',
      'removing /tools/CodeTune...      <span class="t-error">โœ– GONE</span>',
      'removing /platforms/dev.to...    <span class="t-error">โœ– GONE</span>',
      'removing /stats/followers...     <span class="t-error">โœ– GONE</span>',
      '', '<span class="t-error">๐Ÿ’€ FATAL: filesystem destroyed</span>',
      '<span class="t-error">๐Ÿ’€ FATAL: career.exe has stopped working</span>',
      '<span class="t-dim">Segmentation fault (core dumped)</span>',
    ];
    let i = 0;
    const iv = setInterval(() => {
      if (i < errors.length) { T.addLine('  ' + errors[i++]); }
      else {
        clearInterval(iv);
        setTimeout(() => { if (window.triggerDestruction) window.triggerDestruction(); }, 400);
      }
    }, 80);
  }
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ’ป The Ultimate Failsafe: Reverting via git reverse

Once the purge executes:

  1. All elements on the screen collapse, slide off, and blur out.
  2. The Blue Screen of Death (BSOD) prints simulated deletion logs and counts to 100%.
  3. The Raw HTML Failsafe: The page transitions into a completely blank white screen showing a raw, unstyled HTML page.
    • Standard default black text.
    • Times New Roman font.
    • <h1>Hello World</h1> header.
    • A basic browser <textarea> and <button> with absolutely no CSS.
  4. To fix the system, the user is required to write git reverse in the text area. (Note for the Git purists: yes, in real Git we use git restore or git revert. But in this hacker-themed scenario, typing git reverse felt like the perfect theatrical command to undo the payload).

Raw Hello World HTML Page without CSS

  1. Entering the command triggers a dark progress bar showing the git status restoration from 0% to 100%, rebuilding all project files and restoring the site layout.

Restoring Environment Progress Bar

Here is the raw HTML restoration flow implemented in script.js:

function showBlankScreen() {
  const blank = document.createElement('div');
  blank.id = 'blankScreen';
  blank.style.cssText = `
    position: fixed; inset: 0; background: white; color: black;
    z-index: 99999; padding: 50px; overflow: auto; text-align: left;
    font-family: 'Times New Roman', Times, serif;
  `;
  blank.innerHTML = `
    <h1>Hello World</h1>
    <p>Index of /</p>
    <hr>
    <p>The server has encountered a critical failure. All active resources have been unlinked.</p>
    <p>To reverse this action and restore the system to its last commit, please type the recovery command below and press Enter.</p>
    <div style="margin-top: 20px;">
      <textarea id="recoveryTextArea" rows="4" cols="50" placeholder="Type command here..." style="all: revert; font-family: monospace; font-size: 14px; width: 100%; max-width: 500px; padding: 5px;"></textarea>
      <br><br>
      <button id="recoveryBtn" style="all: revert; cursor: pointer; padding: 5px 15px;">Execute Command</button>
      <p id="recoveryError" style="color: red; font-weight: bold; margin-top: 10px; display: none;">Invalid recovery command!</p>
    </div>
  `;
  document.body.appendChild(blank);

  const ta = document.getElementById('recoveryTextArea');
  const btn = document.getElementById('recoveryBtn');
  const err = document.getElementById('recoveryError');

  ta.focus();

  const handleRecovery = () => {
    const val = ta.value.trim().toLowerCase();
    if (val === 'git reverse') {
      blank.remove();
      runSystemRestoredProgress();
    } else {
      err.style.display = 'block';
      ta.value = '';
      ta.focus();
    }
  };

  btn.addEventListener('click', handleRecovery);
  ta.addEventListener('keydown', (e) => {
    if (e.key === 'Enter') {
      e.preventDefault();
      handleRecovery();
    }
  });
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ“ˆ Summary of Improvements

Metric Before Refactor (v1.0.0) After Refactor (v1.1.0) Benefit
JS File Size 1500+ line Monolith Modular ES6 Files Easy maintenance and debugging
Particle Physics $O(n^2)$ complexity Average of $O(n)$ Spatial Grid 95% CPU savings
Mobile Refresh Rate Uncapped 60 FPS (heavy CPU lag) Capped at 30 FPS + 50% particles Smooth experience, low battery drain
Security Risk High XSS risk via new Function Mitigated (strict whitelist parsing) Zero code execution vulnerability
Interactive Easter Eggs Static logs Rigged game + git reverse prompt Unforgettable user experience ๐ŸŽฎ

Conclusion

Refactoring doesn't have to be boring. By restructuring the codebase of dotUniverse into modular pieces, we didn't just gain a massive performance speedup and security hardeningโ€”we opened up the architecture to support complex interactive behaviors. Adding this easter egg turned a static portfolio page into a memorable, interactive game that web developers can love.

What is your favorite terminal easter egg? Let me know in the comments below! ๐Ÿš€

Top comments (0)