From cd58c07c6b475ebb94e26d636d811109e8f6b2d8 Mon Sep 17 00:00:00 2001 From: Dan Date: Wed, 21 Jan 2026 17:44:05 +0000 Subject: [PATCH] pupdates --- assets/js/games/engine/scene-manager.js | 127 ++++++++++++++++++++++++ assets/js/games/games/boxing-day.js | 111 ++++++++++++++++----- assets/js/games/games/test-adventure.js | 47 +++++++++ assets/js/games/glitch-example.md | 100 +++++++++++++++++++ 4 files changed, 362 insertions(+), 23 deletions(-) create mode 100644 assets/js/games/glitch-example.md diff --git a/assets/js/games/engine/scene-manager.js b/assets/js/games/engine/scene-manager.js index e55f9e5..d67ac85 100644 --- a/assets/js/games/engine/scene-manager.js +++ b/assets/js/games/engine/scene-manager.js @@ -173,6 +173,11 @@ class SceneManager { continue; } + if (block.type === "glitch") { + await this._renderGlitch(block); + continue; + } + // Text with optional className (supports html: true for HTML content) if (block.text !== undefined) { if (block.html) { @@ -611,4 +616,126 @@ class SceneManager { await Promise.all(fadePromises); this.activeSounds.clear(); } + + // Render glitching text effect + async _renderGlitch(block) { + const text = this._interpolateText(block.text || ""); + const intensity = block.intensity || 0.3; // How much glitch (0-1) + const spread = block.spread || 2; // How many lines above/below to infect + const speed = block.speed || 50; // Animation speed in ms + const duration = block.duration || 2000; // How long the glitch lasts + const className = block.className || "glitch-text"; + + // Glitch character pool - mix of unicode, symbols, and corrupted chars + const glitchChars = [ + "▓", "▒", "░", "█", "▀", "▄", "▌", "▐", "║", "╬", "╣", "╠", + "¡", "¿", "‽", "※", "§", "¶", "†", "‡", "∞", "≈", "≠", "±", + "░", "▒", "▓", "█", "▀", "▄", "▌", "▐", "╔", "╗", "╚", "╝", + "Ω", "∑", "∏", "∫", "√", "∂", "∆", "∇", "∈", "∉", "∩", "∪", + "̴", "̵", "̶", "̷", "̸", "̡", "̢", "̧", "̨", "̛", "̖", "̗", + "É", "È", "Ê", "Ë", "Á", "À", "Â", "Ã", "Ä", "Å", "Æ", "Ç", + "Ñ", "Õ", "Ö", "Ø", "Ú", "Ù", "Û", "Ü", "Ý", "Þ", "ß", "ð", + "!", "@", "#", "$", "%", "^", "&", "*", "?", "~", "`", "|" + ]; + + // Generate the glitched text + const generateGlitch = (baseText, glitchAmount) => { + let result = ""; + for (let i = 0; i < baseText.length; i++) { + if (Math.random() < glitchAmount && baseText[i] !== " ") { + // Replace character with glitch + result += glitchChars[Math.floor(Math.random() * glitchChars.length)]; + } else { + result += baseText[i]; + } + } + return result; + }; + + // Generate random glitch lines that "infect" surrounding area + const generateInfectionLines = (baseLength) => { + const lines = []; + for (let i = 0; i < spread; i++) { + const lineLength = Math.floor(baseLength * Math.random() * 0.7); + const offset = Math.floor(Math.random() * baseLength * 0.3); + const glitchLine = " ".repeat(offset) + + Array.from({ length: lineLength }, () => + glitchChars[Math.floor(Math.random() * glitchChars.length)] + ).join(""); + lines.push(glitchLine); + } + return lines; + }; + + // Create container for animated glitch + const containerId = `glitch-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`; + this.adapter.printHTML( + `
` + ); + + const container = this.adapter.terminal.output.querySelector(`#${containerId}`); + if (!container) return; + + // Animation loop + const startTime = Date.now(); + let finalLinesAbove = []; + let finalLinesBelow = []; + + const animate = () => { + const elapsed = Date.now() - startTime; + + if (elapsed >= duration) { + // Final state - show original text with minimal glitch, keep infection lines + const finalGlitch = generateGlitch(text, intensity * 0.1); + + let output = ""; + finalLinesAbove.forEach(line => { + output += `
${line}
`; + }); + output += `
${finalGlitch}
`; + finalLinesBelow.forEach(line => { + output += `
${line}
`; + }); + + container.innerHTML = output; + return; + } + + // Current glitch intensity (ramps up then down) + const progress = elapsed / duration; + const currentIntensity = intensity * Math.sin(progress * Math.PI); + + // Generate infected lines above + const linesAbove = generateInfectionLines(text.length); + const linesBelow = generateInfectionLines(text.length); + + // Store for final state + finalLinesAbove = linesAbove; + finalLinesBelow = linesBelow; + + // Generate glitched main text + const glitchedText = generateGlitch(text, currentIntensity); + + // Build output + let output = ""; + linesAbove.forEach(line => { + output += `
${line}
`; + }); + output += `
${glitchedText}
`; + linesBelow.forEach(line => { + output += `
${line}
`; + }); + + container.innerHTML = output; + + // Continue animation + setTimeout(animate, speed); + }; + + // Start animation + animate(); + + // Wait for animation to complete + await this._sleep(duration); + } } diff --git a/assets/js/games/games/boxing-day.js b/assets/js/games/games/boxing-day.js index e52334b..d6a63a6 100644 --- a/assets/js/games/games/boxing-day.js +++ b/assets/js/games/games/boxing-day.js @@ -34,6 +34,7 @@ const boxingDayGame = { read_new_message: false, found_number: false, dialed_lighthouse: false, + seen_archive_glitch: false, // deletion flags (this needs to persist across game sessions somehow... TBD) archives_deleted: false, @@ -573,12 +574,12 @@ const boxingDayGame = { "", "---", { text: "Reply from: NightWatchman [SYSOP]", className: "warning" }, - "Looking into it. Please forward any suspicious messages.", - "And don't dial any numbers you don't recognize.", + " Looking into it. Please forward any suspicious messages.", + " And don't dial any numbers you don't recognize.", "", "---", { text: "Reply from: [DELETED USER]", className: "error" }, - "[This post cannot be accessed]", + " [This post cannot be accessed]", "", { type: "delay", ms: 1000 }, { @@ -621,15 +622,26 @@ const boxingDayGame = { }, board_archives: { - title: "The Archives", + // title: "The Archives", content: [ - "═══ THE ARCHIVES ═══", - { text: "Historical posts - Read only", className: "info" }, - "", - " [1998] The Lighthouse Project - NightWatchman", - " [1999] Frequencies and Patterns - Signal_Lost", - " [1999] RE: Has anyone heard from Keeper? - Anonymous", - "", + { + type: "table", + title: "THE ARCHIVES", + headers: ["#", "SUBJECT", "OP", "LAST"], + rows: [ + ["1", "The Lighthouse Project", "NightWatchman", "1998"], + ["2", "Frequencies and Patterns", "Signal_Lost", "1999"], + ["3", "RE: Has anyone heard from Keeper?", "[UNKNOWN]", "1999"], + ], + widths: [4, 35, 16, 8], + align: ["right", "left", "right", "left"], + style: "single", + }, + { + text: "Historical posts, read only...", + italic: true, + className: "info", + }, { condition: { not: "visited.archive_warning" }, content: [ @@ -655,14 +667,17 @@ const boxingDayGame = { }, archive_lighthouse: { - title: "The Lighthouse Project", + //title: "The Lighthouse Project", content: [ - "═══ The Lighthouse Project ═══", { - text: "Posted by: NightWatchman - November 15, 1998", - className: "info", + type: "table", + title: "The Lighthouse Project", + headers: ["FROM", "TO", "DATE"], + rows: [["NightWatchman [SYSOP]", "All", "15/11/98"]], + widths: [25, 15, 10], + align: ["left", "left", "left"], + style: "single", }, - "", "Some of you have asked about the secondary BBS.", "Yes, it exists. No, I can't give you the number.", "", @@ -670,14 +685,13 @@ const boxingDayGame = { "He said he found something in the noise between stations.", "Patterns that shouldn't exist.", "", - "I hosted his board as a favor.", + "I set up his board as a favor.", "Then one day, he stopped logging in.", "", "The board is still there. Still running.", "I check it sometimes. The files he left behind...", "", "Some doors are better left closed.", - "", { text: "- NW", className: "info" }, ], options: [{ text: "Back", next: "board_archives" }], @@ -710,10 +724,17 @@ const boxingDayGame = { }, archive_keeper: { - title: "RE: Has anyone heard from Keeper?", + //title: "RE: Has anyone heard from Keeper?", content: [ - "═══ RE: Has anyone heard from Keeper? ═══", - { text: "Posted by: Anonymous - December 20, 1999", className: "info" }, + { + type: "table", + title: "RE: Has anyone heard from Keeper?", + headers: ["FROM", "TO", "DATE"], + rows: [["[UNKNOWN]", "All", "20/12/99"]], + widths: [25, 15, 10], + align: ["left", "left", "left"], + style: "single", + }, "", "He's still there.", "In The Lighthouse.", @@ -722,17 +743,61 @@ const boxingDayGame = { "The cascade is ready.", "It just needs carriers.", "", - "555-0237", + { + type: "glitch", + text: "ERROR: MEMORY FAULT AT 0x555f0237", + intensity: 0.7, + spread: 0, + speed: 200, + duration: 2000, + className: "error glitch-text", + }, "", "Before midnight on the 31st.", "The alignment only happens once.", "", + { text: "[This post was flagged for removal but persists]", className: "error", }, + { + html: true, + text: "

", + }, + { + condition: { not: "seen_archive_glitch" }, + content: [ + { + text: "What the hell was that...", + italic: true, + className: "info", + }, + ], + else: [ + { + text: "The glitch persists...", + italic: true, + className: "info", + }, + ], + }, + { + condition: "found_number", + content: { + text: "The memory location looks oddly like the phone number... 555-0237", + italic: true, + className: "warning", + }, + }, + ], + onAfterRender: [ + // Decided to move the phone number out of discovery here.. + // Not sure if it should be found in two places + // Message should be enough, surely? + // { set: "found_number", value: true }, + { set: "seen_archive_glitch", value: true }, ], - onEnter: [{ set: "found_number", value: true }], options: [{ text: "Back", next: "board_archives" }], }, diff --git a/assets/js/games/games/test-adventure.js b/assets/js/games/games/test-adventure.js index e29cecf..1605c23 100644 --- a/assets/js/games/games/test-adventure.js +++ b/assets/js/games/games/test-adventure.js @@ -62,9 +62,56 @@ const testAdventureGame = { condition: { not: { path: "visited.cursor-talk" } }, next: "cursor-talk", }, + { text: "Test glitch effect", next: "glitch-demo" }, ], }, + "glitch-demo": { + title: "Glitch Effect Demo", + content: [ + "The terminal screen begins to distort...", + { type: "delay", ms: 800 }, + "", + { + type: "glitch", + text: "REALITY CORRUPTING", + intensity: 0.5, + spread: 3, + duration: 2500, + }, + "", + { type: "delay", ms: 500 }, + "The corruption spreads across nearby lines...", + { type: "delay", ms: 600 }, + "", + { + type: "glitch", + text: "ERROR: MEMORY FAULT AT 0x7FFFFFFF", + intensity: 0.7, + spread: 4, + speed: 40, + duration: 3000, + className: "error glitch-text", + }, + "", + { type: "delay", ms: 500 }, + "A subtle glitch flickers briefly...", + { type: "delay", ms: 400 }, + "", + { + type: "glitch", + text: "Connection unstable", + intensity: 0.2, + spread: 1, + duration: 1500, + }, + "", + { type: "delay", ms: 300 }, + "The screen stabilizes again.", + ], + options: [{ text: "Back to start", next: "start" }], + }, + "look-around": { title: "Searching...", content: ["You search the area carefully...", { type: "delay", ms: 500 }], diff --git a/assets/js/games/glitch-example.md b/assets/js/games/glitch-example.md new file mode 100644 index 0000000..0baf623 --- /dev/null +++ b/assets/js/games/glitch-example.md @@ -0,0 +1,100 @@ +# Glitch Content Type - Usage Guide + +The `glitch` content type creates an animated glitching text effect that makes text appear to corrupt and "infect" surrounding lines with random glitch characters. + +## Basic Usage + +```javascript +{ + type: "glitch", + text: "SYSTEM CORRUPTED" +} +``` + +## Configuration Options + +### Required +- **text** (string): The text to glitch + +### Optional +- **intensity** (number, 0-1, default: 0.3): How much the text glitches. Higher = more characters replaced +- **spread** (number, default: 2): Number of "infection" lines to show above and below the main text +- **speed** (number, default: 50): Animation frame speed in milliseconds +- **duration** (number, default: 2000): How long the glitch effect lasts in milliseconds +- **className** (string, default: "glitch-text"): CSS class to apply to the container + +## Examples + +### Subtle Glitch +```javascript +{ + type: "glitch", + text: "Connection unstable...", + intensity: 0.2, + spread: 1, + duration: 1500 +} +``` + +### Intense Corruption +```javascript +{ + type: "glitch", + text: "ERROR: MEMORY FAULT", + intensity: 0.7, + spread: 4, + speed: 30, + duration: 3000, + className: "error glitch-text" +} +``` + +### Quick Flicker +```javascript +{ + type: "glitch", + text: "Reality fragmenting", + intensity: 0.4, + spread: 2, + speed: 25, + duration: 1000 +} +``` + +### In Scene Content +```javascript +content: [ + "The terminal screen begins to distort...", + { type: "delay", ms: 500 }, + { + type: "glitch", + text: "CASCADE.EXE EXECUTING", + intensity: 0.6, + spread: 3, + duration: 2500 + }, + { type: "delay", ms: 500 }, + "Something is very wrong." +] +``` + +## Visual Effect Description + +The glitch effect: +1. Replaces characters in the text with random glitch symbols (unicode blocks, special chars, etc.) +2. Creates random "infection" lines above and below the main text +3. Animates over time with a sine wave intensity (ramps up, then down) +4. Ends with the text showing minimal corruption + +The infection lines are offset randomly and contain random glitch characters, making it look like the corruption is spreading to surrounding content. + +## Character Pool + +The glitch uses a pool of: +- Block drawing characters (▓▒░█) +- Box drawing characters (║╬╣╠╔╗╚╝) +- Mathematical symbols (Ω∑∏∫√∂∆∇) +- Accented characters (É È Ê Ë Á À) +- Special symbols (¡¿‽※§¶†‡∞≈≠±) +- Combining diacritics (creates zalgo-like text) +- Standard symbols (!@#$%^&*)