조이너리 (Joinery)은(는) 무엇을 하나요?
한 조각, 한 페이지, 한 팩. 방문자는 조립된 가구를 보고, 슬라이더를 움직이면 분해되며, 단계별로 조립 과정을 살펴보고, 부품을 클릭하면 자재 치수를 확인할 수 있습니다. 부품을 움직이는 동일한 모델이 재단 목록, 도면, 설명서를 작성하므로, 종이에 적힌 내용과 화면에 보이는 내용이 서로 다를 수 없습니다.
SKILL_DIR은 이 파일이 있는 폴더입니다. 빌드 결과물과 팩은 명령을 실행하는 폴더의 ./joinery-out에 저장됩니다.
첫 실행
cd "$SKILL_DIR" && npm install
Node 20.10+ 이상이 필요합니다. 리뷰 스틸 이미지와 설명서 이미지를 생성하려면 Chromium이 필요합니다: npx playwright install chromium, 또는 CHROMIUM 환경 변수를 Chrome/Chromium 바이너리 경로로 설정하세요 (CHROMIUM=/usr/bin/google-chrome).
파이프라인
사진 + 앵커 ─► spec.json ─► model.js ─► 검증 ─► 페이지 ─► 스틸 이미지 ─► 팩
| 단계 | 명령 | 결과물 |
|---|---|---|
| 1. 해석 | 당신, 사진 읽기 | spec.json: 유형, 앵커, 재료, 모든 부재 이름, 모든 접합부 결정, 모든 가정 기록 |
| 2. 모델링 | 당신, model.js 작성 | 가구를 매개변수의 함수로 정의: 상자, 접합부, 단계 |
| 3. 검증 + 팩 | node "$SKILL_DIR/pack.mjs" ./my-piece | 충돌이나 떠 있는 부재가 있으면 패킹 거부; 재단 목록, 도면, 판재 및 합판 절단 다이어그램, 자재, 공구, 마감, 설명서(Chromium이 있으면 manual.pdf도 생성) |
| 4. 페이지 빌드 | node "$SKILL_DIR/build.mjs" ./my-piece | joinery-out/dist/my-piece.html, 오프라인, ~570KB |
| 5. 리뷰 | node "$SKILL_DIR/capture.mjs" my-piece --stills steps | 모든 뷰와 단계의 콘택트 시트 — 보고, 수정하고, 반복 |
| 6. 재패킹 | node "$SKILL_DIR/pack.mjs" ./my-piece | 설명서와 PDF에 단계 이미지 포함 |
가장 비슷한 예제를 복사하여 시작하세요. 각 예제에는 spec.json, model.js, main.js 파일이 포함되어 있습니다. 가구 파일은 일반적으로 SKILL_DIR이 아닌 개인 폴더에 위치합니다: 복사한 후 model.js와 main.js에 있는 ../../kit/ import 경로를 절대 경로 $SKILL_DIR/kit/로 변경하세요.
| 예제 | 복사 용도 | 설명 |
|---|---|---|
parsons-table | 간단한 테이블, 책상, 벤치 | 최소 구성: 다리, 가로대, 상판, 장붓구멍-장부, 버튼. 64줄 |
walnut-racetrack-table | 원형, 타원형, 테이퍼진 부재 | roundedRect / circle 프로파일, 테이퍼진 원형 다리, 다리 안에서 서로 겹치지 않도록 짧은 장부 |
walnut-display-cabinet | 곡선이나 유리가 있는 케이스 가구 | 벤트 라미네이션 모서리(quarterRing, stock.layers), 클램프 힌지 유리문, 선반 핀, 홈이 파인 뒷판, 받침대 |
walnut-entry-unit | 붙박이 가구, 옷장, 주방 스타일 유닛 | 여러 개의 캐비닛, 액자-패널 문, 레일 위 서랍, 플로팅 선반, 도장 MDF와 베니어 혼합, LED 및 후크 부속품 |
walnut-hallway-unit | 철제와 목재 혼합 가구 | 용접 강철 프레임에 나무 상자, 케인 패널 문, 전기 패널 주변에 남겨진 개방형 벽감 |
1단계: 사진을 정직하게 읽기
단일 사진은 어떤 치수도, 숨겨진 구조도 제공하지 않습니다. 이 스킬은 사진 측량이 아니라 설계 해석입니다. 기하학을 작성하기 전에 다음을 수행하세요:
- 앵커 확보. 전체 가로 × 세로 × 높이, 또는 "상판이 180cm"와 같은 하나의 알려진 치수 등 최대 3개의 실제 치수를 요청하세요. 사용자가 아무 치수도 제공할 수 없으면
kit/validate.js의 인체 공학적 표준(식탁 높이 750, 의자 높이 450)을 사용하고 그렇게 명시하세요. 다른 모든 치수는 사진에서 읽은 비율에 앵커를 곱한 값입니다. - 유형 지정.
dining-table,chair,bookshelf… 이 유형에 따라 인체 공학적 검사와 일반적인 구조 방식이 결정됩니다. - 보이는 것과 보이지 않는 것 목록 작성. 다리, 상판, 보이는 선반은
visible. 두꺼운 상판 아래의 가로대, 뒷판, 가로장, 서랍 레일, 모서리 블록은inferred— 해당 부재에inferred: true로 표시하여 모든 출력에서 플래그가 지정되도록 하세요. 제작자가 이를 재정의할 수 있습니다. 제작자는 어떤 가정이 여러분의 것인지 알아야 합니다. - 라이브러리에서 접합부 선택 (
templates/joinery-library.md), 유형 × 재료 × 작업장 기준. 작업장이 명확하지 않으면 어떤 작업장(shop:hand,cabinet,cnc)이 있는지 물어보세요; 이는 공구 목록도 결정합니다. 기본값은 캐비닛 작업장: 다리/가로대는 장붓구멍-장부, 선반은 장붓구멍, 패널은 다월 또는 도미노, 숨겨진 곳에만 포켓 스크류. 선택과 그 이유를spec.source.assumptions에 기록하세요. - 재료와 마감 읽기. 색상과 결에서 수종, 가장자리 비율에서 두께, 하이라이트에서 가장자리 처리(둥글림 / 모따기 / 날카롭게)를 결정합니다. 두께는 표준 자재 크기(
STOCK_Tinkit/validate.js)여야 합니다 — 38.7이 아닌 40. 광택에서finish를 설정합니다: 열린 무광 표면은hardwax-oil(기본값) 또는oil, 균일한 새틴 필름은lacquer. 페인트칠 및 금속 부재는 해당 재료에 따라 처리합니다.
이 모든 내용을 templates/spec.schema.json을 사용하여 spec.json에 작성하세요. 스펙은 사람을 위한 것입니다: 제작자는 다른 것보다 먼저 source.assumptions를 읽습니다.
2단계: 모델 구축
model.js는 piece = definePiece({name, type, shop, finish, params, source, materials, build})를 내보냅니다. build(P)는 {parts, joints, steps, hardware}를 반환합니다. 예제는 70줄이고, 의자는 약 120줄입니다.
부재(parts) 는 조립된 자세에서 축에 정렬된 상자입니다: box(id, name, [sx, sy, sz], [x, y, z], {grain, material, edge, explode, inferred, note}). x는 길이, y는 바닥이 0인 위쪽, z는 깊이입니다. grain은 목재 결 방향을 나타내며, 재단 목록의 자재 길이와 렌더링의 나이테 패턴을 결정합니다. 동일한 절단 부재는 동일한 name을 가지며 하나의 재단 목록 라인으로 병합됩니다. id는 고유하게 유지됩니다.
곡선 및 둥근 부재는 size/at에 대한 경계 상자를 유지하고 profile: {axis, path, note}를 추가합니다: 상자 중앙의 axis를 가로지르는 실제 윤곽선입니다 (quarterRing(R, t, [su, sv])는 구부러진 모서리용, roundedRect(w, h, radii)는 둥근 유리, 뒷판, 경주로 상판용, circle(d)는 둥근 다리용; profile.taper: {to, end}는 한쪽 끝으로 갈수록 가늘어짐). 프로파일을 따라 압출되어 렌더링되고, 윤곽선에서 검증되며, 윤곽선으로 그려집니다. 상자가 자재가 아닌 경우(벤트 라미네이션) stock: {L, W, T, layers, layerT}를 추가하면 재단 목록과 구매 목록이 이를 사용합니다. 두 방향으로 구부러진 부재(조각된 의자 등받이, 복합 곡선 등받이)는 아직 본체 유형이 없습니다: 사용자에게 알리고, 가장 가까운 직선 압출 모델을 만들고, note에 그 사실을 명시하세요.
부속품(fittings) 은 부재 위에 그려지는 구매한 하드웨어로, 자르지 않습니다: fittings: [{kind, size, at, material, axis, dir, holes: {n, d, cc, axis}}] (at은 부재 중심 기준). 손잡이, 후크, LED 프로파일이 렌더링됩니다; 나사 구멍은 부재 도면에 표시됩니다. 또한 hardware에도 나열하세요.
부재별 색상: materials 맵의 항목은 다른 부재를 변경하지 않고 사진에 맞게 키트 재료를 조정하기 위해 base, dark, ring, streak, rough, clearcoat, env를 가질 수 있습니다. 넓은 평평한 상판의 어두운 오일 처리 목재는 rough ≈ 0.9가 필요합니다. 그렇지 않으면 키 조명의 광택이 회색으로 보이게 합니다. 사진과 렌더링의 숫자를 비교하고 인상이 아닌 수치로 판단하세요.
접합부(joints) 는 두 부재 ID를 연결합니다: {a, b, type} (a는 장부/나사를, b는 이를 받음). 유형: mortise-tenon (tenonLen, tenonT, shoulder, mitred), dowel (count, d, len), dado (depth), rebate (face, depth: b의 가장자리를 따라 홈에 끼워지는 뒷판), shelf-pin (count, d, len, inset: b의 핀 위 선반), hinge (face, at: [world y…], cup: 35 to bore the cup in a: +z 방향을 향한 문이 b에 매달림), groove (width, depth: 패널 또는 서랍 바닥이 b의 가장자리나 면에 떠 있음), runner (b의 측면 장착 슬라이드 위 서랍 상자), weld (철-철), pocket-screw, button, figure-8, screw, glue. shelf-pin과 hinge는 하드웨어가 연결하는 몇 mm의 여유 공간을 허용합니다. 모든 부재는 나머지 부재와 접합되어야 하며, 그렇지 않으면 검증이 거부됩니다. applyJoinery는 일치하는 피처를 두 부재 모두에 작성합니다: 장부는 재단 목록의 자재 길이를 늘리고, 장붓구멍은 다리 도면에 면과 위치와 함께 표시되며, 둘 다 렌더링됩니다. 접합부는 또한 validate에 이 두 몸체가 서로 닿을 수 있음을 알립니다.
단계(steps) 는 설명서입니다: {title, parts: [ids], note, check, view}. 모든 부재는 정확히 하나의 단계에 나타나야 합니다. 제작자 방식으로 정렬하세요: 서브 어셈블리 먼저(끝 프레임, 서랍 상자), 그 다음 그것들을 연결하는 것, 그 위에 놓이는 것, 그리고 그렇게 하는 방식일 때 가구를 거꾸로 뒤집는 것. view는 페이지와 설명서에서 해당 단계의 카메라를 설정합니다.
매개변수(Params). 모든 것은 P의 숫자입니다. L을 변경하면 가로대, 장부, 버튼 간격, 재단 목록이 따라 옵니다. 이것이 핵심입니다: 동일한 model.js가 1600 버전과 2200 버전을 만듭니다.
제작 가능 여부를 결정하는 규칙
- 사진에서 시작하고, 상상에서 시작하지 마세요. 사진을 기준으로 모델을 만들고 렌더링을 나란히 비교하십시오: 실루엣, 다리 대 상판 비율, 오버행, 가로대 그림자 선이 떨어지는 위치. "멋진 오크 테이블"에서 발명된 가구는 일반적으로 나옵니다. 동일한 코드가 일치시킬 대상이 있을 때 실제 가구를 밀접하게 재구성합니다.
- 실제 자재. 두께는 표준 크기입니다. 너비가 200mm를 초과하는 것은 한 조각의 판자가 아닙니다.
pack.mjs는 이를 스트립의 접착으로 변환하고 명시합니다. 두께가 50mm를 초과하는 것도 한 조각의 판자가 아닙니다. 라미네이션이 됩니다. 결은 모든 부재의 길이 방향을 따라 이어집니다. 그렇지 않으면 검증이 짧은 결에 대해 경고합니다. - 모든 접합부는 실제 접합부입니다. 두 부재는 선언된 접합부를 통해서만 부피를 공유할 수 있습니다. 다리 내부에서 만나는 장부는
mitred: true이거나 짧아져야 합니다. 검증이 충돌을 확인합니다. 넓은 단단한 상판은 버튼, figure-8 또는 슬롯 구멍으로 고정되어야 합니다. 결코 단단히 접착되지 않아야 하며, 검증은 그렇지 않으면 경고합니다. - 충돌은 숫자로 수정하세요. 검증이 한 부재가 다른 부재를 통과한다고 보고하면
P또는build에서 값을 변경하세요. 카메라로 절대 숨기지 마세요. - 부재뿐만 아니라 가정도 기록하세요. 사진에 보이지 않는 가로대는
inferred: true와note로 표시하세요. 설명서의 첫 번째 상자는 모든 가정을 나열합니다. - 하나의 숫자, 하나의 출처. 재단 목록, 도면, 페이지의 HUD 및 설명서는 모두
stockOf(part)를 읽습니다. 숫자가 잘못 보이면 출력이 아닌 모델을 수정하세요.
라이브 페이지 규칙
- 페이지는 1MB 미만의 오프라인 HTML 파일 하나입니다(three.js가 인라인됨). 여러 부재가 있는 큰 가구도 각 부재가 하나의 둥근 상자이고 목재가 텍스처가 아닌 셰이더이므로 빠르게 유지됩니다.
- 조명 스튜디오: 따뜻한 키, 차가운 필, 부드러운 바닥 그림자. 목재 셰이더는
grain을 따라 평할석 무늬를 그리고 끝 부분은 자동으로 단면 무늬를 그립니다.roughness ≥ 0.45유지; 창백한 바닥의 광택 목재는 플라스틱으로 읽힙니다. - 20초 동안 방치하면 페이지가 스스로 투어합니다: 분해, 단계별, 밑면 X-ray. 입력이 있으면 제어권이 반환됩니다.
- URL 상태가 캡처를 제어합니다:
?step=2,?explode=1,?iso=leg-fl,?view=under&xray=1,?panel=0. 이 중 하나라도 설정되면 페이지는 애니메이션 대신 스냅샷을 생성하므로 스틸 이미지는 5fps에서나 60fps에서나 동일합니다.
리뷰 루프
페이지를 직접 볼 수는 없지만 스틸 이미지는 볼 수 있습니다. 현재 빌드의 시트를 읽지 않고 완료되었다고 보고하지 마세요.
node "$SKILL_DIR/capture.mjs" <name> --stills steps→joinery-out/<name>-sheet.png: 조립된 상태, 분해된 상태, 정면, 밑면 X-ray, 단계별 타일 하나.- 체크리스트에 따라 모든 타일을 읽으세요.
front및assembled타일 옆에 참조 사진을 놓으세요. - 부재의 경우
--stills parts가 각각을 분리합니다. 하나의 상태의 경우--still "step=3&view=under". - 수정하고, 다시 빌드하고, 1단계로 돌아가세요. 통과할 때 아무 문제도 발견되지 않으면 중지하세요.
joinery-out/<name>/manual.html을 같은 방식으로 열고 제작자처럼 읽으세요.
체크리스트:
- 비례. 사진과 비교: 다리 두께 대 길이, 상판 두께 대 길이, 오버행, 가로대 높이. 5% 이내여야 하며 그렇지 않으면 매개변수를 변경하세요.
- 접합부. 장붓구멍은 가로대가 만나는 면에 나타나야 합니다. 장부는 분해도와 X-ray에서 보여야 합니다. 분해도에서 공중에 떠 있는 부재가 없어야 합니다(접합부가 없는 부재는 이해할 수 있는 분해 벡터가 없습니다).
- 단계. 각 단계는 눈에 보이는 것을 추가합니다. 카메라는 추가되는 부재를 보여줍니다. 이미 배치된 부재는 아래에서 보여야 합니다. 1단계는 절대 상판이 아닙니다.
- 도면. 도면의 모든 장붓구멍, 장붓구멍, 구멍은 면과 끝에서의 거리를 지정합니다. 장부를 포함하는 재단 목록 길이는 이를 명시합니다.
- 자재. 자재 목록에는 너비 200mm 또는 두께 50mm를 초과하는 판재가 없습니다. 접착 및 라미네이션이 나열됩니다. 모든 부재는 절단 다이어그램의 판재 또는 합판 위에 있습니다.
- 공구 및 마감.
tools.md는 제작자의 작업장이 사용할 공구를 나열하고, 클램프 길이는 가장 큰 접착에 적합해야 합니다. 페인트칠, 베니어, 금속 부재는 각각 자체 마감 처리를 받습니다. - 렌더링. 가장자리에서 60px 이내에 아무것도 없어야 하며, 패널이 가구를 덮지 않고, 거의 흰색 목재(단풍나무, 물푸레)는 창백한 바닥과 구별되는 가장자리를 가져야 합니다.
재료(Materials)
kit/stage.js → MATERIALS: white-oak, red-oak, walnut, maple, ash, beech, pine, cherry, birch-ply, mdf, steel, brass. 베이스/다크 색상과 링, 스트릭 강도로 수종을 추가하세요. 또한: walnut-mdf, walnut-bendply (베니어 시트), mdf-black, glass (투명, 가장자리로 그려지며, 판재에서 자르는 대신 팩에서 크기에 맞게 절단 주문 처리). definePiece의 materials 맵은 재단 목록에서 이름을 지정합니다("White oak, solid").