Skip to Content
Lumensalis CircuitPython framework coming soon 🎉

What to Expect for Programmers

Expect the Unexpected

đźš«

If you’re already a coder, please read (at least) this first section carefully. If you haven’t done any programming, and you’re not particularly interested in learning to, this page is not for you - probably best to close this page and avoid/ignore the entire Internal Develpment section.

If (more likely when) you see something in or about the LCPF and your reaction is

  • that’s not Pythonic
  • that is so wasteful
  • that’s downright heretical
  • why can’t I just write a class to extend things
  • why do theses examples use known bad practices
  • …

please understand that - all else being equal - I probably agree with you. For an overview of my general development philosophy, check out my Software Engineering Manifesto.

However, all is not equal. The LCPF is not a traditional framework/API, and it employs some extremely opinionated architectural decisions which often prioritize design goals over traditional software development best practices. It quite intentionally makes some usually dubious choices, which I’d actually strongly discourage in most python projects.

⚠️

quick note - as of late August / early September 2025 this is still under construction. It was added to provide a FAQ-ish overview to hopefully reduce the need to keep explaining why the LCPF does things differently in conversations on developer-oriented forums, especially for the CircuitPython channels on Adafruit’s Discord server. So there may be some rough edges and missing bits, especially towards the end.

for example…

To illustrate how seriously the LCPF embraces the path less taken…

It is mostly possible1 (and actually expected) for a user to write their entire ProjectDefinition (which technically is just a CircuitPython file - potentially even in code.py) without using a single1 python reserved word (e.g. if, for, def, class, import1, builtins1, …). This is not an accident - it’s derived from a core part of the LCPF’s design philosophy, to let users use LCPF without needing to “learn programming”.

It may help to consider the “public” face of the LCPF (what users write in their project files) as a Domain Specific Language rather than Python/CircuitPython code. 2

The Primary Goal

The primary goal of the LCPF is

  • providing a way to add complex interactive light, audio, and motion effects to DIY projects (tabletop terrain, Cosplay, stage props, etc)
  • useable by people with little to no programming experience (and potentially no interest in learning about programming)

The LCPF goes to some rather extreme measures abstracting and hiding “normal” programming concepts, even to the point of being potentially unintuitive and confusing for existing developers or encouraging traditionaly “bad” practices. This is intentional, and a core part of the LCPF’s design philosophy.

It is not a traditional framework/API, and is specifically designed for non-programmers, and it prioritizes it’s design goals over tradtional approaches and “best practices”. So when choices between software development “best practices” conflict with the LCPF’s goals, the LCPF often prioritizes those goals what will (hopefully) make the most sense to non-programmers. Even when that might risk establishing bad habits for someone whose “introduction to programming” happens to be the LCPF.

I realize I’m mostly restating repetitive points all over again, but this is a fundamental aspect of the LCPF, and unless you accept it as a given it will probably be difficult to engage in much meaningful discussion regarding the LCPF. You don’t have to agree with LCPF’s design bias, but further discussion on how/why LCPF does things or digging deeper into it’s implementation and design philosophy without accepting - at least for the sake of argument - this fundamental priority is unlikely to be productive.

What the LCPF is and is not - a developer’s perspective

Now that that’s out of the way, if you haven’t run off to grab the pitchforks yet, we can begin a high level overview of what the LCPF is and isn’t from a developer’s perspective.

Overall Design Goals

There is an older but still relevant document detailing some of the original goals of the LCPF document.

No (direct) knowledge of Python required

While an LCPF ProjectDefinition is technically still just a CircuitPython file, the intent is that (other than the boilerpate first and last lines1 ), a typical project can be fully defined with zero knowledge or even (direct) use/awareness of

  • any python reserved words
    • no if, def, class, import[1], etc
    • no builtins
  • modules used internally by LCPF
    • including all the modules of the LCPF itself
    • including all the LCPF dependencies from
      • CircuitPython standard modules
      • addtional drivers, etc from (primarily) the Adafruit CircuitPython bundle

Minimizing hardware details

Many people who are intimidated by the thought of writing code are also likely to see picking up a soldering iron or cross referencing documentation for various bits of embedded kit to map between logical and physical assignments as something they’d rather avoid.

The LCPF employs several measures to reduce the number of hardware specific details (especially things like pin assignments and I2C addresses) in a ProjectDefinition. This is partly achieved by heavily leveraging ShieldStandards like the D1Mini and Adafruit Feather form factors, and standardized cable systems for addon Devices like StemmaQTQwiic. More details in the Hiding Details section.

Influences

It is highly influenced by concepts from low /no  code development. It still requires “writing code”, but

  • that code is (hopefully) easy to understand and modify
  • most projects will simply start by copying and modifying an existing example
  • it’s plausible that the majority of projects will be less than 100 lines of “code”
  • there probably will be a “visual” quick start tool at some point - likely based on blockly. However, there are some limitations to this approach which means that it will never be the only way - and probably won’t even be the recommended way - to build LCPF project configurations.

It is also based on declarative programming  principles.

It’s designed to be as simple as possible for non-programmers to use to define what they want to happen, without needing to say how to make it happen.

While it uses many patterns you’d likely recognize under the hoods, the “API” as such is provided in a very non-traditional manner. The LCPF is NOT a

although it may (and in practice does) incorporate or take inspiration from these internally

Keeping it simple

There are numerous ways in which the LCPF attempts to keep things simple and provide a “beginner friendly” environment.

Declarative programming patterns

The declarative aspect is fundamental - letting users specify what they want to happen instead of coding the control flow and logic necessary to make it happen.

As such, while the LCPF seeks to dramatically reduce the need for users to learn traditional programming concepts and (mostly) syntax, it does require learning the vocabulary provided to define projects.
The vocabulary is designed to be intuitive for non-programmers, as such some terms may be used in ways contrary to what someone with programming experience might expect.

One Rule to Bind Them

Once again, the LCPF’s primary goal of enabling non-programmers to create complex projects with minimal coding knowledge takes precedence over all other considerations, including

This doesn’t mean other goals aren’t important - the LCPF does quite a bit internally to optimize performance and effeciency (especially regarding temporary allocations and the garbage collection system). But wherever a choice has to be made, there is an overwhelming bias towards keeping things simple.

This also doesn’t mean that the LCPF is a “dumbed down” in any way - it’s based on patterns developed over decades from experience in some very complex systems (from algorithmic trading to machine control and robotics). However, it probably won’t look or feel like anything you’ve seen before.

Footnotes

  1. Techinically this is mostly true. True, False, and occasionally None, might sneak their way in, but that’s been rare so far. The first (from LumensalisCP.Simple import *) and last (main.launchProject(globals())) lines cheat, but those are boilerplate the user simply copies in and never changes which sets up the environment in which the project can be defined. ↩ ↩2 ↩3 ↩4 ↩5

  2. I’ve used DSLs in the past, and a simple DSL front end could actually work well for the LCPF. The main reasons I haven’t pursued this is that implementing it as pure python on top of the Python grammar/parser was obviously quicker, and (more importantly) modern python editors have excellent support for code completion and (given thorough annotations and type hints) indicating suspicous / incorect type and method/funtion parameter usage. This can eliminate a lot of frustration for beginners (and pros for that matter) ↩

Last updated on