HoopLang Docs
/
Playground
Referencia del lenguaje

Herramientas

HoopLang se usa con tres herramientas que comparten el mismo compilador: la línea de comandos hoop (verificar, producir archivos de máquina y formatear), el playground en el navegador (editor de varios archivos con el bordado en vivo) y la API WebAssembly sobre la que está construido el playground. Este capítulo describe cada una, las reglas de formato de hoop fmt y el soporte de editores.

La herramienta hoop#

Desde la raíz del repositorio:

Terminal
cargo run -q --release --bin hoop -- check <archivo.hoop>
cargo run -q --release --bin hoop -- build <archivo.hoop> <carpeta>
cargo run -q --release --bin hoop -- fmt [--check] <archivo.hoop>…

(El binario compilado queda en target/release/hoop; en los ejemplos se escribe hoop.) Sin argumentos válidos imprime el uso y termina con código 2:

Salida del compilador
usage: hoop check <file.hoop> | hoop build <file.hoop> <out-dir> | hoop fmt [--check] <file.hoop>…

Los import y place se resuelven relativos a la carpeta del archivo que se pasa (ver Módulos). Si ese archivo no se puede leer: <archivo>: cannot read: <motivo>, código 2.

hoop check#

Analiza, verifica y compila el archivo (sin coser ni escribir nada) e imprime cada diagnóstico con el formato de Diagnósticos, precedido por la ruta del archivo.

  • Un design: se verifica y, si no hay errores, se compila para revisar los límites (E006, W008, W009). Si todo está bien, termina con

    Salida del compilador
    <archivo>: ok — T threads, L layers, O objects

    donde T cuenta los colores distintos que se cosen (incluidos los de los diseños colocados con place; dos hilos del mismo color son uno, como en build) y O las primitivas y place del archivo (una vez evaluados los for e if), no los objetos del motor. Si el design declara frame, también revisa que quepa (ver más abajo).

  • Un hoop: se monta entero (cada diseño colocado se compila y se ubica) y termina con

    Salida del compilador
    <archivo>: ok — N designs, T threads, O objects

    donde N es la cantidad de diseños colocados, T los colores distintos que se cosen y O los objetos del motor.

  • Una biblioteca (un archivo con sólo import, thread, const y shape): se verifica como la ve quien la importa y termina con

    Salida del compilador
    <archivo>: library — T threads, C consts, S shapes
  • Código de salida: 0 si no hay errores (aunque haya advertencias), 1 si hay al menos un error, 2 por un problema de uso o de lectura.

Terminal
$ hoop check w008.hoop
w008.hoop:1:1: warning W008: no canvas: bounds are not checked; the design measures 30.0 × 20.0 mm (declare `canvas: rect(size: (30mm, 20mm))`)
w008.hoop: ok — 1 threads, 1 layers, 1 objects

El frame de un design se revisa con la caja de los objetos, sin coser (puede diferir en décimas de lo bordado): si no cabe, imprime <archivo>: error: the design is W × H mm and does not fit the A × B mm frame y termina con 1. Los límites de los formatos de máquina dependen de las puntadas: los revisa sólo build.

hoop build#

Compila el archivo, borda (genera las puntadas) y escribe los archivos de máquina y las vistas en <carpeta> (que se crea si no existe). Con <nombre> el nombre del archivo sin .hoop:

ArchivoContenido
<nombre>.pesBrother (PES v6, con los nombres, marcas y códigos de los hilos).
<nombre>.dstTajima.
<nombre>.expMelco / Bernina.
<nombre>.jefJanome.
<nombre>.vp3Husqvarna / Pfaff.
<nombre>.xxxSinger.
<nombre>.svgVista realista del bordado.
<nombre>.needles.svgVista de las agujas (los puntos de cada puntada).
Terminal
$ hoop build bastidor.hoop out
bastidor.hoop: 70.4 × 90.4 mm, 6420 stitches, 2 threads, 11 trims, 56 ms
  • Antes de la línea de resumen se imprimen las advertencias del compilador y los avisos de límites de máquina (ver Avisos de máquina), cada uno precedido por la ruta. Estos avisos no detienen la escritura, pero si alguno es error (no cabe en el bastidor, demasiados colores para un formato), build termina con código 1 después de escribir los archivos.
  • El resumen da el tamaño del bordado, las puntadas, los hilos (bloques de color: un color que vuelve después de otro cuenta de nuevo), los cortes y el tiempo que tomó.
  • Si hay errores, se imprimen (uno por línea, con la ruta) y termina con código 1 sin escribir archivos de máquina.
  • El origen de los archivos de máquina es el centro del bastidor en un hoop y el centro del bordado en un design (ver Bastidor).
  • La salida es determinista: la misma entrada da los mismos bytes.

