mirror of
https://github.com/penpot/penpot.git
synced 2026-07-31 18:36:18 +00:00
3.0 KiB
3.0 KiB
Library Architecture and Workflow
library/: builds @penpot/library; JS-facing in-memory Penpot file builder and .penpot ZIP exporter. Separate from main app runtime.
Layout and commands
- Source:
library/src/; tests:library/test/; experimentation/docs:playground/,docs/; config:shadow-cljs.edn,deps.edn,package.json. - From
library/: buildpnpm run build; bundle helperpnpm run build:bundleor./scripts/build; testspnpm run test; watchpnpm run watch/pnpm run watch:test; lintpnpm run lint; format check/fixpnpm run check-fmt/pnpm run fmt. - When changing file-format construction or export behavior in
common/, consider whether@penpot/libraryshould be tested because it constructs Penpot files outside the app UI. - Cross-cutting testing principles and anti-patterns:
mem:testing.
JS API and builder state
- The JS build context wraps an atom and implements
IDeref;getInternalStateexposes the CLJ state converted to JS. - Public methods decode JS objects through the JSON transformer before calling common builder functions. Exceptions become JS
BuilderErrorobjects with enumerablecauseand anexplaingetter for Malli explain data. create-build-contextcan store an optionalreferer, later written into the export manifest.- The builder is stateful: call
addFilebeforeaddPage.addPageresets the frame/group stack to the root and clears page-local naming state when the page closes. addBoardandaddGrouppush onto the parent stack; matching close calls pop it.closeGrouprequires at least one child and recalculates group geometry. Masked groups use the first child as mask and copy its geometry.commit-shapeemits:add-objwith:ignore-touched true, using the current parent, frame, and page from the stack.- Layer names are uniqued per current page; duplicate names get generated suffixes.
addBoolconverts an existing group into a bool shape and updates style/content/geometry via:mod-objoperations rather than adding a new object.- Media blobs are stored separately from file-media metadata;
add-file-mediarequires aBlobWrapper.
Export package
.penpotZIPs includemanifest.json, file/page/shape JSON, components/colors/typographies/tokens, media metadata, and media object blobs.- Path/bool shape
:contentis converted to vectors before JSON encoding. - File export intentionally includes only selected top-level attrs plus data options; color export removes
:file-idand drops empty paths. - Manifest type is
penpot/export-files, version 1, generated bypenpot-library/%version%, with optional referer and file relations. - Export generation is sequential and lazy: delayed JSON/blob work is computed only as each zip entry is written, and the progress callback receives
{total,item,path}after each entry. - The library has compatibility defaults for features/migrations in the common builder; do not assume it always exports with the newest app-default migrations/features.