mueble nombre # dimensiones, materiales, zócalo, patas... distribucion # grid + asignaciones zona A1..A3 puerta # overlay (opcional) montaje # pendiente
Indentación 2 espacios. Comentarios con #.
| ancho | mm — anchura |
| alto | mm — altura |
| fondo | mm — profundidad |
| grosor | mm — tablero (defecto 19) |
| tablero <color/textura> | carcasa |
| frente <color/textura> | puertas/cajones |
| canto fino|grueso | 0.4mm o 2mm ABS |
| trasera fino|tablero|ranurar | tipo de fondo (también acepta ranurado) |
Texturas: roble · pino · haya · nogal. Colores hex: #1a1a1a o nombres (blanco, negro...). Los hex #XXXXXX NO se confunden con comentarios.
patas 4 alto = 120 grueso = 40 retranqueo = 50 anclaje = inserto # tornillo|inserto|pegado
Anclaje: tornillo (4 tornillos por pata, defecto), inserto (rosca M6 + tornillo M6×40, típico de tarugo), pegado (sin tornillería). Sintaxis vieja sigue funcionando: altura-patas, grosor-patas...
ruedas 4 zocalo 80 retranqueo = 60 lateral = 30 trasero = 0 coronacion 60
Cada bloque acepta valor inline (cantidad/altura) y props anidadas. Para desactivar: zocalo no.
| sin-lateral-izq si | quita el lateral izquierdo |
| sin-lateral-dcha si | quita el lateral derecho |
| sin-techo si | sin tablero superior |
| sin-suelo si | sin tablero inferior |
cornisa alto = 35 perfil = escalon voladizo = 10
Perfiles: escalon · recto · redondo · curvo · corona · gola. Se cuenta por metros lineales en el despiece. Hardware: clavillos pin 1mm + tornillos ocultos + cola blanca. Forma corta: cornisa 30.
# tablero superior + holguras entre puertas y laterales marco superior = 80 entre = 4 lateral = 4
Fuerza puertas encastradas automáticamente. Tablero superior aparece en despiece + 4 confirmats. Forma corta: marco 80 (solo altura).
# bajo cocina con paso de tubos trasera = no largueros superior = si inferior = si alto = 80
Sin fondo pero con dos travesaños horizontales arriba/abajo. Cada larguero = 4 confirmats (2 por lateral). Aparece en el despiece. Sintaxis vieja larguero-superior / larguero-inferior también funciona.
Atajo: ` (backtick) abre/cierra · Ctrl+Enter o ▶ ejecuta · Esc cierra · arrastra por la barra superior
| A1 | resumen de la celda |
| A1.bisagra | valor de una propiedad |
| A1.alto | dimensión real de la celda en mm |
| mueble | resumen del mueble entero |
| lateral-izq · techo · suelo · tapa · fondo · zocalo | descripción de la pieza estructural |
| <nombre-de-zona> | datos de la zona con nombre |
| ? | aliases activos |
| ?? | MFL exportado completo |
| añadir mueble · nuevo mueble | crea un mueble nuevo en el escenario (no modifica el actual) |
| posicion = x, y | dentro del bloque añadir/nuevo mueble · mm respecto al origen (0,0) dibujado en el lienzo |
Crear un mueble nuevo (no modifica el actual; el plano del fondo es común a todos):
añadir mueble armario ancho = 1200 alto = 2000 fondo = 400 posicion = 800, 0 # x,y mm desde el origen — sólo XY, sin Z distribucion columnas = 2 filas = 1 A1 = puerta A2 = puerta
añadir mueble y nuevo mueble son equivalentes. Sin esa palabra inicial, mueble X se sigue interpretando como modificación del mueble actual. Convención Cartesiana: X crece a la derecha, Y crece hacia arriba (altura desde el suelo). El origen (0,0) está dibujado abajo-izquierda del lienzo: eje X rojo, eje Y verde. Un mueble con posicion = 0, 0 apoya en el suelo. Para apilar otro encima, su Y = altura del mueble que le soporta (p.ej. posicion = 0, 720).
Expresiones aritméticas + variables locales:
comoda.ancho → 800 comoda.lateral_izq.ancho → 19 comoda.tapa.voladizo_frente → 30 comoda.ancho - 2 * comoda.grosor → 762 _libre = comoda.ancho - 2*comoda.grosor _libre / 3 → 254
Operadores + - * / y paréntesis. Variables con prefijo _ persisten en la sesión. Acceso jerárquico con . sobre objetos: mueble, comoda (nombre), lateral_izq/_dcha, techo, suelo, tapa, fondo, zocalo, armazon, A1...
| A1.bordes | qué piezas delimitan la celda (4 lados) |
| A1.borde-arriba | solo una cara (techo, divisor_h_N…) |
| techo · lateral_izq · divisor_h_1 | info de la pieza · dimensiones · orient. |
| techo.uniones | con qué piezas se une (L-corner, T-joint, cross, butt) |
| union(a, b) | info de la unión + hardware actual |
| union(...).hardware = allen×2 | override persistido (pasa a despiece + CNC) |
| union(...).note = "..." | nota libre asociada a la unión |
| inventario | total de hardware del mueble |
| cnc · export | resumen del export con operaciones por pieza |
| <pieza>.operaciones | lista de taladros/fresados (con coords y diámetros) |
| validar | warnings/errores de las uniones |
| montaje | secuencia recomendada de ensamblaje paso a paso |
Tipos de hardware: tubillón, minifix, allen, escuadra, cabezal escondido, tornillo madera, grapa. Sintaxis libre: tubillón×4 + minifix×2.
construccion armazon # caja|armazon poste = 40 lateral = 12 travesano = 35 ranura = 10
En modo armazón los postes son las patas. Trasera encastrada en ranuras de los postes traseros. Sintaxis vieja: armazon-poste, armazon-lateral... también funciona.
caja joyero ancho = 300 fondo = 200 alto = 80 tapa alto = 25 bisagras = 2 apartados columnas = 3 filas = 2 piso # el 1º es el de abajo alto = 50 cajones = 2 cierres = 2 asa = frente # frente | tapa | no acabado = laton
Tapa y pisos soldados; laterales y trasera hasta el suelo. Repite piso para más pisos. tapa = no = bandeja. Ver manual → Caja / Joyero.
tapa izq = 50 dcha = 50 frente = 30 trasero = 0 encimera = si # piedra/compacto
Defecto: tapa de madera (copia carcasa). Sintaxis vieja voladizo-izq/dcha/frente/trasero sigue funcionando.
distribucion columnas = 3 A:400 B:400 C:resto filas = 2 1:300 2:resto A1 = puerta B1..B2 = cajon # rango: 1 sola pieza con span cantidad = 3 A2.bisagra = derecha # excepción A1..C1.bisagra = izquierda # por rango
Tamaños: número en mm, fracción (1:resto) o ausentes. Rangos A1..A2 = puerta crean UNA puerta alta con rowSpan=2, no dos puertas separadas.
distribucion columnas = 3 filas = 1 A1 = puerta B1 = abierto B1.dividir-horizontal = 3 # B en 3 pisos C1 = puerta
El compilador expande filas a 3 y mantiene A y C enteras. Existe también dividir-vertical análogo para subdividir una fila en columnas.
El compilador asigna solo:
| Primera columna con puerta | → izquierda (sobre lateral) |
| Última columna con puerta | → derecha (sobre lateral) |
| Columnas intermedias | → encadenan vecina izq (sin colisiones) |
Solo escribe .bisagra si quieres romper la regla. Aviso del compilador si dos puertas adyacentes acaban con bisagras enfrentadas (chocarían al abrir 90°).
mueble armario ancho = 1200 distribucion.columnas = 3 distribucion.A1 = puerta distribucion.A1.bisagra = derecha puerta.tirador = pomo # default global
Prefijos válidos: distribucion, puerta, cajon, balda, barra, carpinteria. Mezclables con la sintaxis indentada clásica.
| puerta | puerta batiente |
| cajon | cajón o módulo de cajones |
| balda | balda fija (divide en filas) |
| barra | barra de colgar |
| abierto | hueco vacío |
| ciego | panel ciego (sin apertura) |
| falso-frente | panel decorativo fijo |
| bisagra izq|dcha|arriba|abajo | lado del giro (auto si no se indica) |
| hojas 1|2 | una o dos hojas |
| estilo superpuesta|encastrada|interior | superpuesta=overlay (def), encastrada=flush, interior=retranqueada. Sinónimos: solapada/embutida. |
| cristal si|no | puerta con vidrio |
| espejo si|no | |
| cierre-suave si|no | amortiguador |
| kit si|no | comprada hecha (no se fabrica) |
| tirador | ver tabla tiradores |
| cantidad <n> | cajones en la celda |
| separacion <mm> | entre frentes (def 2) |
| estilo superpuesto|encastrado | overlay/flush del frente. Sinónimos: solapado/embutido |
| espejo si|no | frente con espejo |
| cierre-suave si|no | guía con freno |
| push si|no | sin tirador, push-to-open |
| kit si|no | cuerpo comprado, fabricamos solo frontal |
| tirador | ver tabla tiradores |
| cantidad <n> | balda: nº de baldas |
| regulable si|no | balda en sistema 32mm |
| grosor <mm> | balda: si difiere |
| altura <mm> | barra: desde el techo |
| material aluminio|acero|madera | barra |
| tirador barra | tirador alargado (defecto) |
| tirador pomo | tirador puntual |
| tirador perfil | canal en el frente |
| tirador ninguno | sin tirador (push-to-open) |
zona A1..A3 puerta nombre = puerta-columna hojas = 1 bisagra = izquierda tirador = barra cristal = no mostrar = si kit = si
Rango contiguo H o V. Tipo: puerta (estructural) o ciego.
mueble x primera_columna = a1..a3 # declaración global fila_top = a1..c1 distribucion primera_columna = puerta primera_columna.bisagra = derecha fila_top = balda zona primera_columna puerta
Identificador en minúsculas (sin tildes). Visible desde distribucion y zona.
mueble x puerta # defaults para TODAS las puertas bisagra = izquierda tirador = barra cajon cierre-suave = si kit = si distribucion ...
Bloques puerta, cajon, balda, barra a nivel mueble = defaults; las celdas pueden sobrescribir.
| = | asignación |
| .. | rango (A1..C4) |
| resto | ocupa el sobrante |
| si / no | booleanos en castellano |
| # ... fin línea | comentario |
| ### ... ### | comentario de bloque |
El orden importa: lo último gana. Lo más específico (celda) sobrescribe lo heredado (defaults).
mueble base ancho = 1200 alto = 800 ... mueble alto ancho = 1200 alto = 700 ...
Varios bloques mueble en un fichero = varios muebles independientes.
Lote de keywords añadidas al MFL para cubrir propiedades del modelo Furniture / GridCell / Zone que antes no eran expresables. Tests en mfl/tests/mfl-gap-2026.test.js.
grosor-tapa = 38 # mm — encimera más gruesa que carcasa grosor-suelo = 25 # mm — suelo más fino
frente-corredero 2 fondo = 60 # profundidad TOTAL del paquete (mm) profundidad-carril = 80 hoja 1 material = glass # wood | glass | mirror filas-cristal = 3 columnas-cristal = 2 junquillo = 25 hoja 2 material = wood tirador = channel # recessed | channel | none
base 30 color = #444 voladizo-frente = 15 voladizo-izq = 10 voladizo-dcha = 10
listones ancho = 30 # mm grosor = 15 separacion = 25 direccion = vertical # vertical | horizontal color = #c9a87a
trasera-cubre-zocalo = si veta-trasera = horizontal # auto | horizontal | vertical
tablero-inferior = 80 # nuevo: marco superior + inferior retranqueo-tapa = 10 # mm de retranqueo en la tapa retranqueo-suelo = 15
patas 4 forma-patas = redonda # cuadrada | redonda retranqueo-patas-trasero = 20 retranqueo-patas-lateral = 30
cubrejunta-izq = 30 # tira que tapa la junta con el mueble vecino cubrejunta-dcha = 25 color-suelo = #aaa # color/textura por cara (override de carcasa) color-trasera = #bbb color-tirador = #ccc
zocalo 80 estilo = solo-frente # normal | solo-frente | solo-trasero | frente-y-trasero esquina = lados-cubren # front-cover | sides-cover ocultar-izq = si # oculta el listón izquierdo del zócalo ocultar-dcha = si coronacion 60 estilo = normal esquina = frontal-cubre
cornisa 35 perfil = gola perfil-svg = perfiles/cornisa/g1.svg ancho = 40 referencia = Maderpan-G1 longitud-comercial = 2400 solo-frente = si
faldon 120 frente = si izq = si aleros 250 izq = si dcha = si apoyo-puerta = si toallero lado = left altura = 600 diametro = 18
tapa-bisagra cantidad = 3 alto = 200 cierre-cofre = si puerta-jambas modo = overlay # between | overlay grosor = 22 holgura = 3 bisagra = derecha apertura = 110
tapa-poligonal = poly-42 anclaje-tapa = tornillos-tapon anclaje-suelo = liston # cleat | brackets | none
encimera grosor = 38 voladizo-frente = 25 lazy-susan = si altura = 0 # mm desde el suelo del mueble
A1 = cesta # wire-basket extraíble (kit) alto-cesta = 120 color-cesta = anthracite # white | anthracite | beige extraible = si A2 = cajas # cajas organizadoras de fieltro cantidad-cajas = 4 color-cajas = white alto-caja = 80 A3 = puerta hojas = 2 anclaje-tirador = tl # 1ª hoja: top-left anclaje-tirador-dcha = tr # 2ª hoja: top-right textura = roble # override del panel global falsa = si # estética sin bisagras apertura = 110 # grados de apertura (45..180) anchos-hoja = 500,700 # anchos custom de cada hoja (mm)
zona A1..A2 puerta hojas = 2 cierre-suave = si espejo = si apertura = 120 color = #112233 anchos-hoja = 400,600
Segundo lote tras auditar el quick-panel contra el lenguaje: modo columnas, empotrado, canteado y extras de mueble/celda/zona. Tests en mfl/tests/mfl-gap-2026-07.test.js.
distribucion-columnas # sustituye a distribucion columna 400 hueco 300 = cajon # mismas props que una celda cantidad = 2 hueco resto = puerta bisagra = derecha columna resto hueco resto
empotrado anchos = 2000, 1995, 2003 # arriba, medio, abajo (1 valor = los 3) altos = 2400 # izq, centro, dcha fondos = 600 # 4 esquinas diagonales = 3120, 3118 pared = ladrillo # tabique | ladrillo | piedra fijacion = escuadras # liston-pared | escuadras | pasante | ninguna obstaculo columna # columna|tubo|viga|enchufe|rodapie|otro x = 100 ancho = 120 fondo = 150 hasta = 900
canteado tapa = frente, izq, dcha lateral-izq = frente, arriba # piezas: tapa suelo lateral-izq/dcha zocalo coronacion
forma-patas = inclinada # cuadrada | redonda | inclinada (escandinava) apertura-patas = 30 # % apertura del pie (solo inclinada) color-patas = #663300 color-lateral-izq = #aabbcc # idem textura-lateral-izq/dcha veta-tapa = horizontal # veta-lateral-izq/dcha, veta-suelo, veta-frontal bastidor = si # face frame; ancho-bastidor = 60 anclaje-pared = no # quita antivuelco (activo por defecto) rinconera = si # frente-rincon = 300; mano-rincon = derecha color-canto = #112233 # idem textura-canto voladizo-suelo-frente = 30 # idem -izq/-dcha/-trasero profundidad-ranura = 14 # fondo ranurado vuelo-superior = 40 # laterales sobre el cuerpo; vuelo-inferior
A1 = mesa-abatible # pivote-abatible = 150 B1 = puerta bisagra = arriba abatible = si # hoja-tablero con patas en U rueda-u = si # ruedín bajo puertas grandes puerta-cuadro = si # panel central de madera tirador = concha # tambien: gola color = #ff8800 etiqueta = vajilla cara = lateral-izq organizador-puerta # bandeja interna; altura + fondo altura = 300 A2 = barra altura = 250 # mm desde el techo del interior B2 = frente-fijo # diametro = 25 (Ø tubo) A1.trasera-celda = falso-frente # panel | abierto | falso-frente A1.bisagra-trasera = derecha A1.ruedin-trasero = si
zona A1..B1 mesa-abatible # pivote-abatible = 120 zona A2..B2 puerta abatible = si alto-hoja = 500 zona A3..B3 puerta corredera = si # deslizante en vez de batiente hojas-correderas = 3 # 2 | 3
| 📂 Cargar MFL | Abre fichero .mfl en el editor |
| 💾 Guardar MFL | Descarga el código actual como <mueble>.mfl |
| 📥 Cargar JSON/SVG | Importa proyecto JSON o SVG (con metadata) y regenera el MFL |
| ↓ Exportar JSON/SVG/GLB | Proyecto, proyecto SVG, o modelo 3D real (metros, sin herrajes) |
| ↓ Exportar despiece/presupuesto | CSV (piezas+medidas / material+herrajes+total) |
| ↓ Exportar PLANK | Paneles con tag+medidas para PLANK Visual (sin posición real) |
| ↗ Abrir visor GLB | Pestaña nueva, arrastra el .glb exportado |
Los SVG exportados por MuebleLab llevan el JSON del proyecto incrustado en <metadata>. Cargar un SVG → reconstruye Furniture → genera MFL automáticamente vía furnitureToMFL().
Sentencias de programa, sueltas sin indentar — no van dentro de mueble. No generan piezas.
@validate soft # off|soft(default)|strict @export svg armario-negro @export glb armario-negro # repetible, un formato por línea
| svg / json | proyecto (recargable en app.php) |
| glb | modelo 3D real, sin herrajes |
| cutlist | CSV pieza+medidas |
| presupuesto | CSV material+herrajes+total |
| plank | paneles PLANK, tag+medidas (sin posición real — v1) |
Solo dispara la descarga en mfl.html, tras compilar sin errores. Sin comillas ni paréntesis (tokeniza por espacios). Dentro de para cada genera una directiva por vuelta con el nombre ya sustituido — ver "Bucles" más abajo.
datos modulos - nombre=bajo-40 ancho=400 alto=800 fondo=600 - nombre=bajo-60 ancho=600 alto=800 fondo=600 para cada m en modulos mueble $m.nombre ancho = $m.ancho alto = $m.alto fondo = $m.fondo distribucion columnas = 1 filas = 1 A1 = puerta fin-para
Bucle ACOTADO (sin mientras ni mutación, como for_each de Terraform): el nº de vueltas lo fija el tamaño de la tabla, así que siempre termina. $var.campo se sustituye en CUALQUIER token de la vuelta — nombre del mueble, dimensiones, incluso una directiva @export. fin-para (o fin) es obligatorio — error de compilación si falta.
si $m.tipo = puerta A1 = puerta A1.hojas = $m.hojas sino si $m.tipo = cajon A1 = cajon sino A1 = abierto fin-si
Operadores: = <>/!= < > <= >= (numérico si ambos lados parecen número, si no compara texto). Funciona anidado en cualquier bloque — dentro de distribucion, de mueble, o suelto — no hace falta que esté dentro de un para cada. La rama se decide al expandir el fichero: el mueble final sigue siendo 100% declarativo. fin-si obligatorio.
import { compileMFL, generateProjectSVG, serializeFurniture } from 'https://mueblelab.com/mfl/dist/mfl-compiler.js'; const { cabinets, errors } = compileMFL(textoMFL); const svg = generateProjectSVG( { furnitures: [{ id: 'm0', x: 0, y: 0, furniture: cabinets[0] }], tabletops: [] }, serializeFurniture, { crop: true } );
Un solo fichero, sin dependencias externas, funciona igual en Node y en el navegador (<script type="module">) — cero fs/child_process/nada específico de un entorno, con cabecera CORS para importarlo desde cualquier dominio. Solo trae compileMFL + exportar a SVG — nada de 3D/GLB/despiece/herrajes (eso vive en la app principal, no está pensado para usarse suelto todavía).
Bajo el editor hay una consola de 3 líneas (con scroll, hasta 200 entradas) que muestra:
| 🔴 errores | propiedad desconocida, bloque no reconocido, tipo de celda inválido |
| 🟡 warnings | colisiones de bisagras, pegado en mueble grande... |
| 🟢 ok | "✓ N mueble(s) compilado(s)" |
Botón 🔩 Ver tornillería hace transparentes los tableros (0.13 op.) y deja visibles:
| tornillos & levas | aglomerado, minifix, allen |
| bisagras | cazoleta + brazo + plato + tornillos |
| guías de cajón | raíles + bolas de rodamiento (4–10 por guía) |
| tiradores | barra, pomo, perfil |