flappy-evolution-worker

Off-thread evolution and playback authority for the Flappy Bird browser demo.

This worker boundary exists to keep the browser honest. The main thread owns explanation, HUD rendering, and network inspection, while the worker owns the hot path: evolving generations, materializing playback state, advancing the simulation, and packaging compact snapshots back to the host.

That separation is doing two jobs at once. It protects the browser from heavy simulation work, and it turns responsibility into something a reader can see directly because every cross-thread handoff must become an explicit typed message.

Read this folder as the protocol chapter between the browser host and the deterministic runtime that actually evolves and replays the flock. The important design question is not merely "how do Web Workers run code?" It is "which side should own each piece of truth when evolution, playback, and inspection all need the same population?"

In this example, the answer is deliberate:

What This Folder Is Trying To Teach

The worker chapter is organized around four reader questions:

  1. How does the browser request evolution work without becoming the simulation authority?
  2. How does one evolved population become a replayable playback session?
  3. Why are snapshots packed into typed arrays instead of posted as nested render objects?
  4. Where should you read next when the protocol is clear but one runtime step still feels opaque?

Core Worker Map

flowchart LR
    Host["browser-entry/\nhost UI and controls"] --> Protocol["protocol service\nlegal message transitions"]
    Protocol --> Runtime["runtime service\nworker-local NEAT controller"]
    Runtime --> Evolution["evolution service\nadvance one generation"]
    Runtime --> Playback["playback service\nmaterialize and step population"]
    Playback --> Snapshot["snapshot utils\npacked typed-array transport"]
    Snapshot --> Host

    WarmStart["warm-start service\ngeneration zero bootstrap"] -.-> Evolution
    Types["worker types\nmessage and DTO contracts"] -.-> Protocol

    classDef boundary fill:#001522,stroke:#0fb5ff,color:#9fdcff,stroke-width:2px;
    classDef runtime fill:#03111f,stroke:#00e5ff,color:#d8f6ff,stroke-width:2px;
    classDef highlight fill:#2a1029,stroke:#ff4a8d,color:#ffd7e8,stroke-width:3px;

    class Host,Protocol,Types boundary;
    class Runtime,Evolution,Playback,Snapshot runtime;
    class Snapshot highlight;

Read the diagram left to right. The host is allowed to request work, but it never takes ownership of the worker's mutable simulation state. The worker can then optimize for determinism and throughput while the browser optimizes for explanation.

Choose Your Route

Minimal host-side sketch:

worker.postMessage({
  type: 'init',
  payload: { populationSize: 50, elitismCount: 10, rngSeed: 12345 },
});
worker.postMessage({ type: 'request-generation' });
worker.postMessage({
  type: 'start-playback',
  payload: { visibleWorldWidthPx: 1280, visibleWorldHeightPx: 720 },
});
worker.postMessage({
  type: 'request-playback-step',
  payload: {
    requestId: 1,
    simulationSteps: 2,
    visibleWorldWidthPx: 1280,
    visibleWorldHeightPx: 720,
  },
});

If you want background reading before the symbol shelf, the MDN Web Workers guide is the fastest practical reference for why this example pushes both evolution and playback off the main thread.

Parallel evaluation ownership

This worker chapter now sits on top of the public turnkey helper ladder instead of proving each worker primitive in demo-local code. Flappy uses the shared library helpers for capability detection, transport auto-selection, browser worker URL resolution, bounded inference pools, ordered batch evaluation, and the boolean-first NEAT population helper.

The worker still owns the parts that are example-specific rather than transport-generic: deciding which architecture profiles should opt into parallel evaluation, preparing Flappy-specific rollout payloads, and turning worker-local results into the compact generation-ready or playback-step messages the host consumes.

flappy-evolution-worker/flappy-evolution-worker.ts

beginWorkerGenerationRequest

beginWorkerGenerationRequest(
  workerMutableRuntimeState: WorkerMutableRuntimeState,
): void

Begins one asynchronous generation request and captures failures.

This is intentionally fire-and-forget from the protocol perspective. The actual completion signal is the later generation-ready or error message posted back to the host.

Parameters:

Returns: Nothing.

beginWorkerInitialization

beginWorkerInitialization(
  workerMutableRuntimeState: WorkerMutableRuntimeState,
  initPayload: { architectureProfileId?: ExampleArchitectureProfileId | undefined; championNetworkJson?: SerializedNetwork | undefined; populationSize: number; elitismCount: number; rngSeed: number; },
): void

Begins worker initialization and captures asynchronous failures.

The worker retains the initialization promise so later generation requests can await setup completion instead of racing against it.

Parameters:

Returns: Nothing.

beginWorkerPlayback

beginWorkerPlayback(
  workerMutableRuntimeState: WorkerMutableRuntimeState,
  payload: { visibleWorldWidthPx: number; visibleWorldHeightPx: number; },
): Promise<void>

Begins a new playback session from the current evolved population.

A playback session is a deterministic simulation snapshot seeded from the current population. Each new session resets playback RNG and world state so the host can replay generations cleanly.

Parameters:

Returns: Nothing.

createWorkerEvaluationPoolIfSupported

createWorkerEvaluationPoolIfSupported(
  initPayload: { architectureProfileId?: ExampleArchitectureProfileId | undefined; championNetworkJson?: SerializedNetwork | undefined; populationSize: number; elitismCount: number; rngSeed: number; },
): FlappyEvaluationWorkerPool | undefined

Creates the optional shared-memory evaluation pool for recurrent browser profiles.

The pool is useful only when the worker can honestly spawn the emitted shared inference worker with SharedArrayBuffer transport. Otherwise the runtime keeps the worker-local direct evaluator, which avoids a chatty nested-worker path on ordinary local servers without COOP/COEP isolation.

Parameters:

Returns: Shared-memory pool when the host can support it; otherwise undefined.

createWorkerMessageHandler

createWorkerMessageHandler(
  workerMutableRuntimeState: WorkerMutableRuntimeState,
): (event: MessageEvent<WorkerRequestMessage>) => void

Creates the top-level worker message handler.

The returned function is intentionally thin. All protocol decisions are delegated to the router service so the worker entrypoint stays readable as a high-level orchestration module.

Parameters:

Returns: Worker message handler.

Example:

self.onmessage = createWorkerMessageHandler(workerMutableRuntimeState);

createWorkerMutableRuntimeState

createWorkerMutableRuntimeState(): WorkerMutableRuntimeState

Creates the mutable worker runtime state container.

Educational note: The worker keeps one small mutable state bag instead of scattering globals. That makes the protocol flow easier to explain and lets the entrypoint pass a single dependency object through the orchestration helpers.

