Skills Plugins MCP Prompt Model 博客 我的中心
内容创作 #design #ai #mcp

furniture-design-sketchup

Use when designing, sketching, or modeling furniture using the SketchUp MCP server. Trigger when user mentions SketchUp, 3D modeling furniture, loft beds, shelves, cabinets, stairs, desks, or any woodworking project that needs visualization. Also use when creating cut lists, shop drawings, or validating furniture designs before building.

DeepseekModel 官方收录技能 质量 良好 · 48 v1.0.0

获取

https://deepseekmodel.com/api/download.php?id=dasfink-sketchup-mcp-skills-furniture-design-sketchup-skill-md&format=skill
下载 .skill 标准格式,含 system_prompt 与 model_config,导入任意 Agent 框架即可使用
.skill 文件中 system_prompt 字段的实际内容。
name furniture-design-sketchup description Use when designing, sketching, or modeling furniture using the SketchUp MCP server. Trigger when user mentions SketchUp, 3D modeling furniture, loft beds, shelves, cabinets, stairs, desks, or any woodworking project that needs visualization. Also use when creating cut lists, shop drawings, or validating furniture designs before building. Furniture Design with SketchUp MCP Design and produce build-ready plans for furniture using SketchUp via MCP ( eval_ruby ). Two key challenges: the pushpull inversion bug corrupts geometry ~50% of the time, and scenes silently fail to capture state. Verify everything visually — never trust that SketchUp did what you asked. Architecture Claude Code → stdio → sketchup-mcp (Python) → TCP :9876 → SketchUp Ruby Extension Before Starting Any Design Check these BEFORE modeling (see references/materials-and-tools.md ): What tools does the builder have? → Constrains joint selection What's the finish? → Affects joint visibility and material choice Indoor or outdoor? → Affects species, joints, and fasteners Project archetype? → Sets defaults (see references/project-archetypes.md ) Then select plan tier (see references/plan-tiers.md ): Simple shelf/box → Tier 1 Furniture → Tier 2 Complex/modular → Tier 3 Design Phases Concept — Identify archetype, select joints (see references/joint-selection.md ). Block out volumes with create_component_box . Get proportions right first. Use ACTUAL lumber dimensions (not nominal). Detail — Real lumber dimensions. Convert Groups → Components. Apply materials + tags. Follow archetype tag conventions. Joinery — Apply joints per selection guide. Prefer MCP tools ( safe_cut_dado , create_mortise_tenon , etc.) for simple operations; use WW.* via eval_ruby for complex multi-joint scripts. Always verify bounds after every operation. Shop Drawings — Generate plan artifacts per tier. Scenes for Layout, generate_cutlist for cut lists. Verify with verify_scenes . Critical: The Pushpull Inversion Bug face.pushpull(distance) direction depends on face normal winding order — unpredictable . Affects boxes, dados, AND bolt holes. For boxes: Never use pushpull module MCP_Helpers def self .make_box(entities, model, name, x, y, z, w, d, h, color_rgb) grp = entities.add_group ge = grp.entities ge.add_face([ 0 , 0 , 0 ],[w, 0 , 0 ],[w,d, 0 ],[ 0 ,d, 0 ]) ge.add_face([ 0 , 0 ,h],[ 0 ,d,h],[w,d,h],[w, 0 ,h]) ge.add_face([ 0 , 0 , 0 ],[w, 0 , 0 ],[w, 0 ,h],[ 0 , 0 ,h]) ge.add_face([ 0 ,d, 0 ],[ 0 ,d,h],[w,d,h],[w,d, 0 ]) ge.add_face([ 0 , 0 , 0 ],[ 0 , 0 ,h],[ 0 ,d,h],[ 0 ,d, 0 ]) ge.add_face([w, 0 , 0 ],[w,d, 0 ],[w,d,h],[w, 0 ,h]) tr = Geom::Transformation .new([x, y, z]) grp.transform!(tr) grp.name = name mat = model.materials.add( " #{name} _mat_ #{rand( 9999 )} " ) mat.color = Sketchup::Color .new(*color_rgb) mat.alpha = color_rgb[ 3 ] if color_rgb.length > 3 grp.material = mat grp end end For dados: Rebuild the definition (preferred) Instead of pushpull (which inverts ~50% of the time), rebuild the entire component definition with the dado as explicit geometry. A 6-face solid becomes a 10-face solid with the notch: # Example: 1x6 drawer side (0.75 × 22 × 5.5) with 1/2" dado, 1/4" deep, 1/2" up from bottom defn.entities.clear! de = defn.entities w, d, h = 0.75 , 22.0 , 5.5 dado_z1, dado_z2, dado_depth = 0.5 , 1.0 , 0.25 # 1/2" wide, 1/4" deep # Bottom, top, outside — full rectangles (unchanged) de.add_face([ 0 , 0 , 0 ],[w, 0 , 0 ],[w,d, 0 ],[ 0 ,d, 0 ]) de.add_face([ 0 , 0 ,h],[ 0 ,d,h],[w,d,h],[w, 0 ,h]) de.add_face([w, 0 , 0 ],[w,d, 0 ],[w,d,h],[w, 0 ,h]) # Inside face — split into 2 sub-faces (below dado + above dado) de.add_face([ 0 , 0 , 0 ],[ 0 ,d, 0 ],[ 0 ,d,dado_z1],[ 0 , 0 ,dado_z1]) de.add_face([ 0 , 0 ,dado_z2],[ 0 ,d,dado_z2],[ 0 ,d,h],[ 0 , 0 ,h]) # Dado groove — 3 faces (bottom, top, back wall) de.add_face([ 0 , 0 ,dado_z1],[ 0 ,d,dado_z1],[dado_depth,d,dado_z1],[dado_depth, 0 ,dado_z1]) de.add_face([ 0 , 0 ,dado_z2],[dado_depth, 0 ,dado_z2],[dado_depth,d,dado_z2],[ 0 ,d,dado_z2]) de.add_face([dado_depth, 0 ,dado_z1],[dado_depth,d,dado_z1],[dado_depth,d,dado_z2],[dado_depth, 0 ,dado_z2]) # End faces — with dado notch profile de.add_face([ 0 , 0 , 0 ],[w, 0 , 0 ],[w, 0 ,h],[ 0 , 0 ,h],[ 0 , 0 ,dado_z2],[dado_depth, 0 ,dado_z2],[dado_depth, 0 ,dado_z1],[ 0 , 0 ,dado_z1]) de.add_face([ 0 ,d, 0 ],[ 0 ,d,dado_z1],[dado_depth,d,dado_z1],[dado_depth,d,dado_z2],[ 0 ,d,dado_z2],[ 0 ,d,h],[w,d,h],[w,d, 0 ]) This avoids pushpull entirely. The dado is geometrically exact and visible when zoomed in. For dados/holes: Pushpull then VERIFY bounds (fallback) Only use pushpull when rebuilding the definition is impractical (e.g., complex existing geometry): expected_max = 77.0 # record BEFORE cutting face = ents.add_face(pts) face.pushpull(- 1.5 ) if face # MANDATORY: check bounds didn't grow if defn.bounds.max.y.to_f > expected_max + 0.01 # Inversion! Trim with helper in references/sketchup-ruby-api.md end Bolt holes: add_face returns nil add_circle splits existing faces; add_face returns nil. Use fallback: edges = ents.add_circle(center, normal, radius, 16 ) face = ents.add_face(edges) face | |= edges.first.faces.select { | f | f.valid? && f.area < 0.5 }.first rescue nil face.pushpull(-depth) if face Verify bounds after every hole. See references/sketchup-ruby-api.md for the full drill_hole and trim_extrusion helpers. OpenCutList Integration Requirements: Components (not Groups), materials applied, woodworking attributes set. # Convert group to component inst = grp.to_component inst.definition.name = "RailB" # Watch for #1 suffix if name exists inst.material = pine inst.set_attribute( "woodworking" , "species" , "Pine" ) inst.set_attribute( "woodworking" , "nominal_size" , "2x12" ) Fold repeated parts (e.g., 15 slats → "BedSlat x15"): all instances must share one ComponentDefinition. Keep one definition, erase others, re-place as instances of the kept definition. Programmatic cut list: worker = Ladb::OpenCutList::CutlistGenerateWorker .new( auto_orient: true , smart_material: true , part_folding: true ) cutlist = worker.run cutlist.groups.each { | g | g.parts.each { | p | " #{p.count} x #{p.name} | #{p.cutting_length} " } } Verification Discipline SketchUp's Ruby API silently produces wrong results. The geometry is fully queryable — use programmatic verification as the primary check and screenshots as visual confirmation. Level 1: Programmatic Verification (after every operation) The model state is queryable through eval_ruby . Always verify programmatically before moving on: After pushpull (dados, holes, mortises): # Bounds check — catches pushpull inversions defn = inst.definition bb = defn.bounds issues = [] issues << "X: #{bb.min.x.to_f.round( 2 )} .. #{bb.max.x.to_f.round( 2 )} " if bb.max.x.to_f > expected_x + 0.01 issues << "Y: #{bb.min.y.to_f.round( 2 )} .. #{bb.max.y.to_f.round( 2 )} " if bb.max.y.to_f > expected_y + 0.01 # Entity count — confirms geometry was actually modified face_count = defn.entities.select { | e | e.is_a?( Sketchup : :Face ) }.count issues << "face_count= #{face_count} (expected >6)" if face_count <= 6 After scene creation: # Query scene state — no screenshot needed for basic checks page = m.pages[idx] cam = page.camera checks = [] checks << "perspective= #{cam.perspective?} " # should match intent checks << "height= #{cam.height.to_f.round( 1 )} " # ortho height # Activate scene and check layer visibility m.pages.selected_page = page visible = m.layers.select { | l | l.visible? && l.name != "Layer0" }.map(& :name ) checks << "visible=[ #{visible.join( ',' )} ]" # Compare against expected Batch verification after all joinery: # Verify ALL component bounds match expected dimensions in one pass expected = { "PostBC" => { x: [ 0 , 3.5 ], y: [ 0 , 3.5 ], z: [ 0 , 71.25 ]}, "RailB" => { x: [ 0 , 1.5 ], y: [ 0 , 77 ], z: [ 0 , 11.25 ]}, # ... all parts } issues = [] expected.each do | name, dims | inst = entities.find { | e | e.is_a?( Sketchup : :ComponentInstance ) && e.definition.name == name } bb = inst.definition.bounds dims.each do | axis, range | val = axis == :x ? [bb.min.x, bb.max.x] : axis == :y ? [bb.min.y, bb.max.y] : [bb.min.z, bb.max.z] issues << " #{name} #{axis} #{val[ 0 ].to_f.round( 2 )} .. #{val[ 1 ].to_f.round( 2 )} " if (val[ 0 ].to_f - range[ 0 ]).abs > 0.01 | | (val[ 1 ].to_f - range[ 1 ]).abs > 0.01 end end issues.empty? ? "All clean" : issues.join( "\n" ) Level 2: Visual Verification (after scenes, after joinery batches) Screenshots confirm what programmatic checks can't — camera framing, visual clarity of joints, overall composition. Take screenshots at two checkpoints: After each scene: Activate with ShowTransition = false , take screenshot, Read the PNG: m.options[ "PageOptions" ][ "ShowTransition" ] = false m.pages.selected_page = page path = File .join( Dir .tmpdir, "verify_ #{page.name.gsub( ' ' , '_' )} .png" ) m.active_view.write_image(path, 1920 , 1080 , true ) When reviewing the screenshot, check: Correct parts visible (no duplicates, no tag bleed) Camera framing (subject centered, not cropped) Joinery clearly visible (dados read as pockets, holes read as holes) Orthographic scenes show no perspective convergence After all scenes — transition test: Cycle through every scene and verify layer visibility programmatically. The critical failure: tags created after scenes were saved bleed into all views. Level 3: Annotated Screenshots (for joint details) For joint detail scenes, add temporary dimensions before the screenshot to make the drawing self-documenting: # Add dimensions that explain the joint d1 = ents.add_dimension_linear([ 0 , 0 , 60 ], [ 0 , 0 , 71.25 ], [ 5 , 0 , 0 ]) # rail height d2 = ents.add_dimension_linear([ 2.0 , 0 , 65 ], [ 3.5 , 0 , 65 ], [ 0 , 0 , 5 ]) # dado depth # Screenshot m.active_view.write_image(path, 1920 , 1080 , true ) # Remove temporary dimensions if not wanted in final model # d1.erase!; d2.erase! This produces screenshots that a builder (or an LLM reviewing the work) can interpret without needing to read the model file. Scenes for Layout Critical pattern — set state BEFORE adding page: # 1. Set layers m.layers.each { | l | l.visible = visible_tags. include ?(l.name) } # 2. Set camera cam = Sketchup : :Camera .new cam.set(eye, target, up) cam.perspective = false ; cam.height = 95 # for orthographic m.active_view.camera = cam # 3. THEN add page page = m.pages.add( "Front Elevation" ) page.use_camera = true # 4. VERIFY — take screenshot and confirm visually m.options[ "PageOptions" ][ "ShowTransition" ] = false m.pages.selected_page = page
Agent 识别该技能的关键词,点击任意一个即可复制。

