@micheeeeel/yinyangapp 1.0.6 → 2.0.1

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 (118) hide show
  1. package/README.md +105 -0
  2. package/dist/bundle.js +2 -1
  3. package/dist/bundle.js.LICENSE.txt +1 -0
  4. package/dist/types/adapters/yinYangAdapter.d.ts +10 -0
  5. package/dist/types/animations/AnimationsMngr.d.ts +7 -19
  6. package/dist/types/api-film.d.ts +22 -0
  7. package/dist/types/api.d.ts +48 -0
  8. package/dist/types/benchmark/runner.d.ts +5 -0
  9. package/dist/types/benchmark/scenarios.d.ts +118 -0
  10. package/dist/types/components/action-image/ActionImageModal.d.ts +42 -0
  11. package/dist/types/components/controller/YinYangController.d.ts +946 -18
  12. package/dist/types/components/controller/action-stack/ActionStackController.d.ts +149 -0
  13. package/dist/types/components/controller/action-stack/ActionStackDragHandler.d.ts +111 -0
  14. package/dist/types/components/controller/action-stack/ActionStackManager.d.ts +118 -0
  15. package/dist/types/components/controller/action-stack/ActionStackState.d.ts +169 -0
  16. package/dist/types/components/controller/actions/ActionProjectionService.d.ts +73 -0
  17. package/dist/types/components/controller/actions/ChildActionMenuController.d.ts +83 -0
  18. package/dist/types/components/controller/actions/CoreEventMenuController.d.ts +90 -0
  19. package/dist/types/components/controller/actions/radialItemMenu.d.ts +117 -0
  20. package/dist/types/components/controller/children/ChildInteractionController.d.ts +38 -0
  21. package/dist/types/components/controller/children/ChildrenOrbitService.d.ts +14 -0
  22. package/dist/types/components/controller/force-field/EventFieldLifecycleController.d.ts +104 -0
  23. package/dist/types/components/controller/force-field/EventFieldRenderer.d.ts +86 -0
  24. package/dist/types/components/controller/force-field/ForceFieldComputationService.d.ts +50 -0
  25. package/dist/types/components/controller/force-field/ForceFieldDetailsPanel.d.ts +639 -0
  26. package/dist/types/components/controller/force-field/ForceFieldLifecycleController.d.ts +53 -0
  27. package/dist/types/components/controller/force-field/ForceFieldRenderer.d.ts +67 -0
  28. package/dist/types/components/controller/force-field/types.d.ts +42 -0
  29. package/dist/types/components/controller/labels/ChildScoresDeltaRenderer.d.ts +33 -0
  30. package/dist/types/components/controller/labels/ContextLabelsRenderer.d.ts +155 -0
  31. package/dist/types/components/controller/labels/WeightPreviewRingRenderer.d.ts +61 -0
  32. package/dist/types/components/controller/odd/ChildrenOrbitManager.d.ts +25 -0
  33. package/dist/types/components/controller/odd/OddViewManager.d.ts +44 -0
  34. package/dist/types/components/controller/search/SearchPanelSynchronizer.d.ts +125 -0
  35. package/dist/types/components/controller/settings/ControllerSettingsApplier.d.ts +50 -0
  36. package/dist/types/components/controller/state/BlockingAnimationTracker.d.ts +17 -0
  37. package/dist/types/components/controller/state/YinYangControllerState.d.ts +176 -0
  38. package/dist/types/components/controller/utils/actionStackMath.d.ts +13 -0
  39. package/dist/types/components/controller/utils/actionStackReorder.d.ts +7 -0
  40. package/dist/types/components/controller/utils/childrenOrbit.d.ts +18 -0
  41. package/dist/types/components/controller/utils/cuttingLabels.d.ts +9 -0
  42. package/dist/types/components/controller/utils/eventFieldStyle.d.ts +13 -0
  43. package/dist/types/components/controller/utils/eventFieldTargets.d.ts +47 -0
  44. package/dist/types/components/controller/utils/forceFieldMetadata.d.ts +4 -0
  45. package/dist/types/components/controller/utils/forceFieldPresentation.d.ts +9 -0
  46. package/dist/types/components/controller/utils/forceFieldStyle.d.ts +10 -0
  47. package/dist/types/components/controller/utils/labelGeometry.d.ts +5 -0
  48. package/dist/types/components/controller/utils/oddCutting.d.ts +2 -0
  49. package/dist/types/components/controller/utils/svgCoordinates.d.ts +9 -0
  50. package/dist/types/components/controller/utils/svgTransform.d.ts +5 -0
  51. package/dist/types/components/controller/utils/textLayout.d.ts +2 -0
  52. package/dist/types/components/controls/VizControlsPanel.d.ts +14 -0
  53. package/dist/types/components/factory/YinYangAppFactory.d.ts +4 -6
  54. package/dist/types/components/model/YinYangModel.d.ts +4 -30
  55. package/dist/types/components/panel/DiagramPanelBridge.d.ts +34 -0
  56. package/dist/types/components/panel/PanelManager.d.ts +150 -0
  57. package/dist/types/components/search/GlobalSearchController.d.ts +396 -0
  58. package/dist/types/components/stack-nav/StackNavOverlay.d.ts +82 -0
  59. package/dist/types/components/view/BorderDrawer.d.ts +203 -13
  60. package/dist/types/components/view/SpikeDrawer.d.ts +37 -31
  61. package/dist/types/components/view/ViewInitializer.d.ts +438 -2
  62. package/dist/types/components/view/YinYangDrawer.d.ts +414 -11
  63. package/dist/types/config/animationConfig.d.ts +37 -0
  64. package/dist/types/config/deltaColors.d.ts +64 -0
  65. package/dist/types/config/labelStyleConfig.d.ts +50 -0
  66. package/dist/types/data/OddCategoryColors.d.ts +12 -2
  67. package/dist/types/data/adverse-action-planner.d.ts +51 -0
  68. package/dist/types/data/adverse-action-planner.test.d.ts +1 -0
  69. package/dist/types/data/amplifier-engine.d.ts +107 -0
  70. package/dist/types/data/amplifier-engine.test.d.ts +1 -0
  71. package/dist/types/data/combo-engine.d.ts +94 -0
  72. package/dist/types/data/combo-engine.test.d.ts +1 -0
  73. package/dist/types/data/odd_generic_descriptions.d.ts +4 -0
  74. package/dist/types/data/odd_labels.d.ts +5 -0
  75. package/dist/types/data/yasuni_actions.d.ts +47 -0
  76. package/dist/types/data/yasuni_adverse_actions.d.ts +2 -0
  77. package/dist/types/data/yasuni_adverse_key_events.d.ts +2 -0
  78. package/dist/types/data/yasuni_cause.d.ts +33 -0
  79. package/dist/types/data/yasuni_graph.d.ts +22 -0
  80. package/dist/types/data/yasuni_key_events.d.ts +61 -0
  81. package/dist/types/data/yasuni_propagation_layers.d.ts +3 -0
  82. package/dist/types/interfaces/IActions.d.ts +1 -0
  83. package/dist/types/interfaces/ICauseGraph.d.ts +9 -0
  84. package/dist/types/interfaces/ICauseModel.d.ts +33 -0
  85. package/dist/types/interfaces/IGraphicsStrategy.d.ts +9 -5
  86. package/dist/types/interfaces/IPropagationLayers.d.ts +27 -0
  87. package/dist/types/interfaces/IViewData.d.ts +12 -0
  88. package/dist/types/interfaces/IYinYangAppFactory.d.ts +3 -3
  89. package/dist/types/interfaces/IYinYangController.d.ts +301 -6
  90. package/dist/types/interfaces/IYinYangGeometry.d.ts +43 -0
  91. package/dist/types/interfaces/IYinYangInternalModel.d.ts +34 -0
  92. package/dist/types/interfaces/IYinYangModel.d.ts +3 -11
  93. package/dist/types/main.d.ts +9 -0
  94. package/dist/types/utils/actionImages.d.ts +14 -0
  95. package/dist/types/utils/actionPropagation.d.ts +74 -0
  96. package/dist/types/utils/appMode.d.ts +5 -0
  97. package/dist/types/utils/causeGraph.d.ts +6 -0
  98. package/dist/types/utils/causeMetrics.d.ts +26 -0
  99. package/dist/types/utils/chainCardHeight.d.ts +27 -0
  100. package/dist/types/utils/d3/D3Element.d.ts +2 -2
  101. package/dist/types/utils/d3/D3GraphicsStrategy.d.ts +21 -4
  102. package/dist/types/utils/deltaChips.d.ts +15 -0
  103. package/dist/types/utils/deltaLabels.d.ts +54 -0
  104. package/dist/types/utils/facetteImages.d.ts +1 -0
  105. package/dist/types/utils/geometryUtils.d.ts +0 -1
  106. package/dist/types/utils/hierBadge.d.ts +44 -0
  107. package/dist/types/utils/idleSphereImage.d.ts +8 -0
  108. package/dist/types/utils/keyEventImages.d.ts +41 -0
  109. package/dist/types/utils/oddLegend.d.ts +30 -0
  110. package/dist/types/utils/positionalEfficiency.d.ts +16 -0
  111. package/dist/types/utils/yinYangWatermark.d.ts +29 -0
  112. package/package.json +27 -12
  113. package/dist/index.html +0 -1
  114. package/dist/types/data/coupe_rase_Orangs-outans/data_Kalimantan.d.ts +0 -3
  115. package/dist/types/data/coupe_rase_Orangs-outans/data_PT_Mayawana_Persada.d.ts +0 -3
  116. package/dist/types/data/data_institu_bancaire.d.ts +0 -3
  117. package/dist/types/interfaces/IOddItem.d.ts +0 -6
  118. package/dist/types/script.d.ts +0 -13
