-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathconfig.js
More file actions
1800 lines (1652 loc) · 86 KB
/
config.js
File metadata and controls
1800 lines (1652 loc) · 86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// Emergence Engine Configuration
// Organized config for physics, trails, AI, and learning
// Note: Node.js filesystem imports are commented out for browser compatibility
// If you need to run this in Node.js (e.g., for testing), uncomment these:
// import fs from 'node:fs';
// import path from 'node:path';
// import { fileURLToPath } from 'node:url';
// Browser-compatible stubs for Node.js modules
const fs = null;
const path = {
isAbsolute: (_p) => false,
resolve: (...args) => args[args.length - 1],
dirname: (_p) => ''
};
const __dirname = '';
const hasFs = false;
const isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
const localStorageRef = (() => {
if (!isBrowser) return null;
try {
return window.localStorage;
} catch {
return null;
}
})();
import { applyTcConfig } from './tcStorage.js';
import { TapeMachineRegistry } from './tc/tcTape.js';
const resolveConfigPath = (maybePath) => {
if (!maybePath || typeof maybePath !== 'string') return null;
if (path.isAbsolute(maybePath)) return maybePath;
return path.resolve(__dirname, maybePath);
};
const validateTapeSnapshotSchema = (schemaRef) => {
if (!schemaRef) return null;
const resolved = resolveConfigPath(schemaRef);
if (!resolved || !hasFs) return resolved;
try {
const contents = fs.readFileSync(resolved, 'utf8');
JSON.parse(contents);
} catch (error) {
console.warn(`Failed to validate tape snapshot schema '${schemaRef}':`, error?.message || error);
}
return resolved;
};
const loadTapeMachineEntry = (entry, id, schemaRef) => {
if (!entry) return null;
if (typeof entry === 'string') {
if (!hasFs) {
console.warn(`Unable to load tape machine '${id}' from '${entry}' without filesystem access.`);
return null;
}
const resolved = resolveConfigPath(entry);
if (!resolved) return null;
try {
const contents = fs.readFileSync(resolved, 'utf8');
const parsed = JSON.parse(contents);
if (!parsed.id) parsed.id = id;
if (schemaRef && !parsed.snapshotSchema) parsed.snapshotSchema = schemaRef;
return parsed;
} catch (error) {
console.warn(`Failed to load tape machine '${id}' from '${entry}':`, error?.message || error);
return null;
}
}
if (typeof entry === 'object') {
if (entry.table) {
return loadTapeMachineEntry(entry.table, entry.id || id, schemaRef);
}
const descriptor = { ...entry };
if (!descriptor.id) descriptor.id = id;
if (schemaRef && !descriptor.snapshotSchema) descriptor.snapshotSchema = schemaRef;
return descriptor;
}
return null;
};
const loadTapeMachinesFromConfig = (tcConfig = {}) => {
if (!tcConfig || typeof tcConfig !== 'object') return;
const machines = tcConfig.machines;
if (!machines || typeof machines !== 'object') return;
const schemaRef = tcConfig.snapshots?.turingTape?.schema || 'schemas/tc_tape_snapshot.schema.json';
validateTapeSnapshotSchema(schemaRef);
for (const [machineId, entry] of Object.entries(machines)) {
const descriptor = loadTapeMachineEntry(entry, machineId, schemaRef);
if (!descriptor) continue;
try {
TapeMachineRegistry.register(descriptor, null, { overwrite: true });
} catch (error) {
console.warn(`Failed to register tape machine '${machineId}':`, error?.message || error);
}
}
};
export const CONFIG = {
debug: false,
// === Physics & Core Mechanics ===
startChi: 15,
baseDecayPerSecond: 0.10,
moveSpeedPxPerSec: 150,
moveCostPerSecond: 0.35,
rewardChi: 10, // DEPRECATED: kept for backward compatibility
resourceRadius: 10,
bundleSize: 40,
startingAgents: 3, // Number of agents to start the simulation with
// === Turing Completeness Recording ===
tc: {
enabled: false, // Set to true to enable TC features (Rule 110, Turing machines)
seed: 0,
tickSalt: 0x9e3779b9,
maxCachedChunks: 64,
updateCadence: null, // Set to 1 to run every tick, or null for default cadence
mode: null, // Set to 'rule110' to enable Rule 110 cellular automaton
snapshots: {
rule110: {
capture: false, // Set to true to capture Rule 110 snapshots
schema: 'schemas/tc_rule110_snapshot.schema.json'
},
turingTape: {
capture: false, // Set to true to capture Turing machine tape snapshots
schema: 'schemas/tc_tape_snapshot.schema.json'
}
},
machines: {
// Turing machine definitions
// In browser: use inline definitions (objects)
// In Node.js: can use file paths (strings) like 'tc/machines/file.json'
unaryIncrementer: {
// File path (only works in Node.js with fs module)
table: 'tc/machines/unary_incrementer.json',
// OR: Inline definition (works in browser!)
// Uncomment to use inline definition instead of file:
// table: {
// id: "unaryIncrementer",
// description: "Moves right across a unary number and appends a trailing 1 before halting.",
// alphabet: ["_", "1"],
// blank: "_",
// initialState: "scan",
// haltStates: ["halt"],
// states: {
// scan: {
// "1": { write: "1", move: "R", next: "scan" },
// "_": { write: "1", move: "N", next: "halt", halt: true }
// },
// halt: {}
// }
// }
}
}
},
// === Resource Ecology (dynamic resource availability) ===
resourceDynamicCount: true, // Use dynamic resource ecology vs fixed count
resourceInitialMin: 5, // Starting resources (min) - initial abundance
resourceInitialMax: 7, // Starting resources (max) - initial abundance
resourceStableMin: 2, // Stable minimum after depletion
resourceStableMax: 4, // Stable maximum after depletion
resourceDepletionRate: 0.025, // Rate of decline per collection (carrying capacity pressure)
resourceRecoveryChance: 0.10, // Chance per second to add a resource (if below stable max)
resourceRespawnCooldown: 100, // Ticks (3 seconds at 60fps) before resource can respawn after collection
// Legacy fixed count (used when resourceDynamicCount = false)
resourceCount: 3, // Fixed number of resources (legacy mode)
// Resource scaling relative to living agents (INVERSE: more agents = less food)
resourceScaleWithAgents: true, // Scale max resources based on living agent count
resourceBaseAbundance: 50, // Base resource abundance (when few agents)
resourceCompetition: 1.0, // Resource reduction per agent (competition pressure)
resourceScaleMinimum: 5, // Minimum resources even with many agents
resourceScaleMaximum: 80, // Maximum resources (with very few agents)
// === Plant Ecology System (soil fertility & clustering) ===
plantEcology: {
enabled: true, // Use plant-based resource system
// Fertility Grid (like trail grid, but for soil quality)
fertilityCell: 75, // Size of fertility cells (pixels)
// Initial conditions
initialFertility: 0.7, // Starting soil quality (0-1)
fertilityVariation: 0.6, // Random variation in initial fertility
// Growth mechanics
seedChance: 0.01, // Chance per second for resource to spawn seed
seedDistance: 100, // Max distance for seed dispersal (pixels)
growthFertilityThreshold: 0.3, // Min fertility needed for growth
growthChance: 0.1, // Chance per second to grow in fertile soil
// Resource clustering
patchCount: 5, // Number of initial fertile patches
patchRadius: 200, // Radius of fertile patches (pixels)
patchFertility: 0.3, // Fertility in patch centers
// Depletion & recovery
harvestDepletion: 0.20, // Fertility lost per harvest (local)
harvestRadius: 40, // Radius of depletion effect (pixels)
fertilityRecovery: 0.10, // Fertility gain per second (when not harvested)
maxFertility: 1.0, // Max fertility cap
// Population pressure
populationPressure: true, // Enable population-based degradation
pressurePerAgent: 0.01, // Global fertility drain per agent per second
pressureThreshold: 10, // Agents above this cause pressure
// Spawn pressure (reduce growth when population high)
spawnPressure: {
startAgents: 8, // Agents before pressure kicks in
maxAgents: 50, // Population where pressure is maxed
minSeedMultiplier: 0.35, // Minimum fraction of seed chance
minGrowthMultiplier: 0.2, // Minimum fraction of spontaneous growth chance
minResourceMultiplier: 0.3 // Minimum fraction of resource abundance cap
}
},
// === Adaptive Reward System ===
// Biologically-grounded rewards that scale with search difficulty
// Based on ATP/glucose metabolism and optimal foraging theory
adaptiveReward: {
enabled: true, // Toggle adaptive vs fixed reward
gainFactor: 5.0, // "Ecosystem generosity" (4-10 range recommended)
avgMoveFraction: 0.7, // Assume 70% of time spent moving
emaAlpha: 0.1, // EMA smoothing (0.05-0.2, lower = more stable)
minReward: 3.0, // Safety floor (prevent tiny rewards)
maxReward: 100.0, // Safety ceiling (prevent explosion)
// Optional: Absolute biological anchor (disabled by default)
// When enabled, rewards based on ~1 femtomole glucose = 6×10⁸ molecules
useAbsoluteAnchor: false,
chiPerATP: 1 / 1e8, // 1 χ per 10^8 ATP molecules
moleculesPerPatch: 6e8, // 1 femtomole = 6×10^8 molecules
atpPerGlucose: 30, // ~30 ATP per glucose molecule
},
// === Trail System ===
trailCell: 7,
depositPerSec: 2.5,
evapPerSec: .05,
diffusePerSec: .08,
enableDiffusion: true,
renderTrail: true,
// === Residuals (public-good reuse) ===
residualGainPerSec: 1,
residualCapPerTick: 0.3,
trailCooldownTicks: 8,
// === Own Trail Penalty (discourages circuit running) ===
ownTrailPenalty: 0.5, // Chi cost per second for being on own fresh trail
ownTrailGraceAge: 10, // Ticks before own trail is "safe" to cross (0 = always penalize)
// === Autonomy ===
autoMove: true, // Start in auto mode (no manual control)
// === Sensing (smooth + delta-paid) ===
aiSensoryRangeBase: 175, // Reduced from 220 (tighter base vision)
aiSensoryRangeMax: 360, // Reduced from 560 (less popping)
aiSenseRangePerChi: 35, // Reduced from 55 (83% more expensive!)
aiSenseBiasFromFrustr: 0.8,
aiSenseSlewPerSec: 380,
// === Wall Avoidance ===
aiWallAvoidMargin: 100, // Distance from wall to start avoiding (pixels)
aiWallAvoidStrength: 3.5, // Strength of wall repulsion force
// === Agent Collision ===
enableAgentCollision: true, // Enable collision between agents
agentCollisionPushback: 0.5, // Strength of separation force (0-1) - reduced to avoid wall pushing
// === Exploration & Trail Following ===
aiExploreNoiseBase: 0.15,
aiExploreNoiseGain: 0.55,
aiTrailFollowingNear: 0.25,
aiTrailFollowingFar: 2.6,
aiSampleDistance: 46,
// === Resource Seeking ===
aiResourceAttractionStrength: 5.0, // Strength of pull toward visible resources (1.0 = original, 5.0 = stronger)
aiResourceAttractionScaleWithDistance: true, // Scale attraction stronger when closer to resource
// === Frustration (now smooth 0..1) ===
aiFrustrationBuildRate: 0.5, // Reduced from 0.25 (slower frustration build)
aiFrustrationDecayRate: 0.6,
aiFrustrationSightGrace: 30,
aiFrustrationLowTrail: 0.10, // Reduced from 0.20 (stricter threshold)
// === Frustration Effects ===
aiSurgeMax: 0.5,
aiTurnRateBase: 4.0,
aiTurnRateGain: 3.5,
// === Hunger System (biological drive) ===
hungerBuildRate: 0.10, // Rate hunger increases per second
hungerDecayOnCollect: 0.7, // How much hunger decreases when collecting resource (0.7 = 70% relief)
hungerThresholdLow: 0.3, // Below this, agent is "satisfied"
hungerThresholdHigh: 0.6, // Above this, agent is "starving"
hungerExplorationAmp: 5, // Multiplier on exploration noise when hungry (max)
hungerFrustrationAmp: 3, // Multiplier on frustration build rate when hungry (max)
hungerSenseAmp: 2, // Multiplier on sensory range bias when hungry (max)
hungerSurgeAmp: 1.5, // Multiplier on speed surge when hungry (max)
// === Resource Scent Gradient System ===
// Resources emit "scent" that decreases with distance, giving agents a gradient to climb
scentGradient: {
enabled: true, // Enable scent gradient system
maxRange: 400, // Maximum distance scent can be detected (pixels)
falloffType: 'inverse-square', // 'linear', 'inverse', 'inverse-square', 'exponential'
strength: 1, // Base strength of scent at resource location
showSubtleIndicator: true, // Show pulsating rings around resources
// Distance-based reward settings
rewardEnabled: true, // Give rewards for getting closer to food
rewardScale: 0.75, // Scaling factor for distance rewards (χ per pixel closer)
rewardUpdateInterval: 3.5, // Check distance every N ticks (avoid per-frame noise)
// Multi-scale density sensing
densitySensingEnabled: true, // Enable food density sensing in observations
densityRadiusNear: 400, // Near field radius (pixels)
densityRadiusMid: 400, // Mid field radius (pixels)
densityRadiusFar: 600, // Far field radius (pixels)
// Consumable gradient by orbiting agents
consumable: true,
consumePerSec: 0.15, // Strength/sec removed when orbiting closely
recoverPerSec: 0.03, // Strength/sec recovery when no agents orbit
minStrength: 0.2, // Floor for strength
minRange: 150, // Floor for range (px)
orbitBandPx: 140, // Band outside resource.r considered "orbit"
// Resource vitality depletion
vitalityConsumePerSec: 0.10, // Resource health depletes from orbiting
vitalityRecoverPerSec: 0.02, // Resource health recovers when not orbited
minVitality: 0.0, // Floor for vitality (0 = completely depleted)
depletionThreshold: 0.3, // Below this, resource becomes uncollectible
vitalityToChiRate: 2.0 // Chi gained per unit of vitality consumed (conversion rate)
},
// === TC-Resource Integration ===
// Link Rule 110 cellular automaton to resource generation
tcResourceIntegration: {
enabled: false, // Set to true to link resources to Rule 110
// How Rule 110 influences spawning
mode: 'hybrid', // 'spatial' | 'activity' | 'hybrid'
// Spatial mapping (Rule 110 X → World X)
spatialMapping: true, // Map Rule 110 cell positions to world X coordinates
localityRadius: 5, // Cells to check for local activity patterns
verticalSpread: 0.3, // How much Y variation (0=flat line, 1=full height)
// Activity modulation (Rule 110 density → spawn rate)
activityInfluence: 0.5, // 0 = no influence, 1 = full control over spawn rate
minSpawnMultiplier: 0.5, // Min spawn rate at 0% Rule 110 activity
maxSpawnMultiplier: 1.5, // Max spawn rate at 100% Rule 110 activity
// Visual feedback
showOverlay: false, // Show Rule 110 state as overlay on world (enable for debugging)
overlayOpacity: 0.3, // Overlay transparency (increased from 0.15 for better visibility)
overlayHeight: 20, // Height of Rule 110 visualization bar (pixels)
overlayPosition: 'top', // 'top' | 'bottom'
},
// === Mitosis System (Reproduction Mechanics) ===
// Agents can reproduce when they have sufficient energy
mitosis: {
enabled: true, // Enable mitosis system
enabledDuringTraining: false, // Disable during training (keep population fixed)
threshold: 100, // Minimum χ required to reproduce
cost: 50, // χ spent by parent on reproduction
childStartChi: 12, // Child's starting χ
cooldown: 150, // Ticks between mitosis attempts (5 seconds at 60fps)
maxAgents: 50, // Hard population cap
maxAliveAgents: 50, // Target cap for living agents
spawnOffset: 60, // Distance from parent to spawn child (pixels)
inheritHeading: true, // Child inherits parent's heading (with noise)
headingNoise: 0.8, // Radians of noise added to inherited heading
// Discrete budding reproduction when χ is very high
buddingThreshold: 150, // χ required to trigger budding split
buddingShare: 0.5, // Fraction of parent's χ transferred to budded child
buddingOffset: 20, // Random jitter radius for budding spawn (pixels)
buddingRespectCooldown: true, // Reuse cooldown before another budding/mitosis event
// Population dynamics
respectCarryingCapacity: true, // Integrate with resource ecology
carryingCapacityMultiplier: 1.5, // Allow population = resources × multiplier
// Baseline mitosis controller
baseline: {
enabled: true, // Enable baseline probability gating
threshold: 0.5, // Logistic offset for probability
weights: { // Signal weights
capacity: 1.0,
strain: 1.0,
pressure: 1.0,
opportunity: 1.0,
harmony: 1.0,
},
pressureRadius: 180, // px radius to measure local crowding
pressureMaxNeighbors: 6, // Neighbor count that saturates crowding
opportunityRadius: 220, // px radius to scan for resources/opportunity
opportunityMaxResources: 3, // Resource count that maxes opportunity
},
// Lineage visualization
showLineage: false, // Draw lines connecting parent to child
lineageMaxDistance: 5000, // Max distance to draw lineage link (pixels)
lineageFadeDuration: 10000, // Ticks until lineage link fades (10 seconds at 60fps)
lineageOpacity: 1, // Base opacity of lineage lines (0-1)
lineageColor: "#CFFF04", // Color of lineage lines
},
// === Decay System (Chi Recycling) ===
// Dead agents decay and release their chi back into the environment
decay: {
enabled: true, // Enable decay system
duration: 360, // Ticks for full decay (6 seconds at 60fps)
fertilityBoost: 0.4, // Chi → fertility conversion rate (0.4 fertility per chi)
releaseRadius: 80, // Area of effect for chi release (pixels)
visualFade: true, // Gradually fade and shrink visually
removeAfterDecay: true, // Remove fully decayed agents from array
},
// === HUD ===
hud: {
show: true,
showActions: true // Show action values (turn/thrust/senseFrac) for debugging
},
// === Learning System ===
learning: {
// Observation vector settings
observationDims: 29, // total observation vector size (includes χ, motion, walls, resource, trails, scent, density, signals)
normalizeObs: true, // normalize observations to [-1, 1]
// Action space
turnRate: 0.1, // max turn per step (radians)
thrustScale: 1.0, // thrust multiplier
// Reward function weights
rewards: {
collectResource: 500.0, // +R when collecting resource
chiGain: 0.5, // +R per χ gained (residual reuse)
chiSpend: -0.1, // -R per χ spent
stuck: -0.8, // -R when stuck near walls
idle: -0.5, // -R per tick when idle
explore: 10.0, // +R for unique trail coverage
provenanceCredit: .5, // +R when others reuse your trails
death: -50.0, // -R when χ reaches 0
gradientClimb: 5.0, // +R per pixel moved closer to food (gradient climbing)
signalResponse: 1.5, // +R for moving toward resource signal gradients
},
// Episode settings
episodeLength: 3000, // max ticks per episode
terminateOnDeath: true, // end episode when χ = 0
// CEM/CMA-ES settings
populationSize: 20, // number of policies per generation
eliteCount: 5, // top K policies to keep
mutationStdDev: 0.5, // initial exploration noise
generations: 100, // training generations
},
// === Rendering & UI ===
rendering: {
renderTrail: true,
hud: { show: true },
},
// === Controls ===
controls: {
autoMove: false, // toggle with [A]
},
// === Link System (agent-to-agent tubes) ===
link: {
radius: 120, // px
formCost: 1.2, // χ to create (per agent)
maintPerSec: 0.02, // χ/sec * strength (per agent)
decayPerSec: 0.015, // strength/sec loss
strengthenPerUse: 0.04, // strength/sec when used
initStrength: 0.8, // initial strength at formation
minStrength: 0.1,
guidanceGain: 0.6, // steering bias multiplier
springK: 0.004, // gentle
transfer: { capPerSec: 0.4, loss: 0.2 },
trailMin: 0.25, // need “hot” shared cell to form
// Hunger escape: hungry agents reduce link influence and increase decay
hungerEscape: 0.7, // 0..1 fraction to damp link forces at max hunger
hungerDecayPerSec: 0.02 // extra strength/sec decay at max hunger (averaged)
},
// === Signal Field (multi-channel environmental signals) ===
signal: {
enabled: true,
cell: 10,
decayPerSec: 0.06,
diffusePerSec: 0.12,
channels: 3,
memoryLength: 12,
activationThreshold: 0.08,
sensitivity: {
resource: 1.0,
distress: 1.0,
bond: 1.0
},
decay: {
resource: 0.08,
distress: 0.1,
bond: 0.06
},
channelWeights: {
resource: 1.0,
distress: 1.0,
bond: 1.0
},
// Resource signal strengths
resourceSensingStrength: 0.3, // Signal strength when agent first senses a resource
resourceConsumptionStrength: 1.0, // Signal strength when agent consumes a resource
resourceConsumptionPersistence: 3, // Number of frames to deposit consumption signal (for persistence)
},
// === Participation Modes (channel gating & falloff) ===
participation: {
enabled: true,
debugLog: false,
maxForceFraction: 0.35, // Max participation force as fraction of agent speed (0.35 = 35%)
visualRadiusScale: 1.0, // Scale factor for visual circles (1.0 = actual radius, 0.2 = 20% size)
modes: {
resource: {
strength: 8.0,
decay: 1.0,
radius: 80
},
distress: {
strength: 12.0,
decay: 1.2,
radius: 100
},
bond: {
strength: 6.0,
decay: 0.9,
radius: 70
}
}
},
// === Bond Loss Signals ===
bondLoss: {
onDeathExploreBoost: 1.0, // Extra exploration noise multiplier when a bonded partner dies
onDeathBoostDuration: 600 // Duration in ticks for bereavement exploration boost
},
};
applyTcConfig(CONFIG.tc || {});
loadTapeMachinesFromConfig(CONFIG.tc || {});
// --- Snapshots for panel resets ---
let CURRENT_BASE_SNAPSHOT = null; // last loaded/applied profile
let BOOT_SNAPSHOT = null; // factory defaults (boot-time read)
function initSnapshotsOnce() {
if (!BOOT_SNAPSHOT) BOOT_SNAPSHOT = ConfigIO.snapshot();
if (!CURRENT_BASE_SNAPSHOT) CURRENT_BASE_SNAPSHOT = BOOT_SNAPSHOT;
}
export const CONFIG_SCHEMA = {
Diagnostics: {
debug: { label: "Debug mode", type: "boolean" }
},
Metabolism: {
startChi: { label: "Start χ", min: 0, max: 200, step: 1 },
baseDecayPerSecond: { label: "Leak χ/sec", min: 0, max: 2, step: 0.01 },
moveSpeedPxPerSec: { label: "Move speed (px/sec)", min: 10, max: 400, step: 5 },
moveCostPerSecond: { label: "Move χ/sec", min: 0, max: 5, step: 0.01 },
rewardChi: { label: "Pickup reward χ", min: 0, max: 200, step: 1 },
},
Resources: {
resourceRadius: { label: "Resource radius (px)", min: 1, max: 80, step: 1 },
bundleSize: { label: "Bundle size", min: 1, max: 200, step: 1 },
startingAgents: { label: "Starting agents", min: 1, max: 100, step: 1 },
resourceDynamicCount: { label: "Dynamic resource count", type: "boolean" },
resourceInitialMin: { label: "Initial min resources", min: 0, max: 100, step: 1 },
resourceInitialMax: { label: "Initial max resources", min: 0, max: 150, step: 1 },
resourceStableMin: { label: "Stable min resources", min: 0, max: 100, step: 1 },
resourceStableMax: { label: "Stable max resources", min: 0, max: 150, step: 1 },
resourceDepletionRate: { label: "Depletion rate", min: 0, max: 1, step: 0.005 },
resourceRecoveryChance: { label: "Recovery chance", min: 0, max: 1, step: 0.01 },
resourceRespawnCooldown: { label: "Respawn cooldown (ticks)", min: 0, max: 2000, step: 10 },
resourceCount: { label: "Legacy resource count", min: 0, max: 200, step: 1 },
resourceScaleWithAgents: { label: "Scale with agents", type: "boolean" },
resourceBaseAbundance: { label: "Base abundance", min: 0, max: 500, step: 5 },
resourceCompetition: { label: "Competition factor", min: 0, max: 5, step: 0.01 },
resourceScaleMinimum: { label: "Scale minimum", min: 0, max: 200, step: 1 },
resourceScaleMaximum: { label: "Scale maximum", min: 0, max: 500, step: 5 },
},
"Plant Ecology": {
"plantEcology.enabled": { label: "Enable plant ecology", type: "boolean" },
"plantEcology.fertilityCell": { label: "Fertility cell (px)", min: 10, max: 200, step: 5 },
"plantEcology.initialFertility": { label: "Initial fertility", min: 0, max: 1, step: 0.01 },
"plantEcology.fertilityVariation": { label: "Fertility variation", min: 0, max: 1, step: 0.01 },
"plantEcology.seedChance": { label: "Seed chance/sec", min: 0, max: 1, step: 0.001 },
"plantEcology.seedDistance": { label: "Seed distance (px)", min: 0, max: 600, step: 5 },
"plantEcology.growthFertilityThreshold": { label: "Growth fertility threshold", min: 0, max: 1, step: 0.01 },
"plantEcology.growthChance": { label: "Growth chance/sec", min: 0, max: 1, step: 0.005 },
"plantEcology.patchCount": { label: "Patch count", min: 0, max: 40, step: 1 },
"plantEcology.patchRadius": { label: "Patch radius (px)", min: 0, max: 800, step: 10 },
"plantEcology.patchFertility": { label: "Patch fertility", min: 0, max: 1, step: 0.01 },
"plantEcology.harvestDepletion": { label: "Harvest depletion", min: 0, max: 1, step: 0.01 },
"plantEcology.harvestRadius": { label: "Harvest radius (px)", min: 0, max: 400, step: 5 },
"plantEcology.fertilityRecovery": { label: "Fertility recovery/sec", min: 0, max: 1, step: 0.01 },
"plantEcology.maxFertility": { label: "Max fertility", min: 0, max: 1, step: 0.01 },
"plantEcology.populationPressure": { label: "Enable population pressure", type: "boolean" },
"plantEcology.pressurePerAgent": { label: "Pressure per agent", min: 0, max: 0.5, step: 0.005 },
"plantEcology.pressureThreshold": { label: "Pressure threshold", min: 0, max: 200, step: 1 },
"plantEcology.spawnPressure.startAgents": { label: "Spawn pressure start agents", min: 0, max: 200, step: 1 },
"plantEcology.spawnPressure.maxAgents": { label: "Spawn pressure max agents", min: 0, max: 500, step: 1 },
"plantEcology.spawnPressure.minSeedMultiplier": { label: "Min seed multiplier", min: 0, max: 1, step: 0.01 },
"plantEcology.spawnPressure.minGrowthMultiplier": { label: "Min growth multiplier", min: 0, max: 1, step: 0.01 },
"plantEcology.spawnPressure.minResourceMultiplier": { label: "Min resource multiplier", min: 0, max: 1, step: 0.01 },
},
"Adaptive Reward": {
"adaptiveReward.enabled": { label: "Enable adaptive reward", type: "boolean" },
"adaptiveReward.gainFactor": { label: "Gain factor", min: 0, max: 20, step: 0.1 },
"adaptiveReward.avgMoveFraction": { label: "Avg move fraction", min: 0, max: 1, step: 0.01 },
"adaptiveReward.emaAlpha": { label: "EMA alpha", min: 0, max: 1, step: 0.01 },
"adaptiveReward.minReward": { label: "Min reward", min: 0, max: 200, step: 1 },
"adaptiveReward.maxReward": { label: "Max reward", min: 0, max: 500, step: 5 },
"adaptiveReward.useAbsoluteAnchor": { label: "Use absolute anchor", type: "boolean" },
"adaptiveReward.chiPerATP": { label: "χ per ATP", min: 0, max: 0.1, step: 0.000001 },
"adaptiveReward.moleculesPerPatch": { label: "Molecules per patch", min: 0, max: 1e10, step: 1e7 },
"adaptiveReward.atpPerGlucose": { label: "ATP per glucose", min: 0, max: 100, step: 1 },
},
Trails: {
trailCell: { label: "Trail cell (px)", min: 1, max: 40, step: 1 },
depositPerSec: { label: "Deposit/sec", min: 0, max: 10, step: 0.05 },
evapPerSec: { label: "Evap/sec", min: 0, max: 1, step: 0.01 },
diffusePerSec: { label: "Diffuse/sec", min: 0, max: 1, step: 0.01 },
enableDiffusion: { label: "Enable diffusion", type: "boolean" },
renderTrail: { label: "Render trails", type: "boolean" },
residualGainPerSec: { label: "Residual gain/sec", min: 0, max: 10, step: 0.1 },
residualCapPerTick: { label: "Residual cap/tick", min: 0, max: 5, step: 0.01 },
trailCooldownTicks: { label: "Trail cooldown (ticks)", min: 0, max: 200, step: 1 },
ownTrailPenalty: { label: "Own trail penalty", min: 0, max: 5, step: 0.05 },
ownTrailGraceAge: { label: "Own trail grace age", min: 0, max: 200, step: 1 },
},
Autonomy: {
autoMove: { label: "Auto move", type: "boolean" },
"controls.autoMove": { label: "Controls auto move", type: "boolean" },
},
Sensing: {
aiSensoryRangeBase: { label: "Base range (px)", min: 20, max: 800, step: 5 },
aiSensoryRangeMax: { label: "Max range (px)", min: 50, max: 1200, step: 10 },
aiSenseRangePerChi: { label: "Range per χ", min: 0, max: 200, step: 1 },
aiSenseBiasFromFrustr: { label: "Frustration bias", min: 0, max: 5, step: 0.01 },
aiSenseSlewPerSec: { label: "Sense slew/sec", min: 0, max: 1000, step: 10 },
},
"Wall & Collision": {
aiWallAvoidMargin: { label: "Wall avoid margin", min: 0, max: 400, step: 5 },
aiWallAvoidStrength: { label: "Wall avoid strength", min: 0, max: 10, step: 0.1 },
enableAgentCollision: { label: "Enable collision", type: "boolean" },
agentCollisionPushback: { label: "Collision pushback", min: 0, max: 2, step: 0.01 },
},
Behavior: {
aiExploreNoiseBase: { label: "Explore noise base", min: 0, max: 2, step: 0.01 },
aiExploreNoiseGain: { label: "Explore noise gain", min: 0, max: 4, step: 0.01 },
aiTrailFollowingNear: { label: "Trail follow (near)", min: 0, max: 10, step: 0.05 },
aiTrailFollowingFar: { label: "Trail follow (far)", min: 0, max: 10, step: 0.05 },
aiSampleDistance: { label: "Sample distance (px)", min: 0, max: 400, step: 1 },
aiResourceAttractionStrength: { label: "Resource attraction", min: 0, max: 20, step: 0.1 },
aiResourceAttractionScaleWithDistance: { label: "Scale attraction w/ distance", type: "boolean" },
},
Frustration: {
aiFrustrationBuildRate: { label: "Frustration build", min: 0, max: 5, step: 0.01 },
aiFrustrationDecayRate: { label: "Frustration decay", min: 0, max: 5, step: 0.01 },
aiFrustrationSightGrace: { label: "Sight grace", min: 0, max: 500, step: 1 },
aiFrustrationLowTrail: { label: "Low trail threshold", min: 0, max: 1, step: 0.01 },
},
"Frustration Effects": {
aiSurgeMax: { label: "Surge max", min: 0, max: 5, step: 0.01 },
aiTurnRateBase: { label: "Turn rate base", min: 0, max: 20, step: 0.1 },
aiTurnRateGain: { label: "Turn rate gain", min: 0, max: 20, step: 0.1 },
},
TC: {
"tc.enabled": { label: "Enable TC runtime", type: "boolean" },
"tc.seed": { label: "TC seed", min: 0, max: 4294967295, step: 1 },
"tc.maxCachedChunks": { label: "TC cache size", min: 1, max: 2048, step: 1 },
"tc.updateCadence": { label: "TC update cadence", min: 0, max: 1000, step: 1 }
},
Hunger: {
hungerBuildRate: { label: "Hunger build/sec", min: 0, max: 5, step: 0.01 },
hungerDecayOnCollect: { label: "Hunger decay on collect", min: 0, max: 1, step: 0.01 },
hungerThresholdLow: { label: "Hunger low threshold", min: 0, max: 1, step: 0.01 },
hungerThresholdHigh: { label: "Hunger high threshold", min: 0, max: 1, step: 0.01 },
hungerExplorationAmp: { label: "Hunger explore amp", min: 0, max: 20, step: 0.1 },
hungerFrustrationAmp: { label: "Hunger frustration amp", min: 0, max: 20, step: 0.1 },
hungerSenseAmp: { label: "Hunger sense amp", min: 0, max: 20, step: 0.1 },
hungerSurgeAmp: { label: "Hunger surge amp", min: 0, max: 10, step: 0.1 },
},
"Scent Gradient": {
"scentGradient.enabled": { label: "Enable scent gradient", type: "boolean" },
"scentGradient.maxRange": { label: "Max range (px)", min: 0, max: 1000, step: 10 },
"scentGradient.falloffType": {
label: "Falloff type",
type: "options",
options: ["linear", "inverse", "inverse-square", "exponential"],
},
"scentGradient.strength": { label: "Scent strength", min: 0, max: 10, step: 0.1 },
"scentGradient.showSubtleIndicator": { label: "Show indicator", type: "boolean" },
"scentGradient.rewardEnabled": { label: "Enable distance reward", type: "boolean" },
"scentGradient.rewardScale": { label: "Reward scale", min: 0, max: 5, step: 0.01 },
"scentGradient.rewardUpdateInterval": { label: "Reward update interval", min: 0, max: 200, step: 0.1 },
"scentGradient.densitySensingEnabled": { label: "Density sensing", type: "boolean" },
"scentGradient.densityRadiusNear": { label: "Density radius near", min: 0, max: 1000, step: 10 },
"scentGradient.densityRadiusMid": { label: "Density radius mid", min: 0, max: 1000, step: 10 },
"scentGradient.densityRadiusFar": { label: "Density radius far", min: 0, max: 1000, step: 10 },
"scentGradient.consumable": { label: "Consumable gradient", type: "boolean" },
"scentGradient.consumePerSec": { label: "Consume/sec", min: 0, max: 1, step: 0.01 },
"scentGradient.recoverPerSec": { label: "Recover/sec", min: 0, max: 1, step: 0.01 },
"scentGradient.minStrength": { label: "Min strength", min: 0, max: 5, step: 0.01 },
"scentGradient.minRange": { label: "Min range (px)", min: 0, max: 400, step: 5 },
"scentGradient.orbitBandPx": { label: "Orbit band (px)", min: 0, max: 400, step: 5 },
"scentGradient.vitalityConsumePerSec": { label: "Vitality consume/sec", min: 0, max: 1, step: 0.01 },
"scentGradient.vitalityRecoverPerSec": { label: "Vitality recover/sec", min: 0, max: 1, step: 0.01 },
"scentGradient.minVitality": { label: "Min vitality", min: 0, max: 1, step: 0.01 },
"scentGradient.depletionThreshold": { label: "Depletion threshold", min: 0, max: 1, step: 0.01 },
"scentGradient.vitalityToChiRate": { label: "Vitality to χ rate", min: 0, max: 10, step: 0.1 },
},
Mitosis: {
"mitosis.enabled": { label: "Enable mitosis", type: "boolean" },
"mitosis.enabledDuringTraining": { label: "Enable during training", type: "boolean" },
"mitosis.threshold": { label: "Mitosis threshold", min: 0, max: 500, step: 1 },
"mitosis.cost": { label: "Mitosis cost", min: 0, max: 500, step: 1 },
"mitosis.childStartChi": { label: "Child start χ", min: 0, max: 200, step: 1 },
"mitosis.cooldown": { label: "Mitosis cooldown", min: 0, max: 5000, step: 10 },
"mitosis.maxAgents": { label: "Max agents", min: 0, max: 500, step: 1 },
"mitosis.maxAliveAgents": { label: "Max alive agents", min: 0, max: 500, step: 1 },
"mitosis.spawnOffset": { label: "Spawn offset (px)", min: 0, max: 400, step: 5 },
"mitosis.inheritHeading": { label: "Inherit heading", type: "boolean" },
"mitosis.headingNoise": { label: "Heading noise", min: 0, max: 3.14, step: 0.01 },
"mitosis.buddingThreshold": { label: "Budding threshold", min: 0, max: 500, step: 1 },
"mitosis.buddingShare": { label: "Budding share", min: 0, max: 1, step: 0.01 },
"mitosis.buddingOffset": { label: "Budding offset (px)", min: 0, max: 200, step: 1 },
"mitosis.buddingRespectCooldown": { label: "Budding respects cooldown", type: "boolean" },
"mitosis.respectCarryingCapacity": { label: "Respect carrying capacity", type: "boolean" },
"mitosis.carryingCapacityMultiplier": { label: "Carrying capacity multiplier", min: 0, max: 10, step: 0.1 },
"mitosis.baseline.enabled": { label: "Baseline controller", type: "boolean" },
"mitosis.baseline.threshold": { label: "Baseline threshold", min: -2, max: 2, step: 0.01 },
"mitosis.baseline.weights.capacity": { label: "Weight: capacity", min: -4, max: 4, step: 0.1 },
"mitosis.baseline.weights.strain": { label: "Weight: strain", min: -4, max: 4, step: 0.1 },
"mitosis.baseline.weights.pressure": { label: "Weight: pressure", min: -4, max: 4, step: 0.1 },
"mitosis.baseline.weights.opportunity": { label: "Weight: opportunity", min: -4, max: 4, step: 0.1 },
"mitosis.baseline.weights.harmony": { label: "Weight: harmony", min: -4, max: 4, step: 0.1 },
"mitosis.baseline.pressureRadius": { label: "Pressure radius", min: 20, max: 800, step: 5 },
"mitosis.baseline.pressureMaxNeighbors": { label: "Pressure max neighbors", min: 1, max: 16, step: 1 },
"mitosis.baseline.opportunityRadius": { label: "Opportunity radius", min: 20, max: 800, step: 5 },
"mitosis.baseline.opportunityMaxResources": { label: "Opportunity max resources", min: 1, max: 10, step: 1 },
"mitosis.showLineage": { label: "Show lineage", type: "boolean" },
"mitosis.lineageMaxDistance": { label: "Lineage max distance", min: 0, max: 20000, step: 10 },
"mitosis.lineageFadeDuration": { label: "Lineage fade duration", min: 0, max: 60000, step: 10 },
"mitosis.lineageOpacity": { label: "Lineage opacity", min: 0, max: 1, step: 0.01 },
"mitosis.lineageColor": { label: "Lineage color", type: "color" },
},
Decay: {
"decay.enabled": { label: "Enable decay", type: "boolean" },
"decay.duration": { label: "Decay duration", min: 0, max: 5000, step: 10 },
"decay.fertilityBoost": { label: "Fertility boost", min: 0, max: 5, step: 0.01 },
"decay.releaseRadius": { label: "Release radius (px)", min: 0, max: 400, step: 5 },
"decay.visualFade": { label: "Visual fade", type: "boolean" },
"decay.removeAfterDecay": { label: "Remove after decay", type: "boolean" },
},
HUD: {
"hud.show": { label: "Show HUD", type: "boolean" },
"hud.showActions": { label: "Show actions", type: "boolean" },
},
Learning: {
"learning.observationDims": { label: "Observation dimensions", min: 1, max: 200, step: 1 },
"learning.normalizeObs": { label: "Normalize observations", type: "boolean" },
"learning.turnRate": { label: "Turn rate", min: 0, max: 1, step: 0.001 },
"learning.thrustScale": { label: "Thrust scale", min: 0, max: 5, step: 0.01 },
"learning.rewards.collectResource": { label: "Reward: collect", min: -1000, max: 2000, step: 1 },
"learning.rewards.chiGain": { label: "Reward: χ gain", min: -10, max: 10, step: 0.01 },
"learning.rewards.chiSpend": { label: "Reward: χ spend", min: -10, max: 10, step: 0.01 },
"learning.rewards.stuck": { label: "Reward: stuck", min: -10, max: 10, step: 0.01 },
"learning.rewards.idle": { label: "Reward: idle", min: -10, max: 10, step: 0.01 },
"learning.rewards.explore": { label: "Reward: explore", min: -100, max: 500, step: 0.5 },
"learning.rewards.provenanceCredit": { label: "Reward: provenance", min: -10, max: 10, step: 0.01 },
"learning.rewards.death": { label: "Reward: death", min: -500, max: 0, step: 1 },
"learning.rewards.gradientClimb": { label: "Reward: gradient climb", min: -50, max: 50, step: 0.1 },
"learning.rewards.signalResponse": { label: "Reward: signal response", min: -10, max: 10, step: 0.1 },
"learning.episodeLength": { label: "Episode length", min: 100, max: 20000, step: 10 },
"learning.terminateOnDeath": { label: "Terminate on death", type: "boolean" },
"learning.populationSize": { label: "Population size", min: 1, max: 200, step: 1 },
"learning.eliteCount": { label: "Elite count", min: 1, max: 200, step: 1 },
"learning.mutationStdDev": { label: "Mutation std dev", min: 0, max: 5, step: 0.01 },
"learning.generations": { label: "Generations", min: 1, max: 1000, step: 1 },
},
Rendering: {
"rendering.renderTrail": { label: "Render trail (UI)", type: "boolean" },
"rendering.hud.show": { label: "Render HUD", type: "boolean" },
},
Links: {
"link.radius": { label: "Link radius", min: 0, max: 500, step: 5 },
"link.formCost": { label: "Form cost χ", min: 0, max: 10, step: 0.01 },
"link.maintPerSec": { label: "Maintain χ/sec", min: 0, max: 1, step: 0.001 },
"link.decayPerSec": { label: "Decay/sec", min: 0, max: 1, step: 0.001 },
"link.strengthenPerUse": { label: "Strengthen per use", min: 0, max: 1, step: 0.001 },
"link.initStrength": { label: "Initial strength", min: 0, max: 1, step: 0.01 },
"link.minStrength": { label: "Min strength", min: 0, max: 1, step: 0.01 },
"link.guidanceGain": { label: "Guidance gain", min: 0, max: 5, step: 0.01 },
"link.springK": { label: "Spring K", min: 0, max: 0.1, step: 0.0005 },
"link.transfer.capPerSec": { label: "Transfer cap/sec", min: 0, max: 10, step: 0.01 },
"link.transfer.loss": { label: "Transfer loss", min: 0, max: 1, step: 0.01 },
"link.trailMin": { label: "Trail minimum", min: 0, max: 1, step: 0.01 },
"link.hungerEscape": { label: "Hunger escape", min: 0, max: 1, step: 0.01 },
"link.hungerDecayPerSec": { label: "Hunger decay/sec", min: 0, max: 1, step: 0.001 },
},
"Signal Field": {
"signal.enabled": { label: "Enable signal field", type: "boolean" },
"signal.cell": { label: "Signal cell (px)", min: 1, max: 80, step: 1 },
"signal.decayPerSec": { label: "Signal decay/sec", min: 0, max: 1, step: 0.01 },
"signal.diffusePerSec": { label: "Signal diffuse/sec", min: 0, max: 1, step: 0.01 },
"signal.channels": { label: "Signal channels", min: 1, max: 8, step: 1 },
"signal.memoryLength": { label: "Signal memory length", min: 3, max: 120, step: 1 },
"signal.activationThreshold": { label: "Signal activation threshold", min: 0, max: 1, step: 0.01 },
"signal.sensitivity.resource": { label: "Resource sensitivity gain", min: 0, max: 5, step: 0.01 },
"signal.sensitivity.distress": { label: "Distress sensitivity gain", min: 0, max: 5, step: 0.01 },
"signal.sensitivity.bond": { label: "Bond sensitivity gain", min: 0, max: 5, step: 0.01 },
"signal.decay.resource": { label: "Resource bias decay", min: 0, max: 1, step: 0.01 },
"signal.decay.distress": { label: "Distress bias decay", min: 0, max: 1, step: 0.01 },
"signal.decay.bond": { label: "Bond bias decay", min: 0, max: 1, step: 0.01 },
"signal.resourceSensingStrength": { label: "Resource sensing strength", min: 0, max: 2, step: 0.05 },
"signal.resourceConsumptionStrength": { label: "Resource consumption strength", min: 0, max: 2, step: 0.05 },
"signal.resourceConsumptionPersistence": { label: "Consumption persistence (frames)", min: 1, max: 10, step: 1 },
"signal.channelWeights.resource": { label: "Resource channel weight", min: 0, max: 5, step: 0.01 },
"signal.channelWeights.distress": { label: "Distress channel weight", min: 0, max: 5, step: 0.01 },
"signal.channelWeights.bond": { label: "Bond channel weight", min: 0, max: 5, step: 0.01 },
},
Participation: {
"participation.enabled": { label: "Enable participation", type: "boolean" },
"participation.debugLog": { label: "Debug logging", type: "boolean" },
"participation.maxForceFraction": { label: "Max force fraction", min: 0, max: 5, step: 0.05 },
"participation.visualRadiusScale": { label: "Visual radius scale", min: 0.1, max: 2, step: 0.05 },
"participation.modes.resource.strength": { label: "Resource strength", min: 0, max: 20, step: 0.1 },
"participation.modes.resource.decay": { label: "Resource decay", min: 0, max: 2, step: 0.01 },
"participation.modes.resource.radius": { label: "Resource radius (px)", min: 0, max: 1000, step: 10 },
"participation.modes.distress.strength": { label: "Distress strength", min: 0, max: 20, step: 0.1 },
"participation.modes.distress.decay": { label: "Distress decay", min: 0, max: 2, step: 0.01 },
"participation.modes.distress.radius": { label: "Distress radius (px)", min: 0, max: 1000, step: 10 },
"participation.modes.bond.strength": { label: "Bond strength", min: 0, max: 20, step: 0.1 },
"participation.modes.bond.decay": { label: "Bond decay", min: 0, max: 2, step: 0.01 },
"participation.modes.bond.radius": { label: "Bond radius (px)", min: 0, max: 1000, step: 10 },
},
"Bond Loss": {
"bondLoss.onDeathExploreBoost": { label: "On-death explore boost", min: 0, max: 10, step: 0.01 },
"bondLoss.onDeathBoostDuration": { label: "On-death boost duration", min: 0, max: 10000, step: 10 },
},
};
const CONFIG_HINTS = {
debug: "Enable debug instrumentation and telemetry forwarding.",
// Metabolism
startChi: "Starting chi for freshly spawned agents.",
baseDecayPerSecond: "Passive chi leak each second.",
moveSpeedPxPerSec: "Maximum movement speed in pixels per second.",
moveCostPerSecond: "Chi spent each second while moving.",
rewardChi: "Chi awarded when a resource is collected.",
// Resources
resourceRadius: "Visual radius of each resource patch.",
bundleSize: "How many chi units each pickup contains.",
startingAgents: "Number of agents to start the simulation with.",
resourceDynamicCount: "Toggle adaptive resource spawning vs fixed count.",
resourceInitialMin: "Minimum resources spawned at boot.",
resourceInitialMax: "Maximum resources spawned at boot.",
resourceStableMin: "Lower bound once ecology stabilizes.",
resourceStableMax: "Upper bound once ecology stabilizes.",
resourceDepletionRate: "Fraction removed from patch per harvest.",
resourceRecoveryChance: "Chance per second a depleted patch respawns.",
resourceRespawnCooldown: "Ticks before a harvested spot can respawn.",
resourceCount: "Fixed resource count when dynamics are disabled.",
resourceScaleWithAgents: "Scale ecology supply based on living agents.",
resourceBaseAbundance: "Target resources available with few agents.",
resourceCompetition: "How strongly extra agents reduce resources.",
resourceScaleMinimum: "Floor for scaled resource count.",
resourceScaleMaximum: "Ceiling for scaled resource count.",
// Plant ecology
"plantEcology.enabled": "Enable soil fertility driven resource growth.",
"plantEcology.fertilityCell": "Size of each fertility grid cell in pixels.",
"plantEcology.initialFertility": "Average starting soil fertility level.",
"plantEcology.fertilityVariation": "Randomized spread of initial fertility.",
"plantEcology.seedChance": "Per-second chance fertile cells emit a seed.",
"plantEcology.seedDistance": "Maximum distance a new seed can land.",
"plantEcology.growthFertilityThreshold": "Minimum fertility needed for growth.",
"plantEcology.growthChance": "Per-second chance a fertile cell grows food.",
"plantEcology.patchCount": "Number of initial fertile hotspots.",
"plantEcology.patchRadius": "Radius of each fertile hotspot in pixels.",
"plantEcology.patchFertility": "Fertility boost inside hotspot centers.",
"plantEcology.harvestDepletion": "Fertility lost locally per harvest.",
"plantEcology.harvestRadius": "Radius affected by harvest depletion.",
"plantEcology.fertilityRecovery": "Fertility regained per second when idle.",
"plantEcology.maxFertility": "Cap on fertility value after recovery.",
"plantEcology.populationPressure": "Enable global fertility drain from crowding.",
"plantEcology.pressurePerAgent": "Fertility drain per agent above threshold.",
"plantEcology.pressureThreshold": "Agent count where pressure begins.",
"plantEcology.spawnPressure.startAgents": "Population before spawn pressure begins.",
"plantEcology.spawnPressure.maxAgents": "Population where pressure maxes out.",
"plantEcology.spawnPressure.minSeedMultiplier": "Minimum seed rate under pressure.",
"plantEcology.spawnPressure.minGrowthMultiplier": "Minimum growth rate under pressure.",
"plantEcology.spawnPressure.minResourceMultiplier": "Minimum abundance cap under pressure.",
// Adaptive reward
"adaptiveReward.enabled": "Toggle adaptive reward calculations.",
"adaptiveReward.gainFactor": "Scales generosity of adaptive rewards.",
"adaptiveReward.avgMoveFraction": "Assumed fraction of time agents spend moving.",
"adaptiveReward.emaAlpha": "Smoothing factor for reward EMA.",
"adaptiveReward.minReward": "Floor value for adaptive rewards.",
"adaptiveReward.maxReward": "Ceiling value for adaptive rewards.",
"adaptiveReward.useAbsoluteAnchor": "Anchor rewards to absolute ATP estimates.",
"adaptiveReward.chiPerATP": "Chi credited for each ATP molecule.",
"adaptiveReward.moleculesPerPatch": "Estimated molecules per food patch.",
"adaptiveReward.atpPerGlucose": "ATP released per glucose molecule.",
// Trails
trailCell: "Trail grid cell size in pixels.",
depositPerSec: "Trail strength deposited each second.",
evapPerSec: "Trail evaporation rate per second.",
diffusePerSec: "Trail diffusion rate per second.",
enableDiffusion: "Allow trail scent to spread between cells.",
renderTrail: "Draw trail heatmap in the simulation view.",
residualGainPerSec: "Chi gained per second from residual reuse.",
residualCapPerTick: "Max residual chi recovered per tick.",
trailCooldownTicks: "Ticks before leaving trail again deposits.",
ownTrailPenalty: "Chi penalty per second for running own trail.",
ownTrailGraceAge: "Ticks before own trail becomes safe again.",
// Autonomy
autoMove: "Start sim with agents auto-controlled.",
"controls.autoMove": "Toggle for manual controls auto move.",
// Sensing
aiSensoryRangeBase: "Baseline sensory range when chi is low.",
aiSensoryRangeMax: "Hard cap on sensory range.",
aiSenseRangePerChi: "Extra sensing range gained per chi.",
aiSenseBiasFromFrustr: "Bias to sensory focus from frustration.",
aiSenseSlewPerSec: "How fast sensing direction can slew.",
// Wall & collision
aiWallAvoidMargin: "Distance from walls before avoidance kicks in.",
aiWallAvoidStrength: "Strength of wall repulsion force.",
enableAgentCollision: "Enable physical separation between agents.",
agentCollisionPushback: "Pushback strength when agents collide.",
// Behavior
aiExploreNoiseBase: "Baseline randomness added to steering.",
aiExploreNoiseGain: "Extra noise when exploration is boosted.",
aiTrailFollowingNear: "Trail following weight for nearby scent.",
aiTrailFollowingFar: "Trail following weight for distant scent.",
aiSampleDistance: "Distance ahead sampled for decisions.",
// Frustration
aiFrustrationBuildRate: "Rate frustration accumulates per second.",
aiFrustrationDecayRate: "Rate frustration dissipates per second.",
aiFrustrationSightGrace: "Ticks frustration stays low after seeing food.",
aiFrustrationLowTrail: "Trail strength threshold treated as low.",
// Frustration effects
aiSurgeMax: "Max speed surge granted by frustration.",
aiTurnRateBase: "Base turning rate before modifiers.",
aiTurnRateGain: "Extra turn rate unlocked by frustration.",
// Hunger
hungerBuildRate: "Per-second hunger accumulation rate.",
hungerDecayOnCollect: "Fraction of hunger removed per food pickup.",
hungerThresholdLow: "Hunger level considered satisfied.",
hungerThresholdHigh: "Hunger level considered starving.",
hungerExplorationAmp: "Exploration boost applied when hungry.",
hungerFrustrationAmp: "Frustration build multiplier when hungry.",
hungerSenseAmp: "Sensory range boost under hunger.",
hungerSurgeAmp: "Speed surge boost under hunger.",
// Scent gradient
"scentGradient.enabled": "Enable distance-based scent fields.",
"scentGradient.maxRange": "Maximum distance scent can travel.",
"scentGradient.falloffType": "How scent strength decays with distance.",
"scentGradient.strength": "Base strength of scent at resources.",
"scentGradient.showSubtleIndicator": "Show visual rings for resources.",
"scentGradient.rewardEnabled": "Grant rewards for moving toward food.",
"scentGradient.rewardScale": "Chi gained per pixel closer to food.",
"scentGradient.rewardUpdateInterval": "Ticks between gradient reward checks.",
"scentGradient.densitySensingEnabled": "Expose nearby food density in observations.",
"scentGradient.densityRadiusNear": "Near-field density sampling radius.",
"scentGradient.densityRadiusMid": "Mid-field density sampling radius.",