该技能未提供触发词。

下载的 .skill 包内含以下字段。
字段 说明
format格式标识(skill/v1)
skill_id技能唯一 ID
name技能名称
version版本号
description技能描述
category所属分类(数组)
trigger_words触发词列表
tags标签列表
source来源标识
source_url来源链接(本页地址)
exported_at导出时间(每次下载生成)
system_prompt系统提示词正文
model_config模型参数:provider / model / temperature / max_tokens / top_p
examples示例
install_guide各平台导入说明(Coze / Dify / Claude / 自定义框架)
同一份技能可按不同平台格式导出。
.skill 标准格式,含 system_prompt 与 model_config,导入任意 Agent 框架即可使用 下载
.skillpro 增强格式,额外含脚本 / 工具 / 依赖 / 钩子占位 下载
.json 纯 JSON 导出,只含 system_prompt 与模型参数 下载
Coze 带 frontmatter 的 Markdown,Coze 平台导入用 下载
Dify Dify DSL,创建应用后直接导入 下载

每日精选 Skill 推荐,免费送到你邮箱

输入邮箱,每天接收一个精选 AI Agent 技能推荐。完全免费,持续更新。

验证码 --

提交后我们会发送一封确认邮件,点击邮件里的链接才会开始收信。

完全免费,取消任意时间。我们不会发送垃圾邮件。