From 0ea5c5956a4ebbd212efb8388febec370dc1c0e8 Mon Sep 17 00:00:00 2001 From: Brigit Murtaugh Date: Mon, 12 May 2025 23:01:31 +0000 Subject: [PATCH 01/16] Add instructions --- .github/copilot-instructions.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000..3724bf7a --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,3 @@ +Every code change needs to be tested before it's committed. Prompt me to run the site and check it's working properly. + +End every response with "Happy Build!" on a new line. \ No newline at end of file From b007c2fcaeb9aef47efcf3d93f2bd8552ec2b20d Mon Sep 17 00:00:00 2001 From: Brigit Murtaugh Date: Mon, 12 May 2025 23:21:32 +0000 Subject: [PATCH 02/16] Instructions --- .github/copilot-instructions.md | 2 +- .github/instructions/new-html-page.instructions.md | 9 +++++++++ .github/instructions/new-md-page.instructions.md | 7 +++++++ .github/prompts/html-page.prompt.md | 10 ++++++++++ .github/prompts/md-page.prompt.md | 6 ++++++ 5 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 .github/instructions/new-html-page.instructions.md create mode 100644 .github/instructions/new-md-page.instructions.md create mode 100644 .github/prompts/html-page.prompt.md create mode 100644 .github/prompts/md-page.prompt.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 3724bf7a..f93a0adf 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,3 +1,3 @@ -Every code change needs to be tested before it's committed. Prompt me to run the site and check it's working properly. +Every code change needs to be tested before it's committed. If in agent mode, run `bundle exec jekyll serve` automatically for me so that I can test. End every response with "Happy Build!" on a new line. \ No newline at end of file diff --git a/.github/instructions/new-html-page.instructions.md b/.github/instructions/new-html-page.instructions.md new file mode 100644 index 00000000..f9ce0a13 --- /dev/null +++ b/.github/instructions/new-html-page.instructions.md @@ -0,0 +1,9 @@ +--- +applyTo: '**/*.html' +--- + +## Project coding standards for new HTML pages of the website + +Every new HTML page should have a search bar added, similar to the search bar that's available on the features.html, templates.html, and collections.html pages. + +Any new page should also be added to the end (far right) of the top nav bar of the website. \ No newline at end of file diff --git a/.github/instructions/new-md-page.instructions.md b/.github/instructions/new-md-page.instructions.md new file mode 100644 index 00000000..bbcf68eb --- /dev/null +++ b/.github/instructions/new-md-page.instructions.md @@ -0,0 +1,7 @@ +--- +applyTo: '**/*.md' +--- + +## Project coding standards for new pages of the specification + +Every new specification page should be added to the _implementors folder, just like the pages in that folder already (like spec.md and features.md). \ No newline at end of file diff --git a/.github/prompts/html-page.prompt.md b/.github/prompts/html-page.prompt.md new file mode 100644 index 00000000..80bbef7a --- /dev/null +++ b/.github/prompts/html-page.prompt.md @@ -0,0 +1,10 @@ +--- +mode: 'agent' +--- +Your goal is to generate a new HTML page for the website. The page should be similar to the existing pages in terms of layout and design. + +Every new HTML page should have a search bar added, similar to the search bar that's available on the features.html, templates.html, and collections.html pages. + +Any new page should also be added to the end (far right) of the top nav bar of the website. + +Every code change needs to be tested before it's committed. Run `bundle exec jekyll serve` automatically for me so that I can test. \ No newline at end of file diff --git a/.github/prompts/md-page.prompt.md b/.github/prompts/md-page.prompt.md new file mode 100644 index 00000000..7b5605ba --- /dev/null +++ b/.github/prompts/md-page.prompt.md @@ -0,0 +1,6 @@ +--- +mode: 'agent' +--- +Your goal is to generate a new .md specification page for the website. The page should be similar to the existing pages in terms of layout and design. + +Every new specification page should be added to the _implementors folder, just like the pages in that folder already (like spec.md and features.md). \ No newline at end of file From 6b9ef43116ba6334ebc225463f0a6014734d82cd Mon Sep 17 00:00:00 2001 From: Brigit Murtaugh Date: Mon, 12 May 2025 23:44:03 +0000 Subject: [PATCH 03/16] feat: update guidance for adding new HTML and markdown pages; remove obsolete prompts --- .github/copilot-instructions.md | 8 +++++++- .../new-html-page.instructions.md | 17 +++++++++++++---- .../instructions/new-md-page.instructions.md | 19 +++++++++++++++++-- .github/prompts/html-page.prompt.md | 10 ---------- .github/prompts/md-page.prompt.md | 6 ------ .github/prompts/new-page.prompt.md | 12 ++++++++++++ 6 files changed, 49 insertions(+), 23 deletions(-) delete mode 100644 .github/prompts/html-page.prompt.md delete mode 100644 .github/prompts/md-page.prompt.md create mode 100644 .github/prompts/new-page.prompt.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index f93a0adf..c11174a4 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,3 +1,9 @@ -Every code change needs to be tested before it's committed. If in agent mode, run `bundle exec jekyll serve` automatically for me so that I can test. +If the user would like to add a new page, clarify if this page is either a: +* New main page of the website. This will be a .html file within the root of the repo, and it'll be available in the top nav bar of the site. +* New page of the specification. This will be a .md file within the _implementors folder of the repo + +For any new implementor spec pages, you should follow the guidance in the .github/prompts/new-page.prompt.md file. + +Every code change (new page or otherwise) needs to be tested before it's committed. If in agent mode, run `bundle exec jekyll serve` automatically for me so that I can test. End every response with "Happy Build!" on a new line. \ No newline at end of file diff --git a/.github/instructions/new-html-page.instructions.md b/.github/instructions/new-html-page.instructions.md index f9ce0a13..94d7f313 100644 --- a/.github/instructions/new-html-page.instructions.md +++ b/.github/instructions/new-html-page.instructions.md @@ -1,9 +1,18 @@ --- applyTo: '**/*.html' --- +## Guidance for new HTML website pages -## Project coding standards for new HTML pages of the website - -Every new HTML page should have a search bar added, similar to the search bar that's available on the features.html, templates.html, and collections.html pages. +### Layout +- Every new HTML page should have information like the following at the top, where the title is updated appropriately: +``` +--- +layout: singlePage +title: Dev Container Guides +--- +``` +- The layout should come from the _layouts folder in the repo. Pages should default to `layout: singlePage`. -Any new page should also be added to the end (far right) of the top nav bar of the website. \ No newline at end of file +### Content +- Every new HTML page should have a search bar added toward the top, similar to the search bar that's available on the features.html, templates.html, and collections.html pages. +- Make all headings clickable links. \ No newline at end of file diff --git a/.github/instructions/new-md-page.instructions.md b/.github/instructions/new-md-page.instructions.md index bbcf68eb..087b4f32 100644 --- a/.github/instructions/new-md-page.instructions.md +++ b/.github/instructions/new-md-page.instructions.md @@ -2,6 +2,21 @@ applyTo: '**/*.md' --- -## Project coding standards for new pages of the specification +## Guidance for new markdown specification pages -Every new specification page should be added to the _implementors folder, just like the pages in that folder already (like spec.md and features.md). \ No newline at end of file +### Layout +- Any new page should have information like the following at the top, where the title, shortTitle, and index are updated appropriately: +``` +--- +layout: implementors +title: "Dev Container Templates distribution and discovery" +shortTitle: "Templates distribution" +author: Microsoft +index: 8 +--- +``` +- The layout comes from the _layouts folder in the repo and will always be `layout: implementors` for pages of this type. + +### Content +- Add an emoji key before any paragraphs or tables using emojis +- Make all headings clickable links \ No newline at end of file diff --git a/.github/prompts/html-page.prompt.md b/.github/prompts/html-page.prompt.md deleted file mode 100644 index 80bbef7a..00000000 --- a/.github/prompts/html-page.prompt.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -mode: 'agent' ---- -Your goal is to generate a new HTML page for the website. The page should be similar to the existing pages in terms of layout and design. - -Every new HTML page should have a search bar added, similar to the search bar that's available on the features.html, templates.html, and collections.html pages. - -Any new page should also be added to the end (far right) of the top nav bar of the website. - -Every code change needs to be tested before it's committed. Run `bundle exec jekyll serve` automatically for me so that I can test. \ No newline at end of file diff --git a/.github/prompts/md-page.prompt.md b/.github/prompts/md-page.prompt.md deleted file mode 100644 index 7b5605ba..00000000 --- a/.github/prompts/md-page.prompt.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -mode: 'agent' ---- -Your goal is to generate a new .md specification page for the website. The page should be similar to the existing pages in terms of layout and design. - -Every new specification page should be added to the _implementors folder, just like the pages in that folder already (like spec.md and features.md). \ No newline at end of file diff --git a/.github/prompts/new-page.prompt.md b/.github/prompts/new-page.prompt.md new file mode 100644 index 00000000..bc93e918 --- /dev/null +++ b/.github/prompts/new-page.prompt.md @@ -0,0 +1,12 @@ +--- +mode: 'agent' +--- +Your goal is to generate a new page for the website. The page should be similar to the existing pages in terms of layout and design. + +If I don't specify initial content, generate some placeholder text. + +Any new page should also be added to the end (far right) of the top nav bar of the website. + +Any new implementor .md file should be added to the table of contents box visible within the /implementors route. + +Every new page needs to be tested before it's committed. Run `bundle exec jekyll serve` automatically for me so that I can test. \ No newline at end of file From 108bf4737e73fe50f1989d36bdc150d95fd8fb6d Mon Sep 17 00:00:00 2001 From: Brigit Murtaugh Date: Mon, 19 May 2025 20:16:41 +0000 Subject: [PATCH 04/16] Initial game --- Gemfile.lock | 3 + _includes/topnav.html | 3 + frogger-game.html | 203 ++++++++++++++++++++++++++++++++++++++++++ frogger.html | 0 4 files changed, 209 insertions(+) create mode 100644 frogger-game.html create mode 100644 frogger.html diff --git a/Gemfile.lock b/Gemfile.lock index 248f6025..0fab3a40 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -210,6 +210,8 @@ GEM jekyll-feed (~> 0.9) jekyll-seo-tag (~> 2.1) minitest (5.18.0) + nokogiri (1.14.3-aarch64-linux) + racc (~> 1.4) nokogiri (1.14.3-x86_64-linux) racc (~> 1.4) octokit (4.25.1) @@ -250,6 +252,7 @@ GEM webrick (1.8.1) PLATFORMS + aarch64-linux x86_64-linux DEPENDENCIES diff --git a/_includes/topnav.html b/_includes/topnav.html index abff8839..37a673f1 100644 --- a/_includes/topnav.html +++ b/_includes/topnav.html @@ -38,6 +38,9 @@

