O que Joinery faz?
Uma peça, uma página, um pacote. O visitante vê a peça montada, arrasta um controle deslizante e ela se desmonta, percorre os passos de montagem, clica em uma peça e lê suas dimensões de estoque. O mesmo modelo que movimenta as peças escreve a lista de cortes, os desenhos e o manual, para que nada no papel possa discordar do que está na tela.
SKILL_DIR é a pasta onde este arquivo está localizado. As construções e o pacote vão para ./joinery-out na pasta de onde você executa.
Primeira execução
cd "$SKILL_DIR" && npm install
Node 20.10+. Para imagens de revisão e imagens do manual, você precisa do Chromium: npx playwright install chromium, ou aponte CHROMIUM para qualquer binário Chrome/Chromium (CHROMIUM=/usr/bin/google-chrome).
O pipeline
foto + âncoras ─► spec.json ─► model.js ─► validar ─► página ─► imagens ─► pacote
| Etapa | Comando | O que você obtém |
|---|---|---|
| 1. Interpretar | você, lendo a foto | spec.json: tipo, âncoras, materiais, cada peça nomeada, cada encaixe escolhido, cada suposição escrita |
| 2. Modelar | você, escrevendo model.js | a peça como uma função de seus parâmetros: caixas, encaixes, passos |
| 3. Validar + empacotar | node "$SKILL_DIR/pack.mjs" ./my-piece | recusa empacotar se algo colidir ou flutuar; escreve lista de cortes, desenhos, diagramas de corte de tábuas e placas, estoque, ferramentas e acabamento, manual (e manual.pdf quando o Chromium estiver presente) |
| 4. Construir página | node "$SKILL_DIR/build.mjs" ./my-piece | joinery-out/dist/my-piece.html, offline, ~570 KB |
| 5. Revisar | node "$SKILL_DIR/capture.mjs" my-piece --stills steps | uma folha de contato de cada vista e passo — leia, corrija, repita |
| 6. Empacotar novamente | node "$SKILL_DIR/pack.mjs" ./my-piece | manual e PDF agora carregam as imagens dos passos |
Comece copiando o exemplo mais próximo da peça. Cada um tem todos os arquivos que uma peça precisa: spec.json, model.js, main.js. Uma peça geralmente fica na própria pasta da pessoa, não em SKILL_DIR: após copiar, altere os dois imports ../../kit/ (em model.js e main.js) para o caminho absoluto $SKILL_DIR/kit/.
| Exemplo | Copie para | Mostra |
|---|---|---|
parsons-table | uma mesa simples, escrivaninha, banco | o mínimo: pernas, travessas, tampo, mortise-and-tenon, botões. 64 linhas |
walnut-racetrack-table | peças redondas, ovais ou cônicas | perfis roundedRect / circle, pernas redondas cônicas, tenões curtos o suficiente para não se encontrarem na perna |
walnut-display-cabinet | uma peça com curvas ou vidro | cantos laminados curvos (quarterRing, stock.layers), portas de vidro em dobradiças de grampo, pinos de prateleira, fundo encaixado, um plinto |
walnut-entry-unit | embutidos, guarda-roupas, unidades estilo cozinha | vários corpos, portas de painel e moldura, gavetas em corrediças, prateleiras flutuantes, MDF pintado junto com folheado, encaixes para LED e ganchos |
walnut-hallway-unit | uma peça mista de aço e madeira | uma estrutura de aço soldada segurando caixas de madeira, portas de painel de junco, um nicho aberto deixado ao redor de um painel elétrico |
Etapa 1: leia a foto honestamente
Uma única foto não fornece escala nem estrutura oculta. Este skill é interpretação de design, não fotogrametria. Antes de escrever qualquer geometria:
- Obtenha âncoras. Peça uma a três dimensões reais (C × L × A total, ou uma conhecida como "o tampo tem 180 cm"). Se a pessoa não puder fornecer nenhuma, use os padrões ergonômicos em
kit/validate.js(jantar 750 A, assento 450 A) e diga isso. Todas as outras dimensões são uma proporção lida da foto vezes a âncora. - Nomeie o tipo.
mesa-de-jantar,cadeira,estante… isso seleciona as verificações ergonômicas e a construção típica. - Liste o que você pode ver e o que não pode. Pernas, tampo, prateleiras visíveis são
visible. Travessas sob um tampo grosso, painéis traseiros, esticadores, corrediças de gaveta, blocos de canto sãoinferred— marque-os comoinferred: truena peça para que sejam sinalizados em todas as saídas. O construtor irá substituí-los; eles devem saber quais são seus. - Escolha os encaixes da biblioteca (
templates/joinery-library.md), indexados por tipo × material × oficina. Pergunte qual oficina o construtor tem se não for óbvio (shop:hand,cabinet,cnc); também seleciona a lista de ferramentas. Padrão para oficina de marcenaria: mortise-and-tenon para pernas/travessas, dados para prateleiras, cavilhas ou Dominos para painéis, parafusos de bolso apenas onde ocultos. Escreva a escolha e o motivo emspec.source.assumptions. - Leia o material e o acabamento. Espécie pela cor e figura, espessura pela proporção da borda, tratamento da borda (arredondamento / chanfro / reto) pelos realces. A espessura deve recair em um tamanho de estoque (
STOCK_Temkit/validate.js) — 40, não 38,7. Definafinishpelo brilho: uma superfície aberta e fosca éhardwax-oil(o padrão) ouoil, uma película acetinada uniforme élacquer. Peças pintadas e de metal seguem seu material.
Escreva tudo isso em spec.json usando templates/spec.schema.json. O spec é para humanos: o construtor lê source.assumptions antes de qualquer outra coisa.
Etapa 2: construa o modelo
model.js exporta piece = definePiece({name, type, shop, finish, params, source, materials, build}). build(P) retorna {parts, joints, steps, hardware}. O exemplo tem 70 linhas; uma cadeira tem cerca de 120.
Peças são caixas alinhadas aos eixos em sua pose montada: box(id, name, [sx, sy, sz], [x, y, z], {grain, material, edge, explode, inferred, note}). x é comprimento, y é para cima com o chão em 0, z é profundidade. grain é o eixo ao longo do qual a madeira corre — decide o comprimento do estoque na lista de cortes e o padrão dos anéis no render. Peças que são do mesmo corte recebem o mesmo name e se fundem em uma linha da lista de cortes; id permanece único.
Peças curvas e com raio mantêm uma caixa delimitadora para size/at e adicionam profile: {axis, path, note}: o contorno real através de axis, centralizado na caixa (quarterRing(R, t, [su, sv]) para um canto curvado, roundedRect(w, h, radii) para vidro com cantos arredondados, um fundo ou um tampo oval, circle(d) para uma perna redonda; profile.taper: {to, end} afunila em direção a uma extremidade). Ele renderiza extrudado, valida em seu contorno e desenha como seu contorno. Quando a caixa não é o estoque (uma laminação curva), adicione stock: {L, W, T, layers, layerT} e a lista de cortes e a lista de compras usarão isso. Uma peça curva em duas direções (um encosto de cadeira esculpido, uma travessa composta) ainda não tem tipo de corpo: informe a pessoa, modele a extrusão reta mais próxima e diga isso em sua note.
Acessórios são ferragens compradas desenhadas em uma peça, não cortadas: fittings: [{kind, size, at, material, axis, dir, holes: {n, d, cc, axis}}] com at relativo ao centro da peça. Puxadores, ganchos e perfis de LED renderizam; seus furos para parafusos aparecem no desenho da peça. Liste-os também em hardware.
Cores por peça: uma entrada no mapa materials pode conter base, dark, ring, streak, rough, clearcoat, env para reajustar um material do kit para a foto sem alterar outras peças. Madeiras escuras oleadas em um tampo grande e plano precisam de rough ≈ 0,9 ou o brilho da luz principal as torna acinzentadas; amostre a foto e o render e compare números, não impressões.
Encaixes conectam dois IDs de peça: {a, b, type} onde a carrega o tenão/parafuso e b o recebe. Tipos: mortise-tenon (tenonLen, tenonT, shoulder, mitred), dowel (count, d, len), dado (depth), rebate (face, depth: um fundo em um rebate ao longo da borda de b), shelf-pin (count, d, len, inset: uma prateleira em pinos em b), hinge (face, at: [y mundo…], cup: 35 para furar a taça em a: uma porta voltada para +z pendurada em b), groove (width, depth: um painel ou fundo de gaveta flutuando na borda ou face de b), runner (uma caixa de gaveta em corrediças laterais em b), weld (aço com aço), pocket-screw, button, figure-8, screw, glue. shelf-pin e hinge permitem os poucos mm de folga que a ferragem preenche; toda peça deve estar unida ao resto ou a validação recusa. applyJoinery escreve as características correspondentes em ambos os membros: o tenão aumenta o comprimento do estoque na lista de cortes, a mortise aparece no desenho da perna com sua face e posição, e ambos renderizam. Um encaixe também diz ao validate que esses dois corpos podem se tocar.
Passos são o manual: {title, parts: [ids], note, check, view}. Cada peça deve aparecer em exatamente um passo. Ordene-os da forma que um construtor faria: submontagens primeiro (estruturas das extremidades, caixas de gaveta), depois o que as une, depois o que fica em cima, com a peça de cabeça para baixo quando for assim que se faz. view define a câmera para aquele passo na página e no manual.
Parâmetros. Tudo é um número em P. Altere L e as travessas, tenões, espaçamento dos botões e lista de cortes seguem. Esse é o objetivo: o mesmo model.js faz a versão de 1600 e a versão de 2200.
Regras que decidem se pode ser construído
- Comece pela foto, nunca pela imaginação. Construa contra ela e compare renders lado a lado: silhueta, proporção perna-tampo, balanço, onde a linha de sombra da travessa cai. Uma peça inventada a partir de "uma bela mesa de carvalho" sai genérica; o mesmo código reconstrói a real de perto quando tem algo para igualar.
- Estoque real. A espessura é um tamanho de estoque. Nada mais largo que 200 mm é uma tábua —
pack.mjstransforma em uma colagem de tiras e diz isso. Nada mais grosso que 50 mm é uma tábua — torna-se uma laminação. O grão corre ao longo do comprimento de cada peça, ou a validação avisa sobre grão curto. - Cada encaixe é um encaixe real. Duas peças só podem compartilhar volume por meio de um encaixe declarado. Tenões que se encontram dentro de uma perna devem ser
mitred: trueou encurtados; a validação verifica a colisão. Um tampo maciço largo deve ser preso com botões, figure-8s ou furos alongados — nunca colado rigidamente — e a validação avisa se for. - Corrija colisões com um número. Quando a validação reportar uma peça passando por outra, altere um valor em
Pou embuild. Nunca esconda com a câmera. - Escreva a suposição, não apenas a peça. Uma travessa que a foto não mostrou é
inferred: truecom umanote. A primeira caixa do manual lista cada suposição. - Um número, uma fonte. A lista de cortes, o desenho, o HUD na página e o manual leem todos
stockOf(part). Se um número parecer errado, corrija o modelo, não a saída.
Regras da página ao vivo
- A página é um arquivo HTML offline com menos de 1 MB (Three.js embutido). Peças grandes com muitas partes permanecem rápidas porque cada parte é uma caixa arredondada e a madeira é um shader, não uma textura.
- Estúdio de luz, luz principal quente, preenchimento frio, sombra suave no chão. O shader de madeira desenha figura de corte plano ao longo de
graine grão final nas extremidades automaticamente. Mantenharoughness ≥ 0,45; madeira brilhante em um fundo pálido parece plástico. - Deixado sozinho por 20 s, a página faz um tour: explode, percorre passos, raio-X por baixo. Qualquer entrada devolve o controle.
- O estado da URL impulsiona a captura:
?step=2,?explode=1,?iso=leg-fl,?view=under&xray=1,?panel=0. Com qualquer um desses definidos, a página captura em vez de animar, para que uma imagem seja a mesma a 5 fps que a 60.
Ciclo de revisão
Você não pode olhar para a página; pode olhar para imagens. Nunca relate uma peça como concluída sem ler uma folha da construção atual.
node "$SKILL_DIR/capture.mjs" <name> --stills steps→joinery-out/<name>-sheet.png: montada, explodida, frontal, raio-X por baixo, um bloco por passo.- Leia cada bloco contra a lista de verificação. Coloque a foto de referência ao lado dos blocos
fronteassembled. - Para uma peça,
--stills partsisola cada uma; para um estado,--still "step=3&view=under". - Corrija, reconstrua, volte para 1. Pare quando uma passagem não encontrar nada.
- Abra
joinery-out/<name>/manual.htmlda mesma forma e leia como o construtor faria.
Lista de verificação:
- Proporção. Contra a foto: espessura da perna vs comprimento, espessura do tampo vs comprimento, balanço, altura da linha da travessa. Dentro de 5% ou altere um parâmetro.
- Encaixes. Mortises aparecem nas faces que as travessas encontram; tenões visíveis na vista explodida e no raio-X; nada flutua no ar na vista explodida (uma peça sem encaixe não tem vetor de explosão que faça sentido).
- Passos. Cada passo adiciona algo que você pode ver; a câmera mostra as peças sendo adicionadas; peças já colocadas são visíveis por baixo. O passo 1 nunca é o tampo.
- Desenhos. Cada mortise, dado e furo em um desenho nomeia sua face e distância da extremidade. Comprimentos da lista de cortes que incluem tenões dizem isso.
- Estoque. A lista de estoque não tem tábua mais larga que 200 ou mais grossa que 50; colagens e laminações estão listadas. Cada peça está em uma tábua ou chapa nos diagramas de corte.
- Ferramentas e acabamento.
tools.mdlista o que a oficina do construtor usaria, e os comprimentos dos grampos fazem sentido para a maior colagem. Peças pintadas, folheadas e de metal recebem cada uma seu próprio acabamento. - Render. Nada a menos de 60 px de uma borda, o painel nunca cobre a peça, madeiras quase brancas (bordo, freixo) têm uma borda visível contra o fundo pálido.
Materiais
kit/stage.js → MATERIALS: carvalho-branco, carvalho-vermelho, nogueira, bordo, freixo, faia, pinho, cerejeira, compensado-bétula, mdf, aço, latão. Adicione uma espécie como cores base/escuras mais força dos anéis e listras. Também: nogueira-mdf, nogueira-bendply (chapa folheada), mdf-preto, vidro (transparente, desenhado por suas bordas, encomendado cortado no tamanho certo no pacote em vez de cortado de tábuas). O mapa materials em definePiece os nomeia para a lista de cortes ("Carvalho branco, maciço").