Skip to main content

A Python package for parametric 3D modeling of keyboard keycaps.

Project description

Capistry

A Python package for parametric 3D modeling of keyboard keycaps using build123d.

Docs License: MPL 2.0 PyPI Version Python 3.13+

Rendered keycap model created with Capistry

Table of Contents

Overview

  • Parametric Design: Create custom keycaps with precise control over dimensions, angles, and styling.
  • Shapes: Rectangular, slanted, skewed, and trapezoidal keycap shapes.
  • Stems: Compatible with MX and Choc switches.
  • Advanced Geometry: Tapers, fillets, and surface modeling.
  • Batching: Generate panels of multiple keycaps for 3D printing.
  • Exporting: Export to any format supported by build123d, including STL, STEP, DXF, SVG, and more.
  • Ergogen: Export Ergogen configurations consisting of keycap positions and outlines.
  • Extensible: Designed to be extensible - you can create custom stems, cap classes, fillet strategies, and sprue designs by extending the base classes.

Installation

pip install capistry

Requirements

  • Python 3.13+
  • Dependencies:
    • build123d
    • rich
    • mashumaro
    • more-itertools
    • attrs
    • tzdata

Quick Start

from build123d import *
from capistry import *
import logging

# Initialize logging
init_logger(level=logging.INFO)

# Create a basic rectangular keycap
cap = RectangularCap(
    width=18,
    length=18,
    height=5,
    wall=1.25,
    roof=1.25,
    taper=Taper.uniform(7),
    stem=MXStem(center_at=CenterOf.GEOMETRY),
    fillet_strategy=FilletUniform()
)

# Export as STL
export_stl(cap.compound, "keycap.stl")

# Create a sprued grid-like panel for 3D printing
panel = Panel(
    items=[
        PanelItem(cap, quantity=10, mirror=True),
    ],
    sprue=SprueCylinder(),
)

# Export panel as STL
export_stl(panel.compound, "panel.stl")

[!TIP] You can use ocp-vscode to preview your parts in VS-Code during development.

Features

Keycap Shapes

As of now, all keycap shapes are quadrilaterals, i.e. four-sided polygons.

RectangularCap

Standard rectangular keycap:

cap = RectangularCap(width=18, length=18, height=5)

SlantedCap

An asymmetric keycap where two sides are angled evenly away from their respective orientations. The resulting shape has two orthogonal (90°) corners, one corner at 90 + v° and another at 90 – v°, where v is the slant angle.

cap = SlantedCap(width=18, length=18, height=5, angle=7)

SkewedCap

Keycap with a parallelogram shape:

cap = SkewedCap(width=18, length=18, height=5, skew=5, skew_width=True)

TrapezoidCap

Keycap with a trapezoidal shape:

cap = TrapezoidCap(width=18, length=18, height=5, angle=5)

Stems

Support for different stems:

# MX-style stem
stem = MXStem()

# Choc-style stem
stem = ChocStem()

cap = RectangularCap(stem=stem)

Tapering

Control the slope of keycap sides:

# Uniform taper on all sides
taper = Taper.uniform(7)

# Side-specific tapering
taper = Taper(front=10, back=7, left=4, right=4)

cap = RectangularCap(taper=taper)

Fillet Strategies

Choose how edges are rounded:

# Uniform filleting
fillet_strat = FilletUniform()

# Sides-first filleting
fillet_strat = FilletSidesFirst()

# Sides-Last filleting
fillet_strat = FilletSidesFirst()

cap = RectangularCap(fillet_strategy=fillet_strat)

[!WARNING] Due to the nature of CAD modeling, some fillet configurations simply won't be compatible with every combination of cap, taper and surface due to geometric constraints. If you run into issues building a certain cap, try to adjust these parameters to resolve the problem. FilletUniform tends to be the least error-prone strategy.

Surface Modeling

The top face of keycaps can be precisely modeled by defining a Surface. A Surface is represented by a matrix (a 2-dimensional list), specifying the offset values which will be used to model the top face. Optionally, a weights matrix may also be supplied.

surface = Surface(
        [
            [4, 4, 4, 4],
            [2, -1, -1, 2],
            [0, -1, -1, 0],
            [0, 0, 0, 0],
        ]
    )

cap = TrapezoidCap(surface=surface)

Comparisons

You can compare caps, fillets, stems, and surfaces using the capistry.Comparer class. This is useful for identifying both dimensional differences and property variations.

# Create two keycaps with different parameters
c1 = RectangularCap(width=18, length=18, height=5)
c2 = RectangularCap(width=19*2 - 1, length=18, height=5)

# Create a comparer
comparer = Comparer(c2, c2)

# Show the comparison, outputs a rich table in the console
comparer.show(show_deltas=True)

Panel Generation

Create grid-like panels of keycaps for simpler 3D printing by creating a capistry.Panel:

cap = RectangularCap()

# Create a 4x4 panel of a keycap
panel = Panel(
    items=[PanelItem(cap, quantity=16)], 
    sprue=SprueCylinder(), 
    cols=4
)

# Export the entire panel
export_stl(panel.compound, "keycap_panel.stl")

Ergogen Export

Export your keycaps in their current locations to an Ergogen configuration file.

# Create two rectangular keycaps
c1 = RectangularCap()
c2 = RectangularCap()

# Position the second keycap to the right of the first
c2.locate(c1.top_right)

#  Create an ergogen instance, and write the configuration to a YAML file
ergogen = Ergogen(c1, c2)
ergogen.write_yaml("config.yaml", precision=3)

Documentation

Full API documentation is available and generated using pdoc.

👉 View the full documentation here

Examples

For more detailed examples, see the examples/ directory in the repository.

Development

Building from Source

git clone https://github.com/larssont/capistry.git
cd capistry
uv sync

License

This project is licensed under the Mozilla Public License 2.0 - see the LICENSE.md file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Acknowledgments

  • build123d — CAD library powering Capistry

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

capistry-0.1.0.tar.gz (69.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

capistry-0.1.0-py3-none-any.whl (75.9 kB view details)

Uploaded Python 3

File details

Details for the file capistry-0.1.0.tar.gz.

File metadata

  • Download URL: capistry-0.1.0.tar.gz
  • Upload date:
  • Size: 69.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for capistry-0.1.0.tar.gz
Algorithm Hash digest
SHA256 53795778e1b6ca4a3c1ec26907b2d6b7b7c5778284f2c5093a3068cc3006a24d
MD5 ac2c9f7b16b835f88550d6a7a5ed36db
BLAKE2b-256 33cc44c038b919cac4707aebd7f311775607710d7db0637257798ec2b4a3f6fc

See more details on using hashes here.

Provenance

The following attestation bundles were made for capistry-0.1.0.tar.gz:

Publisher: publish.yml on larssont/capistry

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file capistry-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: capistry-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 75.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for capistry-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7f348c7143003d7017f3cc488608b7e81b1b45ce778f0f5a2675a296fafe6d98
MD5 cd893c5900f032fb0ae042fa0f6d72fb
BLAKE2b-256 56cc46d3f9cbac7c79dc7b178cee3d6aaeb421bceebac7f68e16d90c6658930f

See more details on using hashes here.

Provenance

The following attestation bundles were made for capistry-0.1.0-py3-none-any.whl:

Publisher: publish.yml on larssont/capistry

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page