# Symboles SVG portables

> Composez et partagez des symboles SVG statiques avec des liaisons Ganter sûres et des bornes de raccordement typées.

Les symboles Ganter tiennent le dessin et les données vivantes séparés. Le dessin est du SVG
ordinaire et statique. Ganter Lab possède chaque correspondance de valeur et chaque animation :
un fichier importé ne peut donc exécuter ni script, ni gestionnaire d'événement, ni code
d'animation embarqué, ni requête réseau. Cette page est la référence complète du modèle de
création : ce qu'un symbole déclare, ce que l'import accepte et refuse, et comment les symboles
voyagent d'une station à l'autre.

Un symbole déclare trois choses par-dessus son dessin :

- **Zones actives** : des entrées nommées (remplissage, contour, mouvement, texte, visibilité)
  qu'une instance posée sur un [tableau de bord](home) alimente ensuite depuis une adresse Logic
  ou une valeur fixe.
- **Bornes** : des points de raccordement typés sur le périmètre, pour que le tableau de bord
  puisse acheminer tuyaux, gaines, câbles et arbres entre symboles.
- **Propositions** : des compositions facultatives avec d'autres symboles, posées explicitement.

## Symboles système et Mes symboles {#system-symbols-and-my-symbols}

Le catalogue a deux origines, filtrables partout où des symboles sont listés :

| Origine | Référence | Ce que c'est |
| --- | --- | --- |
| Système | `system:<clé-stable>` | Les bibliothèques intégrées livrées avec l'application. Inspectables et exportables, jamais modifiables sur place. |
| Les miens | `user:<guid>` | Les symboles que vous avez créés, importés ou dupliqués. Modifiables et supprimables. |

Chaque symbole système propose **Dupliquer dans Mes symboles** : la copie est une ressource
utilisateur figée et possédée à part (dessin, zone d'affichage, ajustement, encombrement, zones
actives, configurations de type, bornes et suggestions copiés ensemble), elle continue donc de se
comporter comme au moment du choix, même quand une mise à jour ultérieure change l'original.
Supprimer un symbole utilisateur demande une confirmation ; les tableaux de bord qui le
référencent encore affichent un espace réservé au lieu de se casser.

## Les façons de créer un symbole {#ways-to-create-a-symbol}

- **Importer un fichier** : **Logic > Assets > Symbols > Importer un symbole** accepte un
  `.svg` simple ou un paquet `.ganter-symbol.json` complet. Chaque import crée une **nouvelle**
  ressource avec sa propre identité ; il n'écrase jamais un symbole existant, et une collision de
  nom se résout par un suffixe (« 2 », « 3 », etc.) plutôt que par un échec. Le sélecteur refuse
  les fichiers de plus de **1 MB** avant même de lire un octet. Après l'import d'un SVG simple,
  l'application indique combien d'éléments dangereux elle a retirés, s'il y en avait.
- **Composer dans l'application** : **Nouveau symbole utilisateur** ouvre un éditeur pour le nom,
  le balisage SVG, la disposition sur le tableau de bord (ajustement et encombrement initial) et
  les zones actives ; une fois le symbole créé, les changements valides sont enregistrés
  automatiquement. La géométrie des bornes n'est volontairement **pas** modifiable dans
  l'application : des bornes typées ne peuvent venir que d'un paquet, et les bornes définies par un
  paquet sont conservées en lecture seule à travers les modifications ultérieures.
- **Demander à une IA** : deux chemins partagent exactement le même contrat. Par l'[endpoint MCP](agent) intégré, l'outil `symbol_validate` simule l'import et
  `symbol_import` enregistre une nouvelle ressource ; tous deux portent le contrat complet dans
  leur description. Depuis une conversation externe sans accès à l'application, **Copier
  l'instruction de conversation**, dans le volet Symboles, copie une consigne autoportante ;
  enregistrez le SVG ou le paquet renvoyé comme fichier et importez-le ici.

Voir [Logic](logic) pour l'espace de travail des ressources qui l'entoure.

## Préparer un SVG simple {#prepare-a-plain-svg}

