Penpot Documentation

repository·main·Indexed 41 days ago

https://github.com/penpot/penpot-docs

User guides and technical documentation for the Penpot project, including comprehensive instructions for building, testing, and deploying Penpot plugins. Covers the Plugin API, manifest configuration, permission levels, two-way communication via postMessage, and deployment to platforms like Netlify, Cloudflare Pages, and Surge.

Tokens
31.9K
Snippets
89
Records
153
Agent score
100%

What's inside Penpot

  1. Overview of Penpot's core data model and business logic modules

    main

    The core logic of Penpot is organized into several key modules located under common/src/app/common/:

    geom

    Manages 2D geometric entities:

    • point: Defines the 2D Point type and geometric transformations.
    • matrix: Defines 2D transformation matrix types and operations.
    • shapes: Manages shapes as collections of points with bounding rectangles.

    path

    Manages SVG paths, including transformations and converting other shape types into paths.

    pages

    Contains the Penpot data model and conceptual business logic (transformations independent of UI or storage):

    • spec: Defines data structures for files and shapes using Clojure spec; includes the changes module transformations.
    • init: Defines default content for files, pages, and shapes.
    • helpers: Utility functions for manipulating data structures.
    • migrations: Manages data model evolution. It identifies file versions and applies necessary migrations to the data content.
    • changes & changes_builder: Defines transactional operations (e.g., adding a page/shape, changing attributes) that perform semantic operations on file data.

    types

    An evolving module aimed at implementing the Abstract Data Types paradigm for the Penpot model.

  2. How object buckets and deduplication work

    main

    Penpot uses buckets as internal logical groupings (not to be confused with S3 buckets). Buckets allow the storage module to apply special logic, such as custom storage paths or specific reference-checking rules.

    Deduplication (Content Hashing): To save space, Penpot shares duplicated objects. When an object is uploaded, its content is hashed. If a matching hash is found within the same bucket, the existing StorageObject is reused instead of creating a new one. This means multiple unrelated assets may share the same :object-id.

  3. Understand the structure of File data

    main

    A Penpot File contains a central data attribute that holds its core content. This content is organized into several specialized lists that are modeled as distinct entities due to their complex business logic:

    • Pages: The primary layout containers within a file.
    • Components: Reusable design elements.
    • Colors: The color palette/assets used in the file.
    • MediaItems: Embedded media assets.
    • Typographies: Font and text style assets.
  4. How team invitations are processed

    main

    Team invitations use the /auth/verify-token frontend view. The invitation link contains a token that includes the invited email address.

    When the link is followed:

    1. The token is verified.
    2. The system determines if the email belongs to an existing account or requires a new one.
    3. The :register-profile or :login services are invoked.
    4. The invitation token is attached so the resulting profile is correctly linked to the team.
  5. How Penpot uses shared code across frontend and backend

    main

    Penpot leverages a shared codebase between the frontend and backend by using the same language (Clojure/ClojureScript). To handle environment-specific differences (e.g., Clojure+Java vs. ClojureScript+JS), Penpot uses conditional compilation with the #? construct.

    When writing code that must behave differently in the backend (CLJ) versus the frontend (CLJS), use the following syntax:

    (defn ordered-set?
      [o]
      #?(:cljs (instance? lks/LinkedSet o)
         :clj (instance? LinkedSet o)))
  6. Navigate the tmux development session

    main

    The development environment uses tmux to manage multiple service windows. You can navigate between them using the prefix Ctrl+b.

    Window Mapping

    • Window 0 (gulp): Handles building and watching styles, images, fonts, and templates.
    • Window 1 (frontend): Handles shadow-cljs compilation for the frontend Clojurescript code.
    • Window 2 (exporter): Handles shadow-cljs compilation for the exporter.
    • Window 3 (backend): Runs the backend JVM process.

    Essential tmux Shortcuts

    • Ctrl+b 0 through Ctrl+b 3: Switch to a specific window.
    • Ctrl+b c: Create a new shell window.
    • Ctrl+b w: Switch between windows (window list).
    • Ctrl+b &: Kill the current window.
  7. How Pages and Components work via the Container abstraction

    main

    In Penpot, both Pages and Components share similar logic and structures, so they are both modeled as a Container entity.

    • Container: An abstraction representing either a Page or a Component.
    • ShapeTree: A hierarchical set of shapes within a Container. The top-level frame contains top-level shapes (frames or others), and these can contain nested non-frame shapes.
  8. Data Integrity and Attribute Best Practices

    main

    When modifying Penpot's data structures (e.g., adding attributes to shapes), follow these core principles to maintain integrity during file export/import and model evolution:

    • Prefer Optional Attributes: Design page and shape attributes to be optional. A feature should be activated by the presence of an attribute (e.g., if fill-color is absent, the shape is not filled).
    • Avoid null for Default States: When reverting an attribute to its default state, remove the key entirely rather than setting it to null. Many processes, including import/export, filter out null attributes. null is not considered a distinct state from the absence of the attribute.
    • Naming Conventions: Do not use special Clojure symbols in object attribute names (e.g., do not end boolean keys with ?), as this can cause issues during export.
  9. How the garbage collector handles file-media-objects

    main
    A specialized collector periodically checks file-media-objects. It verifies if a media object is still referenced by any shape or asset within its associated file. If no references exist, the media object is marked as :touched, which triggers the standard garbage collection lifecycle (marking as :deleted and eventual permanent removal from the backend and database).
  10. Understand Penpot authentication backends

    main

    Penpot supports multiple authentication methods implemented as distinct backends. A user's profile stores the initial backend used for registration (for auditing), but users can log in using other methods later if the email address matches an existing profile.

    Supported backends:

    • penpot: Internal registration using email and password.
    • ldap: Authentication via an external LDAP directory.
    • oidc, google, github, gitlab: Authentication via external services using the OpenID Connect protocol. Penpot includes a generic OIDC handler and preconfigured handlers for popular providers.