muse/book-reading-clip-lamp
A tscircuit package created by muse.
- Version
- 0.4.6
- License
- unset
- Stars
- 0
base-service-connectors.ts
import { box, cyl, move, turn, union, subtract, tint, type Plan, type V3 } from "./mechanical-primitives"
import type { MechanicalPart } from "./enclosure-geometry"
/** Drawing-based external models, NOT vendor STEP. 222 blocks each join ONE
* potential: never insert different nets in different holes of the same block.
* Wire-entry detail is a visual approximation; envelope dimensions are catalog.
*/
const wago = (id: string, net: string, center: V3, count = 2, angle = 0) => ({
id, label: `${net} · WAGO 222-${count === 5 ? "415" : "412"}`,
family: "WAGO 222", parts: [count === 5 ? "222-415" : "222-412"], center,
size: [count === 5 ? 26.6 : 12.4, 20.5, 14.5] as V3,
pitch: 5.1, rows: 1, circuits: count, nets: Array(count).fill(net) as string[], angle,
source: `https://www.wago.com/us/wire-splicing-connectors/splicing-connector/p/222-${count === 5 ? "415" : "412"}`,
})
export const baseServiceConnectors = [
wago("vbat-splice", "VBAT", [-15,-148,-180.4]),
wago("ntc-splice", "NTC", [0,-148,-180.4]),
wago("ntc-return-splice", "NTC_RETURN", [15,-148,-180.4]),
wago("ground-splice", "GND", [-11,-177,-180.4], 5),
wago("chat-splice", "ASK_REMOTE", [15,-186,-180.4], 2, -Math.PI/2),
wago("power-splice", "PWR_REMOTE", [15,-171,-180.4], 2, -Math.PI/2),
{ id:"speaker-service-connector",label:"Speaker · PicoBlade 51021 / 51047",family:"Molex PicoBlade",
parts:["0510210200 (speaker)","0510470200 (harness)"],center:[-23.3,-164.5,-167.6] as V3,
size:[4.25,13.8,4.2] as V3,pitch:1.25,rows:1,circuits:2,nets:["SPK_P","SPK_N"],angle:0,
source:"https://www.molex.com/en-us/products/part-detail/510470200" },
]
function place(c: typeof baseServiceConnectors[number], p: V3): V3 {
const a=c.angle
return [c.center[0]+p[0]*Math.cos(a)-p[1]*Math.sin(a),c.center[1]+p[0]*Math.sin(a)+p[1]*Math.cos(a),c.center[2]+p[2]]
}
export function splicePort(id: string, cavity: number): V3 {
const c=baseServiceConnectors.find(c=>c.id===id)
if(!c || cavity<0 || cavity>=c.circuits) throw new Error(`Invalid terminal ${id}.${cavity}`)
return place(c,[(cavity-(c.circuits-1)/2)*c.pitch,c.size[1]/2,-2])
}
// Legacy logical branch names preserved for the head-harness endpoint audit.
export function connectorPort(id: string,index: number,side:"head"|"load"):V3 {
if(id==="speaker-service-connector") {
const c=baseServiceConnectors.find(c=>c.id===id)!
return [c.center[0]+(index-.5)*1.25,c.center[1]+(side==="head"?1:-1)*c.size[1]/2,c.center[2]]
}
if(id==="battery-service-connector") return splicePort(["vbat-splice","ground-splice","ntc-splice","ntc-return-splice"][index],side==="head"?0:1)
if(id==="chat-service-connector") return index===0?splicePort("chat-splice",side==="head"?0:1):splicePort("ground-splice",2)
if(id==="power-service-connector") return index===0?splicePort("power-splice",side==="head"?0:1):splicePort("ground-splice",3)
throw new Error(`Unknown branch ${id}`)
}
/** Ownership split: speaker's supplied housing moves with the speaker;
* harness-side plug stays with its cable. These share the old mated envelope.
*/
export function speakerConnectorHousing(side:"head"|"load"):Plan {
const c=baseServiceConnectors.find(c=>c.id==="speaker-service-connector")!
const shell=side==="load" ? union(box([4.25,8,3.3],[0,-2.9,-.3]),box([2.9,3,.55],[0,-1,1.6])) : box([4.1,5.8,4.2],[0,4,0])
return move(c.center,tint([.91,.90,.82],subtract(shell,...[-.625,.625].map(x=>move([x,0,0],turn([Math.PI/2,0,0],{type:"cylinder",radius:.48,height:14,segments:20}))))))
}
const model=(c:typeof baseServiceConnectors[number]):Plan=> {
const [w,d,h]=c.size
if(c.family!=="WAGO 222") return speakerConnectorHousing("head")
const holes=Array.from({length:c.circuits},(_,i)=>move([(i-(c.circuits-1)/2)*c.pitch,d/2-5,-2],turn([Math.PI/2,0,0],{type:"cylinder",radius:1.65,height:10.2,segments:24})))
const body=subtract(box([w,d,h-2],[0,0,-1]),...holes,
...Array.from({length:c.circuits},(_,i)=>box([3.8,13,2],[(i-(c.circuits-1)/2)*c.pitch,-1,5.4])))
const levers=Array.from({length:c.circuits},(_,i)=>tint([1,.10,.004],union(
box([3.6,14.4,1.8],[(i-(c.circuits-1)/2)*c.pitch,-1,6.35]),
box([3.6,1.3,2.1],[(i-(c.circuits-1)/2)*c.pitch,6,5.6]))))
return move(c.center,turn([0,0,c.angle],union(tint([.12,.13,.12],body),...levers)))
}
export const serviceConnectorParts:MechanicalPart[]=baseServiceConnectors.map(c=>({id:c.id,label:c.label,plan:model(c),group:"reference",color:[.48,.49,.48],multicolor:true,printable:false,explode:c.family==="WAGO 222"?[0,0,8]:[0,0,0],note:c.family==="WAGO 222"?`${c.parts[0]}; ${c.size.join(" x ")} mm catalog envelope. ONE potential per block; 28–12 AWG; strip 9–10 mm. Open levers with lid/cradle removed; drawing-based exterior, internal clamp omitted.`:"Harness-side Molex 51047 plug only; stock 51021 receptacle belongs to the speaker assembly. Drawing-based exterior; verify shipped mating, polarity and latch."}))
/** Visible bare conductor inserted into a stock lever clamp; the housing's
* entry bores already reserve this 9.5 mm strip length. No soldered splice.
*/
export function terminalMetalEnd(points:V3[], conductorRadius:number):Plan[] {
const end=points[points.length-1]
for(const c of baseServiceConnectors.filter(c=>c.family==="WAGO 222"))for(let i=0;i<c.circuits;i++) {
const entry=splicePort(c.id,i)
if(Math.hypot(...entry.map((n,j)=>n-end[j]))>1e-7)continue
const localX=(i-(c.circuits-1)/2)*c.pitch
const at=place(c,[localX,c.size[1]/2-4.75,-2])
return [move(at,turn([Math.PI/2,0,c.angle],tint([.72,.32,.055],{type:"cylinder",radius:conductorRadius,height:9.5,segments:16})))]
}
return []
}