Donnez un `id` SVG stable à chaque partie que vous voulez lier. Après l'import, ces identifiants
apparaissent dans les sélecteurs de cible des zones actives. Les identifiants et les noms de zone
active partagent une grammaire : ils commencent par une lettre ou `_`, continuent par des lettres,
des chiffres, `_`, `.`, `:` ou `-`, et comptent 128 caractères au plus.

Les attributs facultatifs `data-ganter-*` sont le seul balisage propre à Ganter qu'un symbole peut
porter :

| Attribut | Sur | Ce qu'il déclare |
| --- | --- | --- |
| `data-ganter-pivot="x y"` | tout élément liable | Le point de pivot exact (en coordonnées de la zone d'affichage) pour les zones actives de rotation, d'échelle et de rotation continue. Obligatoire sur l'élément visé par ces trois natures. |
| `data-ganter-spin-ratio` | un enfant d'un élément en rotation continue | La vitesse relative d'un rotor enfant visible. Finie, non nulle, d'une valeur absolue de 100 au plus ; une valeur négative tourne dans l'autre sens. Retiré si l'élément ne déclare pas aussi son propre pivot. |
| `data-ganter-role` | tout élément | Un rôle sémantique stable pour les outils de création. Purement informatif. |
| `data-ganter-fit-width` | `<text>` / `<tspan>` | Affichage borné, sur demande, pour une zone active de texte : quand le texte lié mesure plus que ce nombre d'unités de la zone d'affichage, la police rétrécit pour tenir. |
| `data-ganter-fit-min-font-size` | `<text>` / `<tspan>` | La plus petite taille de police jusqu'à laquelle l'ajustement peut rétrécir. En deçà, l'élément affiche le texte de repli tandis que la valeur entière reste dans le nom accessible et dans l'infobulle. |
| `data-ganter-fit-fallback` | `<text>` / `<tspan>` | Le texte affiché quand même la taille de police minimale ne permet pas d'afficher la valeur. |

Les bornes de raccordement ne vivent pas dans le SVG et ne visent pas des identifiants d'élément
SVG. Les attributs nommés `data-ganter-port` ou `data-ganter-port-*` ne font pas partie du format :
un import de SVG simple les retire ; un paquet strict qui en contient est rejeté.

L'import d'un SVG simple donne toujours un symbole **purement visuel** valide : zéro borne, zéro
zone active. L'inspecteur signale qu'aucune borne raccordable n'existe, parce que le rôle, le type,
la direction extérieure et le chemin interne n'ont pas été déclarés. Ganter ne déduit pas ces
champs du nom de fichier, de la catégorie ni du dessin, et n'ouvre aucun éditeur interne de bornes
ni de chemins.

## Ce que l'assainissement accepte {#what-the-sanitizer-accepts}

La même politique SVG s'applique à tous les chemins d'entrée (import de fichier, éditeur intégré,
MCP, paquet). Elle est délibérément plus étroite que SVG :

- **Gardé** : la géométrie et la structure inertes, soit `svg`, `g`, `defs`, `symbol`, `use`,
  `path`, `rect`, `circle`, `ellipse`, `line`, `polyline`, `polygon`, `text`, `tspan`, `title`,
  `desc`, `clipPath`, `mask`, `linearGradient`, `radialGradient`, `stop`, `pattern`, `marker`,
  avec les attributs de présentation (remplissage, contour, opacité, transformation, style) et les
  libellés ARIA.
- **Retiré ou refusé** : `<script>`, `<style>`, `<foreignObject>`, les gestionnaires d'événements,
  l'animation embarquée, et toute URL externe ou en `data:`/`file:`/`http(s)`. Seules les
  références internes `url(#id)` et `href="#id"` survivent.
- **Limites** : le balisage compte **512 KB** et **4096 éléments** au plus.

Les peintures sûres sont les couleurs hexadécimales, les couleurs nommées de CSS,
`rgb()`/`rgba()`/`hsl()`/`hsla()`, et les jetons de thème de l'application `var(--color-<nom>)`
(par exemple `var(--color-success)`, `var(--color-symbol-off)`). Les jetons de thème sont ce qui
permet à un seul dessin de s'adapter au clair et au sombre : livrez un dessin qui référence des
jetons, jamais deux variantes de thème.

Le traitement d'une violation dépend du chemin d'entrée : un **SVG simple** est réparé (les
éléments dangereux sont retirés et chaque retrait est signalé par un avertissement) ; un **paquet**
est strict et se voit rejeté, les premières violations nommées, au lieu d'être réparé en silence.

## Paquet portable v2 {#portable-package-v2}

Exporter un symbole crée un fichier `.ganter-symbol.json`. Chaque champ de l'enveloppe est
obligatoire ; les trois tableaux du contrat peuvent être vides mais doivent être présents :

| Champ | Exigence |
| --- | --- |
| `$schema` | Exactement `https://ganterlab.com/schemas/ganter-symbol-v2.schema.json`. |
| `format` | Exactement `ganter-symbol`. |
| `version` | Exactement `2`. Les paquets en version 1 sont rejetés au lieu de passer par un lecteur d'ancien format. |
| `name` | Le nom affiché. Un import peut le remplacer, et une collision reçoit automatiquement un suffixe. |
| `svg` | Du SVG statique assaini, dont l'élément racine porte un `viewBox` égal au champ `viewBox`. |
| `viewBox` | `minX minY width height` : quatre nombres finis, largeur et hauteur positives. |
| `fit` | `contain`, `stretch`, `stretch-x` ou `stretch-y`. |
| `footprint` | `{ "width": 1..24, "height": 1..12 }`, les cellules conseillées sur le tableau de bord. |
| `slots` | Tableau des déclarations de zone active (ci-dessous). |
| `typeConfigurations` | Tableau des choix de type partagés entre bornes (ci-dessous). |
| `terminals` | Tableau de 16 bornes complètes au plus (ci-dessous). |
| `suggestions` | Tableau des compositions ordonnées (ci-dessous). |

Le [schéma JSON public Ganter symbol v2](/schemas/ganter-symbol-v2.schema.json) valide l'enveloppe
de transport. L'importeur effectue ensuite les contrôles sémantiques que JSON Schema ne peut pas
exprimer : l'existence des cibles SVG, la géométrie des chemins internes, la compatibilité des
suggestions. Un paquet est strict dans toutes les dimensions : le balisage dangereux, les champs
inconnus, les entrées nulles dans un tableau et les anciens contrats `ports[]`, `anchors[]`,
`profile` et `connectionStyle` sont rejetés au lieu d'être réparés.

Le paquet ne contient jamais d'adresse de station, de liaison de tableau de bord, de choix de type
par instance, de GUID de base de données ni d'identité d'utilisateur. Une zone active qui porte une
adresse Logic ne peut même pas être exportée : l'adresse appartient à l'instance posée, pas au
symbole réutilisable.

## Taille, zone d'affichage et ajustement {#size-view-box-and-fit}

La **zone d'affichage** (`viewBox`) est l'espace de coordonnées naturel du symbole. Les bornes et
les chemins internes y sont déclarés, et elle doit correspondre exactement au `viewBox` de la
racine du SVG ; un paquet dont les deux zones d'affichage divergent est rejeté. Les zones
d'affichage non carrées sont pleinement prises en charge : un long convoyeur n'a donc pas à tenir
dans un carré.

Le **mode d'ajustement** dit comment le dessin occupe le rectangle que l'opérateur dessine sur le
tableau de bord :

| Ajustement | Comportement |
| --- | --- |
| `contain` | Conserve les proportions ; le dessin s'insère avec des marges dans le rectangle de la cellule. C'est la valeur par défaut. |
| `stretch` | Remplit le rectangle sur les deux axes, quitte à déformer. |
| `stretch-x` | Étire horizontalement, garde la proportion verticale naturelle. |
| `stretch-y` | Étire verticalement, garde la proportion horizontale naturelle. |

L'**encombrement** est la taille initiale, en cellules de la grille du tableau de bord, au moment
où le symbole est posé pour la première fois : largeur de 1 à 24, hauteur de 1 à 12 (l'éditeur
propose 4 × 4 par défaut). C'est une suggestion, pas une contrainte ; l'opérateur redimensionne
librement ensuite.

Deux barrières distinctes bornent la taille d'un import : le sélecteur de fichier refuse tout ce
qui dépasse **1 MB** avant de le lire, et l'assainissement refuse un balisage de plus de **512 KB**
ou de plus de **4096 éléments**.

## Zones actives : la surface de liaison {#slots--the-binding-surface}

Une zone active déclare une entrée : quel élément elle pilote, ce qu'elle lui fait, et comment les
valeurs d'entrée se transforment en sortie. L'instance posée sur un tableau de bord choisit ensuite
la source de chaque zone active (une adresse Logic ou une valeur fixe) ; le symbole lui-même ne
conserve jamais de source.

Chaque zone active porte :

| Champ | Signification |
| --- | --- |
| `name` | Le nom de paramètre montré à l'auteur du tableau de bord. Grammaire d'identifiant ci-dessus ; unique parmi les zones actives du symbole. |
| `elementId` | L'`id` d'un élément SVG existant. Un élément accepte au plus une zone active par canal : deux zones actives ne peuvent donc pas se disputer le remplissage du même élément. |
| `kind` | L'une des treize natures ci-dessous. |
| `inMin`, `inMax` | La plage d'entrée : les deux valeurs mises en correspondance avec `outMin`/`outMax`. Nombres finis ; utilisés par les natures continues et comme milieu de seuil par `fill` et `stroke`. |
| `outMin`, `outMax` | La plage de sortie dans l'unité de la nature (degrés, unités de la zone d'affichage, 0..1, degrés par seconde). Nombres finis. |
| `outMinSecondary`, `outMaxSecondary` | Second axe de sortie facultatif, pour `translate` et `scale` seulement : la sortie principale est X et la secondaire est Y. Fournissez les deux ou aucune. |
| `onColor`, `offColor` | Peintures sûres pour `fill` et `stroke` (les deux états du seuil). Pour `fillColor` et `strokeColor`, `onColor` est la couleur d'aperçu de l'inspecteur. |

