makeit4me 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,363 @@
1
+ ---
2
+ name: sketchup-review-design
3
+ description: |
4
+ Review a SketchUp building model like an architect or general contractor would.
5
+ Use when: (1) model is nearing completion and needs a quality check, (2) user
6
+ asks "does this look right" or "review the design", (3) checking if materials
7
+ are real-world purchasable (Home Depot, lumber yards), (4) verifying basic US
8
+ building code compliance for sheds/outbuildings, (5) looking for geometry
9
+ problems like mesh collisions or z-fighting, (6) generating a punch list of
10
+ issues to fix, (7) comparing model against a reference/goal image using Gemini
11
+ vision. Supports both whole-model review and section-by-section focused review.
12
+ author: Claude Code
13
+ version: 2.0.0
14
+ date: 2026-03-12
15
+ ---
16
+
17
+ # SketchUp Design Review
18
+
19
+ Review a building model the way an architect or GC would before breaking ground.
20
+ This skill supports two modes: **section-by-section** (preferred) and **whole-model**.
21
+
22
+ ---
23
+
24
+ ## Section-by-Section Review (Preferred)
25
+
26
+ Reviewing the entire model at once produces generic, surface-level feedback.
27
+ Instead, isolate and review one section at a time for detailed, actionable findings.
28
+
29
+ ### How to Review Section by Section
30
+
31
+ **Step 1: Identify sections.** List the distinct areas of the model:
32
+ ```ruby
33
+ # Get all group name prefixes to identify sections
34
+ groups = model.entities.grep(Sketchup::Group)
35
+ prefixes = groups.map { |g| g.name.split(" ").first(2).join(" ") }.uniq.sort
36
+ prefixes.join("\n")
37
+ ```
38
+
39
+ Typical sections for a building:
40
+ - Foundation/slab
41
+ - Each exterior wall (front, back, left, right)
42
+ - Interior walls
43
+ - Floor framing / deck
44
+ - Roof (rafters, sheathing, ridge)
45
+ - Turrets / towers
46
+ - Porch / entryway
47
+ - Balcony / deck
48
+ - Trim and decorative elements
49
+ - Fixtures (doors, windows, hardware)
50
+
51
+ **Step 2: For each section, do a focused review cycle:**
52
+
53
+ #### 2a. Isolate the section visually
54
+ Hide everything except the section under review + its supporting structure:
55
+ ```ruby
56
+ section_prefix = "Balcony" # change per section
57
+ groups = model.entities.grep(Sketchup::Group)
58
+
59
+ # Hide all, show only this section + foundation
60
+ groups.each do |g|
61
+ g.visible = g.name.start_with?(section_prefix) ||
62
+ g.name.include?("Slab") || g.name.include?("Foundation") ||
63
+ g.name.include?("Bot Plate") # show what it connects to
64
+ end
65
+ ```
66
+
67
+ #### 2b. Screenshot the isolated section from multiple angles
68
+ Position the camera close to the section, not the whole model.
69
+
70
+ First, compute the section center and viewing distance via `sketchup_inspect`:
71
+ ```ruby
72
+ section_groups = model.entities.grep(Sketchup::Group).select { |g|
73
+ g.name.start_with?(section_prefix)
74
+ }
75
+ if section_groups.any?
76
+ min_x = section_groups.map { |g| g.bounds.min.x }.min
77
+ min_y = section_groups.map { |g| g.bounds.min.y }.min
78
+ min_z = section_groups.map { |g| g.bounds.min.z }.min
79
+ max_x = section_groups.map { |g| g.bounds.max.x }.max
80
+ max_y = section_groups.map { |g| g.bounds.max.y }.max
81
+ max_z = section_groups.map { |g| g.bounds.max.z }.max
82
+
83
+ cx = (min_x + max_x) / 2.0
84
+ cy = (min_y + max_y) / 2.0
85
+ cz = (min_z + max_z) / 2.0
86
+ span = [max_x - min_x, max_y - min_y, max_z - min_z].max
87
+ dist = span * 2.5
88
+ "center=#{cx},#{cy},#{cz} dist=#{dist}"
89
+ end
90
+ ```
91
+
92
+ Then take screenshots from multiple angles using `sketchup_screenshot` with those computed values:
93
+ - **Iso**: eye [cx + dist*0.6, cy - dist*0.6, cz + dist*0.4], target [cx, cy, cz]
94
+ - **Front**: eye [cx, cy - dist, cz], target [cx, cy, cz]
95
+ - **Side**: eye [cx + dist, cy, cz], target [cx, cy, cz]
96
+
97
+ The screenshot tool returns the image directly — just view the result.
98
+
99
+ #### 2c. Compare section against goal image
100
+ Take a `sketchup_screenshot` from an angle that matches the goal image, then compare
101
+ visually. If using the Gemini comparison script, save the screenshot first and pass
102
+ both paths:
103
+ ```bash
104
+ ./scripts/compare_images.sh "goal_section.jpg" "/tmp/review_section.png"
105
+ ```
106
+
107
+ If no cropped goal image exists, instruct Gemini to focus on just that area:
108
+ - Modify the compare script prompt to say "Focus ONLY on the [section name] area"
109
+ - Or take a screenshot from an angle that emphasizes the section being reviewed
110
+
111
+ #### 2d. Run programmatic checks on section groups
112
+ ```ruby
113
+ section_groups = model.entities.grep(Sketchup::Group).select { |g|
114
+ g.name.start_with?(section_prefix)
115
+ }
116
+
117
+ checks = []
118
+
119
+ # Check for oversized lumber
120
+ section_groups.each do |g|
121
+ length = [g.bounds.width, g.bounds.depth, g.bounds.height].max
122
+ checks << "OVERSIZED: #{g.name} (#{length.to_l})" if length > 192
123
+ end
124
+
125
+ # Check for manifold solids
126
+ section_groups.each do |g|
127
+ checks << "NON-MANIFOLD: #{g.name}" if g.respond_to?(:manifold?) && !g.manifold?
128
+ end
129
+
130
+ # Check for floating pieces (not touching anything else)
131
+ section_groups.each do |g|
132
+ bb = g.bounds
133
+ touching = section_groups.any? { |other|
134
+ next if other == g
135
+ ob = other.bounds
136
+ !(bb.min.x > ob.max.x + 0.5 || bb.max.x < ob.min.x - 0.5 ||
137
+ bb.min.y > ob.max.y + 0.5 || bb.max.y < ob.min.y - 0.5 ||
138
+ bb.min.z > ob.max.z + 0.5 || bb.max.z < ob.min.z - 0.5)
139
+ }
140
+ checks << "FLOATING: #{g.name} — not touching any other section piece" unless touching
141
+ end
142
+
143
+ checks.empty? ? "All checks passed" : checks.join("\n")
144
+ ```
145
+
146
+ #### 2e. Record findings
147
+ After each section review, compile:
148
+ - What's correct
149
+ - What's wrong (with specific fix descriptions)
150
+ - Priority (critical / warning / cosmetic)
151
+
152
+ **Step 3: Restore visibility**
153
+ ```ruby
154
+ model.entities.grep(Sketchup::Group).each { |g| g.visible = true }
155
+ ```
156
+
157
+ ### Recommended Review Order
158
+
159
+ Review sections in build order (bottom-up), since upper sections depend on lower:
160
+
161
+ 1. **Foundation / slab** — correct size, position, Z-offset
162
+ 2. **Floor framing** — joists spacing, deck coverage
163
+ 3. **Walls** (one at a time) — stud spacing, plates, headers, openings
164
+ 4. **Interior walls** — height matches roof line, door openings
165
+ 5. **Roof structure** — rafters, ridge, bearing on walls
166
+ 6. **Roof sheathing** — covers full area, no gaps
167
+ 7. **Exterior features** — porch, balcony, turrets
168
+ 8. **Trim and decorative** — fascia, shutters, star, scalloped trim
169
+ 9. **Fixtures** — doors, windows, hardware
170
+
171
+ ### Section Review Prompt Template
172
+
173
+ When running Gemini comparison for a section, use a focused prompt:
174
+
175
+ ```
176
+ Focus ONLY on the {SECTION_NAME} in both images. Ignore everything else.
177
+
178
+ For the goal image: describe the {section} in detail — dimensions, lumber sizes,
179
+ joints, spacing, materials, decorative elements.
180
+
181
+ For the model image: describe the same {section} — what matches, what's different.
182
+
183
+ List the top 3 specific changes needed to make the model's {section} match the goal.
184
+ Be precise: "move X from Y to Z", "change 2x4 to 4x4", "add 6 more balusters".
185
+ ```
186
+
187
+ ---
188
+
189
+ ## Whole-Model Review (Quick Pass)
190
+
191
+ Use this for a fast overall health check, not detailed design feedback.
192
+
193
+ ### Quick Review Script
194
+
195
+ ```ruby
196
+ results = []
197
+ bb = model.bounds
198
+ cx = bb.center.x; cy = bb.center.y; cz = bb.center.z
199
+
200
+ # Dimensions
201
+ sqft = (bb.width * bb.depth) / 144.0
202
+ results << "Footprint: #{sqft.round(1)} sq ft, Height: #{bb.height.to_l}"
203
+ results << (sqft > 120 ? "NOTE: Likely needs building permit" : "May be permit-exempt")
204
+
205
+ # Entity count
206
+ counts = Hash.new(0)
207
+ model.entities.each { |e| counts[e.typename] += 1 }
208
+ results << "Entities: #{counts.map { |t,c| "#{t}:#{c}" }.join(", ")}"
209
+
210
+ # Stray geometry
211
+ strays = model.entities.grep(Sketchup::Edge).select { |e| e.faces.empty? }
212
+ results << (strays.empty? ? "OK: No stray edges" : "WARNING: #{strays.length} stray edges")
213
+
214
+ # Loose top-level faces
215
+ loose = model.entities.grep(Sketchup::Face).length
216
+ results << (loose == 0 ? "OK: No loose faces" : "WARNING: #{loose} loose faces at top level")
217
+
218
+ # Oversized lumber check
219
+ oversized = []
220
+ model.entities.each do |e|
221
+ next unless e.is_a?(Sketchup::Group)
222
+ length = [e.bounds.width, e.bounds.depth, e.bounds.height].max
223
+ oversized << "#{e.name} (#{length.to_l})" if length > 192
224
+ end
225
+ results << (oversized.empty? ? "OK: All lumber fits standard stock" : "WARNING: Oversized: #{oversized.join(", ")}")
226
+
227
+ results.join("\n")
228
+ ```
229
+
230
+ ### Multi-Angle Screenshots
231
+
232
+ Use `./scripts/capture_views.sh <design_folder>` for standardized 10-angle capture.
233
+
234
+ ---
235
+
236
+ ## Geometry Validation Checks
237
+
238
+ ### Collision Detection
239
+ ```ruby
240
+ check_collisions = lambda { |entities|
241
+ items = entities.to_a.select { |e|
242
+ e.is_a?(Sketchup::Group) || e.is_a?(Sketchup::ComponentInstance)
243
+ }
244
+ collisions = []
245
+ items.combination(2).each do |a, b|
246
+ ab = a.bounds; bb_b = b.bounds
247
+ next if ab.min.x > bb_b.max.x || ab.max.x < bb_b.min.x
248
+ next if ab.min.y > bb_b.max.y || ab.max.y < bb_b.min.y
249
+ next if ab.min.z > bb_b.max.z || ab.max.z < bb_b.min.z
250
+ a_name = a.respond_to?(:name) ? a.name : a.definition.name
251
+ b_name = b.respond_to?(:name) ? b.name : b.definition.name
252
+ collisions << "#{a_name} <-> #{b_name}"
253
+ end
254
+ collisions
255
+ }
256
+ ```
257
+
258
+ ### Slab-Relative Z-Offsets
259
+ All framing should start at slab top, not Z=0:
260
+ ```ruby
261
+ slab = model.entities.to_a.find { |e| e.is_a?(Sketchup::Group) && e.name.include?("Slab") }
262
+ slab_top = slab ? slab.bounds.max.z : 0
263
+ model.entities.grep(Sketchup::Group).each do |g|
264
+ next if g.name.include?("Slab") || g.name.include?("Foundation")
265
+ if g.bounds.min.z < slab_top - 0.5 && g.bounds.min.z >= 0
266
+ puts "WARNING: #{g.name} starts at Z=#{g.bounds.min.z.round(1)}, slab top is Z=#{slab_top}"
267
+ end
268
+ end
269
+ ```
270
+
271
+ ---
272
+
273
+ ## Structural / Framing Review
274
+
275
+ ### Stud Spacing (16" OC)
276
+ ```ruby
277
+ studs = model.entities.to_a.select { |e|
278
+ e.is_a?(Sketchup::Group) && e.name.include?("Stud") && e.name.start_with?(wall_prefix)
279
+ }
280
+ positions = studs.map { |s| s.bounds.min.x }.sort # or .min.y for Y-axis walls
281
+ positions.each_cons(2) do |a, b|
282
+ spacing = b - a
283
+ puts "WARNING: Stud spacing #{spacing.round(1)}\"" if spacing > 16.5 || spacing < 15.5
284
+ end
285
+ ```
286
+
287
+ ### Header Sizing (IRC R602.7)
288
+ | Opening Width | Minimum Header |
289
+ |---------------|----------------|
290
+ | Up to 4 ft | 2x6 |
291
+ | 4–6 ft | 2x8 |
292
+ | 6–8 ft | 2x10 |
293
+ | 8–10 ft | 2x12 |
294
+
295
+ ### Double Top Plate Check
296
+ ```ruby
297
+ ["FW", "BW", "LW", "RW", "DW"].each do |prefix|
298
+ plates = model.entities.to_a.select { |e|
299
+ e.is_a?(Sketchup::Group) && e.name.start_with?("#{prefix} Top Plate")
300
+ }
301
+ puts "WARNING: #{prefix} has #{plates.length} top plate(s), need 2" if plates.length < 2
302
+ end
303
+ ```
304
+
305
+ ---
306
+
307
+ ## Visual Comparison with Gemini Flash
308
+
309
+ ### Full Model Comparison
310
+ ```bash
311
+ ./scripts/compare_images.sh "path/to/goal.jpg" /tmp/current_model.png
312
+ ```
313
+
314
+ ### Section-Focused Comparison
315
+ For reviewing a specific section, modify the prompt in the compare script or
316
+ use a focused camera angle that isolates the section being reviewed.
317
+
318
+ **Best practice:** Take a close-up screenshot of the section from the same angle
319
+ as the goal image, then compare just those two crops.
320
+
321
+ ---
322
+
323
+ ## Building Code Quick Reference (IRC)
324
+
325
+ - **Under 120 sq ft**: Often permit-exempt
326
+ - **Over 200 sq ft**: Almost always requires permit
327
+ - **Min ceiling height**: 7ft habitable, no min for storage
328
+ - **Min roof pitch for shingles**: 2:12 (4:12 preferred)
329
+ - **Overhang**: 6-12" typical
330
+ - **Setbacks**: Verify with local zoning (can't check in model)
331
+
332
+ ---
333
+
334
+ ## Output: Punch List Format
335
+
336
+ ```
337
+ === DESIGN REVIEW: {SECTION NAME} ===
338
+ Model: [model name]
339
+ Date: [date]
340
+
341
+ ## CRITICAL (must fix)
342
+ - [ ] [issue]
343
+
344
+ ## WARNINGS (should fix)
345
+ - [ ] [issue]
346
+
347
+ ## COSMETIC (nice to have)
348
+ - [ ] [issue]
349
+
350
+ ## VERIFIED OK
351
+ - [x] [check] ✓
352
+ ```
353
+
354
+ ---
355
+
356
+ ## References
357
+ - [IRC Framing Inspection Checklist](https://mybuildingpermit.com/sites/default/files/documentation/Framing_0.pdf)
358
+ - [Framing Inspection Checklist: Builder Tips](https://www.southeasterngc.com/framing-inspection-checklist/)
359
+
360
+ ## See Also
361
+ - `sketchup-bridge`: MCP tools and Ruby API reference
362
+ - `sketchup-building-framing`: Generating proper framing
363
+ - `sketchup-model-auditing`: Automated geometry checks