Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ jscad-electronics includes models for various components, including:
- ICs (DIP, SOIC, TSSOP, QFN, QFP, BGA)
- Diodes (SOD-123)
- Transistors (SOT-23, SOT-563, SOT-723)
- Connectors (JST PH, SH, ZH, generic SMD, FPC, RJ45, pin headers)
- And more!

Check the `lib` directory for a full list of available components.
Expand All @@ -76,6 +77,15 @@ Refer to the individual component files for available customization options.
jscad-electronics is designed to work seamlessly with tscircuit. You can use these 3D models in your tscircuit projects to create accurate 3D representations of your PCB designs just by
using the `footprint` prop

### JST footprint models

`Footprinter3d` supports every JST variant exposed by footprinter:

- `jst4` or `jst4_ph` for PH-style through-hole connectors
- `jst4_sh` for SH 1 mm surface-mount connectors
- `jst4_zh` for ZH 1.5 mm through-hole connectors
- `jst4_smd` for generic parameterized surface-mount connectors

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.
Expand Down
4 changes: 2 additions & 2 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions examples/jst-family.example.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { JsCadView, Translate } from "jscad-fiber"
import { JSTPH2mm, JSTSH1mm, JSTSmd, JSTZH1_5mm } from "../lib"

export default function Example() {
return (
<JsCadView zAxisUp showGrid>
<Translate offset={[-12, 0, 0]}>
<JSTPH2mm numPins={4} />
</Translate>
<Translate offset={[-4, 0, 0]}>
<JSTSH1mm numPins={4} />
</Translate>
<Translate offset={[5, 0, 0]}>
<JSTZH1_5mm numPins={4} />
</Translate>
<Translate offset={[14, 0, 0]}>
<JSTSmd numPins={4} mountPadPitchX={8} />
</Translate>
</JsCadView>
)
}
44 changes: 43 additions & 1 deletion lib/Footprinter3d.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ import { AxialCapacitor } from "./AxialCapacitor"
import { StampBoard } from "./stampboard"
import { MountedPcbModule } from "./MountedPcbModule"
import SOD723 from "./SOD723"
import { JSTPH2mm } from "./JSTPH2mm"
import { JSTSH1mm } from "./JSTSH1mm"
import { JSTZH1_5mm } from "./JSTZH1_5mm"
import { JSTSmd } from "./JSTSmd"
import { FPC } from "./FPC"
import { SmdPinHeader } from "./SmdPinHeader"
import { RJ45 } from "./RJ45"
Expand All @@ -83,6 +86,8 @@ export const Footprinter3d = ({ footprint }: { footprint: string }) => {
pw: number
num_pins: number
fn: string
ph?: boolean
sh?: boolean
zh?: boolean
thermalpad?: { x: number; y: number }
imperial: String
Expand Down Expand Up @@ -319,10 +324,47 @@ export const Footprinter3d = ({ footprint }: { footprint: string }) => {
/>
)
case "jst":
if (fpJson.smd) {
return (
<JSTSmd
numPins={fpJson.num_pins}
pitch={fpJson.p}
bodyWidth={fpJson.w}
bodyDepth={fpJson.h}
padWidth={fpJson.pw}
padLength={fpJson.pl}
mountPadPitchX={fpJson.mpx}
mountPadRowDistance={fpJson.mpy}
mountPadWidth={fpJson.mpw}
mountPadLength={fpJson.mpl}
mountTop={fpJson.mounttop}
/>
)
}
if (fpJson.sh) {
return (
<JSTSH1mm
numPins={fpJson.num_pins}
pitch={fpJson.p}
padWidth={fpJson.pw}
padLength={fpJson.pl}
/>
)
}
if (fpJson.zh) {
return <JSTZH1_5mm numPins={fpJson.num_pins} />
}
break
return (
<JSTPH2mm
numPins={fpJson.num_pins}
pitch={fpJson.p}
bodyWidth={fpJson.w}
bodyDepth={fpJson.h}
holeDiameter={fpJson.id}
padWidth={fpJson.pw}
padLength={fpJson.pl}
/>
)
case "fpc":
return (
<FPC
Expand Down
148 changes: 148 additions & 0 deletions lib/JSTPH2mm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import type { PcbPlatedHole } from "circuit-json"
import {
Colorize,
Cuboid,
Cylinder,
Rotate,
RoundedCuboid,
Subtract,
Translate,
} from "jscad-fiber"
import { FootprintPlatedHole } from "./FootprintPlatedHole"

export interface JSTPH2mmProps {
numPins?: number
pitch?: number
bodyWidth?: number
bodyDepth?: number
bodyHeight?: number
pinRowY?: number
holeDiameter?: number
padWidth?: number
padLength?: number
showPins?: boolean
showFootprint?: boolean
bodyColor?: string
pinColor?: string
}

/**
* Parametric JST PH-style, side-entry through-hole header.
*
* The body follows the PH family envelope while the pin locations and pad
* dimensions can be driven directly by a footprinter definition.
*/
export const JSTPH2mm = ({
numPins = 2,
pitch = 2,
bodyWidth,
bodyDepth = 5,
bodyHeight = 6,
pinRowY = 2,
holeDiameter = 0.7,
padWidth = 1.2,
padLength = 1.2,
showPins = true,
showFootprint = true,
bodyColor = "#f2eee1",
pinColor = "#b9a56b",
}: JSTPH2mmProps) => {
const pinSpan = (numPins - 1) * pitch
const resolvedBodyWidth = Math.max(bodyWidth ?? 0, pinSpan + 3.9)
const bodyCenterY = pinRowY - bodyDepth / 2 + 0.5
const bodyBottom = 0.2
const cavityDepth = Math.min(bodyDepth * 0.56, 2.8)
const cavityCenterY = bodyCenterY - bodyDepth / 2 + cavityDepth / 2 - 0.05
const cavityHeight = Math.max(bodyHeight - 1.5, 2)
const startX = -pinSpan / 2
const pinRadius = Math.max(0.2, Math.min(holeDiameter * 0.37, 0.32))
const horizontalPinEndY = bodyCenterY + bodyDepth * 0.05
const horizontalPinLength = Math.max(pinRowY - horizontalPinEndY, 0.8)

return (
<>
<Colorize color={bodyColor}>
<Subtract>
<RoundedCuboid
size={[resolvedBodyWidth, bodyDepth, bodyHeight]}
center={[0, bodyCenterY, bodyBottom + bodyHeight / 2]}
roundRadius={0.16}
/>
<Cuboid
size={[resolvedBodyWidth - 1.15, cavityDepth + 0.2, cavityHeight]}
center={[0, cavityCenterY, bodyBottom + 0.75 + cavityHeight / 2]}
/>
<Cuboid
size={[0.8, 0.55, 0.5]}
center={[
-resolvedBodyWidth / 2 + 0.85,
bodyCenterY - bodyDepth / 2,
bodyBottom + bodyHeight - 0.25,
]}
/>
</Subtract>

<Cuboid
size={[resolvedBodyWidth - 0.7, 0.32, 0.45]}
center={[
0,
bodyCenterY + bodyDepth / 2 - 0.16,
bodyBottom + bodyHeight - 0.55,
]}
/>
</Colorize>

{showPins &&
Array.from({ length: numPins }).map((_, index) => {
const x = startX + index * pitch
return (
<Colorize key={`pin:${index}`} color={pinColor}>
<Cylinder
center={[x, pinRowY, 0.4]}
height={3.6}
radius={pinRadius}
/>
<Translate
offset={[
x,
(pinRowY + horizontalPinEndY) / 2,
bodyBottom + 1.65,
]}
>
<Rotate rotation={[Math.PI / 2, 0, 0]}>
<Cylinder height={horizontalPinLength} radius={pinRadius} />
</Rotate>
</Translate>
</Colorize>
)
})}

{showFootprint &&
Array.from({ length: numPins }).map((_, index) => {
const hole: PcbPlatedHole = {
type: "pcb_plated_hole",
pcb_plated_hole_id: `jstph_${index}`,
shape: "circular_hole_with_rect_pad",
x: startX + index * pitch,
y: pinRowY,
hole_diameter: holeDiameter,
hole_shape: "circle",
pad_shape: "rect",
rect_pad_width: padWidth,
rect_pad_height: padLength,
layers: ["top", "bottom"],
port_hints: [`${index + 1}`],
}
return (
<FootprintPlatedHole
key={`footprint:${index}`}
hole={hole}
isPin1={index === 0}
/>
)
})}
</>
)
}

export default JSTPH2mm
Loading
Loading