Returns: Mutable worker runtime state.

createWorkerProtocolHandlers

createWorkerProtocolHandlers(
  workerMutableRuntimeState: WorkerMutableRuntimeState,
): { markStopped: () => void; beginInitialization: (payload: { architectureProfileId?: ExampleArchitectureProfileId | undefined; championNetworkJson?: SerializedNetwork | undefined; populationSize: number; elitismCount: number; rngSeed: number; }) => void; beginGenerationRequest: () => void; hasPopulation: () => boolean; startPlayback: (payload: { visibleWorldWidthPx: number; visibleWorldHeightPx: number; }) => void; hasPlaybackState: () => boolean; processPlaybackStep: (payload: { requestId: number; simulationSteps: number; visibleWorldWidthPx: number; visibleWorldHeightPx: number; }) => void; postWorkerMessage: typeof postWorkerMessage; }

Creates protocol handlers bound to the mutable worker runtime state.

This helper is the bridge between the pure protocol router and the impure worker runtime. Each callback closes over the same mutable state bag so the protocol layer can remain small and declarative.

Parameters:

Returns: Protocol handler bundle.

evolveAndPublishGeneration

evolveAndPublishGeneration(
  workerMutableRuntimeState: WorkerMutableRuntimeState,
): Promise<void>

Evolves one generation and publishes the best-network summary message.

Educational note: This method is the orchestration seam between evolutionary search and browser rendering: it runs evolution, snapshots the population, and emits a compact payload for UI state updates.

Returns: Promise resolved after generation payload is posted.

initializeRuntime

initializeRuntime(
  workerMutableRuntimeState: WorkerMutableRuntimeState,
  initPayload: { architectureProfileId?: ExampleArchitectureProfileId | undefined; championNetworkJson?: SerializedNetwork | undefined; populationSize: number; elitismCount: number; rngSeed: number; },
): Promise<void>

Initializes the worker-local NEAT runtime used by browser evolution playback.

Educational note: The runtime is configured once with deterministic RNG state and a lightweight early-termination fitness rollout. Keeping this setup centralized helps ensure reproducibility between runs and keeps host<->worker contracts simple.

This function only prepares the evolutionary controller. It does not start playback and it does not evolve a generation yet; those remain separate protocol steps so the host can control them explicitly.

Parameters:

Returns: Promise resolved when runtime setup is complete.

logWorkerEvaluationPoolFallback

logWorkerEvaluationPoolFallback(
  architectureProfileId: ExampleArchitectureProfileId | undefined,
  reasons: readonly string[],
): void

Logs why recurrent evaluation stayed on the direct worker-local evaluator.

Parameters:

Returns: Nothing.

postWorkerMessage

postWorkerMessage(
  workerMessage: WorkerResponseMessage,
  transferList: Transferable[] | undefined,
): void

Posts a typed message from worker to host.

This is the narrowest possible transport helper: all message construction is done elsewhere so the README can point to one stable worker-to-host boundary.

Parameters:

Returns: Nothing.

postWorkerRuntimeStatus

postWorkerRuntimeStatus(
  payload: { phase: WorkerRuntimeStatusPhase; statusText: string; detail?: string | undefined; },
): void

Posts an informational runtime-status update from worker to browser host.

Parameters:

Returns: Nothing.

processWorkerPlaybackStepRequest

processWorkerPlaybackStepRequest(
  workerMutableRuntimeState: WorkerMutableRuntimeState,
  playbackStepPayload: { requestId: number; simulationSteps: number; visibleWorldWidthPx: number; visibleWorldHeightPx: number; },
): Promise<void>

Advances playback by a host-requested number of simulation steps.

Educational note: The browser host can request multiple simulation steps per RAF to trade visual smoothness against throughput. This function keeps that loop deterministic and emits one compact snapshot payload per request.

Importantly, the worker remains authoritative for deciding when the run is over and which bird should be treated as the playback winner.

Parameters:

Returns: Nothing.

resolveWorkerEvaluationRuntimeStatusPayload

resolveWorkerEvaluationRuntimeStatusPayload(
  evaluationWorkerPool: FlappyEvaluationWorkerPool | undefined,
): { phase: WorkerRuntimeStatusPhase; statusText: string; detail?: string | undefined; }

Resolves the status payload for the active recurrent evaluation transport.

Parameters:

Returns: Runtime-status payload for the HUD.

flappy-evolution-worker/flappy-evolution-worker.types.ts

SerializedNetwork

Loose JSON-compatible network payload used by worker messages.

The worker never posts live Network instances back to the browser host. The transferable inference payload now owns playback-friendly transport, while this JSON bridge remains only for the browser-side network-view cache.

WorkerErrorMessage

Worker error response message.

Errors are normalized into a display-safe string so the host UI can surface failures without depending on worker-specific exception classes.

WorkerFrameBirdSnapshot

Render-only bird snapshot DTO posted to host.

This shape is useful conceptually, but the current transport uses the packed typed-array variant for lower allocation and transfer cost.

WorkerFramePipeSnapshot

Render-only pipe snapshot DTO posted to host.

Like WorkerFrameBirdSnapshot, this documents the logical payload shape even though the worker currently sends the packed transport form.

WorkerGenerationReadyMessage

Worker generation-ready response message.

The browser host uses this message to refresh HUD state, render the current best network visualization, and start playback for the current population. Generation zero can be a startup release after warm-start rather than a full post-selection NEAT generation.

WorkerHeuristicObservationFeatures

Structured features used by heuristic generation-0 teacher policy.

The warm-start service reuses the same high-level observation semantics as the real policy inference path, which keeps the heuristic teacher aligned with the features evolved networks will later see.

WorkerInitMessage

Worker init request message.

This is the first message the host should send. It seeds deterministic RNG state and configures the worker-local NEAT runtime.

WorkerPackedPlaybackBirdSnapshot

Packed typed-array payload for playback bird snapshot transport.

The host can reconstruct renderer-friendly bird views from these arrays while the worker keeps the authoritative mutable simulation objects private.

WorkerPackedPlaybackPipeSnapshot

Packed typed-array payload for playback pipe snapshot transport.

Packing the per-pipe fields into column-oriented typed arrays makes the browser/worker boundary cheaper than sending large arrays of object literals on every animation frame.

WorkerPlaybackFrameSnapshot

Full frame snapshot payload posted to host.

Educational note: packed-v1 is a transport contract, not a rendering primitive. The versioned format string gives the browser host a stable way to decode snapshots even if the worker later gains additional packed fields or alternate transport modes.

Example:

const message = {
  type: 'playback-step',
  payload: {
    requestId: 7,
    snapshot,
    done: false,
  },
};

