@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
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FLAPPY_GROUND_GRID_HORIZONTAL_LINE_COUNT,
|
|
3
|
+
FLAPPY_GROUND_GRID_MIN_VERTICAL_LINE_COUNT,
|
|
4
|
+
FLAPPY_GROUND_GRID_PULSE_MIN_ELIGIBLE_THICKNESS_PX,
|
|
5
|
+
FLAPPY_GROUND_GRID_PULSE_PREFERRED_HORIZONTAL_START_RATIO,
|
|
6
|
+
FLAPPY_GROUND_GRID_PULSE_VISIBLE_VIEWPORT_INSET_PX,
|
|
7
|
+
FLAPPY_GROUND_GRID_SCROLL_RATIO,
|
|
8
|
+
FLAPPY_GROUND_GRID_TARGET_VERTICAL_LINE_SPACING_PX,
|
|
9
|
+
FLAPPY_GROUND_GRID_TARGET_VERTICAL_SEGMENT_HEIGHT_PX,
|
|
10
|
+
FLAPPY_GROUND_GRID_VERTICAL_OVERFLOW_COUNT,
|
|
11
|
+
FLAPPY_GROUND_GRID_VERTICAL_PULSE_END_RATIO,
|
|
12
|
+
FLAPPY_GROUND_GRID_VERTICAL_PULSE_START_RATIO,
|
|
13
|
+
} from './playback.background.ground-grid.constants';
|
|
14
|
+
import { positiveModulo } from '../../playback.starfield.utils';
|
|
15
|
+
import {
|
|
16
|
+
resolvePlaybackGroundGridDepthCurve,
|
|
17
|
+
resolvePlaybackGroundGridDepthFromHorizonDistance,
|
|
18
|
+
resolvePlaybackGroundGridLineAlpha,
|
|
19
|
+
resolvePlaybackGroundGridLineBlur,
|
|
20
|
+
resolvePlaybackGroundGridLineThickness,
|
|
21
|
+
} from './playback.background.ground-grid.math.utils';
|
|
22
|
+
import {
|
|
23
|
+
ensureGroundGridViewportCacheValidity,
|
|
24
|
+
resolveCachedGroundGridHorizontalGeometry,
|
|
25
|
+
resolveCachedGroundGridVerticalGeometry,
|
|
26
|
+
resolveGroundGridSceneCacheKey,
|
|
27
|
+
resolveGroundGridVerticalCycleCacheKey,
|
|
28
|
+
} from './playback.background.ground-grid.cache.services';
|
|
29
|
+
import type {
|
|
30
|
+
PlaybackGroundGridAnchorBounds,
|
|
31
|
+
PlaybackGroundGridAnchorBoundsInput,
|
|
32
|
+
PlaybackGroundGridAnchorProjectionInput,
|
|
33
|
+
PlaybackBackgroundGroundGridSceneContext,
|
|
34
|
+
PlaybackGroundGridHorizontalGeometry,
|
|
35
|
+
PlaybackGroundGridHorizontalGeometryFactory,
|
|
36
|
+
PlaybackGroundGridLineSegment,
|
|
37
|
+
PlaybackGroundGridPulsePath,
|
|
38
|
+
PlaybackGroundGridSegmentBatch,
|
|
39
|
+
PlaybackGroundGridVerticalCycleContext,
|
|
40
|
+
PlaybackGroundGridVerticalGeometry,
|
|
41
|
+
PlaybackGroundGridVerticalRayInput,
|
|
42
|
+
} from './playback.background.ground-grid.types';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Resolves cached screen-horizontal depth bands for the lower neon plane.
|
|
46
|
+
*
|
|
47
|
+
* @param sceneContext - Lower-band geometry for the current viewport.
|
|
48
|
+
* @returns Ordered far-to-near line segments and pulse subsets.
|
|
49
|
+
*/
|
|
50
|
+
export function resolvePlaybackGroundGridHorizontalGeometry(
|
|
51
|
+
sceneContext: PlaybackBackgroundGroundGridSceneContext,
|
|
52
|
+
): PlaybackGroundGridHorizontalGeometry {
|
|
53
|
+
ensureGroundGridViewportCacheValidity(sceneContext);
|
|
54
|
+
const sceneCacheKey = resolveGroundGridSceneCacheKey(sceneContext);
|
|
55
|
+
|
|
56
|
+
return resolveCachedGroundGridHorizontalGeometry(sceneCacheKey, () =>
|
|
57
|
+
buildPlaybackGroundGridHorizontalGeometry(sceneContext),
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Resolves cached perspective rays that converge to the centered horizon point.
|
|
63
|
+
*
|
|
64
|
+
* @param sceneContext - Lower-band geometry for the current viewport.
|
|
65
|
+
* @param scrollBasePx - Shared world scroll used for parallax motion.
|
|
66
|
+
* @returns Wrapped left-to-right perspective rays and pulse subsets.
|
|
67
|
+
*/
|
|
68
|
+
export function resolvePlaybackGroundGridVerticalGeometry(
|
|
69
|
+
sceneContext: PlaybackBackgroundGroundGridSceneContext,
|
|
70
|
+
scrollBasePx: number,
|
|
71
|
+
): PlaybackGroundGridVerticalGeometry {
|
|
72
|
+
ensureGroundGridViewportCacheValidity(sceneContext);
|
|
73
|
+
|
|
74
|
+
const sceneCacheKey = resolveGroundGridSceneCacheKey(sceneContext);
|
|
75
|
+
const verticalCycleContext = resolvePlaybackGroundGridVerticalCycleContext(
|
|
76
|
+
sceneContext,
|
|
77
|
+
scrollBasePx,
|
|
78
|
+
);
|
|
79
|
+
const cycleCacheKey = resolveGroundGridVerticalCycleCacheKey(
|
|
80
|
+
sceneCacheKey,
|
|
81
|
+
verticalCycleContext.quantizedWrappedOffsetPx,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
return resolveCachedGroundGridVerticalGeometry(cycleCacheKey, () =>
|
|
85
|
+
buildPlaybackGroundGridVerticalGeometry(
|
|
86
|
+
sceneContext,
|
|
87
|
+
verticalCycleContext.safeLaneSpacingPx,
|
|
88
|
+
verticalCycleContext.quantizedWrappedOffsetPx,
|
|
89
|
+
),
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Builds the screen-horizontal depth bands for the lower neon plane.
|
|
95
|
+
*
|
|
96
|
+
* @param sceneContext - Lower-band geometry for the current viewport.
|
|
97
|
+
* @returns Ordered far-to-near line segments and pulse subsets.
|
|
98
|
+
*/
|
|
99
|
+
function buildPlaybackGroundGridHorizontalGeometry(
|
|
100
|
+
sceneContext: PlaybackBackgroundGroundGridSceneContext,
|
|
101
|
+
): PlaybackGroundGridHorizontalGeometry {
|
|
102
|
+
const maximumDistanceToHorizonPx = Math.max(
|
|
103
|
+
1,
|
|
104
|
+
sceneContext.lowerBandBottomYPx - sceneContext.alignedHorizonYPx,
|
|
105
|
+
);
|
|
106
|
+
const horizontalLines = new Array<PlaybackGroundGridLineSegment>(
|
|
107
|
+
FLAPPY_GROUND_GRID_HORIZONTAL_LINE_COUNT,
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
for (
|
|
111
|
+
let lineIndex = 0;
|
|
112
|
+
lineIndex < FLAPPY_GROUND_GRID_HORIZONTAL_LINE_COUNT;
|
|
113
|
+
lineIndex += 1
|
|
114
|
+
) {
|
|
115
|
+
// Step 1: Resolve normalized depth so the first line hugs the horizon.
|
|
116
|
+
const depthRatio =
|
|
117
|
+
(lineIndex + 1) / FLAPPY_GROUND_GRID_HORIZONTAL_LINE_COUNT;
|
|
118
|
+
const curvedDepthRatio = resolvePlaybackGroundGridDepthCurve(depthRatio);
|
|
119
|
+
const lineYPx =
|
|
120
|
+
sceneContext.lowerBandTopYPx +
|
|
121
|
+
curvedDepthRatio * sceneContext.lowerBandHeightPx;
|
|
122
|
+
const thicknessDepthRatio =
|
|
123
|
+
resolvePlaybackGroundGridDepthFromHorizonDistance(
|
|
124
|
+
lineYPx - sceneContext.alignedHorizonYPx,
|
|
125
|
+
maximumDistanceToHorizonPx,
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
// Step 2: Strengthen the near lines while softening the far ones.
|
|
129
|
+
horizontalLines[lineIndex] = {
|
|
130
|
+
startXPx: 0,
|
|
131
|
+
startYPx: lineYPx,
|
|
132
|
+
endXPx: sceneContext.visibleWorldWidthPx,
|
|
133
|
+
endYPx: lineYPx,
|
|
134
|
+
alpha: resolvePlaybackGroundGridLineAlpha(depthRatio),
|
|
135
|
+
blurPx: resolvePlaybackGroundGridLineBlur(depthRatio),
|
|
136
|
+
thicknessPx: resolvePlaybackGroundGridLineThickness(thicknessDepthRatio),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
horizontalLineBatches:
|
|
142
|
+
groupPlaybackGroundGridSegmentsByStyle(horizontalLines),
|
|
143
|
+
horizontalLines,
|
|
144
|
+
preferredHorizontalPulsePaths:
|
|
145
|
+
resolvePlaybackGroundGridPreferredHorizontalPulsePaths(horizontalLines),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Resolves the wrapped vertical-geometry cycle for the current scroll value.
|
|
151
|
+
*
|
|
152
|
+
* @param sceneContext - Lower-band geometry for the current viewport.
|
|
153
|
+
* @param scrollBasePx - Shared world scroll used for parallax motion.
|
|
154
|
+
* @returns Quantized wrapped offset and safe lane spacing for cache lookups.
|
|
155
|
+
*/
|
|
156
|
+
function resolvePlaybackGroundGridVerticalCycleContext(
|
|
157
|
+
sceneContext: PlaybackBackgroundGroundGridSceneContext,
|
|
158
|
+
scrollBasePx: number,
|
|
159
|
+
): PlaybackGroundGridVerticalCycleContext {
|
|
160
|
+
const visibleAnchorBounds = resolvePlaybackGroundGridAnchorBounds({
|
|
161
|
+
horizonLeftXPx: 0,
|
|
162
|
+
horizonRightXPx: sceneContext.visibleWorldWidthPx,
|
|
163
|
+
sceneContext,
|
|
164
|
+
});
|
|
165
|
+
const totalVisibleLaneCount = Math.max(
|
|
166
|
+
FLAPPY_GROUND_GRID_MIN_VERTICAL_LINE_COUNT,
|
|
167
|
+
Math.ceil(
|
|
168
|
+
visibleAnchorBounds.anchorSpanPx /
|
|
169
|
+
FLAPPY_GROUND_GRID_TARGET_VERTICAL_LINE_SPACING_PX,
|
|
170
|
+
) + 1,
|
|
171
|
+
);
|
|
172
|
+
const laneSpacingPx =
|
|
173
|
+
totalVisibleLaneCount > 1
|
|
174
|
+
? visibleAnchorBounds.anchorSpanPx / (totalVisibleLaneCount - 1)
|
|
175
|
+
: visibleAnchorBounds.anchorSpanPx;
|
|
176
|
+
const safeLaneSpacingPx = Math.max(1, laneSpacingPx);
|
|
177
|
+
const wrappedOffsetPx = positiveModulo(
|
|
178
|
+
scrollBasePx * FLAPPY_GROUND_GRID_SCROLL_RATIO,
|
|
179
|
+
safeLaneSpacingPx,
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
quantizedWrappedOffsetPx: Math.round(wrappedOffsetPx),
|
|
184
|
+
safeLaneSpacingPx,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Builds the perspective rays that converge to the centered horizon point.
|
|
190
|
+
*
|
|
191
|
+
* @param sceneContext - Lower-band geometry for the current viewport.
|
|
192
|
+
* @param safeLaneSpacingPx - Stable lane spacing used for ray anchors.
|
|
193
|
+
* @param quantizedWrappedOffsetPx - Quantized wrapped offset used for cache reuse.
|
|
194
|
+
* @returns Wrapped left-to-right perspective rays and pulse subsets.
|
|
195
|
+
*/
|
|
196
|
+
function buildPlaybackGroundGridVerticalGeometry(
|
|
197
|
+
sceneContext: PlaybackBackgroundGroundGridSceneContext,
|
|
198
|
+
safeLaneSpacingPx: number,
|
|
199
|
+
quantizedWrappedOffsetPx: number,
|
|
200
|
+
): PlaybackGroundGridVerticalGeometry {
|
|
201
|
+
const visibleAnchorBounds = resolvePlaybackGroundGridAnchorBounds({
|
|
202
|
+
horizonLeftXPx: 0,
|
|
203
|
+
horizonRightXPx: sceneContext.visibleWorldWidthPx,
|
|
204
|
+
sceneContext,
|
|
205
|
+
});
|
|
206
|
+
const totalVisibleLaneCount = Math.max(
|
|
207
|
+
FLAPPY_GROUND_GRID_MIN_VERTICAL_LINE_COUNT,
|
|
208
|
+
Math.ceil(
|
|
209
|
+
visibleAnchorBounds.anchorSpanPx /
|
|
210
|
+
FLAPPY_GROUND_GRID_TARGET_VERTICAL_LINE_SPACING_PX,
|
|
211
|
+
) + 1,
|
|
212
|
+
);
|
|
213
|
+
const firstAnchorXPx =
|
|
214
|
+
visibleAnchorBounds.leftAnchorXPx -
|
|
215
|
+
FLAPPY_GROUND_GRID_VERTICAL_OVERFLOW_COUNT * safeLaneSpacingPx -
|
|
216
|
+
quantizedWrappedOffsetPx;
|
|
217
|
+
const totalRayCount =
|
|
218
|
+
totalVisibleLaneCount + FLAPPY_GROUND_GRID_VERTICAL_OVERFLOW_COUNT * 2 + 1;
|
|
219
|
+
const maximumLateralDistancePx =
|
|
220
|
+
Math.max(
|
|
221
|
+
Math.abs(
|
|
222
|
+
visibleAnchorBounds.leftAnchorXPx - sceneContext.vanishingPointXPx,
|
|
223
|
+
),
|
|
224
|
+
Math.abs(
|
|
225
|
+
visibleAnchorBounds.rightAnchorXPx - sceneContext.vanishingPointXPx,
|
|
226
|
+
),
|
|
227
|
+
) +
|
|
228
|
+
FLAPPY_GROUND_GRID_VERTICAL_OVERFLOW_COUNT * safeLaneSpacingPx;
|
|
229
|
+
const maximumDistanceToHorizonPx = Math.max(
|
|
230
|
+
1,
|
|
231
|
+
sceneContext.lowerBandBottomYPx - sceneContext.alignedHorizonYPx,
|
|
232
|
+
);
|
|
233
|
+
const verticalSegmentCount = Math.max(
|
|
234
|
+
6,
|
|
235
|
+
Math.ceil(
|
|
236
|
+
maximumDistanceToHorizonPx /
|
|
237
|
+
FLAPPY_GROUND_GRID_TARGET_VERTICAL_SEGMENT_HEIGHT_PX,
|
|
238
|
+
),
|
|
239
|
+
);
|
|
240
|
+
const verticalPulsePaths = new Array<PlaybackGroundGridPulsePath>(
|
|
241
|
+
totalRayCount,
|
|
242
|
+
);
|
|
243
|
+
const verticalLineSegments = new Array<PlaybackGroundGridLineSegment>(
|
|
244
|
+
totalRayCount * verticalSegmentCount,
|
|
245
|
+
);
|
|
246
|
+
const visibleVerticalPulsePaths: PlaybackGroundGridPulsePath[] = [];
|
|
247
|
+
const midTravelRatio =
|
|
248
|
+
FLAPPY_GROUND_GRID_VERTICAL_PULSE_START_RATIO +
|
|
249
|
+
(FLAPPY_GROUND_GRID_VERTICAL_PULSE_END_RATIO -
|
|
250
|
+
FLAPPY_GROUND_GRID_VERTICAL_PULSE_START_RATIO) *
|
|
251
|
+
0.5;
|
|
252
|
+
let segmentWriteIndex = 0;
|
|
253
|
+
|
|
254
|
+
for (let rayIndex = 0; rayIndex < totalRayCount; rayIndex += 1) {
|
|
255
|
+
// Step 1: Resolve the bottom anchor and its centered strength.
|
|
256
|
+
const anchorXPx = firstAnchorXPx + rayIndex * safeLaneSpacingPx;
|
|
257
|
+
const lateralDistancePx = Math.abs(
|
|
258
|
+
anchorXPx - sceneContext.vanishingPointXPx,
|
|
259
|
+
);
|
|
260
|
+
const centeredStrength =
|
|
261
|
+
1 - Math.min(1, lateralDistancePx / maximumLateralDistancePx);
|
|
262
|
+
const lineDepthRatio = 0.45 + centeredStrength * 0.55;
|
|
263
|
+
const verticalPulsePath: PlaybackGroundGridPulsePath = {
|
|
264
|
+
orientation: 'vertical',
|
|
265
|
+
startXPx: anchorXPx,
|
|
266
|
+
startYPx: sceneContext.lowerBandBottomYPx,
|
|
267
|
+
endXPx: sceneContext.vanishingPointXPx,
|
|
268
|
+
endYPx: sceneContext.vanishingPointYPx,
|
|
269
|
+
thicknessPx: resolvePlaybackGroundGridLineThickness(1),
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
verticalPulsePaths[rayIndex] = verticalPulsePath;
|
|
273
|
+
if (
|
|
274
|
+
isPlaybackGroundGridVerticalPulsePathVisible(
|
|
275
|
+
verticalPulsePath,
|
|
276
|
+
sceneContext,
|
|
277
|
+
midTravelRatio,
|
|
278
|
+
)
|
|
279
|
+
) {
|
|
280
|
+
visibleVerticalPulsePaths.push(verticalPulsePath);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
segmentWriteIndex = appendPlaybackGroundGridVerticalLineSegments(
|
|
284
|
+
verticalLineSegments,
|
|
285
|
+
segmentWriteIndex,
|
|
286
|
+
{
|
|
287
|
+
...verticalPulsePath,
|
|
288
|
+
lineDepthRatio,
|
|
289
|
+
maximumDistanceToHorizonPx,
|
|
290
|
+
sceneContext,
|
|
291
|
+
verticalSegmentCount,
|
|
292
|
+
},
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return {
|
|
297
|
+
verticalLineBatches:
|
|
298
|
+
groupPlaybackGroundGridSegmentsByStyle(verticalLineSegments),
|
|
299
|
+
verticalPulsePaths,
|
|
300
|
+
visibleVerticalPulsePaths,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Appends tapered style segments for one perspective ray.
|
|
306
|
+
*
|
|
307
|
+
* @param targetSegments - Target line-segment buffer.
|
|
308
|
+
* @param startIndex - Current insertion index within the target buffer.
|
|
309
|
+
* @param input - Geometry and depth context for one ray.
|
|
310
|
+
* @returns Next insertion index after all ray segments have been written.
|
|
311
|
+
*/
|
|
312
|
+
function appendPlaybackGroundGridVerticalLineSegments(
|
|
313
|
+
targetSegments: PlaybackGroundGridLineSegment[],
|
|
314
|
+
startIndex: number,
|
|
315
|
+
input: PlaybackGroundGridVerticalRayInput,
|
|
316
|
+
): number {
|
|
317
|
+
const rayDeltaXPx = input.endXPx - input.startXPx;
|
|
318
|
+
const rayDeltaYPx = input.endYPx - input.startYPx;
|
|
319
|
+
let writeIndex = startIndex;
|
|
320
|
+
|
|
321
|
+
for (
|
|
322
|
+
let segmentIndex = 0;
|
|
323
|
+
segmentIndex < input.verticalSegmentCount;
|
|
324
|
+
segmentIndex += 1
|
|
325
|
+
) {
|
|
326
|
+
// Step 1: Resolve the interpolation bounds for this sub-segment.
|
|
327
|
+
const segmentStartRatio = segmentIndex / input.verticalSegmentCount;
|
|
328
|
+
const segmentEndRatio = (segmentIndex + 1) / input.verticalSegmentCount;
|
|
329
|
+
const segmentMidpointRatio = (segmentStartRatio + segmentEndRatio) * 0.5;
|
|
330
|
+
const segmentStartXPx = input.startXPx + rayDeltaXPx * segmentStartRatio;
|
|
331
|
+
const segmentStartYPx = input.startYPx + rayDeltaYPx * segmentStartRatio;
|
|
332
|
+
const segmentEndXPx = input.startXPx + rayDeltaXPx * segmentEndRatio;
|
|
333
|
+
const segmentEndYPx = input.startYPx + rayDeltaYPx * segmentEndRatio;
|
|
334
|
+
|
|
335
|
+
// Step 2: Resolve style from the segment midpoint distance to the horizon.
|
|
336
|
+
const segmentMidpointYPx =
|
|
337
|
+
input.startYPx + rayDeltaYPx * segmentMidpointRatio;
|
|
338
|
+
const segmentDepthRatio = resolvePlaybackGroundGridDepthFromHorizonDistance(
|
|
339
|
+
segmentMidpointYPx - input.sceneContext.alignedHorizonYPx,
|
|
340
|
+
input.maximumDistanceToHorizonPx,
|
|
341
|
+
);
|
|
342
|
+
const combinedAlphaDepthRatio =
|
|
343
|
+
segmentDepthRatio * 0.7 + input.lineDepthRatio * 0.3;
|
|
344
|
+
|
|
345
|
+
// Step 3: Append the tapered segment so the ray narrows toward the horizon.
|
|
346
|
+
targetSegments[writeIndex] = {
|
|
347
|
+
startXPx: segmentStartXPx,
|
|
348
|
+
startYPx: segmentStartYPx,
|
|
349
|
+
endXPx: segmentEndXPx,
|
|
350
|
+
endYPx: segmentEndYPx,
|
|
351
|
+
alpha: resolvePlaybackGroundGridLineAlpha(combinedAlphaDepthRatio),
|
|
352
|
+
blurPx: resolvePlaybackGroundGridLineBlur(segmentDepthRatio),
|
|
353
|
+
thicknessPx: resolvePlaybackGroundGridLineThickness(segmentDepthRatio),
|
|
354
|
+
};
|
|
355
|
+
writeIndex += 1;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
return writeIndex;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Projects the visible horizon span back onto the floor anchor line.
|
|
363
|
+
*
|
|
364
|
+
* @param input - Visible horizon bounds and scene geometry.
|
|
365
|
+
* @returns Bottom-anchor bounds required to cover the full visible horizon.
|
|
366
|
+
*/
|
|
367
|
+
function resolvePlaybackGroundGridAnchorBounds(
|
|
368
|
+
input: PlaybackGroundGridAnchorBoundsInput,
|
|
369
|
+
): PlaybackGroundGridAnchorBounds {
|
|
370
|
+
const leftAnchorXPx = projectPlaybackGroundGridHorizonXToAnchorX({
|
|
371
|
+
horizonXPx: input.horizonLeftXPx,
|
|
372
|
+
sceneContext: input.sceneContext,
|
|
373
|
+
});
|
|
374
|
+
const rightAnchorXPx = projectPlaybackGroundGridHorizonXToAnchorX({
|
|
375
|
+
horizonXPx: input.horizonRightXPx,
|
|
376
|
+
sceneContext: input.sceneContext,
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
return {
|
|
380
|
+
leftAnchorXPx,
|
|
381
|
+
rightAnchorXPx,
|
|
382
|
+
anchorSpanPx: Math.max(1, rightAnchorXPx - leftAnchorXPx),
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Projects one horizon x-position down to the required floor anchor x-position.
|
|
388
|
+
*
|
|
389
|
+
* @param input - Horizon target and scene geometry.
|
|
390
|
+
* @returns Bottom anchor x-position whose ray reaches the target horizon x.
|
|
391
|
+
*/
|
|
392
|
+
function projectPlaybackGroundGridHorizonXToAnchorX(
|
|
393
|
+
input: PlaybackGroundGridAnchorProjectionInput,
|
|
394
|
+
): number {
|
|
395
|
+
const verticalProjectionDenominatorPx =
|
|
396
|
+
input.sceneContext.alignedHorizonYPx - input.sceneContext.vanishingPointYPx;
|
|
397
|
+
if (Math.abs(verticalProjectionDenominatorPx) < Number.EPSILON) {
|
|
398
|
+
return input.horizonXPx;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const verticalProjectionRatio =
|
|
402
|
+
(input.sceneContext.lowerBandBottomYPx -
|
|
403
|
+
input.sceneContext.vanishingPointYPx) /
|
|
404
|
+
verticalProjectionDenominatorPx;
|
|
405
|
+
return (
|
|
406
|
+
input.sceneContext.vanishingPointXPx +
|
|
407
|
+
(input.horizonXPx - input.sceneContext.vanishingPointXPx) *
|
|
408
|
+
verticalProjectionRatio
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Groups line segments into ordered style batches for lower-overhead drawing.
|
|
414
|
+
*
|
|
415
|
+
* @param segments - Ordered line segments that should preserve draw grouping.
|
|
416
|
+
* @returns Ordered style batches that can be stroked with fewer state changes.
|
|
417
|
+
*/
|
|
418
|
+
function groupPlaybackGroundGridSegmentsByStyle(
|
|
419
|
+
segments: readonly PlaybackGroundGridLineSegment[],
|
|
420
|
+
): readonly PlaybackGroundGridSegmentBatch[] {
|
|
421
|
+
const groupedSegmentsByStyle = new Map<
|
|
422
|
+
string,
|
|
423
|
+
PlaybackGroundGridLineSegment[]
|
|
424
|
+
>();
|
|
425
|
+
|
|
426
|
+
for (const segment of segments) {
|
|
427
|
+
const styleKey = `${segment.alpha}:${segment.blurPx}:${segment.thicknessPx}`;
|
|
428
|
+
const existingGroup = groupedSegmentsByStyle.get(styleKey);
|
|
429
|
+
if (existingGroup) {
|
|
430
|
+
existingGroup.push(segment);
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
groupedSegmentsByStyle.set(styleKey, [segment]);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const segmentBatches: PlaybackGroundGridSegmentBatch[] = [];
|
|
438
|
+
for (const groupedSegments of groupedSegmentsByStyle.values()) {
|
|
439
|
+
const firstSegment = groupedSegments[0];
|
|
440
|
+
segmentBatches.push({
|
|
441
|
+
alpha: firstSegment.alpha,
|
|
442
|
+
blurPx: firstSegment.blurPx,
|
|
443
|
+
thicknessPx: firstSegment.thicknessPx,
|
|
444
|
+
segments: groupedSegments,
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
return segmentBatches;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Prefers the nearer, thicker horizontal tracks when picking a pulse lane.
|
|
453
|
+
*
|
|
454
|
+
* @param horizontalLines - Visible horizontal grid bands.
|
|
455
|
+
* @returns Pulse-eligible horizontal paths biased toward the foreground.
|
|
456
|
+
*/
|
|
457
|
+
function resolvePlaybackGroundGridPreferredHorizontalPulsePaths(
|
|
458
|
+
horizontalLines: readonly PlaybackGroundGridLineSegment[],
|
|
459
|
+
): readonly PlaybackGroundGridPulsePath[] {
|
|
460
|
+
const eligibleHorizontalPulsePaths: PlaybackGroundGridPulsePath[] = [];
|
|
461
|
+
|
|
462
|
+
for (const horizontalLine of horizontalLines) {
|
|
463
|
+
if (
|
|
464
|
+
horizontalLine.thicknessPx <
|
|
465
|
+
FLAPPY_GROUND_GRID_PULSE_MIN_ELIGIBLE_THICKNESS_PX
|
|
466
|
+
) {
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
eligibleHorizontalPulsePaths.push({
|
|
471
|
+
orientation: 'horizontal',
|
|
472
|
+
startXPx: horizontalLine.startXPx,
|
|
473
|
+
startYPx: horizontalLine.startYPx,
|
|
474
|
+
endXPx: horizontalLine.endXPx,
|
|
475
|
+
endYPx: horizontalLine.endYPx,
|
|
476
|
+
thicknessPx: horizontalLine.thicknessPx,
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (eligibleHorizontalPulsePaths.length === 0) {
|
|
481
|
+
return eligibleHorizontalPulsePaths;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
const preferredStartIndex = Math.min(
|
|
485
|
+
eligibleHorizontalPulsePaths.length - 1,
|
|
486
|
+
Math.floor(
|
|
487
|
+
eligibleHorizontalPulsePaths.length *
|
|
488
|
+
FLAPPY_GROUND_GRID_PULSE_PREFERRED_HORIZONTAL_START_RATIO,
|
|
489
|
+
),
|
|
490
|
+
);
|
|
491
|
+
return eligibleHorizontalPulsePaths.slice(preferredStartIndex);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Resolves whether one vertical pulse path is safely visible in the viewport.
|
|
496
|
+
*
|
|
497
|
+
* @param pulsePath - Candidate vertical pulse path.
|
|
498
|
+
* @param sceneContext - Current lower-band scene geometry.
|
|
499
|
+
* @param midTravelRatio - Midpoint travel ratio used for visibility checks.
|
|
500
|
+
* @returns True when the pulse midpoint stays inside the visible ground band.
|
|
501
|
+
*/
|
|
502
|
+
function isPlaybackGroundGridVerticalPulsePathVisible(
|
|
503
|
+
pulsePath: PlaybackGroundGridPulsePath,
|
|
504
|
+
sceneContext: PlaybackBackgroundGroundGridSceneContext,
|
|
505
|
+
midTravelRatio: number,
|
|
506
|
+
): boolean {
|
|
507
|
+
const pulseMidpointXPx =
|
|
508
|
+
pulsePath.startXPx +
|
|
509
|
+
(pulsePath.endXPx - pulsePath.startXPx) * midTravelRatio;
|
|
510
|
+
const visibleLeftXPx = FLAPPY_GROUND_GRID_PULSE_VISIBLE_VIEWPORT_INSET_PX;
|
|
511
|
+
const visibleRightXPx =
|
|
512
|
+
sceneContext.visibleWorldWidthPx -
|
|
513
|
+
FLAPPY_GROUND_GRID_PULSE_VISIBLE_VIEWPORT_INSET_PX;
|
|
514
|
+
|
|
515
|
+
return (
|
|
516
|
+
pulseMidpointXPx >= visibleLeftXPx && pulseMidpointXPx <= visibleRightXPx
|
|
517
|
+
);
|
|
518
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FLAPPY_GROUND_GRID_DEPTH_CURVE_EXPONENT,
|
|
3
|
+
FLAPPY_GROUND_GRID_MAX_ALPHA,
|
|
4
|
+
FLAPPY_GROUND_GRID_MAX_BLUR_PX,
|
|
5
|
+
FLAPPY_GROUND_GRID_MAX_THICKNESS_PX,
|
|
6
|
+
FLAPPY_GROUND_GRID_MIN_ALPHA,
|
|
7
|
+
FLAPPY_GROUND_GRID_MIN_BLUR_PX,
|
|
8
|
+
FLAPPY_GROUND_GRID_MIN_THICKNESS_PX,
|
|
9
|
+
} from './playback.background.ground-grid.constants';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Small point value used when interpolating positions along one grid ray.
|
|
13
|
+
*/
|
|
14
|
+
export type PlaybackGroundGridPoint = {
|
|
15
|
+
xPx: number;
|
|
16
|
+
yPx: number;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Maps a normalized depth ratio into a stronger synthwave spacing curve.
|
|
21
|
+
*
|
|
22
|
+
* @param depthRatio - Normalized 0..1 depth where 0 is far and 1 is near.
|
|
23
|
+
* @returns Curved depth ratio used for line placement and styling.
|
|
24
|
+
*/
|
|
25
|
+
export function resolvePlaybackGroundGridDepthCurve(
|
|
26
|
+
depthRatio: number,
|
|
27
|
+
): number {
|
|
28
|
+
return Math.pow(depthRatio, FLAPPY_GROUND_GRID_DEPTH_CURVE_EXPONENT);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Resolves neon alpha for one line based on its normalized depth.
|
|
33
|
+
*
|
|
34
|
+
* @param depthRatio - Normalized 0..1 depth where 0 is far and 1 is near.
|
|
35
|
+
* @returns Opacity for the rendered line.
|
|
36
|
+
*/
|
|
37
|
+
export function resolvePlaybackGroundGridLineAlpha(depthRatio: number): number {
|
|
38
|
+
return (
|
|
39
|
+
FLAPPY_GROUND_GRID_MIN_ALPHA +
|
|
40
|
+
(FLAPPY_GROUND_GRID_MAX_ALPHA - FLAPPY_GROUND_GRID_MIN_ALPHA) * depthRatio
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Resolves glow blur for one line based on its normalized depth.
|
|
46
|
+
*
|
|
47
|
+
* @param depthRatio - Normalized 0..1 depth where 0 is far and 1 is near.
|
|
48
|
+
* @returns Blur radius for the rendered line.
|
|
49
|
+
*/
|
|
50
|
+
export function resolvePlaybackGroundGridLineBlur(depthRatio: number): number {
|
|
51
|
+
return (
|
|
52
|
+
FLAPPY_GROUND_GRID_MAX_BLUR_PX -
|
|
53
|
+
(FLAPPY_GROUND_GRID_MAX_BLUR_PX - FLAPPY_GROUND_GRID_MIN_BLUR_PX) *
|
|
54
|
+
depthRatio
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Resolves stroke thickness for one line based on its normalized depth.
|
|
60
|
+
*
|
|
61
|
+
* @param depthRatio - Normalized 0..1 depth where 0 is far and 1 is near.
|
|
62
|
+
* @returns Stroke width in pixels.
|
|
63
|
+
*/
|
|
64
|
+
export function resolvePlaybackGroundGridLineThickness(
|
|
65
|
+
depthRatio: number,
|
|
66
|
+
): number {
|
|
67
|
+
return (
|
|
68
|
+
FLAPPY_GROUND_GRID_MIN_THICKNESS_PX +
|
|
69
|
+
(FLAPPY_GROUND_GRID_MAX_THICKNESS_PX -
|
|
70
|
+
FLAPPY_GROUND_GRID_MIN_THICKNESS_PX) *
|
|
71
|
+
depthRatio
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Resolves normalized depth from a vertical distance away from the horizon.
|
|
77
|
+
*
|
|
78
|
+
* @param distanceToHorizonPx - Vertical distance from the vanishing horizon.
|
|
79
|
+
* @param maximumDistanceToHorizonPx - Largest visible vertical horizon distance.
|
|
80
|
+
* @returns Normalized 0..1 depth where 0 is at the horizon and 1 is nearest.
|
|
81
|
+
*/
|
|
82
|
+
export function resolvePlaybackGroundGridDepthFromHorizonDistance(
|
|
83
|
+
distanceToHorizonPx: number,
|
|
84
|
+
maximumDistanceToHorizonPx: number,
|
|
85
|
+
): number {
|
|
86
|
+
if (maximumDistanceToHorizonPx <= 0) {
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return Math.min(
|
|
91
|
+
1,
|
|
92
|
+
Math.max(0, distanceToHorizonPx / maximumDistanceToHorizonPx),
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Interpolates one point along a perspective ray.
|
|
98
|
+
*
|
|
99
|
+
* @param startXPx - Bottom anchor x-position.
|
|
100
|
+
* @param startYPx - Bottom anchor y-position.
|
|
101
|
+
* @param endXPx - Vanishing-point x-position.
|
|
102
|
+
* @param endYPx - Vanishing-point y-position.
|
|
103
|
+
* @param interpolationRatio - Normalized 0..1 position along the ray.
|
|
104
|
+
* @returns Interpolated point on the perspective ray.
|
|
105
|
+
*/
|
|
106
|
+
export function interpolatePlaybackGroundGridPoint(
|
|
107
|
+
startXPx: number,
|
|
108
|
+
startYPx: number,
|
|
109
|
+
endXPx: number,
|
|
110
|
+
endYPx: number,
|
|
111
|
+
interpolationRatio: number,
|
|
112
|
+
): PlaybackGroundGridPoint {
|
|
113
|
+
return {
|
|
114
|
+
xPx: startXPx + (endXPx - startXPx) * interpolationRatio,
|
|
115
|
+
yPx: startYPx + (endYPx - startYPx) * interpolationRatio,
|
|
116
|
+
};
|
|
117
|
+
}
|