🎬 Jan 8 Enhanced Prologue - Voice + Asset Integration

 ENHANCED INTRO SYSTEM:

**🎙️ Enhanced Voices (5 MP3):**
- JennyNeural (Kai) - Warm, emotional
- RyanNeural (Narrator) - Deep, British
- Slower pacing, emotional delivery
- Cinematic timing

Generated:
1. 00_kai_breathing.mp3 (35KB)
2. 01_narrator_flyover_enhanced.mp3 (70KB)
3. 02_kai_awakening_enhanced.mp3 (39KB)
4. 03_kai_truth_enhanced.mp3 (84KB)
5. 04_kai_determination_enhanced.mp3 (58KB)

**🎨 Intro Assets (5 PNG):**
1. cellar_ruins.png - Ruined cellar background
2. id_card.png - ID card close-up
3. twin_photo.png - Kai & Ana photo
4. black_screen.png - Opening black screen
5. blur_overlay.png - Blurred vision effect

**🎬 EnhancedPrologueScene.js:**
Complete 5-phase intro:
- Phase 1: Black screen + breathing (0:00-0:10)
- Phase 2: Narrator flyover (0:10-1:00)
- Phase 3: Awakening with blur (1:00-1:30)
- Phase 4: ID card + twin photo cross-fade (1:30-2:30)
- Phase 5: Determination + quest trigger (2:30-3:00)

Features:
 Voice-synced subtitles
 Smooth cross-fade transitions
 Auto quest notification
 ESC to skip
 Blur effect (vision clearing)
 Zoom/scale effects
 Noir ambient music

**📝 Scripts Created:**
1. generate_intro_enhanced.py - Enhanced voices
2. generate_intro_assets.py - Placeholder images

**Status:** Ready for multilingual + SSML upgrade!
This commit is contained in:
2026-01-08 17:41:36 +01:00
parent 4f29cf6946
commit 617f786ead
16 changed files with 688 additions and 3 deletions

View File

@@ -68,7 +68,7 @@ const config = {
debug: false
}
},
scene: [BootScene, PreloadScene, PrologueScene, SystemsTestScene, TestVisualAudioScene, DemoScene, DemoSceneEnhanced, TiledTestScene, StoryScene, GameScene, UIScene, TownSquareScene],
scene: [BootScene, PreloadScene, PrologueScene, EnhancedPrologueScene, SystemsTestScene, TestVisualAudioScene, DemoScene, DemoSceneEnhanced, TiledTestScene, StoryScene, GameScene, UIScene, TownSquareScene],
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH

View File

