pupdates
This commit is contained in:
parent
3e2d6c6a5c
commit
cd58c07c6b
4 changed files with 362 additions and 23 deletions
|
|
@ -173,6 +173,11 @@ class SceneManager {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (block.type === "glitch") {
|
||||||
|
await this._renderGlitch(block);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Text with optional className (supports html: true for HTML content)
|
// Text with optional className (supports html: true for HTML content)
|
||||||
if (block.text !== undefined) {
|
if (block.text !== undefined) {
|
||||||
if (block.html) {
|
if (block.html) {
|
||||||
|
|
@ -611,4 +616,126 @@ class SceneManager {
|
||||||
await Promise.all(fadePromises);
|
await Promise.all(fadePromises);
|
||||||
this.activeSounds.clear();
|
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(
|
||||||
|
`<div id="${containerId}" class="${className}"></div>`
|
||||||
|
);
|
||||||
|
|
||||||
|
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 += `<div class="glitch-line glitch-above">${line}</div>`;
|
||||||
|
});
|
||||||
|
output += `<div class="glitch-line glitch-main">${finalGlitch}</div>`;
|
||||||
|
finalLinesBelow.forEach(line => {
|
||||||
|
output += `<div class="glitch-line glitch-below">${line}</div>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
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 += `<div class="glitch-line glitch-above">${line}</div>`;
|
||||||
|
});
|
||||||
|
output += `<div class="glitch-line glitch-main">${glitchedText}</div>`;
|
||||||
|
linesBelow.forEach(line => {
|
||||||
|
output += `<div class="glitch-line glitch-below">${line}</div>`;
|
||||||
|
});
|
||||||
|
|
||||||
|
container.innerHTML = output;
|
||||||
|
|
||||||
|
// Continue animation
|
||||||
|
setTimeout(animate, speed);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start animation
|
||||||
|
animate();
|
||||||
|
|
||||||
|
// Wait for animation to complete
|
||||||
|
await this._sleep(duration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ const boxingDayGame = {
|
||||||
read_new_message: false,
|
read_new_message: false,
|
||||||
found_number: false,
|
found_number: false,
|
||||||
dialed_lighthouse: false,
|
dialed_lighthouse: false,
|
||||||
|
seen_archive_glitch: false,
|
||||||
|
|
||||||
// deletion flags (this needs to persist across game sessions somehow... TBD)
|
// deletion flags (this needs to persist across game sessions somehow... TBD)
|
||||||
archives_deleted: false,
|
archives_deleted: false,
|
||||||
|
|
@ -573,12 +574,12 @@ const boxingDayGame = {
|
||||||
"",
|
"",
|
||||||
"---",
|
"---",
|
||||||
{ text: "Reply from: NightWatchman [SYSOP]", className: "warning" },
|
{ text: "Reply from: NightWatchman [SYSOP]", className: "warning" },
|
||||||
"Looking into it. Please forward any suspicious messages.",
|
" Looking into it. Please forward any suspicious messages.",
|
||||||
"And don't dial any numbers you don't recognize.",
|
" And don't dial any numbers you don't recognize.",
|
||||||
"",
|
"",
|
||||||
"---",
|
"---",
|
||||||
{ text: "Reply from: [DELETED USER]", className: "error" },
|
{ text: "Reply from: [DELETED USER]", className: "error" },
|
||||||
"[This post cannot be accessed]",
|
" [This post cannot be accessed]",
|
||||||
"",
|
"",
|
||||||
{ type: "delay", ms: 1000 },
|
{ type: "delay", ms: 1000 },
|
||||||
{
|
{
|
||||||
|
|
@ -621,15 +622,26 @@ const boxingDayGame = {
|
||||||
},
|
},
|
||||||
|
|
||||||
board_archives: {
|
board_archives: {
|
||||||
title: "The Archives",
|
// title: "The Archives",
|
||||||
content: [
|
content: [
|
||||||
"═══ THE ARCHIVES ═══",
|
{
|
||||||
{ text: "Historical posts - Read only", className: "info" },
|
type: "table",
|
||||||
"",
|
title: "THE ARCHIVES",
|
||||||
" [1998] The Lighthouse Project - NightWatchman",
|
headers: ["#", "SUBJECT", "OP", "LAST"],
|
||||||
" [1999] Frequencies and Patterns - Signal_Lost",
|
rows: [
|
||||||
" [1999] RE: Has anyone heard from Keeper? - Anonymous",
|
["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" },
|
condition: { not: "visited.archive_warning" },
|
||||||
content: [
|
content: [
|
||||||
|
|
@ -655,14 +667,17 @@ const boxingDayGame = {
|
||||||
},
|
},
|
||||||
|
|
||||||
archive_lighthouse: {
|
archive_lighthouse: {
|
||||||
title: "The Lighthouse Project",
|
//title: "The Lighthouse Project",
|
||||||
content: [
|
content: [
|
||||||
"═══ The Lighthouse Project ═══",
|
|
||||||
{
|
{
|
||||||
text: "Posted by: NightWatchman - November 15, 1998",
|
type: "table",
|
||||||
className: "info",
|
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.",
|
"Some of you have asked about the secondary BBS.",
|
||||||
"Yes, it exists. No, I can't give you the number.",
|
"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.",
|
"He said he found something in the noise between stations.",
|
||||||
"Patterns that shouldn't exist.",
|
"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.",
|
"Then one day, he stopped logging in.",
|
||||||
"",
|
"",
|
||||||
"The board is still there. Still running.",
|
"The board is still there. Still running.",
|
||||||
"I check it sometimes. The files he left behind...",
|
"I check it sometimes. The files he left behind...",
|
||||||
"",
|
"",
|
||||||
"Some doors are better left closed.",
|
"Some doors are better left closed.",
|
||||||
"",
|
|
||||||
{ text: "- NW", className: "info" },
|
{ text: "- NW", className: "info" },
|
||||||
],
|
],
|
||||||
options: [{ text: "Back", next: "board_archives" }],
|
options: [{ text: "Back", next: "board_archives" }],
|
||||||
|
|
@ -710,10 +724,17 @@ const boxingDayGame = {
|
||||||
},
|
},
|
||||||
|
|
||||||
archive_keeper: {
|
archive_keeper: {
|
||||||
title: "RE: Has anyone heard from Keeper?",
|
//title: "RE: Has anyone heard from Keeper?",
|
||||||
content: [
|
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.",
|
"He's still there.",
|
||||||
"In The Lighthouse.",
|
"In The Lighthouse.",
|
||||||
|
|
@ -722,17 +743,61 @@ const boxingDayGame = {
|
||||||
"The cascade is ready.",
|
"The cascade is ready.",
|
||||||
"It just needs carriers.",
|
"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.",
|
"Before midnight on the 31st.",
|
||||||
"The alignment only happens once.",
|
"The alignment only happens once.",
|
||||||
"",
|
"",
|
||||||
|
|
||||||
{
|
{
|
||||||
text: "[This post was flagged for removal but persists]",
|
text: "[This post was flagged for removal but persists]",
|
||||||
className: "error",
|
className: "error",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
html: true,
|
||||||
|
text: "<br /><br />",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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" }],
|
options: [{ text: "Back", next: "board_archives" }],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,9 +62,56 @@ const testAdventureGame = {
|
||||||
condition: { not: { path: "visited.cursor-talk" } },
|
condition: { not: { path: "visited.cursor-talk" } },
|
||||||
next: "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": {
|
"look-around": {
|
||||||
title: "Searching...",
|
title: "Searching...",
|
||||||
content: ["You search the area carefully...", { type: "delay", ms: 500 }],
|
content: ["You search the area carefully...", { type: "delay", ms: 500 }],
|
||||||
|
|
|
||||||
100
assets/js/games/glitch-example.md
Normal file
100
assets/js/games/glitch-example.md
Normal file
|
|
@ -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 (!@#$%^&*)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue