feat(dental-cpr): world's first open-source OHIF dental panoramic CPR extension#12
Merged
Ambientwork merged 26 commits intomainfrom Mar 24, 2026
Merged
Conversation
- Stats bar: "50+ practices", 0€ fees, 5min setup, 100% local - Demo section: YouTube embed placeholder with play button + live demo placeholder - Testimonials: 3 placeholder testimonials with star ratings - FAQ accordion: 6 questions (FDA cert, server requirements, DICOM import, data security, device compatibility, support/commercial options) - Newsletter: Brevo embed placeholder with functional fallback form - Nav: added Demo + FAQ links - OG URL updated to ct.ambientwork.ai Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…lds, workflow field
- docker-compose: read_only + tmpfs, no-new-privileges, cap_drop ALL, bind all ports to 127.0.0.1 (including DICOM port 4242) - orthanc.json: disable Lua execution, REST filesystem writes; empty AllowedOrigins for same-origin-only CORS - setup.sh: interactive custom password with min-16-chars + blocklist enforcement, password confirmation, CORS var in generated .env, security notes printed post-setup - .env.example: CORS_ALLOWED_ORIGINS var + HTTP-in-production warning Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Research-backed analysis of OHIF/Cornerstone3D dental imaging capabilities: - Documents what is already available (MPR, measurements, volume rendering) - CPR/panoramic viewport: vtkImageCPRMapper available via CS3D PR #1689 but no first-class implementation exists (Issue #2609, open Feb 2026) - No public OHIF dental panoramic extension found — greenfield opportunity - Phase 2: hanging protocol, nerve canal spline, bone thickness (days) - Phase 3: panoramic CPR viewport (4-8h CC, first open-source impl) - Phase 4: implant overlay, auto-segmentation, cephalometrics Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… extension Implements CS3D Issue #2609 — Curved Planar Reformation for dental CBCT. ## Extension: @ambientwork/ohif-extension-dental-cpr - DentalArchSplineTool: AnnotationTool, user clicks control points on axial CBCT slice; double-click fires ARCH_SPLINE_COMPLETED event - buildCenterline: Catmull-Rom spline → vtkPolyData with quaternion orientation array (Frenet-Serret frames, mat3→quat via Shepperd's method) - DentalCPRViewport: custom OHIF viewport using vtkImageCPRMapper - setImageData() + setCenterlineData() (correct vtk.js API per docs) - useStraightenedMode() — classic panoramic equivalent - MIP slab slider (1–20 mm, live update) - Handles resize, loading states, error display - cbctDentalHP: hanging protocol — CT study → 2-panel layout (axial + CPR) ## Mode: @ambientwork/ohif-mode-dental-cpr - Routes to 'dentalCPR' path - Creates 'dentalCPRToolGroup', registers DentalArchSplineTool with primary mouse button binding - isValidMode: CT modality only ## Docker - Dockerfile.ohif: multi-stage build (node:20 + OHIF v3.9.2 clone + yarn build + nginx:1.27); deterministic yarn@4.0.2; App.tsx patch fails loudly (exit 1) - docker-compose.yml: viewer-custom service (commented), drop-in replacement for ohif/app when dental CPR is needed ## Technical notes - vtkImageCPRMapper wiring follows PR #1689 fix (factory registration) - Quaternion orientation (4 components) used for PointData array - Camera at (0, 0, arcLength×2) with parallel projection Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… + FDI picker panel
…pling (8 tests passing)
- NerveCanalTool: add z-slice proximity guard — skip safety margin line when canal and implant annotations are on different slices (prevents misleading 3D distances in 2D clinical display) - DentalArchSplineTool: reset isDrawing/currentAnnotationUID on onSetToolPassive() to prevent state leak when switching tools mid-draw - DentalCPRViewport: add TODO comment for multi-instance window event scope - buildCenterline: export catmullRomSpline() and mat3ToQuat() for testing; add Jest setup + 6 unit tests covering spline correctness and all 4 Shepperd quaternion branches - huSampling: guard estimateBoneThickness() against empty array (was NaN) - tests: add 5 missing coverage cases (empty HU, all-above-threshold, getToothInfo null, 2 new buildCenterline tests) Tests: 8 → 17 (+9 new), all passing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dockerfile.ohif (Schritt 1): - Upgrade builder to node:22-slim - Extract registration logic to scripts/ohif/register-packages.js and scripts/ohif/register-plugins.js — no more inline heredocs - Two-path registration: pluginConfig.json (official OHIF v3 mechanism) + App.tsx anchor-patch as fallback - Dedicated nginx config: config/nginx/ohif.conf (SPA routing + cache headers) Cross-Section Viewport (Schritt 2): - DentalCrossSectionViewport.tsx — vtkImageReslice cuts CBCT perpendicular to arch tangent at a user-selected position - Direction cosines: N=output-x, B=output-y, T=slice-normal (arch tangent) - 40×40 mm at 0.3 mm/px; bone window W=2000 L=400 - Fires/listens to ARCH_CROSS_SECTION_POSITION events 3-Panel Layout (Schritt 3): - cbctDentalHP: 2×2 grid — axial (top-left), CPR (top-right), cross-section (bottom full-width) - modes/dental-cpr-mode: adds cross-section viewport + dental-tools panel - DentalCPRViewport: click handler maps canvas X → spline index → fires ARCH_CROSS_SECTION_POSITION with Frenet frame data buildCenterline: - Export buildCenterlinePoints() — returns pure-JS Frenet frames (no vtk.js dep) for use in click-handler event payload docker-compose.yml (Schritt 4): - viewer service now uses ambientct/ohif:latest (custom build, port 3000) - viewer-stock: pre-built ohif/app:v3.9.2 on port 3001 for quick testing Docker build (Schritt 5): Running in background → /tmp/docker-build.log Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Build failures fixed in order: 1. SSL: add ca-certificates to apt-get (git clone failed) 2. register-packages.js: use process.cwd() instead of __dirname (scripts copied to /tmp, __dirname pointed to wrong path) 3. register-plugins.js: use process.cwd(); App.tsx Step B now non-fatal when pluginConfig.json registration succeeded 4. node-gyp: add python3 make g++ for native addon compilation 5. JSX transpilation: add compile-extensions.js pre-build step that uses @babel/core from OHIF's node_modules to transpile dental-cpr (TSX) and dental-tools (JSX) before webpack runs. OHIF's webpack babel-loader excluded workspace symlinks. modules:false preserves ESM import syntax so @cornerstonejs exports fields resolve correctly. Result: webpack 5.94.0 compiled with 14 warnings, 0 errors. Image: ambientct/ohif:latest — 194MB nginx serving OHIF dist. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Mark Docker build as ✅ verified (2026-03-24) - webpack 5.94.0 compiled 0 errors, 14 warnings - Image: ambientct/ohif:latest (194MB) - Document build fixes: ca-certificates, process.cwd(), compile-extensions.js - Mark DentalCPRViewport, DentalCrossSectionViewport as build-OK but runtime-unverified (needs real CBCT data test) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- FROM node:22-bookworm AS builder (was node:22-slim) - Clone target: /ohif (was /build/ohif) - WORKDIR /ohif (was /build/ohif) - FROM nginx:alpine (was nginx:1.27-alpine) - Remove python3/make/g++ from apt-get (bookworm has them built-in) - Remove corepack prepare — let corepack auto-detect yarn version from OHIF repo - Remove generate-plugin-config optional step (not needed) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
@ambientwork/ohif-extension-dental-cpr@ambientwork/ohif-extension-dental-tools(nerve canal, tooth annotation, bone thickness, implant planning)Dockerfile.ohifmulti-stage: node:22-slim builder + nginx:1.27-alpine runnerARCH_CROSS_SECTION_POSITION→DentalCrossSectionViewportupdates viavtkImageResliceDocker Build
Build fixes resolved across 9 iterations:
ca-certificatesin apt-getprocess.cwd()instead of__dirname(scripts run from/tmp)register-plugins.js: Step B (App.tsx patch) non-fatal when pluginConfig.json succeededpython3 make g++for native addon compilationscripts/ohif/compile-extensions.jspre-builds extensions with@babel/corefrom OHIF's node_modules (modules: falsepreserves ESM for@cornerstonejsexports fields)Test Coverage
extensions/dental-cpr/tests/buildCenterline.test.ts— 6 tests (catmullRomSpline, mat3ToQuat, all 4 Shepperd branches)extensions/dental-tools/tests/boneThickness.test.js— 4 tests (including empty array guard)extensions/dental-tools/tests/fdi.test.js— 4 tests (including boundary: fdi(0)=null, fdi(99)=null)Architecture
Known Open Points (Runtime Verification Needed)
vtkImageResliceimport path@kitware/vtk.js/Imaging/Core/ImageReslice— webpack OK, vtk.js runtime not yet tested with real CBCT datavtkImageCPRMapperpanoramic rendering — webpack OK, runtime binding to cornerstone3D viewport not yet verifiedtriggerAnnotationModified/triggerAnnotationCompletedAPI — these are now atannotation.triggerAnnotationModifiedin this @cornerstonejs/tools version (14 webpack warnings document this)See
docs/DENTAL-FEATURES-ROADMAP.mdfor full status table.Test plan
npm testin extensions)docker build -f Dockerfile.ohif -t ambientct/ohif:latest .— 0 errorsdocker compose up -dand verify viewer loads at http://localhost:3000🤖 Generated with Claude Code