The Problem: When Legacy Code Meets Modern Needs
The original cephalometric analysis tool worked, but it was slow. 30+ second build times, sluggish UI, and technology from 2018. As a developer working in healthcare technology, I modernized this legacy application - and the results were dramatic.
The results: 30+ second builds → <1 second HMR, 100% class components → modern React hooks, and 100% backward compatibility maintained. The result is Ortho Cephalometry.
What is Cephalometric Analysis?
Cephalometric analysis is the science of measuring facial structures - how teeth, jaws, and facial bones relate to each other. Orthodontists use lateral cephalogram X-rays to:
- Measure angles and distances between anatomical landmarks
- Assess skeletal and dental relationships
- Plan treatment (braces, aligners, surgery)
- Track progress over time
The analysis involves placing specific points on X-ray images and calculating measurements using methods like Downs Analysis, Steiner Analysis, Tweed's Triangle, and more. Accuracy and speed matter - these measurements directly impact treatment decisions.
The Modernization Journey
Before → After
Original Stack (from 2018):
- Webpack 4 (30+ second builds)
- React 16 (class components)
- TypeScript 2.9
- TSLint (deprecated)
- node-sass
- MobX 5
Modern Stack:
- Vite 5 - <1 second HMR
- React 18 - Functional components with hooks
- TypeScript 5 - Better type inference
- ESLint - Modern linting
- Sass (Dart Sass) - Latest compiler
- MobX 6 - Latest state management
Key Improvements
- Build Times: 30+ seconds → <1 second for HMR
- Component Architecture: 100% migration to functional components with hooks
- Type Safety: TypeScript 5 caught several bugs during migration
- Developer Experience: Comprehensive Makefile for easy project management
The Challenge: 100% Backward Compatibility
We maintained complete compatibility - same file format, same iframe protocol, identical analysis results. Users can migrate without losing any data. Zero breaking changes.
Features
- Interactive Point Placement: Upload X-rays and place anatomical points with drag-and-drop
- 9+ Analysis Methods: Downs, Steiner, Tweed, Wits, and more
-
Save & Load:
.cephalometricformat for tracking patients over time - Export: PNG export for patient reports
- Embeddable: iframe support for integration into larger systems
Technical Highlights
MobX 6 for reactive state management - when points are placed, calculations update automatically:
import { observer } from 'mobx-react-lite';
export const Main = observer(() => {
// Automatically re-renders when observable data changes
return <AnalysisView />;
});
Modern React Hooks - clean, testable code:
useEffect(() => {
window.onmessage = function (e) {
if (e.data?.startsWith('cephalometric-open:')) {
data.loadProject(parseProjectData(e.data));
}
};
}, []);
TypeScript 5 caught several undefined point errors during migration that would have been runtime bugs.
Getting Started
Prerequisites
- Node.js 18+ and npm
- Make (usually pre-installed on Unix-like systems)
Quick Start
# Clone and install
git clone https://github.com/tjandrayana/ortho-cephalometry.git
cd ortho-cephalometry
make install
# Run dev server (background)
make dev-bg
# Check status, view logs, or stop
make status
make logs
make stop
The app runs at http://localhost:3000 with instant HMR thanks to Vite.
Key Makefile Commands: make install, make dev-bg, make build, make preview, make lint, make clean
Alternative: Use npm scripts directly (npm install, npm run dev, etc.)
Project Structure
ortho-cephalometry/
├── src/
│ ├── data/ # MobX state management
│ ├── literature/ # Cephalometric definitions
│ │ ├── analysis/ # Analysis methods
│ │ ├── angles.ts # Angle definitions
│ │ ├── distances.ts # Distance measurements
│ │ └── points.ts # Point definitions
│ ├── view-components/ # React components
│ └── main.tsx # Entry point
├── Makefile # Build automation
└── vite.config.ts # Vite config
Migration Notes
100% backward compatible - existing .cephalometric files work perfectly. Same file format, same iframe protocol, identical analysis results. Users can migrate seamlessly.
Use Cases
- Orthodontic Clinics: Daily diagnostic analysis
- Dental Schools: Educational tool for teaching
- Research: Data collection and analysis
- Practice Management: iframe integration into larger systems
Lessons Learned
What worked: Vite over Webpack (build time improvement was huge), sticking with MobX (perfect for reactive calculations), the Makefile (small QoL improvements matter), 100% backward compatibility (zero migration pain).
What I'd do differently: Start with TypeScript 5 directly (incremental upgrade was slower), convert components in batches (more efficient), add more tests before migration (would catch issues earlier).
Conclusion
Modernizing this application created a tool that saves time, reduces errors, improves maintainability, and enhances developer experience. The result serves the orthodontic community while being a pleasure to develop with.
If you're working in healthcare technology or modernizing legacy applications, I hope this project serves as a useful reference. The techniques apply to any legacy React application.
Check it out: Repository | Original Project | Original Demo
Note: This tool is intended for professional use by qualified dental professionals. Always ensure proper training and understanding of cephalometric analysis before using in clinical practice.

Top comments (0)