@@ -1,31 +1,197 @@
1
1
  import { IYinYangModel } from "../../interfaces/IYinYangModel";
2
2
  import { IYinYangView } from "../../interfaces/IYinYangView";
3
3
  import { IYinYangController } from "../../interfaces/IYinYangController";
4
- import { ICategory } from "../../interfaces/ICategory";
5
4
  import { IYinYangAppFactory } from "../../interfaces/IYinYangAppFactory";
6
- import { IOddItem } from "../../interfaces/IOddItem";
7
5
  import { IAnimator } from "../../interfaces/IAnimator";
6
+ import { YinYangInternalModel } from "../../interfaces/IYinYangInternalModel";
7
+ import { type ComboResult } from "../../data/combo-engine";
8
+ import { type AmplifierResult, type AmplifierTargetBreakdown } from "../../data/amplifier-engine";
9
+ import { ForceFieldLinkDetail } from "./force-field/types";
10
+ /**
11
+ * Bloc "action" de la vue cumulative (mode STACK) : "source" = action jouée
12
+ * sur le satellite ciblé, "propagation" = effet indirect qui l'atteint depuis
13
+ * un autre satellite.
14
+ */
15
+ type ActionCumulativeBlock = {
16
+ type: "source" | "propagation";
17
+ actionId?: string;
18
+ actionName: string;
19
+ actionDescription: string;
20
+ sourceComponentName?: string;
21
+ sourceOddName?: string;
22
+ sourceOddId: string;
23
+ sourceCuttingId: number | undefined;
24
+ totalDelta: number;
25
+ rawDelta?: number;
26
+ baseDelta?: number;
27
+ weightDelta?: number;
28
+ weightDeltaBase?: number;
29
+ detailRows: ForceFieldLinkDetail[];
30
+ comboResults?: ComboResult[];
31
+ amplifierResults?: AmplifierResult[];
32
+ stackItemId?: string;
33
+ color?: string;
34
+ /** This item's own propagation edges from the real sequential
35
+ * simulation (see computeSequentialStackContributionsAtFocus) — lets
36
+ * the panel build this block's descriptive breakdown (cascade,
37
+ * absorption/gap badges, "satellites touchés" list) from data that
38
+ * exactly matches totalDelta, instead of the shared isolated pool. */
39
+ sequentialDetailPool?: ForceFieldLinkDetail[];
40
+ /** Position dans la pile (ActionStackItem.slotIndex) — permet de fusionner
41
+ * et trier les blocs "keyEvent" avec les blocs action dans leur ordre
42
+ * naturel de pile (voir renderCumulativeDetailsForCutting). */
43
+ slotIndex?: number;
44
+ };
45
+ /**
46
+ * Bloc "keyEvent" de la vue cumulative : un Événement Clé joué (kind="keyEvent"
47
+ * dans la pile), toujours affiché dès que sa Facette d'origine correspond à
48
+ * celle affichée — voir buildKeyEventBlocksForComponent. `active` distingue
49
+ * visuellement "amplifie actuellement une action ciblée" de "présent mais
50
+ * rien ne l'active encore" (voir isKeyEventCurrentlyActive) ; l'existence du
51
+ * bloc, elle, ne dépend jamais de cette condition.
52
+ */
53
+ type KeyEventCumulativeBlock = {
54
+ type: "keyEvent";
55
+ keyEventId: string;
56
+ active: boolean;
57
+ totalDelta: number;
58
+ slotIndex?: number;
59
+ stackItemId?: string;
60
+ color?: string;
61
+ targetedActions: Array<{
62
+ id: string;
63
+ name: string;
64
+ }>;
65
+ breakdowns?: AmplifierTargetBreakdown[];
66
+ };
67
+ /**
68
+ * Un bloc de la vue cumulative (mode STACK). Hissé au niveau module (au lieu
69
+ * d'un type local à renderCumulativeDetailsForCutting) pour être partagé avec
70
+ * buildKeyEventBlocksForComponent, réutilisé aussi par renderComposanteInfo
71
+ * quand aucun satellite n'est sélectionné.
72
+ */
73
+ export type CumulativeBlock = ActionCumulativeBlock | KeyEventCumulativeBlock;
74
+ type DiagramNavEvent = {
75
+ type: "composante";
76
+ componentIndex: number;
77
+ } | {
78
+ type: "cutting";
79
+ componentIndex: number;
80
+ oddId: string;
81
+ cuttingIndex: number;
82
+ } | {
83
+ type: "action";
84
+ componentIndex: number;
85
+ oddId: string;
86
+ cuttingIndex: number;
87
+ actionId: string;
88
+ } | {
89
+ type: "keyEvent";
90
+ componentIndex: number;
91
+ keyEventId: string;
92
+ };
8
93
  export declare class YinYangController implements IYinYangController {
9
94
  model: IYinYangModel;
10
95
  view: IYinYangView;
11
96
  factory: IYinYangAppFactory;
12
97
  animator: IAnimator;
98
+ private childControllers;
99
+ private childrenOrbitManager;
100
+ private childOddMap;
13
101
  /**
14
- * Constructor to initialize the controller with its model, view, and factory.
102
+ * Persists the active action across component switches.
103
+ * Cleared only when the user explicitly deselects the action.
15
104
  */
16
- constructor(model: IYinYangModel, view: IYinYangView, factory: IYinYangAppFactory);
105
+ private persistentActionContext;
17
106
  /**
18
- * Retrieves the number of borders for the YinYang view.
107
+ * Prepared by prepareForComponentSwitch() before children are hidden.
108
+ * undefined = not yet prepared (fallback path)
109
+ * null = prepared but no action applies to target component
110
+ * { type: 'incoming', ... } = show incoming force fields on arrival
111
+ * { type: 'reactivate' } = re-activate the source action on arrival
19
112
  */
20
- getBorderNb(): number;
113
+ private pendingComponentSwitchContext;
114
+ private readonly CHILD_LABEL_SHORT_MAX_CHARS;
115
+ private readonly ACTION_DRAG_THRESHOLD_PX;
116
+ private htmlDragGhost;
117
+ private selectedSourceFocus;
118
+ /** Focus saved just before switching away from the source component, so returning
119
+ * to the source component restores the same highlighted cutting (multi-action). */
120
+ private focusBeforeComponentSwitch;
121
+ /** Cross-component force-field links from the source component, saved when
122
+ * switching away to a target component. Used to recompute the incoming view
123
+ * when a checkbox toggle fires while already on the target component. */
124
+ private savedSourceComponentLinks;
125
+ /** Set by navigateToCutting for cross-component nav: after the switch the
126
+ * incoming force field context is established, then onCuttingLabelClick is
127
+ * called for this cutting to show its propagated card. */
128
+ private _pendingCuttingFocusAfterSwitch;
129
+ private _pendingOddHighlightAfterSwitch;
130
+ /** Set by SearchPanelSynchronizer.searchNavigateToCutting when a stack-item
131
+ * click switches facette while an action is active: prepareForComponentSwitch
132
+ * owns pendingComponentSwitchContext for the incoming force field, so this
133
+ * navigation is applied separately once the switch completes. */
134
+ private _pendingCuttingNavigationAfterSwitch;
135
+ /** Menu cœur à déployer à l'arrivée sur la facette (voir searchSetKeyEventMenuOpen). */
136
+ private _pendingKeyEventMenuAfterSwitch;
137
+ private actionStackController;
138
+ private childActionMenuController;
139
+ private coreEventMenuController;
140
+ private isCoreEventMenuOpen;
141
+ /** Id de l'Événement Clé actuellement en aperçu (carte affichée), ou null. */
142
+ private activeKeyEventId;
143
+ private forceFieldDetailsPanel;
144
+ private forceFieldRenderer;
145
+ /** Champ d'événement — liens cœur → satellites amplifiés par l'Événement
146
+ * Clé actuellement actif (voir eventFieldLifecycleController). */
147
+ private eventFieldRenderer;
148
+ private eventFieldLifecycleController;
149
+ private childScoresDeltaRenderer;
150
+ private weightPreviewRingRenderer;
151
+ private contextLabelsRenderer;
152
+ private forceFieldComputationService;
153
+ private childInteractionController;
154
+ private forceFieldLifecycleController;
155
+ private settingsApplier;
156
+ private oddViewManager;
157
+ private searchPanelSynchronizer;
158
+ private actionStackManager;
159
+ private state;
160
+ /** Callback to open the search tab and set a query — wired from main.ts. */
161
+ private openSearchWithQuery?;
162
+ /** Callback: injecte le bloc d'impact d'action directe dans l'onglet Recherche. */
163
+ private _onShowDirectActionBlock?;
164
+ /** Callback: affiche le bloc d'action directe d'un prérequis dans le panneau B. */
165
+ private _onShowDirectActionBlockPanelB?;
166
+ /** Quand vrai, le prochain appel à _onShowDirectActionBlock est routé vers le panneau B. */
167
+ private _routeNextDirectActionBlockToPanelB;
168
+ /** Quand vrai, renderSourceActionDetailsForCurrentSource ne re-rend pas le bloc Panel A.
169
+ * Utilisé pendant reactivatePersistentAction pour préserver l'état des <details> ouverts. */
170
+ private _suppressDirectActionBlockRender;
171
+ /** Callback: efface le bloc d'impact d'action directe de l'onglet Recherche. */
172
+ private _onClearDirectActionBlock?;
173
+ /** Callback: injecte la carte descriptive d'un Événement Clé dans l'onglet Recherche. */
174
+ private _onShowKeyEventBlock?;
175
+ /** Callback: efface la carte d'Événement Clé de l'onglet Recherche. */
176
+ private _onClearKeyEventBlock?;
177
+ /** Notifie la hiérarchie RECHERCHE de l'état du menu radial des Événements
178
+ * Clés (diagramme → arbre), pour que le groupe "Événements Clés" reste le
179
+ * reflet exact des bulles réellement déployées. */
180
+ private _onKeyEventMenuStateChange?;
181
+ /** Callback: injecte le bloc d'action propagée dans l'onglet Recherche. */
182
+ private _onShowPropagationBlock?;
183
+ /** Callback: efface le bloc d'action propagée de l'onglet Recherche. */
184
+ private _onClearPropagationBlock?;
21
185
  /**
22
- * Retrieves the sorted data for the model.
186
+ * Constructor to initialize the controller with its model, view, and factory.
23
187
  */
24
- getSortedData(): IOddItem[];
188
+ constructor(model: IYinYangModel, view: IYinYangView, factory: IYinYangAppFactory);
25
189
  /**
26
- * Retrieves the categories from the model.
190
+ * Retrieves the number of borders for the YinYang view.
27
191
  */
28
- getCategories(): ICategory[];
192
+ getBorderNb(): number;
193
+ getInternalModel(): YinYangInternalModel;
194
+ private getAllComponents;
29
195
  /**
30
196
  * Retrieves the unique key for this instance of the model.
31
197
  */
@@ -34,14 +200,7 @@ export declare class YinYangController implements IYinYangController {
34
200
  * Retrieves the parent key for this instance, if it exists.
35
201
  */
36
202
  getParentKey(): string | null;
37
- /**
38
- * Determines whether the current model represents an enemy.
39
- */
40
- getIsEnemy(): boolean;
41
- /**
42
- * Calculates the average score based on the model's data.
43
- */
44
- calculateAverageScore(): number;
203
+ getForceFieldAllLinkDetails(): ForceFieldLinkDetail[];
45
204
  /**
46
205
  * Generates a unique child key for sub-instances.
47
206
  */
@@ -51,9 +210,778 @@ export declare class YinYangController implements IYinYangController {
51
210
  * Each child is generated based on the small circle data.
52
211
  */
53
212
  createYinYangChildren(): void;
213
+ /** Both distance and size are fixed relative to the facette's uniform
214
+ * baseline radius, independent of any satellite's own weight-scaled
215
+ * radius — mirrors ChildActionMenuController's action cluster geometry. */
216
+ private getChildActionClusterReach;
217
+ /** Décalage constant appliqué au poids ET à sa moyenne avant de calculer le
218
+ * ratio de taille d'un satellite (voir weightToSizeRatio) : resserre la
219
+ * fourchette de tailles (poids min moins minuscule, poids max un peu
220
+ * moins dominant) sans changer la taille d'un satellite au poids moyen
221
+ * exact (ratio toujours 1 dans ce cas), et sans dépendre du poids moyen
222
+ * de la fratrie pour l'ampleur du resserrement. */
223
+ private static readonly WEIGHT_SIZE_FLOOR_OFFSET;
224
+ /** Ratio de taille d'un satellite (rayon relatif à la baseline uniforme de
225
+ * sa facette) à partir de son poids et du poids moyen de sa fratrie —
226
+ * voir WEIGHT_SIZE_FLOOR_OFFSET pour le resserrement. */
227
+ private static weightToSizeRatio;
228
+ /** Ratio of a component's heaviest satellite radius to its own uniform
229
+ * baseline radius. Mirrors the per-cutting weight-based scaling applied
230
+ * in createYinYangChildren(). */
231
+ private getMaxWeightRatio;
232
+ /** The container-fit shrink ratio only depends on borderOuterRadius/
233
+ * smallCircleRadius/distanceFromChild, which are fixed for the whole
234
+ * session once this top-level view is first initialized (they don't get
235
+ * recomputed on facette switch) — so this is computed once (on the worst
236
+ * case weight ratio across every facette) and cached. That's what keeps
237
+ * the whole diagram's size from visibly changing every time the user
238
+ * switches facette. */
239
+ private cachedGlobalFitShrinkRatio?;
240
+ private computeGlobalFitShrinkRatio;
241
+ applyChildrenFitScale(): void;
242
+ /** Creates the facette image ring, sized from the room actually left between
243
+ * the border and the container edge. Call after applyChildrenFitScale() so
244
+ * the pattern's final scale is already known. */
245
+ createFacetteImageRing(): void;
246
+ /** Re-applies the "Images facette" dev-control parameters (margin, fade
247
+ * start/opacity) by rebuilding the ring. */
248
+ rebuildFacetteImageRing(): void;
249
+ /** Re-applies the border-arc shape dev controls (corner radius, bevel
250
+ * intensity) by rebuilding the segments — they are built once at init, so
251
+ * a plain redraw would not pick the new values up. */
252
+ rebuildBorderSegments(): void;
253
+ setChildrenEnabled(isEnabled: boolean): void;
254
+ /**
255
+ * Dev-only helper: vide la pile d'actions et la remplit avec des actions
256
+ * choisies au hasard parmi les enfants visibles, en réutilisant le pipeline
257
+ * normal de validation (`validateActionSelection`) afin d'exercer le même
258
+ * calcul de projection ghost que dans l'usage réel. Sert à tester
259
+ * rapidement l'affichage des yin-yang ghost sans clics manuels répétés.
260
+ */
261
+ debugFillActionStackWithRandomActions(count?: number): void;
262
+ /**
263
+ * Immediately starts hiding children animation without waiting.
264
+ * Called at the moment of component selection to start hide animation early.
265
+ */
266
+ animateChildrenHide(): void;
267
+ beginBlockingAnimation(label: string): symbol;
268
+ endBlockingAnimation(token: symbol): void;
269
+ hasActiveBlockingAnimation(): boolean;
270
+ /**
271
+ * Re-syncs the ghost visual state (tension + display) with the current
272
+ * mode/animation gate. Safe to call unconditionally — internally a no-op
273
+ * when ghost display isn't currently allowed (see ViewInitializer.isGhostDisplayAllowed).
274
+ * Called on STACK/RECHERCHE tab switches and whenever a blocking animation
275
+ * (rotation, facette/ODD switch, ...) starts or stops.
276
+ */
277
+ refreshGhostVisualState(): void;
278
+ prepareForComponentSwitch(targetComponentId: string): void;
279
+ handleComponentSwitchChildren(): void;
280
+ private refreshChildrenForComponentSwitch;
281
+ private restoreIncomingForceFieldContext;
282
+ /**
283
+ * Recomputes the incoming force-field view for `currentComponentId` based on
284
+ * the subset of source actions provided by `items`, using the source links saved
285
+ * when the user originally switched away from the source component.
286
+ * Returns true if matching cross-component links were found and the view was
287
+ * updated; returns false if no links target the current component (caller should
288
+ * fall back to switching to the source component instead).
289
+ */
290
+ private recomputeIncomingForceFieldForItems;
291
+ private reactivatePersistentAction;
292
+ private setChildrenHiddenState;
293
+ private attachChildToggleHandler;
294
+ /**
295
+ * @param forceOpen Skips the toggle-to-close branch below. Used by "navigate to"
296
+ * callers (search/history replay) where the intent is always to land on this
297
+ * satellite in its open state, never to close it — unlike a real diagram click,
298
+ * which should toggle. Without this, replaying a history entry for a satellite
299
+ * whose menu is still flagged active (e.g. after browsing away from it via a
300
+ * card-link in cumulative mode, which doesn't change activeChildKey) closes it
301
+ * instead of restoring it.
302
+ */
303
+ private openActionMenuFromChild;
304
+ /**
305
+ * Focus a cutting's child spike by oddId + cuttingIndex (0-based).
306
+ * Equivalent to clicking the corresponding spike on the diagram.
307
+ * Called both directly (same component) and after a component switch
308
+ * (via pendingComponentSwitchContext.type === "searchFocus").
309
+ */
310
+ private focusChildByOddCutting;
311
+ private focusChildByOddCuttingAndAction;
312
+ /** Mirrors the ODD state update performed by a diagram cutting click. */
313
+ private applyOddStateForCutting;
314
+ /** Shared deselect: clears the active action while keeping the action menu open,
315
+ * then highlights the parent ODD and syncs the Recherche tree to ODD level. */
316
+ private _deactivateActionKeepMenu;
317
+ private applyOddHighlight;
318
+ private applyEnterOddView;
319
+ searchHandleComposanteClick(componentIndex: number): void;
320
+ searchNavigateToComponent(componentIndex: number): void;
321
+ searchNavigateToOdd(componentIndex: number, oddId: string): void;
322
+ /** Mirrors a RECHERCHE legend chip's open/closed state onto its arc in the
323
+ * diagram — no-op if that chip's facette isn't the one currently shown. */
324
+ searchActivateOdd(componentIndex: number, oddId: string, isOpen: boolean): void;
325
+ searchHandleOddArcClick(componentIndex: number, oddId: string): void;
326
+ searchHighlightOdd(componentIndex: number, oddId: string): void;
327
+ searchPreviewHover(target: {
328
+ type: string;
329
+ componentIndex: number;
330
+ oddId?: string;
331
+ cuttingIndex?: number;
332
+ actionId?: string;
333
+ } | null): void;
334
+ /** Référence au nœud SVG du satellite mis en évidence depuis le hover du panneau force field. */
335
+ private _ffHoverChildNode;
336
+ searchHandleCuttingClick(componentIndex: number, oddId: string, cuttingIndex: number): void;
337
+ searchNavigateToCutting(componentIndex: number, oddId: string, cuttingIndex: number, forceOpen?: boolean): void;
338
+ searchNavigateToAction(componentIndex: number, oddId: string, cuttingIndex: number, actionId: string): void;
339
+ restoreActionDiagramState(componentIndex: number, oddId: string, cuttingIndex: number, actionId: string): void;
340
+ activateForceFieldMultiSource(sources: Array<{
341
+ oddId: string;
342
+ cuttingIndex: number;
343
+ }>): void;
344
+ startSearchActionDrag(componentIndex: number, oddId: string, cuttingIndex: number, actionId: string, label: string, startEvent: PointerEvent, sourceEl: Element, onDragIntentDetected?: () => void): void;
345
+ startSearchKeyEventDrag(componentIndex: number, keyEventId: string, label: string, startEvent: PointerEvent, sourceEl: Element, onDragIntentDetected?: () => void): void;
346
+ private navigateToSource;
347
+ private navigateToPrereqAction;
348
+ private navigateToCutting;
349
+ private buildProjectionActionsFromStackItems;
350
+ private buildForceFieldSourceIndicesFromStackItems;
351
+ private applyProjectedGhostFromStackItems;
352
+ private onStackItemVisibilityToggle;
353
+ private activateActionFromChild;
354
+ private syncGhostTensionFromAction;
355
+ private attachChildHoverHandler;
356
+ /**
357
+ * Enters ODD view for the given ODD id.
358
+ * Called when the user clicks on an already-highlighted arc.
359
+ */
360
+ enterOddView(oddId: string): void;
361
+ /**
362
+ * Cancels any ODD highlight without changing view mode.
363
+ * Called when the user clicks outside arcs/children.
364
+ */
365
+ cancelOddHighlight(): void;
366
+ isChildrenEnabled(): boolean;
367
+ isActionActive(): boolean;
368
+ /**
369
+ * Attaches a click handler on the SVG container to cancel ODD highlight
370
+ * when clicking outside arcs and children.
371
+ */
372
+ private attachBackgroundClickHandler;
373
+ /**
374
+ * Exits ODD view and returns to component view.
375
+ */
376
+ exitOddView(): void;
377
+ showOddInfo(oddId: string): void;
378
+ showComposanteInfo(): void;
379
+ private setActiveChild;
380
+ private clearActiveChild;
381
+ private animateChildren;
382
+ private clearChildren;
383
+ setChildrenOrbitEnabled(isEnabled: boolean): void;
384
+ setChildrenOrbitDuration(_durationMs: number): void;
385
+ setChildrenOrbitSpeed(speed: number): void;
386
+ setChildrenOrbitRadiusScale(scale: number): void;
387
+ setRandomForceFieldCount(count: number): void;
388
+ setActionDeltaLabelsVisible(isVisible: boolean): void;
389
+ setChildrenContextLabelsVisible(isVisible: boolean): void;
390
+ setComboUncappedChainedPerformance(isEnabled: boolean): void;
391
+ setComboDangerousCanBecomeBonus(isEnabled: boolean): void;
392
+ /**
393
+ * Réévalue les combos affectés par un changement de réglage "Combos"
394
+ * (voir state.combos) et rafraîchit les aperçus qui en dépendent : les
395
+ * items déjà validés dans la pile (via onStackItemVisibilityToggle, qui
396
+ * réécrit item.comboResults/effectiveDelta puis re-render la carte
397
+ * focalisée) et, à défaut, l'action en simple aperçu (pas encore ajoutée
398
+ * à la pile — computeComboResultsForAction n'a pas de cache à invalider
399
+ * dans ce cas).
400
+ */
401
+ private recomputeActiveComboDisplays;
402
+ setLabelsFontScale(scale: number): void;
403
+ setLabelsTextShadowEnabled(isEnabled: boolean): void;
404
+ setChildLabelPlacement(position: "top" | "bottom"): void;
405
+ setActionStackLabelFontScale(scale: number): void;
406
+ setActionStackHistoryButtonScale(scale: number): void;
407
+ setComponentLabelFontScale(scale: number): void;
408
+ setChildStateDeltaFontScale(scale: number): void;
409
+ setChildStateDeltaOffset(offset: number): void;
410
+ setChildStateDeltaBoxScale(scale: number): void;
411
+ setOddLabelFontScale(scale: number): void;
412
+ setFacetteLabelFontScale(scale: number): void;
413
+ setFacetteLabelSuffixVisible(isVisible: boolean): void;
414
+ setComponentLegendLabelFontScale(scale: number): void;
415
+ setLegendLabelsBgEnabled(enabled: boolean): void;
416
+ setDisplayEllipsisForShortLabels(enabled: boolean): void;
417
+ /** Wire from main.ts so rule-tag clicks with absent actions open the search tab. */
418
+ setOpenSearchWithQuery(cb: (query: string) => void): void;
419
+ private _onDiagramActionDragIntentCb?;
420
+ /** Déclenché une fois, au franchissement du seuil de glisser d'une bulle
421
+ * d'action satellite (voir la dépendance startActionDrag câblée au
422
+ * constructeur de ChildActionMenuController) — DiagramPanelBridge s'en
423
+ * sert pour basculer sur l'onglet STACK, comme pour le glisser RECHERCHE. */
424
+ setOnDiagramActionDragIntent(cb: () => void): void;
425
+ private _onActiveChildChange?;
426
+ setOnActiveChildChange(cb: () => void): void;
427
+ private _onOuterSparkAutoToggle?;
428
+ /** Notified whenever the Sphère/Facette status auto-toggles the perimeter
429
+ * spark, so the "Étincelle périmètre" checkbox can mirror it. */
430
+ setOnOuterSparkAutoToggle(cb: (enabled: boolean) => void): void;
431
+ /** Turns the perimeter spark off. Called on every real Idle/Facette state
432
+ * transition (app boot, a facette getting activated, or one being
433
+ * deselected) — the spark is never turned on automatically any more.
434
+ * Deselecting a facette returns to Idle exactly like a fresh load, not to
435
+ * some separate "spark sweeping" status: nothing about deselecting
436
+ * logically implies "start sweeping." The only ways to turn the spark on
437
+ * are the manual "Étincelle périmètre" checkbox and the dev "Étincelle"
438
+ * button (see triggerOuterSparkDev). */
439
+ private disableOuterSpark;
440
+ /** Called once at startup to apply the true Idle state: no facette active
441
+ * (already the case — border segments are created with no active index)
442
+ * and no spark sweeping either — nothing has happened yet. */
443
+ initIdleDefault(): void;
444
+ /** Immediately cancels the perimeter spark. Called at the very start of
445
+ * any *real* facette activation (never the spark's own pseudo-activation
446
+ * as it sweeps across a border arc — see ViewInitializer.animateToComponent's
447
+ * notifyChildren flag). Must run synchronously before the switch animation
448
+ * starts, not only once it finalizes: otherwise a spark sweep still running
449
+ * during those ~800ms can cross another arc, overwrite the shared
450
+ * currentAnimation slot with its own pseudo-switch, and silently swallow
451
+ * the real switch's finalization (which is what used to turn the spark off). */
452
+ cancelOuterSparkForActivation(): void;
453
+ /** Dev-only: toggles the perimeter spark sweep from the "Étincelle"
454
+ * button — a second click restores whatever it was before the first
455
+ * (off, in every normal case, since the spark otherwise never turns on
456
+ * by itself). The spark stays purely opt-in — this button and the
457
+ * "Étincelle périmètre" checkbox are the only ways to start it. */
458
+ triggerOuterSparkDev(): void;
459
+ /** Dev-only: (re)lance l'étincelle d'équilibre sur la facette active.
460
+ * L'orientation passée est celle de la facette, c'est-à-dire son lobe
461
+ * dominant (getRadiiForScore le dessine à 0.5 + score/2, donc toujours
462
+ * le plus grand des deux) : c'est la seule qui satisfasse le contrat de
463
+ * triggerBalanceSpark, qui calibre la croissance de queue et le taux de
464
+ * combustion partagé sur l'étincelle primaire. Elle était codée en dur
465
+ * sur "yang", ce qui inversait les rôles sur une facette yin-dominante
466
+ * — la survivante se faisait alors tuer par la limite de durée de vie à
467
+ * l'instant même où sa jumelle s'éteignait, sans pondre un seul têtard.
468
+ * Contrairement à l'étincelle du périmètre, c'est une animation
469
+ * ponctuelle (elle s'arrête d'elle-même une fois le sous-cercle
470
+ * parcouru à moitié) : chaque clic la relance depuis le début plutôt
471
+ * que de la toggle. `onComplete`, transmis tel quel à triggerBalanceSpark,
472
+ * permet à l'appelant (le bouton dev, une fois basculé en mode actif) de
473
+ * la relancer en boucle sans dupliquer sa logique de durée. */
474
+ triggerBalanceSparkDev(onComplete?: () => void): void;
475
+ /** Satellite dont le menu d'action est ouvert, sinon (repli) le satellite
476
+ * "sélectionné en lecture seule" — même surbrillance que la bordure du
477
+ * diagramme (selectedSourceFocus / lien force-field sélectionné, voir
478
+ * renderChildScoresDeltas). Sert notamment à resynchroniser le chip
479
+ * d'en-tête STACK sur le satellite courant, y compris quand celui-ci a été
480
+ * choisi via l'arbre RECHERCHE plutôt qu'en ouvrant son menu d'action. */
481
+ getActiveChildMeta(): {
482
+ oddId: string;
483
+ cuttingIndex: number;
484
+ componentId: string;
485
+ } | null;
486
+ private getSelectedCuttingMeta;
487
+ /**
488
+ * Called when the hierarchy (RECHERCHE tree or STACK overlay) collapses/deselects a cutting.
489
+ * Closes the satellite's radial action menu in the diagram without firing onDiagramNavChangeCb
490
+ * (to avoid a recursive sync loop).
491
+ */
492
+ deactivateChildMenuFromHierarchy(): void;
493
+ /**
494
+ * Fermeture du menu radial d'un satellite et de l'action qu'il projetait
495
+ * (champ de force, ghosts, bloc d'action du panneau) — chemin unique partagé
496
+ * par la hiérarchie (deactivateChildMenuFromHierarchy) et par l'exclusivité
497
+ * action/événement (toggleCoreEventMenu, previewKeyEvent). No-op si aucun
498
+ * satellite n'est actif.
499
+ */
500
+ private closeChildActionMenu;
501
+ deactivateComposanteFromHierarchy(): void;
502
+ /**
503
+ * Fermeture de la facette courante — chemin unique partagé par l'arc de
504
+ * bordure du diagramme (toggleComposanteChildrenFromDiagram) et par les
505
+ * hiérarchies RECHERCHE / STACK (deactivateComposanteFromHierarchy).
506
+ * Referme le menu radial, purge l'état d'action projetée (champ de force,
507
+ * ghosts, bloc d'action du panneau) puis masque les satellites : on retombe
508
+ * en mode Sphère, quel que soit le point d'entrée.
509
+ */
510
+ private closeCurrentComposante;
511
+ /**
512
+ * Called when switching FROM STACK → RECHERCHE tab.
513
+ * Stops the STACK force field animation and clears mode-specific state so
514
+ * STACK's multi-source force fields don't bleed into RECHERCHE mode.
515
+ */
516
+ clearForceFieldForModeSwitch(): void;
517
+ /**
518
+ * Called when switching FROM RECHERCHE → STACK tab.
519
+ * Clears any RECHERCHE-preview force field still active in state/diagram,
520
+ * then re-renders the combined force fields of STACK's own active items
521
+ * (no-op visually if the stack is empty).
522
+ */
523
+ syncForceFieldToStackMode(): void;
524
+ /**
525
+ * Recalcule le Champ d'événement pour le mode courant — à appeler APRÈS que
526
+ * l'onglet a réellement basculé (les gardes RECHERCHE/STACK, elles, tournent
527
+ * en phase de capture, avant le toggle de `ff-tab-active`, et liraient donc
528
+ * encore l'ancien mode via isStackModeActive).
529
+ *
530
+ * RECHERCHE → STACK : fait apparaître le souffle des Événements Clés cochés
531
+ * de la pile. STACK → RECHERCHE : le fait disparaître, faute d'aperçu actif.
532
+ */
533
+ syncEventFieldToCurrentMode(): void;
534
+ /**
535
+ * Deselecting a satellite (diagram toggle-close or hierarchy collapse) tears
536
+ * down clearProjectedActionState's shared hasActiveChildAction flag, which
537
+ * doubles as "STACK's checked items have a force field to show". In STACK
538
+ * mode with items still checked, that field must survive the deselect — so
539
+ * rebuild it from the stack, mirroring the RECHERCHE→STACK tab-switch sync
540
+ * in syncForceFieldToStackMode. No-op in RECHERCHE mode or an empty stack.
541
+ */
542
+ private reassertStackForceFieldAfterDeselect;
543
+ setOnLocateStackItemInSearch(cb: (componentId: string, oddId: string, cuttingIndex: number, actionId: string, kind: "action" | "keyEvent") => void): void;
544
+ /**
545
+ * Clic sur le libellé d'un item de la pile : sélectionne automatiquement
546
+ * son satellite porteur (action) ou sa Facette d'origine (Événement Clé)
547
+ * dans le diagramme, en restant en mode STACK (pendant "sans changement
548
+ * d'onglet" de setOnLocateStackItemInSearch).
549
+ */
550
+ setOnSelectStackItemSatellite(cb: (componentId: string, oddId: string, cuttingIndex: number, stackItemId: string) => void): void;
551
+ /** Centre automatiquement (scroll animé) le bloc "Effets cumulés" correspondant
552
+ * à cet item de pile, dès qu'il apparaît dans le panneau — voir
553
+ * ForceFieldDetailsPanel.requestScrollToStackItemBlock. */
554
+ requestScrollToStackItemBlock(stackItemId: string): void;
555
+ /**
556
+ * Wire from main.ts — injecte le bloc d'impact d'action directe dans l'onglet Recherche
557
+ * plutôt que dans l'onglet Analyse.
558
+ */
559
+ setOnDirectActionBlock(show: (compId: string, oddId: string, cutIdx: number, actionId: string, cardsHtml: string, attachHandlers: (container: HTMLElement) => void) => void, clear: () => void): void;
560
+ /** Wire from main.ts — injecte la carte descriptive d'un Événement Clé dans l'onglet Recherche. */
561
+ setOnShowKeyEventBlock(show: (compId: string, keyEventId: string, cardsHtml: string, attachHandlers: (container: HTMLElement) => void) => void, clear: () => void): void;
562
+ /** Enregistre le miroir "menu cœur déployé ?" vers la hiérarchie RECHERCHE. */
563
+ setOnKeyEventMenuStateChange(cb: (componentIndex: number, open: boolean) => void): void;
564
+ /** Wire from main.ts — affiche le bloc d'action directe d'un prérequis dans le panneau B. */
565
+ setOnDirectActionBlockPanelB(show: (compId: string, oddId: string, cutIdx: number, actionId: string, cardsHtml: string, attachHandlers: (container: HTMLElement) => void) => void): void;
566
+ /**
567
+ * Construit le bloc d'action directe pour un emplacement connu (compId/oddId/cutIdx/actionId)
568
+ * sans naviguer le diagramme, et fire le callback avec (compId, oddId, cutIdx, actionId, html, attachHandlers).
569
+ * Utilisé par les panneaux contextuels pour afficher le bloc d'une action cliquée dans leur arbre.
570
+ */
571
+ /**
572
+ * Déclenche l'affichage du bloc de propagation dans un panneau contextuel lorsque
573
+ * l'utilisateur clique sur un cutting dans l'arbre de ce panneau.
574
+ * Retourne true si le cutting est effectivement impacté par l'action active (bloc affiché),
575
+ * false sinon (aucun changement).
576
+ */
577
+ showPropagationForContextCutting(componentId: string, oddId: string, cuttingIndex: number): boolean;
578
+ buildDirectActionBlockForContext(compId: string, oddId: string, cutIdx: number, actionId: string, onReady: (compId: string, oddId: string, cutIdx: number, actionId: string, html: string, attachHandlers: (container: HTMLElement) => void) => void): void;
579
+ /**
580
+ * Wire from main.ts — injecte le bloc d'action propagée dans l'onglet Recherche
581
+ * lorsque l'utilisateur clique sur un cutting cible dans l'arbre ou le diagramme.
582
+ */
583
+ setOnPropagationBlock(show: (compId: string, oddId: string, cutIdx: number, html: string, attachHandlers: (container: HTMLElement) => void, sourceDesc: {
584
+ breadcrumb: string;
585
+ title: string;
586
+ description: string;
587
+ }, rationale?: string) => void, clear: () => void): void;
588
+ /** Wire from main.ts — notifie le chip STACK du badge + nom affiché par les
589
+ * cartes d'info minimales Sphère/ODD (voir ForceFieldDetailsPanel.setOnHeaderUpdate). */
590
+ setOnHeaderUpdate(cb: (badge: {
591
+ label: string;
592
+ cssClass: string;
593
+ } | undefined, name: string | undefined) => void): void;
594
+ /** Fired unconditionally at the end of onCuttingLabelClick (both the cumulative and
595
+ * the normal branch), regardless of which internal path handled the click, so that
596
+ * DiagramPanelBridge can keep the STACK hierarchy (chip + history) in sync even when
597
+ * the cumulative view intercepts the click before renderForceFieldDetails /
598
+ * _onShowPropagationBlock is reached. Signature mirrors setOnPropagationBlock's
599
+ * (compId, oddId, cuttingIndex) shape so the same STACK-sync handler can be reused. */
600
+ private _onCuttingNavigated?;
601
+ setOnCuttingNavigated(cb: (compId: string, oddId: string, cuttingIndex: number) => void): void;
602
+ private notifyCuttingNavigated;
603
+ private onDiagramOddChangeCb?;
604
+ /** Wire from main.ts to sync the search panel when the user clicks an ODD arc. */
605
+ setOnDiagramOddChange(cb: (componentIndex: number, oddId: string, mode: "highlight") => void): void;
606
+ private onDiagramNavChangeCb?;
607
+ /** Wire from main.ts to sync the search panel on composante / cutting / action clicks. */
608
+ setOnDiagramNavChange(cb: (event: DiagramNavEvent) => void): void;
609
+ /** Fired when the user re-clicks the active satellite in the diagram (toggle-to-close),
610
+ * or when an ODD-level interaction deselects it — componentIndex lets the listener
611
+ * restore its detail panel to the facette view rather than clearing it entirely. */
612
+ private _onDiagramSatelliteDeselect?;
613
+ setOnDiagramSatelliteDeselect(cb: (componentIndex: number) => void): void;
614
+ /** Fired when the user clicks the current composante's border arc to hide its satellites. */
615
+ private _onDiagramComposanteDeselect?;
616
+ setOnDiagramComposanteDeselect(cb: () => void): void;
617
+ /** Callback vers le panneau Recherche quand la souris entre/sort d'un satellite dans le diagramme. */
618
+ private _onDiagramChildHoverCb;
619
+ setOnDiagramChildHover(cb: (componentIndex: number | null, oddId: string | null, cuttingIndex?: number) => void): void;
620
+ /** Callback vers le panneau Recherche quand la souris entre/sort d'un arc de bordure (composante). */
621
+ private _onDiagramComposanteHoverCb;
622
+ setOnDiagramComposanteHover(cb: (componentIndex: number | null) => void): void;
623
+ /** Callback vers le panneau Recherche quand la souris entre/sort d'un cercle d'action dans le menu radial. */
624
+ private _onDiagramActionHoverCb;
625
+ setOnDiagramActionHover(cb: (componentIndex: number | null, oddId: string | null, cuttingIndex: number | null, actionId: string | null) => void): void;
626
+ /** Callback externe (panneau RECHERCHE) quand la souris entre/sort d'un arc ODD dans le diagramme. */
627
+ private _onDiagramOddArcHoverCb;
628
+ setOnDiagramOddArcHover(cb: (oddId: string | null) => void): void;
629
+ /** Called by BorderDrawer when the user clicks a composante border arc. */
630
+ onDiagramComposanteClicked(componentIndex: number): void;
631
+ /** Toggle satellite (cutting circle) visibility for the current composante from the diagram. */
632
+ toggleComposanteChildrenFromDiagram(componentIndex: number): void;
633
+ /**
634
+ * A satellite drill-down and facette-level ODD browsing are mutually
635
+ * exclusive: deselect any active satellite before an ODD arc interaction
636
+ * proceeds, so the panel falls back to a view that actually contains the
637
+ * clicked ODD's legend chip (renderCuttingInfo/an active action only show
638
+ * a single ODD, or none — toggleOddLegendChipById would otherwise silently
639
+ * no-op). Mirrors the toggle-close branch of openActionMenuFromChild, plus
640
+ * an explicit renderComposanteInfo (clearProjectedActionState alone falls
641
+ * back to the Sphère card, not the Facette one).
642
+ */
643
+ private deselectActiveChildForOddInteraction;
644
+ /**
645
+ * Called by YinYangDrawer when the user clicks an ODD arc. Mirrors a click
646
+ * on that ODD's legend chip in the panel: toggles its description open/
647
+ * closed under whatever is already displayed (sphère/facette/satellite),
648
+ * mirrors the resulting open/closed state onto the global circle's own arc
649
+ * (never a satellite's own arc style, which stays owned entirely by
650
+ * satellite-click interactions — see the isChild guard in YinYangDrawer),
651
+ * and highlights (as a whole, not via their own arc) the satellites that
652
+ * belong to this ODD. Also deselects any satellite whose action menu was
653
+ * open, since browsing the facette-level ODD legend and drilling into a
654
+ * satellite are mutually exclusive.
655
+ */
656
+ onDiagramOddArcClicked(oddId: string): void;
657
+ setOddContextLabelsVisible(isVisible: boolean): void;
658
+ setAllLabelsVisible(isVisible: boolean): void;
659
+ setOddLabelsCompact(compact: boolean): void;
660
+ setChildActionMenuItemDistance(distance: number): void;
661
+ setChildActionMenuItemScale(scale: number): void;
662
+ setChildActionIconFontScale(scale: number): void;
663
+ setCoreEventMenuDistanceOffset(offset: number): void;
664
+ setCoreEventMenuItemScale(scale: number): void;
665
+ setCoreEventIconFontScale(scale: number): void;
666
+ setChildLabelMaxLines(lines: number): void;
667
+ setLabelShortMaxChars(chars: number): void;
668
+ setOddLabelMaxLines(lines: number): void;
669
+ private startChildrenOrbit;
670
+ private stopChildrenOrbit;
671
+ private buildChildrenOrbitData;
672
+ private applyChildrenOrbitTransforms;
673
+ private clearForceFieldVisualState;
674
+ private clearForceFieldVisualOnly;
675
+ private renderOppositeChildrenForceField;
676
+ private clearGhostDetails;
677
+ private renderGhostDetailsForActiveAction;
678
+ clearForceFieldDetails(): void;
679
+ private renderActionPropagationTable;
680
+ /**
681
+ * Calcule les ComboResult pour une action donnée.
682
+ * Priorité : résultats pré-calculés du stack item → évaluation à la volée.
683
+ * Utilisé par le panneau principal et tous les panneaux contextuels.
684
+ */
685
+ private _computeComboResultsForAction;
686
+ private renderSourceActionDetailsForCurrentSource;
687
+ private _mergeAllComponentLinkDetails;
688
+ /**
689
+ * For each cross-component inter row in the source's allLinkDetails, compute the
690
+ * cascade intra rows that would appear in the target component's ODD.
691
+ * These rows live in the target controller's state (only populated after the user
692
+ * switches to that component), so we recompute them eagerly here, mirroring the
693
+ * logic of restoreIncomingForceFieldContext exactly.
694
+ *
695
+ * Three sub-cases, matching restoreIncomingForceFieldContext:
696
+ * A) intraEdges.length === 0 → distributeToAllChildren (equal split)
697
+ * B) targetedCutting undefined → global mode: each flat intra edge gets the full budget
698
+ * C) targetedCutting set → targeted DFS with cascading budget from entry node
699
+ * C') entry node not found → distributeToAllChildren fallback (non-bridge only)
700
+ */
701
+ private _computeCrossComponentCascadeRows;
702
+ private renderForceFieldDetails;
703
+ private flashChildCuttings;
704
+ /** Anime un point rouge vif traversant `waypoints` en séquence segment par
705
+ * segment. `onWaypointArrival` est appelé à chaque arrivée (sauf la source).
706
+ * `onSegmentStart` est appelé au début de chaque segment (utile pour pulser
707
+ * le lien force-field correspondant). */
708
+ private _animatePropagationArc;
709
+ private getCurrentComponent;
710
+ private getCurrentComponentOrUndefined;
711
+ private getCurrentComponentTitle;
712
+ /** Second (et, le cas échéant, troisième) niveau du titre : libellé + couleur
713
+ * ODD du satellite actif sous la facette courante (menu ouvert, ou
714
+ * sélection en lecture seule — voir getActiveChildMeta), avec le libellé
715
+ * de son action active le cas échéant. Un Événement Clé actif (frère du
716
+ * Satellite, jamais les deux à la fois côté menu — voir activeKeyEventId)
717
+ * prend la priorité et occupe cette même ligne, sans action associée
718
+ * (targetedActionIds sont des renvois, pas une Action propre). Null hors
719
+ * facette / sans satellite ni Événement Clé actif. */
720
+ private getCurrentSatelliteTitle;
721
+ /** Troisième niveau du titre : libellé de l'action actuellement active,
722
+ * seulement si elle appartient bien au satellite affiché (oddId,
723
+ * cuttingIndex) — actionSourceChildKey peut différer du satellite affiché
724
+ * quand l'utilisateur navigue vers un autre satellite en lecture seule
725
+ * (recherche/STACK) pendant qu'une action reste techniquement active sur
726
+ * le précédent (voir le commentaire sur actionSourceChildKey). Sans ce
727
+ * contrôle, le titre affichait le libellé de l'ancienne action sous le
728
+ * nouveau satellite. */
729
+ private getCurrentActionTitle;
730
+ /** Refreshes just the top-left title's satellite line against the current
731
+ * state — cheap, idempotent DOM diffing — from every code path that can
732
+ * change which satellite is active (menu open/close, force-field link
733
+ * click, hierarchy/search navigation, cumulative view). */
734
+ private refreshComponentTitle;
735
+ /** Cross-fades the top-left component-title label to `componentIndex`'s
736
+ * name immediately, without waiting for the full updateContextLabels()
737
+ * pass (orbit data, legend, etc.) that only runs once the diagram's
738
+ * component-switch animation completes. A facette switch always starts
739
+ * with no active satellite (createYinYangChildren() resets it), so the
740
+ * satellite line is cleared here rather than read from state mid-switch. */
741
+ private updateComponentTitleLabelImmediate;
742
+ private updateContextLabels;
743
+ private renderChildScoresDeltas;
744
+ /** Re-syncs the weightDelta ghost/wave/pulse against the current
745
+ * ViewInitializer settings (basePulseEnabled, ghostPulseDurationSec,
746
+ * pulseMorphRatio) without waiting for the next natural preview change.
747
+ * Needed because toggling "Pulsation rayons activée" only calls
748
+ * redrawBothGhosts() (VizControlsPanel), which refreshes the facette's own
749
+ * score ghost but has no reason to know about the weightDelta preview. */
750
+ refreshWeightPreviewPulse(): void;
751
+ /** Draws the weightDelta ghost + traveling wave for every satellite
752
+ * targeted by a currently-previewed action — see
753
+ * ActionStackManager.getWeightDeltaByChildKey. The satellite's own circle
754
+ * never resizes, same as the facette ghost never resizes the real
755
+ * yin-yang circle; WeightPreviewRingRenderer resyncs every child each
756
+ * call (no delta = no ghost/wave), same "recompute the full desired
757
+ * state" pattern as highlightOddInChildren. */
758
+ private applyWeightPreview;
759
+ private clearChildActionMenu;
760
+ private clearProjectedActionState;
761
+ private applyEmptyGhostProjectionState;
762
+ private updateChildActionMenu;
763
+ /**
764
+ * Appelé par YinYangDrawer quand le petit cercle "œil" du lobe dominant
765
+ * (yin ou yang, selon Composante.orientation) est cliqué — jamais l'autre
766
+ * lobe, jamais un satellite (garde déjà appliquée côté YinYangDrawer, même
767
+ * principe que onDiagramOddArcClicked pour les arcs ODD). Ouvre/ferme le
768
+ * menu radial des Événements Clés de la facette active.
769
+ */
770
+ onCoreEventNucleusClicked(): void;
771
+ private notifyKeyEventMenuState;
772
+ private toggleCoreEventMenu;
773
+ /**
774
+ * Fermeture du Champ d'événement : l'Événement Clé en aperçu et les bulles
775
+ * du menu cœur — chemin unique partagé par la fermeture de facette
776
+ * (closeCurrentComposante) et par l'exclusivité action/événement
777
+ * (openActionMenuFromChild). No-op si rien n'est ouvert.
778
+ *
779
+ * hide() d'abord pour la rétraction immédiate du souffle (le geste
780
+ * d'ouverture joué à l'envers — cf. prepareForComponentSwitch),
781
+ * updateCoreEventMenu() ensuite pour replier les bulles et laisser
782
+ * refreshTargets constater qu'il n'y a plus rien à dessiner. La carte du
783
+ * panneau RECHERCHE part avec : elle décrit l'Événement Clé qu'on vient de
784
+ * retirer du diagramme, et rien ne garantit qu'un autre bloc prenne sa
785
+ * place (ouvrir un satellite n'affiche qu'un descriptif, pas un bloc).
786
+ */
787
+ private closeKeyEventField;
788
+ private updateCoreEventMenu;
789
+ /**
790
+ * Événements Clés qui pilotent le Champ d'événement en ce moment — source
791
+ * unique de vérité pour EventFieldLifecycleController (cibles) comme pour
792
+ * getEventFieldSource (point d'émission).
793
+ *
794
+ * Deux régimes, mêmes règles de priorité que le champ de force d'action :
795
+ * un APERÇU (clic sur une bulle du menu cœur ou sur l'entrée de l'arbre
796
+ * RECHERCHE) prend toujours la main — c'est le geste que l'utilisateur
797
+ * vient de faire, quel que soit l'onglet ; sinon, en mode STACK, ce sont
798
+ * les Événements Clés COCHÉS de la pile qui décident, exactement comme les
799
+ * actions cochées y décident des champs de force. En mode RECHERCHE sans
800
+ * aperçu, rien : la pile n'a pas voix au chapitre.
801
+ *
802
+ * Le renderer n'a qu'une source (le souffle part d'UN point, voir
803
+ * EventFieldRenderer), donc on ne renvoie jamais qu'un jeu d'événements
804
+ * partageant la même : ceux nés de la facette courante partent tous de son
805
+ * cœur et se cumulent ; à défaut, on retombe sur le plus récent des
806
+ * événements distants qui atteignent cette facette (mode entrant, source =
807
+ * l'arc de sa facette d'origine).
808
+ */
809
+ private getEventFieldKeyEvents;
810
+ /**
811
+ * Point d'émission du Champ d'événement : le CŒUR du yin/yang, c'est-à-dire
812
+ * le disque central du lobe correspondant à l'orientation de la facette
813
+ * courante — le cœur noir du yang sur une facette Yang, le cœur blanc du
814
+ * yin sur une facette Yin. Ce n'est PAS le centre géométrique du symbole :
815
+ * les deux lobes ont des rayons qui varient avec le score, donc le cœur se
816
+ * déplace le long de l'axe vertical au fil de la partie, d'où la
817
+ * relecture de la géométrie à chaque frame. Injecté dans
818
+ * EventFieldLifecycleController (getEventFieldSource), rappelé à chaque
819
+ * frame de son animation.
820
+ *
821
+ * `geometry.yin/yang.centerY` est la position CANONIQUE (pré-rotation) :
822
+ * pendant une rotation Yin/Yang (AnimationsMngr), le cœur visible se
823
+ * déplace via un `transform` écrit à même `graphElementGroup` à chaque
824
+ * frame, sans jamais toucher `geometry`. On lit donc la position réelle
825
+ * via getLiveLobeCoreCenter plutôt que la géométrie statique, pour que les
826
+ * anneaux du champ d'événement suivent le cœur qui tourne au lieu de
827
+ * naître à une origine figée.
828
+ */
829
+ private getEventFieldSource;
830
+ /**
831
+ * Résout un point porté par `lobeGroup` (coordonnées locales, ici le
832
+ * centre canonique du cœur) dans le repère de globalGroup — celui où
833
+ * EventFieldRenderer dessine (voir EventFieldLifecycleController,
834
+ * getGlobalGroupNode). Passe par les CTM SVG plutôt que de reparser
835
+ * l'attribut `transform` (comme getChildRenderedCenter le fait pour une
836
+ * simple translation) : le transform posé sur graphElementGroup pendant
837
+ * une rotation combine rotate ET translate, et cette composition suit
838
+ * fidèlement AnimationsMngr sans dépendre de sa formule exacte — un
839
+ * changement futur de celle-ci n'a pas besoin d'être répercuté ici.
840
+ */
841
+ private getLiveLobeCoreCenter;
842
+ /**
843
+ * Rejoue l'aperçu d'un Événement Clé depuis une navigation Recherche
844
+ * (historique précédent/suivant) — pendant minimal de searchNavigateToAction,
845
+ * sans mise au point du diagramme (pas de satellite/facette à recentrer,
846
+ * l'entrée d'arbre dédiée est hors scope pour l'instant).
847
+ */
848
+ searchNavigateToKeyEvent(keyEventId: string): void;
849
+ /**
850
+ * Rétablit le Champ d'événement d'un Événement Clé DÉJÀ affiché à droite —
851
+ * pendant de restoreActionDiagramState pour les événements, utilisé au
852
+ * retour en mode RECHERCHE (voir PanelManager.resyncDiagramToMasterPanel).
853
+ *
854
+ * Volontairement plus étroit que previewKeyEvent : ni carte redessinée, ni
855
+ * notification de navigation (donc pas d'entrée d'historique en double) —
856
+ * le panneau montre déjà cet événement, c'est le diagramme qui le rattrape.
857
+ * On garde en revanche l'exclusivité action/événement : les deux champs ne
858
+ * cohabitent jamais.
859
+ *
860
+ * Si la facette courante n'est plus celle de l'événement (l'utilisateur a
861
+ * navigué ailleurs pendant le mode STACK), on revient d'abord sur sa facette
862
+ * d'origine — mêmes gestes que searchSetKeyEventMenuOpen : l'aperçu survit
863
+ * au switch (prepareForComponentSwitch le garde vivant, destination =
864
+ * origine) et le menu cœur se redéploie à l'arrivée avec sa bulle active.
865
+ */
866
+ restoreKeyEventDiagramState(keyEventId: string): void;
867
+ /**
868
+ * Dépli/repli du groupe "Événements Clés" depuis la hiérarchie RECHERCHE —
869
+ * pendant exact du clic sur le cœur du yin/yang (onCoreEventNucleusClicked),
870
+ * pour que l'arbre et le diagramme montrent le même menu déployé : ouvrir le
871
+ * groupe déploie les bulles de la facette, le refermer les rétracte (même
872
+ * règle que le dépli d'un Satellite, qui déploie ses boutons d'Action).
873
+ *
874
+ * Le repli passe par closeKeyEventField plutôt que par le toggle : il doit
875
+ * aussi emporter l'Événement Clé en aperçu (et sa carte), sinon une bulle
876
+ * validée resterait allumée sous un groupe replié.
877
+ */
878
+ searchSetKeyEventMenuOpen(componentIndex: number, open: boolean): void;
879
+ /** Ouverture idempotente du menu cœur — no-op s'il est déjà déployé (le
880
+ * toggle le refermerait). */
881
+ private openCoreEventMenu;
882
+ /** Seul point de mutation de activeKeyEventId — resynchronise la ligne
883
+ * Événement Clé du titre (voir getCurrentSatelliteTitle) à chaque
884
+ * changement, exactement comme setActiveChildKey le fait pour le
885
+ * satellite. */
886
+ private setActiveKeyEventId;
887
+ /** Aperçu — 1er clic sur un Événement Clé : affiche sa carte descriptive
888
+ * dans le panneau Recherche, ne joue rien (même principe que
889
+ * activateActionFromChild côté satellite). */
890
+ private previewKeyEvent;
891
+ /** Validation — 2e clic sur l'Événement Clé déjà en aperçu, ou glisser une
892
+ * bulle jusqu'à une position précise de la pile (voir startKeyEventDrag,
893
+ * même mécanisme que validateActionSelection côté satellite). Sans
894
+ * insertAtVisibleIndex, l'item est ajouté au sommet — le menu radial
895
+ * reste ouvert dans les deux cas, pour enchaîner d'autres choix. */
896
+ private validateKeyEventSelection;
897
+ private validateActionSelection;
898
+ private clientPointToGlobalGroup;
899
+ private renderDragGhost;
900
+ private removeDragGhost;
901
+ private onCuttingLabelClick;
902
+ private resolveActionSource;
903
+ private getActiveActionMeta;
904
+ /**
905
+ * Per active stack item sourced from the CURRENT component: its marginal
906
+ * contribution (state units, 0..100) to (oddId, cuttingId), and its own
907
+ * detailed propagation edges — both produced by the real sequential
908
+ * simulation (projectGhostStateForActionSequence), the same one that
909
+ * drives the diagram's displayed Δ.
910
+ *
911
+ * - marginalDeltaAtFocus: summing this across items equals the diagram's Δ
912
+ * exactly, by construction (telescoping sum over the fractional
913
+ * accumulator). Used as the authoritative block total.
914
+ * - detailPool: this item's OWN propagation edges (absorption/gap/cascade),
915
+ * from the exact same single-pass computation (computeActionPropagationDetails,
916
+ * via onStep) that produced marginalDeltaAtFocus — not a second, separately
917
+ * re-run propagation — against the exact rolled-forward state this item
918
+ * saw at its point in the stack, not the pristine base state. Used so the
919
+ * panel's descriptive breakdown badges match the authoritative total
920
+ * instead of an isolated estimate.
921
+ *
922
+ * Items sourced from a DIFFERENT component are absent from the map: they
923
+ * don't participate in this component's rolling simulation (their effect
924
+ * is merged separately via the cross-component bridge/incoming-links path).
925
+ * Callers must fall back to the isolated per-source estimate for those.
926
+ */
927
+ private computeSequentialStackContributionsAtFocus;
928
+ /**
929
+ * Blocs "keyEvent" pour la vue cumulative : un Événement Clé actif (coché
930
+ * dans la pile) dont la Facette d'origine (originComposanteId) correspond à
931
+ * `component` — indépendamment du satellite précis sélectionné, et même si
932
+ * aucune de ses actions ciblées n'est jouée (voir isKeyEventCurrentlyActive
933
+ * pour le seul état visuel actif/inactif). Réutilisé par
934
+ * renderCumulativeDetailsForCutting (satellite sélectionné) et par les
935
+ * appelants de renderComposanteInfo (Facette sélectionnée, aucun satellite).
936
+ */
937
+ private buildKeyEventBlocksForComponent;
938
+ private renderCumulativeDetailsForCutting;
939
+ private collectDetailRowsForSourceTarget;
940
+ private getChildRenderedCenter;
941
+ private getComponentBorderTargetPoint;
942
+ private clearForceFieldComputationState;
943
+ private removeOppositeChildrenForceField;
54
944
  /**
55
945
  * Initializes animations for this instance and sets up event listeners for clicks.
56
946
  * Rotations are reverted on click events.
57
947
  */
58
948
  InitializeAnimations(): void;
949
+ highlightOddInChildren(oddId: string | null): void;
950
+ highlightOddByStackItemId(stackItemId: string | null): void;
951
+ /**
952
+ * Retourne les actions applicables au cutting associé à `childKey`,
953
+ * en consultant `yasuniCause` via `actionMap` (lookup O(1)).
954
+ *
955
+ * Les actions adverses vivent sous le même satellite (l'invariant "une
956
+ * action vit sous un satellite" tient) mais ne sont jamais proposées au
957
+ * joueur ici : le système se chargera de les placer lui-même dans la
958
+ * pile, pas un clic sur le satellite.
959
+ */
960
+ private getActionsForChild;
961
+ /**
962
+ * Dev-only : le système place lui-même `count` items adverses — actions
963
+ * ET Événements adverses (yasuni_adverse_key_events.ts) — dans la pile
964
+ * active, piochés dans tout le catalogue (toutes les facettes, pas
965
+ * seulement celle affichée à l'écran), aux slots choisis par
966
+ * adverse-action-planner.ts (chaînes de combos complètes, ordre narratif,
967
+ * fenêtres d'effet respectées — un combo d'action adverse peut avoir un
968
+ * Événement adverse pour prérequis). Les adverses déjà présents dans la
969
+ * pile ne sont pas rejoués.
970
+ *
971
+ * Une action d'une facette non affichée n'a pas de childController vivant
972
+ * (childControllers/childOddMap ne connaissent que la facette courante,
973
+ * voir createYinYangChildren) : l'item de pile est donc construit à la
974
+ * main plutôt que via ActionStackManager.insertActionAtSlot, qui exige un
975
+ * childController réel. sourceChildKey reste au sentinel "" — le reste du
976
+ * code résout toujours l'origine d'un item via sourceComponentId /
977
+ * sourceOddId / sourceCuttingIndex, jamais via sourceChildKey une fois en
978
+ * pile (childOddMap est reconstruit avec de nouvelles clés à chaque
979
+ * changement de facette). Un Événement adverse porte les sentinelles d'un
980
+ * item keyEvent (sourceOddId "" / sourceCuttingIndex −1, voir
981
+ * validateKeyEventSelection) et sa Facette d'origine en sourceComponentId
982
+ * — indispensable au scoping Facette de son bloc dans l'ANALYSE (voir
983
+ * buildKeyEventBlocksForComponent).
984
+ */
985
+ debugInsertAdverseActions(count: number): void;
59
986
  }
987
+ export {};