diff --git a/packages/library/src/core/component.ts b/packages/library/src/core/component.ts index e9aab00a..bc30f199 100644 --- a/packages/library/src/core/component.ts +++ b/packages/library/src/core/component.ts @@ -132,7 +132,10 @@ export class Component extends BaseComponent { // Hook up state from controller this.state = this.internals.controller.global.datastore?.state - this.random = new Random(this.options.random) + this.random = this.internals.controller.createRNG( + this.id ?? '', // ID is defined only on base.Component ATM + this.options.random, + ) // Create timeline this.internals.timeline = new Timeline( this.internals.controller, diff --git a/packages/library/src/core/controller.ts b/packages/library/src/core/controller.ts index c70df4f1..d00b9705 100644 --- a/packages/library/src/core/controller.ts +++ b/packages/library/src/core/controller.ts @@ -2,6 +2,8 @@ import { Component } from './component' import { Controller as BaseController } from '../base/controller' import { Row, Store } from '../data/store' import { ImageCache, AudioCache } from './cache' +import { RNGOptions, Random } from '../util/random' +import { autoSeed } from '../util/random/seed' declare global { interface Window { @@ -38,6 +40,7 @@ export interface ControllerGlobal { */ export class Controller extends BaseController { global!: ControllerGlobal + #seed: String /** * Create a new controller @@ -71,5 +74,18 @@ export class Controller extends BaseController { } super({ root, global, initialContext }) + + // Generate random seed + this.#seed = autoSeed() + } + + createRNG(seedFragment: String, options: RNGOptions = {}) { + // Auto-generate seed by combining controller seed + component ID + const seed = `${this.#seed}-${seedFragment}` + + return new Random({ + seed, + ...options, // Allow manual override of component seed + }) } }