@micheeeeel/yinyangapp 3.1.0 → 3.1.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.
@@ -1,6 +1,6 @@
1
1
  import type { Composante } from "../data/yasuni_cause";
2
2
  import type { Cause } from "../interfaces/ICauseModel";
3
- import { type ContactProfileData } from "../data/contacts";
3
+ import { type ContactProfileData, type ObstacleSignatureData } from "../data/contacts";
4
4
  /**
5
5
  * Adapte le catalogue Composante[] (format yasuni_cause.ts) vers le format
6
6
  * Cause attendu par mapCauseToInternalModel.
@@ -28,3 +28,14 @@ export declare function getYasuniCause(id?: string): Cause;
28
28
  * bornes (`validateContactProfile`).
29
29
  */
30
30
  export declare function contactProfileToCause(profile: ContactProfileData, id?: string): Cause;
31
+ /**
32
+ * La `Cause` d'une SIGNATURE D'OBSTACLE (OBS-UI-01) : les huit facettes
33
+ * universelles d'un contact, chacune pesant son exigence O_f, SANS SCORE
34
+ * (`scoreless`) — un obstacle n'a pas de qualité. Montée avec
35
+ * `presentation: true`, elle s'affiche en Idle « facettes » ou « tab »
36
+ * (satellites-facettes à la taille de O_f) ; `setFacetModulation` y
37
+ * superpose ensuite la lecture d'un contact. Fraîchement construite à
38
+ * chaque appel ; lève une erreur explicite pour une signature invalide
39
+ * (`validateObstacleSignature`).
40
+ */
41
+ export declare function obstacleSignatureToCause(signature: ObstacleSignatureData, id?: string): Cause;
@@ -10,6 +10,8 @@ export { mapCauseToInternalModel } from "./adapters/yinYangAdapter";
10
10
  /** Sous-état Idle du diagramme (aucune facette ouverte) — voir
11
11
  * `YinYangMountConfig.idleView`. */
12
12
  export type YinYangIdleView = "arcs" | "facettes" | "tab";
13
+ export type { FacetModulation, FacetModulationOptions, } from "./components/controller/children/facetModulation";
14
+ import type { FacetModulation, FacetModulationOptions } from "./components/controller/children/facetModulation";
13
15
  /** Données acceptées : soit une `Cause` (format métier), soit le modèle interne déjà adapté. */
14
16
  export type YinYangData = Cause | YinYangInternalModel;
15
17
  export interface YinYangSvgConfig {
@@ -46,6 +48,15 @@ export interface YinYangMountHandle {
46
48
  /** Bascule (animée) du sous-état Idle — voir `YinYangMountConfig.idleView`.
47
49
  * Facette ouverte : le choix s'applique à sa fermeture. */
48
50
  setIdleView(view: YinYangIdleView): Promise<void>;
51
+ /** Signature d'obstacle (`obstacleSignatureToCause`) : y superpose la
52
+ * lecture d'un contact, ou la retire (`null`). Pour chaque facette (id) :
53
+ * `weights` le poids modulé W_f (0–10, diamètre du satellite), `scores`
54
+ * la qualité Q_f du contact (0–100, sa chance affichée). Le diamètre
55
+ * d'origine (O_f) reste visible en fantôme ; places et échelle ne
56
+ * bougent pas. `durationMs` anime le passage (0 : immédiat),
57
+ * `ghostWaves` fait courir la vague du fantôme (à couper en mouvement
58
+ * réduit). Une facette de poids nul reste sans score. */
59
+ setFacetModulation(modulation: FacetModulation | null, options?: FacetModulationOptions): Promise<void>;
49
60
  /** Arrête toutes les boucles d'animation du diagramme (champ de force,
50
61
  * orbite, rotation, ghost, étincelles…) puis vide le conteneur. */
51
62
  destroy(): void;
@@ -73,10 +84,12 @@ export { createYinYangFilmSvg, createYinYangFilmSvgAsync } from "./api-film";
73
84
  export type { YinYangFilmConfig, YinYangFilmAsyncOptions } from "./api-film";
74
85
  export { createRandomCause } from "./api-random";
75
86
  export type { RandomCauseOptions, RandomRange } from "./api-random";
76
- export { getYasuniCause, contactProfileToCause } from "./adapters/yasuniCauseAdapter";
87
+ export { getYasuniCause, contactProfileToCause, obstacleSignatureToCause, } from "./adapters/yasuniCauseAdapter";
77
88
  export { validateContactProfile } from "./data/contacts/buildContactSphere";
78
89
  export type { ContactProfileData, ContactSatelliteValue, } from "./data/contacts/buildContactSphere";
79
90
  export { UNIVERSAL_FACETS, CONTACT_CATEGORIES } from "./data/contacts/universalFacets";
91
+ export { contactFacetReadings, obstacleFacetWeight, obstacleModulation, validateObstacleSignature, } from "./data/contacts/obstacleSignature";
92
+ export type { ContactFacetReading, ObstacleSignatureData, } from "./data/contacts/obstacleSignature";
80
93
  export type { SatelliteKey, ContactFacetId, ContactCategoryId, UniversalFacet, UniversalSatellite, ContactCategory, } from "./data/contacts/universalFacets";
81
94
  export { mountYinYangWorkspace } from "./api-workspace";
82
95
  export type { YinYangWorkspaceConfig, YinYangWorkspaceHandle, } from "./api-workspace";
@@ -6,6 +6,7 @@ import { IAnimator } from "../../interfaces/IAnimator";
6
6
  import { YinYangInternalModel } from "../../interfaces/IYinYangInternalModel";
7
7
  import { ForceFieldLinkDetail } from "./force-field/types";
8
8
  import { type IdleTabHooks } from "./children/IdleFacettesController";
9
+ import type { FacetModulation, FacetModulationOptions } from "./children/facetModulation";
9
10
  import type { IdleView } from "./state/YinYangControllerState";
10
11
  import type { DiagramNavEvent } from "./types";
11
12
  export declare class YinYangController implements IYinYangController {
@@ -88,6 +89,10 @@ export declare class YinYangController implements IYinYangController {
88
89
  /** Clic sur l'illustration centrale : facettes ↔ tab (sans effet hors Idle
89
90
  * et en « arcs »). */
90
91
  toggleIdleView(): Promise<void>;
92
+ /** Superpose (ou retire, `null`) la lecture d'un contact à une
93
+ * signature d'obstacle (OBS-UI-01) — voir
94
+ * IdleFacettesController.setModulation. */
95
+ setFacetModulation(modulation: FacetModulation | null, options?: FacetModulationOptions): Promise<void>;
91
96
  /** Vrai quand le sous-état Idle « facettes » est visé (arcs repliés). */
92
97
  isIdleFacettesActive(): boolean;
93
98
  /** Réaligne le sous-état Idle après une entrée/sortie d'Idle. */
@@ -9,6 +9,8 @@ import { StackFocusController } from "../action-stack/StackFocusController";
9
9
  import { ComponentTitlePresenter } from "../labels/ComponentTitlePresenter";
10
10
  import type { ControllerUiCallbacks } from "../state/ControllerUiCallbacks";
11
11
  import { ChildrenOrbitManager } from "../odd/ChildrenOrbitManager";
12
+ /** Écart (px, repère du motif) entre deux satellites voisins d'un anneau. */
13
+ export declare const SATELLITE_RING_GAP_PX = 6;
12
14
  export type ChildrenBuilderDeps = {
13
15
  animateChildren: (show: boolean) => Promise<void>;
14
16
  applyChildrenOrbitTransforms: (angleOffset: number, orbitData?: ChildrenOrbitEntry[]) => void;
@@ -58,28 +60,21 @@ export declare class ChildrenBuilder {
58
60
  * baseline radius, independent of any satellite's own weight-scaled
59
61
  * radius — mirrors ChildActionMenuController's action cluster geometry. */
60
62
  private getChildActionClusterReach;
61
- /** Décalage constant appliqué au poids ET à sa moyenne avant de calculer le
62
- * ratio de taille d'un satellite (voir weightToSizeRatio) : resserre la
63
- * fourchette de tailles (poids min moins minuscule, poids max un peu
64
- * moins dominant) sans changer la taille d'un satellite au poids moyen
65
- * exact (ratio toujours 1 dans ce cas), et sans dépendre du poids moyen
66
- * de la fratrie pour l'ampleur du resserrement. */
67
- private static readonly WEIGHT_SIZE_FLOOR_OFFSET;
68
- /** Ratio de taille d'un satellite (rayon relatif à la baseline uniforme de
69
- * sa facette) à partir de son poids et du poids moyen de sa fratrie —
70
- * voir WEIGHT_SIZE_FLOOR_OFFSET pour le resserrement. */
71
- static weightToSizeRatio(weight: number, averageWeight: number): number;
72
- /** Ratio of a component's heaviest satellite radius to its own uniform
73
- * baseline radius. Mirrors the per-cutting weight-based scaling applied
74
- * in createYinYangChildren(). */
75
- private getMaxWeightRatio;
76
- /** The container-fit shrink ratio only depends on borderOuterRadius/
77
- * smallCircleRadius/distanceFromChild, which are fixed for the whole
78
- * session once this top-level view is first initialized (they don't get
79
- * recomputed on facette switch) — so this is computed once (on the worst
80
- * case weight ratio across every facette) and cached. That's what keeps
81
- * the whole diagram's size from visibly changing every time the user
82
- * switches facette. */
63
+ /** Ratio de taille d'un satellite (rayon relatif à la taille de base,
64
+ * ViewInitializer.smallCircleRadius) : sur son poids ABSOLU, le même pour
65
+ * la cause et pour la sphère d'un personnage — un satellite de poids 7 a
66
+ * la même taille dans tous les diagrammes, quels que soient ses voisins.
67
+ * `(poids + 1) / (référence + 1)` : 1 au poids de référence (5), 1/6 au
68
+ * poids nul (un satellite vide reste visible), 11/6 au poids maximal. */
69
+ static weightToSizeRatio(weight: number): number;
70
+ /** Ratio de taille du satellite le plus lourd possible (poids maximal). */
71
+ static readonly MAX_SIZE_RATIO: number;
72
+ /** Réduction d'ensemble qui fait tenir l'anneau de satellites dans le
73
+ * conteneur. Elle ne dépend que de la géométrie du motif (rayon, taille
74
+ * de base, orbite), pas des données : elle réserve la place du satellite
75
+ * le plus lourd possible, si bien que le cercle central occupe la même
76
+ * part du conteneur dans tous les diagrammes, et qu'aucune évolution des
77
+ * poids en cours de partie ne fait déborder l'anneau. Calculée une fois. */
83
78
  private cachedGlobalFitShrinkRatio?;
84
79
  private computeGlobalFitShrinkRatio;
85
80
  applyChildrenFitScale(): void;
@@ -3,6 +3,7 @@ import { IYinYangController } from "../../../interfaces/IYinYangController";
3
3
  import { IYinYangAppFactory } from "../../../interfaces/IYinYangAppFactory";
4
4
  import { YinYangInternalModel } from "../../../interfaces/IYinYangInternalModel";
5
5
  import { IdleView, YinYangControllerState } from "../state/YinYangControllerState";
6
+ import { FacetModulation, FacetModulationOptions } from "./facetModulation";
6
7
  /** Crochets de l'hôte autour du sous-état « tab » — voir
7
8
  * `IYinYangController.setIdleTabHooks`. */
8
9
  export type IdleTabHooks = {
@@ -76,13 +77,31 @@ export declare class IdleFacettesController {
76
77
  private settled;
77
78
  private queue;
78
79
  private escapeListener;
80
+ /** Modulation de la signature par un contact (OBS-UI-01), voir
81
+ * setModulation ; null : chaque satellite montre son propre modèle. */
82
+ private modulation;
83
+ private modulationOptions;
84
+ /** Géométrie radiale de l'anneau, calculée à la sortie sur les poids du
85
+ * MODÈLE (O_f d'une signature) : la modulation change les tailles,
86
+ * jamais les places ni l'échelle. */
87
+ private ring;
88
+ /** Par satellite : clé de son affichage, son diamètre au poids du modèle
89
+ * et son diamètre réel (modulé). */
90
+ private displays;
91
+ /** Fantôme de signature de chaque satellite modulé (dans son enveloppe). */
92
+ private ghosts;
93
+ /** Détruit : les transitions encore en file n'ont plus rien à faire (sans
94
+ * quoi un diagramme démonté puis remonté dans le même conteneur — double
95
+ * montage d'un hôte React en développement — y recevait les satellites
96
+ * du premier, sortis après coup). */
97
+ private destroyed;
79
98
  constructor(deps: IdleFacettesControllerDeps);
80
99
  setTabHooks(hooks: IdleTabHooks | null): void;
81
100
  getView(): IdleView;
82
101
  /** Vrai dès qu'un sous-état à satellites-facettes (« facettes » ou
83
102
  * « tab ») est l'état visé en Idle (arcs repliés ou en train de l'être). */
84
103
  isActive(): boolean;
85
- setView(view: IdleView): Promise<void>;
104
+ setView(requested: IdleView): Promise<void>;
86
105
  /** Centre et rayon du satellite-facette d'une facette, une fois sorti. */
87
106
  getSatelliteAnchor(componentId: string): {
88
107
  center: {
@@ -96,6 +115,21 @@ export declare class IdleFacettesController {
96
115
  * chaque entrée/sortie d'Idle. */
97
116
  sync(): Promise<void>;
98
117
  private isIdle;
118
+ /** Vrai pour une Cause sans score (signature d'obstacle). */
119
+ private isScorelessModel;
120
+ /**
121
+ * Superpose à la signature la lecture d'un contact (OBS-UI-01) — ou la
122
+ * retire (`null`). Chaque satellite-facette concerné prend le diamètre de
123
+ * W_f et la chance Q_f, à partir de sa taille courante (animation de
124
+ * `durationMs`) ; un fantôme garde le diamètre du poids du modèle (O_f).
125
+ * Les places et l'échelle restent celles du modèle : revenir à la
126
+ * signature puis réappliquer le même contact redonne exactement le même
127
+ * dessin. Appliquée en file avec les bascules de sous-état ; hors
128
+ * « facettes »/« tab », elle est mémorisée pour la prochaine sortie.
129
+ */
130
+ setModulation(modulation: FacetModulation | null, options?: FacetModulationOptions): Promise<void>;
131
+ private applyModulation;
132
+ private displayOf;
99
133
  private wantedLayout;
100
134
  private applyDesiredState;
101
135
  /** Arcs repliés sous l'illustration, puis satellites jaillissant du centre
@@ -127,8 +161,28 @@ export declare class IdleFacettesController {
127
161
  * SVG). */
128
162
  private tabArea;
129
163
  private fadeImageRing;
164
+ /** Ratio de taille de chaque satellite-facette : sur le poids de sa
165
+ * facette (C_f), ramené à l'échelle d'un satellite [0, WEIGHT_MAX] — tel
166
+ * quel en règle `mean`, divisé par le nombre de satellites en règle `sum`
167
+ * — pour la même règle de taille que les satellites d'une Facette. */
130
168
  private computeSizeRatios;
131
169
  private createSatellites;
170
+ /** Angles et resserrement de l'anneau, sur les poids du modèle. */
171
+ private computeRing;
172
+ /** Crée le satellite-facette d'une composante, à sa place dans l'anneau,
173
+ * selon son affichage (ordinaire, signature, modulé). */
174
+ private createSatellite;
175
+ /**
176
+ * Remplace un satellite-facette par celui de son nouvel affichage, SUR
177
+ * PLACE : même enveloppe de grille, même centre. Le nouveau part de la
178
+ * taille de l'ancien et gagne la sienne (O_f → W_f, ou retour) pendant
179
+ * que l'ancien s'efface ; sans durée, d'un coup.
180
+ */
181
+ private replaceSatellite;
182
+ /** Fantôme de signature d'un satellite modulé plus petit que son poids
183
+ * de modèle : contour au diamètre de O_f, dans son enveloppe (il suit la
184
+ * grille). Retiré sinon. */
185
+ private refreshGhost;
132
186
  /** Glisse un groupe enveloppe entre le satellite et le groupe des enfants
133
187
  * du motif : il porte la transformation de la grille, sans interférer
134
188
  * avec celles que d'autres posent sur le satellite lui-même. */
@@ -0,0 +1,49 @@
1
+ import { YinYangComponentNode } from "../../../interfaces/IYinYangInternalModel";
2
+ /**
3
+ * MODULATION d'une signature par un contact (OBS-UI-01) : pour chaque
4
+ * facette (id de composante), le poids W_f que la signature prend face à ce
5
+ * contact (0–10) et la qualité Q_f du contact (0–100), sa chance de
6
+ * réussir cette facette. L'hôte fournit les valeurs : la lib ne fait que
7
+ * les montrer (diamètre sur W_f, pourcentage Q_f, fantôme sur le poids du
8
+ * modèle, O_f).
9
+ */
10
+ export type FacetModulation = {
11
+ weights: Record<string, number>;
12
+ scores: Record<string, number>;
13
+ };
14
+ export type FacetModulationOptions = {
15
+ /** Durée de l'animation des diamètres (ms) ; 0 : immédiat (défaut). */
16
+ durationMs?: number;
17
+ /** Vague entre satellite et fantôme ; à couper en mouvement réduit.
18
+ * Défaut : false. */
19
+ ghostWaves?: boolean;
20
+ };
21
+ /** Ce qu'un satellite-facette montre. */
22
+ export type FacetDisplay =
23
+ /** Ses propres score et poids (diagramme ordinaire). */
24
+ {
25
+ kind: "ordinary";
26
+ }
27
+ /** Poids seul, sans score (signature d'obstacle). */
28
+ | {
29
+ kind: "signature";
30
+ }
31
+ /** Poids modulé W_f et qualité Q_f d'un contact. */
32
+ | {
33
+ kind: "modulated";
34
+ weight: number;
35
+ quality: number;
36
+ };
37
+ /** Poids d'une facette du modèle (O_f pour une signature, C_f sinon). */
38
+ export declare function componentWeight(component: YinYangComponentNode): number;
39
+ /**
40
+ * Affichage d'une facette. Une facette sans exigence (poids nul) d'une
41
+ * signature reste sans score même modulée : W_f y est nul, elle n'entre
42
+ * dans aucun tirage — lui montrer une chance serait faux.
43
+ */
44
+ export declare function resolveFacetDisplay(component: YinYangComponentNode, scoreless: boolean, modulation: FacetModulation | null): FacetDisplay;
45
+ /** Clé d'égalité d'un affichage (un satellite inchangé n'est pas refait). */
46
+ export declare function facetDisplayKey(display: FacetDisplay): string;
47
+ /** La facette portant la qualité Q_f d'un contact : tous ses satellites
48
+ * à la même tension, si bien que sa qualité (moyenne pondérée) vaut Q_f. */
49
+ export declare function withQuality(component: YinYangComponentNode, quality: number): YinYangComponentNode;
@@ -0,0 +1,10 @@
1
+ import { IYinYangController } from "../../../interfaces/IYinYangController";
2
+ /**
3
+ * Apparence d'un satellite-facette SANS SCORE (signature d'obstacle,
4
+ * OBS-UI-01) : un disque neutre, liseré de la couleur de sa catégorie, et
5
+ * sa pastille de poids — ni lobes yin/yang ni pourcentage, puisqu'un
6
+ * obstacle n'a pas de qualité. Le marquage `data-scoreless` tait le reste
7
+ * (styles/signature.css) ; le disque est posé dans le cœur, qui porte
8
+ * aussi l'animation de sortie du satellite.
9
+ */
10
+ export declare function applyScorelessLook(satellite: IYinYangController): void;
@@ -18,6 +18,11 @@ export declare class WeightPreviewRingRenderer {
18
18
  private basePulseEnabled;
19
19
  private pulseDurationMs;
20
20
  private pulseMorphRatio;
21
+ /** Fantôme en contour seul (signature, voir renderFixed) plutôt qu'en
22
+ * lavis quand il est plus grand que le satellite. */
23
+ private outlineOnly;
24
+ /** Vague entre le satellite et son fantôme (coupée en mouvement réduit). */
25
+ private wavesEnabled;
21
26
  private getChildRenderedCenter;
22
27
  render(params: {
23
28
  orbitData: ChildrenOrbitEntry[];
@@ -41,6 +46,28 @@ export declare class WeightPreviewRingRenderer {
41
46
  pulseDurationMs: number;
42
47
  pulseMorphRatio: number;
43
48
  }): void;
49
+ /**
50
+ * Fantôme de SIGNATURE (OBS-UI-01, satellites-facettes d'une signature
51
+ * d'obstacle modulée par un contact) : le même cercle d'or et la même
52
+ * vague que l'aperçu de poids, mais sur des rayons fournis par l'appelant
53
+ * — le satellite a déjà sa taille modulée (`baseRadius`), le fantôme garde
54
+ * celle de la signature (`targetRadius`). Contour seul (une trace de
55
+ * l'exigence, pas un gain), sans pulsation du satellite : sa taille est
56
+ * celle de la modulation, l'animer la rendrait fausse. `waves: false`
57
+ * (mouvement réduit) laisse le fantôme immobile, même information.
58
+ */
59
+ renderFixed(params: {
60
+ groupNode: SVGGElement | null;
61
+ entries: Array<{
62
+ id: string;
63
+ controller: IYinYangController;
64
+ centerX: number;
65
+ centerY: number;
66
+ baseRadius: number;
67
+ targetRadius: number;
68
+ }>;
69
+ waves: boolean;
70
+ }): void;
44
71
  /** Frame d'orbite : recentre fantômes et vagues sur leur satellite (les
45
72
  * entrées sont les données liées aux cercles), sans data join. */
46
73
  followOrbit(): void;
@@ -0,0 +1,3 @@
1
+ import type { YinYangController } from "../controller/YinYangController";
2
+ /** Câble le groupe #debug-obstacle-group (affiché pour l'obstacle seul). */
3
+ export declare function mountObstacleDemoControl(controller: YinYangController): void;