An open API service indexing awesome lists of open source software.

https://github.com/20lives/flatboard

A Parameterized ortholinear split low-profile custom 3d printed keyboard generator
https://github.com/20lives/flatboard

Last synced: about 1 month ago
JSON representation

A Parameterized ortholinear split low-profile custom 3d printed keyboard generator

Awesome Lists containing this project

README

          

# flatboard

**Generate custom 3D-printable keyboard cases without CAD or programming knowledge.**

A parametric keyboard case generator that creates production-ready STL files from simple configuration. Design split keyboards, unibody boards, macropads, or any custom layout — all through TypeScript configuration files.

## Features

- **No CAD software needed** — define your keyboard with parameters, not 3D modeling
- **No programming required** — just edit configuration values in TypeScript files
- **Direct STL output** — generate print-ready files without running or even installing OpenSCAD
- **Fully parametric** — every dimension calculated from your configuration
- **Organic outlines** — key-following non-rectangular case shapes, not just bounding boxes
- **Snap-fit assembly** — no screws needed, top and bottom snap together
- **Magnetic tenting** — built-in MagSafe ring support for phone holder mounts

## What You Can Configure

### Switch Types

Built-in support for popular mechanical switches:
- **Kailh Choc** — low-profile switches (17.7×16.6mm spacing)
- **Cherry MX** — standard mechanical switches (18.6×18.6mm spacing)

Add custom switch types by defining specifications in `src/switches.ts`:
```typescript
mySwitch: {
description: 'My Custom Switch',
outerWidth: 15.0,
outerHeight: 15.0,
innerWidth: 13.8,
innerHeight: 13.8,
wallThickness: 1.3,
depth: 4.35,
ledgeHeight: 2.2,
spacingX: 17.7,
spacingY: 16.6,
}
```

### Connectors

Built-in connector types:
- **USB-C** — pill-shaped female socket
- **TRRS** — 3.5mm audio jack (for split keyboards)
- **Power Button** — rectangular button cutout

Create custom connectors with any shape:
- `circle` — circular cutout (specify radius)
- `pill` — rounded rectangle (specify circle radius + center distance)
- `square` — rectangular cutout (specify width + height)

Connectors can be placed on any face (top, bottom, left, right) with precise 0–1 positioning along the edge.

Example custom connector:
```typescript
myConnector: {
description: 'My Custom Port',
geometry: {
type: 'circle',
radius: 4.0
}
}
```

### Layout System

Fully flexible row-based layouts with per-row control:

```typescript
rowLayout: [
{ start: 0, length: 6, offset: 0 }, // 6 keys starting at column 0
{ start: -1, length: 6, offset: 2 }, // 6 keys starting at column -1, 2mm stagger
{ start: 0, length: 5, offset: 5 }, // 5 keys starting at column 0, 5mm stagger
]
```

- **`start`** — starting column position (can be negative for left offset)
- **`length`** — number of keys in the row
- **`offset`** — column stagger in millimeters
- **`thumbAnchor`** — optional key index to anchor the thumb cluster to this row

Optional thumb clusters with independent control:
- Number of keys
- Spacing between keys
- Rotation angle
- Offset position
- Per-key rotation and offsets

Split keyboard support with automatic mirroring for left/right halves.

### Enclosure

Snap-fit rounded-corner enclosure with no screws required. Full control over case dimensions:
- Plate thickness (top, bottom, walls)
- Edge margins (uniform or per-side)
- Electronics cavity depth
- Rubber feet / magnet socket positions and sizes

### Outline Shapes

Two enclosure outline modes:

**`rect`** (default) — traditional rectangular bounding box with rounded corners:
```typescript
enclosure: {
cornerRadius: 3, // corner rounding radius (mm)
}
```

**`organic`** — key-following outline that hugs the layout, creating non-rectangular case shapes:
```typescript
enclosure: {
outline: {
type: 'organic',
keyPadding: 1.3, // mm from key edge to inner wall
closingRadius: 10, // concavity control (higher = smoother concave regions)
cornerRadius: 3, // outline corner rounding
resolution: 1.0, // grid cell size in mm (smaller = more detailed)
simplifyEpsilon: 0.8, // point simplification tolerance in mm
},
}
```

