Skills Plugins MCP Prompt Model 博客 我的中心
Content Creation #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 Curated skill Quality Good · 48 v1.0.0

Get

https://deepseekmodel.com/api/download.php?id=dasfink-sketchup-mcp-skills-furniture-design-sketchup-skill-md&format=skill
Download .skill Standard format with system_prompt and model_config, ready for any agent framework
The actual content of the system_prompt field in the .skill file.
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
Keywords that activate this skill. Click one to copy it.

This skill does not provide trigger words.

The downloaded .skill package contains the following fields.
Field Description
formatFormat tag (skill/v1)
skill_idUnique skill ID
nameSkill name
versionVersion
descriptionDescription
categoryCategories (array)
trigger_wordsTrigger words
tagsTags
sourceSource
source_urlSource URL (this page)
exported_atExported at (set per download)
system_promptSystem prompt body
model_configModel config: provider / model / temperature / max_tokens / top_p
examplesExamples
install_guideImport guide for Coze / Dify / Claude / custom frameworks
The same skill can be exported in different platform formats.
.skill Standard format with system_prompt and model_config, ready for any agent framework Download
.skillpro Enhanced format with scripts, tools, dependencies and hooks Download
.json Plain JSON export with system_prompt and model parameters only Download
Coze Markdown with frontmatter, for Coze platform import Download
Dify Dify DSL, import directly after creating an app Download

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

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

验证码 --

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

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