WorkerPlaybackState

Mutable simulation state stored between worker playback requests.

A start-playback message creates this state once, and each request-playback-step message advances it by a host-selected number of simulation steps.

WorkerPlaybackStepMessage

Worker playback-step response message.

The message carries the packed frame snapshot plus optional instrumentation and end-of-run summary statistics when the whole simulated population has been eliminated.

The split between per-frame snapshot data and end-of-run summary fields keeps the hot path compact while still giving the host enough telemetry to update HUD metrics when a playback session completes.

WorkerPopulationBird

Mutable bird state tracked by the worker playback simulation.

Educational note: Each bird keeps both physics state and policy state. The observationMemoryState field stays on the bird so worker playback shares the same control-state shape as evaluation and browser helpers. The current controller input does not read external history, but the aligned state shelf keeps future opt-in experiments from forking the runtime contracts.

WorkerPopulationPipe

Mutable pipe state tracked by the worker playback simulation.

These objects exist only inside the worker runtime. The host later receives a packed snapshot derived from them rather than these live mutable records.

WorkerRequestGenerationMessage

Worker request asking for the next playable generation payload.

The first response may release the bounded generation-zero warm-start population before a full recurrent evolution pass. Later responses publish normally evolved populations.

WorkerRequestMessage

Union of inbound worker request messages.

Reading this union top-to-bottom is the quickest way to understand the worker protocol: initialize, evolve, start playback, step playback, then stop.

WorkerRequestPlaybackStepMessage

Worker request asking to advance playback by N simulation steps.

The host typically sends this once per animation frame and chooses simulationSteps based on how much simulation throughput it wants relative to rendering smoothness.

WorkerResponseMessage

Union of outbound worker response messages.

Together with WorkerRequestMessage, this forms the full host/worker protocol contract for the demo.

WorkerRuntimeStatusMessage

Worker runtime status response message.

Status messages are informational and never complete a request. The browser listens for them beside generation/playback responses so long recurrent waits can explain whether work is initializing, evolving, playing back, or using a direct-evaluation fallback.

WorkerRuntimeStatusPhase

Worker phase labels surfaced to the browser HUD during long-running work.

WorkerStartPlaybackMessage

Worker request asking to initialize playback state.

This materializes the mutable world state for the current evolved population. After this message succeeds, the host can begin issuing playback-step requests.

WorkerStopMessage

Worker stop request message.

This is a cooperative shutdown signal. Long-running worker flows can observe the stopped flag and fail fast instead of continuing work the UI no longer cares about.

flappy-evolution-worker/flappy-evolution-worker.runtime.service.ts

buildWorkerSharedRolloutSeedBatch

buildWorkerSharedRolloutSeedBatch(
  workerInitSeed: number,
  generation: number,
  sharedRolloutSeedCount: number,
): number[]

Builds the deterministic rollout seed batch used by the pipe-first worker objective.

Parameters:

Returns: Shared rollout seed batch.

createInitializedWorkerRuntime

createInitializedWorkerRuntime(
  initPayload: { architectureProfileId?: ExampleArchitectureProfileId | undefined; championNetworkJson?: SerializedNetwork | undefined; populationSize: number; elitismCount: number; rngSeed: number; },
  workerRuntimeDependencies: WorkerRuntimeDependencies,
): default

Creates and configures the worker-local NEAT runtime used by browser evolution playback.

Educational note: The browser worker reuses the same core NeatapticTS runtime as the Node-side trainer, but trims configuration down to the pieces needed for an interactive example: deterministic seeding, feed-forward mutation policy, and a fitness function that favors quick browser-visible iteration.

The resulting runtime is both the evolution engine and the source of the population that later playback requests visualize.

For background reading, the Wikipedia article on "Neuroevolution of augmenting topologies" is a useful overview of the family of ideas this demo is exercising, even though the repository implements its own detailed runtime behavior and modern extensions.

Parameters:

Returns: Initialized NEAT runtime.

Example:

const neatRuntime = createInitializedWorkerRuntime({
  populationSize: 50,
  elitismCount: 10,
  rngSeed: 12345,
});

createWorkerFitnessEvaluator

createWorkerFitnessEvaluator(
  architectureProfileId: NonNullable<ExampleArchitectureProfileId | undefined>,
  workerInitSeed: number,
  resolveCurrentGeneration: () => number,
  workerRuntimeDependencies: WorkerRuntimeDependencies,
): NeatFitnessFunction

Builds the worker fitness evaluator for the selected architecture profile.

NARX, GRU, and LSTM benefit from a slightly stricter browser objective because the tiny interactive population is otherwise too willing to overfit one lucky rollout and stall at a zero-pipe local optimum.

Parameters:

Returns: Worker-local scalar fitness function.

logWorkerFitnessTransportMode

logWorkerFitnessTransportMode(
  architectureProfileId: NonNullable<ExampleArchitectureProfileId | undefined>,
  usesPipeFirstSharedSeeds: boolean,
  usesParallelWorkerPool: boolean,
): void

Logs the worker-side fitness transport selection.

Parameters:

Returns: Nothing.

resolveFirstSharedRolloutSeedBatch

resolveFirstSharedRolloutSeedBatch(
  sharedRolloutSeeds: readonly number[],
): number[]

Resolves the cheap first-seed batch used before full recurrent scoring.

Parameters:

Returns: One-seed batch used for the progressive gate.

resolveRequiredFirstSeedAggregate

resolveRequiredFirstSeedAggregate(
  aggregateByGenome: ReadonlyMap<default, FlappySeedBatchEvaluation>,
  genome: default,
): FlappySeedBatchEvaluation

Resolves the required first-seed aggregate for a genome.

Parameters:

Returns: Aggregate evaluation for the genome.

resolveWorkerPipeFirstEvaluationPlan

resolveWorkerPipeFirstEvaluationPlan(
  architectureProfileId: NonNullable<ExampleArchitectureProfileId | undefined>,
): WorkerPipeFirstEvaluationPlan

Resolves the recurrent worker evaluation plan for one browser profile.

LSTM gets a slightly broader shared-seed batch than the other recurrent profiles because the heavier gated controller was still regressing after generation-zero warm-start when browser selection only saw one static lane.

Parameters:

Returns: Shared-seed batch size for worker fitness.

resolveWorkerPipeFirstRolloutOptions

resolveWorkerPipeFirstRolloutOptions(): { enableEarlyTermination: true; maxFrames: number; normalizeFitness: true; pipeProgressTarget: number; }

Resolves shared rollout options for the pipe-first browser objective.

Returns: Rollout options used by recurrent worker scoring.