Les treize natures de zone active :

| Nature | Ce qu'elle pilote | Remarques |
| --- | --- | --- |
| `rotate` | Fait tourner l'élément ; l'entrée est mise en correspondance linéaire avec des degrés. | La cible doit déclarer `data-ganter-pivot`. |
| `opacity` | L'opacité de l'élément ; l'entrée est mise en correspondance avec 0..1. | |
| `fill` | Peint le remplissage avec `offColor` sous le milieu de la plage d'entrée et avec `onColor` à partir de ce milieu. Une entrée booléenne bascule directement. | Vise les formes qui se remplissent (pas `<line>`). |
| `visible` | Affiche ou masque l'élément selon la véracité de la valeur. | |
| `text` | Remplace le contenu textuel de l'élément par la valeur mise en forme. | Vise `<text>` et `<tspan>` seulement ; à combiner avec les attributs `data-ganter-fit-*` pour un affichage borné. |
| `translate` | Déplace l'élément en unités de la zone d'affichage ; la sortie principale est X, la secondaire facultative est Y. | |
| `scale` | Met l'élément à l'échelle ; la sortie principale est X, la secondaire est Y (omise = échelle uniforme). | La cible doit déclarer `data-ganter-pivot`. |
| `stroke` | Peint le contour selon la même règle de seuil que `fill`. | |
| `spin` | Rotation continue dans le temps ; l'entrée est mise en correspondance avec une vitesse angulaire en degrés par seconde. Les enfants portant `data-ganter-spin-ratio` tournent avec lui au rapport déclaré. | La cible doit déclarer `data-ganter-pivot`. Le mouvement est cadencé par l'hôte et indépendant des préférences d'animation du système d'exploitation. |
| `spinEnabled` | Met en pause ou reprend la zone active `spin` du même élément sans le masquer. | Exige une zone active `spin` visant le même élément. |
| `fillColor` | Règle le remplissage directement depuis la valeur de couleur liée (une ressource Couleur, une variable Couleur ou une couleur CSS sûre). | |
| `strokeColor` | Règle le contour directement depuis la valeur de couleur liée. | |
| `strokeWidth` | Règle la largeur du contour directement, en unités utilisateur SVG de **0.5 à 32** ; ni suffixe d'unité, ni CSS. | Une entrée invalide, non résolue ou de mauvaise qualité rétablit le `stroke-width` d'origine ; la réinitialisation, le remontage et la destruction aussi. |

