Przejdź do treści

Write a plugin for Dentra Viewer

Wtyczka dodaje funkcje do Viewera. Ty ją piszesz, my ją testujemy, a jeśli nam się spodoba, wszyscy znajdą ją w panelu «Wtyczki».

Wprowadzenie

Wtyczki pisze społeczność: są dla każdego, kto chce dostosować Viewer albo dodać do niego funkcje. My dajemy środowisko i tę dokumentację.

Wtyczka to mała strona internetowa (HTML, JavaScript i CSS), którą Viewer otwiera we własnej ramce. Z ramki wtyczka rozmawia z Viewerem przez zestaw DentraViewer, który jest już załadowany.

Wtyczka działa w zamkniętej ramce: nie widzi strony, konta ani danych Dentra. Może robić tylko to, o co prosi w uprawnieniach, a dentysta czyta je, zanim ją włączy.

Co możesz zbudować

  • Nowe sposoby sterowania widokiem: gesty dłoni przed kamerą internetową, kontrolery do gier, komendy głosowe.
  • Pomiary i adnotacje: kliknięcia na modelu, punkty, linie i napisy w scenie.
  • Analiza modeli: kontrole siatki, obliczenia, wyniki zapisane do pliku.
  • Połączenia z innymi usługami: modele z zewnątrz, telefon jako pilot.

Pierwsze kroki

  1. 1

    Zostań developerem

    Potrzebujesz konta Dentra. W /app, w pozycji «Developer», poproś o dostęp: my go zatwierdzamy.

  2. 2

    Zacznij od przykładu

    Pobierz przykładową wtyczkę: cztery strzałki, które obracają model. Jest w niej wszystko, czego potrzebujesz.

  3. 3

    Napisz własną

    Zmień dentra-plugin.json (id, name, permissions) i stronę. Zestaw DentraViewer już tam jest: nie trzeba go importować.

  4. 4

    Wypróbuj ją w Viewerze

    Spakuj folder do zipa i wgraj go ze swojej strefy Developer przyciskiem «Wgraj jako wersję roboczą»: widzisz ją tylko ty i nie trafia do weryfikacji. «Wypróbuj w Viewerze» otwiera Viewer z włączoną twoją wtyczką, na dwóch przykładowych łukach albo na twoich własnych modelach. Po każdej zmianie wgraj zip ponownie z tym samym numerem wersji i spróbuj jeszcze raz.

  5. 5

    Zgłoś ją

    Gdy działa, naciśnij «Zgłoś do weryfikacji» obok wersji roboczej. Jeśli coś w zipie jest nie tak, powiemy ci od razu, już przy wgrywaniu.

Struktura zipa

my-plugin.zip
├── dentra-plugin.json
├── index.html        ← "entry"
├── plugin.js
├── style.css
└── icon.png          ← "icon" (optional)

W zipie mogą być tylko te typy plików: html, js, mjs, css, json, wasm, png, jpg, jpeg, svg, webp, gif, ico, woff, woff2, txt, md, task, tflite, bin, data, onnx. Najwyżej 400 plików i 120 MB po rozpakowaniu; sam zip może mieć do 40 MB.

dentra-plugin.json

Plik leży w katalogu głównym zipa i mówi, czym jest wtyczka i czego potrzebuje.

