Open-Source Meets Design Tooling With Penpot — Smashing Magazine
This article is a sponsored by [Penpot](https://penpot.app/?utm%5Fsource=Article&utm%5Fmedium=SmashingMag&utm%5Fid=Penpot2.0)
Penpot is a free, open-source design tool that allows true collaboration between designers and developers. Designers can create interactive prototypes and design systems at scale, while developers enjoy ready-to-use code and make their workflow easy and fast because it's built with web technologies, works in the browser, and has already passed [33K starts on GitHub](https://github.com/penpot/penpot).
The UI feels intuitive and makes it easy to get things done, even for someone who’s not a designer (guilty as charged!). You can get things done in the same way and with the same quality as with other more popular and closed-source tools like Figma.

Why Open-Source Is Important
As someone who works with commercial open-source on my day-to-day, I strongly believe in it as a way to be closer to your users and unlock the next level of delivery. Being open-source creates a whole new level of accountability and flexibility for a tool.
Developers are a different breed of user. When we hit a quirk or a gap in the UX, our first instinct is to play detective and figure out why that pattern stuck out as a sore thumb to what we’ve been doing. When the code is open-source, it’s not unusual for us to jump into the source and create an issue with a proposal on how to solve it already. At least, that’s the dream.
On top of that, being open-source allows you and your team to **self-host**, giving you that extra layer of privacy and control, or at least a more cost-effective solution if you have the time and skills to DYI it all.
When the cards are played right, and the team is able to afford the long-term benefits, commercial open-source is a win-win strategy.
Introducing: Penpot Plugin System
Talking about the extensibility of open-source, Penpot has the [PenpotHub](https://penpot.app/penpothub?utm%5Fsource=SmashingMag&utm%5Fmedium=Article&utm%5Fcampaign=PluginsContest) the home for open-source **templates** and the newly released **plugin** gallery. So now, if there’s a functionality missing, you don’t need to jump into the code-base straightaway — you can create a plugin to achieve what you need. And you can even serve it from localhost!
### Creating Penpot Plugins
When it comes to the plugins, creating one is extremely ergonomic. First, there are already set [templates](https://penpot.app/penpothub/libraries-templates?utm%5Fsource=SmashingMag&utm%5Fmedium=Article&utm%5Fcampaign=PluginsContest) for a few frameworks, and I created one for [SolidJS in this PR](https://github.com/penpot/plugin-examples/pull/2) — the power of open-source!
When using [Vite](https://vite.dev/), plugins are Single-Page Applications; if you have ever built a Hello World app with Vite, you have what it takes to create a plugin. On top of that, the Penpot team has a few packages that can give you a headstart in the process:
```
npm install @penpot/plugin-styles
```
That will allow you to import with a CSS loader or a CSS import from `@penpot/plugin-styles/styles.css`. The JavaScript API is available through the window object, but if your plugin is in TypeScript, you need to teach it:
```
npm add -D @penpot/plugin-types
```
With those types in your `node_modules`, you can pop-up the `tsconfig.json` and add the `types` to the `compilerOptions`.
```
{
"compilerOptions": {
"types": ["@penpot/plugin-types"]
}
}
```
And there you are, now, the Language Service Provider in your editor and the TypeScript Compiler will accept that penpot is a valid namespace, and you’ll have auto-completion for the Penpot APIs throughout your entire project. For example, defining your plugin will look like the following:
```
penpot.ui.open("Your Plugin Name", "", {
width: 500,
height: 600
})
```
The last step is to define a plugin manifest in a `manifest.json` file and make sure it’s in the outpot directory from Vite. The manifest will indicate where each asset is and what permissions your plugin requires to work:
```
{
"name": "Your Plugin Name",
"description": "A Super plugin that will win Penpot Plugin Contest",
"code": "/plugin.js",
"icon": "/icon.png",
"permissions": [
"content:read",
"content:write",
"library:read",
"library:write",
"user:read",
"comment:read",
"comment:write",
"allow:downloads"
]
}
```
Once the initial setup is done, the communication between the Penpot API and the plugin interface is done with a bidirectional messaging system, not so different than what you’d do with a Web-Worker.
So, to send a message from your plugin to the Penpot API, you can do the following:
```
penpot.ui.sendMessage("Hello from my Plugin");
```
And to receive it back, you need to add an event listener to the `window` object (the top-level scope) of your plugin:
```
window.addEventListener("message", event => {
console.log("Received from Pendpot::: ", event.data);
})
```
**A quick performance tip**: _If you’re creating a more complex plugin with different views and perhaps even routes, you need to have a cleanup logic. Most frameworks provide decent ergonomics to do that; for example, React does it via their return statements._
```
useEffect(() => {
function handleMessage(e) {
console.log("Received from Pendpot::: ", event.data);
}
window.addEventListener('message', handleMessage);
return () => window.removeEventListener('message', handleMessage);
}, []);
```
And Solid has `onMount` and `onCleanup` helpers for it:
```
onMount(() => {
function handleMessage(e) {
console.log("Received from Penpot::: ", event.data);
}
window.addEventListener('message', handleMessage);
})
onCleanup(() => {
window.removeEventListener('message', handleMessage);
})
```
Or with the [@solid-primitive/event-listener](https://primitives.solidjs.community/package/event-listener#createeventlistener) helper library, so it will be automatically disposed:
```
import { makeEventListener } from "@solid-primitives/event-listener";
function Component() {
const clear = makeEventListener(window, "message", handleMessage);
// ...
return (Hello!)
}
```
In the official documentation, there’s a [step-by-step guide](https://help.penpot.app/plugins/create-a-plugin?utm%5Fsource=SmashingMag&utm%5Fmedium=Article&utm%5Fcampaign=PluginsContest) that will walk you through the process of creating, testing, and publishing your plugin. It will even help you out.
So, what are you waiting for?
Plugin Contest: Imagine, Build, Win
Well, maybe you’re waiting for a push of motivation. The [Penpot](https://penpot.app/?utm%5Fsource=SmashingMag&utm%5Fmedium=Article&utm%5Fcampaign=PluginsContest) team thought of that, which is why they’re starting a [Plugin Contest](https://penpot.app/plugins-contest?utm%5Fsource=SmashingMag&utm%5Fmedium=Article&utm%5Fcampaign=PluginsContest)!

For this contest, they want a fully functional plugin; it must be open-source and include comprehensive documentation. Detailing its features, installation, and usage. The first prize is US$ 1000, and the criteria are innovation, functionality, usability, performance, and code quality. The contest will run from November 15th to December 15th.
Final Thoughts
If you decide to build a plugin, I’d love to know what you’re building and what stack you chose. Please let me know in the comments below or on [BlueSky](https://atila.io/bsky)!
https://smashingmagazine.com/2024/11/open-source-meets-design-tooling-penpot/