resolveWorkerSeedNetwork

resolveWorkerSeedNetwork(
  initPayload: { architectureProfileId?: ExampleArchitectureProfileId | undefined; championNetworkJson?: SerializedNetwork | undefined; populationSize: number; elitismCount: number; rngSeed: number; },
  architectureProfileId: NonNullable<ExampleArchitectureProfileId | undefined>,
): default

Resolves the worker seed network from a saved champion override or the shared profile template.

Parameters:

Returns: Seed network for the worker-local NEAT runtime.

scorePipeFirstWorkerAggregateEvaluation

scorePipeFirstWorkerAggregateEvaluation(
  aggregateEvaluation: FlappySeedBatchEvaluation,
): number

Scores one aggregate with a pipe-first browser selection scalar.

The interactive worker population is tiny, so escaping the first-pipe local optimum matters more than preserving the exact trainer ranking stack. This scalar therefore promotes mean pipe progress first, then uses survival and stability as tie-breakers inside the same shared-seed batch.

Parameters:

Returns: Scalar fitness consumed by the browser worker NEAT loop.

shouldSpendFullWorkerSeedBatch

shouldSpendFullWorkerSeedBatch(
  aggregateEvaluation: FlappySeedBatchEvaluation,
): boolean

Resolves whether one genome should receive the full recurrent seed batch.

Parameters:

Returns: True when the genome showed enough pipe progress to justify full scoring.

flappy-evolution-worker/flappy-evolution-worker.protocol.service.ts

routeWorkerProtocolMessage

routeWorkerProtocolMessage(
  workerMessage: WorkerRequestMessage,
  handlers: WorkerProtocolHandlers,
): void

Routes one inbound worker request message to the corresponding runtime action.

Educational note: This router is the protocol gatekeeper for the worker. It enforces the two important sequencing rules in the demo:

In practice this acts like a tiny finite-state machine. If you want a quick conceptual refresher, the Wikipedia article on "finite-state machine" maps well onto the worker's init -> evolve -> start playback -> step playback flow.

Parameters:

Returns: Nothing.

Example:

routeWorkerProtocolMessage(
  { type: 'request-generation' },
  workerProtocolHandlers,
);

WorkerProtocolHandlers

Callback bundle used by worker protocol routing.

Each callback corresponds to one legal transition in the worker message protocol. Keeping the router dependent on this narrow interface makes the protocol easy to read in generated docs and easy to test independently from the worker-global self.onmessage hook.

flappy-evolution-worker/flappy-evolution-worker.evolution.service.ts

buildGenerationReadyMessage

buildGenerationReadyMessage(
  options: { architectureProfileId: ExampleArchitectureProfileId; generation: number; bestNetwork: default; population: default[]; },
): WorkerGenerationReadyMessage

Builds the generation-ready worker response from a population snapshot.

Parameters:

Returns: Generation-ready worker response payload.

evolveAndBuildGenerationReadyMessage

evolveAndBuildGenerationReadyMessage(
  options: WorkerEvolutionServiceOptions,
): Promise<WorkerGenerationReadyMessage>

Creates the next compact generation-ready response payload.

Educational note: The first browser-visible population should not wait for a full recurrent selection batch or optional warm-start assist. When the caller opts in, generation zero is released immediately so playback can begin promptly. Later requests run the bounded warm-start assist, the normal NEAT evolve() pass, and emit the same compact summary shape: generation index, best fitness, transferable inference payloads for playback, and the temporary JSON visualization bridge used by the host network panel.

Parameters:

Returns: Generation-ready worker response payload.

Example:

const generationMessage = await evolveAndBuildGenerationReadyMessage({
  initializationPromise,
  neatRuntime,
  isStopped: () => false,
  warmStartGenerationZeroIfNeeded,
  setCurrentPopulation,
});

resolveBestNetworkFromPopulation

resolveBestNetworkFromPopulation(
  population: readonly default[],
): default

Chooses the best network from a population snapshot using available scores.

Parameters:

Returns: Highest-scored network, falling back to the first network when scores are equal.

resolveGenerationReadyMessageTransferList

resolveGenerationReadyMessageTransferList(
  workerMessage: WorkerGenerationReadyMessage,
): ArrayBuffer[]

Collect the transferable buffers owned by one generation-ready response payload.

The transfer list intentionally includes only the typed-array inference payloads. The temporary JSON visualization bridge remains structured-clone data so the browser can continue rebuilding network-view models separately.

Parameters:

Returns: Transfer list for postMessage(...).

resolveRuntimePopulation

resolveRuntimePopulation(
  runtimeNeat: { population?: default[] | undefined; },
  fallbackNetwork: default | undefined,
): default[]

Resolves the current runtime population with an optional best-network fallback.

Parameters:

Returns: Non-empty population when one is available.

runBestEffortWarmStart

runBestEffortWarmStart(
  warmStartGenerationZeroIfNeeded: (neatController: default) => Promise<void>,
  neatRuntime: default,
): Promise<void>

Runs generation-zero warm-start as an optional assist before regular evolution.

Parameters:

Returns: Promise resolved after warm-start succeeds or is skipped.

shouldPublishStartupPopulationBeforeEvolution

shouldPublishStartupPopulationBeforeEvolution(
  generation: number,
  population: readonly default[],
  publishStartupPopulationBeforeFirstEvolution: boolean | undefined,
): boolean

Resolves whether the worker should release generation zero before evolving.

Parameters:

Returns: True when generation zero can be published immediately for playback.

WorkerEvolutionServiceOptions

Dependencies required to evolve one generation and prepare host payload output.

Educational note: This interface isolates the evolution step from the worker entrypoint. That makes the README easier to follow: the entrypoint owns protocol orchestration, while this service owns one well-defined "run generation -> publish summary" slice of behavior.

flappy-evolution-worker/flappy-evolution-worker.playback.service.ts

beginWorkerPlaybackSession

beginWorkerPlaybackSession(
  options: { currentPopulation: default[]; payload: { visibleWorldWidthPx: number; visibleWorldHeightPx: number; }; createPopulationRenderState: (networks: default[], rng: FlappyRng, initialVisibleWorldWidthPx: number, initialVisibleWorldHeightPx: number, channelWorkerUrl?: string | undefined) => WorkerPlaybackState; channelWorkerUrl?: string | undefined; },
): { currentPlaybackState: WorkerPlaybackState; currentPlaybackRng: FlappyRng; playbackWinnerIndex: number; }

Creates a fresh worker playback session state from the current evolved population.

Educational note: Evolution and playback are intentionally separated. Evolution produces a new population, then playback freezes that population into a deterministic simulation state that the host can step frame-by-frame for rendering.

