I fell down a rabbit hole last weekend and came back with a thing: CETsize â a tiny web app that measures whale body length from drone photos, right in your browser, no uploads, no servers.
Live: whales.luisg.me
Hereâs a quick peek at the app UI â load a photo, zoom/pan, and lay down straight or curved measurements:
This started with Jan Hofmanâs R program (massive shoutâout đ). I loved the idea and wanted something biologists could run anywhere without installing R or touching a terminal. Also⌠Iâve been exploring agents + GitHub Copilot, so this was the perfect excuse to see how far I could push a browserâonly build.
The plan
- Keep everything clientâside (privacy first).
- Read the metadata we already have (EXIF/XMP/DNG).
- Do the math once and make the UI feel nice (zoom/pan, stable handles).
- Ship it fast on Cloudflare Pages.
What it actually does
- Parses image metadata inâbrowser:
- EXIF: GPSAltitude (MSL), focal length, image width
- DJI XMP: RelativeAltitude and other goodies when present
- DNG/TIFF: basic tag parsing + preview extraction
- Measures:
- Straight distance (two points)
- Curved length (polyline) â handy for following body curvature
- Stays readable at any zoom (handles/lines donât scale visually)
- Exports results as JSON or CSV
- Has a builtâin sensor width cheatâsheet (by camera/module codes like DJI FC####), with manual override
The math (aka turning pixels into meters)
Take altitude, focal length, sensor width, and image width; produce a metersâperâpixel scale. Prefer AGL when available; otherwise EXIF GPSAltitude (MSL) is used with a clear hint to doubleâcheck.
This is the panel where you can review/override camera parameters (sensor width, focal length, altitude) when metadata is missing or needs correction:
Roughly:
meters_per_px = altitude_m * (sensor_width_mm / focal_length_mm) / image_width_px
All calculations happen in original image pixels to avoid rounding issues. The overlay is SVG on top, but the math stays in image space.
The fun bits
- Zoom/pan that feels natural (cursorâcentered zoom).
- Nonâscaling UI: control points and stroke widths stay readable at any zoom.
- Gentle âguard railsâ: if we canât find sensor width or focal length, the app asks â youâre always in control.
Agents + Copilot as coâpilots
I used agents and GitHub Copilot to:
- Scaffold components fast (the measurement overlay came together in hours, not days).
- Iterate on EXIF/XMP/DNG parsing without yakâshaving libraries.
- Fuzz edge cases (missing EXIF, 35mmâeq only, negative altitudes).
- Draft tests and error messages, then I tightened them up.
The human bits were the important ones: picking the architecture, validating the math, and polishing the UX.
Tech + deployment
- Frontend: React + SVG overlay
- Parsing: lightweight EXIF/XMP/DNG utilities tailored for the browser
- Node 18+ toolchain
- Cloudflare Pages for deploys (push â build â live)
Whatâs next
- More camera presets
- Optional annotated export (image + overlay)
- Mobile polish
- A short guide for consistent field workflows
If you work with drone imagery or marine biology and have ideas, Iâd love to hear them.
Live app: whales.luisg.me
Huge thanks again to Jan Hofman for the original R inspiration. This was a fun weekend ship â and a neat exploration of what orchestrating an agentic LLM feels like.