-
-
Three receding edges land on the vanishing point. One misses by six degrees, and the number is the point.
-
Two Cloud Run services over HTTP. Gemini 3.5 Flash on Vertex AI teaches; all persistent state lives in Firestore, append-only.
-
Conic perspective: 4.5° average convergence error, 20.3° on the worst line. The green badge is earned per critique, amber if none answered.
-
Isometric: X should be 30.0°, measured 36.0°, systematic +6.0° across all 17 edges. A set square placed wrong, not an unsteady hand.
-
A Monge plate whose plan sits 18 px sideways: one placement mistake every vertex inherits, reported once, with no orphans.
-
A page of notes, uploaded by mistake. Gemini declines before anything is measured, in its own words. Nothing was measured.
-
Progression read from Firestore, not from a fixture. The counts are low because every one of them is a real drawing.
-
The same engine in Spanish: the critique is written in the student's language, not translated. Note 0,4° rather than 0.4°.
-
Step one of three. Eleven calibration samples, each tagged with the system it belongs to, because that decides how it is measured.
-
The calibration set: errors injected at known angles, which is what the golden tests assert against.
Inspiration
Descriptive geometry — sistemas de representación, the Monge tradition — is a first-year subject in architecture, engineering and animation degrees. It has a property most drawing subjects do not: correctness is objective. An isometric axis is at 30° or it is not. A point's plan lies on the reference line dropped from its elevation or it does not. Nothing depends on an examiner's taste.
So I read eighteen published syllabi and rubrics — Spanish public engineering and architecture
schools, Carnegie Mellon's 48-175, Sheridan College, open courseware. The finding is documented in
docs/PEDAGOGY.md:
Not one of them states a numerical tolerance.
The discipline defines correctness precisely and then hands the checking to a person with a set square at the end of a stack of plates. Meanwhile a general-purpose multimodal model asked to critique a drawing will happily invent the number — "your angle is off by about 15 degrees" — with no spatial ground truth behind it.
Atelier sits in that gap, and the scope is narrow on purpose: it automates the objective verification the discipline already defines. It does not invent a new criterion.
What it does
A student photographs a construction. Before anything is measured, Gemini 3.5 Flash looks at the page and answers two questions: is this an exercise at all, and which system is it. A shopping list is declined in the model's own words, and nothing is measured.
Then the matching engine runs. Atelier measures three of the four systems of representation, and what separates them is not difficulty but where the reference comes from — which sets a ceiling on how far each result can be trusted:
| System | Reference | Trust |
|---|---|---|
| Conic perspective | Inferred — RANSAC estimates the vanishing point from the student's own lines | Weakest. A consistently wrong drawing yields a vanishing point that agrees with it, and the reported error shrinks |
| Orthographic (diédrico) | Read off the page — the ground line is a line the student drew | Middle. Nothing is guessed, but a crooked ground line skews everything, so its tilt is reported separately |
| Axonometric | Given — the axes are constants of the projection system | Strongest. Nothing is estimated at all |
That ranking is stated in the documentation rather than hidden, and it is measurable: in the golden case an error injected at exactly 6° comes back at 6.00°, asserted to within 0.05°. The perspective suite cannot hold a bound that tight, and says so.
The critique is then split into two planes that may not mix. Plane A carries only figures OpenCV produced. Plane B carries what a teacher would say and is forbidden a number at all. An anti-hallucination validator asks the analysis what it measured and rejects any figure the model did not get from that set — then regenerates with corrective feedback.
The collaborative loop is four verbs: ASK before measuring, GUIDE to the next exercise from a ladder documented in published curricula, CAPTURE explicit feedback as an immutable Firestore event, and ADAPT the profile from that event stream. The profile is a difficulty level, not a person.
How I built it
atelier-agent— Python 3.12 + FastAPI on Cloud Run. Three OpenCV engines (geometry.py,axonometry.py,dihedral.py), a two-stage pre-router, the validator, and the append-only memory model.Atelier.Web— Blazor Server on .NET 10, also on Cloud Run. Three-step flow, one viewer per projection system, bilingual EN/ES with the language travelling with the request so the critique is written in the student's language rather than translated afterwards.- Gemini 3.5 Flash on Vertex AI (
europe-west3) for the vision gate and the critique, called through the Google GenAI SDK. - Gemma 4 (
gemma-4-26b-a4b-it) through the Gemini API, routing intent from the student's own words. - Firestore as the append-only store — every exercise and every feedback event, never updated in place. Plus Cloud Storage + Eventarc for asynchronous ingestion and Cloud Scheduler for the weekly digest, so the agent works with nobody at the keyboard.
Challenges I ran into
The mean of an empty set is not zero. Twice — in the orthographic engine and again in the
progress profile — an average computed over nothing was reported as 0.00, which reads as
perfect. A plate whose two views did not correspond at all reported a correspondence error of
zero: a worse drawing produced a better number. Both aggregates are nullable now and render as
a dash.
Silent fallbacks make a broken system look healthy. The critique path once caught every
exception and returned a hand-written template stamped validated=true with the real model's name
on it. Deleting Vertex AI from the project would have changed nothing observable. Provenance is now
stamped by the server, never by the model, and the green badge is gated on it.
A schema that cannot express the answer produces no answer. The intent router still offered only the conic taxonomy after the axonometric and orthographic engines shipped. Asking it to classify "an isometric cube" into a set with no axonometric member did not return something wrong — it returned nothing at all, for 300 seconds, and what eventually unblocked the interface was the HTTP client's 100-second default. Three of the eleven calibration samples are parallel projections, so any user describing what they opened would have hit it. Fixed by extending the taxonomy to the three systems and putting a deadline on the call.
Vertex AI region. gemini-3.5-flash is not published in the Cloud Run region, and pointing
Vertex at the service's own region made every critique fail into a silent fallback for days. The
two are configured separately now, and the video says so out loud.
Accomplishments I'm proud of
The golden case: an error injected at exactly six degrees comes back at exactly six, and the critique separates a systematic deviation from a per-line one — which lets it say something no published rubric can: your hand is steady, the set square was placed wrong, and the fix happens once before drawing rather than edge by edge.
And the refusal. Measuring the wrong thing carefully is worse than declining to measure it.
What I learned
For technical disciplines — drawing, engineering, surgery — use computer vision for ground truth and a language model for teaching, and make the boundary between them something the code enforces rather than something the prompt requests.
And that the useful failures are all about honesty rather than about models: a figure that looks like success when nothing was measured is not a formatting detail, it is the failure mode.
What's next
Planos acotados — the fourth system — needs the numeric annotations read off the page, which is OCR rather than line geometry. Cylinders and ellipses, cast shadows, and true magnitudes (abatimientos, giros, cambios de plano) are each documented as measurable in principle and unimplemented in fact, in the README's gaps table. The agent does not prescribe a rung the engine cannot yet assess.
Log in or sign up for Devpost to join the conversation.