Community이미지github.com

조이너리 (Joinery)

가구 사진을 실제 목수가 제작할 수 있는 3D 모델로 변환합니다 — 모든 부위는 실제 자재와 실제 조인트로 구성되며, 분해도, X-ray, 단계별 조립 가이드가 포함된 오프라인 HTML 페이지와 함께 재단 목록, 치수 도면, 목재 구매 목록, 하드웨어 목록, 조립 설명서가 담긴 메이커 팩을 생성합니다.

조이너리 (Joinery)란 무엇인가요?

조이너리(Joinery)는 사용자가 보낸 가구 사진 한 장을 바탕으로, 실제 목공 작업자가 제작할 수 있는 완전한 3D 모델과 제작 도면을 생성하는 AI 어시스턴트 스킬입니다. 이 스킬은 사진 측량(photogrammetry)이 아닌 설계 해석(design interpretation) 방식으로 동작합니다. 사용자가 제공한 사진과 몇 가지 기준 치수(앵커)를 바탕으로 가구의 종류, 각 부재의 이름과 치수, 접합 방식, 재료, 마감 등을 추론하여 `spec.json` 파일로 정리합니다. 이후 사용자는 `model.js`를 작성하여 부재, 접합부, 조립 단계를 정의하고, 내장된 `pack.mjs` 및 `build.mjs` 스크립트를 실행하여 부재 간 충돌 검증, 재단 목록, 치수 도면, 자재 구매 목록, 하드웨어 목록, 조립 설명서(HTML 및 PDF)를 자동 생성합니다. 또한 `capture.mjs`를 통해 조립 단계별 미리보기 이미지를 생성하여 검토할 수 있습니다. 모든 출력은 하나의 오프라인 HTML 파일(약 570KB, three.js 내장)로 제공되며, 분해도, X-ray 뷰, 단계별 조립 애니메이션을 지원합니다. 현재 Claude Code 환경에서 사용 가능하며, Node.js 20.10+와 Chromium(선택 사항)을 필요로 합니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/JoseChipanaTica/joinery/tree/HEAD

Installed? Explore more 이미지 skills: steipete/songsee, affaan-m/frontend-design, mattpocock/improve-codebase-architecture · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

조이너리 (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-piecejoinery-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단계: 사진을 정직하게 읽기

단일 사진은 어떤 치수도, 숨겨진 구조도 제공하지 않습니다. 이 스킬은 사진 측량이 아니라 설계 해석입니다. 기하학을 작성하기 전에 다음을 수행하세요:

  1. 앵커 확보. 전체 가로 × 세로 × 높이, 또는 "상판이 180cm"와 같은 하나의 알려진 치수 등 최대 3개의 실제 치수를 요청하세요. 사용자가 아무 치수도 제공할 수 없으면 kit/validate.js의 인체 공학적 표준(식탁 높이 750, 의자 높이 450)을 사용하고 그렇게 명시하세요. 다른 모든 치수는 사진에서 읽은 비율에 앵커를 곱한 값입니다.
  2. 유형 지정. dining-table, chair, bookshelf… 이 유형에 따라 인체 공학적 검사와 일반적인 구조 방식이 결정됩니다.
  3. 보이는 것과 보이지 않는 것 목록 작성. 다리, 상판, 보이는 선반은 visible. 두꺼운 상판 아래의 가로대, 뒷판, 가로장, 서랍 레일, 모서리 블록은 inferred — 해당 부재에 inferred: true로 표시하여 모든 출력에서 플래그가 지정되도록 하세요. 제작자가 이를 재정의할 수 있습니다. 제작자는 어떤 가정이 여러분의 것인지 알아야 합니다.
  4. 라이브러리에서 접합부 선택 (templates/joinery-library.md), 유형 × 재료 × 작업장 기준. 작업장이 명확하지 않으면 어떤 작업장(shop: hand, cabinet, cnc)이 있는지 물어보세요; 이는 공구 목록도 결정합니다. 기본값은 캐비닛 작업장: 다리/가로대는 장붓구멍-장부, 선반은 장붓구멍, 패널은 다월 또는 도미노, 숨겨진 곳에만 포켓 스크류. 선택과 그 이유를 spec.source.assumptions에 기록하세요.
  5. 재료와 마감 읽기. 색상과 결에서 수종, 가장자리 비율에서 두께, 하이라이트에서 가장자리 처리(둥글림 / 모따기 / 날카롭게)를 결정합니다. 두께는 표준 자재 크기(STOCK_T in kit/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 버전을 만듭니다.

제작 가능 여부를 결정하는 규칙

  1. 사진에서 시작하고, 상상에서 시작하지 마세요. 사진을 기준으로 모델을 만들고 렌더링을 나란히 비교하십시오: 실루엣, 다리 대 상판 비율, 오버행, 가로대 그림자 선이 떨어지는 위치. "멋진 오크 테이블"에서 발명된 가구는 일반적으로 나옵니다. 동일한 코드가 일치시킬 대상이 있을 때 실제 가구를 밀접하게 재구성합니다.
  2. 실제 자재. 두께는 표준 크기입니다. 너비가 200mm를 초과하는 것은 한 조각의 판자가 아닙니다. pack.mjs는 이를 스트립의 접착으로 변환하고 명시합니다. 두께가 50mm를 초과하는 것도 한 조각의 판자가 아닙니다. 라미네이션이 됩니다. 결은 모든 부재의 길이 방향을 따라 이어집니다. 그렇지 않으면 검증이 짧은 결에 대해 경고합니다.
  3. 모든 접합부는 실제 접합부입니다. 두 부재는 선언된 접합부를 통해서만 부피를 공유할 수 있습니다. 다리 내부에서 만나는 장부는 mitred: true이거나 짧아져야 합니다. 검증이 충돌을 확인합니다. 넓은 단단한 상판은 버튼, figure-8 또는 슬롯 구멍으로 고정되어야 합니다. 결코 단단히 접착되지 않아야 하며, 검증은 그렇지 않으면 경고합니다.
  4. 충돌은 숫자로 수정하세요. 검증이 한 부재가 다른 부재를 통과한다고 보고하면 P 또는 build에서 값을 변경하세요. 카메라로 절대 숨기지 마세요.
  5. 부재뿐만 아니라 가정도 기록하세요. 사진에 보이지 않는 가로대는 inferred: true와 note로 표시하세요. 설명서의 첫 번째 상자는 모든 가정을 나열합니다.
  6. 하나의 숫자, 하나의 출처. 재단 목록, 도면, 페이지의 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에서나 동일합니다.

리뷰 루프

페이지를 직접 볼 수는 없지만 스틸 이미지는 볼 수 있습니다. 현재 빌드의 시트를 읽지 않고 완료되었다고 보고하지 마세요.

  1. node "$SKILL_DIR/capture.mjs" <name> --stills steps → joinery-out/<name>-sheet.png: 조립된 상태, 분해된 상태, 정면, 밑면 X-ray, 단계별 타일 하나.
  2. 체크리스트에 따라 모든 타일을 읽으세요. front 및 assembled 타일 옆에 참조 사진을 놓으세요.
  3. 부재의 경우 --stills parts가 각각을 분리합니다. 하나의 상태의 경우 --still "step=3&view=under".
  4. 수정하고, 다시 빌드하고, 1단계로 돌아가세요. 통과할 때 아무 문제도 발견되지 않으면 중지하세요.
  5. 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").

관련 스킬