MAKER-PANEL(5)
β¨ MAKER-PANEL(5) β¨
okay bestie, this is the quick reference for the maker-panel specification language. it's a lot, but we're gonna get through it together, and honestly? it's kind of iconic. π
πΈ SYNTAX πΈ
maker-panel specs are similar to code β they're interpreted top-down, and they're built kinda like modern high-level languages. no cap, if you've ever touched a real programming language you'll feel right at home. π
Creating features
features (they get explained further down, don't worry) are declared similar to functions in other programming languages, and they take this rough form:
FEATURE_NAME<PARAMETERS>(OPTIONAL_SURFACE_FEATURES)
like, for example:
R<5>()
which creates:
- a feature
R(which corresponds to a rectangle feature) - with the parameter
5(for rectangle features, this means a width and height of 5 units) - and no inner surface features β¨
surface features are a lil different though β they can only appear within a non-surface feature. so if we update that example above to have the rectangle contain the drill hit surface feature, we'd get:
R<5>(h)
(h being the shorthand for a hole, AKA a drill hit π³οΈ)
Comments
all comments start with a # and they extend for the remainder of the line. simple as that, periodt. π
Variables
Feature variables
features can be saved to a variable and then created multiple times later. you define a variable using the let statement:
let top = R<7>(h);
that defines a variable named top, which is a 7x7 square containing an h feature. slay.
you can use a variable wherever you would use a feature, just write its name prefixed by a $ character. for example:
[2]$top
manifests the top twice (as part of an array). two for the price of one, we love to see it π«Ά
Number variables
you can also save the value of a CEL expression to a variable and use it later. yes, numbers get variables too:
let diameter = !{26}
let radius = !{diameter / 2}
C<$radius>
so in that example we save 26 to diameter, which we then use in another CEL expression to compute radius. then we use radius as the input to a circle feature. math but make it cute π§
π FEATURES π
the different elements that make up a spec are called features. and here's the tea: if features are specified alongside one another, they get combined. specifically:
- features that detail the geometry of the panel are unioned (ie: two overlapping squares produce a larger rectangle with dimensions no greater than the extremes of either rectangle)
- surface features are applied to the panel in the order in which they appear
β οΈ in general, it is an error if your shapes don't overlap to form a single, combined shape. π
you can change this behavior with the -c flag, which will compute the convex hull of all the shapes (hence forming a single shape). crisis averted π
Geometry
geometric features make up the overall shape of the panel, and they're the most common ones. almost all shapes can be represented by combining different, simpler shapes β like rectangles, circles, and triangles. build-a-bear but for panels, fr fr π
Rectangles
okay so the original put this in a table, but tables are not the vibe here so we're doing it in list form. same facts, better energy π
R<dimension>()β example:R<5>()β creates a rectangle with a width and height of5units.R<@(x, y), dimension>()β example:R<@(1, 2), 5>()β creates a rectangle with a width and height of5units, centered on(1, 2).R<width, height>()orR<size = (width, height)>()β examples:R<3, 5>(),R<size = (3,5)>()β creates a rectangle with a width of3units and a height of5units.R<@(x, y), width, height>()orR<@(x, y), size = (width, height)>()β examples:R<@(1, 2), 3, 5>(),R<@(1, 2), size = (3,5)>()β creates a rectangle with a width of3units and a height of5units, centered on(1, 2).
Circles π
okay so circles are literally giving main-character geometry. here's the vibe:
- Form:
5(),radius = 5(),r = 5()β Example:5(),radius = 5(),r = 5()β creates a circle with a radius of 5 units. slay. - Form:
@(x, y), radius(),@(x, y), radius = radius(),@(x, y), r = radius()β Example:@(2, 3), 5(),@(2, 3), radius = 5(),@(2, 3), r = 5()β creates a circle with a radius of 5 units. the center of the circle is positioned at (2, 3). iconic placement fr fr.
Triangles πΊ
triangles are also here and they're lowkey serving:
- Form:
T<dimension>()β Example:T<5>()β creates a triangle with a width and height of 5 units. - Form:
T<width, height>(),T<size = (width, height)>()β Example:T<3, 5>(),R<size = (3,5)>()β creates a triangle with a width of 3 units and a height of 5 units. yes bestie, thatRis exactly what the page says β copy it exactly and don't come for me π.
Right-angle mount π©
this one creates a cut-out suitable for bolting another panel to the side at right angles, using M3 fasteners. it's giving "I need structural support but make it cute."
- Form:
mount_cut<length>β Example:mount_cut<8>()β creates an upwards-facing mount cutout, with a depth of 8mm. - Form:
mount_cut_left<length>β Example:mount_cut_left<8>()β creates a left-facing mount cutout, with a depth of 8mm. - Form:
mount_cut_right<length>β Example:mount_cut_right<8>()β creates a right-facing mount cutout, with a depth of 8mm.
Surface β¨
surface features can only be specified within the parentheses of a geometry feature. and they're typically centered in the feature that contains them. so yeah β put them inside the geometry feature's parentheses, not just floating around like a lost AirPod.
Drill hits / holes π³οΈ
a circular drill through the panel, with metal plating like a through-hole solder joint. very "I belong here but also I'm a little industrial."
- Form:
hβ Example:hβ creates an M3 (3mm) drill hit. - Form:
hDIAMETERβ Example:h5β creates an M5 (5mm) drill hit.
the specified diameter may be a decimal. so yes, you can get precise with it. π
Metal solder points π
- Form:
mspβ Example:mspβ creates a rectangular pad with a via in it, suitable for soldering something that needs to be anchored mechanically.
TODO
Composite π§©
composite features let you position features relative to other features. it's giving "everything is connected" and honestly? obsessed. π
Columns ποΈ
positions a series of features downwards, with their vertical edges touching and justified as specified. stacked, touching, justified β the whole vibe check. β¨
column center { feature1 feature2 featureN }β likecolumn center { R<1> R<2> }. Slaps a 1x1 rectangle right on top of a 2x2 rectangle, aligned to the center. πcolumn left { feature1 feature2 featureN }β e.g.column left { R<1> R<2> }. Same deal: a 1x1 rectangle on top of a 2x2 rectangle, but aligned to the left.column right { feature1 feature2 featureN }β e.g.column right { R<1> R<2> }. A 1x1 rectangle on top of a 2x2 rectangle, aligned to the right.
TODO positioning β yeah bestie, that's literally what the page says, it's a TODO, don't come for me π
π§© Pairs, tuples
A little lineup of geometric features, laid out left-to-right with their edges touching. Think of it as your features holding hands in a row π«Ά
(feature1, feature2, ...)β example:(R<5>(), R<10>()). That positions a 5x5 rectangle to the left of a 10x10 rectangle.
π Arrays
A repetition of one single geometric or composite feature, extending out in a given cardinal direction. Iconic for when you need like, a lot of the same thing β¨
[N]featureβ example:[5]C<3.5>. That's 5 circles with a 3.5 unit radius, positioned adjacent to each other extending right.[N; U/D/L/R]featureβ example:[5; D]C<3.5>. 5 circles with a 3.5 unit radius, positioned adjacent to each other extending down.[N; U/D/L/R; v-score]featureβ example:[5; D; v-score]C<3.5>. Same as above, except an additional fabrication layer is included in the gerbers which indicates to the fab house where to v-score. πβ¨
π Wraps (edge positioning)
Okay so a wrap positions any number of features about the cardinal directions of a center feature. It's giving main character in the middle with an entourage π The basic form looks like this:
wrap (SOME_CENTER_FEATURE) with {
positioning => feature1,
positioning => feature2,
}
Every section inside those { } braces describes how one feature β the one that 'wraps' the center one β should be laid out. You write these sections like this:
okay bestie, next up is the positioning cheat sheet β every form, every example, every meaning, no skips ππ
top/bottom/left/right => featureβ example:top => R<5>,β Positions a 5x5 rectangle to the center-top of its wrapping feature, overlapping halfway.top/bottom/left/right+offset => featureβ example:top-0.5 => R<5>,β Positions a 5x5 rectangle to the top-left of its wrapping feature, overlapping halfway.top/bottom/left/right align interior => featureβ example:top align interior => R<5>,β Aligns a 5x5 rectangle to the center-top of its wrapping feature, completely contained within the feature it wraps.top/bottom/left/right align exterior => featureβ example:top align exterior => R<5>,β Positions a 5x5 rectangle to the center-top of its wrapping feature, touching edges with the feature it wraps but otherwise outside of its geometry.min/max-top/bottom/left/right => featureβ example:min-left align exterior => R<5>,β Positions a 5x5 rectangle to the left of its wrapping feature, aligned across the top.angle(ANGLE)+offset => featureβ example:angle(45)+15 => R<5>,β Positions a 5x5 rectangle 15 units away from the centeroid of its wrapping feature, at a 45 degree angle.center => featureβ example:center => R<5>,β Positions a 5x5 rectangle at the centeroid of its wrapping feature.
Putting it all together looks like this:
wrap (R<30, 10>) with {
left => C<5>,
right => C<5>,
}
That positions two circles at either end of a rectangle. π
π³οΈ Negative
A negative makes all the children features cut-outs rather than unions. So if you have a circle in a larger circle, it will produce a ring. π
negative {
C<5>
}
C<10>
β¨ Other language constructs
π§ CEL expressions
You can read the specification for the CEL language at https://github.com/google/cel-spec β that's the link the page points you to. π
You can perform simple math in maker-panel using CEL expressions. You can use CEL expressions anywhere in <> where you would specify a number, by instead writing:
!{my-CEL-expression}
For example:
C<!{2 + 4}>
You can reference any numeric variable from within your expressions. For example:
let some_number = !{4};
C<!{2 + some_number}>
That's the Reference() footer vibe β source/version and date are doing their thing down there, and we're signing off with a sparkle instead of copy-pasting the line. πβ¨π
π¦ where this page comes from
- nixos 26.05: maker-panel 0.12.4
- nixpkgs unstable: maker-panel 0.12.4
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms