HoopLang Docs
/
Playground
Referencia del lenguaje

Bastidor: hoop y place

Una máquina de bordar no borda diseños sueltos: borda un bastidor. Un archivo hoop monta uno o varios diseños (cada uno en su propio archivo .hoop) en el área útil de un bastidor real, en milímetros, y se compila a un solo archivo de máquina. Este capítulo describe la declaración hoop, sus propiedades, la instrucción place con todos sus modificadores, el sistema de coordenadas, cómo se ordena el bordado entre diseños, dónde queda el origen de los archivos de máquina y qué se valida. place también puede usarse dentro de una capa de un design, para usar un diseño como componente de otro; ese uso se describe al final y en Módulos.

Forma general#

Salida del compilador
hoop_decl := "hoop" STRING "{" ( prop | place | for | if ) * "}"
place     := "place" STRING ( "(" args ")" )? "at" expr ( IDENT ":" expr )*

Un ejemplo completo, el archivo bastidor.hoop:

HoopLang
hoop "Dos parches" {
  frame: Brother_200x200
  fabric: Twill
  margin: 10mm
  place "parche.hoop" at (100mm, 60mm)
  place "parche.hoop"(nombre: "LUIS", ancho: 70mm) at (100mm, 120mm) anchor: top_center
}

con el componente parche.hoop en la misma carpeta:

HoopLang
// file: parche.hoop
param nombre = "ANA"
param ancho: Length = 50mm
design "Parche" { canvas: rect(size: (ancho, 20mm), radius: 4mm) }
thread fondo = #f2f2f2 "Fondo"
thread borde = #1f3a8a "Azul"
layer base { fill fondo { shape: canvas } }
layer texto { text borde { value: nombre, height: 8mm, at: canvas.center + (0mm, 3mm), align: center } }
layer marco { satin borde { border: canvas, width: 2mm } }
Terminal
$ hoop check bastidor.hoop
bastidor.hoop: ok — 2 designs, 2 threads, 6 objects

