Skip to content

20lives/flatboard

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

74 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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:

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:

myConnector: {
  description: 'My Custom Port',
  geometry: {
    type: 'circle',
    radius: 4.0
  }
}

Layout System

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

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:

enclosure: {
  cornerRadius: 3,        // corner rounding radius (mm)
}

organic — key-following outline that hugs the layout, creating non-rectangular case shapes:

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

git clone [email protected]:20lives/flatboard.git
cd flatboard
bun install

Quick Start

1. List available keyboards

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

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)

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

bun run build -- <profile>
  • Outputs to dist/<profile>-<hash>/
  • Generates SCAD files only
  • Each build preserved with unique timestamp
  • Fast iteration for design changes

STL Build

bun run build:stl -- <profile>
  • Outputs to dist/<profile>-<hash>/
  • Generates both SCAD and STL files
  • Uses scad-js renderer internally (no OpenSCAD installation required)
  • Ready for 3D printing

Development Mode

bun run build:dev -- <profile>
  • 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:

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

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:

enclosure: {
  cornerRadius: 3,        // corner rounding radius (mm)
}

Organic — non-rectangular shapes that follow the key layout:

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

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:

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:

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:

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:

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

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:

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 — TypeScript-to-OpenSCAD transpiler (also renders STL directly)
  • fp-ts — functional programming patterns
  • Bun — runtime and build system
  • Biome — linting and formatting

Commands Reference

bun run build -- <profile>      # Generate SCAD files
bun run build:dev -- <profile>  # Watch mode (live preview)
bun run build:stl -- <profile>  # 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

About

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

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors