{"id":30818230,"url":"https://github.com/20lives/flatboard","last_synced_at":"2026-06-30T01:32:05.922Z","repository":{"id":310558560,"uuid":"1039904598","full_name":"20lives/flatboard","owner":"20lives","description":"A Parameterized ortholinear split low-profile custom 3d printed keyboard generator","archived":false,"fork":false,"pushed_at":"2026-03-07T17:01:21.000Z","size":1169,"stargazers_count":49,"open_issues_count":0,"forks_count":3,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-03-07T22:33:30.816Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/20lives.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-08-18T06:53:49.000Z","updated_at":"2026-03-07T17:01:25.000Z","dependencies_parsed_at":"2025-08-18T22:23:05.919Z","dependency_job_id":"14320b29-6802-4458-bdb7-e8ad447d72d3","html_url":"https://github.com/20lives/flatboard","commit_stats":null,"previous_names":["20lives/flatboard"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/20lives/flatboard","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/20lives%2Fflatboard","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/20lives%2Fflatboard/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/20lives%2Fflatboard/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/20lives%2Fflatboard/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/20lives","download_url":"https://codeload.github.com/20lives/flatboard/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/20lives%2Fflatboard/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34949234,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-29T02:00:05.398Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-09-06T09:10:45.285Z","updated_at":"2026-06-30T01:32:05.908Z","avatar_url":"https://github.com/20lives.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# flatboard\n\n**Generate custom 3D-printable keyboard cases without CAD or programming knowledge.**\n\nA 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.\n\n## Features\n\n- **No CAD software needed** — define your keyboard with parameters, not 3D modeling\n- **No programming required** — just edit configuration values in TypeScript files\n- **Direct STL output** — generate print-ready files without running or even installing OpenSCAD\n- **Fully parametric** — every dimension calculated from your configuration\n- **Organic outlines** — key-following non-rectangular case shapes, not just bounding boxes\n- **Snap-fit assembly** — no screws needed, top and bottom snap together\n- **Magnetic tenting** — built-in MagSafe ring support for phone holder mounts\n\n## What You Can Configure\n\n### Switch Types\n\nBuilt-in support for popular mechanical switches:\n- **Kailh Choc** — low-profile switches (17.7×16.6mm spacing)\n- **Cherry MX** — standard mechanical switches (18.6×18.6mm spacing)\n\nAdd custom switch types by defining specifications in `src/switches.ts`:\n```typescript\nmySwitch: {\n  description: 'My Custom Switch',\n  outerWidth: 15.0,\n  outerHeight: 15.0,\n  innerWidth: 13.8,\n  innerHeight: 13.8,\n  wallThickness: 1.3,\n  depth: 4.35,\n  ledgeHeight: 2.2,\n  spacingX: 17.7,\n  spacingY: 16.6,\n}\n```\n\n### Connectors\n\nBuilt-in connector types:\n- **USB-C** — pill-shaped female socket\n- **TRRS** — 3.5mm audio jack (for split keyboards)\n- **Power Button** — rectangular button cutout\n\nCreate custom connectors with any shape:\n- `circle` — circular cutout (specify radius)\n- `pill` — rounded rectangle (specify circle radius + center distance)\n- `square` — rectangular cutout (specify width + height)\n\nConnectors can be placed on any face (top, bottom, left, right) with precise 0–1 positioning along the edge.\n\nExample custom connector:\n```typescript\nmyConnector: {\n  description: 'My Custom Port',\n  geometry: {\n    type: 'circle',\n    radius: 4.0\n  }\n}\n```\n\n### Layout System\n\nFully flexible row-based layouts with per-row control:\n\n```typescript\nrowLayout: [\n  { start: 0, length: 6, offset: 0 },    // 6 keys starting at column 0\n  { start: -1, length: 6, offset: 2 },   // 6 keys starting at column -1, 2mm stagger\n  { start: 0, length: 5, offset: 5 },    // 5 keys starting at column 0, 5mm stagger\n]\n```\n\n- **`start`** — starting column position (can be negative for left offset)\n- **`length`** — number of keys in the row\n- **`offset`** — column stagger in millimeters\n- **`thumbAnchor`** — optional key index to anchor the thumb cluster to this row\n\nOptional thumb clusters with independent control:\n- Number of keys\n- Spacing between keys\n- Rotation angle\n- Offset position\n- Per-key rotation and offsets\n\nSplit keyboard support with automatic mirroring for left/right halves.\n\n### Enclosure\n\nSnap-fit rounded-corner enclosure with no screws required. Full control over case dimensions:\n- Plate thickness (top, bottom, walls)\n- Edge margins (uniform or per-side)\n- Electronics cavity depth\n- Rubber feet / magnet socket positions and sizes\n\n### Outline Shapes\n\nTwo enclosure outline modes:\n\n**`rect`** (default) — traditional rectangular bounding box with rounded corners:\n```typescript\nenclosure: {\n  cornerRadius: 3,        // corner rounding radius (mm)\n}\n```\n\n**`organic`** — key-following outline that hugs the layout, creating non-rectangular case shapes:\n```typescript\nenclosure: {\n  outline: {\n    type: 'organic',\n    keyPadding: 1.3,       // mm from key edge to inner wall\n    closingRadius: 10,     // concavity control (higher = smoother concave regions)\n    cornerRadius: 3,       // outline corner rounding\n    resolution: 1.0,       // grid cell size in mm (smaller = more detailed)\n    simplifyEpsilon: 0.8,  // point simplification tolerance in mm\n  },\n}\n```\n\n## Installation\n\n```bash\ngit clone git@github.com:20lives/flatboard.git\ncd flatboard\nbun install\n```\n\n## Quick Start\n\n### 1. List available keyboards\n\n```bash\nbun run list\n```\n\nOutput:\n```\nAvailable keyboard profiles:\n  • corne: 23 keys {0:2,0:3,0:3,0:3,0:3,0:3,0:3} + 3 thumbs [mx] (split)\n  • macropad-3x3: 18 keys {0:3,0:3,0:3} [mx] (unibody)\n  • planck: 48 keys {0:4,0:4,0:4,0:4,0:4,0:4} [mx] (unibody)\n  • split-36: 18 keys {0:3,0:3,0:3,0:3,0:3} + 3 thumbs [mx] (split)\n  • sweep: 17 keys {0:3,0:3,0:3,0:3,0:3} + 2 thumbs [choc] (split)\n  • test-single-choc: 1 keys {0:1} [choc] (split)\n  • test-single-mx: 1 keys {0:1} [mx] (split)\n  • unibody-36: 36 keys {0:3,0:3,0:3,0:3,0:3} + 3 thumbs [choc] (unibody)\n```\n\n### 2. Build a keyboard\n\n```bash\nbun run build -- split-36\n```\n\nOutput:\n```\nGenerated files for profile: split-36\n  • Keyboard size: 18 keys\n  • Plate dimensions: 123.5×114.2mm\n\n./dist/split-36-w92ivk/\n├── bottom.scad (7.9K)\n├── complete.scad (50.7K)\n└── top.scad (38.2K)\n```\n\n### 3. Generate STL files (3D-print ready)\n\n```bash\nbun run build:stl -- split-36\n```\n\nOutput:\n```\n./dist/split-36-w92ivk/\n├── bottom.scad (7.9K)\n├── bottom.stl (52.8K)    ← Ready to print\n├── complete.scad (5.9K)\n├── complete.stl (49.6K)\n├── top.scad (3.5K)\n└── top.stl (50.5K)        ← Ready to print\n```\n\n## Build Modes\n\n### Production Build\n```bash\nbun run build -- \u003cprofile\u003e\n```\n- Outputs to `dist/\u003cprofile\u003e-\u003chash\u003e/`\n- Generates SCAD files only\n- Each build preserved with unique timestamp\n- Fast iteration for design changes\n\n### STL Build\n```bash\nbun run build:stl -- \u003cprofile\u003e\n```\n- Outputs to `dist/\u003cprofile\u003e-\u003chash\u003e/`\n- Generates both SCAD and STL files\n- Uses scad-js renderer internally (no OpenSCAD installation required)\n- Ready for 3D printing\n\n### Development Mode\n```bash\nbun run build:dev -- \u003cprofile\u003e\n```\n- Outputs to `dist/` (overwrites previous)\n- Watch mode: rebuilds on file changes\n- Open `dist/complete.scad` in OpenSCAD for live preview\n- Perfect for rapid iteration\n\n## Creating Your Own Keyboard\n\n### Step 1: Create a profile file\n\nCreate `profiles/my-keyboard.ts`:\n\n```typescript\nimport type { ParameterProfile } from '../src/interfaces.js';\n\nexport const profile: ParameterProfile = {\n  layout: {\n    matrix: {\n      rowLayout: [\n        { start: 0, length: 5, offset: 0 },\n        { start: 0, length: 5, offset: 2 },\n        { start: 0, length: 4, offset: 5 },\n      ],\n    },\n    edgeMargin: 8.0,      // Space around keys (or use { top: 3, bottom: 3, left: 4, right: 3 })\n    baseDegrees: 10.0,    // Overall rotation\n  },\n\n  switch: {\n    type: 'choc',         // or 'mx'\n  },\n\n  thumb: {\n    cluster: {\n      keys: 3,            // Number of thumb keys\n      spacing: 20.0,      // Space between thumb keys\n      rotation: 15.0,     // Thumb cluster angle\n    },\n    offset: {\n      x: 25,              // Horizontal position\n      y: 2,               // Vertical position\n    },\n  },\n\n  connectors: [\n    {\n      type: 'usbC',\n      face: 'top',        // top, bottom, left, or right\n      position: 0.5,      // 0-1 along the edge\n      enabled: true,\n      clearance: 0.2,\n    },\n  ],\n\n  enclosure: {\n    plate: {\n      topThickness: 1.5,\n      bottomThickness: 1.5,\n    },\n    walls: {\n      thickness: 1.5,\n      height: 9.0,\n    },\n  },\n\n  output: {\n    showSwitches: true,   // Show switches in preview\n    showKeycaps: true,    // Show keycaps in preview\n    keycapProfile: 'dsa', // Keycap style: 'dsa', 'xda', 'choc', or 'none'\n  },\n};\n```\n\n### Step 2: Build it\n\n```bash\nbun run build:dev -- my-keyboard\n```\n\nThe filename (without `.ts`) becomes the profile name. No registration needed — profiles are auto-discovered.\n\n## Advanced Customization\n\n### Outline Modes\n\n**Rectangular** (default) — uses `enclosure.cornerRadius` for rounding:\n```typescript\nenclosure: {\n  cornerRadius: 3,        // corner rounding radius (mm)\n}\n```\n\n**Organic** — non-rectangular shapes that follow the key layout:\n```typescript\nenclosure: {\n  outline: {\n    type: 'organic',\n    keyPadding: 1.3,       // mm from key edge to inner wall surface\n    closingRadius: 10,     // concavity control (higher = smoother concave regions)\n    cornerRadius: 3,       // outline corner rounding\n    resolution: 1.0,       // grid cell size in mm (smaller = more detailed)\n    simplifyEpsilon: 0.8,  // point simplification tolerance in mm\n  },\n}\n```\n\n### Per-key Thumb Rotation\n\n```typescript\nthumb: {\n  cluster: {\n    keys: 3,\n    spacing: 20.0,\n    rotation: 15.0,\n  },\n  perKey: {\n    rotations: [-10, 0, 10],    // Individual key angles\n    offsets: [\n      { x: 2, y: 0 },            // Fine-tune each key position\n      { x: 0, y: 0 },\n      { x: 2, y: 0 },\n    ],\n  },\n}\n```\n\n### Rubber Feet Sockets\n\nAdd reinforced sockets for silicon rubber feet:\n\n```typescript\nenclosure: {\n  bottomPadsSockets: [\n    {\n      shape: 'round',              // or 'square'\n      size: { radius: 5.05 },\n      depth: 1.1,\n      position: {\n        anchor: 'bottom-left',     // corner anchor\n        offset: { x: 0, y: 0 }    // fine adjustment\n      },\n      reinforcement: {\n        thickness: 1,\n        height: 0.2\n      },\n    },\n  ],\n}\n```\n\n### MCU Pocket\n\nAdd a built-in microcontroller pocket to the top plate:\n\n```typescript\nenclosure: {\n  topMCUPocket: {\n    size: {\n      width: 18.5,               // Pocket width\n      height: 33.5,              // Pocket height\n      depth: 0.0,                // Pocket depth from top surface\n    },\n    pinAccess: {\n      width: 12,                 // Center opening for pin through-holes\n    },\n    position: {\n      anchor: 'bottom-left',     // Corner anchor\n      offset: { x: 9, y: -5 },  // Fine adjustment\n      rotation: -90,             // Rotation in degrees\n    },\n    reinforcement: {\n      thickness: 1,              // Wall thickness around pocket\n      height: 3.5,               // Reinforcement height\n    },\n    usbPort: {\n      width: 11,                 // USB port cutout width\n      height: 6.5,               // USB port cutout height\n      position: 'bottom',        // Edge of pocket: top, bottom, left, right\n      offset: 0,                 // Offset along the edge\n    },\n  },\n}\n```\n\n### Bottom Patterns\n\nAdd weight-reducing patterns to the bottom plate:\n\n```typescript\nenclosure: {\n  bottomPattern: {\n    type: 'honeycomb',           // 'honeycomb', 'circles', or 'square'\n    cellSize: 14,                // Size of each cell\n    wallThickness: 4,            // Wall between cells\n    margin: 5,                   // Inset from case edges\n  },\n}\n```\n\nPatterns automatically avoid cutting through pad sockets and MagSafe ring areas.\n\n### Magnetic Mounting\n\nAdd a MagSafe ring socket for tenting with phone holders and magnetic mounts:\n\n```typescript\nenclosure: {\n  magsafeRing: {\n    clearance: 0.2,              // Fit adjustment (positive = looser)\n    reinforcement: {\n      outer: 2.0,                // Thickness around outer diameter\n      inner: 2.0,                // Grip margin on inner diameter\n      height: 0.5,               // Additional height for ring\n    },\n    position: {\n      offset: { x: 0, y: 0 },    // Offset from keyboard center\n      placement: 'embedded',      // 'external' or 'embedded'\n    },\n  },\n}\n```\n\nStandard MagSafe dimensions: 56mm outer / 44mm inner / 0.6mm depth.\n\n### Multiple Connectors\n\n```typescript\nconnectors: [\n  {\n    type: 'usbC',\n    face: 'left',\n    position: 0.8,\n    enabled: true,\n    clearance: 0.2,\n  },\n  {\n    type: 'trrs',\n    face: 'right',\n    position: 0.3,\n    enabled: true,\n    clearance: 0.2,\n  },\n  {\n    type: 'powerButton',\n    face: 'top',\n    position: 0.1,\n    enabled: true,\n    clearance: 0.2,\n  },\n]\n```\n\n### Visualization Options\n\nControl how your keyboard appears in the preview:\n\n```typescript\noutput: {\n  showSwitches: true,           // Show Cherry MX switch bodies\n  showKeycaps: true,            // Show keycaps\n  keycapProfile: 'dsa',         // 'dsa', 'xda', 'choc', or 'none'\n  colors: {\n    topPlate: '#b54c9e',        // Top plate color (hex or named)\n    bottomPlate: '#037da3',     // Bottom plate color\n    keycaps: 'WhiteSmoke',      // Keycap color\n  },\n}\n```\n\nVisualization settings only affect the `complete.scad` / `complete.stl` preview file. The `top` and `bottom` files are generated without switches or keycaps for actual printing.\n\n## Included Profiles\n\n### Complete Keyboards\n- **split-36** — 36-key split ergonomic (MX, MCU pocket, MagSafe, honeycomb, organic outline)\n- **corne** — 42-key split ergonomic (MX, USB-C, MagSafe, circles pattern)\n- **sweep** — 34-key split minimalist (Choc, USB-C, MagSafe, honeycomb)\n- **unibody-36** — 36-key unibody ergonomic (Choc, USB-C, power button, organic outline)\n- **planck** — 48-key unibody ortholinear (MX, USB-C)\n- **macropad-3x3** — 3×3 macropad (MX, MCU pocket, honeycomb)\n\n### Test Profiles\n- **test-single-choc** — single Choc switch for fit testing\n- **test-single-mx** — single MX switch for fit testing\n\n## Design and Print Tips\n\n### Before Your First Build\n\nPrint 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.\n\n### Planning Your Layout\n\n- Leave adequate room for your microcontroller and battery\n- Consider wiring thickness — adjust `walls.height` for more internal space\n- Add `layout.edgeMargin` for extra room around switches\n- Use `build:dev` mode with OpenSCAD preview to verify connector clearances\n- Double-check connectors don't interfere with switch positions or wiring paths\n\n### Printing\n\n- **Material**: PLA works, PETG recommended for durability\n- **Supports**: the top plate needs support for switch cutouts; bottom may need support for rubber feet sockets\n- **Orientation**: the top plate may need to be printed upside down (rotated 180 degrees)\n\n### Assembly\n\nAll electronics and wiring fit in the top part of the case. The bottom snaps on and can be removed with a plastic pry tool.\n\n### Output Files\n- `top.scad` / `top.stl` — top plate with switch mounting, electronics cavity, and optional MCU pocket\n- `bottom.scad` / `bottom.stl` — bottom case with snap-fit walls, optional pad sockets, MagSafe ring, and bottom pattern\n- `complete.scad` / `complete.stl` — assembled preview with optional switch bodies and keycaps\n\n## Technical Stack\n\n- **TypeScript** — configuration and geometry logic\n- **[scad-js](https://github.com/nicholasgasior/scad-js)** — TypeScript-to-OpenSCAD transpiler (also renders STL directly)\n- **[fp-ts](https://github.com/gcanti/fp-ts)** — functional programming patterns\n- **[Bun](https://bun.sh)** — runtime and build system\n- **[Biome](https://biomejs.dev)** — linting and formatting\n\n## Commands Reference\n\n```bash\nbun run build -- \u003cprofile\u003e      # Generate SCAD files\nbun run build:dev -- \u003cprofile\u003e  # Watch mode (live preview)\nbun run build:stl -- \u003cprofile\u003e  # Generate STL files (3D printing)\nbun run list                    # List all keyboards\nbun run help                    # Show help\nbun run clean                   # Remove generated files\nbun run check                   # Lint and format (Biome)\n```\n\n## Planned Features\n\n- **Web UI** — browser-based visual configurator\n- **Multi-row thumb clusters** — complex thumb layouts with multiple rows\n- **Trackpad/trackpoint support** — integrated pointing device mounting\n- **Screw standoffs** — alternative to snap-fit assembly\n\n## Contributing\n\nAdd your keyboard profiles — create a `.ts` file in `profiles/` and submit a PR.\n\nFor custom switch types or connectors, add them to `src/switches.ts` or `src/connector-specs.ts`.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F20lives%2Fflatboard","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F20lives%2Fflatboard","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F20lives%2Fflatboard/lists"}