hoop fmt#

Reescribe cada archivo en el estilo estándar. Acepta varios archivos.

  • Sin --check: un archivo que cambia se sobrescribe y se informa <archivo>: formatted; uno que ya estaba formateado no se toca ni se menciona.
  • Con --check: no escribe nada; informa <archivo>: not formatted por cada archivo que cambiaría.
  • Un archivo con un error léxico se informa como diagnóstico (malo.hoop:1:17: error E000: unclosed string (missing closing quote)) y no se toca. El formateador trabaja sobre los tokens: un archivo con errores de sintaxis o de tipos, pero léxicamente válido, se formatea igual.
  • Código de salida: 0 si todo está formateado (o se formateó), 1 si con --check hay archivos sin formatear, 2 si algún archivo no se pudo leer o tiene un error léxico (o faltan argumentos).
Terminal
$ hoop fmt --check feo.hoop cuadro.hoop
feo.hoop: not formatted
$ hoop fmt feo.hoop
feo.hoop: formatted

Otras herramientas#

  • palette genera bibliotecas de hilos de una marca a partir de una carta en CSV, o las de Brother y Janome (ver Módulos).
  • export <carpeta> <entradas>… es una herramienta de auditoría: para cada entrada (.hoop, PNG o SVG) escribe los seis formatos de máquina y las puntadas del motor en JSON, para compararlos con un lector independiente.

Reglas de formato (hoop fmt)#

hoop fmt aplica un solo estilo, como gofmt: no hay opciones. Garantías: el formateo no cambia los tokens (por lo tanto, tampoco el significado), conserva los comentarios y es idempotente (formatear dos veces da lo mismo).

