mirror of
https://github.com/timmypidashev/web.git
synced 2026-04-14 11:03:50 +00:00
Update background animation to be more fluid and natural
This commit is contained in:
@@ -30,9 +30,9 @@ interface BackgroundProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const CELL_SIZE = 25;
|
const CELL_SIZE = 25;
|
||||||
const TRANSITION_SPEED = 0.1;
|
const TRANSITION_SPEED = 0.05; // Reduced from 0.1 for slower animations
|
||||||
const SCALE_SPEED = 0.15;
|
const SCALE_SPEED = 0.05; // Reduced from 0.15 for slower animations
|
||||||
const CYCLE_FRAMES = 120;
|
const CYCLE_FRAMES = 180; // Increased from 120 to give more time for transitions
|
||||||
const INITIAL_DENSITY = 0.15;
|
const INITIAL_DENSITY = 0.15;
|
||||||
const SIDEBAR_WIDTH = 240;
|
const SIDEBAR_WIDTH = 240;
|
||||||
|
|
||||||
@@ -119,6 +119,8 @@ const Background: React.FC<BackgroundProps> = ({
|
|||||||
const col = (x + i + grid.cols) % grid.cols;
|
const col = (x + i + grid.cols) % grid.cols;
|
||||||
const row = (y + j + grid.rows) % grid.rows;
|
const row = (y + j + grid.rows) % grid.rows;
|
||||||
|
|
||||||
|
// Only count cells that are actually alive according to the game state
|
||||||
|
// Not cells that are just visually transitioning
|
||||||
if (grid.cells[col][row].alive) {
|
if (grid.cells[col][row].alive) {
|
||||||
neighbors.count++;
|
neighbors.count++;
|
||||||
neighbors.colors.push(grid.cells[col][row].color);
|
neighbors.colors.push(grid.cells[col][row].color);
|
||||||
@@ -144,11 +146,13 @@ const Background: React.FC<BackgroundProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const computeNextState = (grid: Grid) => {
|
const computeNextState = (grid: Grid) => {
|
||||||
|
// First, calculate the next state for all cells based on standard rules
|
||||||
for (let i = 0; i < grid.cols; i++) {
|
for (let i = 0; i < grid.cols; i++) {
|
||||||
for (let j = 0; j < grid.rows; j++) {
|
for (let j = 0; j < grid.rows; j++) {
|
||||||
const cell = grid.cells[i][j];
|
const cell = grid.cells[i][j];
|
||||||
const { count, colors } = countNeighbors(grid, i, j);
|
const { count, colors } = countNeighbors(grid, i, j);
|
||||||
|
|
||||||
|
// Standard Conway's Game of Life rules
|
||||||
if (cell.alive) {
|
if (cell.alive) {
|
||||||
cell.next = count === 2 || count === 3;
|
cell.next = count === 2 || count === 3;
|
||||||
} else {
|
} else {
|
||||||
@@ -157,14 +161,30 @@ const Background: React.FC<BackgroundProps> = ({
|
|||||||
cell.color = averageColors(colors);
|
cell.color = averageColors(colors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then, set up animations for cells that need to change state
|
||||||
|
for (let i = 0; i < grid.cols; i++) {
|
||||||
|
for (let j = 0; j < grid.rows; j++) {
|
||||||
|
const cell = grid.cells[i][j];
|
||||||
|
|
||||||
if (cell.alive !== cell.next && !cell.transitioning) {
|
if (cell.alive !== cell.next && !cell.transitioning) {
|
||||||
cell.transitioning = true;
|
cell.transitioning = true;
|
||||||
cell.transitionComplete = false;
|
cell.transitionComplete = false;
|
||||||
|
|
||||||
|
// Random delay for staggered animation effect
|
||||||
|
const delay = Math.random() * 800;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
if (!cell.next) {
|
if (!cell.next) {
|
||||||
cell.targetScale = 0;
|
cell.targetScale = 0;
|
||||||
cell.targetOpacity = 0;
|
cell.targetOpacity = 0;
|
||||||
|
} else {
|
||||||
|
cell.targetScale = 1;
|
||||||
|
cell.targetOpacity = 1;
|
||||||
}
|
}
|
||||||
|
}, delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,28 +195,24 @@ const Background: React.FC<BackgroundProps> = ({
|
|||||||
for (let j = 0; j < grid.rows; j++) {
|
for (let j = 0; j < grid.rows; j++) {
|
||||||
const cell = grid.cells[i][j];
|
const cell = grid.cells[i][j];
|
||||||
|
|
||||||
|
// Smooth transitions
|
||||||
cell.opacity += (cell.targetOpacity - cell.opacity) * TRANSITION_SPEED;
|
cell.opacity += (cell.targetOpacity - cell.opacity) * TRANSITION_SPEED;
|
||||||
cell.scale += (cell.targetScale - cell.scale) * SCALE_SPEED;
|
cell.scale += (cell.targetScale - cell.scale) * SCALE_SPEED;
|
||||||
|
|
||||||
if (cell.transitioning) {
|
if (cell.transitioning) {
|
||||||
if (!cell.next && cell.scale < 0.05) {
|
// When a cell is completely faded out, update its alive state
|
||||||
|
if (!cell.next && cell.opacity < 0.01 && cell.scale < 0.01) {
|
||||||
cell.alive = false;
|
cell.alive = false;
|
||||||
cell.transitioning = false;
|
cell.transitioning = false;
|
||||||
cell.transitionComplete = true;
|
cell.transitionComplete = true;
|
||||||
cell.scale = 0;
|
|
||||||
cell.opacity = 0;
|
cell.opacity = 0;
|
||||||
|
cell.scale = 0;
|
||||||
}
|
}
|
||||||
|
// When a new cell is born
|
||||||
else if (cell.next && !cell.alive && !cell.transitionComplete) {
|
else if (cell.next && !cell.alive && !cell.transitionComplete) {
|
||||||
cell.alive = true;
|
cell.alive = true;
|
||||||
cell.transitioning = false;
|
cell.transitioning = false;
|
||||||
cell.transitionComplete = true;
|
cell.transitionComplete = true;
|
||||||
cell.targetScale = 1;
|
|
||||||
cell.targetOpacity = 1;
|
|
||||||
}
|
|
||||||
else if (cell.next && !cell.alive && cell.transitionComplete) {
|
|
||||||
cell.transitioning = true;
|
|
||||||
cell.targetScale = 1;
|
|
||||||
cell.targetOpacity = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -270,6 +286,7 @@ const Background: React.FC<BackgroundProps> = ({
|
|||||||
frameCount.current++;
|
frameCount.current++;
|
||||||
|
|
||||||
if (gridRef.current) {
|
if (gridRef.current) {
|
||||||
|
// Every CYCLE_FRAMES, compute the next state
|
||||||
if (frameCount.current % CYCLE_FRAMES === 0) {
|
if (frameCount.current % CYCLE_FRAMES === 0) {
|
||||||
computeNextState(gridRef.current);
|
computeNextState(gridRef.current);
|
||||||
}
|
}
|
||||||
@@ -289,7 +306,8 @@ const Background: React.FC<BackgroundProps> = ({
|
|||||||
for (let i = 0; i < grid.cols; i++) {
|
for (let i = 0; i < grid.cols; i++) {
|
||||||
for (let j = 0; j < grid.rows; j++) {
|
for (let j = 0; j < grid.rows; j++) {
|
||||||
const cell = grid.cells[i][j];
|
const cell = grid.cells[i][j];
|
||||||
if (cell.opacity > 0.01) {
|
// Draw all transitioning cells, even if they're fading out
|
||||||
|
if ((cell.alive || cell.targetOpacity > 0) && cell.opacity > 0.01) {
|
||||||
const [r, g, b] = cell.color;
|
const [r, g, b] = cell.color;
|
||||||
ctx.fillStyle = `rgb(${r},${g},${b})`;
|
ctx.fillStyle = `rgb(${r},${g},${b})`;
|
||||||
ctx.globalAlpha = cell.opacity * 0.8;
|
ctx.globalAlpha = cell.opacity * 0.8;
|
||||||
@@ -336,7 +354,7 @@ const Background: React.FC<BackgroundProps> = ({
|
|||||||
clearTimeout(resizeTimeoutRef.current);
|
clearTimeout(resizeTimeoutRef.current);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, []); // Empty dependency array since we're managing state internally
|
}, [layout]); // Added layout as a dependency since it's used in the effect
|
||||||
|
|
||||||
const getContainerClasses = () => {
|
const getContainerClasses = () => {
|
||||||
if (layout === 'index') {
|
if (layout === 'index') {
|
||||||
|
|||||||
Reference in New Issue
Block a user