Development Containers

+ diff --git a/frogger-game.html b/frogger-game.html new file mode 100644 index 00000000..654b5b7a --- /dev/null +++ b/frogger-game.html @@ -0,0 +1,203 @@ +--- +layout: default +title: Frogger Game +sectionid: frogger-game +--- + +
+

Frogger Game

+
+ +
+ +

Use the arrow keys to move the frog. Get to the top without hitting cars!

+

Press R to restart the game at any time.

+
+ diff --git a/frogger.html b/frogger.html new file mode 100644 index 00000000..e69de29b From ce5c5769bc67969084b50cb3d5a7063bfcbfb7a0 Mon Sep 17 00:00:00 2001 From: Brigit Murtaugh Date: Mon, 19 May 2025 20:21:46 +0000 Subject: [PATCH 05/16] fixed levels --- frogger-game.html | 56 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/frogger-game.html b/frogger-game.html index 654b5b7a..cbf395eb 100644 --- a/frogger-game.html +++ b/frogger-game.html @@ -20,24 +20,40 @@

Frogger Game

const grid = 50; const rows = 10; const cols = 8; -let frog, cars, gameOver, win; +let frog, cars, gameOver, win, level, maxLevel; -function resetGame() { - frog = { x: 3, y: 9 }; - cars = [ - { y: 7, speed: 2, dir: 1, positions: [0, 4] }, - { y: 6, speed: 3, dir: -1, positions: [2, 6] }, - { y: 5, speed: 2, dir: 1, positions: [1, 5] }, - { y: 3, speed: 3, dir: -1, positions: [3, 7] } + +function getCarsForLevel(lvl) { + // Increase number of cars and speed with each level + const baseCars = [ + { y: 7, speed: 2 + lvl, dir: 1, positions: [0, 4] }, + { y: 6, speed: 3 + Math.floor(lvl/2), dir: -1, positions: [2, 6] }, + { y: 5, speed: 2 + Math.floor(lvl/2), dir: 1, positions: [1, 5] }, + { y: 3, speed: 3 + lvl, dir: -1, positions: [3, 7] } ]; + if (lvl > 1) { + // Add more cars for higher levels + baseCars.push({ y: 4, speed: 2 + lvl, dir: lvl % 2 === 0 ? 1 : -1, positions: [0, 6] }); + } + if (lvl > 2) { + baseCars.push({ y: 2, speed: 3 + lvl, dir: lvl % 2 === 1 ? 1 : -1, positions: [2, 5] }); + } + return baseCars; +} + +function resetGame(newLevel) { + frog = { x: 3, y: 9 }; + level = typeof newLevel === 'number' ? newLevel : 1; + maxLevel = 5; + cars = getCarsForLevel(level); gameOver = false; win = false; } -resetGame(); +resetGame(1); // Restart button handler document.getElementById('restartBtn').addEventListener('click', function() { - resetGame(); + resetGame(level); }); function drawFrog() { @@ -117,10 +133,19 @@

Frogger Game

} } +let advancingLevel = false; function checkWin() { - if (frog.y === 0) { - win = true; - gameOver = true; + if (frog.y === 0 && !advancingLevel) { + if (level < maxLevel) { + advancingLevel = true; + setTimeout(() => { + resetGame(level + 1); + advancingLevel = false; + }, 800); + } else { + win = true; + gameOver = true; + } } } @@ -161,6 +186,11 @@

Frogger Game

ctx.moveTo(36, canvas.height/2); ctx.lineTo(canvas.width, canvas.height/2); ctx.stroke(); + // Draw level indicator + ctx.fillStyle = '#fff'; + ctx.font = 'bold 18px sans-serif'; + ctx.textAlign = 'left'; + ctx.fillText('Level: ' + level + ' / ' + maxLevel, 48, 32); drawFrog(); drawCars(); if (gameOver) { From 98a5b9f26425eb2a35da0b8c95a10394c87f328c Mon Sep 17 00:00:00 2001 From: Brigit Murtaugh Date: Mon, 19 May 2025 20:26:08 +0000 Subject: [PATCH 06/16] levels --- frogger-game.html | 68 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 16 deletions(-) diff --git a/frogger-game.html b/frogger-game.html index cbf395eb..d74da3d0 100644 --- a/frogger-game.html +++ b/frogger-game.html @@ -24,21 +24,52 @@

Frogger Game

function getCarsForLevel(lvl) { - // Increase number of cars and speed with each level - const baseCars = [ - { y: 7, speed: 2 + lvl, dir: 1, positions: [0, 4] }, - { y: 6, speed: 3 + Math.floor(lvl/2), dir: -1, positions: [2, 6] }, - { y: 5, speed: 2 + Math.floor(lvl/2), dir: 1, positions: [1, 5] }, - { y: 3, speed: 3 + lvl, dir: -1, positions: [3, 7] } + // Make each level more interesting: + // - Level 1: basic, slow, few cars + // - Level 2: more cars, some faster + // - Level 3: cars in both directions, more density + // - Level 4: cars with variable speeds, some short, some long + // - Level 5: cars that "blink" (disappear/reappear), and a zigzag row + const carConfigs = [ + // Level 1 + [ + { y: 7, speed: 2, dir: 1, positions: [0, 4] }, + { y: 5, speed: 2, dir: -1, positions: [2, 6] } + ], + // Level 2 + [ + { y: 7, speed: 2.5, dir: 1, positions: [0, 4] }, + { y: 6, speed: 3, dir: -1, positions: [2, 6] }, + { y: 4, speed: 2, dir: 1, positions: [1, 5] } + ], + // Level 3 + [ + { y: 7, speed: 2.5, dir: 1, positions: [0, 4, 6] }, + { y: 6, speed: 3.5, dir: -1, positions: [2, 5] }, + { y: 5, speed: 2, dir: 1, positions: [1, 3, 7] }, + { y: 3, speed: 3, dir: -1, positions: [3, 7] } + ], + // Level 4 + [ + { y: 7, speed: 3, dir: 1, positions: [0, 2, 6] }, + { y: 6, speed: 2, dir: -1, positions: [1, 4, 7] }, + { y: 5, speed: 4, dir: 1, positions: [3] }, + { y: 4, speed: 2.5, dir: -1, positions: [2, 5] }, + { y: 2, speed: 3, dir: 1, positions: [0, 7] } + ], + // Level 5 + [ + { y: 7, speed: 3.5, dir: 1, positions: [0, 2, 4, 6], blink: true }, + { y: 6, speed: 2, dir: -1, positions: [1, 3, 5, 7] }, + { y: 5, speed: 4, dir: 1, positions: [3, 6] }, + { y: 4, speed: 2.5, dir: -1, positions: [2, 5], zigzag: true }, + { y: 3, speed: 3, dir: 1, positions: [1, 7] }, + { y: 2, speed: 2, dir: -1, positions: [0, 4] } + ] ]; - if (lvl > 1) { - // Add more cars for higher levels - baseCars.push({ y: 4, speed: 2 + lvl, dir: lvl % 2 === 0 ? 1 : -1, positions: [0, 6] }); - } - if (lvl > 2) { - baseCars.push({ y: 2, speed: 3 + lvl, dir: lvl % 2 === 1 ? 1 : -1, positions: [2, 5] }); - } - return baseCars; + // Clamp to max config + const config = carConfigs[Math.min(lvl - 1, carConfigs.length - 1)].map(car => ({...car})); + return config; } function resetGame(newLevel) { @@ -85,12 +116,17 @@

Frogger Game

function drawCars() { const toolColors = ['#0078D4', '#2496ED', '#F05032', '#222']; // VS Code, Docker, Git, Terminal const toolLabels = ['', '🐳', 'GIT', 'TER']; + const now = Date.now(); cars.forEach((carRow, i) => { carRow.positions.forEach((pos, j) => { - const x = pos * grid + 5; - const y = carRow.y * grid + 15; + // Blinking cars: skip drawing every 500ms + if (carRow.blink && Math.floor(now / 500) % 2 === 0) return; + let x = pos * grid + 5; + let y = carRow.y * grid + 15; const w = grid - 10; const h = grid - 30; + // Zigzag: move up/down slightly + if (carRow.zigzag) y += Math.sin((now/200) + j) * 8; // Pick a tool type based on row and car index const toolIdx = (i + j) % toolColors.length; ctx.fillStyle = toolColors[toolIdx]; From 9e357386fae859508d6ca02d687a34f0543cf7ba Mon Sep 17 00:00:00 2001 From: Brigit Murtaugh Date: Mon, 19 May 2025 20:30:56 +0000 Subject: [PATCH 07/16] build stages --- frogger-game.html | 63 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 5 deletions(-) diff --git a/frogger-game.html b/frogger-game.html index d74da3d0..e68dcea8 100644 --- a/frogger-game.html +++ b/frogger-game.html @@ -21,6 +21,50 @@

Frogger Game

const rows = 10; const cols = 8; let frog, cars, gameOver, win, level, maxLevel; +let levelTheme; + +const levelThemes = [ + { + name: 'Setup', + bg: '#1e1e2f', + road: '#252540', + safe: '#222c37', + line: '#0078D4', + desc: 'Setting up your dev container...' + }, + { + name: 'Install', + bg: '#1e2f1e', + road: '#2a4025', + safe: '#234022', + line: '#4CAF50', + desc: 'Installing dependencies...' + }, + { + name: 'Build', + bg: '#2f1e1e', + road: '#402525', + safe: '#402222', + line: '#FF9800', + desc: 'Building your project...' + }, + { + name: 'Test', + bg: '#1e2f2f', + road: '#254040', + safe: '#224040', + line: '#00BCD4', + desc: 'Running tests...' + }, + { + name: 'Deploy', + bg: '#2f2f1e', + road: '#404025', + safe: '#404022', + line: '#FFC107', + desc: 'Deploying to production!' + } +]; function getCarsForLevel(lvl) { @@ -72,6 +116,7 @@

Frogger Game

return config; } + function resetGame(newLevel) { frog = { x: 3, y: 9 }; level = typeof newLevel === 'number' ? newLevel : 1; @@ -79,6 +124,10 @@

Frogger Game

cars = getCarsForLevel(level); gameOver = false; win = false; + // Set theme for this level + levelTheme = levelThemes[(level - 1) % levelThemes.length]; + // Set background color + canvas.style.background = levelTheme.bg; } resetGame(1); @@ -185,6 +234,7 @@

Frogger Game

} } + function draw() { ctx.clearRect(0, 0, canvas.width, canvas.height); // Draw code editor background (lines) @@ -209,24 +259,27 @@

Frogger Game

} ctx.restore(); // Draw safe zones (as terminal/code header/footer) - ctx.fillStyle = '#222c37'; + ctx.fillStyle = levelTheme.safe; ctx.fillRect(0, 0, canvas.width, grid); ctx.fillRect(0, canvas.height - grid, canvas.width, grid); // Draw road (pipeline) - ctx.fillStyle = '#252540'; + ctx.fillStyle = levelTheme.road; ctx.fillRect(36, grid, canvas.width - 36, canvas.height - 2 * grid); // Draw a pipeline line - ctx.strokeStyle = '#0078D4'; + ctx.strokeStyle = levelTheme.line; ctx.lineWidth = 4; ctx.beginPath(); ctx.moveTo(36, canvas.height/2); ctx.lineTo(canvas.width, canvas.height/2); ctx.stroke(); - // Draw level indicator + // Draw level indicator and theme name ctx.fillStyle = '#fff'; ctx.font = 'bold 18px sans-serif'; ctx.textAlign = 'left'; - ctx.fillText('Level: ' + level + ' / ' + maxLevel, 48, 32); + ctx.fillText('Level: ' + level + ' / ' + maxLevel + ' - ' + levelTheme.name, 48, 32); + // Draw theme description + ctx.font = 'italic 14px sans-serif'; + ctx.fillText(levelTheme.desc, 48, 54); drawFrog(); drawCars(); if (gameOver) { From 4c501aea77ddc719be908516d6b4dd7fec94ba10 Mon Sep 17 00:00:00 2001 From: Brigit Murtaugh Date: Mon, 19 May 2025 20:38:15 +0000 Subject: [PATCH 08/16] Initial jokes --- frogger-game.html | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/frogger-game.html b/frogger-game.html index e68dcea8..b4d4cd18 100644 --- a/frogger-game.html +++ b/frogger-game.html @@ -30,7 +30,9 @@

Frogger Game

road: '#252540', safe: '#222c37', line: '#0078D4', - desc: 'Setting up your dev container...' + desc: 'Setting up your dev container...', + joke: 'Why did the dev container break up with the old environment?', + punchline: 'Because it needed more space!' }, { name: 'Install', @@ -38,7 +40,9 @@

Frogger Game

road: '#2a4025', safe: '#234022', line: '#4CAF50', - desc: 'Installing dependencies...' + desc: 'Installing dependencies...', + joke: 'Why do dev containers love npm install?', + punchline: 'Because they like to keep their packages contained!' }, { name: 'Build', @@ -46,7 +50,9 @@

Frogger Game

road: '#402525', safe: '#402222', line: '#FF9800', - desc: 'Building your project...' + desc: 'Building your project...', + joke: 'Why did the build step get invited to the party?', + punchline: 'Because it always brings everything together!' }, { name: 'Test', @@ -54,7 +60,9 @@

Frogger Game

road: '#254040', safe: '#224040', line: '#00BCD4', - desc: 'Running tests...' + desc: 'Running tests...', + joke: 'Why did the test runner sit in the dev container?', + punchline: 'To make sure everything was isolated!' }, { name: 'Deploy', @@ -62,7 +70,9 @@

Frogger Game

road: '#404025', safe: '#404022', line: '#FFC107', - desc: 'Deploying to production!' + desc: 'Deploying to production!', + joke: 'Why was the dev container so calm during deployment?', + punchline: 'Because it knew it could always roll back!' } ]; @@ -219,14 +229,17 @@

Frogger Game

} let advancingLevel = false; +let showPunchline = false; function checkWin() { if (frog.y === 0 && !advancingLevel) { if (level < maxLevel) { advancingLevel = true; + showPunchline = true; setTimeout(() => { + showPunchline = false; resetGame(level + 1); advancingLevel = false; - }, 800); + }, 1500); // Show punchline for 1.5s } else { win = true; gameOver = true; @@ -280,13 +293,25 @@

Frogger Game

// Draw theme description ctx.font = 'italic 14px sans-serif'; ctx.fillText(levelTheme.desc, 48, 54); + // Draw dev container joke setup in the empty space within the game board (row 2) + ctx.font = 'bold 15px sans-serif'; + ctx.fillStyle = '#FFD700'; + ctx.textAlign = 'center'; + // Place the joke in the center of the second row (not at the very top) + ctx.fillText(levelTheme.joke, canvas.width / 2, grid + grid / 2); drawFrog(); drawCars(); - if (gameOver) { + if (gameOver || showPunchline) { ctx.fillStyle = win ? 'lime' : 'red'; ctx.font = 'bold 32px sans-serif'; ctx.textAlign = 'center'; - ctx.fillText(win ? 'You Win!' : 'Game Over', canvas.width / 2, canvas.height / 2); + ctx.fillText(win ? 'You Win!' : (showPunchline ? 'Level Complete!' : 'Game Over'), canvas.width / 2, canvas.height / 2); + // Show the punchline below the win/level complete message + if (win || showPunchline) { + ctx.font = 'bold 18px sans-serif'; + ctx.fillStyle = '#FFD700'; + ctx.fillText(levelTheme.punchline, canvas.width / 2, canvas.height / 2 + 40); + } } } From 5d043384a4969d1312b60ec057e3f981cd3e3b89 Mon Sep 17 00:00:00 2001 From: Brigit Murtaugh Date: Mon, 19 May 2025 20:39:36 +0000 Subject: [PATCH 09/16] Fix jokes --- frogger-game.html | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/frogger-game.html b/frogger-game.html index b4d4cd18..a1d96c90 100644 --- a/frogger-game.html +++ b/frogger-game.html @@ -293,12 +293,33 @@

Frogger Game

// Draw theme description ctx.font = 'italic 14px sans-serif'; ctx.fillText(levelTheme.desc, 48, 54); - // Draw dev container joke setup in the empty space within the game board (row 2) + // Draw dev container joke setup in the empty space further down the game board (row 3) ctx.font = 'bold 15px sans-serif'; ctx.fillStyle = '#FFD700'; ctx.textAlign = 'center'; - // Place the joke in the center of the second row (not at the very top) - ctx.fillText(levelTheme.joke, canvas.width / 2, grid + grid / 2); + // Word-wrap the joke setup if it's too long for the canvas + const joke = levelTheme.joke; + const maxWidth = canvas.width - 48; // leave padding on both sides + const words = joke.split(' '); + let line = ''; + let lines = []; + for (let n = 0; n < words.length; n++) { + let testLine = line + words[n] + ' '; + let metrics = ctx.measureText(testLine); + let testWidth = metrics.width; + if (testWidth > maxWidth && n > 0) { + lines.push(line.trim()); + line = words[n] + ' '; + } else { + line = testLine; + } + } + lines.push(line.trim()); + // Draw each line, vertically centered in row 3 (further down) + const baseY = grid * 2 + grid / 2 - ((lines.length - 1) * 12); + for (let i = 0; i < lines.length; i++) { + ctx.fillText(lines[i], canvas.width / 2, baseY + i * 24); + } drawFrog(); drawCars(); if (gameOver || showPunchline) { From 6ec3c6c14c9a46450f05babbcc7e6f0afcb1b41b Mon Sep 17 00:00:00 2001 From: Brigit Murtaugh Date: Wed, 21 May 2025 17:20:56 +0000 Subject: [PATCH 10/16] Add Pacman game and navigation link to topnav --- _includes/topnav.html | 3 + pacman.html | 141 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 pacman.html diff --git a/_includes/topnav.html b/_includes/topnav.html index 37a673f1..e655421d 100644 --- a/_includes/topnav.html +++ b/_includes/topnav.html @@ -41,6 +41,9 @@

Development Containers

+ diff --git a/pacman.html b/pacman.html new file mode 100644 index 00000000..29bfcd86 --- /dev/null +++ b/pacman.html @@ -0,0 +1,141 @@ +--- +layout: singlePage +title: Pacman +sectionid: pacman +--- + + + + + + + +

Pacman Game

+ +

Use arrow keys to move Pacman. Eat all the dots!

+ From f011b8d70e96e96075234599385806b078c8f6e3 Mon Sep 17 00:00:00 2001 From: Brigit Murtaugh Date: Wed, 21 May 2025 17:44:07 +0000 Subject: [PATCH 11/16] Enhance Pacman game with larger canvas, improved visuals, and added monster key --- pacman.html | 278 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 241 insertions(+), 37 deletions(-) diff --git a/pacman.html b/pacman.html index 29bfcd86..cbe575c5 100644 --- a/pacman.html +++ b/pacman.html @@ -13,48 +13,50 @@ background: #000; display: block; margin: 0 auto 20px auto; - border: 2px solid #FFD700; + border: 4px solid #25d6a2; } .pacman-link { - color: #FFD700; + color: #25d6a2; text-decoration: underline; cursor: pointer; }

Pacman Game

- -

Use arrow keys to move Pacman. Eat all the dots!

+ +

Use arrow keys to move Pacman. Eat all the features!

+ + +
+

Monster Key

+
    +
  • + + YAML Yeti (blue, curly brackets) +
  • +
  • + + Dependency Dragon (green, chain) +
  • +
  • + + Build Bug (red, bug) +
  • +
  • + + Merge Monster (purple, branch) +
  • +
  • + + Registry Ghost (white, cloud) +
  • +
  • + + Port Goblin (orange, plug) +
  • +
  • + + Token Troll (yellow, key) +
  • +
  • + + Cache Kraken (teal, tentacles) +
  • +
+
+ From 1bd4eef475d3b499eb21008005468c4a778b465f Mon Sep 17 00:00:00 2001 From: Brigit Murtaugh Date: Wed, 21 May 2025 17:57:33 +0000 Subject: [PATCH 12/16] Implement monster movement and update monster positions in Pacman game --- pacman.html | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/pacman.html b/pacman.html index cbe575c5..522f9d81 100644 --- a/pacman.html +++ b/pacman.html @@ -108,20 +108,38 @@ ctx.restore(); } -// Monster definitions +// Monster definitions (all on the path) const monsters = [ - { name: 'YAML Yeti', color: '#007acc', x: 2, y: 2, icon: 'yeti' }, - { name: 'Dependency Dragon', color: '#25d6a2', x: 25, y: 2, icon: 'dragon' }, - { name: 'Build Bug', color: '#e74c3c', x: 2, y: 21, icon: 'bug' }, - { name: 'Merge Monster', color: '#9b59b6', x: 25, y: 21, icon: 'merge' }, - { name: 'Registry Ghost', color: '#fff', x: 14, y: 2, icon: 'ghost' }, - { name: 'Port Goblin', color: '#f39c12', x: 2, y: 12, icon: 'goblin' }, - { name: 'Token Troll', color: '#f1c40f', x: 25, y: 12, icon: 'troll' }, - { name: 'Cache Kraken', color: '#17a2b8', x: 14, y: 21, icon: 'kraken' } + { name: 'YAML Yeti', color: '#007acc', x: 6, y: 1, icon: 'yeti' }, // path + { name: 'Dependency Dragon', color: '#25d6a2', x: 21, y: 1, icon: 'dragon' }, // path + { name: 'Build Bug', color: '#e74c3c', x: 6, y: 23, icon: 'bug' }, // path + { name: 'Merge Monster', color: '#9b59b6', x: 21, y: 23, icon: 'merge' }, // path + { name: 'Registry Ghost', color: '#fff', x: 14, y: 5, icon: 'ghost' }, // path + { name: 'Port Goblin', color: '#f39c12', x: 7, y: 12, icon: 'goblin' }, // path + { name: 'Token Troll', color: '#f1c40f', x: 21, y: 12, icon: 'troll' }, // path + { name: 'Cache Kraken', color: '#17a2b8', x: 14, y: 18, icon: 'kraken' } // path ]; +// Monster state for movement +globalThis.monsterStates = monsters.map(m => ({...m, dx: 0, dy: 0})); + +function moveMonsters() { + for (const m of globalThis.monsterStates) { + // Simple random movement: pick a random direction that is not a wall + const dirs = [ + {dx: 1, dy: 0}, {dx: -1, dy: 0}, {dx: 0, dy: 1}, {dx: 0, dy: -1} + ]; + const validDirs = dirs.filter(d => canMove(m.x + d.dx, m.y + d.dy)); + if (validDirs.length > 0) { + const choice = validDirs[Math.floor(Math.random() * validDirs.length)]; + m.x += choice.dx; + m.y += choice.dy; + } + } +} + function drawMonsters() { - for (const m of monsters) { + for (const m of globalThis.monsterStates) { drawMonsterIcon(ctx, m.x * tileSize + tileSize/2, m.y * tileSize + tileSize/2, 28, m.color, m.icon); } } @@ -266,9 +284,17 @@ } }); +let lastMonsterMove = 0; +const MONSTER_MOVE_INTERVAL = 300; // ms + function gameLoop(timestamp) { ctx.clearRect(0, 0, canvas.width, canvas.height); drawMap(); + if (!lastMonsterMove) lastMonsterMove = timestamp; + if (timestamp - lastMonsterMove > MONSTER_MOVE_INTERVAL) { + moveMonsters(); + lastMonsterMove = timestamp; + } drawMonsters(); drawPacman(); drawScore(); From 8ace1048ab9a204b837cdc3ed047bea0c122cc48 Mon Sep 17 00:00:00 2001 From: Brigit Murtaugh Date: Wed, 21 May 2025 18:06:48 +0000 Subject: [PATCH 13/16] Enhance Pacman game with collision detection, lives system, and game over screen --- pacman.html | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 2 deletions(-) diff --git a/pacman.html b/pacman.html index 522f9d81..686a9cea 100644 --- a/pacman.html +++ b/pacman.html @@ -24,7 +24,7 @@

