HDL — House Description Language

DSL paramétrico para plantas de viviendas, en castellano. Editor · Pruebas

Filosofía

HDL describe la planta de una vivienda como un programa, no como un dibujo. Internamente HDL mantiene un cursor con una posición (x, y) que va dejando paredes detrás: cada muro lleva su propio rumbo absoluto, traza la línea, y avanza el cursor a su extremo para que el siguiente muro arranque pegado. Variables y expresiones se evalúan en compilación, así que cambiar una variable reescala todo lo dependiente.

Mi primera planta

escala metros

muro E 6 como sur      # 6 m hacia el este
muro N 4 como este
muro O 6 como norte
muro S 4 como oeste
cerrar

Esto traza un rectángulo 6×4 m en sentido antihorario (CCW). Cada muro exige rumbo + distancia. cerrar tira un muro recto desde el cursor al primer vértice del polígono. No existen sentencias girar ni rumbo top-level: el rumbo siempre va en cada muro.

Escala

Primera sentencia útil. Si se omite, se asume metros.

escala metros        # default
escala centimetros
escala milimetros
escala pies
escala pulgadas
escala yardas

Cualquier valor puede llevar sufijo de unidad pegado al número, lo que anula la escala global para ese valor: 120cm, 800mm, 2m.

Plano — defaults globales

Bloque opcional que centraliza los valores comunes a todo el plano. Cualquier propiedad inline en una puerta, ventana o muro sobrescribe el default.

plano
  alto-puerta    = 2.10
  alto-ventana   = 1.20
  antepecho      = 1.00
  ancho-puerta   = 0.85
  ancho-ventana  = 1.20
  alto-techo     = 2.50
  grosor-muro    = 0.25
  grosor-pared   = 0.15
  grosor-tabique = 0.08
  alero          = 0.30

Las puertas y ventanas que no especifiquen alto, antepecho, etc. heredan estos valores. Útil para no repetir antepecho 1.00 en cada ventana.

Variables y expresiones

variable largo = 6.00
variable ancho = 4.50

muro E largo
muro N ancho

# tuplas — variables-punto
variable esquina = (0, 1.50)
inicio en esquina

# atajo estilo MFL (_prefijo)
_largo = 6.00
muro E _largo

Soporta + - * / con paréntesis. Regla dimensional:

OperadorLiteral sin sufijo se interpreta como…
+, -distancia (aplica escala global)
*, /escalar adimensional

Por eso largo / 2 divide entre 2 (escalar puro), no entre 2 metros. Y largo - 0.45 resta 45 cm.

Tipos de pared

KeywordGrosor por defectoUso
muro250 mmexterior / de carga
pared150 mminterior portante o medianera
tabique80 mmdivisorio ligero

Los tres aceptan los mismos modificadores: como NAME, grosor T, alero E.

Trazado de muros

Dos formas equivalentes para emitir un muro:

Por rumbo y distancia

muro <rumbo> <distancia> [como NAME] [grosor T] [alero E]

El rumbo puede expresarse como:

muro 90 6 como sur            # compás
muro E 6 como sur               # cardinal letra
muro este 6 como sur            # cardinal palabra
muro E 6 grosor 0.30 alero 0.40
muro E (largo / 2 - 0.45)

Tras emitir un muro, el cursor avanza a su extremo, listo para el siguiente muro sin necesidad de reposicionar.

Por dos puntos (forma de … a …)

muro de <pos1> a <pos2> [como NAME] [grosor T] [alero E]

Cada posición puede ser una tupla (x, y), una variable de tupla, o el nombre de un ancla previa. El cursor salta al primer punto y queda al final del muro.

muro de (0, 0) a (6, 0) como sur
muro de sur.fin a este.fin como diagonal
tabique de p1 a p2 como tab_central

Cursor

El cursor es solo una posición (x, y) — no tiene rumbo propio: cada muro/pared/tabique lleva el suyo. Tras emitir un muro, el cursor queda en su extremo final.

SentenciaEfecto
inicio en (x, y)fija el cursor en una posición absoluta
inicio en <ancla>fija el cursor en un ancla previamente declarada
desde <ancla>salta a un ancla con auto-corrección (ver más abajo)
cerrartraza un muro recto del cursor al primer vértice del polígono actual

