<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hugo Valer</title>
    <description>The latest articles on DEV Community by Hugo Valer (@hugo_valer_79d0d94e00804b).</description>
    <link>https://dev.to/hugo_valer_79d0d94e00804b</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2416269%2Fb24de9e5-7017-4e3c-bec3-1a1330309a29.jpg</url>
      <title>DEV Community: Hugo Valer</title>
      <link>https://dev.to/hugo_valer_79d0d94e00804b</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hugo_valer_79d0d94e00804b"/>
    <language>en</language>
    <item>
      <title>The Geometry Measures, the AI Teaches: An Agent That Verifies Descriptive-Geometry Constructions, with the Google GenAI SDK, Vertex AI &amp; OpenCV</title>
      <dc:creator>Hugo Valer</dc:creator>
      <pubDate>Wed, 19 Aug 2026 06:34:55 +0000</pubDate>
      <link>https://dev.to/hugo_valer_79d0d94e00804b/the-geometry-measures-the-ai-teaches-building-an-art-studio-tutor-with-adk-vertex-ai-opencv-551m</link>
      <guid>https://dev.to/hugo_valer_79d0d94e00804b/the-geometry-measures-the-ai-teaches-building-an-art-studio-tutor-with-adk-vertex-ai-opencv-551m</guid>
      <description>&lt;h2&gt;
  
  
  1. The origin: a discipline that defines correctness and never measures it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Descriptive geometry&lt;/strong&gt; — &lt;em&gt;sistemas de representación&lt;/em&gt;, the tradition Gaspard Monge formalised in&lt;br&gt;
the 1790s — is a first-year subject in architecture, engineering and animation degrees. It has a&lt;br&gt;
property most drawing subjects do not: &lt;strong&gt;correctness is objective.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An isometric axis is at 30° or it is not. A point's plan lies on the reference line dropped from its&lt;br&gt;
elevation or it does not. A rabatment recovers the true length or it does not. Nothing here depends&lt;br&gt;
on an examiner's taste, and the check is itself a construction rather than an opinion. The&lt;br&gt;
assessment rules reflect that: the Universidad de Granada requires a &lt;strong&gt;minimum of 5/10 in each block&lt;br&gt;
independently&lt;/strong&gt;, and the Universidad de Salamanca states plainly that &lt;em&gt;"es necesario superar cada&lt;br&gt;
bloque de forma independiente"&lt;/em&gt;. You cannot compensate a failed system with a strong one, because&lt;br&gt;
these are not matters of degree.&lt;/p&gt;

&lt;p&gt;So I went and read the syllabi — eighteen published sources across Spanish public engineering and&lt;br&gt;
architecture schools, international animation programmes, and open courseware. The finding is in&lt;br&gt;
&lt;a href="//PEDAGOGY.md"&gt;&lt;code&gt;docs/PEDAGOGY.md&lt;/code&gt;&lt;/a&gt;, and it is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Not one of them states a numerical tolerance.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nowhere does a figure in degrees or millimetres appear as a pass mark. The closest any source comes&lt;br&gt;
is a Canadian animation degree that grades &lt;em&gt;"composition, perspective and colour, with speed,&lt;br&gt;
**accuracy&lt;/em&gt;* and dexterity"* — accuracy as a graded outcome of a four-year honours degree, with the&lt;br&gt;
curriculum never saying how accurate.&lt;/p&gt;

&lt;p&gt;The discipline defines correctness exactly, and then hands the checking to a person with a set&lt;br&gt;
square at the end of a stack of plates. Meanwhile a general-purpose multimodal model asked to&lt;br&gt;
critique a drawing will happily invent the number — &lt;em&gt;"your angle is off by about 15 degrees"&lt;/em&gt; — with&lt;br&gt;
no spatial ground truth behind it at all.&lt;/p&gt;

