LayoutKit.git · README.md
LayoutKit.git / README.md
revision 3445df4f7f5f7d987af6ab9bb095cf0dbcbb0396 · complete file
LayoutKit — Spec‑First Page and Scene Layout
Overview
- Spec‑first, deterministic layout engine: “layout as functions”.
- Inputs: `PageSpec`, `SystemSpec` and symbol/text runs in SP (staff‑space) units.
- Output: portable vector display list (`Scene`) in page coordinates (points, y‑up).
- Painting: A `Canvas` abstraction renders `Scene` to backends (SDLKit, CoreGraphics, SVG, PDF).
Clean Mapping
- LayoutKit (this package)
- What: OpenAPI 3.1 for PageSpec, Scene, Commands; Swift types; in‑process engine.
- Role: Deterministic page/scene generator; returns a portable `Scene`.
- Where: In‑process Swift (generated types optional); can also be hosted as a local service.
- SDLKit (separate, we own)
- What: Cross‑platform canvas/runtime.
- Role: Primary `Canvas` backend for LayoutKit (2D first‑class). On Linux/Windows uses SDL + FreeType + HarfBuzz; on macOS maps to CoreGraphics/CoreText.
- Delivers: On‑screen vector preview, PNG/SVG/PDF rasterization.
- ScoreKit
- What: Music model + RulesKit engraving policies (beaming, slurs, spacing).
- Role: Translator to LayoutKit requests. Produces `PageSpec`/`SystemSpec` + symbol runs (SMuFL) in SP; LayoutKit builds `Scene` in page points.
- Teatro
- Host/integrator with plugin registry, CLI, GUI preview, and snapshot culture.
- Renderer plugins call LayoutKit to obtain `Scene`, then paint via chosen backend (SVG/PDF emitters, SDLKitCanvas, CoreGraphicsCanvas).
Data Flow (Teatro in the middle)
1. ScoreKit model (+ RulesKit) → `PageSpec`/`SystemSpec` (+ symbols in SP).
2. Teatro renderer plugin → calls LayoutKit to get a `Scene` (vector display list).
3. `Scene` → painted by selected `Canvas` (SDLKitCanvas for UI; SVG/PDF emitters for artifacts; CoreGraphicsCanvas for macOS previews).
4. CLI/GUI/Apps → built on Teatro keep a consistent UX; Compare app can show ScoreKit→LayoutKit vs Lily side‑by‑side.
Conventions
- Page coords: points (pt, 72 dpi), y‑up internally. Flip only in painters that require y‑down.
- Staff coords: SP (staff‑space units). ScoreKit/RulesKit talk SP; LayoutKit converts to absolute page coords.
- Pixel snapping: `Scene` carries stroke widths; painters snap to half‑pixels for crisp lines.
- Determinism: `Scene` JSON is canonical; SVG snapshots are CI‑diffable.
Immediate Steps (scaffold)
- Spec: `openapi/layoutkit.yaml` (done). See `COORDINATES.md` for pt vs SP and transforms.
- In‑process engine: `LayoutEngine.layout(page:)` builds a minimal `Scene` (page/margins and groups).
- Canvas: `SVGCanvas` renders a `Scene` to SVG for snapshots; SDLKit/CoreGraphics backends live in their respective repos.
- Teatro integration: Add a renderer plugin that depends on LayoutKit and emits SVG/PDF/PNG using the chosen Canvas.
Getting Started
- SwiftPM
- Add to `Package.swift` dependencies: `.package(url: "https://github.com/Fountain-Coach/LayoutKit.git", branch: "main")`
- Target dependency: `.product(name: "LayoutKit", package: "LayoutKit")`
- Sample
```swift
import LayoutKit
let page = PageSpec(widthPt: 595.0, heightPt: 842.0) // A4
let scene = LayoutEngine.layout(page: page)
let canvas = SVGCanvas(width: page.widthPt, height: page.heightPt)
SceneRenderer.render(scene, on: canvas)
let svg = canvas.svgString()
```
OpenAPI Generator (Apple)
- Codegen target: `LayoutKitAPI` uses Apple's Swift OpenAPI Generator plugin.
- Document: `openapi/layoutkit.yaml` (canonical). Symlinked as `Sources/LayoutKitAPI/openapi.yaml` for the plugin.
- Config: `Sources/LayoutKitAPI/openapi-generator-config.yaml` generates public `types`, `client`, and `server` stubs.
- CI: `.github/workflows/ci.yml` builds and tests; generation runs on build and is not checked in.
Client usage (URLSession transport)
```swift
import LayoutKitAPI
import OpenAPIURLSession
let transport = URLSessionTransport()
let client = Client(serverURL: URL(string: "http://127.0.0.1:8080")!, transport: transport)
// Example call (matches /layout/page in the spec)
let page = Components.Schemas.PageSpec(widthPt: 595, heightPt: 842, margins: .init(top: 48, left: 36, right: 36, bottom: 48))
let response = try await client.post_layout_page(.init(body: .json(page)))
let scene: Components.Schemas.Scene
switch response {
case .ok(let ok): scene = try ok.ok.body.json
default: throw SomeError()
}
```
Server stubs
- `LayoutKitAPI` also includes generated server interfaces. Adopt a server transport (e.g., Vapor) in a separate package and implement the handlers by delegating to `LayoutEngine`.
Versioning
- Track breaking changes in `openapi/layoutkit.yaml` via the `info.version` field.
- Keep spec and engine in lockstep; CI ensures generator compatibility.
Teatro Wiring (outline)
- Add a new renderer plugin (e.g., `TeatroLayoutKitRenderer`) that:
- Accepts a high‑level request (e.g., `renderScorePage`).
- Calls ScoreKit to produce `PageSpec`/symbol runs.
- Calls LayoutKit to build a `Scene`.
- Paints via SDLKitCanvas (for UI) or emits SVG/PDF.
- During local development, depend on LayoutKit via a path dependency; switch to the Git URL when the repo is public.
Repository Layout
- `Sources/LayoutKit/` — Swift types, engine, and minimal SVG canvas.
- `openapi/layoutkit.yaml` — OpenAPI 3.1 for the API (future generator/service optional).
- `COORDINATES.md` — Units, transforms, snapping.
- `Tests/` — Determinism and smoke tests.
License
- Copyright (c) Fountain‑Coach.