Frontend app #
The main application, with the user interface and the presentation logic.
To talk with backend, it uses a custom RPC-style API: some functions in the backend are exposed through an HTTP server. When the front wants to execute a query or data mutation, it sends a HTTP request, containing the name of the function to execute, and the ascii-encoded arguments. The resulting data is also encoded and returned. This way we don't need any data type conversion, besides the transport encoding, as there is Clojure at both ends.
When the user opens any file, a persistent websocket is opened with the backend and associated to the file id. It is used to send presence events, such as connection, disconnection and mouse movements. And also to receive changes made by other users that are editing the same file, so it may be updated in real time.
Frontend structure #
Penpot frontend app code resides under frontend/src/app
path in the main repository.
▾ frontend/src/app/
▸ main/
▸ util/
▸ worker/
main.cljs
worker.cljs
main.cljs
andmain/
contain the main frontend app, written in ClojureScript language and using React framework, wrapped in rumext library.worker.cljs
andworker/
contain the web worker, to make expensive calculations in background.util/
contains many generic utilities, non dependant on the user interface.
General namespaces #
-
store contains the global state of the application. Uses an event loop paradigm, similar to Redux, with a global state object and a stream of events that modify it. Made with potok library.
-
refs has the collection of references or lenses: RX streams that you can use to subscribe to parts of the global state, and be notified when they change.
-
streams has some streams, derived from the main event stream, for keyboard and mouse events. Used mainly from the workspace viewport.
-
repo contains the functions to make calls to backend.
-
errors has functions with global error handlers, to manage exceptions or other kinds of errors in the ui or the data events, notify the user in a useful way, and allow to recover and continue working.
UI namespaces #
-
ui is the root web component. It reads the current url and mounts the needed subcomponent depending on the route.
-
auth has the web components for the login, register, password recover, etc. screens.
-
settings has the web comonents for the user profile and settings screens.
-
dashboard has the web components for the dashboard and its subsections.
-
workspace has the web components for the file workspace and its subsections.
-
viewer has the web components for the viewer and its subsections.
-
render contain special web components to render one page or one specific shape, to be used in exports.
-
export contain basic web components that display one shape or frame, to be used from exports render or else from dashboard and viewer thumbnails and other places.
-
shapes is the basic collection of web components that convert all types of shapes in the corresponding svg elements, without adding any extra function.
-
components a library of generic UI widgets, to be used as building blocks of penpot screens (text or numeric inputs, selects, forms, buttons...).
Data namespaces #
-
users has events to login and register, fetch the user profile and update it.
-
dashboard has events to fetch and modify teams, projects and files.
-
fonts has some extra events to manage uploaded fonts from dashboard.
-
workspace has a lot of events to manage the current file and do all kinds of edits and updates.
-
comments has some extra events to manage design comments.
-
viewer has events to fetch a file contents to display, and manage the interactive behavior and hand-off.
-
common has some events used from several places.
-
modal has some events to show modal popup windows.
-
messages has some events to show non-modal informative messages.
-
shortcuts has some utility functions, used in other modules to setup the keyboard shortcuts.
Worker app #
Some operations are costly to make in real time, so we leave them to be executed asynchronously in a web worker. This way they don't impact the user experience. Some of these operations are generating file thumbnails for the dashboard and maintaining some geometric indexes to speed up snap points while drawing.
-
worker contains the worker setup code and the global handler that receives requests from the main app, and process them.
-
thumbnails has a method to generate the file thumbnails used in dashboard.
-
snaps manages a distance index of shapes, and has a method to get other shapes near a given one, to be used in snaps while drawing.
-
selection manages a geometric index of shapes, with methods to get what shapes are under the cursor at a given moment, for select.
-
impl has a simple method to update all indexes in a page at once.
-
import has a method to import a whole file from an external
.penpot
archive. -
export has a method to export a whole file to an external
.penpot
archive.