@reicek/neataptic-ts 0.1.21 → 0.1.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/agents/boundary-mapper.agent.md +29 -0
- package/.github/agents/docs-scout.agent.md +29 -0
- package/.github/agents/plan-scout.agent.md +29 -0
- package/.github/agents/solid-split.agent.md +138 -0
- package/.github/copilot-instructions.md +103 -0
- package/package.json +6 -3
- package/plans/ES2023 migration +13 -8
- package/plans/Evolution_Training_Interoperability_Contracts.md +1 -1
- package/plans/Interactive_Examples_and_Learning_Path.md +10 -2
- package/plans/Memory_Optimization.md +3 -3
- package/plans/README.md +63 -0
- package/plans/Roadmap.md +15 -3
- package/plans/asciiMaze_SOLID_split.done.md +130 -0
- package/plans/flappy_bird_SOLID_split.done.md +67 -0
- package/scripts/assets/theme.css +221 -34
- package/scripts/copy-examples.mjs +9 -5
- package/scripts/export-onnx.mjs +3 -3
- package/scripts/generate-bench-tables.mjs +10 -10
- package/scripts/generate-bench-tables.ts +10 -10
- package/scripts/generate-docs.ts +1415 -449
- package/scripts/render-docs-html.ts +15 -8
- package/src/README.md +101 -223
- package/src/architecture/README.md +57 -185
- package/src/architecture/layer/README.md +38 -38
- package/src/architecture/network/README.md +33 -31
- package/src/architecture/network/activate/README.md +77 -77
- package/src/architecture/network/connect/README.md +15 -13
- package/src/architecture/network/deterministic/README.md +7 -7
- package/src/architecture/network/evolve/README.md +44 -44
- package/src/architecture/network/gating/README.md +20 -20
- package/src/architecture/network/genetic/README.md +51 -51
- package/src/architecture/network/mutate/README.md +97 -97
- package/src/architecture/network/onnx/README.md +264 -264
- package/src/architecture/network/prune/README.md +39 -39
- package/src/architecture/network/remove/README.md +26 -26
- package/src/architecture/network/serialize/README.md +56 -56
- package/src/architecture/network/slab/README.md +61 -61
- package/src/architecture/network/standalone/README.md +24 -24
- package/src/architecture/network/stats/README.md +9 -9
- package/src/architecture/network/topology/README.md +46 -46
- package/src/architecture/network/training/README.md +21 -21
- package/src/methods/README.md +9 -87
- package/src/multithreading/README.md +8 -77
- package/src/multithreading/workers/README.md +2 -2
- package/src/multithreading/workers/browser/README.md +0 -6
- package/src/multithreading/workers/node/README.md +0 -3
- package/src/neat/README.md +562 -568
- package/src/utils/README.md +18 -18
- package/test/examples/asciiMaze/README.md +59 -59
- package/test/examples/asciiMaze/asciiMaze.e2e.test.ts +14 -9
- package/test/examples/asciiMaze/browser-entry/README.md +196 -0
- package/test/examples/asciiMaze/browser-entry/browser-entry.abort.services.ts +95 -0
- package/test/examples/asciiMaze/browser-entry/browser-entry.constants.ts +23 -0
- package/test/examples/asciiMaze/browser-entry/browser-entry.curriculum.services.ts +115 -0
- package/test/examples/asciiMaze/browser-entry/browser-entry.globals.services.ts +106 -0
- package/test/examples/asciiMaze/browser-entry/browser-entry.host.services.ts +157 -0
- package/test/examples/asciiMaze/browser-entry/browser-entry.services.ts +14 -0
- package/test/examples/asciiMaze/browser-entry/browser-entry.ts +129 -0
- package/test/examples/asciiMaze/browser-entry/browser-entry.types.ts +120 -0
- package/test/examples/asciiMaze/browser-entry/browser-entry.utils.ts +98 -0
- package/test/examples/asciiMaze/browser-entry.ts +10 -576
- package/test/examples/asciiMaze/dashboardManager/README.md +276 -0
- package/test/examples/asciiMaze/dashboardManager/archive/README.md +16 -0
- package/test/examples/asciiMaze/dashboardManager/archive/dashboardManager.archive.services.ts +267 -0
- package/test/examples/asciiMaze/dashboardManager/dashboardManager.constants.ts +35 -0
- package/test/examples/asciiMaze/dashboardManager/dashboardManager.services.ts +103 -0
- package/test/examples/asciiMaze/dashboardManager/dashboardManager.ts +181 -0
- package/test/examples/asciiMaze/dashboardManager/dashboardManager.types.ts +267 -0
- package/test/examples/asciiMaze/dashboardManager/dashboardManager.utils.ts +254 -0
- package/test/examples/asciiMaze/dashboardManager/live/README.md +14 -0
- package/test/examples/asciiMaze/dashboardManager/live/dashboardManager.live.services.ts +264 -0
- package/test/examples/asciiMaze/dashboardManager/telemetry/README.md +47 -0
- package/test/examples/asciiMaze/dashboardManager/telemetry/dashboardManager.telemetry.services.ts +513 -0
- package/test/examples/asciiMaze/dashboardManager.ts +13 -2335
- package/test/examples/asciiMaze/evolutionEngine/README.md +1058 -0
- package/test/examples/asciiMaze/evolutionEngine/curriculumPhase.ts +90 -0
- package/test/examples/asciiMaze/evolutionEngine/engineState.constants.ts +36 -0
- package/test/examples/asciiMaze/evolutionEngine/engineState.ts +58 -513
- package/test/examples/asciiMaze/evolutionEngine/engineState.types.ts +212 -0
- package/test/examples/asciiMaze/evolutionEngine/engineState.utils.ts +301 -0
- package/test/examples/asciiMaze/evolutionEngine/evolutionEngine.types.ts +445 -0
- package/test/examples/asciiMaze/evolutionEngine/evolutionLoop.ts +81 -50
- package/test/examples/asciiMaze/evolutionEngine/optionsAndSetup.ts +2 -4
- package/test/examples/asciiMaze/evolutionEngine/populationDynamics.ts +17 -33
- package/test/examples/asciiMaze/evolutionEngine/populationPruning.ts +1 -1
- package/test/examples/asciiMaze/evolutionEngine/rngAndTiming.ts +1 -2
- package/test/examples/asciiMaze/evolutionEngine/sampling.ts +1 -1
- package/test/examples/asciiMaze/evolutionEngine/scratchPools.ts +2 -5
- package/test/examples/asciiMaze/evolutionEngine/setupHelpers.ts +30 -37
- package/test/examples/asciiMaze/evolutionEngine/telemetryMetrics.ts +16 -58
- package/test/examples/asciiMaze/evolutionEngine/trainingWarmStart.ts +2 -2
- package/test/examples/asciiMaze/evolutionEngine.ts +55 -55
- package/test/examples/asciiMaze/fitness.ts +2 -2
- package/test/examples/asciiMaze/fitness.types.ts +65 -0
- package/test/examples/asciiMaze/interfaces.ts +64 -1352
- package/test/examples/asciiMaze/mazeMovement/README.md +356 -0
- package/test/examples/asciiMaze/mazeMovement/finalization/README.md +49 -0
- package/test/examples/asciiMaze/mazeMovement/finalization/mazeMovement.finalization.ts +138 -0
- package/test/examples/asciiMaze/mazeMovement/mazeMovement.constants.ts +101 -0
- package/test/examples/asciiMaze/mazeMovement/mazeMovement.services.ts +230 -0
- package/test/examples/asciiMaze/mazeMovement/mazeMovement.ts +299 -0
- package/test/examples/asciiMaze/mazeMovement/mazeMovement.types.ts +185 -0
- package/test/examples/asciiMaze/mazeMovement/mazeMovement.utils.ts +153 -0
- package/test/examples/asciiMaze/mazeMovement/policy/README.md +91 -0
- package/test/examples/asciiMaze/mazeMovement/policy/mazeMovement.policy.ts +467 -0
- package/test/examples/asciiMaze/mazeMovement/runtime/README.md +95 -0
- package/test/examples/asciiMaze/mazeMovement/runtime/mazeMovement.runtime.ts +354 -0
- package/test/examples/asciiMaze/mazeMovement/shaping/README.md +124 -0
- package/test/examples/asciiMaze/mazeMovement/shaping/mazeMovement.shaping.ts +459 -0
- package/test/examples/asciiMaze/mazeMovement.ts +12 -2978
- package/test/examples/flappy_bird/Trace-20260309T191949.json +24124 -0
- package/test/examples/flappy_bird/browser-entry/README.md +1129 -0
- package/test/examples/flappy_bird/browser-entry/browser-entry.host.utils.ts +4 -324
- package/test/examples/flappy_bird/browser-entry/browser-entry.network-view.utils.ts +6 -399
- package/test/examples/flappy_bird/browser-entry/browser-entry.playback.utils.ts +1 -717
- package/test/examples/flappy_bird/browser-entry/browser-entry.spawn.utils.ts +11 -31
- package/test/examples/flappy_bird/browser-entry/browser-entry.visualization.utils.ts +15 -893
- package/test/examples/flappy_bird/browser-entry/host/README.md +307 -0
- package/test/examples/flappy_bird/browser-entry/host/host.resize.service.ts +1 -295
- package/test/examples/flappy_bird/browser-entry/host/host.ts +562 -6
- package/test/examples/flappy_bird/browser-entry/host/resize/README.md +274 -0
- package/test/examples/flappy_bird/browser-entry/host/resize/host.resize.service.constants.ts +31 -0
- package/test/examples/flappy_bird/browser-entry/host/resize/host.resize.service.services.ts +360 -0
- package/test/examples/flappy_bird/browser-entry/host/resize/host.resize.service.ts +117 -0
- package/test/examples/flappy_bird/browser-entry/host/resize/host.resize.service.types.ts +63 -0
- package/test/examples/flappy_bird/browser-entry/host/resize/host.resize.service.utils.ts +250 -0
- package/test/examples/flappy_bird/browser-entry/network-view/README.md +399 -0
- package/test/examples/flappy_bird/browser-entry/network-view/network-view.topology.utils.ts +255 -0
- package/test/examples/flappy_bird/browser-entry/network-view/network-view.ts +802 -7
- package/test/examples/flappy_bird/browser-entry/playback/README.md +684 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/README.md +277 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/README.md +770 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/playback.background.ground-grid.cache.services.ts +178 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/playback.background.ground-grid.constants.ts +107 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/playback.background.ground-grid.geometry.utils.ts +518 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/playback.background.ground-grid.math.utils.ts +117 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/playback.background.ground-grid.pulse.utils.ts +233 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/playback.background.ground-grid.services.ts +211 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/playback.background.ground-grid.ts +48 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/playback.background.ground-grid.types.ts +212 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/ground-grid/playback.background.ground-grid.utils.ts +81 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/playback.background.cache.services.ts +96 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/playback.background.constants.ts +62 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/playback.background.services.ts +244 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/playback.background.ts +53 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/playback.background.types.ts +68 -0
- package/test/examples/flappy_bird/browser-entry/playback/background/playback.background.utils.ts +100 -0
- package/test/examples/flappy_bird/browser-entry/playback/frame-render/README.md +310 -0
- package/test/examples/flappy_bird/browser-entry/playback/frame-render/playback.frame-render.service.ts +92 -0
- package/test/examples/flappy_bird/browser-entry/playback/frame-render/playback.frame-render.services.ts +272 -0
- package/test/examples/flappy_bird/browser-entry/playback/frame-render/playback.frame-render.types.ts +39 -0
- package/test/examples/flappy_bird/browser-entry/playback/frame-render/playback.frame-render.utils.ts +493 -0
- package/test/examples/flappy_bird/browser-entry/playback/playback.constants.ts +1 -1
- package/test/examples/flappy_bird/browser-entry/playback/playback.frame-render.service.ts +4 -0
- package/test/examples/flappy_bird/browser-entry/playback/playback.snapshot.utils.ts +44 -0
- package/test/examples/flappy_bird/browser-entry/playback/playback.starfield.service.ts +39 -122
- package/test/examples/flappy_bird/browser-entry/playback/playback.starfield.services.ts +272 -0
- package/test/examples/flappy_bird/browser-entry/playback/playback.starfield.types.ts +62 -0
- package/test/examples/flappy_bird/browser-entry/playback/playback.starfield.utils.ts +11 -4
- package/test/examples/flappy_bird/browser-entry/playback/playback.ts +409 -8
- package/test/examples/flappy_bird/browser-entry/playback/playback.types.ts +4 -12
- package/test/examples/flappy_bird/browser-entry/runtime/README.md +235 -0
- package/test/examples/flappy_bird/browser-entry/runtime/runtime.evolution-launch.service.ts +45 -0
- package/test/examples/flappy_bird/browser-entry/runtime/runtime.lifecycle.service.ts +81 -0
- package/test/examples/flappy_bird/browser-entry/runtime/runtime.startup.service.ts +74 -0
- package/test/examples/flappy_bird/browser-entry/runtime/runtime.ts +31 -121
- package/test/examples/flappy_bird/browser-entry/runtime/runtime.types.ts +36 -0
- package/test/examples/flappy_bird/browser-entry/visualization/README.md +557 -0
- package/test/examples/flappy_bird/browser-entry/visualization/visualization.constants.ts +110 -0
- package/test/examples/flappy_bird/browser-entry/visualization/visualization.draw.service.ts +957 -19
- package/test/examples/flappy_bird/browser-entry/visualization/visualization.legend.utils.ts +138 -3
- package/test/examples/flappy_bird/browser-entry/visualization/visualization.topology.utils.ts +3 -27
- package/test/examples/flappy_bird/browser-entry/visualization/visualization.ts +1 -23
- package/test/examples/flappy_bird/browser-entry/worker-channel/README.md +156 -0
- package/test/examples/flappy_bird/constants/README.md +1179 -0
- package/test/examples/flappy_bird/constants/constants.network-view.ts +24 -0
- package/test/examples/flappy_bird/constants/constants.palette.ts +7 -0
- package/test/examples/flappy_bird/constants/constants.starfield.ts +78 -3
- package/test/examples/flappy_bird/environment/README.md +143 -0
- package/test/examples/flappy_bird/environment/environment.observation.utils.ts +1 -19
- package/test/examples/flappy_bird/environment/environment.step.service.ts +3 -66
- package/test/examples/flappy_bird/evaluation/README.md +130 -0
- package/test/examples/flappy_bird/evaluation/evaluation.fitness.utils.ts +1 -1
- package/test/examples/flappy_bird/evaluation/evaluation.rollout.service.ts +5 -375
- package/test/examples/flappy_bird/evaluation/rollout/README.md +291 -0
- package/test/examples/flappy_bird/evaluation/rollout/evaluation.rollout.constants.ts +30 -0
- package/test/examples/flappy_bird/evaluation/rollout/evaluation.rollout.service.ts +58 -0
- package/test/examples/flappy_bird/evaluation/rollout/evaluation.rollout.services.ts +310 -0
- package/test/examples/flappy_bird/evaluation/rollout/evaluation.rollout.types.ts +56 -0
- package/test/examples/flappy_bird/evaluation/rollout/evaluation.rollout.utils.ts +368 -0
- package/test/examples/flappy_bird/flappy-evolution-worker/README.md +618 -0
- package/test/examples/flappy_bird/flappy-evolution-worker/flappy-evolution-worker.playback.service.ts +7 -7
- package/test/examples/flappy_bird/flappy-evolution-worker/flappy-evolution-worker.simulation.frame.service.ts +364 -0
- package/test/examples/flappy_bird/flappy-evolution-worker/flappy-evolution-worker.simulation.types.ts +14 -0
- package/test/examples/flappy_bird/flappy-evolution-worker/flappy-evolution-worker.simulation.utils.ts +4 -201
- package/test/examples/flappy_bird/flappy-evolution-worker/flappy-evolution-worker.ts +184 -345
- package/test/examples/flappy_bird/flappy-evolution-worker/flappy-evolution-worker.warm-start.service.ts +291 -0
- package/test/examples/flappy_bird/flappy.simulation.shared.utils.ts +5 -0
- package/test/examples/flappy_bird/simulation-shared/README.md +417 -0
- package/test/examples/flappy_bird/simulation-shared/observation/README.md +183 -0
- package/test/examples/flappy_bird/simulation-shared/observation/observation.features.utils.ts +301 -0
- package/test/examples/flappy_bird/simulation-shared/observation/observation.ts +9 -0
- package/test/examples/flappy_bird/simulation-shared/observation/observation.vector.utils.ts +59 -0
- package/test/examples/flappy_bird/simulation-shared/simulation-shared.observation.utils.ts +5 -403
- package/test/examples/flappy_bird/simulation-shared/simulation-shared.spawn.utils.ts +20 -6
- package/test/examples/flappy_bird/{evaluation/evaluation.statistics.utils.ts → simulation-shared/simulation-shared.statistics.utils.ts} +23 -8
- package/test/examples/flappy_bird/trainer/README.md +563 -0
- package/test/examples/flappy_bird/trainer/evaluation/README.md +199 -0
- package/test/examples/flappy_bird/trainer/evaluation/trainer.evaluation.service.constants.ts +9 -0
- package/test/examples/flappy_bird/trainer/evaluation/trainer.evaluation.service.services.ts +73 -0
- package/test/examples/flappy_bird/trainer/evaluation/trainer.evaluation.service.ts +165 -0
- package/test/examples/flappy_bird/trainer/evaluation/trainer.evaluation.service.types.ts +25 -0
- package/test/examples/flappy_bird/trainer/evaluation/trainer.evaluation.service.utils.ts +161 -0
- package/test/examples/flappy_bird/trainer/trainer.evaluation.service.ts +13 -0
- package/test/examples/flappy_bird/trainer/trainer.report.service.services.ts +181 -0
- package/test/examples/flappy_bird/trainer/trainer.report.service.ts +126 -0
- package/test/examples/flappy_bird/trainer/trainer.selection.utils.ts +89 -0
- package/test/examples/flappy_bird/trainer/trainer.ts +11 -553
- package/test/examples/flappy_bird/browser-entry/browser-entry.utils.ts +0 -12
- package/test/examples/flappy_bird/environment/environment.ts +0 -7
- package/test/examples/flappy_bird/evaluation/evaluation.ts +0 -7
- package/test/examples/flappy_bird/simulation-shared/simulation-shared.ts +0 -15
- package/test/examples/flappy_bird/trainer/trainer.statistics.utils.ts +0 -78
package/test/examples/flappy_bird/browser-entry/playback/frame-render/playback.frame-render.utils.ts
ADDED
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FLAPPY_BIRD_AURA_ALPHA,
|
|
3
|
+
FLAPPY_BIRD_AURA_BLUR_MULTIPLIER,
|
|
4
|
+
FLAPPY_BIRD_AURA_EXPAND_PX,
|
|
5
|
+
FLAPPY_BIRD_BODY_GLOW_BLUR_PX,
|
|
6
|
+
FLAPPY_BIRD_CHAMPION_EXTRA_GLOW_BLUR_PX,
|
|
7
|
+
FLAPPY_BIRD_CHAMPION_RED_GLOW_ALPHA,
|
|
8
|
+
FLAPPY_BIRD_CHAMPION_RED_GLOW_EXPAND_PX,
|
|
9
|
+
FLAPPY_BIRD_CHAMPION_SHINE_FILL_STYLE,
|
|
10
|
+
FLAPPY_BIRD_CHAMPION_SHINE_GLOW_COLOR,
|
|
11
|
+
FLAPPY_BIRD_RADIUS_PX,
|
|
12
|
+
FLAPPY_BIRD_SHINE_FILL_STYLE,
|
|
13
|
+
FLAPPY_BIRD_SHINE_INSET_RATIO,
|
|
14
|
+
FLAPPY_BIRD_SHINE_SIZE_RATIO,
|
|
15
|
+
FLAPPY_BIRD_WHITE_SHINE_GLOW_BLUR_PX,
|
|
16
|
+
FLAPPY_BIRD_WHITE_SHINE_GLOW_COLOR,
|
|
17
|
+
FLAPPY_BIRD_X_PX,
|
|
18
|
+
FLAPPY_LEADER_RING_GLOW_BLUR_PX,
|
|
19
|
+
FLAPPY_LEADER_RING_LINE_WIDTH_PX,
|
|
20
|
+
FLAPPY_LEADER_RING_RADIUS_OFFSET_PX,
|
|
21
|
+
FLAPPY_NEON_PALETTE,
|
|
22
|
+
FLAPPY_NON_CHAMPION_OPACITY,
|
|
23
|
+
FLAPPY_PIPE_SPEED_PX_PER_FRAME,
|
|
24
|
+
FLAPPY_TRAIL_LINE_WIDTH_PX,
|
|
25
|
+
FLAPPY_TRAIL_MIN_HORIZONTAL_SEGMENT_PX,
|
|
26
|
+
FLAPPY_TRAIL_MIN_VERTICAL_SEGMENT_PX,
|
|
27
|
+
FLAPPY_TRAIL_OPACITY_FACTOR,
|
|
28
|
+
} from '../../../constants/constants';
|
|
29
|
+
import type { TrailPoint } from '../../browser-entry.types';
|
|
30
|
+
import { resolveBirdRenderStyle } from '../playback.render.utils';
|
|
31
|
+
import {
|
|
32
|
+
resolveEdgeOpacityFactor,
|
|
33
|
+
resolveTrailLifetimeOpacityFactor,
|
|
34
|
+
} from '../playback.trail.utils';
|
|
35
|
+
import type { PlaybackEdgeBounds } from '../playback.types';
|
|
36
|
+
import type {
|
|
37
|
+
PlaybackBirdGeometry,
|
|
38
|
+
PlaybackTrailRenderStyle,
|
|
39
|
+
} from './playback.frame-render.types';
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Draws one active bird body, glow, shine, and leader ring.
|
|
43
|
+
*
|
|
44
|
+
* @param context - Canvas 2D drawing context.
|
|
45
|
+
* @param birdYPx - Bird vertical position in world pixels.
|
|
46
|
+
* @param birdIndex - Index of the bird being rendered.
|
|
47
|
+
* @param championBirdIndex - Champion index for the current frame.
|
|
48
|
+
* @returns Nothing.
|
|
49
|
+
*/
|
|
50
|
+
export function renderPlaybackBird(
|
|
51
|
+
context: CanvasRenderingContext2D,
|
|
52
|
+
birdYPx: number,
|
|
53
|
+
birdIndex: number,
|
|
54
|
+
championBirdIndex: number,
|
|
55
|
+
): void {
|
|
56
|
+
// Step 1: Resolve geometry and style contracts for the current bird.
|
|
57
|
+
const birdGeometry = resolvePlaybackBirdGeometry(birdYPx);
|
|
58
|
+
const birdRenderStyle = resolveBirdRenderStyle(birdIndex, championBirdIndex);
|
|
59
|
+
|
|
60
|
+
// Step 2: Draw champion-only glow passes behind the bird body.
|
|
61
|
+
drawPlaybackBirdChampionAura(context, birdGeometry, birdRenderStyle);
|
|
62
|
+
drawPlaybackBirdChampionGlowPlate(context, birdGeometry, birdRenderStyle);
|
|
63
|
+
|
|
64
|
+
// Step 3: Draw the bird body, shine highlight, and champion ring.
|
|
65
|
+
drawPlaybackBirdBody(context, birdGeometry, birdRenderStyle);
|
|
66
|
+
drawPlaybackBirdShine(context, birdGeometry, birdRenderStyle.isChampionBird);
|
|
67
|
+
drawPlaybackBirdLeaderRing(
|
|
68
|
+
context,
|
|
69
|
+
birdGeometry,
|
|
70
|
+
birdRenderStyle.isChampionBird,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Resolves the trail style used for one bird's stepped trail.
|
|
76
|
+
*
|
|
77
|
+
* @param birdIndex - Index of the bird being rendered.
|
|
78
|
+
* @param championBirdIndex - Champion index for the current frame.
|
|
79
|
+
* @returns Base opacity and color for the bird trail.
|
|
80
|
+
*/
|
|
81
|
+
export function resolvePlaybackTrailStyle(
|
|
82
|
+
birdIndex: number,
|
|
83
|
+
championBirdIndex: number,
|
|
84
|
+
): PlaybackTrailRenderStyle {
|
|
85
|
+
// Step 1: Resolve champion-aware opacity and trail color.
|
|
86
|
+
const isChampionBird = birdIndex === championBirdIndex;
|
|
87
|
+
return {
|
|
88
|
+
baseOpacity:
|
|
89
|
+
(isChampionBird ? 1 : FLAPPY_NON_CHAMPION_OPACITY) *
|
|
90
|
+
FLAPPY_TRAIL_OPACITY_FACTOR,
|
|
91
|
+
trailColor: isChampionBird
|
|
92
|
+
? FLAPPY_NEON_PALETTE.trail
|
|
93
|
+
: FLAPPY_NEON_PALETTE.nonChampionBird,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Draws the stepped trail history for one active bird.
|
|
99
|
+
*
|
|
100
|
+
* @param context - Canvas 2D drawing context.
|
|
101
|
+
* @param trailPoints - Cached per-frame trail points for one bird.
|
|
102
|
+
* @param color - Stroke color for the trail.
|
|
103
|
+
* @param anchorX - Bird anchor x-position in world space.
|
|
104
|
+
* @param baseOpacity - Base opacity before edge and lifetime fading.
|
|
105
|
+
* @param edgeBounds - Visible world bounds used for edge fading.
|
|
106
|
+
* @returns Nothing.
|
|
107
|
+
*/
|
|
108
|
+
export function drawTrail(
|
|
109
|
+
context: CanvasRenderingContext2D,
|
|
110
|
+
trailPoints: TrailPoint[],
|
|
111
|
+
color: string,
|
|
112
|
+
anchorX: number,
|
|
113
|
+
baseOpacity: number,
|
|
114
|
+
edgeBounds: PlaybackEdgeBounds,
|
|
115
|
+
): void {
|
|
116
|
+
// Step 1: Guard empty trails.
|
|
117
|
+
if (trailPoints.length === 0) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const latestTrailFrameIndex = trailPoints.at(-1)?.frameIndex ?? 0;
|
|
122
|
+
|
|
123
|
+
const firstTrailPoint = trailPoints[0];
|
|
124
|
+
const firstTrailFrameOffset = Math.max(
|
|
125
|
+
0,
|
|
126
|
+
latestTrailFrameIndex - firstTrailPoint.frameIndex,
|
|
127
|
+
);
|
|
128
|
+
let previousXPosition =
|
|
129
|
+
anchorX - firstTrailFrameOffset * FLAPPY_PIPE_SPEED_PX_PER_FRAME;
|
|
130
|
+
let previousYPosition = firstTrailPoint.yPx;
|
|
131
|
+
let previousFrameOffset = firstTrailFrameOffset;
|
|
132
|
+
const maximumTrailFrameOffset = Math.max(1, firstTrailFrameOffset);
|
|
133
|
+
|
|
134
|
+
// Step 2: Configure trail stroke style.
|
|
135
|
+
const previousGlobalAlpha = context.globalAlpha;
|
|
136
|
+
context.strokeStyle = color;
|
|
137
|
+
context.lineWidth = FLAPPY_TRAIL_LINE_WIDTH_PX;
|
|
138
|
+
|
|
139
|
+
// Step 3: Render stepped segments with edge-proximity alpha fading.
|
|
140
|
+
trailPoints.slice(1).forEach((trailPoint) => {
|
|
141
|
+
const frameOffset = Math.max(
|
|
142
|
+
0,
|
|
143
|
+
latestTrailFrameIndex - trailPoint.frameIndex,
|
|
144
|
+
);
|
|
145
|
+
const nextXPosition =
|
|
146
|
+
anchorX - frameOffset * FLAPPY_PIPE_SPEED_PX_PER_FRAME;
|
|
147
|
+
const nextYPosition = trailPoint.yPx;
|
|
148
|
+
|
|
149
|
+
const horizontalDeltaPx = nextXPosition - previousXPosition;
|
|
150
|
+
const horizontalDirection = Math.sign(horizontalDeltaPx) || 1;
|
|
151
|
+
const steppedHorizontalLengthPx = Math.max(
|
|
152
|
+
Math.abs(horizontalDeltaPx),
|
|
153
|
+
FLAPPY_TRAIL_MIN_HORIZONTAL_SEGMENT_PX,
|
|
154
|
+
);
|
|
155
|
+
const steppedHorizontalXPosition =
|
|
156
|
+
previousXPosition + horizontalDirection * steppedHorizontalLengthPx;
|
|
157
|
+
drawTrailSegmentWithEdgeFade(
|
|
158
|
+
context,
|
|
159
|
+
previousXPosition,
|
|
160
|
+
previousYPosition,
|
|
161
|
+
steppedHorizontalXPosition,
|
|
162
|
+
previousYPosition,
|
|
163
|
+
baseOpacity,
|
|
164
|
+
edgeBounds,
|
|
165
|
+
previousFrameOffset,
|
|
166
|
+
frameOffset,
|
|
167
|
+
maximumTrailFrameOffset,
|
|
168
|
+
);
|
|
169
|
+
previousXPosition = steppedHorizontalXPosition;
|
|
170
|
+
|
|
171
|
+
const verticalDeltaPx = nextYPosition - previousYPosition;
|
|
172
|
+
if (verticalDeltaPx !== 0) {
|
|
173
|
+
const verticalDirection = Math.sign(verticalDeltaPx);
|
|
174
|
+
const steppedVerticalLengthPx = Math.max(
|
|
175
|
+
Math.abs(verticalDeltaPx),
|
|
176
|
+
FLAPPY_TRAIL_MIN_VERTICAL_SEGMENT_PX,
|
|
177
|
+
);
|
|
178
|
+
const steppedVerticalYPosition =
|
|
179
|
+
previousYPosition + verticalDirection * steppedVerticalLengthPx;
|
|
180
|
+
drawTrailSegmentWithEdgeFade(
|
|
181
|
+
context,
|
|
182
|
+
previousXPosition,
|
|
183
|
+
previousYPosition,
|
|
184
|
+
steppedHorizontalXPosition,
|
|
185
|
+
steppedVerticalYPosition,
|
|
186
|
+
baseOpacity,
|
|
187
|
+
edgeBounds,
|
|
188
|
+
previousFrameOffset,
|
|
189
|
+
frameOffset,
|
|
190
|
+
maximumTrailFrameOffset,
|
|
191
|
+
);
|
|
192
|
+
previousYPosition = steppedVerticalYPosition;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
drawTrailSegmentWithEdgeFade(
|
|
196
|
+
context,
|
|
197
|
+
previousXPosition,
|
|
198
|
+
previousYPosition,
|
|
199
|
+
steppedHorizontalXPosition,
|
|
200
|
+
nextYPosition,
|
|
201
|
+
baseOpacity,
|
|
202
|
+
edgeBounds,
|
|
203
|
+
previousFrameOffset,
|
|
204
|
+
frameOffset,
|
|
205
|
+
maximumTrailFrameOffset,
|
|
206
|
+
);
|
|
207
|
+
previousYPosition = nextYPosition;
|
|
208
|
+
|
|
209
|
+
drawTrailSegmentWithEdgeFade(
|
|
210
|
+
context,
|
|
211
|
+
previousXPosition,
|
|
212
|
+
previousYPosition,
|
|
213
|
+
nextXPosition,
|
|
214
|
+
nextYPosition,
|
|
215
|
+
baseOpacity,
|
|
216
|
+
edgeBounds,
|
|
217
|
+
previousFrameOffset,
|
|
218
|
+
frameOffset,
|
|
219
|
+
maximumTrailFrameOffset,
|
|
220
|
+
);
|
|
221
|
+
previousXPosition = nextXPosition;
|
|
222
|
+
previousYPosition = nextYPosition;
|
|
223
|
+
previousFrameOffset = frameOffset;
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Step 4: Restore caller alpha state.
|
|
227
|
+
context.globalAlpha = previousGlobalAlpha;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Resolves the fixed bird geometry used by all body rendering passes.
|
|
232
|
+
*
|
|
233
|
+
* @param birdYPx - Bird vertical position in world pixels.
|
|
234
|
+
* @returns Pixel-aligned square geometry for the bird body.
|
|
235
|
+
*/
|
|
236
|
+
function resolvePlaybackBirdGeometry(birdYPx: number): PlaybackBirdGeometry {
|
|
237
|
+
// Step 1: Resolve a fixed square body size from the collision radius.
|
|
238
|
+
const birdSideLengthPx = Math.max(1, Math.round(FLAPPY_BIRD_RADIUS_PX * 2));
|
|
239
|
+
|
|
240
|
+
// Step 2: Return pixel-aligned body bounds for the current y-position.
|
|
241
|
+
return {
|
|
242
|
+
birdSideLengthPx,
|
|
243
|
+
birdLeftPx: Math.round(FLAPPY_BIRD_X_PX - FLAPPY_BIRD_RADIUS_PX),
|
|
244
|
+
birdTopPx: Math.round(birdYPx - FLAPPY_BIRD_RADIUS_PX),
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Draws the soft champion aura plate behind the bird body.
|
|
250
|
+
*
|
|
251
|
+
* @param context - Canvas 2D drawing context.
|
|
252
|
+
* @param birdGeometry - Pixel-aligned bird geometry.
|
|
253
|
+
* @param birdRenderStyle - Resolved bird style payload.
|
|
254
|
+
* @returns Nothing.
|
|
255
|
+
*/
|
|
256
|
+
function drawPlaybackBirdChampionAura(
|
|
257
|
+
context: CanvasRenderingContext2D,
|
|
258
|
+
birdGeometry: PlaybackBirdGeometry,
|
|
259
|
+
birdRenderStyle: ReturnType<typeof resolveBirdRenderStyle>,
|
|
260
|
+
): void {
|
|
261
|
+
// Step 1: Skip the aura pass for non-champion birds.
|
|
262
|
+
if (!birdRenderStyle.isChampionBird) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Step 2: Draw the additive aura plate behind the champion body.
|
|
267
|
+
const auraExpandPx = Math.round(FLAPPY_BIRD_AURA_EXPAND_PX);
|
|
268
|
+
const previousCompositeOperation = context.globalCompositeOperation;
|
|
269
|
+
context.globalCompositeOperation = 'lighter';
|
|
270
|
+
context.globalAlpha = birdRenderStyle.birdOpacity * FLAPPY_BIRD_AURA_ALPHA;
|
|
271
|
+
context.fillStyle = birdRenderStyle.birdRenderColor;
|
|
272
|
+
context.shadowColor = birdRenderStyle.birdRenderColor;
|
|
273
|
+
context.shadowBlur = Math.round(
|
|
274
|
+
FLAPPY_BIRD_BODY_GLOW_BLUR_PX * FLAPPY_BIRD_AURA_BLUR_MULTIPLIER,
|
|
275
|
+
);
|
|
276
|
+
context.fillRect(
|
|
277
|
+
birdGeometry.birdLeftPx - auraExpandPx,
|
|
278
|
+
birdGeometry.birdTopPx - auraExpandPx,
|
|
279
|
+
birdGeometry.birdSideLengthPx + auraExpandPx * 2,
|
|
280
|
+
birdGeometry.birdSideLengthPx + auraExpandPx * 2,
|
|
281
|
+
);
|
|
282
|
+
context.shadowBlur = 0;
|
|
283
|
+
context.shadowColor = 'transparent';
|
|
284
|
+
context.globalCompositeOperation = previousCompositeOperation;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Draws the champion-only red glow plate beneath the bird body.
|
|
289
|
+
*
|
|
290
|
+
* @param context - Canvas 2D drawing context.
|
|
291
|
+
* @param birdGeometry - Pixel-aligned bird geometry.
|
|
292
|
+
* @param birdRenderStyle - Resolved bird style payload.
|
|
293
|
+
* @returns Nothing.
|
|
294
|
+
*/
|
|
295
|
+
function drawPlaybackBirdChampionGlowPlate(
|
|
296
|
+
context: CanvasRenderingContext2D,
|
|
297
|
+
birdGeometry: PlaybackBirdGeometry,
|
|
298
|
+
birdRenderStyle: ReturnType<typeof resolveBirdRenderStyle>,
|
|
299
|
+
): void {
|
|
300
|
+
// Step 1: Skip the red glow plate for non-champion birds.
|
|
301
|
+
if (!birdRenderStyle.isChampionBird) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Step 2: Draw the expanded red glow plate behind the champion body.
|
|
306
|
+
const expandedGlowInsetPx = Math.round(
|
|
307
|
+
FLAPPY_BIRD_CHAMPION_RED_GLOW_EXPAND_PX,
|
|
308
|
+
);
|
|
309
|
+
context.globalAlpha =
|
|
310
|
+
birdRenderStyle.birdOpacity * FLAPPY_BIRD_CHAMPION_RED_GLOW_ALPHA;
|
|
311
|
+
context.fillStyle = FLAPPY_NEON_PALETTE.championBird;
|
|
312
|
+
context.shadowColor = FLAPPY_NEON_PALETTE.championBird;
|
|
313
|
+
context.shadowBlur =
|
|
314
|
+
FLAPPY_BIRD_BODY_GLOW_BLUR_PX + FLAPPY_BIRD_CHAMPION_EXTRA_GLOW_BLUR_PX;
|
|
315
|
+
context.fillRect(
|
|
316
|
+
birdGeometry.birdLeftPx - expandedGlowInsetPx,
|
|
317
|
+
birdGeometry.birdTopPx - expandedGlowInsetPx,
|
|
318
|
+
birdGeometry.birdSideLengthPx + expandedGlowInsetPx * 2,
|
|
319
|
+
birdGeometry.birdSideLengthPx + expandedGlowInsetPx * 2,
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Draws the square bird body with its base neon glow.
|
|
325
|
+
*
|
|
326
|
+
* @param context - Canvas 2D drawing context.
|
|
327
|
+
* @param birdGeometry - Pixel-aligned bird geometry.
|
|
328
|
+
* @param birdRenderStyle - Resolved bird style payload.
|
|
329
|
+
* @returns Nothing.
|
|
330
|
+
*/
|
|
331
|
+
function drawPlaybackBirdBody(
|
|
332
|
+
context: CanvasRenderingContext2D,
|
|
333
|
+
birdGeometry: PlaybackBirdGeometry,
|
|
334
|
+
birdRenderStyle: ReturnType<typeof resolveBirdRenderStyle>,
|
|
335
|
+
): void {
|
|
336
|
+
// Step 1: Draw the main square body using the resolved bird color.
|
|
337
|
+
context.globalAlpha = birdRenderStyle.birdOpacity;
|
|
338
|
+
context.fillStyle = birdRenderStyle.birdRenderColor;
|
|
339
|
+
context.shadowColor = birdRenderStyle.birdRenderColor;
|
|
340
|
+
context.shadowBlur =
|
|
341
|
+
FLAPPY_BIRD_BODY_GLOW_BLUR_PX +
|
|
342
|
+
(birdRenderStyle.isChampionBird
|
|
343
|
+
? FLAPPY_BIRD_CHAMPION_EXTRA_GLOW_BLUR_PX
|
|
344
|
+
: 0);
|
|
345
|
+
context.fillRect(
|
|
346
|
+
birdGeometry.birdLeftPx,
|
|
347
|
+
birdGeometry.birdTopPx,
|
|
348
|
+
birdGeometry.birdSideLengthPx,
|
|
349
|
+
birdGeometry.birdSideLengthPx,
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Draws the reflective shine highlight for one bird body.
|
|
355
|
+
*
|
|
356
|
+
* @param context - Canvas 2D drawing context.
|
|
357
|
+
* @param birdGeometry - Pixel-aligned bird geometry.
|
|
358
|
+
* @param isChampionBird - Whether the current bird is the champion.
|
|
359
|
+
* @returns Nothing.
|
|
360
|
+
*/
|
|
361
|
+
function drawPlaybackBirdShine(
|
|
362
|
+
context: CanvasRenderingContext2D,
|
|
363
|
+
birdGeometry: PlaybackBirdGeometry,
|
|
364
|
+
isChampionBird: boolean,
|
|
365
|
+
): void {
|
|
366
|
+
// Step 1: Resolve shine geometry inside the square bird body.
|
|
367
|
+
const shineInsetPx =
|
|
368
|
+
birdGeometry.birdSideLengthPx * FLAPPY_BIRD_SHINE_INSET_RATIO;
|
|
369
|
+
const shineSideLengthPx = Math.max(
|
|
370
|
+
1,
|
|
371
|
+
birdGeometry.birdSideLengthPx * FLAPPY_BIRD_SHINE_SIZE_RATIO,
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
// Step 2: Draw the inner shine highlight using champion-aware colors.
|
|
375
|
+
context.fillStyle = isChampionBird
|
|
376
|
+
? FLAPPY_BIRD_CHAMPION_SHINE_FILL_STYLE
|
|
377
|
+
: FLAPPY_BIRD_SHINE_FILL_STYLE;
|
|
378
|
+
context.shadowColor = isChampionBird
|
|
379
|
+
? FLAPPY_BIRD_CHAMPION_SHINE_GLOW_COLOR
|
|
380
|
+
: FLAPPY_BIRD_WHITE_SHINE_GLOW_COLOR;
|
|
381
|
+
context.shadowBlur = FLAPPY_BIRD_WHITE_SHINE_GLOW_BLUR_PX;
|
|
382
|
+
context.fillRect(
|
|
383
|
+
Math.round(birdGeometry.birdLeftPx + shineInsetPx),
|
|
384
|
+
Math.round(birdGeometry.birdTopPx + shineInsetPx),
|
|
385
|
+
Math.round(shineSideLengthPx),
|
|
386
|
+
Math.round(shineSideLengthPx),
|
|
387
|
+
);
|
|
388
|
+
context.shadowBlur = 0;
|
|
389
|
+
context.shadowColor = 'transparent';
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Draws the leader ring around the champion bird.
|
|
394
|
+
*
|
|
395
|
+
* @param context - Canvas 2D drawing context.
|
|
396
|
+
* @param birdGeometry - Pixel-aligned bird geometry.
|
|
397
|
+
* @param isChampionBird - Whether the current bird is the champion.
|
|
398
|
+
* @returns Nothing.
|
|
399
|
+
*/
|
|
400
|
+
function drawPlaybackBirdLeaderRing(
|
|
401
|
+
context: CanvasRenderingContext2D,
|
|
402
|
+
birdGeometry: PlaybackBirdGeometry,
|
|
403
|
+
isChampionBird: boolean,
|
|
404
|
+
): void {
|
|
405
|
+
// Step 1: Skip the leader ring for non-champion birds.
|
|
406
|
+
if (!isChampionBird) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Step 2: Draw the glowing leader ring around the champion body.
|
|
411
|
+
const leaderRingInsetPx = Math.round(FLAPPY_LEADER_RING_RADIUS_OFFSET_PX);
|
|
412
|
+
context.strokeStyle = FLAPPY_NEON_PALETTE.leaderRing;
|
|
413
|
+
context.lineWidth = FLAPPY_LEADER_RING_LINE_WIDTH_PX;
|
|
414
|
+
context.shadowColor = FLAPPY_NEON_PALETTE.leaderRing;
|
|
415
|
+
context.shadowBlur = FLAPPY_LEADER_RING_GLOW_BLUR_PX;
|
|
416
|
+
context.strokeRect(
|
|
417
|
+
birdGeometry.birdLeftPx - leaderRingInsetPx,
|
|
418
|
+
birdGeometry.birdTopPx - leaderRingInsetPx,
|
|
419
|
+
birdGeometry.birdSideLengthPx + leaderRingInsetPx * 2,
|
|
420
|
+
birdGeometry.birdSideLengthPx + leaderRingInsetPx * 2,
|
|
421
|
+
);
|
|
422
|
+
context.shadowBlur = 0;
|
|
423
|
+
context.shadowColor = 'transparent';
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Draws one trail segment with combined edge and lifetime fading.
|
|
428
|
+
*
|
|
429
|
+
* @param context - Canvas 2D drawing context.
|
|
430
|
+
* @param startXPx - Segment start x-position.
|
|
431
|
+
* @param startYPx - Segment start y-position.
|
|
432
|
+
* @param endXPx - Segment end x-position.
|
|
433
|
+
* @param endYPx - Segment end y-position.
|
|
434
|
+
* @param baseOpacity - Base opacity before fade factors.
|
|
435
|
+
* @param edgeBounds - Visible world bounds used for edge fading.
|
|
436
|
+
* @param startFrameOffset - Relative age of the segment start.
|
|
437
|
+
* @param endFrameOffset - Relative age of the segment end.
|
|
438
|
+
* @param maximumTrailFrameOffset - Oldest visible trail age.
|
|
439
|
+
* @returns Nothing.
|
|
440
|
+
*/
|
|
441
|
+
function drawTrailSegmentWithEdgeFade(
|
|
442
|
+
context: CanvasRenderingContext2D,
|
|
443
|
+
startXPx: number,
|
|
444
|
+
startYPx: number,
|
|
445
|
+
endXPx: number,
|
|
446
|
+
endYPx: number,
|
|
447
|
+
baseOpacity: number,
|
|
448
|
+
edgeBounds: PlaybackEdgeBounds,
|
|
449
|
+
startFrameOffset: number,
|
|
450
|
+
endFrameOffset: number,
|
|
451
|
+
maximumTrailFrameOffset: number,
|
|
452
|
+
): void {
|
|
453
|
+
const segmentLengthPx = Math.hypot(endXPx - startXPx, endYPx - startYPx);
|
|
454
|
+
if (segmentLengthPx === 0 || baseOpacity <= 0) {
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// Step 1: Resolve edge-fade factor from both segment endpoints.
|
|
459
|
+
const startOpacityFactor = resolveEdgeOpacityFactor(
|
|
460
|
+
startXPx,
|
|
461
|
+
startYPx,
|
|
462
|
+
edgeBounds,
|
|
463
|
+
);
|
|
464
|
+
const endOpacityFactor = resolveEdgeOpacityFactor(endXPx, endYPx, edgeBounds);
|
|
465
|
+
const edgeOpacityFactor = Math.min(startOpacityFactor, endOpacityFactor);
|
|
466
|
+
|
|
467
|
+
// Step 2: Resolve lifetime fade so older trail history fades near cutoff.
|
|
468
|
+
const startLifetimeOpacityFactor = resolveTrailLifetimeOpacityFactor(
|
|
469
|
+
startFrameOffset,
|
|
470
|
+
maximumTrailFrameOffset,
|
|
471
|
+
);
|
|
472
|
+
const endLifetimeOpacityFactor = resolveTrailLifetimeOpacityFactor(
|
|
473
|
+
endFrameOffset,
|
|
474
|
+
maximumTrailFrameOffset,
|
|
475
|
+
);
|
|
476
|
+
const lifetimeOpacityFactor = Math.min(
|
|
477
|
+
startLifetimeOpacityFactor,
|
|
478
|
+
endLifetimeOpacityFactor,
|
|
479
|
+
);
|
|
480
|
+
|
|
481
|
+
const segmentOpacity =
|
|
482
|
+
baseOpacity * edgeOpacityFactor * lifetimeOpacityFactor;
|
|
483
|
+
if (segmentOpacity <= 0) {
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Step 3: Draw the segment with resolved opacity.
|
|
488
|
+
context.globalAlpha = segmentOpacity;
|
|
489
|
+
context.beginPath();
|
|
490
|
+
context.moveTo(startXPx, startYPx);
|
|
491
|
+
context.lineTo(endXPx, endYPx);
|
|
492
|
+
context.stroke();
|
|
493
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
EvolutionPlaybackStepSnapshot,
|
|
3
|
+
PopulationRenderState,
|
|
4
|
+
} from '../browser-entry.types';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Applies worker snapshot data to the mutable playback render state.
|
|
8
|
+
*
|
|
9
|
+
* @param renderState - Mutable render state mirror used by the browser.
|
|
10
|
+
* @param snapshot - Worker playback snapshot for the current render tick.
|
|
11
|
+
* @returns Nothing.
|
|
12
|
+
*/
|
|
13
|
+
export function applyPlaybackSnapshot(
|
|
14
|
+
renderState: PopulationRenderState,
|
|
15
|
+
snapshot: EvolutionPlaybackStepSnapshot,
|
|
16
|
+
): void {
|
|
17
|
+
renderState.frameIndex = snapshot.frameIndex;
|
|
18
|
+
renderState.visibleWorldWidthPx = snapshot.visibleWorldWidthPx;
|
|
19
|
+
renderState.visibleWorldHeightPx = snapshot.visibleWorldHeightPx;
|
|
20
|
+
renderState.pipes = snapshot.pipes;
|
|
21
|
+
renderState.birds = snapshot.birds.map((birdSnapshot) => ({
|
|
22
|
+
color: birdSnapshot.color,
|
|
23
|
+
yPx: birdSnapshot.yPx,
|
|
24
|
+
pipesPassed: birdSnapshot.pipesPassed,
|
|
25
|
+
framesSurvived: birdSnapshot.framesSurvived,
|
|
26
|
+
done: birdSnapshot.done,
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Resolves the maximum survived-frame count in the current render state.
|
|
32
|
+
*
|
|
33
|
+
* @param renderState - Current render state.
|
|
34
|
+
* @returns Maximum frames survived by any bird.
|
|
35
|
+
*/
|
|
36
|
+
export function resolveLeaderFramesSurvived(
|
|
37
|
+
renderState: PopulationRenderState,
|
|
38
|
+
): number {
|
|
39
|
+
return renderState.birds.reduce(
|
|
40
|
+
(maximumFramesSurvived, bird) =>
|
|
41
|
+
Math.max(maximumFramesSurvived, bird.framesSurvived),
|
|
42
|
+
0,
|
|
43
|
+
);
|
|
44
|
+
}
|