## Installation

```bash
git clone git@github.com:20lives/flatboard.git
cd flatboard
bun install
```

## Quick Start

### 1. List available keyboards

```bash
bun run list
```

Output:
```
Available keyboard profiles:
• corne: 23 keys {0:2,0:3,0:3,0:3,0:3,0:3,0:3} + 3 thumbs [mx] (split)
• macropad-3x3: 18 keys {0:3,0:3,0:3} [mx] (unibody)
• planck: 48 keys {0:4,0:4,0:4,0:4,0:4,0:4} [mx] (unibody)
• split-36: 18 keys {0:3,0:3,0:3,0:3,0:3} + 3 thumbs [mx] (split)
• sweep: 17 keys {0:3,0:3,0:3,0:3,0:3} + 2 thumbs [choc] (split)
• test-single-choc: 1 keys {0:1} [choc] (split)
• test-single-mx: 1 keys {0:1} [mx] (split)
• unibody-36: 36 keys {0:3,0:3,0:3,0:3,0:3} + 3 thumbs [choc] (unibody)
```

### 2. Build a keyboard

```bash
bun run build -- split-36
```

Output:
```
Generated files for profile: split-36
• Keyboard size: 18 keys
• Plate dimensions: 123.5×114.2mm

./dist/split-36-w92ivk/
├── bottom.scad (7.9K)
├── complete.scad (50.7K)
└── top.scad (38.2K)
```

### 3. Generate STL files (3D-print ready)

```bash
bun run build:stl -- split-36
```

Output:
```
./dist/split-36-w92ivk/
├── bottom.scad (7.9K)
├── bottom.stl (52.8K) ← Ready to print
├── complete.scad (5.9K)
├── complete.stl (49.6K)
├── top.scad (3.5K)
└── top.stl (50.5K) ← Ready to print
```

## Build Modes

### Production Build
```bash
bun run build --
```
- Outputs to `dist/-/`
- Generates SCAD files only
- Each build preserved with unique timestamp
- Fast iteration for design changes

### STL Build
```bash
bun run build:stl --
```
- Outputs to `dist/-/`
- Generates both SCAD and STL files
- Uses scad-js renderer internally (no OpenSCAD installation required)
- Ready for 3D printing

### Development Mode
```bash
bun run build:dev --
```
- Outputs to `dist/` (overwrites previous)
- Watch mode: rebuilds on file changes
- Open `dist/complete.scad` in OpenSCAD for live preview
- Perfect for rapid iteration

## Creating Your Own Keyboard

### Step 1: Create a profile file

Create `profiles/my-keyboard.ts`:

```typescript
import type { ParameterProfile } from '../src/interfaces.js';

export const profile: ParameterProfile = {
layout: {
matrix: {
rowLayout: [
{ start: 0, length: 5, offset: 0 },
{ start: 0, length: 5, offset: 2 },
{ start: 0, length: 4, offset: 5 },
],
},
edgeMargin: 8.0, // Space around keys (or use { top: 3, bottom: 3, left: 4, right: 3 })
baseDegrees: 10.0, // Overall rotation
},

switch: {
type: 'choc', // or 'mx'
},

thumb: {
cluster: {
keys: 3, // Number of thumb keys
spacing: 20.0, // Space between thumb keys
rotation: 15.0, // Thumb cluster angle
},
offset: {
x: 25, // Horizontal position
y: 2, // Vertical position
},
},

connectors: [
{
type: 'usbC',
face: 'top', // top, bottom, left, or right
position: 0.5, // 0-1 along the edge
enabled: true,
clearance: 0.2,
},
],

enclosure: {
plate: {
topThickness: 1.5,
bottomThickness: 1.5,
},
walls: {
thickness: 1.5,
height: 9.0,
},
},

output: {
showSwitches: true, // Show switches in preview
showKeycaps: true, // Show keycaps in preview
keycapProfile: 'dsa', // Keycap style: 'dsa', 'xda', 'choc', or 'none'
},
};
```