Ces zones actives habillent le dessin ; elles n'habillent jamais les cheminements de raccordement
du tableau de bord, dont la couleur et la largeur sont globales par type de tracé.

## À qui appartient la liaison {#binding-ownership}

Le symbole déclare des paramètres et des choix de type permis, non des sources vivantes ni la
sélection d'une instance. Après avoir posé un composant Symbol, l'opérateur associe chaque zone
active à une adresse Logic ou à une valeur fixe, et choisit chaque type de tracé configurable sur
cette instance. Ces choix restent dans la station et ne sont jamais exportés avec le symbole
réutilisable. Une zone active non associée reste neutre : l'élément garde l'apparence qui lui a été
donnée.

## Positions globales et types de tracé {#global-positions-and-connection-types}

Chaque borne référence une position du catalogue fixe de seize ancrages du périmètre. Un paquet ne
conserve que l'`anchorId` ; il ne répète et ne remplace jamais des coordonnées. Les positions, en
fractions normalisées de la zone d'affichage :

- en haut : `top-left` (0, 0), `top-25` (0.25, 0), `top-50` (0.5, 0), `top-75` (0.75, 0),
  `top-right` (1, 0) ;
- à droite : `right-25` (1, 0.25), `right-50` (1, 0.5), `right-75` (1, 0.75) ;
- en bas, dans le sens horaire : `bottom-right` (1, 1), `bottom-75` (0.75, 1),
  `bottom-50` (0.5, 1), `bottom-25` (0.25, 1), `bottom-left` (0, 1) ;
