diff --git a/src/css/screens.css b/src/css/screens.css index c5cc933..026c49a 100644 --- a/src/css/screens.css +++ b/src/css/screens.css @@ -60,3 +60,58 @@ font-size: 14px; color: var(--text-color); } +/* Intro Screen Styles */ +.intro-screen { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100vh; + background-color: #0a0a1a; + color: #00ff00; + font-family: 'Courier New', monospace; + text-align: center; +} + +.title { + font-size: 48px; + font-weight: bold; + margin-bottom: 20px; + text-shadow: 0 0 10px #00ff00; + letter-spacing: 4px; +} + +.credits { + font-size: 16px; + margin-bottom: 30px; + color: #a0a0a0; +} + +.instructions { + font-size: 14px; + margin-bottom: 30px; + color: #00ff00; + line-height: 1.5; +} + +.options { + margin-top: 20px; +} + +.option { + padding: 10px 20px; + margin: 5px 0; + font-size: 18px; + cursor: pointer; + transition: all 0.2s; + border: 2px solid transparent; +} + +.option.selected { + border-color: #00ff00; + background-color: rgba(0, 255, 0, 0.1); +} + +.option:hover { + background-color: rgba(0, 255, 0, 0.2); +} diff --git a/src/index.html b/src/index.html index 9d59bef..e6e3f3a 100644 --- a/src/index.html +++ b/src/index.html @@ -27,3 +27,15 @@ +
+ +
+
+ +
+
+ +
+
+ +
diff --git a/src/js/screens/intro.js b/src/js/screens/intro.js new file mode 100644 index 0000000..87b009c --- /dev/null +++ b/src/js/screens/intro.js @@ -0,0 +1,98 @@ +class IntroScreen { + constructor() { + this.title = 'WINGS88'; + this.credits = 'A RetroWeb Games Production'; + this.instructions = 'Use arrow keys to fly\nPress SPACE to start'; + this.options = ['Start Game', 'Instructions', 'Quit']; + this.selectedOption = 0; + this.audioContext = null; + this.musicTrack = null; + } + + init() { + this.setupAudio(); + this.render(); + this.setupEventListeners(); + } + + setupAudio() { + try { + this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); + this.loadMusic(); + } catch (e) { + console.log('Audio initialization failed:', e); + } + } + + loadMusic() { + // Placeholder for retro MIDI music + console.log('Loading retro music...'); + } + + render() { + const screen = document.getElementById('screen'); + screen.innerHTML = ` +
+
${this.title}
+
${this.credits}
+
${this.instructions}
+
+ ${this.options.map((option, index) => ` +
+ ${option} +
+ `).join('')} +
+
+ `; + } + + setupEventListeners() { + document.addEventListener('keydown', (e) => this.handleKeyDown(e)); + } + + handleKeyDown(e) { + switch(e.key) { + case 'ArrowUp': + this.moveSelection(-1); + break; + case 'ArrowDown': + this.moveSelection(1); + break; + case 'Enter': + this.selectOption(); + break; + case 'Escape': + this.selectOption(); + break; + } + } + + moveSelection(direction) { + this.selectedOption = (this.selectedOption + direction + this.options.length) % this.options.length; + this.render(); + } + + selectOption() { + switch(this.selectedOption) { + case 0: + console.log('Starting game...'); + break; + case 1: + console.log('Showing instructions...'); + break; + case 2: + console.log('Quitting game...'); + break; + } + } + + cleanup() { + document.removeEventListener('keydown', this.handleKeyDown); + if (this.audioContext) { + this.audioContext.close(); + } + } +} + +module.exports = IntroScreen; diff --git a/tests/unit/intro.test.js b/tests/unit/intro.test.js new file mode 100644 index 0000000..c031f86 --- /dev/null +++ b/tests/unit/intro.test.js @@ -0,0 +1,85 @@ +const IntroScreen = require('../../src/js/screens/intro'); + +describe('IntroScreen', () => { + let introScreen; + + beforeEach(() => { + introScreen = new IntroScreen(); + }); + + describe('constructor', () => { + it('should initialize with correct default values', () => { + expect(introScreen.title).toBe('WINGS88'); + expect(introScreen.credits).toBe('A RetroWeb Games Production'); + expect(introScreen.instructions).toBe('Use arrow keys to fly\nPress SPACE to start'); + expect(introScreen.options).toEqual(['Start Game', 'Instructions', 'Quit']); + expect(introScreen.selectedOption).toBe(0); + expect(introScreen.audioContext).toBeNull(); + expect(introScreen.musicTrack).toBeNull(); + }); + }); + + describe('moveSelection', () => { + it('should move selection up', () => { + introScreen.selectedOption = 1; + // Mock render to prevent DOM access + introScreen.render = jest.fn(); + introScreen.moveSelection(-1); + expect(introScreen.selectedOption).toBe(0); + expect(introScreen.render).toHaveBeenCalled(); + }); + + it('should move selection down', () => { + introScreen.selectedOption = 0; + // Mock render to prevent DOM access + introScreen.render = jest.fn(); + introScreen.moveSelection(1); + expect(introScreen.selectedOption).toBe(1); + expect(introScreen.render).toHaveBeenCalled(); + }); + + it('should wrap around from last to first', () => { + introScreen.selectedOption = 2; + // Mock render to prevent DOM access + introScreen.render = jest.fn(); + introScreen.moveSelection(1); + expect(introScreen.selectedOption).toBe(0); + expect(introScreen.render).toHaveBeenCalled(); + }); + + it('should wrap around from first to last', () => { + introScreen.selectedOption = 0; + // Mock render to prevent DOM access + introScreen.render = jest.fn(); + introScreen.moveSelection(-1); + expect(introScreen.selectedOption).toBe(2); + expect(introScreen.render).toHaveBeenCalled(); + }); + }); + + describe('selectOption', () => { + it('should handle Start Game selection', () => { + introScreen.selectedOption = 0; + const logSpy = jest.spyOn(console, 'log'); + introScreen.selectOption(); + expect(logSpy).toHaveBeenCalledWith('Starting game...'); + logSpy.mockRestore(); + }); + + it('should handle Instructions selection', () => { + introScreen.selectedOption = 1; + const logSpy = jest.spyOn(console, 'log'); + introScreen.selectOption(); + expect(logSpy).toHaveBeenCalledWith('Showing instructions...'); + logSpy.mockRestore(); + }); + + it('should handle Quit selection', () => { + introScreen.selectedOption = 2; + const logSpy = jest.spyOn(console, 'log'); + introScreen.selectOption(); + expect(logSpy).toHaveBeenCalledWith('Quitting game...'); + logSpy.mockRestore(); + }); + }); +});