RepSMILES — Wiederholungs-Notation
Für längere wiederkehrende Strukturen (Polyole, Alkylketten,
einfache Oligomere) akzeptiert data-molecule eine
schlanke Erweiterung von SMILES, lose inspiriert von
BigSMILES
und Generative BigSMILES.
Vor der Übergabe an RDKit wird das Pattern einmalig zu reinem
SMILES expandiert; alle nachgelagerten Features (3D, Surface,
Deskriptoren, PNG-Export, Clipboard) funktionieren dadurch
unverändert. Es gibt keine Stochastik und keine Bonding-Descriptors —
nur deterministische Wiederholung.
Syntax
| Pattern |
Bedeutung |
{[$N]UNIT[$]} |
UNIT wird N-mal wiederholt und konkateniert. N ist eine Ganzzahl von 0 bis 1000. |
{[$N]UNIT} |
Schließendes [$] ist optional und kann der Lesbarkeit halber weggelassen werden. |
{[$N1]…{[$N2]…[$]}…[$]} |
Verschachtelung erlaubt — innerstes Vorkommen wird zuerst expandiert. |
Beispiele
| Pattern |
Expandiert |
Hinweis |
OC{[$10]C[$]}CO |
OCCCCCCCCCCCCO |
Dodecan-1,12-diol |
CC{[$5]C(C)[$]}CCC |
CCC(C)C(C)C(C)C(C)C(C)CCC |
Verzweigte Alkylkette |
{[$3]O{[$2]CC[$]}[$]} |
OCCCCOCCCCOCCCC |
Verschachtelt: innen 2× CC, außen 3× OCCCC |
{[$8]CC(=O)O[$]} |
CC(=O)OCC(=O)O… |
Polyester-artiges Oligomer (8 Einheiten) |
Limits
Zum Schutz vor versehentlichen Speicher-Explosionen gelten harte
Grenzen: maximal 1000 Wiederholungen pro Block,
maximal 5000 Zeichen Endlänge, maximal
100 Iterationen. Bei Überschreitung wird eine
Fehlermeldung im Viewer angezeigt.
Anzeige & Export
Wird ein Pattern verwendet, zeigt das Zahnrad-Menü unten einen
Info-Block mit dem Original-Pattern und dem expandierten SMILES
zum Vergleich (jeweils als selektierbares Eingabefeld mit
Kopier-Button daneben). copySMILES() kopiert den
expandierten String in die Zwischenablage. Der PNG-Export-Filename
basiert ebenfalls auf dem expandierten SMILES (gekappt auf
200 Zeichen).
Wann nicht verwenden
Für echte Polymere mit Repeat-Unit-Listen, Bonding-Descriptors
($/</>),
Endgruppen-Logik oder Verteilungen ist diese Notation bewusst
zu schmal — dafür empfehlen sich dedizierte BigSMILES-Parser
(z. B. py-bigsmiles).
Die hier eingebaute Variante ist ein Mini-Pre-Processor für
deterministische Wiederholungen, nicht mehr.
Controller & Agents — synchronisierte Viewer
Mehrere Viewer können aneinandergekoppelt werden, sodass sie immer
dieselben Einstellungen, dieselbe Darstellung und dieselbe Kamera
zeigen — sehr praktisch für Side-by-Side-Vergleiche von Stereoisomeren
oder Tautomeren, oder für Lehr-Layouts mit einer Master-Ansicht plus
mehreren Detailansichten.
Ein Viewer wird zum Controller, sobald ein anderer
Viewer ihn über data-controller-id referenziert. Der
Controller selbst trägt einfach ein eindeutiges
data-id. Agents sind die abhängigen
Viewer — sie zeigen weder Zahnrad- noch Maximieren-Button, ihre
Einstellungen kommen vom Controller. Beim Init scannt die Library alle
Viewer in zwei Durchgängen: erst werden alle Instanzen erzeugt, dann
werden Agents an ihren Controller verlinkt — die Reihenfolge im HTML
ist also egal.
HTML-Beispiel: gemeinsames Molekül
<!-- Controller: bekommt eine ID, alle Optionen wie gewohnt -->
<div data-id="master"
data-molecule="CN1C=NC2=C1C(=O)N(C(=O)N2C)C"
data-typ="stick"
data-3d="true"
data-rotate="0.4"
data-controls="true"
></div>
<!-- Agent ohne data-molecule: übernimmt SMILES vom Controller -->
<div data-controller-id="master"
data-bg="#1a1a2e"
data-tooltip="true"
></div>
<div data-controller-id="master"
data-bg="#0a3a1a"
></div>
HTML-Beispiel: Stereoisomer-Vergleich
Setzt ein Agent ein eigenes data-molecule, ist
dieser SMILES gelockt: setMolecule-Sync
vom Controller wird für ihn ignoriert. Style, Farbschema, Oberfläche,
3D-Modus und Kamera bleiben aber synchron — perfekt für direkte
Gegenüberstellungen.
<!-- Controller zeigt das achirale Stammmolekül -->
<div data-id="butanol"
data-molecule="CCCCO"
data-3d="true"
data-controls="true"
></div>
<!-- Agent A: (R)-Enantiomer — eigenes data-molecule "lockt" den SMILES -->
<div data-controller-id="butanol"
data-molecule="C[C@@H](O)CC"
></div>
<!-- Agent B: (S)-Enantiomer -->
<div data-controller-id="butanol"
data-molecule="C[C@H](O)CC"
></div>
Was wird synchronisiert?
Synchron gehalten wird der gesamte Modell-State:
Darstellungsstil, Farbschema, Oberfläche, 3D-Modus, H-Sichtbarkeit,
Auto-Rotation (Richtung & Geschwindigkeit) — und der Kamera-View
(Position, Drehung, Zoom). Der SMILES selbst wird nur dann mitgezogen,
wenn der Agent kein eigenes data-molecule hat.
Auch ein reset() auf dem Controller wirkt auf alle Agents
— und zwar zurück auf die Controller-Defaults, da Agents beim
Verlinken die _initialDefaults vom Controller mitbekommen
(der eigene _ownSmiles bleibt erhalten).
Nicht synchronisiert werden Container-Eigenschaften:
data-bg (Hintergrundfarbe) und data-tooltip
bleiben pro Viewer individuell — ein Agent ist ja eine eigenständige
Anzeige, nur die Darstellung und Kamera werden gespiegelt.
Kamera-Sync in Echtzeit
Sobald ein Controller existiert, läuft im Hintergrund ein
requestAnimationFrame-Loop: pro Frame wird
viewer.getView() ausgelesen, und sobald sich der View
gegenüber dem letzten Frame geändert hat, per setView()
in alle Agents kopiert (mit anschließendem Re-Render). Damit landen
alle Manipulationen auf dem Controller automatisch bei den
Agents:
- Linksklick + Drag → Drehung
- Mausrad → Zoom
- Rechtsklick + Drag (oder Mittelklick) → Verschieben
- Touch-Pinch / Touch-Drag
- Auto-Rotate via
data-rotate oder setRotation()
Der Loop ist günstig: kein Aufwand, wenn keine Agents existieren oder
der View sich nicht geändert hat (Array-Vergleich mit Float-Toleranz).
Wenn der Agent ein anderes Molekül anzeigt (Stereoisomer-Setup), wird
derselbe Kamera-View aufgesetzt — bei chemisch ähnlichen Molekülen
(gleiches Grundgerüst) sieht das visuell perfekt synchron aus.
API-Aufrufe auf Controller und Agents
Aufrufe wie MolViewer.setStyle('master', 'polar') oder
controllerInst.setRotation(0.5) wirken auf den Controller
und werden automatisch an alle Agents weitergereicht — egal ob die
Aufrufe von einem User-Klick im Zahnrad-Menü oder direkt aus der API
kommen. setMolecule wird auf Agents mit
_ownSmiles übersprungen.
Auch ein direkter Aufruf auf einer Agent-Instanz ist technisch
erlaubt — er wird aber beim nächsten Controller-Update wieder
überschrieben. Die Empfehlung ist also: nur den Controller ansprechen
(über seine data-id) und die Agents als read-only-Spiegel
betrachten.
Eine Ausnahme gibt es: das manuelle Drehen mit der Maus
stoppt nur die Auto-Rotation des betreffenden Viewers. Beim Controller
wird der Rotations-Stopp an die Agents propagiert, beim Agent bleibt
der Stopp lokal. Der reine Kamera-View wird trotzdem in beide
Richtungen NICHT zurückgespiegelt — Agent → Controller gibt es nicht,
der Datenfluss bleibt einseitig.
Geteilter 3D-Cache
Bei data-3d="true" wird der PubChem-SDF-Roundtrip nur
einmal gemacht — vom Controller. Alle Agents mit demselben
SMILES teilen sich dasselbe Promise und bekommen die SDF-Daten direkt
geliefert. Bei drei Viewern mit demselben Molekül sind das also zwei
statt drei Netzwerkfetches eingespart. Agents mit eigenem (anderen)
SMILES (Stereoisomer-Setup) holen ihr SDF natürlich separat.
Edge Cases
Verweist ein Agent auf eine ID, die kein registrierter
Controller ist (Tippfehler, vergessenes data-id), wird
eine Warnung in die Konsole geloggt und der Agent läuft im
Standalone-Modus: er nutzt seine eigenen
data-*-Attribute (insbesondere data-molecule,
falls gesetzt). Ein Agent kann nicht selbst Controller eines
weiteren Agents sein — die Kette bleibt einstufig (Controller → Agent),
keine Verschachtelung.