Parameters:

Returns: Playback runtime state and deterministic RNG.

Example:

const session = beginWorkerPlaybackSession({
  currentPopulation,
  payload: { visibleWorldWidthPx: 1280, visibleWorldHeightPx: 720 },
  createPopulationRenderState,
});

maybeDownshiftSuccessfulBrowserPopulation

maybeDownshiftSuccessfulBrowserPopulation(
  neatRuntime: default | undefined,
  winnerPipesPassed: number,
): void

Downshifts the worker's future browser population budget after a successful playback run.

The current generation has already been evaluated, so the savings apply to future generations only. This keeps the demo responsive once an architecture has already demonstrated that it can clear the live pipe target.

Parameters:

Returns: Nothing.

processWorkerPlaybackStep

processWorkerPlaybackStep(
  options: { playbackStepPayload: { requestId: number; simulationSteps: number; visibleWorldWidthPx: number; visibleWorldHeightPx: number; }; currentPlaybackState: WorkerPlaybackState; currentPlaybackRng: FlappyRng; currentPopulation: default[]; neatRuntime: default | undefined; stepPopulationFrame: (renderState: WorkerPlaybackState, rng: FlappyRng, difficultyProfile: SharedDifficultyProfile) => Promise<number>; createPlaybackSnapshot: (playbackState: WorkerPlaybackState) => WorkerPlaybackFrameSnapshot; resolvePlaybackSnapshotTransferList: (snapshot: WorkerPlaybackFrameSnapshot) => Transferable[]; postWorkerMessage: (workerMessage: WorkerResponseMessage, transferList?: Transferable[] | undefined) => void; },
): Promise<{ currentPlaybackState: WorkerPlaybackState | undefined; currentPlaybackRng: FlappyRng | undefined; currentPopulation: default[]; playbackWinnerIndex: number; }>

Processes one worker playback-step request including completion/finalization logic.

Educational note: One playback request may advance multiple simulation steps. This lets the host trade visual smoothness against throughput while keeping the worker in control of simulation correctness, winner selection, and packed snapshot publishing.

Parameters:

Returns: Updated playback runtime state after processing this step.

flappy-evolution-worker/flappy-evolution-worker.snapshot.utils.ts

canReuseSharedSnapshotBuffers

canReuseSharedSnapshotBuffers(): boolean

Resolves whether this host can reuse shared snapshot buffers safely.

Returns: True when SharedArrayBuffer snapshot storage is available.

createFloat32SnapshotArray

createFloat32SnapshotArray(
  elementCount: number,
  useSharedBuffer: boolean,
): Float32Array<ArrayBufferLike>

Creates one packed float column for snapshot transport.

Parameters:

Returns: Float32 snapshot column.

createUint32SnapshotArray

createUint32SnapshotArray(
  elementCount: number,
  useSharedBuffer: boolean,
): Uint32Array<ArrayBufferLike>

Creates one packed uint32 column for snapshot transport.

Parameters:

Returns: Uint32 snapshot column.

createUint8SnapshotArray

createUint8SnapshotArray(
  elementCount: number,
  useSharedBuffer: boolean,
): Uint8Array<ArrayBufferLike>

Creates one packed uint8 column for snapshot transport.

Parameters:

Returns: Uint8 snapshot column.

createWorkerPlaybackSnapshot

createWorkerPlaybackSnapshot(
  playbackState: WorkerPlaybackState,
): WorkerPlaybackFrameSnapshot

Creates a serializable snapshot of current playback state.

Workers should send only structured-clone-safe payloads. This helper strips runtime-only references (e.g., network instances, sets) and keeps only renderer-relevant fields.

Educational note: The snapshot is intentionally column-oriented. By packing values into typed arrays, the worker can transfer large bird populations to the host with much lower overhead than a per-frame array of nested objects.

This is a small example of a structure-of-arrays transport layout. If that pattern is unfamiliar, the Wikipedia article on "AoS and SoA" is a good short reference for why packed columns are often friendlier to hot-path data movement than arrays of rich objects.

Parameters:

Returns: Immutable frame snapshot for the host.

createWorkerPlaybackSnapshotBuffers

createWorkerPlaybackSnapshotBuffers(
  pipeCount: number,
  birdCount: number,
  useSharedBuffers: boolean,
): WorkerPlaybackSnapshotBuffers

Creates typed-array storage for one packed snapshot.

Parameters:

Returns: Snapshot buffer shelf.

isTransferableArrayBuffer

isTransferableArrayBuffer(
  buffer: ArrayBufferLike,
): boolean

Narrows transfer-list candidates to transferable ArrayBuffers.

Parameters:

Returns: True when the buffer can be passed through postMessage transfer list.

resolveWorkerPlaybackSnapshotBuffers

resolveWorkerPlaybackSnapshotBuffers(
  playbackState: WorkerPlaybackState,
  pipeCount: number,
  birdCount: number,
): WorkerPlaybackSnapshotBuffers

Resolves snapshot column storage for one playback state.

Parameters:

Returns: Snapshot buffers sized for the current frame.

resolveWorkerPlaybackSnapshotTransferList

resolveWorkerPlaybackSnapshotTransferList(
  snapshot: WorkerPlaybackFrameSnapshot,
): Transferable[]

Resolves transferable buffers for one packed playback snapshot.

The returned buffers should be passed as the second argument to postMessage(...) so ownership moves to the host thread instead of copying the typed-array contents.

That ownership transfer is a large part of why the worker can stream full population snapshots without forcing the main thread to pay unnecessary copy costs every frame.

Parameters:

Returns: Transfer list used to move typed-array buffers without copying.

flappy-evolution-worker/flappy-evolution-worker.simulation.types.ts

WorkerPlaybackFrameContext

Shared mutable inputs for one worker playback frame simulation pass.

Educational note: The frame service computes several derived geometry values once per logical frame and threads them through the substep helpers in this context object. That keeps the top-level simulation flow declarative while avoiding repeated argument sprawl across helper calls.

flappy-evolution-worker/flappy-evolution-worker.simulation.utils.ts

closeWorkerPopulationRenderState

closeWorkerPopulationRenderState(
  playbackState: WorkerPlaybackState | undefined,
): Promise<void>

Closes any persistent inference channels carried by a playback state.

Parameters:

Returns: Promise resolved after all bird channels are closed.

createWorkerPopulationRenderState

createWorkerPopulationRenderState(
  networks: default[],
  rng: RngLike,
  initialVisibleWorldWidthPx: number,
  initialVisibleWorldHeightPx: number,
  channelWorkerUrl: string | undefined,
): WorkerPlaybackState

