From ffb2409c244eab459d206ac1517b3128f5b2fb0e Mon Sep 17 00:00:00 2001 From: TanerUslu Date: Wed, 29 Jul 2026 15:48:04 +0200 Subject: [PATCH] =?UTF-8?q?Doku:=20vierte=20Funktion=20"Z=C3=A4hlen"=20im?= =?UTF-8?q?=20README=20erg=C3=A4nzt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Funktionstabelle, Ablaufbeschreibung, Aufbau-Tabelle (threshold.js, count-objects.js), Testzahl (165), neuer Grenzen-Abschnitt (beruehrende/ gestapelte Teile, ungleichmaessige Ausleuchtung, geringer Kontrast, stark unterschiedliche Teilegroessen) sowie ein Geraete-Pruefpunkt fuer "Zählen". Co-Authored-By: Claude Opus 5 (1M context) --- README.md | 178 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 134 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index 4e4c14c..4d04027 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,13 @@ Browser-App, die per Handykamera gebrauchte Server-RAM-Module erkennt und beim physischen Sortieren am Tisch anleitet: Modul vor die Kamera halten, die App nennt den Stapel. -Vor dem Scannen wählt der Nutzer eine von drei Funktionen — Strichcode, -QR-Code oder Text erkennen (siehe „Funktionsweise" unten). Jede Funktion nutzt -ausschließlich ihre eigene Quelle; anders als früher weicht die App nicht mehr -automatisch auf Texterkennung aus, wenn kein Code gefunden wird. +Vor dem Scannen wählt der Nutzer eine von vier Funktionen — Strichcode, +QR-Code, Text erkennen oder Zählen (siehe „Funktionsweise" unten). Jede +Funktion nutzt ausschließlich ihre eigene Quelle; anders als früher weicht die +App nicht mehr automatisch auf Texterkennung aus, wenn kein Code gefunden +wird. Die vierte Funktion, „Zählen", gehört nicht zum eigentlichen Sortieren: +Sie bucht nichts, sondern zeigt beim Auslegen von Kleinteilen (z. B. +Festplattenschrauben) fortlaufend deren Anzahl an. Zwei Module gelten als zusammengehörig, wenn sie denselben Barcode-Inhalt tragen — ein Barcode ist exakt gelesen, das ist der zuverlässigste Maßstab. @@ -57,16 +60,17 @@ keine Daten verlassen das Gerät. ## Funktionsweise 0. **Funktion wählen.** Vor dem ersten Scan (und jederzeit erneut über die - antippbare Anzeige in der Scan-Ansicht) wählt der Nutzer eine von drei + antippbare Anzeige in der Scan-Ansicht) wählt der Nutzer eine von vier Funktionen. Kennung, Beschriftung, gelesene Codearten und Verhalten stehen ausschließlich in `src/scan-modes.js` — es gibt keine zweite Stelle, an der das steht: - | Funktion | Liest | Laufende Suche | Texterkennung | + | Funktion | Liest | Laufende Suche/Zählung | Texterkennung | |---|---|---|---| - | **Strichcode** | Code128, Code39, Code93, ITF, EAN-13, EAN-8, UPC-A, UPC-E, Codabar | ja | nein | - | **QR-Code** | QRCode, MicroQRCode, RMQRCode, DataMatrix, Aztec, PDF417 | ja | nein | + | **Strichcode** | Code128, Code39, Code93, ITF, EAN-13, EAN-8, UPC-A, UPC-E, Codabar | ja (Codesuche) | nein | + | **QR-Code** | QRCode, MicroQRCode, RMQRCode, DataMatrix, Aztec, PDF417 | ja (Codesuche) | nein | | **Text erkennen** | keine Codes | nein | ja, auf Knopfdruck | + | **Zählen** | keine Codes | ja (Zählung, keine Buchung) | nein | „QR-Code" heißt auf Wunsch des Auftraggebers „QR-Code", liest aber bewusst nicht nur QR-Varianten, sondern auch DataMatrix, Aztec und PDF417. Der @@ -90,17 +94,21 @@ keine Daten verlassen das Gerät. verschwindet. Liegt beim Start eine gesicherte Sitzung vor, erscheint zuerst die Frage - nach dem Fortsetzen (siehe Punkt 5 unten) und erst danach die Funktionswahl + nach dem Fortsetzen (siehe Punkt 6 unten) und erst danach die Funktionswahl — die Kamera startet in jedem Fall erst, nachdem beides geklärt ist. Technisch bekommen „Strichcode" und „QR-Code" eine Texterkennung hineingereicht, die sofort leeren Text liefert, ohne Tesseract anzustoßen; „Text erkennen" bekommt eine Barcode-Dekodierung hineingereicht, die sofort - eine leere Liste liefert (`buildRecognitionAdapters` in - `src/scan-recognition.js`). Die Erkennungs-Pipeline selbst (`src/pipeline.js`, - Punkte 1–4 unten) bleibt dabei unverändert und kennt keine Funktionen — die - drei Funktionen unterscheiden sich ausschließlich darin, welche Adapter ihr - übergeben werden. + eine leere Liste liefert; „Zählen" bekommt beides leer hineingereicht + (`buildRecognitionAdapters` in `src/scan-recognition.js`). Die + Erkennungs-Pipeline selbst (`src/pipeline.js`, Punkte 1–3 und 5 unten) + bleibt dabei unverändert und kennt keine Funktionen — die drei + code-/textbasierten Funktionen unterscheiden sich ausschließlich darin, + welche Adapter ihr übergeben werden. „Zählen" ruft diese Pipeline im + normalen Betrieb gar nicht erst auf (siehe Punkt 4 unten) — es gibt dort ja + nichts zu buchen, das leere Adapterpaar dient nur als Absicherung für den + seltenen Ersatzweg ohne Kamera (Punkt 7). 1. **Barcode-Dekodierung** (nur in „Strichcode" und „QR-Code"). Die zur Funktion gehörenden Codearten werden laufend aus dem Kamerabild dekodiert (`zxing-wasm`, `decodeBarcodes` in `src/barcode.js` bekommt die Codearten @@ -163,18 +171,44 @@ keine Daten verlassen das Gerät. auszublenden wie in den beiden Barcode-Funktionen (`showResult` in `src/ui/result-overlay.js`). Der Rohtext jedes Eintrags lässt sich später auch in der Sitzungsliste nachlesen. -4. **Stapel-Zuweisung.** Grün (Barcode) und Gelb (OCR) laufen ohne Eingabe +4. **Zählen** (ausschließlich in Funktion „Zählen"). Reine Anzeige, ohne + jeden Bezug zur Sitzung: Solange die Kamera läuft, wird der Zielrahmen + mehrmals pro Sekunde ausgewertet und die Anzahl der darin gefundenen + Fundstücke groß im Bild eingeblendet (`countObjects` in + `src/count-objects.js`, aufgerufen über denselben Zeitgeber/dieselbe + Überlappungssperre wie die Barcode-Dauersuche — siehe + `continuousSearchLoop` in `src/main.js`). Es gibt in dieser Funktion + keinen „Modul scannen"-Knopf, keine Treffer-Rückmeldung und keine + Stapel-Zuweisung; die Zahl wird nirgends gespeichert, nicht einmal + flüchtig für die Dauer der Sitzung. + + Kein Bilderkennungsmodell: Der Ausschnitt wird über denselben + **Otsu-Schwellwert** wie die Texterkennung in zwei Klassen geteilt + (`threshold.js`, aus `ocr.js` herausgezogen, damit beide Funktionen sich + dieselbe Schwellwertbestimmung teilen, ohne dass die reine Zählung an + `tesseract.js` hinge). Die flächenmäßig **kleinere** der beiden Klassen + gilt als Objekt — die ausgelegten Teile belegen so gut wie immer weniger + Fläche als der Untergrund, unabhängig davon, ob sie heller oder dunkler + sind als dieser; der Nutzer muss nichts einstellen. Anschließend werden + zusammenhängende Objektflächen ermittelt (Connected-Component-Labeling + mit einer eigenen Arbeitsliste statt Rekursion, damit ein rund eine + Million Bildpunkte großer Ausschnitt nicht in den Stapelüberlauf läuft), + winzige Flächen als Rauschen verworfen und auffällig große Flächen + (mehrere berührende Teile) auf ein Vielfaches der typischen + Einzelteilgröße hochgerechnet. Details und Begründung der verwendeten + Schwellen: `.superpowers/sdd/counting-report.md`. +5. **Stapel-Zuweisung.** Grün (Barcode) und Gelb (OCR) laufen ohne Eingabe durch; nur bei roter Konfidenz (nichts Eindeutiges erkannt, widersprüchliche Barcodes oder widersprüchliche unbekannte Barcodes ohne jede OCR-Kapazität) oder mehrdeutiger Stapelzuordnung fragt die App nach. -5. **Sitzungsfortsetzung beim Start.** Findet die App beim Laden eine in +6. **Sitzungsfortsetzung beim Start.** Findet die App beim Laden eine in `localStorage` gesicherte, nicht leere Sitzung vor, wird sie nicht stillschweigend übernommen, sondern zur Fortsetzung oder zum Verwerfen angeboten (`askResumeSession` in `src/ui/resume-dialog.js`, verdrahtet über `initResumeOffer()` in `src/main.js`). Erst „fortsetzen“ stellt Stapel, Zähler und die „Zuletzt“-Zeile wieder her; „verwerfen“ löscht den gesicherten Stand und die App startet leer. -6. **Ersatzweg ohne Kamera.** Lässt sich die Kamera nicht starten (z. B. +7. **Ersatzweg ohne Kamera.** Lässt sich die Kamera nicht starten (z. B. verweigerte Berechtigung), bleibt die App bedienbar: eine dauerhaft sichtbare Schaltfläche „Bild auswählen“ öffnet stattdessen die native Dateiauswahl (`setFilePickerVisible` in `src/ui/scan-view.js`). Die App @@ -213,22 +247,26 @@ korrekt funktioniert. npm test ``` -154 Tests, alle grün (Stand dieses Dokuments). Getestet werden ausschließlich +165 Tests, alle grün (Stand dieses Dokuments). Getestet werden ausschließlich die reinen Module ohne Browser-Zugriff: Teilenummer-Decoder, Spec-Normalisierung -und toleranter Vergleich, OCR-Bildaufbereitung (Otsu-Schwellwert) und --Feldextraktion, Stapel-Zuweisung, die Erkennungs-Pipeline samt Zeitgrenzen, -Mehrdeutigkeitsbehandlung und dem additiven OCR-Rohtext (`rawText` wird nur -zurückgegeben, wenn die Texterkennung tatsächlich lief, und beeinflusst -nachweislich nie die Stapelzuordnung), die Sitzungssicherung samt Prüfung -eines wiederhergestellten Zustands (einschließlich `entry.rawText`), die drei -Scan-Funktionen (`scan-modes.js` — -Codearten je Funktion, DataMatrix/Aztec/PDF417 in „QR-Code") sowie die je Funktion +und toleranter Vergleich, OCR-Bildaufbereitung (Otsu-Schwellwert, jetzt in +`threshold.js`) und -Feldextraktion, Stapel-Zuweisung, die Erkennungs-Pipeline +samt Zeitgrenzen, Mehrdeutigkeitsbehandlung und dem additiven OCR-Rohtext +(`rawText` wird nur zurückgegeben, wenn die Texterkennung tatsächlich lief, +und beeinflusst nachweislich nie die Stapelzuordnung), die Sitzungssicherung +samt Prüfung eines wiederhergestellten Zustands (einschließlich +`entry.rawText`), die vier Scan-Funktionen (`scan-modes.js` — Codearten je +Funktion, DataMatrix/Aztec/PDF417 in „QR-Code") sowie die je Funktion tatsächlich aufgerufenen Adapter (`scan-recognition.js` — Texterkennung läuft nachweislich nie in „Strichcode"/„QR-Code", Barcode-Dekodierung nachweislich -nie in „Text erkennen"). Kamera, Barcode-/OCR-Adapter selbst, die -Auswahl-Oberfläche und die Verdrahtung in `main.js` laufen nur im echten -Browser und werden dort manuell geprüft (siehe „Am Gerät noch zu prüfen" -unten) — `node --test` kennt kein DOM. +nie in „Text erkennen"/„Zählen"). Dazu die Zähl-Berechnung selbst +(`count-objects.js` — leeres Bild, einzelne und mehrere getrennte Flächen, +verworfenes Rauschen, Hochrechnung berührender Teile ohne ein nur leicht +größeres Einzelteil zu verdoppeln, helle wie dunkle Objekte, ein Bild ohne +Bildpunkte). Kamera, Barcode-/OCR-Adapter selbst, die Auswahl-Oberfläche und +die Verdrahtung in `main.js` laufen nur im echten Browser und werden dort +manuell geprüft (siehe „Am Gerät noch zu prüfen" unten) — `node --test` kennt +kein DOM. ## Produktion @@ -293,14 +331,16 @@ worauf du bei der Veröffentlichung achten solltest. | `src/ocr-extract.js` | OCR-Rohtext → Spec-Felder | | `src/session.js` | Stapel halten, vorschlagen, buchen, umsortieren, zurücknehmen — inklusive der aus den Einträgen abgeleiteten, je Stapel bekannten Barcode-Inhalte (`stack.codes`), die vor dem Vergleich der technischen Angaben über die Zuordnung entscheiden, sofern diese Angaben nicht widersprechen | | `src/pipeline.js` | Barcode → Teilenummer → OCR → Ampelfarbe, inkl. Zeitgrenzen, Mehrdeutigkeitsbehandlung und Kurzschluss über einen bereits bekannten Barcode-Inhalt (`deps.isKnownCode`) — kennt keine Scan-Funktionen; liefert zusätzlich (additiv) den ungefilterten OCR-Rohtext (`rawText`), leer, wenn keine Texterkennung lief | -| `src/scan-modes.js` | Die drei Scan-Funktionen (Strichcode, QR-Code, Text erkennen): Kennung, deutsche Beschriftung, gelesene Codearten, laufende Suche ja/nein, Texterkennung ja/nein — einzige Quelle, sowohl für die Auswahl-Oberfläche als auch für `main.js` | -| `src/scan-recognition.js` | Baut die an `recognize()` übergebenen Adapter anhand der gewählten Funktion: in „Strichcode"/„QR-Code" liefert die Texterkennung sofort leeren Text ohne Tesseract anzustoßen, in „Text erkennen" liefert die Barcode-Dekodierung sofort eine leere Liste ohne `zxing-wasm` anzustoßen | +| `src/scan-modes.js` | Die vier Scan-Funktionen (Strichcode, QR-Code, Text erkennen, Zählen): Kennung, deutsche Beschriftung, gelesene Codearten, laufende Suche ja/nein, Texterkennung ja/nein, laufende Zählung ja/nein — einzige Quelle, sowohl für die Auswahl-Oberfläche als auch für `main.js` | +| `src/scan-recognition.js` | Baut die an `recognize()` übergebenen Adapter anhand der gewählten Funktion: in „Strichcode"/„QR-Code" liefert die Texterkennung sofort leeren Text ohne Tesseract anzustoßen, in „Text erkennen" liefert die Barcode-Dekodierung sofort eine leere Liste ohne `zxing-wasm` anzustoßen, in „Zählen" liefern beide sofort leer (diese Funktion ruft `recognize()` im normalen Betrieb ohnehin nicht auf) | +| `src/threshold.js` | Otsu-Schwellwertbestimmung (Graustufen, Histogramm, Schwellwert) — reines Modul ohne Browser-Zugriff, aus `ocr.js` herausgezogen; gemeinsame Grundlage für `preprocess()` (ocr.js) und `countObjects()` (count-objects.js) | +| `src/count-objects.js` | Reine Berechnung für Funktion „Zählen": zählt zusammenhängende Objektflächen in einem Bildausschnitt (Otsu-Schwellwert aus `threshold.js`, flächenmäßig kleinere Klasse gilt als Objekt, Connected-Component-Labeling mit eigener Arbeitsliste, Rauschfilter, Hochrechnung berührender Teile über den Flächen-Median) | | `src/storage.js` | Absturzschutz der laufenden Sitzung: sichert und lädt aus `localStorage`, verwirft beim Laden jeden in sich unstimmigen Zustand vollständig (siehe unten); `entry.rawText` ist wie `entry.codes` optional und wird bei Fehlen als leerer Rohtext wiederhergestellt | -| `src/camera.js` | Kamerastart, Einzelbildaufnahme (herunterskaliert, für die Dateiauswahl), Rahmenausschnitt in voller Auflösung (`grabFrameRegion`, für die laufende Barcode-Suche **und** für „Modul scannen" in „Text erkennen"), Bilddatei-Ersatzweg | +| `src/camera.js` | Kamerastart, Einzelbildaufnahme (herunterskaliert, für die Dateiauswahl), Rahmenausschnitt in voller Auflösung (`grabFrameRegion`, für die laufende Barcode-Suche, „Modul scannen" in „Text erkennen" **und** die laufende Zählung in „Zählen"), Bilddatei-Ersatzweg | | `src/barcode.js` | Adapter zu `zxing-wasm`; `decodeBarcodes(imageData, formats)` bekommt die Codearten übergeben, ohne Angabe wie bisher (Code128 + DataMatrix) | -| `src/ocr.js` | Bildaufbereitung (Otsu) und Adapter zu `tesseract.js`; Zeichen-Whitelist deckt Groß- und Kleinbuchstaben, Ziffern sowie übliche Etiketten-Sonderzeichen ab | -| `src/ui/scan-view.js` | Scan-Ansicht: Kamera-Vorschau, antippbare Anzeige der gewählten Funktion (Wechsel), Scan-Knopf (nur in „Text erkennen" sichtbar), Stapel-Leiste, „Zuletzt"-Zeile, Ersatzweg-Schaltfläche bei fehlender Kamera | -| `src/ui/mode-dialog.js` | Vollbild-Auswahl der Scan-Funktion vor dem Start und beim Wechsel: drei große Flächen, eine je Funktion aus `src/scan-modes.js` | +| `src/ocr.js` | Bildaufbereitung (Otsu, über `threshold.js`) und Adapter zu `tesseract.js`; Zeichen-Whitelist deckt Groß- und Kleinbuchstaben, Ziffern sowie übliche Etiketten-Sonderzeichen ab | +| `src/ui/scan-view.js` | Scan-Ansicht: Kamera-Vorschau, antippbare Anzeige der gewählten Funktion (Wechsel), Scan-Knopf (nur in „Text erkennen" sichtbar), große Zählanzeige (nur in „Zählen" sichtbar), Stapel-Leiste, „Zuletzt"-Zeile, Ersatzweg-Schaltfläche bei fehlender Kamera | +| `src/ui/mode-dialog.js` | Vollbild-Auswahl der Scan-Funktion vor dem Start und beim Wechsel: vier große Flächen, eine je Funktion aus `src/scan-modes.js` | | `src/ui/result-overlay.js` | Treffer-Rückmeldung (grün/gelb): blendet sich in „Strichcode"/„QR-Code" nach kurzer Zeit selbst aus; in „Text erkennen" bleibt sie stehen, zeigt den vollen OCR-Rohtext und wartet auf eine Eingabe, bevor sie schließt | | `src/ui/ambiguous-dialog.js` | Rot-Dialog bei roter Konfidenz oder mehrdeutiger Stapelzuordnung | | `src/ui/resume-dialog.js` | Dialog beim Start: gesicherte Sitzung fortsetzen oder verwerfen — läuft vor der Funktionswahl | @@ -312,10 +352,11 @@ worauf du bei der Veröffentlichung achten solltest. | `.vch/deploy.yaml` | Bau- und Startbefehl sowie Gesundheitspfad für die Hosting-Umgebung | `spec`, `pn-decoder`, `ocr-extract`, `session`, `pipeline`, `storage`, -`scan-modes` und `scan-recognition` sind reine Funktionen ohne Browser-Zugriff -(kein `window`, `document` oder `localStorage` direkt) und deshalb vollständig -mit `node:test` prüfbar. `camera.js`, `barcode.js`, `ocr.js` und `src/ui/` -brauchen einen echten Browser und werden nur manuell geprüft. +`scan-modes`, `scan-recognition`, `threshold` und `count-objects` sind reine +Funktionen ohne Browser-Zugriff (kein `window`, `document` oder +`localStorage` direkt) und deshalb vollständig mit `node:test` prüfbar. +`camera.js`, `barcode.js`, `ocr.js` und `src/ui/` brauchen einen echten +Browser und werden nur manuell geprüft. ### Sitzungssicherung im Detail @@ -390,6 +431,37 @@ Eintrag und fließt in keine Stapel-Berechnung ein. Aufnahmen (Zeilenumbrüche, zusätzlich erkannte Wörter, Groß-/ Kleinschreibung, …) und würde als Gruppierungsmerkmal für praktisch jedes Modul einen eigenen Stapel erzeugen. +- **Funktion „Zählen" ist eine Schätzung, keine exakte Zählung** — sie wird + ungenau, wenn eine der folgenden Bedingungen zutrifft: + - **Berührende oder gestapelte Teile.** Mehrere Teile, die sich berühren, + bilden eine einzige zusammenhängende Fläche. Die App rechnet diese über + die typische Einzelteilgröße (Median der gefundenen Flächen) auf ein + Vielfaches hoch, aber je unregelmäßiger sich die Teile überlappen + (z. B. drei Schrauben, die sich gegenseitig teilweise verdecken statt + sich nur zu berühren), desto ungenauer wird die hochgerechnete Fläche. + Liegen Teile übereinander gestapelt statt nebeneinander ausgelegt, sieht + die Kamera von oben nur die Fläche des obersten Teils — verdeckte Teile + werden nicht mitgezählt. + - **Ungleichmäßige Ausleuchtung.** Der Otsu-Schwellwert ist ein einziger, + fester Wert für den gesamten Ausschnitt. Fällt Licht sehr einseitig ein + (z. B. ein Teil des Rahmens hell, der Rest im Schatten), kann derselbe + Untergrund an einer Stelle über und an einer anderen Stelle unter dem + Schwellwert liegen — Teile im schlechter ausgeleuchteten Bereich werden + dann leicht übersehen oder der Untergrund selbst fälschlich als + Objektfläche gewertet. + - **Zu geringer Kontrast zum Untergrund.** Je ähnlicher sich Objekt- und + Untergrundhelligkeit sind, desto unschärfer die Trennung durch Otsu — + bei sehr geringem Kontrast können Teile am Rand verloren gehen oder mit + dem Untergrund verschmelzen. + - **Stark unterschiedlich große Teile.** Die Hochrechnung setzt voraus, + dass die meisten Fundstücke ungefähr gleich groß sind (der Median dient + als Maßstab für „ein Teil"). Liegen im selben Rahmen sowohl deutlich + größere als auch deutlich kleinere Teile derselben Sorte (oder gar + unterschiedliche Teile gemischt), kann die Rauschschwelle ein + tatsächliches kleines Teil verwerfen oder die Hochrechnung ein einzelnes + großes Teil als mehrere zählen. + - Details, die verwendeten Schwellenwerte und ihre Begründung stehen in + `.superpowers/sdd/counting-report.md`. ## Herstellertabellen erweitern @@ -433,10 +505,11 @@ werden: - Datei-Auswahl als Ersatzweg (ohne Kamera) öffnet den nativen Dialog und hinterlässt keine leere Fläche im Layout. -**Funktionswahl (neu)** -- Erster Start ohne gesicherte Sitzung: Auswahl mit drei großen Flächen - („Strichcode", „QR-Code", „Text erkennen") erscheint, *bevor* die Kamera - startet — kein Kamerabild sichtbar, solange keine Funktion gewählt ist. +**Funktionswahl** +- Erster Start ohne gesicherte Sitzung: Auswahl mit vier großen Flächen + („Strichcode", „QR-Code", „Text erkennen", „Zählen") erscheint, *bevor* die + Kamera startet — kein Kamerabild sichtbar, solange keine Funktion gewählt + ist. - Erster Start *mit* gesicherter Sitzung: erst die Frage „Gesicherte Sitzung gefunden" (fortsetzen/verwerfen), erst danach die Funktionswahl. - „Strichcode" wählen: laufende Suche erkennt Code-128/Code-39/EAN/UPC/…, @@ -488,6 +561,23 @@ werden: dass die Vorbereitung tatsächlich nur einmal läuft)? In Funktion „Text erkennen" darf dieses Laden dagegen gar nicht erst anlaufen, da dort nie `decodeBarcodes` aufgerufen wird. +**Zählen (neu)** +- „Zählen" wählen, Kamera auf ausgelegte Kleinteile richten (z. B. silberne + Festplattenschrauben auf dunklem Untergrund): Eine große Zahl erscheint im + Bild und aktualisiert sich laufend, ohne dass etwas angetippt werden muss. + Kein „Modul scannen"-Knopf, keine Treffer-Rückmeldung, kein roter Dialog, + keine Stapel-Zuweisung — der Zielrahmen bleibt sichtbar und zeigt weiterhin, + was gezählt wird. +- Die angezeigte Zahl aus normalem Bedienabstand (Armlänge) lesbar prüfen. +- Ein paar Teile wegnehmen bzw. hinzufügen, während die Kamera läuft: Die + Zahl folgt ohne spürbare Verzögerung. +- Zugänge zur Sitzungsliste und zum Funktionswechsel bleiben auch in dieser + Funktion erreichbar (Anzeige der Funktion antippen, Stapel-Leiste antippen). +- Gegenprobe der Grenzen (siehe „Grenzen" oben): Teile eng aneinanderlegen + (Hochrechnung), Teile stapeln (nur oberste Schicht zählt), einseitige + Beleuchtung, geringer Kontrast zum Untergrund — beobachten, wo die Zahl + spürbar daneben liegt, bisher nur an synthetischen Testbildern geprüft, nie + an einem echten Foto. - Verbindung während des allerersten Scans einer Sitzung unterbrechen (WASM lädt per CDN), danach mit wiederhergestellter Verbindung erneut scannen: Das muss einen echten neuen Ladeversuch auslösen statt dauerhaft mit