Convención de orientación: +X = Este, +Y = Norte. Polígonos exteriores en sentido antihorario (CCW).

Anclas

Puntos con nombre. Hay tres formas de declararlas:

  1. Implícita en el nombre del muro: muro E 6 como fachada_sur registra automáticamente dos anclas: fachada_sur (inicio del muro, en su cara exterior) y fachada_sur.fin (extremo, también en cara exterior).
  2. Dentro de un muro: ancla a 2.50 como cocina_in coloca un ancla a 2.50 m del inicio del muro, en la cara interior.
  3. Libre: ancla en (3.5, 4.0) como centro declara un punto sin asociarlo a ningún muro. Útil para anclar muebles, pilares libres o como extremo de muro de A a B.
muro E 6 como fachada_sur
  ancla a 2.50 como cocina_in

# más adelante
desde cocina_in
tabique N 3.00

# o desde el extremo del muro
desde fachada_sur.fin
tabique N 2

# ancla libre
ancla en (3.5, 4.0) como centro_estancia

Tres formas de medir el offset del ancla en muro

Las distancias dentro de un muro se miden desde donde arranca el trazo (sentido del polígono). Cuando eso choca con tu intuición, tienes dos alternativas:

ancla a 3.00 como p1                       # 3 m desde el inicio
ancla a 3.00 desde fin como p2             # 3 m desde el final
ancla a 3.00 desde fachada_sur como p3   # 3 m perpendicular a fachada_sur

La tercera forma es la más natural cuando varias anclas deben quedar a la misma altura: en lugar de pensar en sentidos de trazado, todas se referencian desde el mismo muro (típicamente la fachada sur) y quedan automáticamente alineadas.

Auto-corrección al usar desde

Cuando arrancas un muro nuevo desde un ancla pegada a otra pared (con desde NAME seguido de un muro/pared/tabique), HDL toma dos decisiones automáticas a partir del rumbo del nuevo muro:

1. Cara del muro de origen

Elige la cara (interior o exterior) que evita que el cuerpo del nuevo muro cruce el del existente. Tú no tienes que sumar/restar el grosor a mano.

2. Lado del cuerpo del nuevo muro

El cuerpo del nuevo muro crece siempre hacia +X (en muros verticales) o +Y (en muros horizontales), independientemente de si el rumbo es N o S, E u O. Esto se traduce a un bodySign interno: +1 = cuerpo a la izquierda del rumbo (CCW estándar), −1 = a la derecha. Resultado: dos tabiques que cruzan otra pared por el mismo punto quedan visualmente alineados aunque uno suba y otro baje.

muro E 8 como carga
  ancla a 3 como junta

# Cruz alineada: ambos cuerpos al este de x=3
desde junta
tabique N 3 como sube         # bodySign=-1 → cuerpo este

desde junta
tabique S 3 como baja         # bodySign=+1 → cuerpo este
Los muros que no arrancan con desde (perimetrales, polígonos cerrados) y los muro de A a B mantienen siempre bodySign = +1 para no romper la convención CCW del polígono.

Puertas y ventanas

Se anidan dentro de un muro. La posición es la distancia desde el inicio del muro.

muro E 6 como fachada_sur
  puerta a 1.20
    ancho 0.90
    tipo abatible
    bisagra derecha
    abre dentro
    hojas 1
  ventana a 4.00
    ancho 1.50
    antepecho 1.00
    alto 1.20

Sentido de apertura

Para puertas en muros exteriores basta con abre dentro o abre fuera. Para tabiques interiores conviene nombrar la habitación o un cardinal absoluto:

puerta a 3.00
  abre hacia dormitorio    # nombre de habitación

puerta a 3.00
  abre N                   # cardinal absoluto

puerta a 3.00
  abre dormitorio          # atajo: hacia es opcional

El renderer encuentra la habitación por nombre, calcula su centroide y hace que la hoja barra hacia ese lado. Con cardinal el barrido es absoluto en mundo.

Tipos de puerta

Tipos de ventana

Variantes de posición de hueco

puerta a 1.20                  # 1.20 m desde el inicio
puerta a 1.20 desde fin        # 1.20 m desde el final
puerta centrada                # centrada en el muro

Pilares

Tres formas de declarar pilares según dónde estén:

# Atado a un muro: anidado en él, con offset desde su inicio
muro E 6 como sur
  pilar a 3
    ancho 0.40
    fondo 0.40

# Pilar libre, posición absoluta
pilar en (3, 2)
  ancho 0.40
  fondo 0.40
  rotacion 0

# Pilar libre centrado en un ancla previa
pilar desde esquina_NW
  ancho 0.30

El pilar libre se sitúa centrado en la posición indicada. rotacion gira el rectángulo en grados (default 0). Default si no se especifican dimensiones: 40 × 40 cm.

Habitaciones

habitacion salon
  delimita [fachada_sur, fachada_este, tab_central, fachada_oeste]

El compilador rellena la habitación con un tono suave en el render y la utiliza para validar la colocación de muebles y para resolver abre hacia.

Plantas (niveles)

Una vivienda de varios niveles se describe con bloques planta NAME. La idea es:

escala metros

# Común a todas las plantas: el perímetro
muro E 7 como sur
muro N 5 como este
muro O 7 como norte
muro S 5 como oeste
cerrar

planta baja
  # tabiques propios + habitaciones
  muro de (0, 2.8) a (7, 2.8) como divisor_pb
  habitacion salon
    delimita [sur, este, divisor_pb, oeste]
  habitacion cocina
    delimita [divisor_pb, este, norte, oeste]

planta primera
  muro de (0, 2) a (7, 2) como divisor_p1
  habitacion estar
    delimita [sur, este, divisor_p1, oeste]

Reglas

Pendiente: solo_en [lista] para restringir un elemento top-level a algunas plantas concretas, escaleras como primitiva del lenguaje, y hueco automático en planta superior conectado a la escalera.

Muebles (integración con MFL/MDL)

Una habitación puede contener muebles definidos en otros DSLs del proyecto:

mueble cocina/bajo_fregadero.mfl
  contra fachada_sur
  a 0.40
  altura 0

mueble cocina/isla.mfl
  en (2.50, 1.80)
  rotacion 45

contra <muro> y rotacion son mutuamente excluyentes: o pegado a una pared (autorota), o libre con rotación absoluta.

v1 dibuja los muebles como un footprint esquemático. La integración real con el compilador MFL para obtener el modelo 3D específico está prevista para v2.

Escaleras (nuevo 2026-05-26)

El bloque escalera declara un tramo de escalera independiente con su forma, número de pasos y dimensiones. Posición vía en (x, y) o desde <ancla>.

escalera principal
  en (1000mm, 2000mm)
  forma        = recta          # recta | espiral | l | u
  pasos        = 14
  huella       = 280mm
  contrahuella = 175mm
  ancho        = 900mm
  rumbo        = 0              # 0|90|180|270 dirección de subida

El compilador calcula automáticamente largo = pasos × huella (proyectado en planta) y alto = pasos × contrahuella (subida total). Si se declara nombre, se crean 4 anclas asociadas: NAME, NAME.fin, NAME.izq, NAME.dcha.

Cotas (nuevo 2026-05-26)

El bloque cota es una anotación dimensional entre dos puntos del plano. Acepta tuplas (x, y) o anclas con nombre.

cota fachada-sur
  desde-punto = (0, 0)
  a-punto     = (6000mm, 0)
  etiqueta    = ancho fachada      # opcional, auto = distancia en m
  offset      = 500mm              # mm desde la línea base

# También sirve referenciar anclas:
cota
  desde-punto = fachada
  a-punto     = fachada.fin

Si omites etiqueta, se calcula automáticamente como la distancia entre los dos puntos en metros con 2 decimales.

Comentarios

# comentario de línea

###
comentario en bloque
multilínea
###

/* también vale
   con la sintaxis estilo C  */

muro E 6 /* inline */ como sur

Editor — atajos del lienzo

AcciónEfecto
Rueda del ratónZoom in/out (centrado en cursor)
Click + arrastrarMover el plano
Doble clickReset (auto-fit centrado al canvas)
Splitter centralRedimensionar editor / canvas

Errores y warnings

El compilador es tolerante: nunca lanza excepciones, acumula errores y warnings con el número de línea. El editor los muestra debajo del código y mantiene el último render válido para que sigas trabajando aunque haya una línea a medias.