Creates initial playback state for a population of networks.

Educational note: This is the ownership boundary for worker playback initialization. The frame simulation service mutates the returned state on every step, but only this helper decides how a fresh population is placed into the world at time zero.

Parameters:

Returns: Fresh mutable playback state.

Example:

const playbackState = createWorkerPopulationRenderState(
  currentPopulation,
  rng,
  1280,
  720,
);

flappy-evolution-worker/flappy-evolution-worker.simulation.frame.service.ts

advanceBirdPhysics

advanceBirdPhysics(
  frameContext: WorkerPlaybackFrameContext,
): void

Integrates bird velocity and vertical motion for one control substep.

Parameters:

Returns: Nothing.

advancePipes

advancePipes(
  frameContext: WorkerPlaybackFrameContext,
): void

Advances all visible pipes and culls those that have left the camera window.

Parameters:

Returns: Nothing.

commitPassedPipeProgress

commitPassedPipeProgress(
  bird: WorkerPopulationBird,
  pipe: WorkerPopulationPipe,
): void

Commits one passed-pipe progress increment for a bird when eligible.

Parameters:

Returns: Nothing.

incrementLivingBirdFrameCounters

incrementLivingBirdFrameCounters(
  renderState: WorkerPlaybackState,
): void

Increments survival counters for birds that remain active at frame start.

Parameters:

Returns: Nothing.

resolveBirdCollisionAgainstPipe

resolveBirdCollisionAgainstPipe(
  bird: WorkerPopulationBird,
  pipe: WorkerPopulationPipe,
  frameContext: WorkerPlaybackFrameContext,
): boolean

Resolves whether a bird collides with one pipe corridor during this substep.

Parameters:

Returns: true when the bird overlaps the pipe body instead of the gap.

resolveBirdControlActions

resolveBirdControlActions(
  frameContext: WorkerPlaybackFrameContext,
): Promise<number>

Runs policy evaluation and commits the resulting observation memory updates.

Parameters:

Returns: Number of activation calls performed in the substep.

resolveBirdOutOfBounds

resolveBirdOutOfBounds(
  bird: WorkerPopulationBird,
  visibleWorldHeightPx: number,
): boolean

Resolves whether a bird has exceeded the vertical play area.

Parameters:

Returns: true when the bird is outside the vertical bounds.

resolveBirdTerminationAndProgress

resolveBirdTerminationAndProgress(
  frameContext: WorkerPlaybackFrameContext,
): void

Resolves bird deaths and passed-pipe progress after motion is applied.

Parameters:

Returns: Nothing.

resolveCameraLeftXPx

resolveCameraLeftXPx(
  visibleWorldWidthPx: number,
): number

Resolves the current left-edge of the visible world in world-space pixels.

Parameters:

Returns: Left edge x-position in world coordinates.

runWorkerPopulationControlSubstep

runWorkerPopulationControlSubstep(
  frameContext: WorkerPlaybackFrameContext,
): Promise<number>

Advances one control substep of the worker playback simulation.

Parameters:

Returns: Number of activation calls performed in the substep.

spawnPipeIfNeeded

spawnPipeIfNeeded(
  frameContext: WorkerPlaybackFrameContext,
): void

Spawns a new pipe when the substep budget crosses the spawn boundary.

Parameters:

Returns: Nothing.

stepWorkerPopulationFrame

stepWorkerPopulationFrame(
  renderState: WorkerPlaybackState,
  rng: RngLike,
  difficultyProfile: SharedDifficultyProfile,
): Promise<number>

Advances the whole population simulation by one logical frame.

Educational note: One logical frame is internally split into smaller control substeps so the worker can make flap decisions, apply gravity, move pipes, spawn new pipes, and resolve collisions with better numerical stability than a single large integration jump.

This function is the main simulation ownership boundary for the folder. The companion simulation.utils file creates initial state; this service is responsible for mutating that state over time.

Parameters:

Returns: Number of policy activation calls made in this frame.

flappy-evolution-worker/flappy-evolution-worker.warm-start.service.ts

applyTeacherWarmStart

applyTeacherWarmStart(
  templateNetwork: default,
  trainingSet: { input: number[]; output: number[]; }[],
  architectureProfileId: ExampleArchitectureProfileId,
): void

Applies the teacher phase that best matches the selected architecture family.

Parameters:

Returns: Nothing.

applyTemplateWeightsWithNoise

applyTemplateWeightsWithNoise(
  genome: default,
  template: default,
  rng: FlappyRng,
  noise: { weightStdDev: number; biasStdDev: number; },
): void

Copies template parameters into a genome and injects small Gaussian noise.

Educational note: The template network gives generation 0 a shared prior, while the noise terms restore diversity so the population is still worth evolving.

Parameters:

Returns: Nothing.

applyWarmStartGenerationZero

applyWarmStartGenerationZero(
  neatController: default,
  warmStartState: WorkerWarmStartState,
  dependencies: WorkerWarmStartDependencies,
): void

Applies the generation-zero warm-start body when the runtime is still eligible.

Parameters:

Returns: Nothing.

buildHeuristicPretrainSet

buildHeuristicPretrainSet(
  rng: FlappyRng,
  sampleCount: number,
): { input: number[]; output: number[]; }[]

Builds synthetic supervised samples for generation-0 behavior cloning.

Educational note: These samples are not recorded gameplay traces. They are synthetic states generated from the same observation pipeline used during real playback so the teacher labels and the evolved policy inputs stay in the same feature space. The critical rule is that the teacher must only read the same compact current-frame controller shelf that the live network will later receive.

Parameters:

Returns: Supervised dataset of input/output pairs.

buildWarmStartRolloutSeedBatch

buildWarmStartRolloutSeedBatch(
  rng: FlappyRng,
  seedCount: number,
): number[]

Builds the deterministic shared rollout seed batch used during warm-start refinement.

Parameters:

Returns: Shared rollout seed batch.

composeWarmStartSeedBatchEvaluation

composeWarmStartSeedBatchEvaluation(
  episodeResults: readonly FlappyEpisodeResult[],
): FlappySeedBatchEvaluation

Composes the completed warm-start rollouts into aggregate evidence.

Parameters:

Returns: Aggregate warm-start evaluation metrics.

createWarmStartDeadline

createWarmStartDeadline(
  architectureProfileId: ExampleArchitectureProfileId,
  resolveCurrentTimeMs: () => number,
): WorkerWarmStartDeadline

Creates the optional deadline used by recurrent warm-start refinement.

Parameters:

Returns: Warm-start deadline contract.

evaluateWarmStartTemplateAcrossRollouts