- à gauche, toujours dans le sens horaire : `left-75` (0, 0.75), `left-50` (0, 0.5),
  `left-25` (0, 0.25).

Ce sont des positions de périmètre, pas une grille 5 × 5. Un symbole ne peut ni ajouter une autre
position, ni conserver ses propres coordonnées d'ancrage.

Les huit types de tracé globaux sont `liquid`, `gas`, `air-duct`, `electrical`, `signal`,
`network`, `material` et `mechanical-shaft`. Utilisez **Logic > Assets > Connection types** pour
configurer la couleur et l'épaisseur de trait associées à chaque type. Les symboles et les tracés
conservent l'identifiant stable du type : un changement global restyle donc chaque cheminement qui
l'utilise. Un paquet ne copie jamais la couleur ni la largeur, et n'a pas de variantes de
cheminement petites, standard ou grandes.

Deux extrémités forment un tracé défini quand elles se résolvent vers le même type. Le rôle de la
borne aide à la création et à la relecture, mais n'interdit pas à lui seul un arrangement de
réseau.

## Choix de type partagés {#shared-type-choices}

Un symbole qui peut travailler avec plus d'un fluide déclare une configuration de type partagée
plutôt que de dupliquer son dessin :

```json
{
  "id": "process-type",
  "name": "Process type",
  "allowedTypes": ["liquid", "gas"],
  "defaultType": "liquid"
}
```

L'`id` est une clé stable : des lettres minuscules et des chiffres séparés par des tirets simples,
commençant et finissant par un caractère alphanumérique (les majuscules sont refusées).
`allowedTypes` n'est pas vide et contient des identifiants de type globaux uniques ; `defaultType`
doit lui appartenir ; `name` est obligatoire. Chaque borne qui référence `process-type` suit un
choix unique fait sur l'instance posée sur le tableau de bord. Une définition peut porter plusieurs
configurations indépendantes, par exemple le fluide de procédé et le fluide d'évent, pendant que
d'autres bornes restent fixes.

