// 🎬 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(); } }