evaluateWarmStartTemplateAcrossRollouts(
  templateNetwork: default,
  sharedRolloutSeeds: readonly number[],
  warmStartDeadline: WorkerWarmStartDeadline,
  runWarmStartRollout: WorkerWarmStartRolloutRunner,
): FlappySeedBatchEvaluation

Evaluates one warm-start template across the shared rollout seed batch.

Parameters:

Returns: Aggregate shared-seed evaluation.

interpolateValue

interpolateValue(
  startValue: number,
  endValue: number,
  ratio: number,
): number

Linearly interpolates between two scalar values.

Parameters:

Returns: Interpolated value.

isWarmStartDeadlineExpired

isWarmStartDeadlineExpired(
  warmStartDeadline: WorkerWarmStartDeadline,
): boolean

Resolves whether rollout refinement should yield to regular NEAT evolution.

Parameters:

Returns: True when the warm-start assist has spent its allowed budget.

isWarmStartEvaluationBetter

isWarmStartEvaluationBetter(
  candidateEvaluation: FlappySeedBatchEvaluation,
  bestEvaluation: FlappySeedBatchEvaluation,
  architectureProfileId: ExampleArchitectureProfileId,
): boolean

Resolves whether the candidate batch evaluation beats the current best one.

Robust fitness is the primary signal. Mean pipe progress and mean frame survival act as deterministic tie-breakers so upgrades remain stable when the robust score is identical.

Parameters:

Returns: True when the candidate should replace the incumbent template.

optimizeWarmStartTemplateNetwork

optimizeWarmStartTemplateNetwork(
  templateNetwork: default,
  workerInitSeed: number,
  architectureProfileId: ExampleArchitectureProfileId,
  warmStartDeadline: WorkerWarmStartDeadline,
  runWarmStartRollout: WorkerWarmStartRolloutRunner,
): default

Refines the generation-0 template against real Flappy rollouts.

The warm-start teacher gets the template out of pure-random territory, but it still only imitates a simple flap heuristic. This refinement pass keeps the topology fixed and searches the parameter surface directly against actual rollout fitness so the first visible generation starts closer to competent control.

Parameters:

Returns: Best rollout-refined template found within the bounded budget.

perturbNetworkParametersInPlace

perturbNetworkParametersInPlace(
  network: default,
  rng: FlappyRng,
  noise: { weightStdDev: number; biasStdDev: number; },
): void

Applies additive Gaussian noise to an existing network in-place.

Unlike the later population seeding copy step, this helper perturbs the candidate template directly so the rollout optimizer can evaluate one local parameter move at a time while keeping the topology unchanged.

Parameters:

Returns: Nothing.

resolveHeuristicTeacherFlapDecisionFromObservationVector

resolveHeuristicTeacherFlapDecisionFromObservationVector(
  observationVector: readonly number[],
): boolean

Heuristic teacher policy used to label synthetic pretraining samples.

The rule intentionally stays simple and interpretable: flap when the bird is meaningfully below the next gap center, not already rising fast, and either near the next pipe or drifting close to the lower edge of the current gap.

The key constraint is architectural consistency: this teacher reads only the same compact 6-value controller vector used by regular training and playback. Extra legacy-derived features must not influence generation-zero labels.

Parameters:

Returns: True when the teacher says to flap.

resolveWarmStartAnnealRatio

resolveWarmStartAnnealRatio(
  optimizationStepIndex: number,
  totalOptimizationSteps: number,
): number

Resolves the annealing ratio for rollout-guided warm-start refinement.

Parameters:

Returns: Clamped ratio in the inclusive range [0, 1].

resolveWarmStartEvaluationScore

resolveWarmStartEvaluationScore(
  aggregateEvaluation: FlappySeedBatchEvaluation,
  architectureProfileId: ExampleArchitectureProfileId,
): number

Resolves the architecture-specific scalar used during warm-start rollout refinement.

NARX, GRU, and LSTM use a pipe-first scalar so rollout refinement prefers real pipe progress over a dense-shaping local optimum before the browser NEAT loop begins.

Parameters:

Returns: Scalar score used for candidate comparison.

resolveWarmStartRolloutOptimizationPlan

resolveWarmStartRolloutOptimizationPlan(
  architectureProfileId: ExampleArchitectureProfileId,
): WorkerWarmStartRolloutOptimizationPlan

Resolves the rollout-refinement budget for one warm-start architecture profile.

NARX gets a stronger rollout pass, while GRU keeps a smaller bounded pass so the browser worker stays responsive after the Flappy-specific readout shortcut expands the recurrent seed.

Parameters:

Returns: Shared-seed count, optimization-step budget, and optional time cap.

resolveWorkerWarmStartTeacherStrategy

resolveWorkerWarmStartTeacherStrategy(
  architectureProfileId: ExampleArchitectureProfileId,
): WorkerWarmStartTeacherStrategy

Resolves which teacher path should run before rollout refinement.

Parameters:

Returns: Teacher strategy best matched to the architecture family.

sampleGaussian

sampleGaussian(
  rng: FlappyRng,
): number

Samples one standard-normal value using the Box-Muller transform.

If you are unfamiliar with the transform, the Wikipedia article on "Box-Muller transform" is a useful short background read. The worker uses it here because it is deterministic, dependency-light, and good enough for small noise injection during warm-start diversification.

Parameters:

Returns: One approximately standard-normal random value.

warmStartWorkerGenerationZeroIfNeeded

warmStartWorkerGenerationZeroIfNeeded(
  neatController: default,
  warmStartState: WorkerWarmStartState,
  dependencies: WorkerWarmStartDependencies,
): Promise<void>

Applies a one-time generation-0 warm-start to improve initial demo quality.

Educational note: The worker entry should stay protocol-first. This service owns the short supervised bootstrap pass that nudges generation 0 away from pure noise while preserving the later NEAT-driven search loop.

Conceptually this is a lightweight behavior-cloning pass. If you want more background, the Wikipedia article on "imitation learning" is a helpful bridge between the heuristic teacher used here and the later evolutionary search.

Parameters:

Returns: Promise resolved when warm-start evaluation finishes.

Example:

await warmStartWorkerGenerationZeroIfNeeded(neatRuntime, {
  workerInitSeed: 123,
  generationZeroWarmStartApplied: false,
});

WorkerWarmStartDeadline

Deadline contract used by recurrent rollout refinement.

WorkerWarmStartDependencies

Dependency bag for generation-0 warm-start orchestration.

The production path uses the real heuristic dataset builder and rollout-guided template refinement. Tests can override these seams to keep assertions small and deterministic.

WorkerWarmStartRolloutOptimizationPlan