Reglas:

  1. Saltos de línea: se respetan los de quien escribe. Varias líneas en blanco seguidas se reducen a una; se quitan las líneas en blanco del principio. El archivo termina con un único salto de línea.
  2. Sangría: 2 espacios por cada {, ( o [ abierto al empezar la línea; una línea que empieza con }, ) o ] va un nivel menos. Una continuación dentro de paréntesis queda un nivel adentro.
  3. Espacios dentro de una línea: un espacio entre tokens, salvo:
    • ninguno antes de ,, :, ), ], . y .., ni después de (, [, . y .. (0..4, [1, 2], s.inset(1mm));
    • ninguno después de un - de signo (después de (, [, {, ,, :, = o de un operador): -2mm, 1mm - -2mm;
    • un nombre seguido de ( queda como se escribió: pegado si estaba pegado (rect(, at() y separado si estaba separado (at (x, y));
    • los argumentos de un place van pegados a la ruta: place "x.hoop"(nombre: "ANA");
    • dos tokens que, pegados, formarían otro token (. y 5mm) se separan. El resultado: un espacio alrededor de = y de los operadores, después de : y ,, y alrededor de { y }.
  4. Comillas: las cadenas entre comillas simples pasan a dobles, salvo que contengan una comilla doble.
  5. Comentarios: quedan donde están, con un espacio antes si siguen a código en la misma línea. Si en varias líneas seguidas el comentario final empezaba en la misma columna, siguen alineados entre sí (con el menor espacio que tenían).
  6. Alineación: en las líneas seguidas que empiezan con thread o con const (con la misma sangría y con =), el = se alinea con espacios. Las const con tipo (const x: Length = …) forman su propio grupo, aparte de las sin tipo. param y shape no se alinean.

Antes:

Salida del compilador
design 'Feo'{canvas:rect(size:(30mm,20mm)),fabric:Twill}



thread negro=#1c1616 "Negro"
thread amarillo   =   #fcd414
const ancho = 3mm
const alto: Length = 2mm
layer a{
      fill amarillo{ shape :canvas.inset( 1mm ),angle:45deg }
   satin negro { border: canvas, width: ancho }  // borde
}

Después de hoop fmt:

HoopLang
design "Feo" { canvas: rect(size: (30mm, 20mm)), fabric: Twill }

thread negro    = #1c1616 "Negro"
thread amarillo = #fcd414
const ancho = 3mm
const alto: Length = 2mm
layer a {
  fill amarillo { shape: canvas.inset(1mm), angle: 45deg }
  satin negro { border: canvas, width: ancho } // borde
}

Playground#

apps/playground es un editor de HoopLang que corre entero en el navegador: el motor compilado a WebAssembly trabaja en un Web Worker, y el sitio es estático.

Terminal
cd apps/playground
npm ci
npm run wasm      # el motor a WebAssembly (requiere wasm-bindgen-cli)
npm run dev       # servidor de desarrollo
npm run build     # dist/, sitio estático

Proyectos de varios archivos#

  • Un proyecto es un conjunto de archivos .hoop con rutas (galeria/, bibliotecas/…), mostrado como árbol de carpetas, con pestañas. Se pueden crear, renombrar, borrar y subir archivos .hoop. Las rutas no pueden contener .. y siempre terminan en .hoop.
  • El proyecto se guarda en el navegador (localStorage). Empieza con los ejemplos del repositorio (galería, ejemplos y bibliotecas de docs/lenguaje/); "Volver a los ejemplos" descarta los cambios.
  • Los import y place se resuelven entre los archivos del proyecto, relativos a la carpeta del archivo que se borda (también los de un archivo importado o colocado), con . y .., igual que hoop check y hoop build.

Compartir, archivos del computador y galería#

  • Compartir por enlace: el botón "Compartir" genera una URL sin servidor con el proyecto entero comprimido en el fragmento #p=… (CompressionStream deflate-raw + base64url: pestañas abiertas, archivos modificados y sus dependencias transitivas de import/place, más cuál es el diseño principal). Al abrir esa URL, el playground carga el proyecto compartido en un espacio aparte en memoria, sin pisar el proyecto guardado del usuario en localStorage, y muestra una barra para "Guardar como mi proyecto" o "Volver a mi proyecto". Si el enlace supera los 8 000 caracteres, avisa y ofrece descargar el .zip.
  • Archivos del computador:
    • "Abrir archivos .hoop…" y "Abrir carpeta…" agregan archivos .hoop (con sus subcarpetas cuando el navegador lo permite) al proyecto.
    • Arrastrar y soltar archivos o carpetas .hoop sobre el editor o el árbol los incorpora al proyecto y abre el diseño.
    • "Descargar archivo (.hoop)" baja el archivo activo; "Descargar proyecto (.zip)" baja todos los archivos respetando su estructura de carpetas.
  • Galería: el botón "Galería" abre una vista con tarjetas de los diseños de docs/lenguaje/galeria. Cada tarjeta muestra la miniatura de las puntadas generada en el build con el motor real (stitch-wasm), nombre, medidas en mm, hilos, puntadas y colores; un clic abre el diseño en el editor.

Qué se borda#

El archivo que se borda es el activo si declara un design o un hoop. Mientras se edita una biblioteca (un archivo sin design ni hoop), se sigue mostrando el último diseño, que se recompila con los cambios.

Vista en vivo#

  • Cada cambio se compila 350 ms después de dejar de escribir. Primero llega una vista inmediata (formas y errores, en milisegundos) y luego las puntadas; si las puntadas tardan más de 120 ms, mientras tanto se ven las formas. Las compilaciones no se encolan: se compila sólo lo último.
  • La vista muestra el área útil del bastidor como tela con una grilla de 10 mm (en un hoop, desde su esquina; en un design con frame, centrada en el bordado, como la centra la máquina), los lienzos (el propio y los de cada diseño colocado), el bordado y, a elección, los saltos, las agujas y las reglas en mm. Hay zoom, arrastre de la vista, "Encuadrar" y la posición del puntero en mm.
  • Reglas y guías de medida (compartidas con la vista previa de VS Code):
    • Las reglas superior e izquierda se adaptan al zoom (marcas cada 1, 5, 10, 50… mm) y miden en coordenadas del código (coordenada − origin, con y hacia abajo): 0 en la esquina superior izquierda con top_left, en el centro del lienzo en un design con origin: center, y en el centro del bastidor en un hoop con origin: center. Se muestran u ocultan con la casilla Reglas o Alt+R (se recuerda la preferencia).
    • Arrastrar desde una regla crea una guía horizontal o vertical con imán a 0,5 mm y etiqueta (x = 30 mm / y = 12.5 mm). Las guías se mueven arrastrando, se editan con doble clic y se borran arrastrándolas de vuelta a la regla o fuera de la vista. Se guardan por archivo.
    • La lectura en la esquina inferior derecha muestra la posición del cursor respecto del origen (x · y mm) y, al pasar sobre una forma, el tamaño de su caja (▢ ancho × alto mm).
  • Los errores se subrayan en su línea, aparecen en el margen, en la pestaña y en un panel de problemas (con clic para ir a la línea). Los de un import o place se muestran también en el archivo de origen. Con errores, se sigue viendo lo último que compiló. Los avisos de límites de máquina aparecen en el panel como "máquina".

Ida y vuelta entre código y vista#

  • Clic en el bordado: el editor salta a la primitiva que lo produjo (o al place que trajo ese diseño).
  • Cursor en el código: se resaltan en la vista los objetos de la primitiva o place bajo el cursor.
  • Arrastrar una pieza mueve su posición y reescribe el at en el código (el at: de una primitiva como text, o el at de un place):
    • si el at es un literal (x, y) en mm, se cambian los números, redondeados a 0.5 mm: at (40mm, 18mm) → at (52.5mm, 18mm);
    • si es una expresión calculada (canvas.center, grid(i, …), p.center), no se reemplaza: se le suma un desplazamiento + (dx, dy), también redondeado a 0.5 mm (grid(i, cols: 3, …) + (5mm, -2.5mm)). Los arrastres siguientes actualizan ese mismo desplazamiento y, si vuelve a (0, 0), se quita;
    • si el at está dentro de un for, se mueven todas las copias;
    • un diseño con fit no se arrastra (sus medidas no son los mm de la vista). Después de soltar, el compilador revisa de inmediato (un objeto llevado fuera del lienzo da E006).

Formatear y descargar#

  • "Formatear" o Ctrl+S (⌘S) aplica hoop fmt al archivo activo.
  • El menú de descargas baja el archivo de máquina del diseño que se borda en PES (Brother), DST (Tajima), EXP (Melco, Bernina), JEF (Janome), VP3 (Husqvarna, Pfaff) o XXX (Singer). Las descargas se desactivan mientras hay errores.

API WebAssembly#

El paquete crates/wasm expone, entre otras, estas funciones para JavaScript:

FunciónDescripción
runHoopProject(main, files, live, onProgress)Compila y borda un proyecto. main es la ruta del archivo a compilar y files un JSON {ruta: texto} con todos los archivos. Devuelve un objeto con diags (JSON), error (texto o null), canvases (JSON: anillos en mm), frame (JSON: [ancho, alto] o null), anchored (si las coordenadas son las del bastidor) y, si compiló, pes, dst, exp, jef, vp3, xxx (bytes), xy, cmd, colors, previewSvg, needlesSvg y summary (JSON). Con live = true no genera archivos de máquina ni vistas SVG. onProgress(etapa, hechas, total) informa el avance.
previewHoopProject(main, files)Compila sin coser y devuelve un JSON con ok, diags y, si compiló, shapes (por objeto: color, line, col, rings y open), canvases, frame y anchored. Es la vista inmediata y la base de la ida y vuelta código ↔ vista.
formatHoop(src)Devuelve el texto formateado como hoop fmt, o lanza el diagnóstico como texto.

En ambas funciones de proyecto, un archivo que no está en files se informa como cannot read …: not found in the project (<ruta>).

Soporte de editores#

El playground (CodeMirror 6) ofrece:

  • resaltado de sintaxis (palabras clave, primitivas, funciones, tipos, números con unidad, colores, cadenas y comentarios); es un modo por líneas, sin gramática completa: los errores reales los da el compilador;
  • autocompletado de palabras del lenguaje, fuentes, bastidores, propiedades, fragmentos (design, fill, satin, text, for, if, place) y los nombres declarados en el archivo (thread, const, shape, param y los espacios de nombres de import);
  • diagnósticos del compilador en la línea, y formateo con Ctrl+S.

Servidor LSP y VS Code#

hoop-lsp es el servidor de lenguaje de HoopLang. Habla LSP por stdio y usa el lexer, parser, verificador y formateador del compilador, sin otro intérprete del lenguaje. Se instala desde la raíz del repositorio:

Terminal
cargo install --path crates/lsp --locked

Ofrece:

  • errores y advertencias al abrir, cambiar y guardar, con sus códigos, severidades y posiciones convertidas de caracteres Unicode a UTF-16;
  • formato de documento con el mismo resultado que hoop fmt;
  • completado de declaraciones, primitivas y propiedades del bloque actual, valores de los catálogos, nombres declarados y miembros de import;
  • hover con tipos y valores evaluados, color/marca de hilos y ayuda extraída de esta referencia durante la compilación del servidor;
  • ir a la definición de hilos, formas, constantes, parámetros, miembros importados y rutas de place e import.

Los archivos se cargan relativos al archivo principal, incluidas las rutas de bibliotecas anidadas, igual que en hoop check. Las ediciones de archivos abiertos tienen prioridad sobre el disco y actualizan los diagnósticos de sus clientes. Las bibliotecas se verifican como bibliotecas; los place se revisan compilando/montando, sin generar puntadas.

La extensión de VS Code está en editors/vscode. Añade resaltado TextMate, comentarios, pares de delimitadores e ícono de .hoop, y lanza el servidor. Para instalarla localmente (Node.js 22 o posterior):

Terminal
cd editors/vscode
npm ci
npm run package
code --install-extension hooplang-0.1.0.vsix

El VSIX contiene el cliente, pero el ejecutable hoop-lsp se instala por separado: debe estar en el PATH de VS Code o configurarse con una ruta absoluta en hooplang.serverPath. Después de cambiarla, recarga la ventana. Ver el README de la extensión.

En otros editores LSP, configura el comando hoop-lsp sin argumentos y con transporte stdio. No despliega proyectos. hoop check y hoop fmt siguen disponibles como herramientas externas.

Vista previa en VS Code#

Con un .hoop abierto, ejecuta HoopLang: Abrir vista previa, o usa el botón de la barra del editor. El panel lateral muestra primero las formas y después las puntadas por color, junto con medidas, puntadas, hilos, cortes y avisos de máquina. Respeta el tema claro/oscuro del editor. La rueda hace zoom, arrastrar desplaza, Ajustar vista encuadra y la casilla Reglas (Alt+R) muestra u oculta las reglas en mm y las guías de medida, que se guardan por documento en el estado del panel. Un clic en una forma selecciona su línea; mover el cursor dentro de una primitiva resalta la forma correspondiente, y pasar sobre una forma muestra su posición y su caja (ancho × alto mm).

Las ediciones sin guardar, incluidos place e import, se usan igual que en los diagnósticos. Tras unos 200 ms se pide una nueva vista; hay una sola petición en curso y se descartan resultados de revisiones anteriores. No exporta archivos de máquina ni permite editar formas arrastrándolas. El LSP ofrece las peticiones propias hoop/preview y hoop/stitches, ambas con textDocument.uri; el protocolo y las pruebas están descritos en el README de la extensión.

API HTTP#

El servidor stitch-api (crates/api) expone HoopLang por HTTP, para usar el lenguaje desde un backend: una tienda que pide "parche con el nombre MARÍA" y recibe el .pes, o un editor propio. Usa el mismo compilador y el mismo motor que hoop, el playground y VS Code.

Terminal
HOOP_TEMPLATES=docs/lenguaje cargo run --release -p stitch-api
# o con Docker, desde la raíz del repositorio:
docker build -f crates/api/Dockerfile -t stitch-api .
docker run -p 8080:8080 stitch-api

Endpoints#

Método y rutaQué haceRespuesta
POST /v1/hoop/checkCompila sin coser{ ok, name, diags }
POST /v1/hoop/previewLas formas, sin coser (milisegundos){ ok, diags, shapes, canvases, frame, anchored }; cada forma con color, line, col, rings, open
POST /v1/hoop/buildBorda{ ok, diags, summary, threads, files }
POST /v1/hoop/format{ "src": … } con el estilo de hoop fmt{ ok, src }
GET /v1/hoop/templatesLas plantillas del servidor{ templates: [{ template, name, params }] }
GET /healthPara el balanceadorok

check, preview y build reciben el diseño de una de dos formas:

json
{ "main": "parche.hoop",
  "files": { "parche.hoop": "…", "bibliotecas/janome.hoop": "…" },
  "params": { "nombre": "MARÍA" } }
json
{ "template": "galeria/parche", "params": { "nombre": "MARÍA" },
  "formats": ["pes", "dst", "svg"] }
  • files: el proyecto entero, {ruta: texto}. main es el archivo principal (por omisión main.hoop); los import y place se resuelven relativos a él, como en el playground.
  • template: un .hoop guardado en la carpeta HOOP_TEMPLATES del servidor (con o sin .hoop, puede incluir subcarpetas). Sus import y place se leen de esa misma carpeta, sin salir de ella.
  • params: valores para los param del archivo principal, como los de un place. En JSON: texto ("ANA"), entero (3), true/false, {"mm": 12}, {"cm": 1.2}, {"deg": 30}, {"pct": 80} o {"color": "#cc3f24"}. Un param que el diseño no declara es E007 (con sugerencia); un valor del tipo equivocado, el error del compilador.
  • formats (sólo build): pes, dst, exp, jef, vp3, xxx (en base64) y svg (la vista previa, como texto). Por omisión pes y dst.
  • summary trae puntadas, cortes, cambios de hilo, medidas en mm, metros de hilo, minutos estimados y los avisos de máquina.

Errores#

EstadoCuándoCuerpo
400La petición está mal armada (falta el archivo principal, formato desconocido, un param con un valor que no se entiende){ ok: false, error }
404La plantilla no existe, o el servidor no tiene plantillas{ ok: false, error }
413La petición pasa HOOP_MAX_BODY_BYTES
422El diseño tiene errores, o más puntadas que HOOP_MAX_STITCHES{ ok: false, error, diags }, con los diagnósticos como los da el compilador (code, severity, pos, msg)
504La compilación pasó HOOP_TIMEOUT_SECS{ ok: false, error }

Configuración#

VariablePor omisiónQué fija
PORT8080Puerto
HOOP_TEMPLATESsin plantillasCarpeta de plantillas
HOOP_MAX_BODY_BYTES4 MiBTamaño máximo de una petición
HOOP_TIMEOUT_SECS20Tiempo máximo de una compilación
HOOP_MAX_STITCHES1 000 000Puntadas máximas de un diseño bordado
HOOP_MAX_CONCURRENTnúcleos del procesadorCompilaciones a la vez (las demás esperan)

Los límites del compilador valen siempre; estas variables permiten que un servidor público sea más estricto.

El servidor también conserva las rutas anteriores al lenguaje (/v1/stitch, /v1/design, /v1/svg: formas en JSON o un SVG).

Pruebas de robustez#

Los tests habituales incluyen proyectos válidos generados con proptest: compilación, determinismo y formato idempotente que conserva los valores del motor. Se ejecutan con cargo test --workspace --release.

El workspace independiente crates/hoop/fuzz ofrece los objetivos lex_parse, check_compile y format. Para empezar desde la raíz:

Terminal
rustup toolchain install nightly --profile minimal
cargo install cargo-fuzz --locked
python3 crates/hoop/fuzz/scripts/seed_corpus.py
cargo +nightly fuzz run lex_parse --fuzz-dir crates/hoop/fuzz -- -max_total_time=1800 -dict=crates/hoop/fuzz/hoop.dict

Repetir el comando con check_compile y format, al menos 30 minutos por objetivo. Los detalles de sanitizador, límites de la campaña, reproducción y minimización están en crates/hoop/fuzz/README.md, en el repositorio.

El compilador y el formateador diagnostican entradas que exceden sus presupuestos de recursos con E002 (los errores de lectura siguen siendo E007). Esto incluye tamaño del archivo, cantidad de tokens, profundidad de sintaxis y valores, tamaño de nombres y cadenas, vértices, texto, cantidad de objetos, trabajo acumulado de bucles y dependencias. Los valores se centralizan en crates/hoop/src/limits.rs; MAX_LOOP sigue siendo 1000 por bucle y se verifica antes de reservar el rango. Un desbordamiento entero también es E002, igual en debug y release. No se cambian densidades, subcapas ni recorridos para hacer pasar una entrada excesiva.

Véase también#

Ejemplos de documentación como pruebas#

cargo test --release -p stitch-tools --test docs recorre todos los Markdown bajo docs/hooplang/. Compila cada bloque hoop y compara las salidas text/sh inmediatamente adyacentes que contienen resultados del CLI. Comprueba posición, código y mensaje; en build, medidas e hilos exactos y puntadas con tolerancia del 2 %. No compara tiempos ni exige cortes exactos.

Los fragmentos usan un único contexto didáctico definido en el test, con un lienzo amplio, hilos negro/blanco/rojo/azul/oro/amarillo y nombres de formas y constantes usados en el libro. Las declaraciones del bloque prevalecen. Los archivos completos no se envuelven. Las dependencias se buscan primero en archivos mostrados en la página, después en docs/lenguaje/ y finalmente en archivos identificados en otras páginas.

Marcas al principio de un bloque (se eliminan antes de compilar):

  • // error E003: debe fallar con ese código, sin otros errores. Puede enumerar varios códigos si el ejemplo los muestra intencionalmente.
  • // no-check Motivo: sólo para plantillas incompletas; el test enumera todas las exclusiones para que no pasen inadvertidas.
  • // file: lib/colores.hoop: identifica un archivo mostrado en la página para que los otros ejemplos puedan importarlo o colocarlo.

El fallo indica archivo Markdown, línea de la cerca y diferencias concretas. Los comentarios de metadatos no desplazan las posiciones del archivo .hoop.

Simulador del bordado#

hoop build escribe además un PNG de hilo sobre tela a partir de las puntadas reales cuantizadas, en su orden y posición. El diámetro inicial es 0,40 mm: si hay huecos entre filas, se ven. Los saltos sin cortar también se ven por defecto. No simula fruncido ni corrige defectos del plan.

La API acepta formats: ["png"] y opciones png: {width: 1000, height: 600, rulers: true}; las reglas, en mm, parten del origen del código, también con origin: center. Se pueden elegir fabric (twill, pique, fleece), fabric_color, thread_mm y ocultar saltos explícitamente con hide_jumps (false por defecto).

En VS Code, HoopLang: Abrir vista previa muestra la misma imagen y tiene un control mínimo Reproducir/Pausar con tiempo estimado. Conserva clic al código y resaltado de formas. El reproductor completo es un trabajo aparte.

Todas estas vistas usan stitch-render, sin E/S. WASM ofrece renderStitches y StitchRenderer incremental: cada cuadro dibuja sólo los nuevos comandos. Los parámetros visuales son valores iniciales que se calibrarán con fotos reales. La API, los valores y las pruebas se documentan en crates/render/README.md.