Reglas del archivo:

  • Un archivo tiene un solo design o un solo hoop (si no: E007 a file has a single design (or a single hoop)).
  • Un archivo hoop no puede tener layer: las capas van en el archivo de cada diseño (E007 a hoop places designs with place; layers go in each design's file).
  • Dentro del bloque sólo van propiedades, place, for e if. Una primitiva (fill, satin, …), seq, inside o layer directamente en el hoop es E000 a hoop only places designs (move fill into a design file); dentro de un if o for del hoop, E007 a hoop only places designs (place, for); stitches go in a design.
  • Una propiedad repetida es E007 duplicate frame``.
  • Los elementos pueden separarse con saltos de línea o con comas: hoop "H" { frame: Brother_100x100, margin: 8mm, place "a.hoop" at (50mm, 50mm) } es válido.
  • El archivo puede tener además import, thread, const, shape y param (sus nombres se pueden usar en las expresiones de los place).

Propiedades del hoop#

PropiedadTipoPor defectoSignificado
framebastidor del catálogo o custom(ancho, alto)— (obligatoria)Área útil del bastidor, en mm.
fabricTwill, Pique, Fleece, Cap, Stretchla tela del primer diseño colocadoTela; manda sobre la de cada diseño.
marginLength5mmDistancia mínima de lo cosido al borde del área útil.
origintop_left, centertop_leftDesde dónde se miden los at de los place (ver Sistema de coordenadas).

Cualquier otra clave es E007 a hoop has no … (frame, fabric, margin, origin).

frame#

El valor es un nombre del catálogo o custom(ancho, alto) con dos Length:

NombreÁrea útil (mm)
Brother_100x100100 × 100
Brother_130x180130 × 180
Brother_160x260160 × 260
Brother_200x200200 × 200
Brother_200x300200 × 300
Tajima_150x150150 × 150
Tajima_240x240240 × 240
Tajima_360x360360 × 360
Cap_130x60130 × 60
HoopLang
hoop "Modificadores" {
  frame: custom(200mm, 200mm)
  place "parche.hoop" at (60mm, 40mm) anchor: top_left
  place "parche.hoop" at (150mm, 100mm) rotate: 90deg
  place "parche.hoop" at (100mm, 180mm) anchor: bottom_center scale: 120%
}
  • Un nombre que no está en el catálogo es E002 unknown frame … (catalog: …).
  • custom con otros argumentos es E001 custom(width, height) takes two Length; cualquier otra expresión, E001 frame: a catalog frame or custom(width, height).
  • Sin frame es E007 the hoop is missing frame, en la línea del hoop. Con un frame inválido se informa sólo ese error: sin bastidor no se revisa el área útil de cada place.

fabric#

La tela del hoop manda: cada diseño colocado se compila con esa tela, de modo que los parámetros que el diseño no escribe (densidades, subcapas, compensación de tirón) se resuelven para ella. Si el hoop no declara fabric, cada diseño usa la suya y la tela del resultado es la del primer diseño colocado. Un valor fuera de la lista es E002 (con sugerencia si hay un nombre parecido); un valor que no es un nombre, E001.

margin#

Una Length; otro tipo es E001 margin is Length, not …. A diferencia del margin de un design (0 a 20 mm), el del hoop no tiene rango verificado.

place#

Salida del compilador
place "archivo.hoop"( "(" nombre: valor, … ")" )? at <Point> ( anchor: … | rotate: … | scale: … )*

Coloca el diseño de archivo.hoop en el bastidor. Partes:

ParteTipoPor defectoSignificado
"archivo.hoop"literal String—El archivo del diseño (ver rutas).
(nombre: valor, …)argumentos con nombre—Valores para los param del diseño (ver componentes).
atPoint— (obligatorio)Dónde cae el ancla del diseño, en coordenadas del bastidor.
anchor:nombre de anclacenterQué punto de la caja del diseño cae en at.
rotate:Angle0degGiro del diseño entero.
scale:Ratio (> 0)100%Escala del diseño entero.
  • La ruta es un literal entre comillas: no puede ser una expresión.
  • at es cualquier expresión que dé un Point: un literal (x, y), un nombre, grid(…), canvas.center + (5mm, 0mm)… Otro tipo es E001 at takes a Point (x, y), not …. Sin at, E000 expected at (x, y)``.
  • Los modificadores van después de at, en cualquier orden, separados por espacios (no por comas) y en la misma instrucción. Cada uno es nombre: valor. Una clave desconocida es E007 place has no … (anchor, rotate, scale); no existe mirror. Un modificador o un argumento repetido es E007 duplicate …``.
  • anchor acepta center, top_left, top_center, top_right, center_left, center_right, bottom_left, bottom_center y bottom_right; otro nombre es E002 (con sugerencia o con la lista). Los alias cortos de los miembros de forma (top, left…) no valen aquí.
  • rotate con otro tipo es E001 rotate is Angle, not ….
  • scale debe ser un Ratio mayor que cero: 0% o un valor negativo (-50%) es E002 scale must be greater than 0%; otro tipo, E001 scale is Ratio, not …. Si achica un texto bajo el mínimo de su fuente, W004 en el place (ver Diagnósticos).
  • Los argumentos van con nombre: place "x.hoop"("ANA") at … es E001 design arguments are named: place "x.hoop"(nombre: "ANA").

Cómo se transforma un diseño colocado#

Para cada place, en este orden:

  1. Se compila el archivo del diseño (con sus import, sus param con los argumentos dados y la tela del hoop), en sus propias coordenadas.
  2. Se escala por scale y se gira por rotate alrededor del origen del diseño, (0, 0). Como el eje y apunta hacia abajo, un ángulo positivo gira en sentido horario en la pantalla. El ángulo de las puntadas de un relleno gira con el diseño (un fill a 45° colocado con rotate: 90deg se borda a 135°). Un texto girado se borda letra por letra: cada letra se convierte en sus columnas y éstas se giran (la fuente no se gira sola). Los grupos seq se conservan, también cuando un texto se divide en letras.
  3. Se calcula la caja del diseño ya escalado y girado: si el diseño declara canvas, la caja alineada a los ejes del lienzo transformado (el ancla top_center es la del parche, no la de lo que tiene dentro); si no, la caja de lo cosido.
  4. Se traslada para que el punto anchor de esa caja caiga en at.

El lienzo de cada diseño colocado, transformado igual, se entrega al editor para dibujarlo (Compiled::canvases); no forma parte del bordado.

En el ejemplo de bastidor.hoop, el primer parche (50 × 20 mm, ancla center) ocupa de (75, 50) a (125, 70) mm; el segundo, de 70 mm de ancho y con ancla top_center en (100, 120), ocupa de (65, 120) a (135, 140) mm.

Sistema de coordenadas#

  • Las coordenadas del bastidor están en milímetros, con (0, 0) en la esquina superior izquierda del área útil, x hacia la derecha e y hacia abajo (como la pantalla y la máquina).
  • Con origin: center, (0, 0) es el centro del área útil, como en la máquina: place "escudo.hoop" at (0mm, 0mm) lo pone al centro, y at (0mm, -30mm) 30 mm más arriba. La y sigue hacia abajo. Lo demás (margen, E006) no cambia; los mensajes muestran la posición medida desde la esquina.
  • El área útil va de (0, 0) a (ancho, alto) del frame; lo cosido debe quedar dentro de [margin, ancho − margin] × [margin, alto − margin].
  • El centro del área útil, (ancho / 2, alto / 2), es el origen de los archivos de máquina (ver abajo).

for e if dentro de un hoop#

for e if funcionan como en las capas (ver Control), y su cuerpo sólo puede contener place, for e if:

HoopLang
hoop "Plancha" {
  frame: Tajima_360x360
  margin: 10mm
  for nombre, i in ["ANA", "LUIS", "SOFÍA", "TOMÁS"] {
    if i mod 2 == 0 {
      place "parche.hoop"(nombre: nombre) at grid(i, cols: 2, step: (70mm, 40mm), start: (60mm, 40mm))
    } else {
      place "parche.hoop"(nombre: nombre) at grid(i, cols: 2, step: (70mm, 40mm), start: (60mm, 40mm)) rotate: 180deg
    }
  }
}
  • Cada vuelta del for produce un place independiente, con los valores de la variable (y del índice) en ese momento. Hasta 1000 vueltas (E002 … iterations: a loop goes up to 1000).
  • En un if se verifican las dos ramas (sus errores se informan, incluido el E006 del ancla), pero sólo se colocan los diseños de la rama elegida:
HoopLang
// error E006
hoop "H" {
  frame: Brother_100x100
  if false {
    place "cuadro.hoop" at (500mm, 50mm)
  } else {
    place "cuadro.hoop" at (50mm, 50mm)
  }
}
Terminal
$ hoop check hoopskip.hoop
hoopskip.hoop:4:5: error E006: (500.0, 50.0) mm is outside the frame's sewing area minus its margin

La galería trae una plancha de doce parches de nombre con grid (docs/lenguaje/galeria/plancha.hoop).

Un solo archivo de máquina#

Todos los diseños de un hoop se juntan en un único diseño:

  • Objetos: los de cada place, en el orden de los place (y de las vueltas de los for). Cada objeto recuerda la línea del place que lo trajo (para ir de la vista al código).
  • Hilos: se juntan por color (sin distinguir mayúsculas en el hexadecimal): si dos diseños declaran el mismo color, queda el primer thread encontrado, con su nombre, marca y código.
  • Orden de bordado: el motor optimiza el orden entre todos los diseños (los objetos del mismo hilo juntos, para tener menos cambios de hilo), respetando las capas de cada diseño y los bloques seq, que se cosen seguidos y en su orden. Doce parches de tres colores son dos cambios de hilo, no treinta y cinco.
  • Tela: la del hoop o, si no la declara, la del primer diseño.

Origen de los archivos de máquina#

En un hoop, el origen (0, 0) de los archivos de máquina es el centro del área útil del bastidor (redondeado a 0.1 mm), no la esquina ni el centro del diseño. Las máquinas de formato relativo (Tajima DST, Melco EXP, Singer XXX) empiezan donde está la aguja, que el operador centra en el bastidor: así cada diseño cae donde dice su at. JEF guarda las distancias reales desde ese origen; PES guarda además el bastidor (en un hoop, PES v6 lo lleva en su cabecera). Las vistas SVG y el resumen siguen en coordenadas del diseño.

Un design compilado solo (sin hoop) usa como origen el centro de su propio bordado.

Validación#

CódigoCuándoDónde se informa
E006El punto at está fuera de [margin, ancho − margin] × [margin, alto − margin].En el place, al verificar.
E006Lo cosido del diseño ya colocado se sale del área útil menos margin.En el place, al montar.
W006Dos diseños colocados se pisan más de 0.5 mm².En el place posterior de los dos.
E007El archivo no se puede leer, es un hoop, coloca su propio archivo (ciclo) o recibe un argumento que no es param.En el place.
E004El diseño no tiene nada que coser, o el hoop no coloca ningún diseño.En el place (o en la línea del hoop).

Área útil (E006)#

Hay dos revisiones. La primera, al verificar, mira sólo el punto at:

HoopLang
// error E006
hoop "H" {
  frame: Brother_100x100
  place "cuadro.hoop" at (98mm, 50mm)
}
Terminal
h_e006a.hoop:3:3: error E006: (98.0, 50.0) mm is outside the frame's sewing area minus its margin

La segunda, al montar, mide lo cosido del diseño ya transformado (no su lienzo): los puntos de su geometría (el camino de un corrido, los rieles de un satín, el contorno de un relleno, el contorno de las letras de un texto). La caja de esos puntos debe quedar dentro del área útil menos margin, con una tolerancia numérica de 10⁻⁶ mm (tocar el margen exacto es válido). Con el diseño cuadro.hoop:

HoopLang
// file: cuadro.hoop
design "Cuadro" { canvas: rect(size: (20mm, 20mm)) }
thread negro = #1c1616 "Negro"
layer a { fill negro { shape: canvas } }
HoopLang
// error E006
hoop "H" {
  frame: Brother_100x100
  place "cuadro.hoop" at (12mm, 50mm)
}
Terminal
h_e006b.hoop:3:3: error E006: `cuadro.hoop` spans (2.0, 40.0)–(22.0, 60.0) mm, outside the sewing area minus its 5 mm margin (100 × 100 mm frame)

Con at (15mm, 50mm) el cuadro va de 5 a 25 mm y verifica.

Diseños que se pisan (W006)#

Para cada par de diseños colocados se calcula el área común real de sus huellas (lo que cubre cada objeto en la tela). Si supera 0.5 mm², se avisa en el place del segundo:

HoopLang
hoop "H" {
  frame: Brother_100x100
  place "cuadro.hoop" at (40mm, 50mm)
  place "cuadro.hoop" at (50mm, 50mm)
}
Terminal
h_w006.hoop:4:3: warning W006: `cuadro.hoop` overlaps `cuadro.hoop` by 200.0 mm²
h_w006.hoop: ok — 2 designs, 1 threads, 2 objects

Es una advertencia: el archivo compila (un aplique encima de un fondo puede ser intencional).

Diagnósticos de los diseños colocados#

Los errores y advertencias de cada diseño colocado se informan en la línea de su place, con el archivo y la posición dentro de él (ver Diagnósticos):

Terminal
h_noparam.hoop:4:3: error E001: in `parche.hoop` 1:1: error: `nombre` is String but it was given Length

Si algún diseño tiene errores, el hoop no compila; los demás se siguen revisando (se informan todos los errores juntos, y después las advertencias).

Ciclos y archivos que no son diseños#

  • Un place cuyo archivo es un hoop: E007 … is a hoop; place takes design files.
  • Un archivo inexistente: E007 cannot read …: … (el detalle lo da el sistema de archivos o el editor).
  • Un diseño que se coloca a sí mismo, directa o indirectamente: E007 place cycle: a.hoop → b.hoop → a.hoop, en el place de más afuera (ver Módulos).
  • Un hoop sin ningún place que llegue a colocarse: E004 the hoop places no designs, en la línea del hoop.

place dentro de un design#

place también vale dentro de una capa (y de for, if e inside) de un design, con la misma sintaxis y la misma transformación. Las coordenadas de at son entonces las del diseño que coloca. Diferencias con el hoop:

  • La tela del diseño que coloca manda sobre la del componente.
  • Los objetos del componente se insertan en la capa, en el lugar del place; sus hilos se suman (sin repetir colores) y sus seq se conservan.
  • No hay revisión de área útil ni W006: lo colocado queda sujeto al canvas (y margin) del diseño que coloca y a sus inside. Si se sale, el mensaje nombra al place:
HoopLang
// error E006
design "Polera" { canvas: rect(size: (60mm, 50mm)) }
layer todo {
  place "parche.hoop" at (50mm, 18mm)
}
Terminal
componente_fuera.hoop:3:3: error E006: place overflows the canvas by 15.0 mm on the right

Un ejemplo que verifica (docs/lenguaje/galeria/polera.hoop es otro):

HoopLang
design "Polera" { canvas: rect(size: (80mm, 50mm)), fabric: Pique }
thread azul = #1f3a8a "Azul"
layer todo {
  place "parche.hoop"(nombre: "SOL") at (40mm, 18mm) scale: 80%
  text azul { value: "2026", height: 6mm, at: (40mm, 46mm), align: center }
}

Dentro de una capa, place debe ir seguido de un literal de texto (place "…").

Véase también#