Remove legacy lockpicking minigame files: Deleted lockpicking-comparison.html and lockpicking-game.js, along with associated CSS styles in lockpicking.css. Updated minigames index to only include the Phaser version of the lockpicking minigame, ensuring a cleaner codebase and improved maintainability. Added new lockpick feedback styling in minigames-framework.css for enhanced user experience.

This commit is contained in:
Z. Cliffe Schreuders
2025-08-12 16:37:41 +01:00
parent daf3491bc8
commit 38c2a0476f
6 changed files with 34 additions and 1037 deletions

View File

@@ -1,515 +0,0 @@
/* Lockpicking Minigame Styles */
/* Override header positioning for lockpicking */
.minigame-header {
position: relative !important;
background: rgba(34, 34, 34, 0.95);
padding: 10px 20px;
margin-bottom: 20px;
border-radius: 5px;
}
.minigame-header h3 {
font-family: 'Press Start 2P', monospace;
font-size: 16px;
margin: 0 0 10px 0;
}
.minigame-header p {
font-family: 'VT323', monospace;
font-size: 18px;
margin: 0;
}
.lock-visual {
display: flex;
justify-content: space-evenly;
align-items: center;
gap: 20px;
height: 300px; /* Taller for better visibility */
background: #f0e6a6; /* Light yellow/beige background */
border-radius: 5px;
padding: 25px;
position: relative;
margin: 20px auto; /* Center and add margins */
border: 2px solid #887722;
max-width: 800px; /* Reasonable maximum width */
width: 90%; /* Responsive width */
}
.pin {
width: 40px;
height: 200px; /* Taller to match container */
position: relative;
background: transparent;
border-radius: 4px 4px 0 0;
overflow: visible;
cursor: pointer;
transition: transform 0.1s;
margin: 0 15px;
}
.pin:hover {
opacity: 0.9;
}
.shear-line {
position: absolute;
width: 100%;
height: 2px;
background: #aa8833;
bottom: 60px; /* Match driver pin starting position */
z-index: 5;
}
.key-pin {
position: absolute;
bottom: 0;
width: 100%;
height: 0px; /* Start at 0px, grows dynamically via JavaScript */
background: #dd3333; /* Red for key pins */
border-radius: 0 0 0 0;
clip-path: polygon(0 0, 100% 0, 100% 70%, 50% 100%, 0 70%); /* Pointed bottom */
transition: height 0.1s ease; /* Smooth height animation */
}
.driver-pin {
position: absolute;
width: 100%;
height: 40px; /* Smaller height for better proportion */
background: #3388dd; /* Blue for driver pins */
bottom: 60px; /* Start at shear line level */
border-radius: 4px 4px 0 0;
transition: bottom 0.1s ease, background-color 0.3s;
}
.spring {
position: absolute;
bottom: 100px; /* Positioned above driver pin */
width: 100%;
height: 30px;
background: repeating-linear-gradient(
to bottom,
#cccccc 0px,
#cccccc 2px,
#999999 2px,
#999999 4px
);
transition: transform 0.1s ease;
}
.pin.binding {
box-shadow: 0 0 8px 2px #ffcc00;
}
/* Keep driver pin (blue) above the shear line when set */
.pin.set .driver-pin {
background: #22aa22; /* Green to indicate set */
}
/* Key pin turns green when set */
.pin.set .key-pin {
background: #22aa22; /* Green to indicate set */
}
.cylinder {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 30px;
background: #ddbb77;
border-radius: 5px;
margin-top: 5px;
position: relative;
z-index: 0;
border: 2px solid #887722;
}
.cylinder-inner {
width: 80%;
height: 20px;
background: #ccaa66;
border-radius: 3px;
transform-origin: center;
transition: transform 0.3s;
}
.cylinder.rotated .cylinder-inner {
transform: rotate(15deg);
}
.lockpick-feedback {
padding: 15px;
background: #333;
border-radius: 5px;
text-align: center;
min-height: 30px;
margin-top: 20px;
font-family: 'VT323', monospace;
font-size: 18px;
}
.tension-control {
display: grid;
grid-template-columns: auto 1fr;
gap: 20px;
align-items: center;
background: #333;
padding: 20px;
border-radius: 5px;
margin-top: 20px;
}
.tension-wrench-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
position: relative;
width: 150px;
height: 60px;
}
.tension-track {
width: 100%;
height: 10px;
background: #444;
border-radius: 5px;
position: relative;
overflow: hidden;
}
.tension-progress {
position: absolute;
height: 100%;
width: 0%;
background: linear-gradient(to right, #666, #2196F3);
transition: width 0.3s;
}
.tension-status {
font-size: 16px;
text-align: left;
padding-left: 10px;
}
.tension-wrench {
width: 60px;
height: 40px;
background: #666;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: transform 0.3s, background-color 0.3s;
position: absolute;
left: 0;
top: 20px;
z-index: 2;
box-shadow: 0 2px 5px rgba(0,0,0,0.3);
}
.tension-wrench:hover {
background: #777;
}
.tension-wrench.active {
background: #2196F3;
}
.wrench-handle {
width: 60%;
height: 10px;
background: #999;
position: absolute;
}
.wrench-tip {
width: 20px;
height: 30px;
background: #999;
position: absolute;
left: 5px;
}
.instructions {
text-align: center;
margin-bottom: 10px;
font-size: 12px;
color: #ccc;
}
/* General success/failure message styles */
.lockpicking-success-message {
font-weight: bold;
font-size: 18px;
margin-bottom: 10px;
color: #2ecc71;
}
.lockpicking-success-subtitle {
font-size: 14px;
margin-bottom: 15px;
color: #fff;
}
.lockpicking-success-details {
font-size: 12px;
color: #aaa;
}
.lockpicking-failure-message {
font-weight: bold;
margin-bottom: 10px;
color: #e74c3c;
}
.lockpicking-failure-subtitle {
font-size: 16px;
margin-top: 5px;
color: #fff;
}
.tension-control {
display: grid;
grid-template-columns: auto 1fr;
gap: 20px;
align-items: center;
background: #333;
padding: 20px;
border-radius: 5px;
margin-top: 20px;
}
.tension-wrench-container {
display: flex;
flex-direction: column;
align-items: center;
gap: 10px;
position: relative;
width: 150px;
height: 60px;
}
.tension-track {
width: 100%;
height: 10px;
background: #444;
border-radius: 5px;
position: relative;
overflow: hidden;
}
.tension-progress {
position: absolute;
height: 100%;
width: 0%;
background: linear-gradient(to right, #666, #2196F3);
transition: width 0.3s;
}
.tension-status {
font-size: 16px;
text-align: left;
padding-left: 10px;
}
.tension-wrench {
width: 60px;
height: 40px;
background: #666;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: transform 0.3s, background-color 0.3s;
position: absolute;
left: 0;
top: 20px;
z-index: 2;
box-shadow: 0 2px 5px rgba(0,0,0,0.3);
}
.tension-wrench:hover {
background: #777;
}
.tension-wrench.active {
background: #2196F3;
}
.wrench-handle {
width: 60%;
height: 10px;
background: #999;
position: absolute;
}
.wrench-tip {
width: 20px;
height: 30px;
background: #999;
position: absolute;
left: 5px;
}
.cylinder {
height: 20px;
margin-top: -5px;
}
.lock-visual {
display: flex;
justify-content: space-evenly;
align-items: center;
gap: 10px;
height: 160px;
background: #f0e6a6; /* Light yellow/beige background */
border-radius: 5px;
padding: 15px;
position: relative;
margin-bottom: 10px;
border: 2px solid #887722;
}
.pin {
width: 30px;
height: 110px;
position: relative;
background: transparent;
border-radius: 4px 4px 0 0;
overflow: visible;
cursor: pointer;
transition: transform 0.1s;
margin: 0 5px;
}
.pin:hover {
opacity: 0.9;
}
.shear-line {
position: absolute;
width: 100%;
height: 2px;
background: #aa8833;
bottom: 50px;
z-index: 5;
}
.key-pin {
position: absolute;
bottom: 0;
width: 100%;
height: 0px;
background: #dd3333; /* Red for key pins */
transition: height 0.05s;
border-radius: 0 0 0 0;
clip-path: polygon(0 0, 100% 0, 100% 70%, 50% 100%, 0 70%); /* Pointed bottom */
}
.driver-pin {
position: absolute;
width: 100%;
height: 50px;
background: #3388dd; /* Blue for driver pins */
transition: bottom 0.05s;
bottom: 50px;
border-radius: 0 0 0 0;
}
.spring {
position: absolute;
bottom: 100px;
width: 100%;
height: 25px;
background: linear-gradient(to bottom,
#cccccc 0%, #cccccc 20%,
#999999 20%, #999999 25%,
#cccccc 25%, #cccccc 40%,
#999999 40%, #999999 45%,
#cccccc 45%, #cccccc 60%,
#999999 60%, #999999 65%,
#cccccc 65%, #cccccc 80%,
#999999 80%, #999999 85%,
#cccccc 85%, #cccccc 100%
);
transition: height 0.05s;
}
.pin.binding {
box-shadow: 0 0 8px 2px #ffcc00;
}
.pin.set .driver-pin {
bottom: 52px; /* Just above shear line */
background: #22aa22; /* Green to indicate set */
}
.pin.set .key-pin {
height: 49px; /* Just below shear line */
background: #22aa22; /* Green to indicate set */
clip-path: polygon(0 0, 100% 0, 100% 70%, 50% 100%, 0 70%);
}
.cylinder {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 30px;
background: #ddbb77;
border-radius: 5px;
margin-top: 5px;
position: relative;
z-index: 0;
border: 2px solid #887722;
}
.cylinder-inner {
width: 80%;
height: 20px;
background: #ccaa66;
border-radius: 3px;
transform-origin: center;
transition: transform 0.3s;
}
.cylinder.rotated .cylinder-inner {
transform: rotate(15deg);
}
.lockpick-feedback {
padding: 15px;
background: #333;
border-radius: 5px;
text-align: center;
min-height: 30px;
margin-top: 20px;
font-family: 'VT323', monospace;
font-size: 18px;
}
/* Phaser-specific styles */
.phaser-game-container {
width: 100%;
height: 400px;
background: #1a1a1a;
border-radius: 5px;
margin: 20px 0;
display: flex;
justify-content: center;
align-items: center;
border: 2px solid #444;
}
.phaser-game-container canvas {
border-radius: 5px;
max-width: 100%;
max-height: 100%;
}

View File

@@ -42,13 +42,13 @@
.minigame-game-container {
width: 80%;
max-width: 600px;
height: 60%;
height: 55%;
margin: 20px auto;
background: #1a1a1a;
border-radius: 5px;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.5) inset;
position: relative;
overflow: hidden;
overflow: visible;
}
.minigame-message-container {
@@ -192,3 +192,31 @@
transition: width 0.3s ease;
border-radius: 5px;
}
/* Lockpicking feedback styling */
.lockpick-feedback {
background: rgba(0, 0, 0, 0.8);
color: #00ff00;
padding: 10px 15px;
border-radius: 5px;
margin: 10px 0;
font-family: 'VT323', monospace;
font-size: 16px;
text-align: center;
border: 1px solid #00ff00;
min-height: 20px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 0 10px rgba(0, 255, 0, 0.3);
position: relative;
z-index: 1000;
width: 100%;
max-width: 600px;
margin-left: auto;
margin-right: auto;
}
.lockpick-feedback:empty {
display: none;
}

View File

@@ -3,13 +3,11 @@ export { MinigameFramework } from './framework/minigame-manager.js';
export { MinigameScene } from './framework/base-minigame.js';
// Export minigame implementations
export { LockpickingMinigame } from './lockpicking/lockpicking-game.js';
export { LockpickingMinigamePhaser } from './lockpicking/lockpicking-game-phaser.js';
export { DustingMinigame } from './dusting/dusting-game.js';
// Initialize the global minigame framework for backward compatibility
import { MinigameFramework } from './framework/minigame-manager.js';
import { LockpickingMinigame } from './lockpicking/lockpicking-game.js';
import { LockpickingMinigamePhaser } from './lockpicking/lockpicking-game-phaser.js';
// Make the framework available globally
@@ -20,6 +18,5 @@ import { DustingMinigame } from './dusting/dusting-game.js';
// Register minigames
MinigameFramework.registerScene('lockpicking', LockpickingMinigamePhaser); // Use Phaser version as default
MinigameFramework.registerScene('lockpicking-legacy', LockpickingMinigame); // Keep old version for backward compatibility
MinigameFramework.registerScene('lockpicking-phaser', LockpickingMinigamePhaser); // Keep explicit phaser name
MinigameFramework.registerScene('dusting', DustingMinigame);

View File

@@ -1,14 +1,5 @@
import { MinigameScene } from '../framework/base-minigame.js';
// Load lockpicking-specific CSS
const lockpickingCSS = document.createElement('link');
lockpickingCSS.rel = 'stylesheet';
lockpickingCSS.href = 'css/lockpicking.css';
lockpickingCSS.id = 'lockpicking-css';
if (!document.getElementById('lockpicking-css')) {
document.head.appendChild(lockpickingCSS);
}
// Phaser Lockpicking Minigame Scene implementation
export class LockpickingMinigamePhaser extends MinigameScene {
constructor(container, params) {
@@ -130,10 +121,12 @@ export class LockpickingMinigamePhaser extends MinigameScene {
// Create a container for the Phaser game
this.gameContainer.innerHTML = `
<div class="phaser-game-container" id="phaser-game-container"></div>
<div class="lockpick-feedback"></div>
`;
this.feedback = this.gameContainer.querySelector('.lockpick-feedback');
// Create feedback element in the minigame container
this.feedback = document.createElement('div');
this.feedback.className = 'lockpick-feedback';
this.gameContainer.appendChild(this.feedback);
console.log('Setting up Phaser game...');

View File

@@ -1,278 +0,0 @@
import { MinigameScene } from '../framework/base-minigame.js';
// Load lockpicking-specific CSS
const lockpickingCSS = document.createElement('link');
lockpickingCSS.rel = 'stylesheet';
lockpickingCSS.href = 'css/lockpicking.css';
lockpickingCSS.id = 'lockpicking-css';
if (!document.getElementById('lockpicking-css')) {
document.head.appendChild(lockpickingCSS);
}
// Lockpicking Minigame Scene implementation
export class LockpickingMinigame extends MinigameScene {
constructor(container, params) {
super(container, params);
this.lockable = params.lockable;
this.difficulty = params.difficulty || 'medium';
this.pinCount = this.difficulty === 'easy' ? 3 : this.difficulty === 'medium' ? 4 : 5;
this.pins = [];
this.lockState = {
tensionApplied: false,
pinsSet: 0,
currentPin: null
};
}
init() {
super.init();
this.headerElement.innerHTML = `
<h3>Lockpicking</h3>
<p>Apply tension and hold click on pins to lift them to the shear line</p>
`;
this.setupLockpickingInterface();
this.createPins();
this.updateFeedback("Apply tension first, then click and hold on pins to lift them");
}
setupLockpickingInterface() {
this.gameContainer.innerHTML = `
<div class="instructions">Apply tension first, then click and hold on pins to lift them to the shear line</div>
<div class="lock-visual">
<div class="shear-line"></div>
</div>
<div class="tension-control">
<div class="tension-wrench" id="tension-wrench"></div>
<span>Tension Wrench</span>
</div>
<div class="lockpick-feedback">Ready to pick</div>
`;
this.lockVisual = this.gameContainer.querySelector('.lock-visual');
this.feedback = this.gameContainer.querySelector('.lockpick-feedback');
// Set up tension wrench
const tensionWrench = document.getElementById('tension-wrench');
this.addEventListener(tensionWrench, 'click', () => {
this.lockState.tensionApplied = !this.lockState.tensionApplied;
tensionWrench.classList.toggle('active', this.lockState.tensionApplied);
this.updateBindingPins();
this.updateFeedback(this.lockState.tensionApplied ?
"Tension applied. Now lift pins to the shear line." :
"Apply tension first.");
});
}
createPins() {
// Create random binding order
const bindingOrder = [];
for (let i = 0; i < this.pinCount; i++) {
bindingOrder.push(i);
}
this.shuffleArray(bindingOrder);
// Create pins
for (let i = 0; i < this.pinCount; i++) {
const pin = {
index: i,
binding: bindingOrder[i],
isSet: false,
currentHeight: 0,
targetHeight: 30 + Math.random() * 30, // Random cut depth
elements: {}
};
// Create pin DOM elements
const pinElement = document.createElement('div');
pinElement.className = 'pin';
pinElement.style.order = i;
const keyPin = document.createElement('div');
keyPin.className = 'key-pin';
const driverPin = document.createElement('div');
driverPin.className = 'driver-pin';
const spring = document.createElement('div');
spring.className = 'spring';
pinElement.appendChild(keyPin);
pinElement.appendChild(driverPin);
pinElement.appendChild(spring);
pin.elements = {
container: pinElement,
keyPin: keyPin,
driverPin: driverPin,
spring: spring
};
// Add event listeners
this.addEventListener(pinElement, 'mousedown', (e) => {
e.preventDefault();
if (this.lockState.tensionApplied) {
this.lockState.currentPin = pin;
this.gameState.mouseDown = true;
this.liftPin();
}
});
this.addEventListener(document, 'mouseup', () => {
if (this.lockState.currentPin) {
this.checkPinSet(this.lockState.currentPin);
this.lockState.currentPin = null;
}
this.gameState.mouseDown = false;
});
this.lockVisual.appendChild(pinElement);
this.pins.push(pin);
}
}
liftPin() {
if (!this.lockState.currentPin || !this.gameState.mouseDown) return;
const pin = this.lockState.currentPin;
pin.currentHeight = Math.min(pin.currentHeight + 2, 80);
// Update visual
pin.elements.keyPin.style.height = `${pin.currentHeight}px`;
pin.elements.driverPin.style.bottom = `${60 + pin.currentHeight}px`;
// Check if close to shear line
const distanceToShearLine = Math.abs(pin.currentHeight - 60);
if (distanceToShearLine < 5) {
pin.elements.container.style.boxShadow = "0 0 5px #ffffff";
} else {
pin.elements.container.style.boxShadow = "";
}
if (this.gameState.mouseDown) {
requestAnimationFrame(() => this.liftPin());
}
}
checkPinSet(pin) {
const distanceToShearLine = Math.abs(pin.currentHeight - 60);
const shouldBind = this.shouldPinBind(pin);
if (distanceToShearLine < 8 && shouldBind) {
// Pin set successfully
pin.isSet = true;
pin.elements.container.classList.add('set');
this.lockState.pinsSet++;
this.updateFeedback(`Pin ${pin.index + 1} set! (${this.lockState.pinsSet}/${this.pinCount})`);
this.updateBindingPins();
if (this.lockState.pinsSet === this.pinCount) {
this.lockPickingSuccess();
}
} else if (this.lockState.tensionApplied && !shouldBind) {
// Wrong pin - reset all pins
this.resetAllPins();
this.updateFeedback("Wrong pin! All pins reset.");
} else {
// Pin falls back down
pin.currentHeight = 0;
pin.elements.keyPin.style.height = '0px';
pin.elements.driverPin.style.bottom = '60px';
pin.elements.container.style.boxShadow = "";
}
}
shouldPinBind(pin) {
if (!this.lockState.tensionApplied) return false;
// Find the next unset pin in binding order
for (let order = 0; order < this.pinCount; order++) {
const nextPin = this.pins.find(p => p.binding === order && !p.isSet);
if (nextPin) {
return pin.index === nextPin.index;
}
}
return false;
}
updateBindingPins() {
if (!this.lockState.tensionApplied) {
this.pins.forEach(pin => {
pin.elements.container.classList.remove('binding');
});
return;
}
// Find the next unset pin in binding order
for (let order = 0; order < this.pinCount; order++) {
const nextPin = this.pins.find(p => p.binding === order && !p.isSet);
if (nextPin) {
this.pins.forEach(pin => {
pin.elements.container.classList.toggle('binding', pin.index === nextPin.index);
});
return;
}
}
// All pins set
this.pins.forEach(pin => {
pin.elements.container.classList.remove('binding');
});
}
resetAllPins() {
this.pins.forEach(pin => {
if (!pin.isSet) {
pin.currentHeight = 0;
pin.elements.keyPin.style.height = '0px';
pin.elements.driverPin.style.bottom = '60px';
pin.elements.container.style.boxShadow = "";
}
});
}
updateFeedback(message) {
this.feedback.textContent = message;
}
lockPickingSuccess() {
this.gameState.isActive = false;
this.updateFeedback("Lock picked successfully!");
const successHTML = `
<div style="font-weight: bold; font-size: 18px; margin-bottom: 10px;">Lock picked successfully!</div>
<div style="font-size: 14px; margin-bottom: 15px;">All pins set at the shear line</div>
<div style="font-size: 12px; color: #aaa;">
Difficulty: ${this.difficulty.charAt(0).toUpperCase() + this.difficulty.slice(1)}<br>
Pins: ${this.pinCount}
</div>
`;
this.showSuccess(successHTML, true, 2000);
this.gameResult = { lockable: this.lockable };
}
start() {
super.start();
this.gameState.isActive = true;
this.lockState.tensionApplied = false;
this.lockState.pinsSet = 0;
this.updateProgress(0, this.pinCount);
}
complete(success) {
super.complete(success, this.gameResult);
}
shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
}

View File

@@ -1,228 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lockpicking Minigame Comparison</title>
<style>
body {
font-family: Arial, sans-serif;
background: #1a1a1a;
color: #ffffff;
margin: 0;
padding: 20px;
}
.comparison-container {
display: flex;
gap: 20px;
max-width: 1400px;
margin: 0 auto;
}
.minigame-section {
flex: 1;
background: #2a2a2a;
border-radius: 10px;
padding: 20px;
border: 2px solid #444;
}
.minigame-section h2 {
text-align: center;
margin-bottom: 20px;
color: #00ff00;
}
.minigame-container {
background: #333;
border-radius: 5px;
padding: 15px;
min-height: 500px;
}
.controls {
margin-top: 20px;
text-align: center;
}
.btn {
background: #00ff00;
color: #000;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
font-size: 14px;
margin: 5px;
}
.btn:hover {
background: #00cc00;
}
.btn:disabled {
background: #666;
cursor: not-allowed;
}
.info-panel {
background: #444;
border-radius: 5px;
padding: 15px;
margin-top: 20px;
}
.info-panel h3 {
margin-top: 0;
color: #00ff00;
}
.feature-list {
list-style: none;
padding: 0;
}
.feature-list li {
padding: 5px 0;
border-bottom: 1px solid #555;
}
.feature-list li:last-child {
border-bottom: none;
}
.feature-list .pro {
color: #00ff00;
}
.feature-list .con {
color: #ff4444;
}
.header {
text-align: center;
margin-bottom: 30px;
}
.header h1 {
color: #00ff00;
margin-bottom: 10px;
}
.header p {
color: #ccc;
font-size: 16px;
}
</style>
</head>
<body>
<div class="header">
<h1>Lockpicking Minigame Comparison</h1>
<p>Compare the original HTML/JS version with the new Phaser.js implementation</p>
</div>
<div class="comparison-container">
<div class="minigame-section">
<h2>Original HTML/JS Version</h2>
<div class="minigame-container" id="original-container">
<!-- Original minigame will be loaded here -->
</div>
<div class="controls">
<button class="btn" onclick="startOriginal()">Start Original</button>
<button class="btn" onclick="stopOriginal()">Stop</button>
</div>
<div class="info-panel">
<h3>Features</h3>
<ul class="feature-list">
<li class="pro">✓ Lightweight - no additional dependencies</li>
<li class="pro">✓ Simple DOM manipulation</li>
<li class="pro">✓ Easy to customize with CSS</li>
<li class="con">✗ Limited animation capabilities</li>
<li class="con">✗ Basic graphics rendering</li>
<li class="con">✗ Manual input handling</li>
</ul>
</div>
</div>
<div class="minigame-section">
<h2>Phaser.js Version</h2>
<div class="minigame-container" id="phaser-container">
<!-- Phaser minigame will be loaded here -->
</div>
<div class="controls">
<button class="btn" onclick="startPhaser()">Start Phaser</button>
<button class="btn" onclick="stopPhaser()">Stop</button>
</div>
<div class="info-panel">
<h3>Features</h3>
<ul class="feature-list">
<li class="pro">✓ Rich graphics and animations</li>
<li class="pro">✓ Built-in game engine features</li>
<li class="pro">✓ Professional game development tools</li>
<li class="con">✗ Larger bundle size</li>
<li class="con">✗ More complex setup</li>
<li class="con">✗ Learning curve for Phaser API</li>
</ul>
</div>
</div>
</div>
<!-- Load Phaser.js -->
<script src="https://cdn.jsdelivr.net/npm/phaser@3.60.0/dist/phaser.min.js"></script>
<!-- Load minigame framework -->
<script type="module">
import { MinigameFramework } from './js/minigames/index.js';
let originalMinigame = null;
let phaserMinigame = null;
window.startOriginal = function() {
if (originalMinigame) {
originalMinigame.cleanup();
}
const container = document.getElementById('original-container');
container.setAttribute('data-external', 'true');
originalMinigame = MinigameFramework.startMinigame('lockpicking-legacy', container, {
lockable: 'test-lock',
difficulty: 'medium'
});
};
window.stopOriginal = function() {
if (originalMinigame) {
originalMinigame.complete(false);
originalMinigame = null;
}
};
window.startPhaser = function() {
if (phaserMinigame) {
phaserMinigame.cleanup();
}
const container = document.getElementById('phaser-container');
container.setAttribute('data-external', 'true');
phaserMinigame = MinigameFramework.startMinigame('lockpicking', container, {
lockable: 'test-lock',
difficulty: 'medium'
});
};
window.stopPhaser = function() {
if (phaserMinigame) {
phaserMinigame.complete(false);
phaserMinigame = null;
}
};
// Auto-start both minigames after a short delay
setTimeout(() => {
startOriginal();
startPhaser();
}, 1000);
</script>
</body>
</html>