Loading...
Loading...
Use when modeling hard-surface objects in Blender (sci-fi panels, props, weapons, vehicles, robots, machined or product parts) with booleans and cutters, bevel modifiers, weighted normals, or subdivision with support loops or creases. Also when shading is broken (smears on flat faces, stretching near a cut, pinching), a bevel shrinks or vanishes after a boolean, a boolean empties the mesh or leaves holes, choosing n-gons vs quads, or making a game-ready mid-poly.
npx skill4agent add scenario-labs/skills scenario-blender-hard-surfacenpx skills add scenario-labs/skills --skill <name>scripts/bx_hardsurface.pyimport sys; sys.path.append("<skills>/scenario-blender-hard-surface/scripts"); import bx_hardsurface as HSHS.order_stackHS.add_booleanHS.clamp_culprits| Input | Why it changes the plan | Default when silent |
|---|---|---|
| Purpose | render: 3+ micro segments (Gambrell); game mid-poly: 1 to 2 segments, triangulated, custom normals; bake: subD or boolean high + separate low | render still |
| Real size | bevel widths are absolute: du Mont uses about 3 mm on a small robot body, 1 mm on small parts, 0.1 mm on a collar | model at real size; if unknown, micro width 0.5% of the largest dimension [added] |
| Surface | mostly planar vs curved vs organic-mechanical | School A for planar parts, B for curved shells, hybrid when mixed |
| Budget and engine | Augusto: 15k tris, one 2K map; a quad-only pipeline forces School B (Gambrell [00:24:35]) | no budget: report tris |
| Later stages | sculpted damage or multires detail needs a quad cage (PzThree); rigging needs collapsed copies (du Mont) | none |
| Symmetry | mirror the target when the part is symmetric; mirror the cutter around the target when only the cut is (Gambrell [00:14:53]) | ask the reference |
HS.apply_scale(ob)bx_review.review(..., modes=("silhouette",))HS.find_edges(ob, min_angle=80, inside=...)HS.set_edge_attr(ob, edges, 1.0)HS.hard_surface_stack(ob, micro_width=..., design_width=...)HS.subd_stack(ob, support_width=...)HS.support_loopsHS.stack_problems(ob) == []HS.make_cutter(target, "BOX"|"CYLINDER"|"SLOT", size, location, ...)HS.as_cutterHS.slice_booleanmake_cutterHS.cutter_report(c, target)HS.clamp_probe(target)["ratio"] < 0.1HS.closeupr = HS.shading_audit(ob); HS.verdict(r)HS.review([ob], out, modes=("matcap","reflect","hsgrey","wire"))references/critique.mdHS.transfer_normalsHS.mirror_seam_fixr["subd_cage"]g, tris = HS.game_version(ob, micro_segments=1)HS.collapse(ob)| Value | Setting | Relative to / source |
|---|---|---|
| Micro bevel | angle 30 degrees, 3 segments render, 1 to 2 game, Harden Normals, Miter Outer Arc | Gambrell [00:17:20], du Mont [00:14:40] |
| Micro width | about 3 mm body, 1 mm small parts, 0.1 mm collar | real size, du Mont |
| Design bevel | Limit Method Weight, 8 to 12 segments | du Mont [00:13:32] |
| Big rolling curve | 46 to 50 segments; cutter edge bevels about 8 to 10 | Ryuu [00:12:53], [00:05:42] |
| Min feature | wall, step, groove, facet width > 2 x micro width | [added, verified] |
| Clamp probe | displacement over 10% of width = clamping | [added] |
| Solver | EXACT; MANIFOLD for speed with manifold operands; FLOAT only to diagnose | verified in 5.2.1 |
| Round cutters | vertex count set at creation (40 for screw holes); half-segment phase vs target | Ryuu [00:29:43]; [verified] |
| Bevel before Subdivision | 2 or 4 segments, profile 1.0, Weight, UV Smooth Keep Corners | Lampel [00:08:06], [00:11:15] |
| Creases | fine for small details or rounding a coarse cylinder at level 1; 10x tris for primary edges | Lampel, du Mont [00:52:18] |
| SubD cage | circle 18 verts body, 36 on a denser part; square quads | rileyb3d [00:01:34], PzThree [00:03:15] |
| Mirror seam fix | bevel Face Strength Affected + WN Face Influence, weight 100 | Gambrell [00:06:57] |
| Game budget | 15k tris, one 2K map, animated parts separate | Augusto [00:11:48] |
| Cost measured | case 1,984 tris (A) vs 4,608 (B, level 2); barrel 7,308 (A), 25,728 (B), 3,716 (A game) | test_03 [added] |
HS.shading_auditHS.verdictstack_problemsHS.tri_countHS.reviewcheck_reflection_horizontalHS.closeup(ob, point, radius, ...)shiny| Mistake | What it looks like | Fix |
|---|---|---|
| Boolean below the micro bevel | cut edges razor sharp, rest beveled | |
| Weighted Normal added after pinning the bevel | WN lands above the bevel, smears return | pin bottom-up ( |
| Cutter near but not on a target face or edge | whole-object bevel narrower, thin steps | move clearly away or snap exactly; |
| Groove or wall thinner than 2x bevel | clamped bevels everywhere | widen the feature or thin the bevel |
| Round cutter in phase with the target facets | streaks, black patches, non-manifold edges | half-segment phase (default in |
| Rounded cutter corners at 30-degree facets | micro bevel catches facet edges, clamps | more segments ( |
| Flat-shaded cutter | facets on the cut walls | cutters smooth ( |
| "Switch to Fast" | non-manifold result on coplanar faces | EXACT; repair the operand instead |
| Unapplied scale | uneven bevel widths | |
| Stacking normal fixes on a non-planar face | stretch that nothing fixes | |
| Data Transfer placed before WN, or scoped by a vertex group | no effect / cut walls shaded like the skin | |
| du Mont's support cut placed through a round cut | rim edges halved, clamp 0 to 1.2 [verified] | only where |
| Creases on primary subD edges | soft, pinched, heavy | support loops or bevel before subdivision |
| Moving a game copy or slice | cuts vanish (cutters stay with the original) | keep it in place, or |
bpy.ops.object.shade_auto_smoothtemp_override'EXACT''MANIFOLD''FLOAT'bevel_weight_edgecrease_edgeedge_weightob.modifiers.move(i, j)modifier_move_to_indexbmesh.ops.bevelsegments=0, profile=0.0mesh.circularizemesh.flattenmesh.space_edge_loops_evenlyreferences/procedures.mdreferences/critique.mdreferences/expert-notes.mdreferences/sources.md