Rollout-refinement budget resolved for one warm-start architecture profile.

WorkerWarmStartRolloutRunner

WorkerWarmStartRolloutRunner(
  templateNetwork: default,
  rolloutOptions: FlappyRolloutOptions,
): FlappyEpisodeResult

Callable shape used to evaluate one warm-start rollout candidate.

Tests can inject this seam to observe deadline hooks without running the full Flappy simulator, while production uses the real rollout service.

WorkerWarmStartState

State carried between generation requests for one worker runtime.

The warm-start service is intentionally one-shot. These fields let the worker remember whether generation 0 has already been bootstrapped and which initial RNG seed should be reused for deterministic synthetic sample generation.

flappy-evolution-worker/flappy-evolution-worker.errors.ts

createWorkerErrorMessage

createWorkerErrorMessage(
  message: string,
): WorkerErrorMessage

Creates a typed worker error response payload from a message string.

Parameters:

Returns: Worker error response message.

Example:

postWorkerMessage(
  createWorkerErrorMessage('Playback step requested before playback start.'),
);

createWorkerErrorMessageFromUnknown

createWorkerErrorMessageFromUnknown(
  error: unknown,
): WorkerErrorMessage

Creates a typed worker error response payload from an unknown thrown value.

This helper keeps the protocol boundary narrow: worker internals can use regular exceptions, while the browser host still receives one predictable WorkerErrorMessage shape.

Parameters:

Returns: Worker error response message.

FLAPPY_WORKER_INIT_FAILED_ERROR_MESSAGE

Worker error emitted when runtime initialization fails unexpectedly.

This message is intentionally stable so the browser host can show a readable error without leaking internal exception shapes into the UI contract.

FLAPPY_WORKER_PLAYBACK_START_REQUIRES_GENERATION_ERROR_MESSAGE

Worker error emitted when playback start is requested before evolution output exists.

Playback is defined over an already-evolved population snapshot. The host must request at least one generation before asking the worker to start playback.

FLAPPY_WORKER_PLAYBACK_STEP_REQUIRES_START_ERROR_MESSAGE

Worker error emitted when playback stepping is requested before playback start.

The protocol is stateful: start-playback materializes the mutable playback state that later request-playback-step messages advance.

resolveWorkerUnknownErrorMessage

resolveWorkerUnknownErrorMessage(
  error: unknown,
): string

Resolves unknown error-like values into display-safe worker error messages.

Educational note: Browser workers can throw anything, including strings or arbitrary objects. Normalizing that value here gives the rest of the protocol a simple string-only error surface.

Parameters:

Returns: Normalized error message string.

flappy-evolution-worker/flappy-evolution-worker.constants.ts

Synthetic sample count used for generation-0 warm-start pretraining.

Educational note: The warm-start service briefly trains a template network on a heuristic teacher before the first NEAT generation is evolved. This value controls how many synthetic state/action examples are generated for that bootstrap pass. Larger values usually make the teacher signal more stable, but they also increase startup latency inside the worker.

FLAPPY_WORKER_GEN0_PRETRAIN_BATCH_SIZE

Batch size for generation-0 warm-start pretraining.

Smaller batches inject a bit more stochasticity into the bootstrap fit, while still keeping the pass cheap enough for a browser worker.

FLAPPY_WORKER_GEN0_PRETRAIN_BIAS_NOISE_STDDEV

Gaussian standard deviation used for post-pretrain node-bias diversification.

Bias noise is slightly smaller than weight noise so the warm-start remains a prior, not a rigid clone of the teacher-fitted template.

FLAPPY_WORKER_GEN0_PRETRAIN_ITERATIONS

Optimizer iteration budget for generation-0 warm-start pretraining.

The goal is not to fully solve Flappy Bird with supervised learning. The worker only needs a short nudge away from completely random action logits so the first browser-visible generation looks less chaotic.

FLAPPY_WORKER_GEN0_PRETRAIN_RATE

Learning rate for generation-0 warm-start pretraining.

This is intentionally moderate: the template network should learn a simple corridor-following prior without overfitting the heuristic teacher.

FLAPPY_WORKER_GEN0_PRETRAIN_ROLLOUT_BIAS_STDDEV_END

Final node-bias noise scale for rollout-guided template refinement.

FLAPPY_WORKER_GEN0_PRETRAIN_ROLLOUT_BIAS_STDDEV_START

Initial node-bias noise scale for rollout-guided template refinement.

FLAPPY_WORKER_GEN0_PRETRAIN_ROLLOUT_OPTIMIZATION_STEPS

Hill-climb step budget used by rollout-guided generation-0 template refinement.

Each step perturbs the current best template, evaluates it on the shared rollout seed batch, and keeps the candidate only when it improves robust fitness. The budget stays intentionally small so worker startup remains fast.

FLAPPY_WORKER_GEN0_PRETRAIN_ROLLOUT_SEED_COUNT

Shared-seed batch size used by rollout-guided generation-0 template refinement.

After the heuristic teacher fit, the worker evaluates the fixed topology on a few real Flappy rollouts so the warm-start prior is pushed toward trajectories that actually survive the environment instead of only matching the synthetic teacher labels.

FLAPPY_WORKER_GEN0_PRETRAIN_ROLLOUT_WEIGHT_STDDEV_END

Final connection-weight noise scale for rollout-guided template refinement.

FLAPPY_WORKER_GEN0_PRETRAIN_ROLLOUT_WEIGHT_STDDEV_START

Initial connection-weight noise scale for rollout-guided template refinement.

Early optimization steps search broadly, then later steps cool toward the smaller end scale below for finer local refinement.

FLAPPY_WORKER_GEN0_PRETRAIN_SAMPLE_COUNT

Synthetic sample count used for generation-0 warm-start pretraining.

Educational note: The warm-start service briefly trains a template network on a heuristic teacher before the first NEAT generation is evolved. This value controls how many synthetic state/action examples are generated for that bootstrap pass. Larger values usually make the teacher signal more stable, but they also increase startup latency inside the worker.

FLAPPY_WORKER_GEN0_PRETRAIN_VISIBLE_WORLD_WIDTH_PX

Visible world width used when generating synthetic warm-start samples.

This should roughly match the browser playback framing so the generated observation vectors look like the states the policy will later see during real worker playback.

FLAPPY_WORKER_GEN0_PRETRAIN_WEIGHT_NOISE_STDDEV

Gaussian standard deviation used for post-pretrain connection-weight diversification.

After the template network is trained once, each genome receives a noisy copy of its weights. That keeps generation 0 visually coherent while preserving enough diversity for NEAT to search meaningfully.

Generated from source JSDoc • GitHub