&lt;p&gt;Atelier sits in that gap, and the scope is narrow on purpose:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;It automates the objective verification the discipline already defines. It does not invent a new&lt;br&gt;
criterion.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The invariant the whole system is built on:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"The geometry measures, the AI teaches, the student grows." (ADR-001)&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  2. Architecture: three systems, three kinds of reference
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                              ATELIER ARCHITECTURE

 ┌────────────────────────┐      ┌──────────────────────────────────────────────┐
 │  Atelier.Web           │      │  Vision gate — Gemini 3.5 Flash (Vertex AI)  │
 │  Blazor Server/.NET 10 │ ───&amp;gt; │  Is this an exercise at all?                 │
 │  - 3-step flow         │      │  Conic / axonometric / orthographic?         │
 │  - per-system viewers  │      └──────────────────────────────────────────────┘
 │  - append-only history │                            │
 └────────────────────────┘        ┌───────────────────┼───────────────────┐
             ▲                     ▼                   ▼                   ▼
             │            ┌────────────────┐  ┌────────────────┐  ┌────────────────┐
             │            │ geometry.py    │  │ axonometry.py  │  │ dihedral.py    │
             │            │ CONIC          │  │ AXONOMETRIC    │  │ ORTHOGRAPHIC   │
             │            │ RANSAC VPs     │  │ fixed axes     │  │ ground line +  │
             │            │ k = 1, 2       │  │ 30 / 90 / 150  │  │ correspondence │
             │            └────────────────┘  └────────────────┘  └────────────────┘
             │                     └───────────────────┼───────────────────┘
             │                                         ▼
 ┌────────────────────────┐      ┌──────────────────────────┐   ┌────────────────────┐
 │  Collaborative loop    │ &amp;lt;─── │  Anti-hallucination      │ &amp;lt;─│  Gemini 3.5 Flash  │
 │  ASK / GUIDE           │      │  validator               │   │  Two-plane critique│
 │  CAPTURE / ADAPT       │      │  measured_values()       │   │  Level-aware rubric│
 └────────────────────────┘      └──────────────────────────┘   └────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Atelier measures &lt;strong&gt;three of the four systems of representation&lt;/strong&gt;. The fourth, contoured planes&lt;br&gt;
(&lt;em&gt;planos acotados&lt;/em&gt;), needs the numeric annotations read off the page — OCR rather than line geometry — and is documented&lt;br&gt;
as not implemented.&lt;/p&gt;

&lt;p&gt;What makes them worth having together is that they are not one tool three times. &lt;strong&gt;They differ in&lt;br&gt;
where the reference comes from&lt;/strong&gt;, and that determines how far each measurement can be trusted:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;System&lt;/th&gt;
&lt;th&gt;Where the reference comes from&lt;/th&gt;
&lt;th&gt;Trust&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Conic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Inferred.&lt;/strong&gt; RANSAC estimates a vanishing point from the student's own lines&lt;/td&gt;
&lt;td&gt;Weakest — a consistently wrong drawing yields a vanishing point that agrees with it, and the reported error shrinks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Orthographic&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Read off the page.&lt;/strong&gt; The ground line is a line the student drew&lt;/td&gt;
&lt;td&gt;Middle — nothing is guessed, but a crooked ground line skews everything, so its tilt is reported as a figure in its own right&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Axonometric&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Given.&lt;/strong&gt; The axes are constants of the projection system&lt;/td&gt;
&lt;td&gt;Strongest — nothing is estimated at all&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That ranking is stated in the documentation rather than hidden, and it is measurable: in the golden&lt;br&gt;
case an error injected at exactly 6° comes back at &lt;strong&gt;6.00°&lt;/strong&gt;, asserted to within 0.05°. The&lt;br&gt;
perspective suite cannot hold a bound that tight, and says so.&lt;/p&gt;

&lt;h3&gt;
  
  
  The two-plane critique
&lt;/h3&gt;

&lt;p&gt;Every critique is split into two planes that may not mix:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Plane A — measured findings.&lt;/strong&gt; Every figure comes from OpenCV, verbatim.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plane B — studio observations.&lt;/strong&gt; Line weight, spatial legibility, cleanliness. &lt;strong&gt;Forbidden a
number at all.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An &lt;strong&gt;anti-hallucination validator&lt;/strong&gt; intercepts the model's answer. It asks the analysis what it&lt;br&gt;
measured — &lt;code&gt;measured_values()&lt;/code&gt; — rather than reading named fields, which is what lets a new&lt;br&gt;
projection system be added without silently arriving unguarded. Any figure the model did not get&lt;br&gt;
from that set is rejected and regenerated with corrective feedback.&lt;/p&gt;

&lt;p&gt;The prose gate is bilingual for a reason that is easy to miss: a detector that only recognises&lt;br&gt;
&lt;code&gt;degrees&lt;/code&gt; stops being a gate the moment the interface is translated. It recognises &lt;code&gt;grados&lt;/code&gt; too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Two models, two jobs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gemini 3.5 Flash&lt;/strong&gt; (Vertex AI, &lt;code&gt;europe-west3&lt;/code&gt;) looks at the photograph twice: once as a gate —
&lt;em&gt;is this an exercise, and which system?&lt;/em&gt; — and once to write the critique.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gemma 4&lt;/strong&gt; (&lt;code&gt;gemma-4-26b-a4b-it&lt;/code&gt;, via the Gemini API — it is not published on Vertex AI) reads
the student's own description and infers which perspective they meant.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the two disagree, &lt;strong&gt;the words do not win.&lt;/strong&gt; An early version re-measured on the router's&lt;br&gt;
say-so, and a one-point box described as "the corner of a building" came back as two-point with 29.9°&lt;br&gt;
of average error. The measurement is evidence; the description is a claim. Atelier now reports the&lt;br&gt;
disagreement and changes nothing.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. The four verbs of "The Collaborative Partner"
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;ASK&lt;/strong&gt; — before analysing: &lt;em&gt;"What were you practising today? Which part felt hardest?"&lt;/em&gt; The
answers set the register of the critique. They never change the measurement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GUIDE&lt;/strong&gt; — the next exercise comes from a ladder documented in published curricula, not invented
to fill a JSON field. Rungs the engine cannot yet assess are recorded as gaps and deliberately
not prescribed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CAPTURE&lt;/strong&gt; — explicit feedback (&lt;code&gt;helpful: bool&lt;/code&gt; + note) persisted as an immutable event in
Firestore (ADR-005).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ADAPT&lt;/strong&gt; — the profile is derived from the event stream, never edited. Note that the profile is a
&lt;strong&gt;difficulty level&lt;/strong&gt;, not a person: it sets the rubric's register and nothing else.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  4. Asynchronous pipeline and Cloud Run deployment
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Async-first ingestion&lt;/strong&gt; — a photograph dropped into a private Cloud Storage inbox
(&lt;code&gt;atelier-hack-inbox/{studentId}/&lt;/code&gt;) fires an Eventarc CloudEvent at the Cloud Run agent, which
downloads the object, measures it and stores the result with nobody touching the app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weekly digest&lt;/strong&gt; — Cloud Scheduler aggregates the week and prescribes a three-day practice plan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The measurement API&lt;/strong&gt; — &lt;code&gt;POST /api/analyze&lt;/code&gt;, &lt;code&gt;/api/analyze/axonometric&lt;/code&gt;, &lt;code&gt;/api/analyze/dihedral&lt;/code&gt;,
plus &lt;code&gt;/api/router/gate&lt;/code&gt; and &lt;code&gt;/api/router/classify&lt;/code&gt; for the two routing decisions, and
&lt;code&gt;GET /api/students/{id}/exercises&lt;/code&gt; for the student's own history.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production hardening&lt;/strong&gt; — Cloud Run with .NET 10 (&lt;code&gt;KnownIPNetworks.Clear()&lt;/code&gt; for proxy header
termination) and Python FastAPI.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
