Automatic layout of structured hierarchical JSON data — JavaFX and TypeScript/React.
Kramer implements the algorithm from Automatic Layout of Structured Hierarchical Reports (Bakke, InfoVis 2013). Given a schema and JSON data, it produces an adaptive layout that switches between outline and nested table views based on available width. The result is a dense, multicolumn hybrid that handles arbitrary nesting depth.
Available in both Java/JavaFX and TypeScript/React.
Requires Maven 3.3+ and Java 25+. TypeScript packages require pnpm.
# Build everything (Java + TypeScript)
mvn clean install
# Java only
mvn -pl kramer install
# TypeScript only
cd js && pnpm install && pnpm run -r test| Module | Description |
|---|---|
| kramer | Core layout engine. Schema-driven layout of JSON into JavaFX controls. |
| kramer-ql | GraphQL integration. Parses queries into Kramer schemas, executes via Jakarta RS. |
| explorer | Interactive app for exploring GraphQL endpoints with autolayout. Includes StandaloneDemo. |
| toy-app | Declarative single-page app framework using GraphQL + autolayout. |
TypeScript (js/)
| Package | Description |
|---|---|
| @kramer/core | Schema, layout pipeline, expression language, query state. Zero DOM dependency. |
| @kramer/measurement | Browser and approximate text measurement strategies. |
| @kramer/graphql | GraphQL query parsing, AST expansion, introspection. |
| @kramer/react | React renderer — AutoLayout, Table, VirtualOutline, ColumnHeader. |
| @kramer/react-ui | Interaction panels — FieldSelector, FieldInspector. |
The layout pipeline:
- Schema — a tree of
Relation(composite) andPrimitive(leaf) nodes describing the JSON structure - Measure — statistical content-width measurement (P90) determines natural column widths
- Layout decision — a constraint solver chooses table or outline mode per relation, maximizing information density while ensuring readability
- Justify — two-pass width distribution guarantees every column gets at least its label width before distributing surplus proportionally
- Compress — DP-optimal column partitioning (painter's partition) packs fields into multicolumn layouts
- Build — platform-specific control tree (JavaFX or React)
The layout is fully reactive — resizing the window re-runs the pipeline and may switch between table and outline modes at different nesting levels.
- Adaptive table/outline hybrid layout
- Constraint solver for global render-mode optimization
- Expression language for per-row filter, formula, sort, and aggregate operations
- Interactive query state (sort, filter, visibility, render mode) with undo/redo
- Context menus, field selector panel, field inspector, keyboard shortcuts
- Virtualized scrolling for large datasets
- CSS-driven styling with schema-aware class names
- Cross-language contract tests ensure Java and TypeScript produce identical layout decisions
cd explorer && mvn package
java -jar target/explorer-0.0.1-SNAPSHOT-phat.jarPoint at any GraphQL endpoint. Or run the standalone demo (no endpoint needed):
java -cp target/explorer-0.0.1-SNAPSHOT-phat.jar com.chiralbehaviors.layout.explorer.StandaloneDemocd js && pnpm install && pnpm --filter @kramer/react devOpens a browser with the course catalog demo. Resize to see table ↔ outline switching.
1300 tests total (1143 Java + 157 TypeScript), all passing.
# Run everything
mvn test
# Java only
mvn -pl kramer test
# TypeScript only
cd js && pnpm run -r test<dependency>
<groupId>com.chiralbehaviors.layout</groupId>
<artifactId>kramer</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>import { relation, primitive, measureRelation, solveConstraints } from '@kramer/core';
import { AutoLayout } from '@kramer/react';
const schema = relation('items', primitive('name'), primitive('price'));
const data = [{ name: 'Widget', price: 9.99 }];
// React component
<AutoLayout schema={schema} data={data} />Apache 2.0 — see LICENSE.