{
  "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
Nazwa techniczna: 3-40 znaków spośród małych liter, cyfr i myślników, z literą albo cyfrą na początku i na końcu. Należy do konta, które wgra ją pierwsze, także jako wersję roboczą: nikt inny nie może jej użyć.
name
Nazwa, którą widzi dentysta, do 40 znaków.
version
Trzy liczby, np. 1.0.0. Przy nowej wersji ją podnieś: numer już zgłoszony do weryfikacji zostaje odrzucony, a wersję roboczą możesz wgrać ponownie z tym samym numerem.
description
Jedna linijka o tym, co robi, do 300 znaków.
author
Twoje imię i nazwisko; e-mail i strona są opcjonalne.
entry
Strona HTML, którą Viewer otwiera w ramce. Jeśli brak, index.html.
permissions
O co prosi Viewer: zobacz «Uprawnienia».
reasons
Dla każdego uprawnienia (oprócz view) jedna linijka o tym, po co, do 160 znaków. Dentysta czyta ją, zanim włączy wtyczkę.
platforms
Gdzie działa: web, desktop albo oba. Jeśli brak, oba. Z internet i models razem tylko desktop.
send
Wymagane tylko, jeśli prosisz o internet i models razem: to (domena, która odbiera skany, np. api.example.com, bez https://) i why (po co).
icon
Opcjonalna: plik .png, .svg lub .webp w zipie.
api
Wersja zestawu: dziś 1.

Uprawnienia

Deklaruje się je w polu permissions. Każde uprawnienie to jedna rzecz. Zanim dentysta włączy wtyczkę, czyta, o co prosi, razem z powodami, które wpisałeś w reasons.

view
obracać, przesuwać i przybliżać model, przywracać widok, wiedzieć, gdzie patrzy.
pick
wiedzieć, gdzie dentysta klika na modelu: punkt, kierunek powierzchni i który model.
draw
rysować w scenie punkty, linie, napisy i modele przyniesione przez wtyczkę (STL, PLY, OBJ).
edit
ukrywać, kolorować lub robić przezroczyste otwarte modele.
models
czytać pliki otwartych modeli.
files
zapisać plik na komputerze dentysty.
toolbar
dodać do 4 przycisków na pasku Viewera.
camera
otrzymywać obrazy z kamery. Otwiera ją Viewer, prosząc dentystę o zgodę; wtyczka dostaje tylko obrazy.
microphone
otrzymywać dźwięk z mikrofonu. Otwiera go Viewer, prosząc dentystę o zgodę.
internet
łączyć się z internetem. Bez tego wtyczka nie może połączyć się z żadną inną stroną.
clipboard
kopiować tekst do schowka.

Przeglądarka i aplikacja na komputer

Wtyczka może działać w Viewerze w przeglądarce (web), w aplikacji na komputer (desktop) albo w obu. Deklarujesz to w polu platforms, a my pokazujemy to na liście i na stronie wtyczki. Dziś panel wtyczek jest w Viewerze w przeglądarce; aplikacja na komputer na razie go nie ma.

Internet i models razem oznaczają, że wtyczka może wysyłać skany pacjentów na zewnątrz. Da się to zrobić tylko w aplikacji na komputer, gdzie pliki należą do dentysty, i tylko deklarując w polu send, dokąd idą i po co. Dentysta czyta to wprost, zanim ją włączy; w przeglądarce takiej wtyczki nie da się włączyć.

"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." }

Opis zestawu

Na stronie wejściowej twojej wtyczki (entry) jest już window.DentraViewer: Viewer ładuje go sam. Funkcje zapisane z await zwracają Promise; pozostałe nie czekają na odpowiedź. Każda funkcja wymaga podanego uprawnienia; bez niego Viewer ją ignoruje albo Promise kończy się błędem. DentraViewer istnieje tylko wewnątrz Viewera: jeśli otworzysz stronę wtyczki osobno, ze swojego komputera, nie znajdziesz go.

await DentraViewer.ready()

czeka na Viewer; zwraca { language, permissions, api }: język użytkownika, przyznane uprawnienia i wersję zestawu.

DentraViewer.view.move({ rotate: { x, y, z }, pan: { x, y }, zoom })

rotate w radianach wokół osi ekranu (x góra i dół, y lewo i prawo, z obrót w miejscu), pan w ułamkach rozmiaru modelu, dodatni zoom przybliża (0.1 = 10%). Każda wartość liczy się najwyżej jako 0.5 na wywołanie.

Uprawnienie: view

DentraViewer.view.reset()

przywraca widok do poprzedniego stanu.

Uprawnienie: view

await DentraViewer.view.get()

gdzie kamera patrzy teraz: position i target, każde [x, y, z].

Uprawnienie: view

DentraViewer.pick.onClick(({ point, normal, model }) => …)

przy każdym kliknięciu na modelu (nie przy przeciąganiu): point i normal jako [x, y, z] oraz model, id klikniętego modelu albo null.

Uprawnienie: pick

DentraViewer.scene.draw(key, { shape, … })

rysuje kształt: shape "points" (points, color, size), "line" (points, color, closed), "text" (point, text, color, size) albo "mesh" (data, format stl/ply/obj, color, opacity). Współrzędne są takie same jak w pick.onClick. Ten sam key go zastępuje. Do 500 kształtów, mesh do 100 MB.

Uprawnienie: draw

DentraViewer.scene.remove(key) / DentraViewer.scene.clear()

usuwa jeden kształt albo wszystkie kształty wtyczki.

Uprawnienie: draw

await DentraViewer.models.list()

otwarte modele: id, name, format.

Uprawnienie: models

await DentraViewer.models.read(id)

plik modelu: data to ArrayBuffer.

Uprawnienie: models

DentraViewer.models.change(id, { visible, opacity, color })

pokazuje albo ukrywa (visible), zmienia przezroczystość (opacity, od 0 do 1) albo kolor (color, "#rrggbb"; null przywraca poprzedni kolor) otwartego modelu.

Uprawnienie: edit

DentraViewer.files.save(name, data, type)

pobiera plik na komputer (string albo ArrayBuffer, do 200 MB); type to typ pliku, np. "text/csv".

Uprawnienie: files

DentraViewer.toolbar.button(key, label) / toolbar.onPress((key) => …) / toolbar.remove(key)

przycisk na pasku Viewera (do 4, etykieta do 24 znaków), to, co się dzieje po jego naciśnięciu, i toolbar.remove(key), żeby go usunąć.

Uprawnienie: toolbar

DentraViewer.camera.start({ fps, width }) / camera.onFrame((image, t) => …)

włącza kamerę: fps od 1 do 30 (domyślnie 15), width od 160 do 1280 pikseli (domyślnie 640). Obrazy przychodzą jako ImageBitmap; camera.onStatus mówi, czy jest włączona, a jeśli nie, dlaczego. camera.stop() ją wyłącza.

Uprawnienie: camera

DentraViewer.microphone.start() / microphone.onAudio((samples, sampleRate) => …)

włącza mikrofon; dźwięk przychodzi w kawałkach Float32Array, z częstotliwością próbkowania. microphone.onStatus mówi, czy jest włączony, a jeśli nie, dlaczego; microphone.stop() go wyłącza.

Uprawnienie: microphone

await DentraViewer.storage.get() / DentraViewer.storage.set(value)

jedna wartość JSON zapisana na tym urządzeniu, tylko dla twojej wtyczki, do 100 KB: większa się nie zapisuje. get() zwraca null, jeśli nic nie ma.

DentraViewer.clipboard.write(text)

kopiuje tekst do schowka, do 2000 znaków.

Uprawnienie: clipboard

DentraViewer.panel.height(px)

wysokość ramki wtyczki w pikselach, od 80 do 560 (domyślnie 180).

Pełny przykład

// 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; }
});