### Step 2: Build it

```bash
bun run build:dev -- my-keyboard
```

The filename (without `.ts`) becomes the profile name. No registration needed — profiles are auto-discovered.

## Advanced Customization

### Outline Modes

**Rectangular** (default) — uses `enclosure.cornerRadius` for rounding:
```typescript
enclosure: {
cornerRadius: 3, // corner rounding radius (mm)
}
```

**Organic** — non-rectangular shapes that follow the key layout:
```typescript
enclosure: {
outline: {
type: 'organic',
keyPadding: 1.3, // mm from key edge to inner wall surface
closingRadius: 10, // concavity control (higher = smoother concave regions)
cornerRadius: 3, // outline corner rounding
resolution: 1.0, // grid cell size in mm (smaller = more detailed)
simplifyEpsilon: 0.8, // point simplification tolerance in mm
},
}
```

### Per-key Thumb Rotation

```typescript
thumb: {
cluster: {
keys: 3,
spacing: 20.0,
rotation: 15.0,
},
perKey: {
rotations: [-10, 0, 10], // Individual key angles
offsets: [
{ x: 2, y: 0 }, // Fine-tune each key position
{ x: 0, y: 0 },
{ x: 2, y: 0 },
],
},
}
```

### Rubber Feet Sockets

Add reinforced sockets for silicon rubber feet:

```typescript
enclosure: {
bottomPadsSockets: [
{
shape: 'round', // or 'square'
size: { radius: 5.05 },
depth: 1.1,
position: {
anchor: 'bottom-left', // corner anchor
offset: { x: 0, y: 0 } // fine adjustment
},
reinforcement: {
thickness: 1,
height: 0.2
},
},
],
}
```

### MCU Pocket

Add a built-in microcontroller pocket to the top plate:

```typescript
enclosure: {
topMCUPocket: {
size: {
width: 18.5, // Pocket width
height: 33.5, // Pocket height
depth: 0.0, // Pocket depth from top surface
},
pinAccess: {
width: 12, // Center opening for pin through-holes
},
position: {
anchor: 'bottom-left', // Corner anchor
offset: { x: 9, y: -5 }, // Fine adjustment
rotation: -90, // Rotation in degrees
},
reinforcement: {
thickness: 1, // Wall thickness around pocket
height: 3.5, // Reinforcement height
},
usbPort: {
width: 11, // USB port cutout width
height: 6.5, // USB port cutout height
position: 'bottom', // Edge of pocket: top, bottom, left, right
offset: 0, // Offset along the edge
},
},
}
```

### Bottom Patterns

Add weight-reducing patterns to the bottom plate:

```typescript
enclosure: {
bottomPattern: {
type: 'honeycomb', // 'honeycomb', 'circles', or 'square'
cellSize: 14, // Size of each cell
wallThickness: 4, // Wall between cells
margin: 5, // Inset from case edges
},
}
```

Patterns automatically avoid cutting through pad sockets and MagSafe ring areas.

### Magnetic Mounting

Add a MagSafe ring socket for tenting with phone holders and magnetic mounts:

```typescript
enclosure: {
magsafeRing: {
clearance: 0.2, // Fit adjustment (positive = looser)
reinforcement: {
outer: 2.0, // Thickness around outer diameter
inner: 2.0, // Grip margin on inner diameter
height: 0.5, // Additional height for ring
},
position: {
offset: { x: 0, y: 0 }, // Offset from keyboard center
placement: 'embedded', // 'external' or 'embedded'
},
},
}
```

Standard MagSafe dimensions: 56mm outer / 44mm inner / 0.6mm depth.

### Multiple Connectors

```typescript
connectors: [
{
type: 'usbC',
face: 'left',
position: 0.8,
enabled: true,
clearance: 0.2,
},
{
type: 'trrs',
face: 'right',
position: 0.3,
enabled: true,
clearance: 0.2,
},
{
type: 'powerButton',
face: 'top',
position: 0.1,
enabled: true,
clearance: 0.2,
},
]
```

