Complexity Library is a deterministic-first complexity analysis application: developers paste a Python, JavaScript, or TypeScript function, and the app returns a typed growth claim, confidence, limitations, and an interactive visualization. The interesting part is not that it says “O(n log n)”; it is that the result is bounded, inspectable, and useful without executing user code or asking a model to improvise an answer.
The problem
Most complexity explanations live in one of two uncomfortable places: static articles that cannot inspect your code, or assistant chats that can produce a plausible explanation without a reliable evidence chain. This project treats code analysis as a product surface in its own right.
The design premise is simple:
Parse the submitted artifact, derive deterministic facts, make a conservative claim, and render a trace from validated data.
That principle governs API design, data modelling, and the UI.
System shape
The web app is a Next.js 16/React 19 interface. FastAPI owns analysis, sessions, request guards, SSE, and persistence decisions. The shared visualization contract is deliberately small and versioned so a renderer consumes data, not dynamically authored UI logic.
Static analysis, not execution
For Python, the project uses the standard-library ast module. JavaScript and TypeScript use tree-sitter. The engine records facts before it makes a complexity claim: loop depth, halving behavior, sort operations, binary-search conventions, recursion, allocations, branches, and known calls.
def find(items, target):
low, high = 0, len(items) - 1
while low <= high:
mid = (low + high) // 2
if items[mid] == target:
return mid
if items[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1
The analyzer sees a loop that repeatedly narrows low/high bounds around a midpoint. That maps to a documented binary-search rule, producing an O(log n) claim with high confidence and O(1) auxiliary space.
The implementation then returns a Pydantic model rather than free-form prose:
class ComplexityAnalysis(BaseModel):
time_complexity: TimeComplexity
space_complexity: SpaceComplexity
confidence: float = Field(ge=0, le=1)
pattern: AlgorithmPattern
reasoning: str
assumptions: list[str]
limitations: list[str]
signature: ComplexitySignature
That distinction is important. A consumer can render confidence and limitations safely, persist a reproducible result, or reject unknown enum values without parsing natural language.
Conservative rules beat invented certainty
The engine knows a practical initial set: simple work, linear scans, halving loops, nested loops, sorting, binary search, two-pointer and sliding-window shapes, and direct recursive patterns. It does not pretend to solve arbitrary program analysis.
When it sees an unresolved call, it lowers confidence and reports a limitation. When it sees submitted source, it never executes it. Those two decisions make the application more trustworthy than a system that is always fluent.
The test suite covers all headline growth classes—from O(1) through O(n!)—and checks exact analysis fields rather than merely snapshotting a paragraph.
cd apps/api
uv run pytest
Visualization is a data contract
The next design decision is easy to miss: visualizations are not screenshots or generated canvas code. The API builds a constrained VisualizationSpec with a template type, bounded steps, annotations, accessible summary, and input controls.
{
"schema_version": 1,
"type": "logarithmic_halving",
"input_size": 16,
"operation_estimate": 4,
"accessible_summary": "The search space halves from 16 until one item remains."
}
The UI can animate, step, reset, and summarize that data locally. It does not need to ask the backend for each frame, and it never treats model output as executable component code.
Anonymous by default
The first use of the product should not require an account. The API issues an opaque HttpOnly anonymous-session cookie and scopes processing-status/SSE access to that session. Local development uses in-memory repositories; production can opt into Supabase for durable sessions and function records.
Before analysis, the service checks a honeypot field, declared request-body size, schema limits, and a process-local sliding-window rate limit. These are intentionally deterministic safeguards. Redis-backed quotas, queues, and further abuse signals are part of the public roadmap.
Why use SSE?
The browser requests an asynchronous analysis job, then connects to a server-sent-events endpoint. The UI maps actual API stage names—parsing, syntax facts, loop/recursion detection, complexity decision, visualization construction—to visible progress.
const events = new EventSource(`${apiUrl}${payload.events_url}`, {
withCredentials: true,
});
events.addEventListener("completed", (message) => {
setResult(JSON.parse(message.data));
events.close();
});
For the local MVP, jobs are in-process. Durable queues and reconnect semantics are open OSS issues rather than hidden behind a claim of production readiness.
The UI: a learning instrument, not a dashboard
The web design uses a graph-paper-like ground, a compact trace palette, editorial display type, and monospace data labels. That visual direction is not ornamental: the grid supplies scale to growth traces, while blue/coral/moss distinguish operation states and results.
The workbench gives the user one clear job—provide a function and inspect its dominant work. Playback has native buttons, visible focus, accessible textual summaries, and reduced-motion-aware behavior. The learn route extends the same visual language into ten input-driven lessons, not static articles.
Running the project
# Install the web workspace
pnpm install
# Run the API
cd apps/api
uv sync --extra dev
uv run uvicorn app.main:app --reload --port 8000
# In another terminal, from the repository root
pnpm dev:web
The project runs locally without LLM, Supabase, or Redis credentials. Supabase migrations and a deterministic curated seed command are available when durable mode is needed.
What contributors can build next
The most useful next contributions are not cosmetic. They are correctness and product-depth work:
- Explicit selection when a submitted file contains multiple functions.
- Better local call-graph and auxiliary-space analysis.
- Cursor pagination, PostgreSQL full-text search, and unified discovery across functions, algorithms, lessons, and tags.
- More bounded visualization templates: sorting, graph traversal, cubic, exponential, and factorial growth.
- Durable queue/reconnect handling, Redis quotas, Supabase migration rehearsal, and E2E/a11y/performance tests.
- A strictly constrained, provider-neutral fallback for genuinely ambiguous analysis—without weakening deterministic precedence.
All remaining work is broken into labeled public issues. The repository is a good fit for contributors who care about developer tools, static analysis, accessible data visualization, or safe AI-adjacent systems.
Complexity Library is a small argument for a different kind of developer-learning product: one where the output is not a confident answer but an inspectable artifact. The parser tells us what it saw. The rules explain the claim. The trace makes the growth visible. And where the system is uncertain, it says so.
That is a much better foundation for learning how software scales.
Code & more: https://www.dailybuild.xyz/project/218-complexity-library

Top comments (0)