The Cardinality Equation

Feb 23, 2026 ⋮ The Kireji Project ⋮ 7 min read
From the start, I've envisioned my web framework as one that allows me to see components represented as equations. These equations would represent components as a relationship between their subcomponents. As it happens, all ecosystem components extend directly or indirectly from the same base type, meaning that I don't have to typeset an equation for every single part. They can just inherit and override their prototype's markup.
On top of that, MathML is now widely supported across the web! This is a fairly recent development that was two and a half decades in the making (MathML 1.0 was recommended by the W3C in 1998). This means that I can typeset these equations without third-party tools.
Still, I didn't have a reliable method of looking at the entire cardinality expression of the demo app ecosystem with various levels of detail... until today. Let's dive in and explore the approach that I used.
Method
I started by equipping the base part type with a new function. This will be inherited by every part of the ecosystem. You can think of it like this:
interface IPart {
// ...
mathML(
DEPTH: number = 0,
EQUATION_TYPE: string = "none",
PARENTHESIZE: boolean = false
): string
// ...
}
With default parameters, every part provides a single variable that can represent the cardinality of its state space. When I say part.mathML(), where part represents some component of the ecosystem, I get the following string as output:
<math displaystyle=true><mrow><msub><mi>𝑘</mi><mi>part</mi></msub></mrow></math>
Your browser renders that string like this:
Every part is represented by a variable that looks more or less the same as this. It's what we get when we don't pass any arguments to part.mathML(). For example, the part that controls which note you're viewing in the notebook is represented by this variable:
The parent part of notes is sections. It controls which section of https://ejaugust.com you are on (currently, there's only notes and home) and it has a variable too. It looks like this:
The root of the entire app ecosystem has one as well, which looks like this:
These single-variable expressions don't tell us a lot. It's not until we start changing these arguments that we get to see more detail.
Parameter DEPTH
Let's try and kick up the DEPTH parameter a little bit. Here's that same notes component given four different depths:
DEPTH = 0
DEPTH = 1
DEPTH = 2
DEPTH = 3
Here is how sections.mathML(...) looks at four different depths:
DEPTH = 0
DEPTH = 1
DEPTH = 2
DEPTH = 3
And now here's the ecosystem root (via _.mathML(...)) at four different depths:
DEPTH = 0
DEPTH = 1
DEPTH = 2
DEPTH = 3
This tells us that notes and sections are each the sum of their parts and that the overall ecosystem cardinality is the product of each top-level domain's cardinality. That makes sense because mutually exclusive state spaces (like notes and sections) are accounted for using simple addition. Their combined state space is the disjoint union of their subpart state spaces. The applications in the ecosystem each have a domain name and an independent state. Independent variables are accounted for using multiplication. The ecosystem's state space is therefore the cartesian product of its individual application state spaces. The applications are grouped by their top-level domain name, so each top-level domain is also a cartesian product space.
What we're really demonstrating, however, is that the DEPTH parameter gives us control over how deeply we will traverse into a part's hierarchy in order to pull out nested MathML expressions. It's a simple approach that lets us reach in and pull out only the details we want to see.
Parameter EQUATION_TYPE
Let's take a look at that second parameter, EQUATION_TYPE. Its a string argument that switches between a simple expression ("none", the default which we've already seen) and three styles of equation ("variable", "value", and "both"). I'm not totally satisfied with this approach and I may replace this argument with a configuration object that will provide much greater control. For now, though, this method will do.
The "variable" Type
The "variable" equation type takes the expressions we've seen so far and makes them the right-hand side of a cardinality equation. The left-hand side of this equation is going to be the expression we saw before when we said DEPTH = 0. So when I say part.mathML(0, "variable"), I get the following:
If I want to render those sections expressions as simple variable equations, I'd say notes.mathML(depth, "variable"):
DEPTH = 0
DEPTH = 1
DEPTH = 2
It's a simple way go beyond the expression and say which part the expression is describing.
The "value" Type
The "value" type flips the equation a bit. It takes our DEPTH-controlled expression and makes it the left-hand side of an equation whose right-hand side is the actual cardinality of the part's state space as an integer. This integer will be in scientific notation whenever sections.mathML(depth, "value"), we'll see:
DEPTH = 0
DEPTH = 1
DEPTH = 2
When we want to depict the cardinality of the entire ecosystem as a simple equation, we can say _.mathML(0, "value"):
The "both" Type
As you may have surmised, the "both" type combines both approaches. We get to see the variable name on the left, the DEPTH-controlled expression in the middle, and the cardinality integer on the right. So sections.mathML(depth, "both") looks like:
DEPTH = 0
DEPTH = 1
DEPTH = 2
Parameter LABELS
There is also a nifty boolean parameter that enables curly brackets underneath expressions in order to clarify their origin in a larger expression. Let's look at the labels parameter in action.
_.mathML(3, "value", true)
sections.mathML(2, "none", true)
_.parts.desktop.mathML(4, "value", true)
_.app.kireji.editor.mathML(4, "value", true)
How deep can we go?
The point of this note is not just to talk about the parameters of part.mathML(...). It's to see the entire ecosystem's equation at increasing depths. part.mathML(...) accepts a DEPTH value of Infinity so it's only logical that we work our way up to the deepest depth we can...
Even Depths
Because of the way that the DEPTH parameter is handled, even-numbered depths depict cardinality expressions as simply operators and variables.
DEPTH = 0
DEPTH = 2
DEPTH = 4
DEPTH = 6
DEPTH = 8
Odd Depths
Meanwhile, odd-numbered depths depict the cardinality as sums and products of sequences.
DEPTH = 1
DEPTH = 3
DEPTH = 5
DEPTH = 7
DEPTH = 9
To Infinity!
Let's see the ecosystem cardinality expanded all the way:
Now we can add EQUATION_TYPE = "both" to make it even more verbose:
Now, let's enable LABELS = true:
Yeah, that's a big equation. Too big. I've noticed that these large labels are beyond the limit of what certain browsers (like Chrome) can render.
Better Animated?
Could animation be the secret to depicting the cardinality of the ecosystem? Press play to find out!
Ummm.... No. I don't think animation is the answer. Press on it again to make it stop.
Conclusion
Perhaps equations that expand and contract with confetti are ahead of their time. Perhaps it will never be the right time. But the part.mathML(...) method is ready today and I've already put it to good use in the Kireji Part Viewer (in each part summary, within the State Space subheading).