Weryfikacja i publikacja

  1. Zgłaszasz zip ze swojej strefy Developer albo naciskasz «Zgłoś do weryfikacji» przy wersji roboczej, którą już wypróbowałeś. Pliki i dentra-plugin.json sprawdzamy od razu, gdy wgrywasz zip, także jako wersję roboczą, i mówimy ci, czego brakuje (komunikaty są po angielsku). Gdy wtyczka trafia do weryfikacji, dostajesz e-mail z potwierdzeniem.
  2. Testujemy wtyczkę w Viewerze, zanim ją opublikujemy. Jeśli czyta modele i korzysta z internetu, przechodzi też kontrolę prywatności.
  3. Jeśli ją zatwierdzimy, publikujemy ją: pojawia się na publicznej liście wtyczek i w panelu Viewera. Jeśli nie, piszemy ci, co zmienić, a w twojej strefie Developer ta wersja ma oznaczenie «Do zmiany» z naszą notatką. W obu przypadkach dostajesz e-mail.
  4. Przy nowej wersji, także po odrzuceniu, podnieś numer w version i zgłoś ją ponownie: numeru już zgłoszonego nie da się użyć drugi raz. Wersję roboczą natomiast wgrywasz ponownie z tym samym numerem, dopóki jej nie zgłosisz. Przechodzi ten sam test, a dopóki jej nie zatwierdzimy, w Viewerze zostaje poprzednia. Gdy ją zatwierdzimy, każdy, kto już włączył wtyczkę, automatycznie korzysta z nowej wersji. Jeśli jednak prosi o uprawnienia, o które poprzednia wersja nie prosiła, każdy, kto ją włączył, zastanie ją wstrzymaną: Viewer pokaże mu nowe uprawnienia z twoimi uzasadnieniami, a wtyczka ruszy znowu dopiero, gdy je zaakceptuje.

Zasady

  • Wtyczki są darmowe dla tych, którzy z nich korzystają.
  • Potrzebujesz konta Dentra z dostępem Developer, który zatwierdzamy. Potem testujemy każdą wtyczkę, jedną po drugiej.
  • Wtyczka działa we własnej zamkniętej ramce: nie widzi strony, kont ani danych Dentra.
  • Każde uprawnienie wymaga uzasadnienia w jednej linijce.
  • Skany wychodzą na zewnątrz tylko w aplikacji na komputer, gdy w send podasz, dokąd i po co.
  • Zgłaszając wtyczkę, zgadzasz się, że ją przetestujemy i, jeśli nam się spodoba, opublikujemy za darmo w Viewerze. Wtyczka pozostaje twoja.
  • Możemy wycofać wtyczkę z katalogu: przy problemie z bezpieczeństwem robimy to od razu, bez czekania. Powód wysyłamy ci e-mailem i znajdziesz go w swojej strefie Developer; kto ją włączył, zastanie ją wyłączoną.

Zostań developerem

Potrzebujesz konta Dentra, z danymi do faktury jak każde konto. Ze swojego konta prosisz o dostęp Developer; gdy go zatwierdzimy, w swojej strefie zgłaszasz wtyczki i widzisz, na jakim są etapie.

Dostęp Developer to początek: wkrótce przejdą przez niego także API Dentra.