### Visualization Options

Control how your keyboard appears in the preview:

```typescript
output: {
showSwitches: true, // Show Cherry MX switch bodies
showKeycaps: true, // Show keycaps
keycapProfile: 'dsa', // 'dsa', 'xda', 'choc', or 'none'
colors: {
topPlate: '#b54c9e', // Top plate color (hex or named)
bottomPlate: '#037da3', // Bottom plate color
keycaps: 'WhiteSmoke', // Keycap color
},
}
```

Visualization settings only affect the `complete.scad` / `complete.stl` preview file. The `top` and `bottom` files are generated without switches or keycaps for actual printing.

## Included Profiles

### Complete Keyboards
- **split-36** — 36-key split ergonomic (MX, MCU pocket, MagSafe, honeycomb, organic outline)
- **corne** — 42-key split ergonomic (MX, USB-C, MagSafe, circles pattern)
- **sweep** — 34-key split minimalist (Choc, USB-C, MagSafe, honeycomb)
- **unibody-36** — 36-key unibody ergonomic (Choc, USB-C, power button, organic outline)
- **planck** — 48-key unibody ortholinear (MX, USB-C)
- **macropad-3x3** — 3×3 macropad (MX, MCU pocket, honeycomb)

### Test Profiles
- **test-single-choc** — single Choc switch for fit testing
- **test-single-mx** — single MX switch for fit testing

## Design and Print Tips

### Before Your First Build

Print the `test-single-choc` or `test-single-mx` profile first to verify your printer is tuned and switches fit snugly. Test the snap-fit mechanism between top and bottom — parts should snap together securely without excessive force.

### Planning Your Layout

- Leave adequate room for your microcontroller and battery
- Consider wiring thickness — adjust `walls.height` for more internal space
- Add `layout.edgeMargin` for extra room around switches
- Use `build:dev` mode with OpenSCAD preview to verify connector clearances
- Double-check connectors don't interfere with switch positions or wiring paths

### Printing

- **Material**: PLA works, PETG recommended for durability
- **Supports**: the top plate needs support for switch cutouts; bottom may need support for rubber feet sockets
- **Orientation**: the top plate may need to be printed upside down (rotated 180 degrees)

### Assembly

All electronics and wiring fit in the top part of the case. The bottom snaps on and can be removed with a plastic pry tool.

### Output Files
- `top.scad` / `top.stl` — top plate with switch mounting, electronics cavity, and optional MCU pocket
- `bottom.scad` / `bottom.stl` — bottom case with snap-fit walls, optional pad sockets, MagSafe ring, and bottom pattern
- `complete.scad` / `complete.stl` — assembled preview with optional switch bodies and keycaps

## Technical Stack

- **TypeScript** — configuration and geometry logic
- **[scad-js](https://github.com/nicholasgasior/scad-js)** — TypeScript-to-OpenSCAD transpiler (also renders STL directly)
- **[fp-ts](https://github.com/gcanti/fp-ts)** — functional programming patterns
- **[Bun](https://bun.sh)** — runtime and build system
- **[Biome](https://biomejs.dev)** — linting and formatting

## Commands Reference

```bash
bun run build -- # Generate SCAD files
bun run build:dev -- # Watch mode (live preview)
bun run build:stl -- # Generate STL files (3D printing)
bun run list # List all keyboards
bun run help # Show help
bun run clean # Remove generated files
bun run check # Lint and format (Biome)
```

## Planned Features

- **Web UI** — browser-based visual configurator
- **Multi-row thumb clusters** — complex thumb layouts with multiple rows
- **Trackpad/trackpoint support** — integrated pointing device mounting
- **Screw standoffs** — alternative to snap-fit assembly

## Contributing

Add your keyboard profiles — create a `.ts` file in `profiles/` and submit a PR.

For custom switch types or connectors, add them to `src/switches.ts` or `src/connector-specs.ts`.

## License

MIT