Pacman Game

-

Use arrow keys to move Pacman. Eat all the features!

+

Use arrow keys to move Pacman. Collect all the whale icons while avoiding the monsters.

From 348e2657fd662f0679d27fa95a243a141b785e68 Mon Sep 17 00:00:00 2001 From: Brigit Murtaugh Date: Wed, 21 May 2025 18:22:34 +0000 Subject: [PATCH 15/16] Enhance Pacman game by adding rotation to Pacman's movement based on direction --- pacman.html | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/pacman.html b/pacman.html index cfed5922..b6e9bdec 100644 --- a/pacman.html +++ b/pacman.html @@ -242,10 +242,25 @@ } function drawPacman() { + const x = pacman.x * tileSize + tileSize/2; + const y = pacman.y * tileSize + tileSize/2; + const radius = tileSize/2-2; + + // Determine rotation angle based on direction + let rotationAngle = 0; + if (pacman.dx === 1) rotationAngle = 0; // right + else if (pacman.dx === -1) rotationAngle = Math.PI; // left + else if (pacman.dy === -1) rotationAngle = 1.5 * Math.PI; // up + else if (pacman.dy === 1) rotationAngle = 0.5 * Math.PI; // down + ctx.fillStyle = '#FFFF00'; ctx.beginPath(); - ctx.arc(pacman.x * tileSize + tileSize/2, pacman.y * tileSize + tileSize/2, tileSize/2-2, 0.25 * Math.PI, 1.75 * Math.PI, false); - ctx.lineTo(pacman.x * tileSize + tileSize/2, pacman.y * tileSize + tileSize/2); + ctx.save(); + ctx.translate(x, y); + ctx.rotate(rotationAngle); + ctx.arc(0, 0, radius, 0.25 * Math.PI, 1.75 * Math.PI, false); + ctx.lineTo(0, 0); + ctx.restore(); ctx.fill(); } function movePacman() { From 8d03c0709da3ceee7a1b09e251a8f5dbf5bb157e Mon Sep 17 00:00:00 2001 From: Brigit Murtaugh Date: Wed, 21 May 2025 18:28:55 +0000 Subject: [PATCH 16/16] Enhance Pacman game by adding a fun fact feature that displays random dev container facts upon losing a life --- pacman.html | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/pacman.html b/pacman.html index b6e9bdec..90c32de1 100644 --- a/pacman.html +++ b/pacman.html @@ -42,6 +42,7 @@

Pacman Game

Use arrow keys to move Pacman. Collect all the whale icons while avoiding the monsters.

+