# Spearfish: a Tender ("sub tub") after the user's blueprint Built on 2026-10-20 in the open Blender through the MCP, after the user's orthographic sheet `reference/user_blueprint.webp` ("SUBMERSIBLE — ORTHOGRAPHIC RECONSTRUCTION": top, port side, underside, front, rear). The user's words: *"Create this blueprint as subtub tender 3d model in blender using MCP precisely accordingly take your time check as the referance image"*. "Spearfish" is a working name after the long pointed nose; the user has not named it. ## Files | | | |---|---| | `Tender_Spearfish.blend` | the model, textured | | `fbx/SM_Spearfish_*.fbx` | one FBX per part, vertices relative to the part's pivot; the hull carries its 15 `UCX_` collision hulls | | `fbx/Spearfish_Assembled.fbx` | everything in place, for a quick look | | `Spearfish_layout.json` | pivots, fold axes, ranges, sockets, clamp interface, every check result, textures (Unreal cm) | | `textures/` | `T_Spearfish_Exterior_Masks` / `_BevelNormal` (4096), `T_Spearfish_Cabin_Masks` / `_BevelNormal` (2048), `T_Spearfish_Screens` | | `previews/` | `v02_*` Cycles renders; `compare/cmp_*.png` the model's outline (red) over each blueprint view; `wb_*` quick looks | | `reference/` | the blueprint and the 4x measuring zooms (`z_*.png`, with pixel rulers) | | `build/` | the scripts (below) and `checks/` with every check's result | | `versions/` | `v01_untextured` (first build), `v02_dense_grid_textured` (the first delivery, sent back for its topology), `v03_clean_topology_untextured` | ## Topology (rebuilt 2026-10-20) The user sent the first delivery back with a viewport wireframe: *"the topology is terrible fix the topology and make this as a game ready asset. also delete the red lined artifact only wings should be"* (the red line round the ribbed actuator at the fin root). The first hull was a dense grid (4 cm x 192 columns, 137k triangles) with holes cut by deleting faces and snapping their edge vertices onto the outlines, seams and frames as floating strips, and fans on the small parts. Rebuilt (`build/sf_hull.py`, `build/sf_topo.py`): - **One quad grid** for the hull: 64 columns placed by arc length on every section, stations spaced by need (13 cm amidships, 4 cm at the nose tip, 5 cm at the stern, 6 cm along the openings). - **Openings are rectangles of the grid.** Along the canopy, the side windows and the hatch, the band's columns are pinned to the opening's outline and relax back to their even places within 0.35 m past its ends; nothing is snapped. (The windows' frames are swept trims since the frame fix below; the hatch keeps its frame in the grid.) - **Frames in the hull's own topology**: the ring of faces round each hole, its inner edge raised 10 mm (6 mm at the hatch), and a sleeve straight down to the cabin lining, whose hole meets it vertex for vertex. The glass is the hole's own grid. - **Seams are not geometry**: two per-vertex distance fields (`seam_ring`, `seam_long`) that the paint draws and the bevel normal bakes. - **Quads only on the parts**: lofts and foils with three-quad end caps, revolved parts and cylinders with Coons-patch caps, cube spheres, vents and lenses as ladder plates that follow the hull's facets. The only triangles: the nose point's fan (64), the grab bar's and light strips' tube ends. - **Custom normals** on the skin from the analytic surface, so reflections do not ripple where the grid bends. - **Removed on the user's word**: the ribbed actuator at each fin root, its dark recess and the dark block at the fin's fore root. The fins and their root fairings stay. - Wireframe renders to check it: `previews/topo_*.png`, `previews/topo_zoom_*.png` (`build/sf_wire.py`). - **Collision** (`build/sf_collision.py`): 15 convex `UCX_SM_Spearfish_Hull_NN` hulls, 1,246 triangles in all: the hull in eight slices from its exact shape (rings of 16 points, pushed 1 cm out), the two rails, the fins with their lamp pods, the canards, the docking clips. Collision hulls are triangles by nature and Unreal never draws them. Their collection "SPEARFISH | Collision (UCX)" is hidden in the viewport. The user asked *"why is the topology looks like this in blender"* with a picture of long thin triangles all over the hull: those were the old collision hulls drawn as wireframes over the model (convex hulls of every vertex in a slice, up to 1,500 faces each, with unused inner vertices). To see the model's own edges in Blender: Overlays > Wireframe, or Edit Mode. ## Two seats and the bigger canopy (2026-10-20, the user's drawing) The user: *"so this tender should be two seater next to each other when two player can seat each should can see the sea from the window front the glass should be bigger"*, with the bigger glass and the two seats drawn in red on a side and a front screenshot (`reference/user_canopy_side_2026-10-20.webp`, `reference/user_canopy_front_2026-10-20.png`). - **Reading the drawing:** each screenshot was fitted to the hull's silhouette (side 417.6 px/m, front 531.8 px/m: `build/fit_side.py`, `build/fit_front.py`) and the red lines turned into metres (`build/canopy_from_drawing.py` -> `build/canopy_user_2026-10-20.json`). The two drawings agree: the glass's top at 0.63 m (side) and 0.65 m (front). - **The canopy** follows the drawn outline (the glass edge 22 mm inside the line, the frame straddling it): from the nose to y -0.79, its top rising to 0.63 m, about 0.3 m under the top line all along, its bottom near the keel. The blueprint's outline stays in `sf_measure.CANOPY` for the record. Eight grid faces across the glass now (was five); the three mullions keep the blueprint's places and slants and run across the whole glass. - **The canards** moved 0.42 m aft and 9 cm out, into the user's loop beside the canard: they sat inside the bigger glass. - **Two seats side by side** (bucket seats, reclined 40 deg, cushion 0.27 m over the deck, backs' tops near z 0.25 as drawn), at y -0.9, 0.504 m either side of the centre line, the hatch just ahead and a centre console between them; two screens on a low pod ahead; footrests. The drawn rectangles are at +-0.70: at that height the hull is too narrow for that anywhere along its length, so the seats stand as far out as the lining allows. The single centre seat and the aft crew seat are gone; the aft cabin by the side windows is the equipment bay (two racks). - **The view:** from each eye (`SOCKET_Seat_L_Eye`, `SOCKET_Seat_R_Eye`; `SOCKET_Pilot_Eye` is the port one) a look straight ahead leaves through that seat's own glass; 59 % of a box 80 deg wide and 40 deg high ahead does too (the rest: the nose's opaque top strip inboard, the wall beside the seat, the roof). `build/view_check.py`, `build/checks/view.json`. The seats were placed by searching place, height and recline with those rays: further forward the hull is too narrow and the nose's top strip blocks the straight-ahead look. - Pictures: `previews/user_views/cmp_side.png`, `cmp_front.png` (the user's red lines over renders framed like their screenshots), `previews/v05_seat_L.png`, `v05_seat_R.png` (the view from each seat). - Before this change: `versions/v04_before_two_seats/` (also the user's live Blender session as it stood). ### The window frames, redone (same day) The user sent the nose's underside back (*"what is this fix the deformations, lines of window frame compeletely borked"*, *"looks terrible those frames"*). Two causes: the outline still carried the hand drawing's tremor, and the frames were the ring of hull faces round each hole, which pinched and kinked where the window's edge runs steeply (the ends, the nose). - The drawn outline is smoothed along itself (Gaussian, 6 cm), its glass edge set 22 mm inside and smoothed again (2 cm); the side windows' blueprint corners are rounded (2.5 cm). `sf_shape.gauss_closed`. - Every window frame is now a swept trim of one constant section along that smooth outline (`sf_hull.frame_sweep`): an outer flange 40 mm out on the skin, a rounded top 12 mm proud, an inner lip 12 mm over the glass, a sleeve straight down to the cabin lining; points every 6 cm and closer where the outline turns (one per 6 deg). It covers the hull's hole edge, which still follows the outline station by station (stations every 2.5 cm near a window's ends). - The glass is its own ladder of quads over the smooth outline (its edge sits on the sleeve); the mullions sit 2 mm over it and end against the sleeve. - Clash test in the build (`REPORT["clash_frames_vs_parts"]`, `["clash_glass_vs_parts"]`): 0. It found two: the dark block at the big fin's aft root sat inside the side window's lower aft corner (removed), and the fin's aft root corner touched that frame (rounded 7 cm forward). - Before: `versions/v05_before_frame_fix/` (the user's live session as it stood). Close-ups: `previews/v06_frame_*.png`, `previews/frames*_*.png` (wireframe). ## How it follows the blueprint Every outline was read in pixels off the original picture: dark-pixel runs per column for the silhouettes, 4x zooms with rulers for the details. All the numbers are in `build/sf_measure.py`. The TOP, SIDE and UNDERSIDE views share one scale; the FRONT and REAR views are drawn 1.16x larger (body width 165 px against 142 px) and were scaled to match. - Hull: top and bottom profile from the SIDE view and half width from the TOP view at 30-40 stations each, lofted as superellipse sections (4 cm apart, 192 round). The section's fullness comes from the REAR and FRONT views (they agree: a full top, the widest line 45 % down, a narrower keel toward the nose). - Canopy and side windows: their SIDE outlines are cut into the hull grid (the edge vertices moved onto the outline, no booleans), with frames, a sleeve to the cabin lining and smoked glass; the canopy has the SIDE view's three mullions. - Fins: planforms from the TOP view (big fins and canards, the hooked tips and concave edges), heights from the FRONT view. - Everything else at its measured place: the two dorsal rails, the top hatch, the dorsal scoop (hump, dark mouth, ramp), the nose sensors top and bottom, the fin-root fairings, the stern pods with whip antennas, the stern vents, lip, lugs and rear hatch with slots, the ventral blister and slots, the panel seams. (The ribbed actuators the SIDE view shows under the fin roots were built first and removed on the user's word.) - `previews/compare/cmp_*.png` lays the model's outline over each view. TOP and SIDE match within a few pixels. Where the views disagree (it is an AI-drawn sheet), the choice made: | what | views | built | |---|---|---| | big fins | TOP/UNDERSIDE: swept fins; FRONT/REAR: a thick ribbed root, a rod and a round disc | the planform fin low on the flank with a small lamp pod on its outer fore corner (the ribbed root was removed on the user's word) | | antennas | TOP/SIDE: two whips raked aft from stern pods; FRONT/REAR: one central mast | the two whips | | canopy's lower edge | SIDE: image y 429; UNDERSIDE/FRONT: further under | between, y 434 | | stern grille | SIDE: under the lip; TOP: on the aft slope; REAR: a hatch with slots | rear hatch with slots on the end, three slots on the aft slope | | fin height | FRONT: nearly level; SIDE: the root fairing falls aft | level root, 8 deg anhedral | ## Added for the game (not in the blueprint) - **Docking clips.** The docking arm (`models/docking-arm`) holds Tenders by four claws round the clamp axis. As on the Manta: four arcs of the Kazah collar's profile on a slim column between the dorsal rails (top z 1.375). The rails' tops are 3 cm under the column's disc and 15 cm under the claws. - **Folding whip masts.** Raised as drawn they reach 0.52 m into the bay's curved wall when the carousel turns; folded aft along the stern they clear it by 0.41 m. `Spearfish_Root["masts_folded"]` (0 raised, 1 folded). Fold them before stowing. - **A real opening under the top hatch** (with a frame sleeve into the cabin), so the hatch opens onto the cabin. - **The cabin**: lining, deck, two seats side by side (see above), a centre console, an instrument pod with two screens, two racks in the aft equipment bay, roof light strips, a rear bulkhead door. ## Size and axes - 9.55 m long (nose tip to stern lugs), 3.81 m span (fin pods), 1.57 m hull height, 2.23 m with the docking clips. Scale: 1 blueprint pixel = 1.55 cm. The Kazah is 6.9 m long, the Remora 8.72 m, the Manta 9.5 m. - As the Kazah: 1 unit = 1 m, nose to -Y, port +X, Z up; origin on the centre line 9 cm behind the clamp axis. - Unreal: FBX forward -Y, up Z, import with Force Front X Axis; `ue_cm = (-y, -x, z) * 100` (nose +X). ## Checks (scripts in `build/`, results in `build/checks/`) | check | result | limit or comparison | |---|---|---| | moon pool at BOARD (launch arm, interior fork's deck well) | **1.107 m** from the well's edge (at a stern lug) | the user's 1 m; Kazah 1.206 | | carousel sweep, three stowed Tenders, 2 degree steps, masts folded | side **0.404 m**, roof 1.007 m | no contact; Kazah 0.366 / 1.114 | | the same with the masts raised | side -0.52 m (the whip tips) | why the masts fold | | docking clamp, `DockArm_Carousel.blend`, 20 poses (lowered 0 to 5.3 m, claws shut and open, both headings) | 0 intersections, least 15.1 mm | as the Manta (16.5 mm) | | docking clamp, ship file, the three Tender places | 0 intersections, least 15.1 mm | | | top hatch 0 to 100 deg, 2 deg steps | 0 intersections, least 12.2 mm | | | whip masts raised to folded, 21 steps | 0 intersections, least 9.3 mm (their sockets left out) | | (Numbers of the rebuilt topology.) Run: in the open Blender `build/dump_spearfish.py` and `build/motion_check.py`, then `sh build/run_checks.sh`. The ship and arm files are opened read-only and never saved. ## Moving parts (own objects, origin on the axis, scale 1) | object | moves | driver on `Spearfish_Root` | |---|---|---| | `SM_Spearfish_Hatch` | swings up about its aft edge (Blender X), 0 .. 100 deg | `hatch_open_deg` | | `SM_Spearfish_Mast_L` / `_R` | fold aft about their foot (axis-angle, 65.7 deg) | `masts_folded` | Drivers are simple expressions (this Blender runs no Python in files). Drivers made by a script can come back flagged invalid; the scripts re-set them before they pose anything. ## Meshes and materials - `SM_Spearfish_Hull` (static, one mesh: skin with its window and hatch frames and sleeves, fins, canards, fairings, rails, scoop, stern parts, sensors, vents, clips), `SM_Spearfish_Cabin`, `SM_Spearfish_Glass`, the hatch and the two masts. Quads, no booleans, no n-gons. Triangles: hull 37,268 (66 of them triangles), cabin 18,016, glass 5,088, hatch 404, masts 204 each (61,184 in all; the first build had 207,021). `M` and `spacing()` in `build/sf_hull.py` set the grid. - Two UV layers: `UVMap` (UV0, the atlas: baked occlusion/edges/crevices and bevel normals) and `UV_Tile` (UV1, metres). - The blueprint is a line drawing, so the colours are mine: a pale blue-white clear-coated paint (the pack's ScratchedMetal under it), smoked blue glass, graphite fittings, StainedSteel on the actuators and whips, yellow marks on the clips, the CC0 leather on the seats, FloorPanel_A on the deck; cool white cabin light, blue-white screens. ## Build In the open Blender: exec `build/build_spearfish.py` (rebuilds only its own collections; reads `sf_measure.py`, then runs `sf_hull.py`, `sf_fittings.py` and `sf_finish.py`), save (or headless: `blender -b Tender_Spearfish.blend --python build/run_build_headless.py`); then `blender -b Tender_Spearfish.blend --python build/surfaces_spearfish.py` (UVs, bakes, materials; saves; generated by `build/make_surfaces.py` from `surfaces_head.py` and the Manta's surfaces), revert the open Blender, `build/export_spearfish.py`, `build/render_previews.py`. To compare with the blueprint: `build/sf_views.py` in Blender, then `python build/compare_views.py`. A rebuild of the geometry needs the surfaces run again. ## Open - Not in Unreal; no import script or actor yet (same axes as the Kazah, so the Kazah's path can be used). - The docking clips, the folding masts and the cabin's layout are my additions; the user has not seen them yet. - No propulsion is drawn on the sheet (the stern grille reads as a water-jet outlet); nothing turns.