@where-stars-drift/core 1.0.0

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.
Files changed (160) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +143 -0
  3. package/dist/src/base/bounded-body.d.ts +8 -0
  4. package/dist/src/base/bounded-body.js +10 -0
  5. package/dist/src/base/celestial-body.d.ts +12 -0
  6. package/dist/src/base/celestial-body.js +11 -0
  7. package/dist/src/base/hoverable.d.ts +10 -0
  8. package/dist/src/base/hoverable.js +4 -0
  9. package/dist/src/base/massive-body.d.ts +8 -0
  10. package/dist/src/base/massive-body.js +10 -0
  11. package/dist/src/config/effects.d.ts +14 -0
  12. package/dist/src/config/effects.js +14 -0
  13. package/dist/src/config/grid.d.ts +10 -0
  14. package/dist/src/config/grid.js +10 -0
  15. package/dist/src/config/panel.d.ts +26 -0
  16. package/dist/src/config/panel.js +26 -0
  17. package/dist/src/config/simulation.d.ts +21 -0
  18. package/dist/src/config/simulation.js +23 -0
  19. package/dist/src/controllers/clan-controller.d.ts +7 -0
  20. package/dist/src/controllers/clan-controller.js +12 -0
  21. package/dist/src/controllers/debug-controller.d.ts +45 -0
  22. package/dist/src/controllers/debug-controller.js +82 -0
  23. package/dist/src/controllers/effects-controller.d.ts +17 -0
  24. package/dist/src/controllers/effects-controller.js +71 -0
  25. package/dist/src/controllers/hover-controller.d.ts +11 -0
  26. package/dist/src/controllers/hover-controller.js +107 -0
  27. package/dist/src/controllers/layer-controller.d.ts +16 -0
  28. package/dist/src/controllers/layer-controller.js +64 -0
  29. package/dist/src/controllers/physics-controller.d.ts +14 -0
  30. package/dist/src/controllers/physics-controller.js +152 -0
  31. package/dist/src/controllers/star-controller.d.ts +12 -0
  32. package/dist/src/controllers/star-controller.js +38 -0
  33. package/dist/src/controllers/starship-controller.d.ts +17 -0
  34. package/dist/src/controllers/starship-controller.js +58 -0
  35. package/dist/src/draw-debug-line.d.ts +9 -0
  36. package/dist/src/draw-debug-line.js +29 -0
  37. package/dist/src/entities/black-hole-factory.d.ts +15 -0
  38. package/dist/src/entities/black-hole-factory.js +23 -0
  39. package/dist/src/entities/black-hole-shapes.d.ts +9 -0
  40. package/dist/src/entities/black-hole-shapes.js +224 -0
  41. package/dist/src/entities/black-hole.d.ts +69 -0
  42. package/dist/src/entities/black-hole.js +210 -0
  43. package/dist/src/entities/clan-manager.d.ts +12 -0
  44. package/dist/src/entities/clan-manager.js +22 -0
  45. package/dist/src/entities/clans.d.ts +15 -0
  46. package/dist/src/entities/clans.js +76 -0
  47. package/dist/src/entities/comet.d.ts +27 -0
  48. package/dist/src/entities/comet.js +81 -0
  49. package/dist/src/entities/docking-point.d.ts +20 -0
  50. package/dist/src/entities/docking-point.js +22 -0
  51. package/dist/src/entities/fleet.d.ts +45 -0
  52. package/dist/src/entities/fleet.js +374 -0
  53. package/dist/src/entities/formations.d.ts +51 -0
  54. package/dist/src/entities/formations.js +340 -0
  55. package/dist/src/entities/meteor.d.ts +26 -0
  56. package/dist/src/entities/meteor.js +48 -0
  57. package/dist/src/entities/nebula.d.ts +18 -0
  58. package/dist/src/entities/nebula.js +43 -0
  59. package/dist/src/entities/orbit.d.ts +23 -0
  60. package/dist/src/entities/orbit.js +43 -0
  61. package/dist/src/entities/pulsar.d.ts +18 -0
  62. package/dist/src/entities/pulsar.js +41 -0
  63. package/dist/src/entities/ring.d.ts +13 -0
  64. package/dist/src/entities/ring.js +26 -0
  65. package/dist/src/entities/ringed-planet.d.ts +21 -0
  66. package/dist/src/entities/ringed-planet.js +68 -0
  67. package/dist/src/entities/sector-grid.d.ts +16 -0
  68. package/dist/src/entities/sector-grid.js +70 -0
  69. package/dist/src/entities/star-factory.d.ts +29 -0
  70. package/dist/src/entities/star-factory.js +47 -0
  71. package/dist/src/entities/star.d.ts +48 -0
  72. package/dist/src/entities/star.js +167 -0
  73. package/dist/src/entities/starship-classes.d.ts +0 -0
  74. package/dist/src/entities/starship-classes.js +2 -0
  75. package/dist/src/entities/starship.d.ts +91 -0
  76. package/dist/src/entities/starship.js +760 -0
  77. package/dist/src/entities/supernova.d.ts +26 -0
  78. package/dist/src/entities/supernova.js +54 -0
  79. package/dist/src/index.d.ts +20 -0
  80. package/dist/src/index.js +19 -0
  81. package/dist/src/lib/energy-stream.d.ts +5 -0
  82. package/dist/src/lib/energy-stream.js +98 -0
  83. package/dist/src/lib/quadtree.d.ts +31 -0
  84. package/dist/src/lib/quadtree.js +124 -0
  85. package/dist/src/lib/simplified-stream.d.ts +6 -0
  86. package/dist/src/lib/simplified-stream.js +19 -0
  87. package/dist/src/types.d.ts +14 -0
  88. package/dist/src/types.js +1 -0
  89. package/dist/src/ui/black-holes-panel.d.ts +2 -0
  90. package/dist/src/ui/black-holes-panel.js +76 -0
  91. package/dist/src/ui/clans-panel.d.ts +2 -0
  92. package/dist/src/ui/clans-panel.js +20 -0
  93. package/dist/src/ui/debug-panel-controller.d.ts +41 -0
  94. package/dist/src/ui/debug-panel-controller.js +285 -0
  95. package/dist/src/ui/fleets-panel.d.ts +2 -0
  96. package/dist/src/ui/fleets-panel.js +127 -0
  97. package/dist/src/ui/formations-panel.d.ts +3 -0
  98. package/dist/src/ui/formations-panel.js +129 -0
  99. package/dist/src/ui/panel-config.d.ts +26 -0
  100. package/dist/src/ui/panel-config.js +26 -0
  101. package/dist/src/ui/ships-panel.d.ts +12 -0
  102. package/dist/src/ui/ships-panel.js +61 -0
  103. package/dist/src/ui/stars-panel.d.ts +2 -0
  104. package/dist/src/ui/stars-panel.js +120 -0
  105. package/dist/src/where-stars-drift.d.ts +71 -0
  106. package/dist/src/where-stars-drift.js +440 -0
  107. package/dist/tsconfig.tsbuildinfo +1 -0
  108. package/package.json +35 -0
  109. package/src/base/bounded-body.ts +14 -0
  110. package/src/base/celestial-body.ts +20 -0
  111. package/src/base/hoverable.ts +11 -0
  112. package/src/base/massive-body.ts +14 -0
  113. package/src/config/effects.ts +15 -0
  114. package/src/config/grid.ts +11 -0
  115. package/src/config/panel.ts +26 -0
  116. package/src/config/simulation.ts +25 -0
  117. package/src/controllers/clan-controller.ts +19 -0
  118. package/src/controllers/debug-controller.ts +112 -0
  119. package/src/controllers/effects-controller.ts +86 -0
  120. package/src/controllers/hover-controller.ts +128 -0
  121. package/src/controllers/layer-controller.ts +78 -0
  122. package/src/controllers/physics-controller.ts +173 -0
  123. package/src/controllers/star-controller.ts +51 -0
  124. package/src/controllers/starship-controller.ts +76 -0
  125. package/src/draw-debug-line.ts +37 -0
  126. package/src/entities/black-hole-factory.ts +28 -0
  127. package/src/entities/black-hole-shapes.ts +276 -0
  128. package/src/entities/black-hole.ts +246 -0
  129. package/src/entities/clan-manager.ts +33 -0
  130. package/src/entities/clans.ts +98 -0
  131. package/src/entities/comet.ts +102 -0
  132. package/src/entities/docking-point.ts +34 -0
  133. package/src/entities/fleet.ts +446 -0
  134. package/src/entities/formations.ts +423 -0
  135. package/src/entities/meteor.ts +59 -0
  136. package/src/entities/nebula.ts +50 -0
  137. package/src/entities/orbit.ts +53 -0
  138. package/src/entities/pulsar.ts +64 -0
  139. package/src/entities/ring.ts +42 -0
  140. package/src/entities/ringed-planet.ts +85 -0
  141. package/src/entities/sector-grid.ts +81 -0
  142. package/src/entities/star-factory.ts +59 -0
  143. package/src/entities/star.ts +222 -0
  144. package/src/entities/starship-classes.ts +1 -0
  145. package/src/entities/starship.ts +906 -0
  146. package/src/entities/supernova.ts +75 -0
  147. package/src/index.ts +24 -0
  148. package/src/lib/energy-stream.ts +127 -0
  149. package/src/lib/quadtree.ts +159 -0
  150. package/src/lib/simplified-stream.ts +28 -0
  151. package/src/types.ts +16 -0
  152. package/src/ui/black-holes-panel.ts +91 -0
  153. package/src/ui/clans-panel.ts +27 -0
  154. package/src/ui/debug-panel-controller.ts +339 -0
  155. package/src/ui/fleets-panel.ts +153 -0
  156. package/src/ui/formations-panel.ts +155 -0
  157. package/src/ui/panel-config.ts +26 -0
  158. package/src/ui/ships-panel.ts +85 -0
  159. package/src/ui/stars-panel.ts +146 -0
  160. package/src/where-stars-drift.ts +542 -0
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @fileoverview Defines the Supernova class for a visual pulse effect.
3
+ */
4
+ import type { BlackHle } from './black-hole';
5
+ export declare const SUPERNOVA_CONFIG: {
6
+ MAX_LIFE: number;
7
+ RADIUS_MULTIPLIER: number;
8
+ INITIAL_RADIUS_MULTIPLIER: number;
9
+ COLOR: string;
10
+ SHADOW_BLUR: number;
11
+ };
12
+ export declare class Supernova {
13
+ x: number;
14
+ y: number;
15
+ radius: number;
16
+ maxRadius: number;
17
+ life: number;
18
+ maxLife: number;
19
+ color: string;
20
+ initialRadius: number;
21
+ parent: BlackHle | null;
22
+ constructor(x: number, y: number, parentRadius: number, parent?: BlackHle | null);
23
+ isAlive(): boolean;
24
+ update(): void;
25
+ draw(ctx: CanvasRenderingContext2D): void;
26
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @fileoverview Defines the Supernova class for a visual pulse effect.
3
+ */
4
+ // --- Supernova Configuration ---
5
+ export const SUPERNOVA_CONFIG = {
6
+ MAX_LIFE: 60, // 1 second in frames
7
+ RADIUS_MULTIPLIER: 2.5,
8
+ INITIAL_RADIUS_MULTIPLIER: 0.2,
9
+ COLOR: 'rgba(255, 255, 255, 0.8)',
10
+ SHADOW_BLUR: 30,
11
+ };
12
+ export class Supernova {
13
+ constructor(x, y, parentRadius, parent = null) {
14
+ this.x = x;
15
+ this.y = y;
16
+ this.initialRadius = parentRadius * SUPERNOVA_CONFIG.INITIAL_RADIUS_MULTIPLIER;
17
+ this.radius = this.initialRadius;
18
+ this.maxRadius = parentRadius * SUPERNOVA_CONFIG.RADIUS_MULTIPLIER;
19
+ this.maxLife = SUPERNOVA_CONFIG.MAX_LIFE;
20
+ this.life = this.maxLife;
21
+ this.color = SUPERNOVA_CONFIG.COLOR;
22
+ this.parent = parent;
23
+ }
24
+ isAlive() {
25
+ return this.life > 0;
26
+ }
27
+ update() {
28
+ this.life--;
29
+ if (this.parent) {
30
+ this.x = this.parent.x;
31
+ this.y = this.parent.y;
32
+ }
33
+ const progress = (this.maxLife - this.life) / this.maxLife; // 0 to 1
34
+ // Ease-out cubic function for radius expansion
35
+ this.radius = this.initialRadius + (this.maxRadius - this.initialRadius) * (1 - Math.pow(1 - progress, 3));
36
+ }
37
+ draw(ctx) {
38
+ const progress = this.life / this.maxLife; // 1 to 0
39
+ const alpha = progress * 0.8; // Fade out
40
+ ctx.save();
41
+ ctx.globalAlpha = alpha;
42
+ ctx.shadowColor = this.color;
43
+ ctx.shadowBlur = SUPERNOVA_CONFIG.SHADOW_BLUR;
44
+ const gradient = ctx.createRadialGradient(this.x, this.y, 0, this.x, this.y, this.radius);
45
+ gradient.addColorStop(0, 'rgba(255, 255, 255, 0)');
46
+ gradient.addColorStop(0.5, 'rgba(255, 255, 255, 0.5)');
47
+ gradient.addColorStop(1, 'rgba(255, 255, 255, 0)');
48
+ ctx.fillStyle = gradient;
49
+ ctx.beginPath();
50
+ ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
51
+ ctx.fill();
52
+ ctx.restore();
53
+ }
54
+ }
@@ -0,0 +1,20 @@
1
+ export { WhereStarsDrift, type SimulationConfig, type SimulationStats } from './where-stars-drift';
2
+ export { Star } from './entities/star';
3
+ export { Pulsar } from './entities/pulsar';
4
+ export { RingedPlanet } from './entities/ringed-planet';
5
+ export { BlackHole, BlackHle, type BlackHoleType } from './entities/black-hole';
6
+ export { Starship, type ShipState, type ShipClass } from './entities/starship';
7
+ export { Fleet } from './entities/fleet';
8
+ export { type Clan } from './entities/clans';
9
+ export { formationRegistry, type Formation, type StrictFormation, type FreeFormation } from './entities/formations';
10
+ export { Comet } from './entities/comet';
11
+ export { Nebula } from './entities/nebula';
12
+ export { Supernova } from './entities/supernova';
13
+ export { SectorGrid } from './entities/sector-grid';
14
+ export { LayerController, type Layer } from './controllers/layer-controller';
15
+ export { PhysicsController } from './controllers/physics-controller';
16
+ export { StarshipController } from './controllers/starship-controller';
17
+ export { StarController } from './controllers/star-controller';
18
+ export { EffectsController } from './controllers/effects-controller';
19
+ export { SIMULATION_CONFIG, DEBUG_CONFIG } from './config/simulation';
20
+ export { GRID_CONFIG } from './config/grid';
@@ -0,0 +1,19 @@
1
+ export { WhereStarsDrift } from './where-stars-drift';
2
+ export { Star } from './entities/star';
3
+ export { Pulsar } from './entities/pulsar';
4
+ export { RingedPlanet } from './entities/ringed-planet';
5
+ export { BlackHole, BlackHle } from './entities/black-hole';
6
+ export { Starship } from './entities/starship';
7
+ export { Fleet } from './entities/fleet';
8
+ export { formationRegistry } from './entities/formations';
9
+ export { Comet } from './entities/comet';
10
+ export { Nebula } from './entities/nebula';
11
+ export { Supernova } from './entities/supernova';
12
+ export { SectorGrid } from './entities/sector-grid';
13
+ export { LayerController } from './controllers/layer-controller';
14
+ export { PhysicsController } from './controllers/physics-controller';
15
+ export { StarshipController } from './controllers/starship-controller';
16
+ export { StarController } from './controllers/star-controller';
17
+ export { EffectsController } from './controllers/effects-controller';
18
+ export { SIMULATION_CONFIG, DEBUG_CONFIG } from './config/simulation';
19
+ export { GRID_CONFIG } from './config/grid';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @fileoverview Defines the energy stream rendering function.
3
+ */
4
+ import type { BlackHle } from '../entities/black-hole';
5
+ export declare const drawEnergyStream: (ctx: CanvasRenderingContext2D, hole: BlackHle, target: BlackHle, pulseTime: number, frameCount: number) => void;
@@ -0,0 +1,98 @@
1
+ /**
2
+ * @fileoverview Defines the energy stream rendering function.
3
+ */
4
+ import { BLACK_HOLE_CONFIG } from '../entities/black-hole';
5
+ export const drawEnergyStream = (ctx, hole, target, pulseTime, frameCount) => {
6
+ const dx = target.x - hole.x;
7
+ const dy = target.y - hole.y;
8
+ const dist = Math.sqrt(dx * dx + dy * dy);
9
+ const angle = Math.atan2(dy, dx);
10
+ const perpAngle = angle + Math.PI / 2;
11
+ let glowColor;
12
+ let baseR, baseG, baseB;
13
+ switch (hole.type) {
14
+ case 'VORTEX':
15
+ glowColor = BLACK_HOLE_CONFIG.VORTEX.VORTEX_COLOR_INNER;
16
+ [baseR, baseG, baseB] = [255, 100, 0];
17
+ break;
18
+ case 'WARPED_DISK':
19
+ glowColor = BLACK_HOLE_CONFIG.WARPED_DISK.DISK_COLOR_INNER;
20
+ [baseR, baseG, baseB] = [255, 220, 150];
21
+ break;
22
+ case 'ACCRETION_DISK':
23
+ glowColor = `rgba(200, 220, 255, 0.8)`;
24
+ [baseR, baseG, baseB] = [200, 220, 255];
25
+ break;
26
+ case 'LENSING':
27
+ default:
28
+ glowColor = `rgba(255, 255, 255, 0.7)`;
29
+ [baseR, baseG, baseB] = [255, 255, 255];
30
+ break;
31
+ }
32
+ const pulse = (Math.sin(pulseTime * hole.pulseFrequency + hole.pulsePhase) + 1) / 2; // 0 to 1
33
+ const startX = hole.x;
34
+ const startY = hole.y;
35
+ ctx.save();
36
+ ctx.globalCompositeOperation = 'lighter';
37
+ ctx.lineCap = 'round';
38
+ // --- Emission Nozzle ---
39
+ if (frameCount % 5 === 0) {
40
+ const nozzleLengthMultiplier = Math.random() * 7 + 3;
41
+ const potentialNozzleLength = hole.radius * nozzleLengthMultiplier;
42
+ hole.nozzleLength = Math.min(potentialNozzleLength, (4 / 5) * dist);
43
+ const nozzleTipX = startX + Math.cos(angle) * hole.nozzleLength;
44
+ const nozzleTipY = startY + Math.sin(angle) * hole.nozzleLength;
45
+ const nozzleGradient = ctx.createLinearGradient(startX, startY, nozzleTipX, nozzleTipY);
46
+ nozzleGradient.addColorStop(0, `rgba(${baseR}, ${baseG}, ${baseB}, ${0.1 + pulse * 0.2})`);
47
+ nozzleGradient.addColorStop(1, `rgba(${baseR}, ${baseG}, ${baseB}, 0)`);
48
+ hole.nozzleColor = nozzleGradient;
49
+ }
50
+ if (hole.nozzleLength > 0 && hole.nozzleColor) {
51
+ const nozzleTipX = startX + Math.cos(angle) * hole.nozzleLength;
52
+ const nozzleTipY = startY + Math.sin(angle) * hole.nozzleLength;
53
+ const nozzleBaseWidth = hole.radius * 2;
54
+ ctx.beginPath();
55
+ ctx.moveTo(nozzleTipX, nozzleTipY);
56
+ ctx.lineTo(startX + Math.cos(perpAngle) * nozzleBaseWidth / 2, startY + Math.sin(perpAngle) * nozzleBaseWidth / 2);
57
+ ctx.lineTo(startX - Math.cos(perpAngle) * nozzleBaseWidth / 2, startY - Math.sin(perpAngle) * nozzleBaseWidth / 2);
58
+ ctx.closePath();
59
+ ctx.fillStyle = hole.nozzleColor;
60
+ ctx.shadowColor = glowColor;
61
+ ctx.shadowBlur = 30;
62
+ ctx.fill();
63
+ }
64
+ // --- Main Stream ---
65
+ const endX = startX + dx;
66
+ const endY = startY + dy;
67
+ const minThicknessFactor = 0.3;
68
+ const maxThicknessFactor = 3.5;
69
+ const distanceFactor = Math.max(0, 1 - dist / BLACK_HOLE_CONFIG.ENERGY_STREAM_DISTANCE);
70
+ const thicknessMultiplier = minThicknessFactor + (maxThicknessFactor - minThicknessFactor) * distanceFactor;
71
+ // --- Outer Glow ---
72
+ const outerGlowAlpha = 0.2 + pulse * 0.3;
73
+ ctx.shadowColor = glowColor;
74
+ ctx.shadowBlur = 25;
75
+ const gradientOuter = ctx.createLinearGradient(startX, startY, endX, endY);
76
+ gradientOuter.addColorStop(0, `rgba(${baseR}, ${baseG}, ${baseB}, ${outerGlowAlpha * 0.7})`);
77
+ gradientOuter.addColorStop(0.95, `rgba(${baseR}, ${baseG}, ${baseB}, 0)`);
78
+ ctx.strokeStyle = gradientOuter;
79
+ ctx.lineWidth = hole.radius * (0.2 + pulse * 0.15) * thicknessMultiplier;
80
+ ctx.beginPath();
81
+ ctx.moveTo(startX, startY);
82
+ ctx.lineTo(endX, endY);
83
+ ctx.stroke();
84
+ // --- Inner Core ---
85
+ const innerGlowAlpha = 0.4 + pulse * 0.6;
86
+ ctx.shadowColor = `rgba(${baseR}, ${baseG}, ${baseB}, ${0.5 + pulse * 0.5})`;
87
+ ctx.shadowBlur = 12;
88
+ const gradientInner = ctx.createLinearGradient(startX, startY, endX, endY);
89
+ gradientInner.addColorStop(0, `rgba(${baseR}, ${baseG}, ${baseB}, ${innerGlowAlpha})`);
90
+ gradientInner.addColorStop(0.95, `rgba(${baseR}, ${baseG}, ${baseB}, 0)`);
91
+ ctx.strokeStyle = gradientInner;
92
+ ctx.lineWidth = hole.radius * 0.1 * thicknessMultiplier;
93
+ ctx.beginPath();
94
+ ctx.moveTo(startX, startY);
95
+ ctx.lineTo(endX, endY);
96
+ ctx.stroke();
97
+ ctx.restore();
98
+ };
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @fileoverview Defines the Quadtree class for spatial partitioning.
3
+ */
4
+ import type { BoundedBody } from '../base/bounded-body';
5
+ export declare const QUADTREE_CONFIG: {
6
+ MAX_OBJECTS: number;
7
+ MAX_LEVELS: number;
8
+ };
9
+ interface Rectangle {
10
+ x: number;
11
+ y: number;
12
+ width: number;
13
+ height: number;
14
+ }
15
+ export declare class Quadtree {
16
+ private maxObjects;
17
+ private maxLevels;
18
+ private level;
19
+ private bounds;
20
+ private objects;
21
+ private nodes;
22
+ constructor(bounds: Rectangle, level?: number);
23
+ clear(): void;
24
+ private split;
25
+ private getIndex;
26
+ insert(body: BoundedBody): void;
27
+ query(range: BoundedBody): BoundedBody[];
28
+ private intersects;
29
+ draw(ctx: CanvasRenderingContext2D): void;
30
+ }
31
+ export {};
@@ -0,0 +1,124 @@
1
+ // --- Quadtree Configuration ---
2
+ export const QUADTREE_CONFIG = {
3
+ MAX_OBJECTS: 10,
4
+ MAX_LEVELS: 5,
5
+ };
6
+ export class Quadtree {
7
+ constructor(bounds, level = 0) {
8
+ this.maxObjects = QUADTREE_CONFIG.MAX_OBJECTS;
9
+ this.maxLevels = QUADTREE_CONFIG.MAX_LEVELS;
10
+ this.level = level;
11
+ this.bounds = bounds;
12
+ this.objects = [];
13
+ this.nodes = [];
14
+ }
15
+ clear() {
16
+ this.objects = [];
17
+ this.nodes = [];
18
+ }
19
+ split() {
20
+ const nextLevel = this.level + 1;
21
+ const subWidth = this.bounds.width / 2;
22
+ const subHeight = this.bounds.height / 2;
23
+ const x = this.bounds.x;
24
+ const y = this.bounds.y;
25
+ // Top right
26
+ this.nodes[0] = new Quadtree({ x: x + subWidth, y: y, width: subWidth, height: subHeight }, nextLevel);
27
+ // Top left
28
+ this.nodes[1] = new Quadtree({ x: x, y: y, width: subWidth, height: subHeight }, nextLevel);
29
+ // Bottom left
30
+ this.nodes[2] = new Quadtree({ x: x, y: y + subHeight, width: subWidth, height: subHeight }, nextLevel);
31
+ // Bottom right
32
+ this.nodes[3] = new Quadtree({ x: x + subWidth, y: y + subHeight, width: subWidth, height: subHeight }, nextLevel);
33
+ }
34
+ getIndex(body) {
35
+ let index = -1;
36
+ const verticalMidpoint = this.bounds.x + (this.bounds.width / 2);
37
+ const horizontalMidpoint = this.bounds.y + (this.bounds.height / 2);
38
+ const topQuadrant = body.y < horizontalMidpoint && body.y + body.boundingRadius < horizontalMidpoint;
39
+ const bottomQuadrant = body.y > horizontalMidpoint;
40
+ if (body.x < verticalMidpoint && body.x + body.boundingRadius < verticalMidpoint) {
41
+ if (topQuadrant) {
42
+ index = 1; // Top left
43
+ }
44
+ else if (bottomQuadrant) {
45
+ index = 2; // Bottom left
46
+ }
47
+ }
48
+ else if (body.x > verticalMidpoint) {
49
+ if (topQuadrant) {
50
+ index = 0; // Top right
51
+ }
52
+ else if (bottomQuadrant) {
53
+ index = 3; // Bottom right
54
+ }
55
+ }
56
+ return index;
57
+ }
58
+ insert(body) {
59
+ if (this.nodes.length) {
60
+ const index = this.getIndex(body);
61
+ if (index !== -1) {
62
+ this.nodes[index].insert(body);
63
+ return;
64
+ }
65
+ }
66
+ this.objects.push(body);
67
+ if (this.objects.length > this.maxObjects && this.level < this.maxLevels) {
68
+ if (!this.nodes.length) {
69
+ this.split();
70
+ }
71
+ let i = 0;
72
+ while (i < this.objects.length) {
73
+ const index = this.getIndex(this.objects[i]);
74
+ if (index !== -1) {
75
+ this.nodes[index].insert(this.objects.splice(i, 1)[0]);
76
+ }
77
+ else {
78
+ i++;
79
+ }
80
+ }
81
+ }
82
+ }
83
+ query(range) {
84
+ let found = [];
85
+ const { x, y, boundingRadius } = range;
86
+ const queryBounds = {
87
+ x: x - boundingRadius,
88
+ y: y - boundingRadius,
89
+ width: boundingRadius * 2,
90
+ height: boundingRadius * 2,
91
+ };
92
+ if (!this.intersects(this.bounds, queryBounds)) {
93
+ return [];
94
+ }
95
+ found = found.concat(this.objects);
96
+ if (this.nodes.length) {
97
+ const index = this.getIndex(range);
98
+ if (index !== -1) {
99
+ found = found.concat(this.nodes[index].query(range));
100
+ }
101
+ else {
102
+ for (let i = 0; i < this.nodes.length; i++) {
103
+ found = found.concat(this.nodes[i].query(range));
104
+ }
105
+ }
106
+ }
107
+ return found;
108
+ }
109
+ intersects(rect1, rect2) {
110
+ return (rect1.x < rect2.x + rect2.width &&
111
+ rect1.x + rect1.width > rect2.x &&
112
+ rect1.y < rect2.y + rect2.height &&
113
+ rect1.y + rect1.height > rect2.y);
114
+ }
115
+ draw(ctx) {
116
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.1)';
117
+ ctx.strokeRect(this.bounds.x, this.bounds.y, this.bounds.width, this.bounds.height);
118
+ if (this.nodes.length) {
119
+ for (let i = 0; i < this.nodes.length; i++) {
120
+ this.nodes[i].draw(ctx);
121
+ }
122
+ }
123
+ }
124
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * @fileoverview Defines a simplified, performant energy stream for star-to-hole effects.
3
+ */
4
+ import type { Star } from '../entities/star';
5
+ import type { BlackHle } from '../entities/black-hole';
6
+ export declare const drawSimpleStarStream: (ctx: CanvasRenderingContext2D, star: Star, hole: BlackHle) => void;
@@ -0,0 +1,19 @@
1
+ export const drawSimpleStarStream = (ctx, star, hole) => {
2
+ const dx = hole.x - star.x;
3
+ const dy = hole.y - star.y;
4
+ const dist = Math.sqrt(dx * dx + dy * dy);
5
+ // Fade the stream as it gets closer to the hole
6
+ const maxDist = hole.radius + 50;
7
+ const alpha = Math.max(0, 1 - (dist / maxDist)) * 0.5;
8
+ if (alpha <= 0)
9
+ return;
10
+ ctx.save();
11
+ ctx.beginPath();
12
+ ctx.moveTo(star.x, star.y);
13
+ ctx.lineTo(hole.x, hole.y);
14
+ ctx.strokeStyle = star.color;
15
+ ctx.globalAlpha = alpha;
16
+ ctx.lineWidth = star.radius * 0.8;
17
+ ctx.stroke();
18
+ ctx.restore();
19
+ };
@@ -0,0 +1,14 @@
1
+ import type { Starship } from './entities/starship';
2
+ import type { Formation } from './entities/formations';
3
+ import type { Clan } from './entities/clans';
4
+ import type { Fleet } from './entities/fleet';
5
+ import type { Star } from './entities/star';
6
+ import type { BlackHle } from './entities/black-hole';
7
+ export type CatalogData = {
8
+ starships: Starship[];
9
+ formations: Formation[];
10
+ clans: Clan[];
11
+ fleets: Fleet[];
12
+ stars: Star[];
13
+ blackHoles: BlackHle[];
14
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import { BlackHole } from '../entities/black-hole';
2
+ export declare function drawBlackHoleCatalog(ctx: CanvasRenderingContext2D, startY: number, blackHoleCatalog: BlackHole[], pulseTime: number, frameCount: number): number;
@@ -0,0 +1,76 @@
1
+ import { PANEL_CONFIG } from './panel-config';
2
+ const DESCRIPTIONS = {
3
+ STANDARD: 'A simple black hole with a soft, ethereal glow.',
4
+ LENSING: 'Features a bright, sharp ring of light caused by gravitational lensing.',
5
+ ACCRETION_DISK: 'Characterized by a stable, flat disk of matter with a bright central line and relativistic jets.',
6
+ WARPED_DISK: 'Shows a dynamic, warped accretion disk that gives a 3D perspective.',
7
+ VORTEX: 'A highly active black hole with swirling arms of super-heated gas.',
8
+ };
9
+ function drawBlackHoleParameters(ctx, hole, x, y) {
10
+ ctx.font = 'bold 12px "Roboto Mono", monospace';
11
+ ctx.fillStyle = '#fff';
12
+ ctx.textAlign = 'left';
13
+ ctx.textBaseline = 'top';
14
+ ctx.fillText(hole.type, x, y);
15
+ // Draw description
16
+ ctx.font = '11px "Roboto Mono", monospace';
17
+ ctx.fillStyle = PANEL_CONFIG.ACCENT_COLOR;
18
+ const description = DESCRIPTIONS[hole.type] || 'A mysterious gravitational anomaly.';
19
+ const words = description.split(' ');
20
+ let line = '';
21
+ let currentY = y + 20; // Start description lower
22
+ for (let n = 0; n < words.length; n++) {
23
+ const testLine = line + words[n] + ' ';
24
+ const metrics = ctx.measureText(testLine);
25
+ if (metrics.width > 200 && n > 0) { // Wrap text
26
+ ctx.fillText(line, x, currentY);
27
+ line = words[n] + ' ';
28
+ currentY += 12;
29
+ }
30
+ else {
31
+ line = testLine;
32
+ }
33
+ }
34
+ ctx.fillText(line, x, currentY);
35
+ currentY += 20;
36
+ // Draw parameters
37
+ ctx.font = '10px "Roboto Mono", monospace';
38
+ const lineHeight = 12;
39
+ const params = [
40
+ { label: 'Type', value: hole.type },
41
+ { label: 'Base Radius', value: hole.baseRadius.toFixed(2) },
42
+ { label: 'Mass', value: hole.mass.toFixed(2) },
43
+ { label: 'Merge State', value: `${hole.mergeState}` },
44
+ ];
45
+ params.forEach(param => {
46
+ ctx.fillStyle = PANEL_CONFIG.ACCENT_COLOR;
47
+ ctx.fillText(`${param.label}:`, x, currentY);
48
+ ctx.fillStyle = PANEL_CONFIG.TEXT_COLOR;
49
+ ctx.fillText(param.value, x + 70, currentY);
50
+ currentY += lineHeight;
51
+ });
52
+ }
53
+ export function drawBlackHoleCatalog(ctx, startY, blackHoleCatalog, pulseTime, frameCount) {
54
+ let currentY = startY + PANEL_CONFIG.PADDING;
55
+ ctx.font = PANEL_CONFIG.GROUP_FONT;
56
+ ctx.fillStyle = PANEL_CONFIG.TEXT_COLOR;
57
+ ctx.textAlign = 'left';
58
+ ctx.textBaseline = 'top';
59
+ ctx.fillText('All Black Hole Types', PANEL_CONFIG.X + PANEL_CONFIG.PADDING, currentY);
60
+ currentY += PANEL_CONFIG.GROUP_HEADER_HEIGHT;
61
+ blackHoleCatalog.forEach(sampleHole => {
62
+ const drawingAreaHeight = 80;
63
+ const rowY = currentY + drawingAreaHeight / 2;
64
+ const xPos = PANEL_CONFIG.X + PANEL_CONFIG.PADDING + 30;
65
+ ctx.save();
66
+ // Position the drawing relative to the catalog panel
67
+ ctx.translate(xPos, rowY);
68
+ // sampleHole.update(ctx, 0, 0, frameCount); // This is expensive, disable animation in catalog
69
+ sampleHole.draw(ctx, 0, 0); // Pass static pulseTime and frameCount
70
+ ctx.restore();
71
+ // Draw Title
72
+ drawBlackHoleParameters(ctx, sampleHole, xPos + 70, rowY - 35);
73
+ currentY += drawingAreaHeight + 45; // Add padding between entries
74
+ });
75
+ return currentY - startY;
76
+ }
@@ -0,0 +1,2 @@
1
+ import type { Clan } from '../entities/clans';
2
+ export declare function drawClanCatalog(ctx: CanvasRenderingContext2D, startY: number, clans: Clan[]): number;
@@ -0,0 +1,20 @@
1
+ import { PANEL_CONFIG } from './panel-config';
2
+ export function drawClanCatalog(ctx, startY, clans) {
3
+ ctx.font = PANEL_CONFIG.ROW_FONT;
4
+ clans.forEach((clan, i) => {
5
+ const y = startY + (i * PANEL_CONFIG.ROW_HEIGHT) + PANEL_CONFIG.PADDING + 15;
6
+ // Draw clan icon
7
+ ctx.save();
8
+ ctx.translate(PANEL_CONFIG.X + PANEL_CONFIG.PADDING + 10, y);
9
+ ctx.fillStyle = clan.color;
10
+ ctx.strokeStyle = clan.color;
11
+ clan.icon(ctx, 12);
12
+ ctx.restore();
13
+ // Draw text
14
+ ctx.fillStyle = PANEL_CONFIG.TEXT_COLOR;
15
+ ctx.textAlign = 'left';
16
+ ctx.textBaseline = 'middle';
17
+ ctx.fillText(`${clan.name} (Fleets: ${clan.fleets.length}, Ships: ${clan.starships.length})`, PANEL_CONFIG.X + PANEL_CONFIG.PADDING + 30, y);
18
+ });
19
+ return (clans.length * PANEL_CONFIG.ROW_HEIGHT) + (PANEL_CONFIG.PADDING * 2);
20
+ }
@@ -0,0 +1,41 @@
1
+ import type { Formation } from '../entities/formations';
2
+ import type { CatalogData } from '../types';
3
+ export declare class DebugPanelController {
4
+ private ctx;
5
+ private activeTab;
6
+ private tabs;
7
+ private shipCatalog;
8
+ private formationCatalog;
9
+ private starCatalog;
10
+ private blackHoleCatalog;
11
+ private panelY;
12
+ private panelHeight;
13
+ private scrollTop;
14
+ private contentHeight;
15
+ private starFactory;
16
+ private blackHoleFactory;
17
+ private isDraggingScrollbar;
18
+ private dragStartY;
19
+ private dragStartScrollTop;
20
+ private scrollbarThumb;
21
+ private scrollbarTrack;
22
+ private showFormationShips;
23
+ constructor(ctx: CanvasRenderingContext2D, allFormations: Formation[]);
24
+ private initializeTabs;
25
+ private cacheShipClasses;
26
+ private cacheFormations;
27
+ private cacheStarVariations;
28
+ private cacheBlackHoleTypes;
29
+ private calculatePanelDimensions;
30
+ isMouseOver(x: number, y: number): boolean;
31
+ handleScroll(deltaY: number): void;
32
+ isDragging(): boolean;
33
+ handleMouseDown(x: number, y: number): void;
34
+ handleMouseMove(x: number, y: number): void;
35
+ handleMouseUp(): void;
36
+ handleResize(): void;
37
+ draw(data: CatalogData, pulseTime: number, frameCount: number): void;
38
+ private drawPanelBase;
39
+ private drawTabs;
40
+ private drawScrollbar;
41
+ }