## Bornes complètes {#complete-terminals}

Chaque borne raccordable déclare une position globale, un rôle, exactement un type fixe **ou** une
configuration partagée, une direction vers l'extérieur dans l'orientation d'origine, et un chemin
d'arrivée interne :

```json
{
  "anchorId": "left-50",
  "role": "input",
  "typeConfiguration": "process-type",
  "direction": "west",
  "internalPath": [
    { "x": 18, "y": 50 },
    { "x": 36, "y": 50 },
    { "x": 48, "y": 62 }
  ]
}
```

Les règles, toutes vérifiées à l'import :

- **16** bornes au plus, et chaque identifiant d'ancrage utilisé une seule fois.
- `role` vaut `input`, `output` ou `bidirectional` ; `direction` vaut `north`, `east`, `south` ou
  `west`.
- Exactement l'un de `type` (un type de tracé global) ou de `typeConfiguration` (l'identifiant
  d'une configuration déclarée) : jamais les deux, jamais aucun.
- L'ancrage global converti dans la zone d'affichage naturelle du SVG est le départ implicite de
  `internalPath` ; ne le répétez pas comme premier point. Les coordonnées sont des valeurs absolues
  de la zone d'affichage, non des fractions normalisées, et le chemin compte au moins un point.
- Chaque segment reste à l'intérieur de la zone d'affichage, a une longueur non nulle, et est
  horizontal, vertical ou exactement à 45° ; deux segments consécutifs tournent de 90° au plus.
- Les bornes exigent que le SVG porte une zone d'affichage.

Le tableau de bord dessine le chemin interne sous le dessin de l'équipement, le transforme lors
d'un redimensionnement, d'un quart de tour et des symétries, et conserve la largeur visuelle du
type de tracé global au lieu de la mettre à l'échelle avec le symbole : un seul trait continu court
donc de l'intérieur d'un corps à l'intérieur de l'autre.

Une borne est tout ou rien. Un paquet strict comportant une borne partielle est invalide ; un
paquet purement visuel utilise plutôt un tableau `terminals` vide. Rien n'est jamais déduit pour
combler un trou.

## Suggestions ordonnées {#ordered-suggestions}

Une suggestion enregistre une composition intentionnelle, pose exacte de la cible comprise :

```json
{
  "sourceAnchorId": "right-75",
  "targetSymbol": "system:capping-station",
  "targetAnchorId": "left-75",
  "targetRotationDegrees": 0,
  "targetFlipHorizontal": false,
  "targetFlipVertical": false,
  "connectionType": "material"
}
```

Validation : `sourceAnchorId` doit être l'une des bornes de ce symbole ; `targetSymbol` doit être
une référence qualifiée par son origine, et dans un paquet portable elle ne peut être que
`system:<clé-stable>` (un GUID d'utilisateur n'a de sens que dans la station qui le possède)
nommant un symbole présent dans le catalogue système avec une borne à `targetAnchorId` ; la
rotation vaut `0`, `90`, `180` ou `270` et les deux indicateurs de symétrie sont obligatoires ;
chaque suggestion doit être unique. `connectionType` ne peut être omis que si les types fixes
égaux des deux extrémités lèvent l'ambiguïté ; il est obligatoire dès qu'une extrémité est
configurable, et il doit alors être permis des deux côtés.

Les suggestions sont orientées et l'ordre du tableau fixe la priorité, mais elles ne sont jamais
une liste d'autorisation pour les tracés ordinaires du tableau de bord. Avec un tableau
`suggestions` vide, l'inspecteur signale qu'aucune composition suggérée n'existe, au lieu
d'inventer un partenaire de catalogue.

## Ce que l'import refuse {#what-the-import-refuses}

Une liste rapide des refus, pour qu'un import raté se lise au lieu de se deviner. Pour un SVG
simple, seul le premier groupe s'applique, et à l'intérieur de celui-ci seules les limites de
taille, un XML mal formé et une racine `<svg>` absente font refuser l'import : le balisage
interdit est réparé avec un avertissement. Pour un paquet, tout ce qui suit est un rejet ferme.

