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;
|
||||
}
|
||||
|
||||
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(
|
||||
`<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,
|
||||
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: "<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" }],
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -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 }],
|
||||
|
|
|
|||
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