Write a plugin for Dentra Viewer
Ein Plugin bringt neue Funktionen in den Viewer. Du schreibst es, wir testen es, und wenn es uns gefällt, finden es alle im Bereich «Plugins».
Einführung
Plugins schreibt die Community: für alle, die den Viewer anpassen oder um Funktionen erweitern wollen. Wir liefern die Umgebung und diese Dokumentation.
Ein Plugin ist eine kleine Webseite (HTML, JavaScript und CSS), die der Viewer in einem eigenen Rahmen öffnet. Aus dem Rahmen spricht das Plugin mit dem Viewer über das Kit DentraViewer, das schon geladen ist.
Das Plugin läuft in einem geschlossenen Rahmen: Es sieht weder die Seite noch das Konto noch die Daten von Dentra. Es kann nur tun, was es in seinen Berechtigungen verlangt, und der Zahnarzt liest sie, bevor er es einschaltet.
Was du bauen kannst
- Neue Steuerungen für die Ansicht: Handgesten vor der Webcam, Gamecontroller, Sprachbefehle.
- Messungen und Notizen: Klicks auf das Modell, Punkte, Linien und Beschriftungen in der Szene.
- Modellanalyse: Prüfungen am Mesh, Berechnungen, Ergebnisse in einer Datei gespeichert.
- Verbindungen zu anderen Diensten: Modelle von außen, das Handy als Fernbedienung.
Erste Schritte
- 1
Werde Developer
Du brauchst ein Dentra-Konto. In /app fragst du unter «Developer» den Zugang an: Wir geben ihn frei.
- 2
Starte mit dem Beispiel
Lade das Beispiel-Plugin herunter: vier Pfeile, die das Modell drehen. Es enthält alles, was du brauchst.
- 3
Schreib dein eigenes
Ändere dentra-plugin.json (id, name, permissions) und die Seite. Das Kit DentraViewer ist schon da: Du musst es nicht importieren.
- 4
Teste es im Viewer
Pack den Ordner in ein Zip und lade es in deinem Developer-Bereich mit «Als Entwurf hochladen» hoch: Nur du siehst es, und es geht nicht in die Prüfung. «Im Viewer testen» öffnet den Viewer mit deinem eingeschalteten Plugin, auf zwei Beispielmodellen oder auf deinen eigenen. Etwas geändert? Lade das Zip mit derselben Versionsnummer neu hoch und teste noch einmal.
- 5
Reich es ein
Wenn es funktioniert, drückst du neben dem Entwurf auf «Zur Prüfung einreichen». Wenn etwas im Zip nicht passt, sagen wir es dir sofort, schon beim Hochladen.
Der Aufbau des Zips
my-plugin.zip
├── dentra-plugin.json
├── index.html ← "entry"
├── plugin.js
├── style.css
└── icon.png ← "icon" (optional)Im Zip dürfen nur diese Dateitypen sein: html, js, mjs, css, json, wasm, png, jpg, jpeg, svg, webp, gif, ico, woff, woff2, txt, md, task, tflite, bin, data, onnx. Höchstens 400 Dateien und 120 MB entpackt; das Zip selbst darf bis 40 MB groß sein.
dentra-plugin.json
Die Datei liegt im Hauptordner des Zips und sagt, wer das Plugin ist und was es braucht.
{
"id": "click-markers",
"name": "Markers",
"version": "1.0.0",
"description": "Places a numbered marker wherever you click on the model.",
"author": {
"name": "Your name",
"email": "[email protected]",
"website": "https://example.com"
},
"entry": "index.html",
"permissions": [
"pick",
"draw",
"toolbar"
],
"reasons": {
"pick": "To place a marker where you click.",
"draw": "To draw the marker on the model.",
"toolbar": "A button to clear the markers."
},
"platforms": [
"web",
"desktop"
],
"api": 1
}- id
- Der technische Name: 3-40 Zeichen aus Kleinbuchstaben, Ziffern und Bindestrichen, am Anfang und am Ende ein Buchstabe oder eine Ziffer. Er gehört dem Konto, das ihn zuerst hochlädt, auch als Entwurf: Niemand sonst kann ihn nutzen.
- name
- Der Name, den der Zahnarzt sieht, bis 40 Zeichen.
- version
- Drei Zahlen, zum Beispiel 1.0.0. Für eine neue Version erhöhst du sie: Eine schon zur Prüfung eingereichte Nummer wird abgelehnt, einen Entwurf lädst du dagegen mit derselben Nummer neu hoch.
- description
- Eine Zeile dazu, was es macht, bis 300 Zeichen.
- author
- Dein Name; E-Mail und Website sind freiwillig.
- entry
- Die HTML-Seite, die der Viewer im Rahmen öffnet. Fehlt das Feld, index.html.
- permissions
- Was es vom Viewer verlangt: siehe «Berechtigungen».
- reasons
- Für jede Berechtigung (außer view) eine Zeile zum Warum, bis 160 Zeichen. Der Zahnarzt liest sie, bevor er es einschaltet.
- platforms
- Wo es läuft: web, desktop oder beides. Fehlt das Feld, beides. Mit internet und models zusammen nur desktop.
- send
- Nur Pflicht, wenn du internet und models zusammen verlangst: to (die Domain, die die Scans bekommt, zum Beispiel api.example.com, ohne https://) und why (warum).
- icon
- Freiwillig: eine .png, .svg oder .webp im Zip.
- api
- Die Version des Kits: heute 1.
Berechtigungen
Du gibst sie im Feld permissions an. Jede Berechtigung ist genau eine Sache. Bevor der Zahnarzt das Plugin einschaltet, liest er, was es verlangt, mit den Gründen, die du in reasons geschrieben hast.
- view
- das Modell drehen, verschieben und zoomen, die Ansicht zurücksetzen, wissen, wohin sie schaut.
- pick
- wissen, wo der Zahnarzt auf das Modell klickt: Punkt, Richtung der Oberfläche und welches Modell.
- draw
- Punkte, Linien, Beschriftungen und vom Plugin mitgebrachte Modelle (STL, PLY, OBJ) in die Szene zeichnen.
- edit
- die geöffneten Modelle ausblenden, einfärben oder durchsichtig machen.
- models
- die Dateien der geöffneten Modelle lesen.
- files
- eine Datei auf dem Computer des Zahnarztes speichern.
- toolbar
- bis zu 4 Knöpfe in die Leiste des Viewers setzen.
- camera
- Bilder der Kamera bekommen. Der Viewer öffnet sie und fragt den Zahnarzt um Erlaubnis; das Plugin bekommt nur die Bilder.
- microphone
- Audio des Mikrofons bekommen. Der Viewer öffnet es und fragt den Zahnarzt um Erlaubnis.
- internet
- sich mit dem Internet verbinden. Ohne diese Berechtigung kann sich das Plugin mit keiner anderen Website verbinden.
- clipboard
- einen Text in die Zwischenablage kopieren.
Web und Desktop-App
Ein Plugin kann im Viewer im Web (web), in der Desktop-App (desktop) oder in beiden laufen. Du gibst es im Feld platforms an, und wir zeigen es in der Liste und auf der Seite des Plugins. Heute gibt es den Plugin-Bereich im Viewer im Web; die Desktop-App hat ihn vorerst nicht.
Internet und models zusammen heißt: Das Plugin kann Scans von Patienten nach außen schicken. Das geht nur in der Desktop-App, wo die Dateien dem Zahnarzt gehören, und nur, wenn du im Feld send angibst, wohin sie gehen und warum. Der Zahnarzt liest es klar und deutlich, bevor er es einschaltet; im Web lässt sich so ein Plugin nicht einschalten.
"platforms": ["web", "desktop"]
// internet + models: desktop only, and you must say where the scans go
"permissions": ["internet", "models"],
"send": { "to": "api.example.com", "why": "Analyses the scan and returns a report." }Kit-Referenz
Auf der Einstiegsseite deines Plugins (entry) gibt es schon window.DentraViewer: Der Viewer lädt es für dich. Funktionen mit await geben ein Promise zurück; die anderen warten auf keine Antwort. Jede Funktion braucht die angegebene Berechtigung; ohne sie ignoriert der Viewer sie oder das Promise schlägt mit einem Fehler fehl. DentraViewer gibt es nur im Viewer: Öffnest du die Seite des Plugins allein, von deinem Computer aus, ist es nicht da.
await DentraViewer.ready()wartet auf den Viewer; gibt { language, permissions, api } zurück: die Sprache des Nutzers, die erteilten Berechtigungen und die Version des Kits.
DentraViewer.view.move({ rotate: { x, y, z }, pan: { x, y }, zoom })rotate in Radiant um die Bildschirmachsen (x hoch und runter, y links und rechts, z Drehung auf der Stelle), pan in Bruchteilen der Modellgröße, ein positiver zoom geht näher heran (0.1 = 10 %). Jeder Wert zählt höchstens 0.5 pro Aufruf.
Berechtigung: view
DentraViewer.view.reset()setzt die Ansicht zurück.
Berechtigung: view
await DentraViewer.view.get()wohin die Kamera gerade schaut: position und target, jeweils [x, y, z].
Berechtigung: view
DentraViewer.pick.onClick(({ point, normal, model }) => …)bei jedem Klick auf das Modell (nicht beim Ziehen): point und normal als [x, y, z], und model, die id des angeklickten Modells oder null.
Berechtigung: pick
DentraViewer.scene.draw(key, { shape, … })zeichnet eine Form: shape "points" (points, color, size), "line" (points, color, closed), "text" (point, text, color, size) oder "mesh" (data, format stl/ply/obj, color, opacity). Die Koordinaten sind dieselben wie bei pick.onClick. Dieselbe key ersetzt sie. Bis zu 500 Formen, ein Mesh bis 100 MB.
Berechtigung: draw
DentraViewer.scene.remove(key) / DentraViewer.scene.clear()entfernt eine Form oder alle Formen des Plugins.
Berechtigung: draw
await DentraViewer.models.list()die geöffneten Modelle: id, name, format.
Berechtigung: models
await DentraViewer.models.read(id)die Datei eines Modells: data ist ein ArrayBuffer.
Berechtigung: models
DentraViewer.models.change(id, { visible, opacity, color })zeigt oder versteckt (visible), ändert die Transparenz (opacity, von 0 bis 1) oder die Farbe (color, "#rrggbb"; null kehrt zur vorherigen Farbe zurück) eines geöffneten Modells.
Berechtigung: edit
DentraViewer.files.save(name, data, type)lädt eine Datei auf den Computer herunter (String oder ArrayBuffer, bis 200 MB); type ist der Dateityp, zum Beispiel "text/csv".
Berechtigung: files
DentraViewer.toolbar.button(key, label) / toolbar.onPress((key) => …) / toolbar.remove(key)ein Knopf in der Leiste des Viewers (bis zu 4, Beschriftung bis 24 Zeichen), was passiert, wenn man ihn drückt, und toolbar.remove(key), um ihn zu entfernen.
Berechtigung: toolbar
DentraViewer.camera.start({ fps, width }) / camera.onFrame((image, t) => …)schaltet die Kamera ein: fps von 1 bis 30 (Standard 15), width von 160 bis 1280 Pixel (Standard 640). Die Bilder kommen als ImageBitmap; camera.onStatus sagt, ob sie an ist oder warum nicht. camera.stop() schaltet sie aus.
Berechtigung: camera
DentraViewer.microphone.start() / microphone.onAudio((samples, sampleRate) => …)schaltet das Mikrofon ein; das Audio kommt in Float32Array-Stücken, mit der Abtastrate. microphone.onStatus sagt, ob es an ist oder warum nicht; microphone.stop() schaltet es aus.
Berechtigung: microphone
await DentraViewer.storage.get() / DentraViewer.storage.set(value)ein JSON-Wert, auf diesem Gerät gespeichert, nur für dein Plugin, bis 100 KB: Größeres wird nicht gespeichert. get() gibt null zurück, wenn nichts da ist.
DentraViewer.clipboard.write(text)kopiert einen Text in die Zwischenablage, bis 2000 Zeichen.
Berechtigung: clipboard
DentraViewer.panel.height(px)die Höhe des Plugin-Rahmens in Pixeln, von 80 bis 560 (Standard 180).
Ein vollständiges Beispiel
// plugin.js: place a numbered marker wherever the dentist clicks
// Permissions in dentra-plugin.json: "pick", "draw", "toolbar" (the manifest above)
let n = 0;
DentraViewer.ready().then(({ language, permissions }) => {
// language: the dentist's language ("it", "en", "de"…), to translate your labels
DentraViewer.panel.height(120);
DentraViewer.toolbar.button("clear", "Clear");
});
DentraViewer.pick.onClick(({ point }) => {
n++;
DentraViewer.scene.draw("dot-" + n, { shape: "points", points: [point], color: "#e5484d", size: 0.6 });
DentraViewer.scene.draw("label-" + n, { shape: "text", point: [point[0], point[1] + 2, point[2]], text: "#" + n });
});
DentraViewer.toolbar.onPress((key) => {
if (key === "clear") { DentraViewer.scene.clear(); n = 0; }
});Prüfung und Veröffentlichung
- Du reichst das Zip in deinem Developer-Bereich ein oder drückst bei einem Entwurf, den du schon getestet hast, auf «Zur Prüfung einreichen». Die Dateien und dentra-plugin.json prüfen wir, sobald du das Zip hochlädst, auch als Entwurf, und sagen dir, was fehlt (die Meldungen sind auf Englisch). Wenn es in die Prüfung geht, bekommst du eine Bestätigung per E-Mail.
- Wir testen es im Viewer, bevor wir es veröffentlichen. Wenn es die Modelle liest und das Internet nutzt, durchläuft es auch eine Datenschutzprüfung.
- Wenn wir es freigeben, veröffentlichen wir es: Es erscheint in der öffentlichen Plugin-Liste und im Bereich des Viewers. Wenn nicht, schreiben wir dir, was du ändern sollst, und in deinem Developer-Bereich ist diese Version mit «Zu ändern» und unserer Notiz markiert. In beiden Fällen bekommst du eine E-Mail.
- Für eine neue Version, auch nach einer Ablehnung, erhöhst du die Zahl in version und reichst sie neu ein: Eine schon eingereichte Zahl geht nicht noch einmal. Einen Entwurf lädst du dagegen mit derselben Zahl neu hoch, bis du ihn einreichst. Sie durchläuft denselben Test, und bis wir sie freigeben, bleibt im Viewer die vorherige. Sobald wir sie freigeben, nutzen alle, die das Plugin schon eingeschaltet haben, automatisch die neue Version. Verlangt sie aber Berechtigungen, die die vorherige Version nicht hatte, finden alle, die es eingeschaltet hatten, es pausiert: Der Viewer zeigt ihnen die neuen Berechtigungen mit deinen Begründungen, und das Plugin läuft erst wieder, wenn sie zustimmen.
Regeln
- Plugins sind für alle, die sie nutzen, kostenlos.
- Du brauchst ein Dentra-Konto mit Developer-Zugang, den wir freigeben. Danach testen wir jedes Plugin, eins nach dem anderen.
- Das Plugin läuft in seinem eigenen geschlossenen Rahmen: Es sieht weder die Seite noch die Konten noch die Daten von Dentra.
- Jede Berechtigung braucht eine Begründung in einer Zeile.
- Scans gehen nur in der Desktop-App nach außen, und nur, wenn du in send angibst, wohin und warum.
- Mit dem Einreichen bist du einverstanden, dass wir es testen und, wenn es uns gefällt, kostenlos im Viewer veröffentlichen. Das Plugin bleibt deins.
- Wir können ein Plugin aus dem Katalog zurückziehen: Bei einem Sicherheitsproblem tun wir das sofort, ohne zu warten. Den Grund schicken wir dir per E-Mail, und du findest ihn in deinem Developer-Bereich; wer es eingeschaltet hatte, findet es ausgeschaltet.
Werde Developer
Du brauchst ein Dentra-Konto, mit Rechnungsdaten wie bei jedem Konto. Über dein Konto fragst du den Developer-Zugang an; sobald wir ihn freigeben, reichst du in deinem Bereich Plugins ein und siehst, wie weit sie sind.
Der Developer-Zugang ist der Anfang: Bald laufen darüber auch die APIs von Dentra.