**Dessin**

- Un fichier de plus de 1 MB, un balisage de plus de 512 KB, ou plus de 4096 éléments.
- Un XML mal formé, ou une racine qui n'est pas un `<svg>` assaini.
- Dans un paquet : tout balisage que la liste d'autorisation aurait dû retirer (scripts,
  gestionnaires d'événements, références externes, éléments ou attributs interdits).
- Un `viewBox` qui n'est pas quatre nombres finis avec une largeur et une hauteur positives, ou qui
  diffère de celui de la racine du SVG ; un paquet sans aucune zone d'affichage à la racine.

**Enveloppe**

- Un schéma, un format ou une version autres que ceux du contrat v2 ; des champs inconnus n'importe
  où ; un `name`, un `fit`, un `footprint` ou l'un des trois tableaux manquants ; une entrée nulle
  dans un tableau.
- Un `fit` hors des quatre modes ; un encombrement hors de 1 à 24 par 1 à 12.

**Zones actives**

- Un nom ou un identifiant d'élément hors de la grammaire d'identifiant ; un nom de zone active en
  double ; un identifiant de cible que le SVG ne contient pas ; une nature que l'élément visé ne
  peut pas prendre (du texte sur un élément qui n'est pas du texte, un remplissage sur un `<line>`).
- Une zone active `rotate`, `spin` ou `scale` dont la cible n'a pas de `data-ganter-pivot` fini ;
  une zone active `spinEnabled` sans zone active `spin` sur le même élément.
- Deux zones actives sur le même canal d'un même élément. Chaque nature est son propre canal, sauf
  que `fill` et `fillColor` partagent le canal du remplissage et que `stroke` et `strokeColor`
  partagent celui du contour : un élément ne peut pas plus prendre deux rotations que deux
  remplissages.
- Des nombres de plage non finis ; une sortie secondaire n'ayant qu'une seule borne, ou portée par
  une nature autre que `translate` et `scale` ; une peinture dangereuse ; une zone active qui porte
  une adresse Logic.

**Tracés**

- Plus de 16 bornes ; un identifiant d'ancrage répété ou inconnu ; une borne portant à la fois ou
  ni l'un ni l'autre de `type` et `typeConfiguration` ; un identifiant de type ou de configuration
  inconnu ; un chemin interne invalide (hors de la zone d'affichage, segments de longueur nulle ou
  d'angle interdit, virage de plus de 90°).
- Une configuration de type dont l'identifiant est invalide, dont le nom manque, dont les types
  permis sont en double ou inconnus, ou dont la valeur par défaut est hors de sa propre liste.
- Une suggestion dont la borne source n'existe pas, dont la cible n'est pas un symbole système
  portant la borne nommée, dont la pose n'est pas un quart de tour, ou dont le type de tracé n'est
  pas accepté des deux côtés.

`symbol_validate`, sur l'[endpoint MCP](agent), exécute exactement cet import comme
une simulation et signale chaque erreur, avertissement et remarque sans rien enregistrer.

## Empaqueter et partager {#packaging-and-sharing}

**Exporter le paquet** (disponible aussi bien pour les symboles système que pour les vôtres)
télécharge `<nom>.ganter-symbol.json` avec le dessin assaini et le contrat complet : `$schema`,
`format`, `version`, `name`, `svg`, `viewBox`, `fit`, `footprint`, `slots[]`,
`typeConfigurations[]`, `terminals[]` et `suggestions[]`, les trois tableaux de raccordement
présents même quand ils sont vides. Ce qui ne voyage jamais : les adresses de station, les choix de
type par instance, l'identité en base de données, l'identité de l'utilisateur, et les couleurs et
largeurs de type de tracé de la station.

Sur la station qui reçoit, le même fichier passe par **Importer un symbole** (ou par
`symbol_import` sur MCP) et arrive comme un nouveau symbole utilisateur, bornes comprises. Comme
l'identité d'un type est un identifiant stable et que l'apparence est globale, les cheminements
d'un symbole importé suivent immédiatement le style des types de tracé de la station qui le reçoit.