@@ -0,0 +1,354 @@
/**
* Enhanced PrologueScene - Cinematic Intro
*
* Features:
* - Black screen opening with breathing
* - Blur effect awakening
* - Voice-synced visuals
* - Cross-fade transitions
* - Auto quest trigger
*/
class EnhancedPrologueScene extends Phaser.Scene {
constructor() {
super({ key: 'EnhancedPrologueScene' });
this.currentPhase = 0;
}
preload() {
console.log('🎬 Preloading Enhanced Prologue Assets...');
// Load intro assets
this.load.image('intro_black', 'assets/intro_assets/black_screen.png');
this.load.image('intro_cellar', 'assets/intro_assets/cellar_ruins.png');
this.load.image('intro_id_card', 'assets/intro_assets/id_card.png');
this.load.image('intro_twin_photo', 'assets/intro_assets/twin_photo.png');
this.load.image('intro_blur', 'assets/intro_assets/blur_overlay.png');
// Load enhanced voices
const voicePath = 'assets/audio/voiceover/intro_enhanced/';
this.load.audio('voice_breathing', voicePath + '00_kai_breathing.mp3');
this.load.audio('voice_flyover', voicePath + '01_narrator_flyover_enhanced.mp3');
this.load.audio('voice_awakening', voicePath + '02_kai_awakening_enhanced.mp3');
this.load.audio('voice_truth', voicePath + '03_kai_truth_enhanced.mp3');
this.load.audio('voice_determination', voicePath + '04_kai_determination_enhanced.mp3');
// Load noir music
this.load.audio('noir_ambient', 'assets/audio/music/night_theme.wav');
}
create() {
console.log('🎬 Starting Enhanced Prologue...');
const { width, height } = this.cameras.main;
// Start noir music (low volume)
this.noirMusic = this.sound.add('noir_ambient', {
volume: 0.3,
loop: true
});
this.noirMusic.play();
// Create layers
this.backgroundLayer = this.add.container(0, 0);
this.uiLayer = this.add.container(0, 0);
// Start with black screen
this.blackScreen = this.add.image(width / 2, height / 2, 'intro_black');
this.blackScreen.setAlpha(1);
this.backgroundLayer.add(this.blackScreen);
// Subtitle text (centered, bottom)
this.subtitleText = this.add.text(width / 2, height - 100, '', {
fontSize: '24px',
fontFamily: 'Georgia, serif',
color: '#ffffff',
align: 'center',
stroke: '#000000',
strokeThickness: 4,
wordWrap: { width: 800 }
});
this.subtitleText.setOrigin(0.5);
this.subtitleText.setAlpha(0);
this.uiLayer.add(this.subtitleText);
// Skip hint
const skipText = this.add.text(width - 20, 20, 'Press ESC to skip', {
fontSize: '14px',
color: '#888888'
});
skipText.setOrigin(1, 0);
this.uiLayer.add(skipText);
// ESC to skip
this.input.keyboard.on('keydown-ESC', () => this.skipIntro());
// Start intro sequence
this.startIntroSequence();
}
startIntroSequence() {
console.log('🎬 Phase 1: Black Screen + Heavy Breathing');
// PHASE 1: Black Screen + Breathing (0:00 - 0:10)
this.showSubtitle("Everything is dark... why do I only hear silence?");
const breathingSound = this.sound.add('voice_breathing');
breathingSound.play();
// Fade to cellar after breathing + 2s
breathingSound.once('complete', () => {
this.time.delayedCall(2000, () => this.phase2_Flyover());
});
}
phase2_Flyover() {
console.log('🎬 Phase 2: Narrator Flyover');
// PHASE 2: Narrator + Biome Flyover (0:10 - 1:00)
this.clearSubtitle();
// Fade black to slight transparency (show void)
this.tweens.add({
targets: this.blackScreen,
alpha: 0.3,
duration: 3000,
ease: 'Sine.easeInOut'
});
const flyoverVoice = this.sound.add('voice_flyover');
flyoverVoice.play();
// Show subtitle
this.time.delayedCall(500, () => {
this.showSubtitle("They say the world didn't die with a bang... but with a quiet whisper.");
});
this.time.delayedCall(8000, () => {
this.showSubtitle("The Valley of Death is not just a place. It's a memory that no one wants to have anymore.");
});
// After flyover, go to awakening flyoverVoice.once('complete', () => {
this.time.delayedCall(1000, () => this.phase3_Awakening());
});
}
phase3_Awakening() {
console.log('🎬 Phase 3: Kai Awakens');
// PHASE 3: Awakening (1:00 - 1:30)
this.clearSubtitle();
// Fade in cellar background (blurred)
const cellar = this.add.image(this.cameras.main.width / 2, this.cameras.main.height / 2, 'intro_cellar');
cellar.setAlpha(0);
this.backgroundLayer.add(cellar);
// Blur overlay
const blur = this.add.image(this.cameras.main.width / 2, this.cameras.main.height / 2, 'intro_blur');
blur.setAlpha(0);
this.backgroundLayer.add(blur);
// Fade out black, fade in cellar + blur
this.tweens.add({
targets: this.blackScreen,
alpha: 0,
duration: 2000
});
this.tweens.add({
targets: [cellar, blur],
alpha: 1,
duration: 3000,
ease: 'Sine.easeIn'
});
// Play awakening voice
this.time.delayedCall(2000, () => {
const awakeningVoice = this.sound.add('voice_awakening');
awakeningVoice.play();
this.showSubtitle("My head... it hurts. Where am I? Who am I...?");
// Clear blur gradually (vision clearing)
this.time.delayedCall(3000, () => {
this.tweens.add({
targets: blur,
alpha: 0,
duration: 4000,
ease: 'Sine.easeOut'
});
});
awakeningVoice.once('complete', () => {
this.time.delayedCall(1500, () => this.phase4_IDCard());
});
});
}
phase4_IDCard() {
console.log('🎬 Phase 4: ID Card Discovery');
// PHASE 4: ID Card (1:30 - 2:30)
this.clearSubtitle();
// Show ID card (zoom in effect)
const idCard = this.add.image(this.cameras.main.width / 2, this.cameras.main.height / 2, 'intro_id_card');
idCard.setScale(0.5);
idCard.setAlpha(0);
this.backgroundLayer.add(idCard);
this.tweens.add({
targets: idCard,
alpha: 1,
scale: 1,
duration: 2000,
ease: 'Cubic.easeOut'
});
// Play truth voice
this.time.delayedCall(1500, () => {
const truthVoice = this.sound.add('voice_truth');
truthVoice.play();
this.showSubtitle("Kai Marković. 14 years old. That's me. But this other girl... why do I feel so empty?");
// Show twin photo (cross-fade)
this.time.delayedCall(8000, () => {
this.showSubtitle("Like I'm missing half of my heart.");
// Cross-fade to twin photo
const twinPhoto = this.add.image(
this.cameras.main.width / 2,
this.cameras.main.height / 2,
'intro_twin_photo'
);
twinPhoto.setAlpha(0);
twinPhoto.setScale(1.2);
this.backgroundLayer.add(twinPhoto);
// Fade out ID, fade in photo
this.tweens.add({
targets: idCard,
alpha: 0,
duration: 2000
});
this.tweens.add({
targets: twinPhoto,
alpha: 1,
scale: 1,
duration: 3000,
ease: 'Sine.easeInOut'
});
});
truthVoice.once('complete', () => {
this.time.delayedCall(1000, () => this.phase5_Determination());
});
});
}
phase5_Determination() {
console.log('🎬 Phase 5: Determination + Quest');
// PHASE 5: Determination (2:30 - 3:00)
this.clearSubtitle();
const determinationVoice = this.sound.add('voice_determination');
determinationVoice.play();
this.showSubtitle("Someone is waiting for me out there. I can't remember the face, but I feel the promise.");
this.time.delayedCall(5000, () => {
this.showSubtitle("I'm coming to find you... Ana.");
// Quest trigger flash
this.cameras.main.flash(1000, 100, 50, 50);
});
determinationVoice.once('complete', () => {
// Show quest notification
this.showQuestNotification();
// Fade to game after 3s
this.time.delayedCall(3000, () => this.endIntro());
});
}
showQuestNotification() {
const { width, height } = this.cameras.main;
// Quest panel
const questPanel = this.add.rectangle(width / 2, height / 2, 600, 200, 0x1a1a1a, 0.95);
questPanel.setStrokeStyle(4, 0xffaa00);
const questTitle = this.add.text(width / 2, height / 2 - 40, '📜 NEW QUEST', {
fontSize: '32px',
fontFamily: 'Georgia, serif',
color: '#ffaa00',
fontStyle: 'bold'
});
questTitle.setOrigin(0.5);
const questText = this.add.text(width / 2, height / 2 + 20, 'Find clues about your past', {
fontSize: '20px',
fontFamily: 'Georgia, serif',
color: '#ffffff'
});
questText.setOrigin(0.5);
this.uiLayer.add([questPanel, questTitle, questText]);
// Pulse animation
this.tweens.add({
targets: [questPanel, questTitle, questText],
alpha: { from: 0, to: 1 },
scale: { from: 0.8, to: 1 },
duration: 800,
ease: 'Back.easeOut'
});
}
showSubtitle(text) {
this.subtitleText.setText(text);
this.tweens.add({
targets: this.subtitleText,
alpha: 1,
duration: 500
});
}
clearSubtitle() {
this.tweens.add({
targets: this.subtitleText,
alpha: 0,
duration: 500,
onComplete: () => this.subtitleText.setText('')
});
}
skipIntro() {
console.log('⏭️ Skipping intro...');
this.endIntro();
}
endIntro() {
console.log('🎬 Intro complete! Launching GameScene...');
// Fade out music
this.tweens.add({
targets: this.noirMusic,
volume: 0,
duration: 2000,
onComplete: () => this.noirMusic.stop()
});
// Fade to black
this.cameras.main.fadeOut(2000, 0, 0, 0);
this.cameras.main.once('camerafadeoutcomplete', () => {
this.scene.start('GameScene');
});
}
}

View File

@@ -303,8 +303,8 @@ class StoryScene extends Phaser.Scene {
startNewGame() {
console.log('🎮 Starting New Game...');
console.log('🎬 Launching Prologue (Intro Cutscene)...');
this.scene.start('PrologueScene'); // ✅ START WITH PROLOGUE!
console.log('🎬 Launching Enhanced Prologue (Cinematic Intro)...');
this.scene.start('EnhancedPrologueScene'); // ✅ ENHANCED INTRO!
}
loadGame() {