diff --git a/index.html b/index.html
index b4586f95f..9d4e883bd 100644
--- a/index.html
+++ b/index.html
@@ -202,6 +202,7 @@
+
diff --git a/src/game.js b/src/game.js
index 3a438463e..0afc9f933 100644
--- a/src/game.js
+++ b/src/game.js
@@ -68,7 +68,7 @@ const config = {
debug: false
}
},
- scene: [BootScene, PreloadScene, PrologueScene, EnhancedPrologueScene, UltimatePrologueScene, SystemsTestScene, TestVisualAudioScene, DemoScene, DemoSceneEnhanced, TiledTestScene, StoryScene, GameScene, UIScene, TownSquareScene],
+ scene: [BootScene, PreloadScene, IntroScene, PrologueScene, EnhancedPrologueScene, UltimatePrologueScene, SystemsTestScene, TestVisualAudioScene, DemoScene, DemoSceneEnhanced, TiledTestScene, StoryScene, GameScene, UIScene, TownSquareScene],
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH
diff --git a/src/scenes/IntroScene.js b/src/scenes/IntroScene.js
new file mode 100644
index 000000000..a425d319c
--- /dev/null
+++ b/src/scenes/IntroScene.js
@@ -0,0 +1,490 @@
+// 🎬 INTRO SEQUENCE - VERSION B (30-45 seconds Fast-Cut)
+// "From Colors to Darkness" - Kai's Amnesia Awakening
+// Created: January 10, 2026
+// Style: Style 32 Dark-Chibi Noir with ADHD energy
+
+class IntroScene extends Phaser.Scene {
+ constructor() {
+ super({ key: 'IntroScene' });
+ this.skipEnabled = false;
+ this.currentPhase = 0;
+ this.skipPrompt = null;
+ this.currentShot = null;
+ this.currentMusic = null;
+ }
+
+ preload() {
+ console.log('🎬 IntroScene: Loading assets...');
+
+ // Base path for intro shots
+ const introPath = 'assets/references/intro_shots/';
+
+ // PHASE 1: HAPPY FAMILY (5 shots)
+ this.load.image('intro_otac_longboard', introPath + 'otac_longboard_pier.png');
+ this.load.image('intro_ana_barbershop', introPath + 'ana_barbershop_dreads.png');
+ this.load.image('intro_twins_childhood', introPath + 'kai_ana_twins_childhood.png');
+ this.load.image('intro_birthday_cake', introPath + 'birthday_cake_rd.png');
+ this.load.image('intro_family_portrait', introPath + 'family_portrait_punk_complete.png');
+
+ // PHASE 2: THE COLLAPSE (4 shots)
+ this.load.image('intro_virus', introPath + 'virus_xnoir_microscope.png');
+ this.load.image('intro_zombies', introPath + 'zombie_silhouettes_panic.png');
+ this.load.image('intro_chaos', introPath + 'chaos_streets_apocalypse.png');
+ this.load.image('intro_ana_taken', introPath + 'ana_taken_military.png');
+
+ // PHASE 3: AMNESIA WAKE-UP (4 shots)
+ this.load.image('intro_bedroom', introPath + 'kai_bedroom_wakeup.png');
+ this.load.image('intro_ana_memory', introPath + 'ana_memory_flash_purple.png');
+ this.load.image('intro_gronk', introPath + 'gronk_doorway_silhouette.png');
+
+ // Optional: Audio files (placeholder paths - not loaded yet)
+ // this.load.audio('intro_music_happy', 'assets/audio/intro_happy.ogg');
+ // this.load.audio('intro_music_punk', 'assets/audio/intro_punk.ogg');
+ // this.load.audio('intro_music_ambient', 'assets/audio/intro_ambient.ogg');
+ }
+
+ create() {
+ console.log('🎬 IntroScene: Starting intro sequence...');
+
+ // Black background
+ this.cameras.main.setBackgroundColor('#000000');
+
+ // Setup input for skip
+ this.setupSkipControls();
+
+ // Enable skip after 5 seconds
+ this.time.delayedCall(5000, () => {
+ this.skipEnabled = true;
+ this.showSkipPrompt();
+ });
+
+ // Start Phase 1
+ this.playPhase1HappyFamily();
+ }
+
+ setupSkipControls() {
+ // Keyboard skip (X key or SPACE)
+ this.input.keyboard.on('keydown-X', () => this.skipIntro());
+ this.input.keyboard.on('keydown-SPACE', () => this.skipIntro());
+
+ // Mouse/touch skip (click anywhere)
+ this.input.on('pointerdown', () => {
+ if (this.skipEnabled) {
+ this.skipIntro();
+ }
+ });
+ }
+
+ showSkipPrompt() {
+ if (this.skipPrompt) return; // Already showing
+
+ const width = this.cameras.main.width;
+ const height = this.cameras.main.height;
+
+ this.skipPrompt = this.add.text(
+ width - 20,
+ height - 20,
+ '[Hold X to face reality]',
+ {
+ fontFamily: 'Courier New',
+ fontSize: '14px',
+ fill: '#00ffff',
+ stroke: '#000000',
+ strokeThickness: 2
+ }
+ );
+ this.skipPrompt.setOrigin(1, 1);
+ this.skipPrompt.setAlpha(0.7);
+ this.skipPrompt.setDepth(1000);
+
+ // Pulse animation
+ this.tweens.add({
+ targets: this.skipPrompt,
+ alpha: { from: 0.7, to: 1.0 },
+ duration: 800,
+ yoyo: true,
+ repeat: -1
+ });
+ }
+
+ skipIntro() {
+ if (!this.skipEnabled) return;
+
+ console.log('⏭️ IntroScene: Skipped by user');
+
+ // Stop all tweens and timers
+ this.tweens.killAll();
+ this.time.removeAllEvents();
+
+ // Fade to GameScene
+ this.cameras.main.fadeOut(500, 0, 0, 0);
+ this.cameras.main.once('camerafadeoutcomplete', () => {
+ this.scene.start('GameScene');
+ });
+ }
+
+ playPhase1HappyFamily() {
+ // PHASE 1: HAPPY FAMILY MEMORIES (0-15s)
+ console.log('🎬 Phase 1: Happy Family');
+ this.currentPhase = 1;
+
+ const width = this.cameras.main.width;
+ const height = this.cameras.main.height;
+
+ // Text overlay
+ const text1 = this.add.text(
+ width / 2,
+ height - 80,
+ 'Nekoč smo imeli barve...',
+ {
+ fontFamily: 'Courier New',
+ fontSize: '24px',
+ fill: '#ffffff',
+ stroke: '#00ffff',
+ strokeThickness: 1,
+ shadow: {
+ offsetX: 2,
+ offsetY: 2,
+ color: '#ff00ff',
+ blur: 5,
+ stroke: false,
+ fill: true
+ }
+ }
+ );
+ text1.setOrigin(0.5);
+ text1.setAlpha(0);
+ text1.setDepth(100);
+
+ this.tweens.add({
+ targets: text1,
+ alpha: 1,
+ duration: 1000,
+ delay: 500
+ });
+
+ // Shots sequence - fast cuts (~3s each)
+ this.showShot('intro_otac_longboard', 0, 3000, { warm: true });
+ this.showShot('intro_ana_barbershop', 3000, 6000, { warm: true });
+ this.showShot('intro_twins_childhood', 6000, 9000, { warm: true, clear: true }); // CLEAREST
+ this.showShot('intro_birthday_cake', 9000, 12000, { warm: true });
+ this.showShot('intro_family_portrait', 12000, 15000, { warm: true, freeze: true });
+
+ // Transition to Phase 2
+ this.time.delayedCall(14500, () => {
+ this.tweens.add({
+ targets: text1,
+ alpha: 0,
+ duration: 500
+ });
+ });
+
+ this.time.delayedCall(15000, () => {
+ text1.destroy();
+ this.playPhase2TheCollapse();
+ });
+ }
+
+ playPhase2TheCollapse() {
+ // PHASE 2: THE COLLAPSE (15-30s)
+ console.log('🎬 Phase 2: The Collapse');
+ this.currentPhase = 2;
+
+ const width = this.cameras.main.width;
+ const height = this.cameras.main.height;
+
+ // Text overlay
+ const text2 = this.add.text(
+ width / 2,
+ height - 80,
+ 'Potem je prišla tema...',
+ {
+ fontFamily: 'Courier New',
+ fontSize: '24px',
+ fill: '#ff0000',
+ stroke: '#00ff00',
+ strokeThickness: 2,
+ shadow: {
+ offsetX: 3,
+ offsetY: 3,
+ color: '#000000',
+ blur: 10,
+ stroke: true,
+ fill: true
+ }
+ }
+ );
+ text2.setOrigin(0.5);
+ text2.setAlpha(0);
+ text2.setDepth(100);
+
+ this.tweens.add({
+ targets: text2,
+ alpha: 1,
+ duration: 800,
+ delay: 300
+ });
+
+ // Shots sequence - faster, chaotic (~4s each)
+ this.showShot('intro_virus', 15000, 19000, { toxic: true, glitch: true });
+ this.showShot('intro_zombies', 19000, 23000, { red: true, glitch: true, strobe: true });
+ this.showShot('intro_chaos', 23000, 27000, { chaos: true });
+ this.showShot('intro_ana_taken', 27000, 30000, { blur: true, red: true });
+
+ // Add camera shake for chaos
+ this.time.delayedCall(19000, () => {
+ this.cameras.main.shake(4000, 0.005);
+ });
+
+ // Transition to Phase 3
+ this.time.delayedCall(29500, () => {
+ this.tweens.add({
+ targets: text2,
+ alpha: 0,
+ duration: 500
+ });
+ });
+
+ this.time.delayedCall(30000, () => {
+ text2.destroy();
+ this.playPhase3AmnesiaWakeUp();
+ });
+ }
+
+ playPhase3AmnesiaWakeUp() {
+ // PHASE 3: AMNESIA WAKE-UP (30-45s)
+ console.log('🎬 Phase 3: Amnesia Wake-Up');
+ this.currentPhase = 3;
+
+ const width = this.cameras.main.width;
+ const height = this.cameras.main.height;
+
+ // Screen goes black first (amnesia darkness)
+ const blackScreen = this.add.rectangle(
+ width / 2,
+ height / 2,
+ width,
+ height,
+ 0x000000
+ );
+ blackScreen.setDepth(50);
+ blackScreen.setAlpha(0);
+
+ this.tweens.add({
+ targets: blackScreen,
+ alpha: 1,
+ duration: 1000,
+ delay: 0
+ });
+
+ // Text overlays
+ const text3a = this.add.text(
+ width / 2,
+ height / 2 - 40,
+ 'In ostal sem sam...',
+ {
+ fontFamily: 'Courier New',
+ fontSize: '20px',
+ fill: '#666666',
+ stroke: '#000000',
+ strokeThickness: 2
+ }
+ );
+ text3a.setOrigin(0.5);
+ text3a.setAlpha(0);
+ text3a.setDepth(100);
+
+ const text3b = this.add.text(
+ width / 2,
+ height / 2,
+ 'z luknjo v glavi.',
+ {
+ fontFamily: 'Courier New',
+ fontSize: '20px',
+ fill: '#999999',
+ stroke: '#000000',
+ strokeThickness: 2
+ }
+ );
+ text3b.setOrigin(0.5);
+ text3b.setAlpha(0);
+ text3b.setDepth(100);
+
+ this.tweens.add({
+ targets: text3a,
+ alpha: 1,
+ duration: 1500,
+ delay: 1500
+ });
+
+ this.tweens.add({
+ targets: text3b,
+ alpha: 1,
+ duration: 1500,
+ delay: 2500
+ });
+
+ // Fade out black screen and text, show bedroom
+ this.time.delayedCall(5000, () => {
+ this.tweens.add({
+ targets: [blackScreen, text3a, text3b],
+ alpha: 0,
+ duration: 2000
+ });
+ });
+
+ // Bedroom appears
+ this.time.delayedCall(7000, () => {
+ blackScreen.destroy();
+ text3a.destroy();
+ text3b.destroy();
+ this.showShot('intro_bedroom', 37000, 40000, { fadeIn: true });
+ });
+
+ // Ana memory flash
+ this.time.delayedCall(10000, () => {
+ const flash = this.add.image(width / 2, height / 2, 'intro_ana_memory');
+ flash.setAlpha(0);
+ flash.setDepth(80);
+ flash.setScale(0.8);
+
+ this.tweens.add({
+ targets: flash,
+ alpha: 1,
+ duration: 300,
+ yoyo: true,
+ repeat: 2,
+ onComplete: () => flash.destroy()
+ });
+ });
+
+ // Gronk entrance
+ this.time.delayedCall(12000, () => {
+ this.showShot('intro_gronk', 42000, 45000, { fadeIn: true });
+ });
+
+ // Final text
+ const textFinal = this.add.text(
+ width / 2,
+ height - 100,
+ 'Moram jo najti.\nTudi če mi vzame celo življenje.',
+ {
+ fontFamily: 'Courier New',
+ fontSize: '18px',
+ fill: '#ffffff',
+ stroke: '#ff00ff',
+ strokeThickness: 1,
+ align: 'center',
+ lineSpacing: 10
+ }
+ );
+ textFinal.setOrigin(0.5);
+ textFinal.setAlpha(0);
+ textFinal.setDepth(100);
+
+ this.time.delayedCall(13000, () => {
+ this.tweens.add({
+ targets: textFinal,
+ alpha: 1,
+ duration: 2000
+ });
+ });
+
+ // Transition to GameScene
+ this.time.delayedCall(17000, () => {
+ console.log('🎬 IntroScene: Complete! Starting game...');
+ this.cameras.main.fadeOut(2000, 0, 0, 0);
+ this.cameras.main.once('camerafadeoutcomplete', () => {
+ this.scene.start('GameScene');
+ });
+ });
+ }
+
+ showShot(imageKey, startTime, endTime, options = {}) {
+ const width = this.cameras.main.width;
+ const height = this.cameras.main.height;
+ const duration = endTime - startTime;
+
+ this.time.delayedCall(startTime, () => {
+ if (this.currentShot) {
+ // Fade out previous shot
+ this.tweens.add({
+ targets: this.currentShot,
+ alpha: 0,
+ duration: 300,
+ onComplete: () => {
+ if (this.currentShot) this.currentShot.destroy();
+ }
+ });
+ }
+
+ // Create new shot
+ const shot = this.add.image(width / 2, height / 2, imageKey);
+ shot.setAlpha(options.fadeIn ? 0 : 1);
+ shot.setDepth(10);
+
+ // Scale to fit screen
+ const scaleX = width / shot.width;
+ const scaleY = height / shot.height;
+ const scale = Math.max(scaleX, scaleY);
+ shot.setScale(scale);
+
+ this.currentShot = shot;
+
+ // Apply visual effects
+ if (options.warm) {
+ shot.setTint(0xffddaa); // Warm nostalgic tint
+ }
+
+ if (options.red) {
+ shot.setTint(0xff6666); // Red danger tint
+ }
+
+ if (options.toxic) {
+ shot.setTint(0x66ff66); // Green toxic tint
+ }
+
+ if (options.fadeIn) {
+ this.tweens.add({
+ targets: shot,
+ alpha: 1,
+ duration: 1500
+ });
+ }
+
+ if (options.glitch) {
+ // Simple glitch effect - position jitter
+ this.tweens.add({
+ targets: shot,
+ x: { from: width / 2 - 5, to: width / 2 + 5 },
+ duration: 100,
+ repeat: duration / 100,
+ yoyo: true
+ });
+ }
+
+ if (options.strobe) {
+ // Strobe effect
+ this.tweens.add({
+ targets: shot,
+ alpha: { from: 0.7, to: 1.0 },
+ duration: 150,
+ repeat: duration / 150,
+ yoyo: true
+ });
+ }
+ });
+ }
+
+ shutdown() {
+ // Cleanup
+ if (this.skipPrompt) {
+ this.skipPrompt.destroy();
+ }
+ if (this.currentShot) {
+ this.currentShot.destroy();
+ }
+ this.tweens.killAll();
+ this.time.removeAllEvents();
+ }
+}
diff --git a/src/scenes/PreloadScene.js b/src/scenes/PreloadScene.js
index bd0233dab..1c2f3758d 100644
--- a/src/scenes/PreloadScene.js
+++ b/src/scenes/PreloadScene.js
@@ -476,10 +476,10 @@ class PreloadScene extends Phaser.Scene {
console.log('✅ PreloadScene: Assets loaded!');
window.gameState.currentScene = 'PreloadScene';
- // ✅ Starting main menu (StoryScene)
+ // ✅ Starting INTRO SEQUENCE (NEW! Jan 10, 2026)
this.time.delayedCall(500, () => {
- console.log('🎮 Starting StoryScene (Main Menu)...');
- this.scene.start('StoryScene'); // ← MAIN MENU
+ console.log('🎬 Starting IntroScene (Cinematic Intro)...');
+ this.scene.start('IntroScene'); // ← NEW INTRO SEQUENCE
});
}
});