Spaces:
Running
Running
File size: 22,672 Bytes
f9273e6 fc169c4 bb15901 fc169c4 f9273e6 bb15901 f9273e6 fc169c4 f9273e6 bb15901 f9273e6 fc169c4 f9273e6 bb15901 f9273e6 fc169c4 f9273e6 bb15901 5455f54 f9273e6 bb15901 f9273e6 fc169c4 bb15901 5455f54 f9273e6 bb15901 5455f54 f9273e6 bb15901 f9273e6 bb15901 f9273e6 bb15901 f9273e6 bb15901 f9273e6 bb15901 fc169c4 f9273e6 bb15901 f9273e6 bb15901 f9273e6 bb15901 fc169c4 bb15901 f9273e6 bb15901 fc169c4 bb15901 f9273e6 bb15901 f9273e6 bb15901 f9273e6 fc169c4 f9273e6 fc169c4 f9273e6 bb15901 f9273e6 fc169c4 bb15901 f9273e6 bb15901 fc169c4 bb15901 f9273e6 bb15901 fc169c4 f9273e6 bb15901 f9273e6 bb15901 f9273e6 bb15901 f9273e6 bb15901 f9273e6 bb15901 f9273e6 bb15901 fc169c4 bb15901 f9273e6 bb15901 f9273e6 bb15901 f9273e6 bb15901 fc169c4 f9273e6 bb15901 fc169c4 f9273e6 bb15901 f9273e6 bb15901 f9273e6 bb15901 fc169c4 f9273e6 bb15901 f9273e6 fc169c4 bb15901 fc169c4 f9273e6 bb15901 fc169c4 f9273e6 bb15901 f9273e6 bb15901 f9273e6 bb15901 f9273e6 bb15901 fc169c4 f9273e6 bb15901 f9273e6 bb15901 f9273e6 fc169c4 bb15901 fc169c4 bb15901 fc169c4 bb15901 fc169c4 bb15901 fc169c4 bb15901 f9273e6 bb15901 fc169c4 f9273e6 fc169c4 bb15901 f9273e6 bb15901 f9273e6 bb15901 fc169c4 bb15901 f9273e6 bb15901 f9273e6 bb15901 f9273e6 bb15901 fc169c4 bb15901 f9273e6 bb15901 f9273e6 bb15901 5455f54 bb15901 5455f54 bb15901 fc169c4 bb15901 f9273e6 bb15901 fc169c4 f9273e6 bb15901 f9273e6 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CMD Ingaze Reveal Animation</title>
<style>
/* Styles for the animation when embedded */
body { /* Removed html selector here, apply to body */
background-color: #000000; /* Black background for the animation area */
color: #00FF00; /* Bright green text */
font-family: 'Courier New', Courier, monospace; /* Classic CMD font */
margin: 0;
padding: 10px; /* Add some padding to the body itself for spacing */
/* overflow: hidden; Removed, let content dictate size */
/* height: 100%; Removed, problematic in iframes */
/* display: flex; Removed */
/* justify-content: center; Removed */
/* align-items: center; Removed */
}
#cmd-animation-container {
padding: 15px; /* Increased padding for better visual separation */
border: 2px solid #00AA00;
background-color: #080808; /* Dark background for the container */
box-shadow: 0 0 10px #00FF00;
border-radius: 8px;
box-sizing: border-box;
/* max-width: calc(100% - 20px); /* Retain max-width for responsiveness */
/* margin: 10px; /* Body padding handles spacing now */
text-align: center; /* Center the pre block if it's narrower */
}
pre#cmd-animation {
white-space: pre;
text-align: left; /* Text within pre should be left-aligned */
font-size: 13px;
line-height: 1.2;
margin: 0 auto; /* Center pre block if container is wider */
overflow-x: auto; /* Allow horizontal scroll if content is too wide */
color: #00FF00;
background-color: #080808; /* Match container background */
display: inline-block; /* Allow margin auto to work for centering */
min-width: 100px; /* Ensure it's not collapsed */
min-height: 50px; /* Ensure it's not collapsed */
/* The height will be determined by scene_height * line-height */
}
</style>
</head>
<body>
<div id="cmd-animation-container">
<pre id="cmd-animation">Loading Animation...</pre>
</div>
<script>
// --- Start of Script ---
console.log("SYNC ANIMATION (Updated HTML): Script execution started.");
// --- Configuration ---
const scene_width = 65; // Width of the animation scene in characters
const scene_height = 22; // Height of the animation scene in lines
const frameDuration = 150; // Duration of each frame in milliseconds
const MAX_DATA_PARTICLES = 100; // Maximum number of data particles
const FLOOR_LEVEL = scene_height - 1; // Y-coordinate of the floor
// --- ASCII Art Definitions ---
const stick_man_art_normal = [" O ", " /|\\ ", " / \\ "];
const stick_man_art_walk_1 = [" O ", " /|\\ ", " / > "];
const stick_man_art_walk_2 = [" O ", " /|\\ ", " < \\ "];
const stick_man_art_surprise = [" \\O/ ", " | ", " / \\ "];
const stick_man_art_gone = [" ", " ", " "]; // Art for when stickman disappears
const linked_in_art = ["+----+", "|i n |", "+----+"]; // LinkedIn logo
const linked_in_art_hit = ["x----x", "|BOOM|", "x----x"]; // LinkedIn logo when hit
const lightning_strike_segment = "\\"; // Character for lightning
const explosion_art_frames = [ // Frames for explosion animation
[" * ", " *#* ", " * "],[" @!% ", " @*#*& ", " X%O "],
[" $*~+@ ", "$#@!%*&"," X*O#~ ", " !+%$ "],[" ~ ", " +*% ", " $ "]
];
const ingaze_logo_art = [ // ASCII art for "INGAZE" logo
"IIIII N N GGG AAA ZZZZZ EEEEE", " I NN N G A A Z E ",
" I N N N G GG AAAAA Z EEE ", " I N NN G G A A Z E ",
"IIIII N N GGG A A ZZZZZ EEEEE"
];
const ingaze_logo_width = ingaze_logo_art[0].length;
const ingaze_logo_height = ingaze_logo_art.length;
// --- State Variables ---
let data_particles_state = []; // Array to hold current data particles
let current_lightning_y_state = -1; // Current Y position of lightning tip
/**
* Overlays ASCII art onto a base scene (array of strings).
* @param {string[]} baseLines - The base scene lines.
* @param {string[]} artLines - The ASCII art lines to overlay.
* @param {number} startX - The starting X coordinate for the art.
* @param {number} startY - The starting Y coordinate for the art.
* @param {boolean} [ignoreSpaces=true] - Whether to ignore spaces in the art.
*/
function overlay(baseLines, artLines, startX, startY, ignoreSpaces = true) {
artLines.forEach((artLine, i) => {
const y = startY + i;
if (y >= 0 && y < baseLines.length && artLine) { // Check if art line is within base scene bounds
let baseLineArr = baseLines[y].split('');
for (let j = 0; j < artLine.length; j++) {
const x = startX + j;
if (x >= 0 && x < baseLineArr.length) { // Check if art character is within line bounds
if (ignoreSpaces && artLine[j] === ' ') continue; // Skip spaces if specified
baseLineArr[x] = artLine[j];
}
}
baseLines[y] = baseLineArr.join('');
}
});
}
/**
* Draws a lightning bolt segment in the scene.
* @param {string[]} sceneLines - The current scene lines.
* @param {number} tipX - The X coordinate of the lightning tip.
* @param {number} tipY - The Y coordinate of the lightning tip.
* @param {number} length - The length of the lightning bolt.
*/
function drawLightningBoltInScene(sceneLines, tipX, tipY, length) {
for (let i = 0; i < length; i++) {
const y = tipY - i; // Lightning travels upwards from tip
const x = tipX + (i % 2 === 0 ? 0 : (i % 4 === 1 ? -1 : 1)); // Jagged path
if (y >= 0 && y < scene_height && x >= 0 && x < scene_width) {
let lineArr = sceneLines[y].split('');
if (x < lineArr.length && lineArr[x] === ' ') { // Check bounds and if space is empty
lineArr[x] = lightning_strike_segment;
sceneLines[y] = lineArr.join('');
}
}
}
}
/**
* Builds a single frame of the animation.
* @returns {string} The complete animation frame as a multi-line string.
*/
function buildSceneFrame(stickmanArt, stickmanPos, showLogo, currentLogoArt, currentLogoPos,
showLightningBolt, lightningTipX, lightningTipY, lightningLength,
currentExplosionArt, explosionPos,
showIngazeLogo, ingazeArt, ingazePos) {
// Initialize scene with empty lines
let sceneLines = Array(scene_height).fill(" ".repeat(scene_width));
// Draw data particles
data_particles_state.forEach(p => {
const px = Math.round(p.x);
const py = Math.round(p.y);
if (py >= 0 && py < sceneLines.length && px >= 0 && px < scene_width) {
let lineArr = sceneLines[py].split('');
if (px < lineArr.length && lineArr[px] === ' ') { // Check bounds and if space is empty
lineArr[px] = p.char;
sceneLines[py] = lineArr.join('');
}
}
});
// Overlay elements onto the scene
overlay(sceneLines, stickmanArt, stickmanPos.x, stickmanPos.y);
if (showLogo) overlay(sceneLines, currentLogoArt, currentLogoPos.x, currentLogoPos.y);
if (showLightningBolt && lightningTipY >=0) {
drawLightningBoltInScene(sceneLines, lightningTipX, lightningTipY, lightningLength);
}
if (currentExplosionArt && currentExplosionArt.length > 0) {
overlay(sceneLines, currentExplosionArt, explosionPos.x, explosionPos.y, false); // Don't ignore spaces for explosion
}
if (showIngazeLogo) overlay(sceneLines, ingazeArt, ingazePos.x, ingazePos.y);
return sceneLines.join('\n'); // Join lines into a single string for display
}
/**
* Spawns a new data particle (0 or 1) falling from the LinkedIn logo.
*/
function spawnNewDataParticle(logoX, logoY, logoWidth) {
if (data_particles_state.length >= MAX_DATA_PARTICLES) return; // Limit particle count
const char = Math.random() > 0.5 ? '1' : '0';
const x = logoX + 1 + Math.floor(Math.random() * (logoWidth - 2)); // Random X within logo
const y = logoY + linked_in_art.length; // Start below logo
const vy = 0.2 + Math.random() * 0.3; // Random vertical speed
data_particles_state.push({ char, x, y, vy, active: true });
}
/**
* Generates all frames for the entire animation sequence.
* @returns {string[]} An array of animation frames.
*/
function generateAnimationFrames() {
console.log("SYNC ANIMATION (Updated HTML): generateAnimationFrames() called.");
const sequence = [];
data_particles_state = []; // Reset particles for each generation
current_lightning_y_state = -1; // Reset lightning state
// Define dimensions and positions
const stickman_height = stick_man_art_normal.length;
const stickman_width = stick_man_art_normal[0].length;
const logo_width = linked_in_art[0].length;
const logo_height = linked_in_art.length;
const stickman_base_y = FLOOR_LEVEL - stickman_height;
const logo_base_y = stickman_base_y; // Align logo with stickman
const stickman_initial_pos = { x: 2, y: stickman_base_y };
const logo_initial_pos = { x: scene_width - logo_width - 15, y: logo_base_y };
const stickman_walk_target_x = Math.max(stickman_initial_pos.x + 1, logo_initial_pos.x - stickman_width - 1);
const ingaze_pos = {
x: Math.floor((scene_width - ingaze_logo_width) / 2),
y: Math.floor((scene_height - ingaze_logo_height) / 2)
};
const explosion_center_x = logo_initial_pos.x + Math.floor(logo_width / 2);
const explosion_center_y = logo_initial_pos.y + Math.floor(logo_height / 2);
// Phase 0: Stickman Walks towards LinkedIn logo
const walk_frames_count = Math.max(10, Math.floor(Math.abs(stickman_walk_target_x - stickman_initial_pos.x) / 1.0));
let current_stickman_x = stickman_initial_pos.x;
const walk_step_x = walk_frames_count > 0 ? (stickman_walk_target_x - stickman_initial_pos.x) / walk_frames_count : 0;
for (let i = 0; i < walk_frames_count; i++) {
current_stickman_x += walk_step_x;
const walk_art = (i % 4 < 2) ? stick_man_art_walk_1 : stick_man_art_walk_2; // Alternate walking art
sequence.push(buildSceneFrame(walk_art, { x: Math.round(current_stickman_x), y: stickman_base_y }, true, linked_in_art, logo_initial_pos, false,0,0,0, [], {}, false, [], {}));
}
current_stickman_x = stickman_walk_target_x; // Ensure exact target position
let current_stickman_pos = { x: Math.round(current_stickman_x), y: stickman_base_y };
// Phase 1: Pause before interaction
for (let i = 0; i < 3; i++) {
sequence.push(buildSceneFrame(stick_man_art_normal, current_stickman_pos, true, linked_in_art, logo_initial_pos, false,0,0,0, [], {}, false, [], {}));
}
// Phase 2: Shaking LinkedIn logo & Data Fall
let current_logo_pos_phase2 = { ...logo_initial_pos };
const shake_frames_count = 20;
for (let i = 0; i < shake_frames_count; i++) {
let logo_shake_adj = { x: 0, y: 0 };
if (i % 6 < 2) logo_shake_adj = { x: 1, y: 0 }; else if (i % 6 < 4) logo_shake_adj = { x: -1, y: 0 }; // Shake horizontally
current_logo_pos_phase2.x = logo_initial_pos.x + logo_shake_adj.x;
if (i % 3 === 0) spawnNewDataParticle(current_logo_pos_phase2.x, current_logo_pos_phase2.y, logo_width); // Spawn particles periodically
data_particles_state.forEach(p => { // Update particle positions
if (p.active) {
p.y += p.vy;
if (p.y >= FLOOR_LEVEL) { p.y = FLOOR_LEVEL; p.vy = 0; p.active = false; } // Particle hits floor
}
});
sequence.push(buildSceneFrame(stick_man_art_normal, current_stickman_pos, true, linked_in_art, current_logo_pos_phase2, false,0,0,0, [], {}, false, [], {}));
}
current_logo_pos_phase2 = { ...logo_initial_pos }; // Reset logo position
// Phase 3: Data Settles, Stickman Surprised
const settle_frames_count = 8;
for (let i = 0; i < settle_frames_count; i++) {
let stickmanArtPhase3 = (i < settle_frames_count / 2) ? stick_man_art_normal : stick_man_art_surprise; // Stickman gets surprised
data_particles_state.forEach(p => { // Continue settling particles
if (p.active) {
p.y += p.vy;
if (p.y >= FLOOR_LEVEL) { p.y = FLOOR_LEVEL; p.vy = 0; p.active = false; }
}
});
sequence.push(buildSceneFrame(stickmanArtPhase3, current_stickman_pos, true, linked_in_art, logo_initial_pos, false,0,0,0, [], {}, false, [], {}));
}
// Phase 4: Lightning Strike on LinkedIn logo
const lightning_target_y = logo_initial_pos.y;
const lightning_strike_frames_count = lightning_target_y + 2; // Frames for lightning to reach logo
const lightning_bolt_length = 4;
const lightning_tip_x_strike = logo_initial_pos.x + Math.floor(logo_width / 2); // Strike center of logo
for (let i = 0; i < lightning_strike_frames_count; i++) {
current_lightning_y_state = i;
let logo_art_to_use = linked_in_art;
if (current_lightning_y_state >= lightning_target_y) { // Lightning hits
logo_art_to_use = linked_in_art_hit;
current_lightning_y_state = lightning_target_y; // Keep lightning at target
}
sequence.push(buildSceneFrame(stick_man_art_surprise, current_stickman_pos, true, logo_art_to_use, logo_initial_pos, true, lightning_tip_x_strike, current_lightning_y_state, lightning_bolt_length, [], {}, false, [], {}));
}
current_lightning_y_state = -1; // Reset lightning
// Phase 5: Explosion of LinkedIn logo
const explosion_duration_per_frame = 2; // How many animation frames each explosion art frame lasts
let stickman_art_explosion = stick_man_art_surprise;
for (let i = 0; i < explosion_art_frames.length; i++) {
const explosion_art = explosion_art_frames[i];
const explosion_art_width = Math.max(...explosion_art.map(l => l.length));
const explosion_art_height = explosion_art.length;
const current_explosion_pos = {
x: explosion_center_x - Math.floor(explosion_art_width / 2),
y: explosion_center_y - Math.floor(explosion_art_height / 2)
};
for (let j = 0; j < explosion_duration_per_frame; j++) {
if (i === 0 && j === 0) { // First frame of explosion
data_particles_state = []; // Clear data particles
stickman_art_explosion = stick_man_art_gone; // Stickman disappears
}
sequence.push(buildSceneFrame(stickman_art_explosion, current_stickman_pos, false, [], {}, false,0,0,0, explosion_art, current_explosion_pos, false, [], {}));
}
}
// Phase 6: "Ingaze" Logo Reveal
const ingaze_reveal_pause_frames = 4; // Pause after explosion
for(let i=0; i < ingaze_reveal_pause_frames; i++) {
sequence.push(buildSceneFrame(stick_man_art_gone, current_stickman_pos, false, [], {}, false,0,0,0, [], {}, false, [], {}));
}
const ingaze_display_frames = 25; // How long Ingaze logo stays
for (let i = 0; i < ingaze_display_frames; i++) {
sequence.push(buildSceneFrame(stick_man_art_gone, current_stickman_pos, false, [], {}, false,0,0,0, [], {}, true, ingaze_logo_art, ingaze_pos));
}
console.log(`SYNC ANIMATION (Updated HTML): Generated ${sequence.length} frames.`);
return sequence;
}
// --- Animation Playback ---
const animationElement = document.getElementById('cmd-animation');
let currentFrameIndex = 0;
let animationIntervalId;
let allAnimationFrames = []; // To store all generated frames
/**
* Runs the animation loop, updating the text content of the animation element.
*/
function runAnimation() {
console.log("SYNC ANIMATION (Updated HTML): runAnimation() called.");
if (!animationElement) {
console.error("SYNC ANIMATION ERROR (Updated HTML): Animation element 'cmd-animation' not found in runAnimation.");
return;
}
if (allAnimationFrames.length === 0) {
console.error("SYNC ANIMATION ERROR (Updated HTML): Animation frames are empty. Cannot play animation.");
animationElement.textContent = "Error: No frames generated.";
return;
}
// Clear any existing interval to prevent multiple loops if re-initialized
if (animationIntervalId) {
clearInterval(animationIntervalId);
}
animationIntervalId = setInterval(() => {
if (allAnimationFrames[currentFrameIndex]) {
animationElement.textContent = allAnimationFrames[currentFrameIndex];
}
currentFrameIndex++;
if (currentFrameIndex >= allAnimationFrames.length) {
currentFrameIndex = 0; // Loop the animation
}
}, frameDuration);
console.log("SYNC ANIMATION (Updated HTML): Animation interval started.");
}
/**
* Initializes the animation: generates frames and starts playback.
*/
function initializeAnimation() {
console.log("SYNC ANIMATION (Updated HTML): initializeAnimation() called.");
if (!animationElement) {
// This is a fallback; DOMContentLoaded should prevent this.
// If it still happens, the element might not be in the DOM when script runs.
console.warn("SYNC ANIMATION WARNING (Updated HTML): Animation element not ready yet in initializeAnimation. Will retry shortly...");
setTimeout(initializeAnimation, 50); // Retry after a short delay
return;
}
animationElement.textContent = "Initializing frames..."; // Provide feedback
try {
console.log("SYNC ANIMATION (Updated HTML): Attempting to generate frames...");
allAnimationFrames = generateAnimationFrames(); // Generate all frames
if (allAnimationFrames.length > 0) {
animationElement.textContent = allAnimationFrames[0]; // Display the first frame
console.log("SYNC ANIMATION (Updated HTML): First frame set. Calling runAnimation().");
runAnimation(); // Start the animation loop
} else {
animationElement.textContent = "Error: Could not generate animation frames.";
console.error("SYNC ANIMATION ERROR (Updated HTML): Could not generate frames (frames array is empty).");
}
} catch (error) {
console.error("SYNC ANIMATION ERROR (Updated HTML): Error during animation generation or initial play:", error);
if(animationElement) animationElement.textContent = "Error initializing animation: " + error.message;
}
}
// --- Script Entry Point ---
console.log("SYNC ANIMATION (Updated HTML): Adding DOMContentLoaded listener or initializing directly.");
// Wait for the DOM to be fully loaded before initializing the animation
if (document.readyState === "loading") { // Document is still loading
document.addEventListener('DOMContentLoaded', () => {
console.log("SYNC ANIMATION (Updated HTML): DOMContentLoaded event fired.");
initializeAnimation();
});
} else { // Document has already loaded (interactive or complete)
console.log("SYNC ANIMATION (Updated HTML): DOM already loaded or interactive. Calling initializeAnimation via setTimeout.");
// Use setTimeout to ensure this runs after the current script block and DOM is settled.
setTimeout(initializeAnimation, 0);
}
// Cleanup when the page (or iframe content) is unloaded
window.addEventListener('unload', () => {
console.log("SYNC ANIMATION (Updated HTML): Unload event. Clearing interval.");
if (animationIntervalId) {
clearInterval(animationIntervalId);
}
});
console.log("SYNC ANIMATION (Updated HTML): Script execution finished.");
// --- End of Script ---
</script>
</body>
</html>
|