• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

excaliburjs / Excalibur / 18977819179

31 Oct 2025 03:49PM UTC coverage: 88.612% (-0.01%) from 88.623%
18977819179

push

github

web-flow
feat: added Color.random() (#3552)

Added Color.random() static method.

Updated spec to add test
Updated docs to add section for mentioning it

ran linting
ran prettier
built and tested independently

5263 of 7162 branches covered (73.49%)

2 of 2 new or added lines in 1 file covered. (100.0%)

2 existing lines in 2 files now uncovered.

14442 of 16298 relevant lines covered (88.61%)

24350.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.75
/src/engine/GarbageCollector.ts
1
export interface GarbageCollectionOptions {
2
  /**
3
   * Textures that aren't drawn after a certain number of milliseconds are unloaded from the GPU
4
   * Default 60_000 ms
5
   */
6
  textureCollectInterval?: number; // default 60_000 ms
7
  // TODO future work to integrate the font and text configuration, refactor existing collection mechanism
8
  // /**
9
  //  * Font pre-renders that aren't drawn after a certain number of milliseconds are unloaded from the GPU
10
  //  * Default 60_000 ms
11
  //  */
12
  // fontCollectInterval: number; // default 60_000 ms
13
  // /**
14
  //  * Text measurements that aren't used after a certain number of milliseconds are unloaded from the GPU
15
  //  * Default 60_000 ms
16
  //  */
17
  // textMeasurementCollectInterval: number; // default 60_000 ms
18
}
19

20
export const DefaultGarbageCollectionOptions: GarbageCollectionOptions = {
248✔
21
  textureCollectInterval: 60_000
22
  // TODO future work to integrate the font and text configuration, refactor existing collection mechanism
23
  // fontCollectInterval: 60_000,
24
  // textMeasurementCollectInterval: 60_000,
25
};
26

27
export interface GarbageCollectorOptions {
28
  /**
29
   * Returns a timestamp in milliseconds representing now
30
   */
31
  getTimestamp: () => number;
32
}
33

34
export class GarbageCollector {
35
  private _collectHandle: number;
36
  private _running = false;
741✔
37
  private _collectionMap = new Map<any, [type: string, time: number]>();
741✔
38
  private _collectors = new Map<string, [(resource: any) => boolean, interval: number]>();
741✔
39

40
  constructor(public options: GarbageCollectorOptions) {}
741✔
41

42
  /**
43
   *
44
   * @param type Resource type
45
   * @param timeoutInterval If resource type exceeds interval in milliseconds collect() is called
46
   * @param collect Collection implementation, returns true if collected
47
   */
48
  registerCollector(type: string, timeoutInterval: number, collect: (resource: any) => boolean) {
49
    this._collectors.set(type, [collect, timeoutInterval]);
738✔
50
  }
51

52
  /**
53
   * Add a resource to be tracked for collection
54
   * @param type
55
   * @param resource
56
   */
57
  addCollectableResource(type: string, resource: any) {
58
    this._collectionMap.set(resource, [type, this.options.getTimestamp()]);
166✔
59
  }
60

61
  /**
62
   * Update the resource last used timestamp preventing collection
63
   * @param resource
64
   */
65
  touch(resource: any) {
66
    const collectionData = this._collectionMap.get(resource);
1,751✔
67
    if (collectionData) {
1,751!
68
      this._collectionMap.set(resource, [collectionData[0], this.options.getTimestamp()]);
1,751✔
69
    }
70
  }
71

72
  /**
73
   * Runs the collection loop to cleanup any stale resources given the registered collect handlers
74
   */
75
  public collectStaleResources = (deadline?: IdleDeadline) => {
741✔
76
    if (!this._running) {
936!
UNCOV
77
      return;
×
78
    }
79
    for (const [type, [collector, timeoutInterval]] of this._collectors.entries()) {
936✔
80
      const now = this.options.getTimestamp();
928✔
81
      for (const [resource, [resourceType, time]] of this._collectionMap.entries()) {
928✔
82
        if (type !== resourceType || time + timeoutInterval >= now) {
347✔
83
          continue;
345✔
84
        }
85

86
        const collected = collector(resource);
2✔
87
        if (collected) {
2!
88
          this._collectionMap.delete(resource);
2✔
89
        }
90
      }
91
    }
92

93
    this._collectHandle = requestIdleCallback(this.collectStaleResources);
936✔
94
  };
95

96
  /**
97
   * Force collect all resources, useful for shutting down a game
98
   * or if you know that you will not use anything you've allocated before now
99
   */
100
  public forceCollectAll() {
101
    for (const [_, [collector]] of this._collectors.entries()) {
736✔
102
      for (const [resource] of this._collectionMap.entries()) {
735✔
103
        const collected = collector(resource);
164✔
104
        if (collected) {
164!
105
          this._collectionMap.delete(resource);
164✔
106
        }
107
      }
108
    }
109
  }
110

111
  running(): boolean {
112
    return this._running;
×
113
  }
114

115
  /**
116
   * Starts the garbage collection loop
117
   */
118
  start() {
119
    this._running = true;
574✔
120
    this.collectStaleResources();
574✔
121
  }
122

123
  /**
124
   * Stops the garbage collection loop
125
   */
126
  stop() {
127
    this._running = false;
580✔
128
    cancelIdleCallback(this._collectHandle);
580✔
129
  }
130
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc