Declarative diagram spec to clean, themeable SVG. Thirteen diagram kinds, no coordinates in the format, writable by an LLM.
drawspec exists because 89 study diagrams were written by hand in SVG and a human reviewing them found the same faults over and over — arrow heads with no shaft, lines that miss their box, text outside its box, a different type size in every figure. Those faults are what the nine kinds and the fit engine are for.
This document asks the other question. Not are the drawings correct, but could drawspec have drawn them at all. It is an inventory of the same 89 originals against the nine kinds, and of the gap that inventory showed.
All five gaps are now closed.
group,matrix,curve,quadrantandfunnelare implemented, each with a reference drawing indocs/reference/and tests that fail without it. The counts below are the state before that work — they are what the decision was made on, and they are left as they were so the reasoning stays readable. Each section says what it turned into.
Where the originals are. They are the
<svg>blocks inline in the opos temario, extracted tooriginals/(gitignored — they are study material, not source, and they belong to the other project).originals/index.jsoncarries each one’s title, the reviewer’s note, its element counts, and the kind this document assigns it.
68 of the 89 are drawable by a kind drawspec already has. 21 are not.
| Kind | Originals | Have it? |
|---|---|---|
| flow | 33 | yes |
| cycle | 9 | yes |
| 6 | now yes | |
| stack | 5 | yes |
| 5 | now yes | |
| timeline | 4 | yes |
| tree | 4 | yes |
| columns | 4 | yes |
| pyramid | 4 | yes |
| rings | 4 | yes |
| 3 | now yes | |
| 2 | now yes | |
| 2 | now yes | |
| picture | 2 | out of scope |
| chart | 1 | yes |
| spans | 1 | no |
The assignment is judgement, made by rendering all 89 and looking at them; it is
recorded per-diagram in originals/index.json under wants. The long tail is
real but it is a tail: flow alone accounts for a third of the corpus, and the
nine kinds between them cover more than three quarters of it.
Ordered by how many originals need them.
groupThe single largest gap, and the least exotic. A Kubernetes control plane holding five components; sector públic holding three peers and a sub-frame holding two more; a medallion architecture holding bronze, silver and gold. The container has its own caption, it nests, and edges cross its boundary to reach what is inside.
This was probably not a kind, and it turned out not to be one. It is a
container over the graph kinds: a flow or a tree gains one by naming
members, and everything else about the drawing is unchanged.
It also turned out to be mostly already there. The schema had declared groups
since v1 and the theme had declared a dashed, unfilled group role since v1 —
nothing had ever drawn either. What was missing between them is
drawspec.kinds.containers, and three decisions it had to make:
See docs/reference/flow-groups.json for the reference drawing.
Originals: estado__administracion-publica,
tic__devops-cicd-contenedores-y-kubernetes,
tic__arquitectura-de-datos-dw-lake-lakehouse,
tic__practicas-itil-de-entrega-de-servicios,
tic__trabajo-documental-sharepoint-y-onedrive,
tic__practicas-itil-de-soporte-al-servicio.
matrixThe shared-responsibility model: three columns (IaaS, PaaS, SaaS), a stack of cells in each, and each cell filled to say who manages it. RAID block layouts. The TCP/IP encapsulation bands, where each layer’s row is segmented and the segments line up down the figure.
What it needed beyond columns: both headings, cells that span, and a fill
vocabulary. The vocabulary arrived with the chart marks and is shared with them
([mark] fills), which is why this came second.
The interesting part was what an author is allowed to say. fill is in the
schema’s rejection table — appearance is a property of the role, not of the
element — and a matrix does not get an exemption just because its whole content
is a comparison. So a cell names a group, and the theme turns groups into
fills in order of first mention. The author says which cells are the same kind of
cell; drawspec decides what that looks like. The test suite caught the first
attempt, which had the author naming the fill.
Two more decisions: the matrix’s extent is derived from its cells, so a cell spanning three columns makes a three-column matrix and there is no “reaches outside” error to write — only a negative index is refusable. And a spanning cell is charged to the last row it covers, so a two-row cell asks for the two rows together rather than making each of them as deep as itself.
The reviewer’s note on the original was the warning to design against: “the
hatching is too strong and client is hard to read”. Every pattern is drawn
faint; the reference drawing has body text over both fills.
See docs/reference/matrix-responsibility.json.
Originals: tic__arquitecturas-de-seguridad-en-la-nube,
tic__computacion-hibrida-iaas-paas-saas, tic__sistemas-san-y-raid,
tic__tcp-ip-v4-y-mpls, tic__itil-v4-conceptos-y-cadena-de-valor.
curveThe Gartner hype cycle, the EVM S-curves, the sprint burn-down. These look like charts and are not: there are no numbers behind the hype cycle, only a named shape with five labelled waypoints on it. The burn-down has two series where one is a straight ideal and the other is the real line, each labelled where it ends.
It is its own kind rather than a chart option, and the reason is the one thing these three have in common: there are no numbers. So there are no ticks — drawing them would invite a reader to measure a shape somebody sketched — and a waypoint carries a name where a data point would carry a value.
Two decisions:
cycle already draws its arcs.
The smoothing is drawspec’s business; the reader’s renderer gets the shape
rather than a recipe for it.A curve’s name is drawn where it ends, and the names go down before the waypoint labels so a label at the end of a curve never lands on that curve’s own name.
See docs/reference/curve-hype.json and docs/reference/curve-burndown.json.
Originals: tic__prospeccion-de-soluciones-tic,
tic__pmbok-rendimiento-riesgos-y-cierre, barcelona__scrum-bit.
quadrantThe Thomas-Kilmann grid: cooperation against assertiveness, five named positions.
Tuckman’s model on a different pair of axes. Small, self-contained, and nothing
in the nine comes close — chart plots series against scales, not labelled points
against named directions.
It lives in the chart family and reuses its axis furniture unchanged, which is what made it small. Three decisions of its own:
across and up are data, not coordinates, in the same sense a chart’s
data is. The author says where a thing sits between two named directions.It also turned up a real bug in the chart: _segment_meets_box sampled a segment
at a fixed twenty-four points, which is fine for a chart’s short segments and
steps clean over a label when the segment is a midline running the height of the
plot. Sampling is now bounded by a spacing smaller than a label box.
Originals: tic__pmbok-liderazgo-equipo-y-recursos__0 and __1.
See docs/reference/quadrant-conflict.json.
funnelAn innovation funnel with three gates; a sales funnel from lead to account. A tapering band divided into stages, captioned at both ends, with the dividers drawn differently from the outline.
It was as close to pyramid as it looked: same trapezoid, same constant
progression, turned a quarter turn. What changes is which way the shape gives
when the text does not fit. A pyramid narrows to its apex, so its base is what
the labels buy; a funnel narrows to its mouth, so what they buy is its depth —
and unlike the pyramid it fills the canvas width, because a funnel that did not
would be a wedge in a corner.
The gates are drawn in the theme’s weak edge role rather than as the shared
sides of separate polygons. A gate is a threshold, not a wall: the band is
continuous and something passes through it, which is what a stage boundary in a
funnel means and what a solid line would deny.
See docs/reference/funnel-innovation.json.
Originals: tic__gestion-de-la-innovacion-sgi__1, tic__soluciones-crm.
spans — an axis of instants with nested labelled brackets over it (RPO, RTO,
WRT, MTD in the disaster-recovery diagram). One original. It is a real shape and
nothing draws it, but one is one; it may be better served by irregular timeline
spacing plus a bracket annotation than by a kind of its own.
Two originals are pictures: overlapping Wi-Fi cells, and one parcel of land drawn vector against raster. They are illustrations of a physical thing, not diagrams of a structure. drawspec should not try to draw them — a declarative document whose author has no coordinates is the wrong tool for a picture, and pretending otherwise is how a diagram language acquires an escape hatch that eats it.
The 68 are drawable, but several want something the kind does not have yet. These are cheaper than kinds and some are nearly free:
| Want | Where it shows | Kind |
|---|---|---|
done — the strong edge role, beside the emphasis node role |
flow | |
| A label inside a bar | the five stars of open data, each in its own column | columns |
| A caption under the axis | “depth of change in the organisation” | timeline |
done — give every entry an at |
timeline | |
| A dashed series, a label at the end of a line | ideal against real | chart |
done — mark: "bar" / "area", and stack |
chart | |
| A fork and a join | components in series against in parallel | flow |
| Straight edges where the mesh is the message | spine-leaf, every leaf to every spine | flow |
That last one is worth its own sentence, because it contradicts a rule. The review’s rule 5.3 is “right angles, not diagonals”, and it is right: a diagonal arriving at a box at a closed angle looks wrong, and orthogonal routing is why drawspec’s flow charts read cleanly. But in the spine-leaf diagram the twelve straight diagonals are the content — “every leaf connects to every spine” is legible as a lattice and illegible as twelve orthogonal routes threading a comb. A rule that good still has an exception, and the exception should be a declared edge style rather than a defeat.
group.Chart marks — done. The library question was the real content of
this item, so here is the answer and its reasons.
Keep hand-rolling. Not because writing marks is easy, but because nothing
an established library emits can pass through this pipeline. drawspec’s
emitter is the only styling point and it enforces the embedding contract: no
<style> element, namespaced ids, only theme-declared colours, no embedded
or referenced font, and a role on every primitive. matplotlib, plotly and
pygal each emit their own complete SVG with their own font handling and their
own style block — wrapping one means either abandoning the Scene seam for
charts, or post-processing foreign SVG, which is more work than the marks and
fails in more ways.
What a library really sells is statistical plotting, interactivity and thirty
chart types. drawspec wants none of those. What it wanted was a mark
abstraction so that the next mark is additive rather than a special case,
and that is what this is: mark: "line" | "bar" | "area", plus stack.
The one thing worth borrowing was the fill vocabulary, and it is now in the
theme as [mark] fills — an ordered sequence of patterns, distinct by
construction, that a mark takes by its own index. Which is exactly what
matrix needs next.
matrix.All five are done — group, matrix, curve, quadrant, funnel — along
with spans’ cousin still open and the two pictures still declined. The count at
the top of this document is the state before that work; what is left is the
features table above and the one limitation below.
One limitation found on the way and worth writing down: a chart series whose
highest and lowest points sit exactly on the plot’s edges can never label them —
above the top point is outside the plot, and below it crosses the curve — so the
all-or-nothing rule drops that series’ labels entirely. The fix is a vertical
margin on the scale, the way quadrant already has one. It is not done here
because it changes every existing chart drawing, and those have been reviewed.
This document asked could drawspec draw them at all, and answered by kind. It could not have found what follows, because the answer there was yes and the drawing still came out wrong.
riseMigrating the corpus for real turned up two originals that draw a scale by making each box taller than the last:
| Original | Geometry | Drawn as | What the document itself says |
|---|---|---|---|
| The five stars of open data | heights 30·60·90·120·150 |
columns |
each star adds a condition to the one before it |
| Degrees of digital transformation | heights 60·75·100, under an axis labelled depth of change |
timeline |
each degree changes more than the last |
columns gave five boxes of one height; timeline gave 51.7 · 51.7 · 66.55,
and the third only because its label took an extra line.
Nothing caught it. Not the word check — every word was present. Not the collision check — nothing crossed anything. Not the clipping check — everything was on the canvas. Those three answer is the text there and readable, and here the text was fine and the geometry was the message. The only thing that found it was putting the old drawing beside the new one and looking.
That is the general lesson, and it is worth more than the field: a kind that can hold every word of an original is not thereby the right kind for it. The inventory below sorts by what a kind can hold. It cannot sort by what a kind says.
rise closes both, and the second one is worth the correction. This paragraph
first said an ascending timeline was not the same field — a timeline’s boxes
sit on an axis, so what rises there is a label above a tick and not a column
from a baseline. Writing the code showed that was a distinction without a
difference: a timeline’s labels already all end at the axis, so the axis is
the common baseline and the ascent is the same arithmetic. One helper serves
both, and the only thing each kind decides is where its floor is.
Every original, the kind that would draw it, and the reviewer’s note where
there is one. * marks a kind drawspec does not have.
A struck-through kind is one this survey got wrong and the redraw corrected.
Fourteen of the eighty-nine moved — one in six. The survey was made by
counting shapes, and a diagram’s shapes are not always what it is saying: three
boxes in a row were called columns and turned out to be a stack, a chart and a
matrix; six activities joined by chords were called a matrix and are a graph; a
grid of customer-against-provider was called a matrix and is a proportion. The
lesson is the one the reviewer taught on the shared-responsibility model: read
what the original is saying before choosing the kind. group is not counted
as a move — it was never a kind, only flow carrying a groups field.
A struck-through kind is one this survey got wrong and the redraw corrected — the survey was made by counting shapes, and a diagram’s shapes are not always what it is saying. The comparison page shows both, so a reclassification is visible rather than quietly applied.
| Original | Wants | Reviewer’s note |
|---|---|---|
tic__pmbok-enfoques-y-ciclo-de-vida |
chart | |
cataluna__estatut-autonomia-catalunya |
||
estado__funcion-publica-y-trebep |
Margen inferior en cajas. “máxim 6 ANYS” está dentro del recuadro. Sin contexto no lo entiendo mucho, no sé si cada caja superior encaja con una inferior? | |
tic__datos-abiertos-y-reutilizacion |
columns | Sólo la última queda con las estrellas encima del título. A lo mejor podrían ir todas así. |
tic__dominios-de-datos-data-mesh |
Las cajas no están alineadas. Las de Domini sobresalen por la derecha. | |
barcelona__scrum-bit |
*curve | Es un poco feo, pero no sé muy bien por qué. Lo de ideal y real está en sitios extraños. |
tic__pmbok-rendimiento-riesgos-y-cierre |
*curve | Es un gráfico muy raro, los textos se solapan, hay flechas con sólo punta, no hay texto para el eje vertical… Revisar entero. |
tic__prospeccion-de-soluciones-tic |
*curve | Puntos fuera de la línea y texto atravesando líneas. El texto “productivity\nPlateau of” queda cortado y creo que el texto esperado sería “Plateau of productivity”. No quedan muy claros los ejes. |
barcelona__estrategia-municipal-de-algoritmos-y-datos |
“3. Contractació” (y todos en general) deberían ir centrados verticalmente? | |
estado__haciendas-locales-y-presupuestos |
cycle | Fatal en cuanto a márgenes y flechas y texto que no cabe. Revisar completo. |
tic__automatizacion-orquestacion-y-rpa |
cycle | Centrado verticalmente. Sólo hay una flecha con cabeza, no sé si es lo esperado. |
tic__certificados-digitales-y-eidas |
Márgenes y no queda claro dónde van “Signant” y “Verificador” | |
tic__gestion-de-incidentes-de-ciberseguridad |
cycle | Las flechas están todas mal. Como parece ser un ciclo, entiendo que tratan de simular un círculo, pero no aciertan. La frase “si hi ha indicis nous” queda cortada y no se ve entera, además de atravesar la línea. |
tic__gestion-de-la-innovacion-sgi__0 |
Flechas sin palo. | |
tic__gestion-del-riesgo-en-itil-v4 |
cycle | Flechas con palo demasiado corto. |
tic__gestion-financiera-de-los-servicios |
cycle | Si trata de ser un ciclo, OK, pero las flechas cruzan líneas y las curvas son extrañas. Valorar ángulos de 90 grados. |
tic__medicion-y-mejora-continua |
cycle | Las flechas no acaban en la caja. |
barcelona__municipio-y-regimen-especial-de-barcelona |
flow | Creo que las frases deberían empezar en mayúscula. Además, estar centradas verticalmente. Y “Presideix la Commissió…” no cabe en la caja. |
barcelona__prevencion-de-riesgos-y-lengua-catalana |
Puede que esté hecho a propósito, pero las flechas no tienen palo. Preferiría que lo tuvieran o bien que sean otro tipo de flechas. | |
estado__administracion-electronica |
flow | |
estado__administracion-general-del-estado |
flow | El texto de “Subdelegat del Govern” tiene interlineado irregular y no tiene margen inferior suficiente. |
estado__buen-gobierno |
flow | “Reclamació…” está debajo de todo y hay flechas que cruzan otras cajas. Si hace falta, haz el esquema vertical con flechas hacia abajo. |
estado__comunidades-autonomas |
flow | Margen inferior en “Competències…”. |
estado__cortes-defensor-y-tribunal-de-cuentas |
flow | Mismo problema de líneas atravesando. Mejor esquema en vertical. Margen inferior en “Veto s’aixeca…”. |
estado__el-gobierno |
flow | Flechas sin palo, Investit debería ir centrado verticalmente. Márgenes inferiores y texto que se sale. |
estado__poder-judicial |
flow | |
tic__administracion-electronica-y-servicios-digitales |
flow | Triángulo raro en “Accés al contingut?”. Texto que se solapa en “No, en 10 dies naturals”. |
tic__analitica-de-datos-y-business-intelligence |
flow | |
tic__arquitectura-de-microservicios |
flow | No sé de dónde debe salir la caja de “API Manager” |
tic__arquitecturas-de-seguridad-on-premise |
flow | Una flecha sin palo. |
tic__catalogo-de-servicios-y-sla |
flow | Líneas curvas extrañas, tratemos de hacerlas con ángulos y líneas rectas. |
tic__centros-de-proceso-de-datos |
flow | “Servidors…” quedan con el texto muy justo. |
tic__copias-de-seguridad-3-2-1-y-ransomware |
flow | |
tic__gestion-centralizada-de-endpoints |
flow | |
tic__gestion-de-capacidad-y-disponibilidad |
flow | |
tic__gestion-de-datos-en-la-administracion |
flow | El subrayado de NIF (si es que hace falta) está muy pegado al texto. |
tic__gestion-de-identidades |
flow | Flechas curvas mejor con ángulos rectos. El texto de “1” se solapa. |
tic__gestion-de-la-demanda-tic |
flow | Flechas sin palo. |
tic__low-code-y-no-code |
flow | |
tic__planificacion-estrategica-tic |
flow | |
tic__plataforma-de-observabilidad |
flow | La letra es muy pequeña. |
tic__pmbok-gestion-del-trabajo |
flow | |
tic__pmbok-planificacion-integrada |
flow | Líneas que no tocan cajas. Entiendo que “C” no está en negrita a propósito. |
tic__pmbok-valor-y-adaptacion |
flow | Texto muy pequeño. |
tic__rgpd |
flow | |
tic__sap-basis-y-s4hana |
flow | “transport” queda tapado por la flecha las dos veces. Una de las flechas no tiene cabeza. |
tic__sap-fi-y-ea-ps |
flow | |
tic__sap-hcm |
flow | Textos en cursiva se cruzan con flechas y cajas. |
tic__soluciones-erp |
flow | |
tic__trabajo-colaborativo-microsoft-365 |
flow | Aquí por ejemplo has usado líneas con ángulos rectos. Me gusta. Pero a diferencia del resto de los esquemas, las puntas de flecha no tocan las cajas de destino. |
tic__gestion-de-la-innovacion-sgi__1 |
*funnel | Flechas sin palo. |
tic__soluciones-crm |
*funnel | Pirámide de forma rara. Texto “Compte i contacte” se solapa con las líneas (no cabe). |
estado__administracion-publica |
Margen inferior e interlineado en b). | |
tic__arquitectura-de-datos-dw-lake-lakehouse |
*group | “Ingesta” no cabe. “format” debería ser “Format”? Líneas entre las tres cajas principales con distinta longitud. |
tic__devops-cicd-contenedores-y-kubernetes |
*group | Comandos en monospace? |
tic__practicas-itil-de-entrega-de-servicios |
*group | La línea que sale de “Disseny del servei” va a “Transició del servei”, mientras que la que llega a “Operació del servei” no viene de “Transició del servei” sino de un item interno, “Revisió posterior”. Sólo comprobar si es correcto. La caja de debajo (“CMDB…”) debería estar centrada con “Transició del servei o con todo el gráfico? Ahora no acaba de estar centrada del todo con nada. |
tic__practicas-itil-de-soporte-al-servicio |
*group | Yexto muy pequeño. Alguna flecha con poco palo. La palabra “excepció” no se sabe si es de la línea entre “Service Desk” y “Petició de servei” o de la línea entre “Esdeveniment” y “Incident” (o de las dos). |
tic__trabajo-documental-sharepoint-y-onedrive |
*group | |
tic__arquitecturas-de-seguridad-en-la-nube |
Las líneas de rayado son demasiado fuertes y cuesta leer “client”. Además, hay como unos separadores entre las tres cajas que no se respetan ni por las líneas generales ni por el rayado. | |
tic__computacion-hibrida-iaas-paas-saas |
*matrix | Mismo problema que antes en cuanto al rayado y las cajas separadas. A lo mejor “Gestiona el client” y “Gestiona el proveïdor” deberían ir al revés. |
tic__itil-v4-conceptos-y-cadena-de-valor |
No acabo de entender este esquema: las líneas cruzan cajas, hay dos posibles flechas sin palo, el texto se sale de las cajas y es muy grande y en negrita (o con sombra, no sé). | |
tic__sistemas-san-y-raid |
*matrix | |
tic__tcp-ip-v4-y-mpls |
*matrix | |
tic__redes-wifi |
*picture | Todos los AP quedan cruzados con el punto. La imagen queda cortada por abajo. El texto “solapament 15-20 %” no sé si está donde toca. Entiendo que el dibujo con los solapamientos sí es correcto. |
tic__servicios-digitales-geograficos |
*picture | Bello. Sólo el borde derecho del “Ràster” no ha quedado lo suficientemente gordo (o se sale de la imagen). |
barcelona__plan-de-igualdad-y-proteccion-de-datos |
pyramid | Irónicamente, cuanto más corto es el espacio, más largo es el texto. Si no cabe, puedes poner el 1 en dos líneas. |
estado__fuentes-del-derecho-publico |
pyramid | |
tic__pruebas-de-software |
pyramid | Pirámide de forma extraña. |
tic__servicio-de-atencion-al-usuario |
pyramid | Pirámide de forma rara, texto pequeño. Revisar si el texto es correcto. |
tic__pmbok-liderazgo-equipo-y-recursos__0 |
Puntas de flecha raras. | |
tic__pmbok-liderazgo-equipo-y-recursos__1 |
*quadrant | “Suavitzar / acomodar” atraviesa línea, y “Retirar / eludir” casi también. |
tic__aplicaciones-nativas-en-la-nube |
rings | Los textos de Cloud, Clúster y Contenidor deberían ir más abajo. Concretamente, Contenidor casi toca la línea. |
tic__gestion-documental-y-archivo-electronico |
rings | |
tic__gobernanza-en-itil-v4 |
rings | Textos que cruzan líneas. Posible falta de un círculo concéntrico. |
tic__inteligencia-artificial-riesgos-y-etica |
rings | Todos los textos atraviesan su propia línea.Valorar otro tipo de esquema o letra más pequeña, porque los textos son muy largos. |
tic__drp-y-bcp |
*spans | |
estado__constitucion-espanola |
stack | A lo mejor un poco más de margen vertical. |
tic__brm-y-gestion-de-expectativas |
stack | Flechas un poco raras, no sé qué significan. |
tic__calidad-del-software |
||
tic__nube-soberana-y-administracion-publica |
||
tic__sap-trm |
stack | Flecha sin palo, márgenes inferiores escasos, entre las dos últimas cajas no hay texto… |
estado__acceso-al-empleo-publico |
timeline | Es raro partir una frase por cualquier lado y poner una parte con letra más pequeña. En el esquema siguiente tiene sentido, pero no aquí. Todo el texto debería ir arriba. No sé si a), b), c) y d) son necesarios, a no ser que vengan así en el texto. |
estado__acto-administrativo |
timeline | |
tic__pmbok-interesadas-y-comunicacion |
timeline | |
tic__transformacion-digital |
timeline | |
barcelona__carta-municipal |
tree | Margen inferior en “Comissió de Govern”. |
tic__despliegue-de-aplicaciones-sccm |
tree | Las líneas no tocan las cajas. |
tic__esquema-nacional-de-seguridad |
~~ |
Parece como si las líneas no llegaran a las cajas inferiores. |
tic__internet-arquitectura-protocolos-dns |
tree | El texto “13 conjunts…” toca líneas y cajas, no queda muy claro dónde debe ir. |