Just some plugins that have been of use lately.
- General
- Development of plugins
- Posted in figma figma-plugins
Just some plugins that have been of use lately.
- Posted in development figma figma-plugins
In the previous tutorial, we ended with 2 rectangles.
The second building block that’s good to learn about is rendering text to the canvas.
Working with text is its own challenge in Figma, because there are a lot of edge cases.
The first thing to understand is that a font needs to be loaded in order for text to be able to render. Fortunately, there is a font that we always know will be there, which is Inter, used by Figma for its UI itself.
So for the sake of the simplicity of this tutorial, let’s start using Inter to render text. Later we can move to a more difficult use case.
If you are starting out, you don’t need to have followed the previous tutorial to do this one. You can start this one from scratch.
We will once again use the Figlet plugin, which makes it so you don’t have to set up a development environment and you can start coding right away.
If you don’t have one already, make a new Figlet account inside the Figlet plugin.
Now, create a new Figma design file, run Figlet, and click the new Figlet button (the + button)
Now you have some code to write! The second building block we will look at is creating text.
Write the following code:
const text = figma.createText()
figma.loadFontAsync(text.fontName).then(() => {
text.characters = 'Hello world'
})
Now log the constant to the console
console.log(text)
There’s a lot of properties there (76 to be exact!).
Let’s examine some of the properties in there that have to do with text styles:
characters: "Hello world"
fontName: {
family: "Inter",
style: "Regular"
},
fontSize: 12,
Let’s try to make the font size a more decent 16px. Add this to your code:
const text = figma.createText()
figma.loadFontAsync(text.fontName).then(() => {
text.characters = 'Hello world'
text.fontSize = 16
})
console.log(text)
Now let’s try to make it bold.
You might be tempted to do something like…
text.characters = 'Hello world'
text.fontSize = 16
text.fontName = { family: "Inter", style: "Bold" }
const text = figma.createText()
However, like we noted before, this will not work, because font is not loaded yet (even though it’s available in Figma).
If you load the font asynchronously, like such:
const text = figma.createText()
figma.loadFontAsync({ family: "Inter", style: "Bold" }).then(() => {
text.characters = 'Hello world'
text.fontSize = 16
text.fontName = { family: "Inter", style: "Bold" }
})
…the code will run. But what if we want to load multiple fonts?
You can use the Promise.all
Javascript method:
async function loadFonts() {
await Promise.all([
figma.loadFontAsync({
family: "Inter",
style: "Regular"
}),
figma.loadFontAsync({
family: "Inter",
style: "Bold"
}),
figma.loadFontAsync({
family: "Inter",
style: "Medium"
})
])
}
loadFonts().then(() => {
const text = figma.createText()
text.characters = 'Hello world'
text.fontSize = 16
text.fontName = { family: "Inter", style: "Medium" }
const text2 = figma.createText()
text2.characters = 'Hello world'
text2.fontSize = 16
text2.fontName = { family: "Inter", style: "Bold" }
text2.y += 20
});
This should result in this:
Notice how I also used the y
part to set the y position of the 2nd text variable.
Let’s see what else we can do with text.
Let’s add a bit more text:
// Make sure the loadFonts from previous example exists
loadFonts().then(() => {
const text = figma.createText()
text.characters = 'Hello world'
text.fontSize = 16
text.fontName = { family: "Inter", style: "Medium" }
const text2 = figma.createText()
text2.characters = 'Hello world'
text2.fontSize = 16
text2.fontName = { family: "Inter", style: "Bold" }
text2.y += 20
const body = figma.createText()
body.characters = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
body.fontSize = 14
body.fontName = { family: "Inter", style: "Regular" }
body.y += 40
});
When you render this, you will see that is unseemingly wide – 2895 pixels to be exact.
Let’s make it a bit more manageable.
Add this code to the body variable and its subsequent manipulations:
body.resize(400,1)
body.textAutoResize = 'HEIGHT'
That looks a bit better.
Now, let’s try to create another style for links. This will involve working an “underline” text decoration, and a color fill.
First set up a basic style:
const link = figma.createText()
link.characters = 'My link'
link.fontSize = 14
link.fontName = { family: "Inter", style: "Regular" }
link.y += 180
Don’t worry about the “manual” y
positionings for now, we will learn about positioning things later.
We’ll need the text decoration, add this line:
link.textDecoration = "UNDERLINE"
Now, let’s do the colors.
If you remember from our previous tutorial, we need a clone function:
function clone(val) {
return JSON.parse(JSON.stringify(val))
}
Add this function to the top level of your code (for example on line 18 if you’ve been following along in an exact manner)
Now add similar code as in the previous tutorial:
const linkFills = clone(link.fills)
const rgbColor = [65,111,181]
linkFills[0].color.r = rgbColor[0]/255
linkFills[0].color.g = rgbColor[1]/255
linkFills[0].color.b = rgbColor[2]/255
link.fills = linkFills
This code is a bit annoying, so let’s extract it into a function.
// Usage: setColor(node, [65,111,181])
function setColor(node, rgbColor) {
const fills = clone(node.fills)
fills[0].color.r = rgbColor[0]/255
fills[0].color.g = rgbColor[1]/255
fills[0].color.b = rgbColor[2]/255
node.fills = fills
}
Once again, place it outside of your loadFonts().then(() => {
block.
Now we have a reusable setColor
function to set colors, where we select the node as the first parameter and an array of RGB colours as the second parameter.
The full code for our link:
const link = figma.createText()
link.characters = 'My link'
link.fontSize = 14
link.fontName = { family: "Inter", style: "Regular" }
link.y += 180
link.textDecoration = "UNDERLINE"
setColor(link, [65,111,181])
Let’s modify our existing code a little bit, to assume we are making a typographical system. Try doing the following:
Your complete text code would look a bit like this:
const text = figma.createText()
text.characters = 'Heading 1'
text.fontSize = 32
text.fontName = { family: "Inter", style: "Bold" }
const text2 = figma.createText()
text2.characters = 'Heading'
text2.fontSize = 24
text2.fontName = { family: "Inter", style: "Medium" }
text2.y += 42
const body = figma.createText()
body.characters = 'Body - Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
body.fontSize = 14
body.fontName = { family: "Inter", style: "Regular" }
body.y += 76
body.resize(400,1)
body.textAutoResize = 'HEIGHT'
const link = figma.createText()
link.characters = 'My link'
link.fontSize = 14
link.fontName = { family: "Inter", style: "Regular" }
link.y += 220
link.textDecoration = "UNDERLINE"
setColor(link, [65,111,181])
And that code would render an example like this:
That’s where we will stop for now. The final code can be found here.
If you followed along with both tutorials, you now have a basic understanding of creating a shape, and how to render text in a Figma plugin.
I don’t know yet what the next tutorial will be about, but I want to find a logical next step to code, to get to a useful plugin. If you have any suggestions. place a comment below, it will motivate me to continue this series.
- Posted in development figma figma-plugins
In this blog post series I would like to give an introduction to building Figma plugins.
We will be learning using a series of “building blocks” and then turn it into a real plugin in the end. In this first tutorial we will be looking at the most basic of basics: creating a rectangle.
We will make our start using the Figlet plugin, which makes it so you don’t have to set up a development environment and you can start coding right away.
Figlet is a new thing in the Figma plugins community. It’s comparable to Codepen or REPL-like environments in the sense that you can share Figlets, you can easily run them without setting up a dev environment, and you can easily have multiple figlets.
Make a new Figlet account inside the Figlet plugin.
Now, create a new Figma design file, run Figlet, and click the new Figlet button.
Now you have some code to write! The first building block we will look at is creating a rectangle.
Enter and run the following code:
figma.createRectangle();
You will see a rectangle created on your artboard.
But where is it? If you can’t see it, try to find your new layer called Rectangle
in the layer panel.
Zoom in to the rectangle (manually) and let’s continue.
Let’s give the rectangle a colour.
This is a good time to learn about nodes first.
Instead of directly running figma.createRectangle()
, assign your rectangle to a variable, and log its contents.
const rect = figma.createRectangle()
console.log(rect)
Now, open the developer console using ⌥ + ⌘ + I (Mac) or Ctrl + Alt + I (Windows/Linux).
You will see the output of an object like this in the developer console.
What we are looking for to change the color is the fills object:
At this point, you might be tempted to just directly change the values using some code like:
const rect = figma.createRectangle()
const color = rect.fills[0].color
color.r = 0.5
color.g = 0.5
color.b = 0.5
This does not work!
You can’t directly manipulate certain objects, you have to clone them in their entirety, then manipulate them, and put back the cloned version.
You can do so using code like this:
function clone(val) {
return JSON.parse(JSON.stringify(val))
}
const rect = figma.createRectangle()
const fills = clone(rect.fills)
fills[0].color.r = 0.75
fills[0].color.g = 0.35
fills[0].color.b = 0.75
rect.fills = fills
(If you are curious, check out the API reference on editing properties here.)
If you run this code, you should see a rectangle on your canvas:
Okay… that was a bit more complicated than you would think. Let’s move on and try to move the rectangle around a bit. Maybe make some more rectangles.
First, let’s resize the rectangle so we have some x/y coordinates to refer to.
Fortunately this is much easier:
rect.resize(50,50)
Now let’s create a function out of creating our rectangle. Move the code into a function and run it.
function clone(val) {
return JSON.parse(JSON.stringify(val))
}
function createMyRectangle(rgbColor, width, height) {
const rect = figma.createRectangle()
const fills = clone(rect.fills)
fills[0].color.r = rgbColor[0]/255
fills[0].color.g = rgbColor[1]/255
fills[0].color.b = rgbColor[2]/255
rect.fills = fills
rect.resize(width,height)
}
createMyRectangle([255,125,250], 50, 50)
Let’s also add an X/Y position parameter.
function clone(val) {
return JSON.parse(JSON.stringify(val))
}
function createMyRectangle(rgbColor, width, height, x, y) {
const rect = figma.createRectangle()
const fills = clone(rect.fills)
fills[0].color.r = rgbColor[0]/255
fills[0].color.g = rgbColor[1]/255
fills[0].color.b = rgbColor[2]/255
rect.fills = fills
rect.resize(width,height)
rect.x = x
rect.y = y
}
createMyRectangle([255,125,250], 50, 50, 0, 0 )
createMyRectangle([125,110,250], 50, 50, 0, 50 )
There we have it. A way to create rectangles.
This is a basic building block for the future of our code – and it also concludes our first tutorial.
In the next tutorial we will render some text.
If you are enthusiastic about this tutorial series, place a comment below, it will motivate me to continue!
The first thing I am building in my bootstrapping journey is a Figma plugin to turn a screenshot into an editable layout. You have a Figma plugin:
Imagine you take this screenshot:
And then when you process your image, you get this editable layout:
This way, as a designer, if somebody hands you something to improve, you have a starting point with the exact copy and you can have a starting point to continue from.
This is a situation that I encounter a lot, so I am kind of solving my own itch here. But I figure it will be useful for others.
If this, or my previous blog post sounds at all interesting and you’d like to discuss things – shoot me an e-mail: letsbootstrap@johanronsse.be .
- Posted in bootstrap
I am starting something on the side, with the goal of bootstrapping a side business. The idea is to
In the past I’ve worked on small products like Kana Master and Keynote Extractor. It’s been a few years since I built and launched a product, and I feel energized to do it now.
What do I want to achieve? Chatting to another fellow indie hacker, the definition of “success” can vary wildly. Having a steady ARR that brings in some cash while having low maintenance can be interesting. For sure something could grow into something bigger. You can’t predict the future but you can get started building and learning and seeing which turns things will take, based on your actions.
One problem I always have is that I am not a backend developer. Over the past few years I’ve added more front-end knowledge to my skillset (e.g. React, Typescript, mostly out of necessity, and Svelte – out of interest). I can build out fully-fledged reactive user interfaces with a solid design, but when it comes to databases and to APIs I am pretty poor.
If any of this sounds at all interesting and you’d like to discuss it – shoot me an e-mail: letsbootstrap@johanronsse.be .
- Posted in inspiration
Joe Chesky, AirBnB CEO makes an observation on why designers never run companies in his sit-down with Figma CEO Dylan Field titled “Leading through uncertainty”:
“…I think because design, in some ways, is fragile. Companies are organized around a scientific method. And the creative process is something that requires nerve. And over the years, I started losing my nerve. I brought in a lot of people from a lot of different companies and they brought their way of working towards us. So what do we do? We basically divisionalize. We had like 10 different divisions, with 10 different subdivisions. We were very much ran by product managers. We had a plethora of A-B experiments. And the thing I started noticing is, the more people we added, the more projects we pursued, the less our app changed, and the more the cost went up. And I didn’t know what to do?”
- Posted in blijvend-leren conference css professioneel webdev
This week I went to the CSS day conference.
It had been 5 years since I had joined CSS day (with no editions in 2020 & 2021), and I was glad to once again visit Amsterdam for an excellently organized two days of talks about CSS.
The conference kicked off with Una Kravets from the Google developer relations team talking about all the new features in CSS. There’s been a lot of evolution over the past few years. If you remember, 2015 was kind of a “banner year” for CSS with a lot going on in terms of grid and flexbox. The last few years there’s been an interesting dynamic, where browser vendors have come together to work on features in an interoperable fashion.
Throughout the conference there were many talks about new features, including container queries, scroll-driven animations, trigonometry functions, new color spaces… as well as the results of some of the efforts of the Open UI working group like selectmenu
(a customizable select) and the popover
element.
I took a lot of notes in the container queries talk, and during Bramus‘s talk section about scroll-driven animations I could not help myself to make a codepen to try out the newest features (warning: Chrome Canary with the right feature flags only). I am especially excited about container queries landing in browsers. For me that’s been the missing part of responsive web design.
A conference is not only about the talks of course, and I was happy to meet some new people, talk to some old CSS friends. Where else can you discuss selector complexity and the need for abstractions like CSS modules and have the other side of the table understand what you are saying?
I especially want to thank the organisers Krijn and PPK, and the team behind the conference. It could not have been smoother and better organized. Props to them.
After a few months of using Mastodon, and a few weeks of sometimes launching Bluesky and being confused, I have thoughts. Like many people, I was fed up with Twitter at some point and decided to look elsewhere.
My Mastodon profile is here and my Bluesky profile is here.
The default Mastodon web experience is not the best… I tried to migitate that by using different clients. Elk is a bit better on web. Ice cubes for iOS is OK, but it seems to have a lot of ghost notifications. I get a push notification, and then my list is empty. I haven’t found a client I really love.
DM’ing on Mastodon is quite different than on Twitter. A DM is a “private mention”, it shows up right on your feed in the same place as other messages.
When you DM, you are essentially sending a messsaging to mentioned people only. But UI-wise, it’s quite unclear what is what.
DM’ing on Twitter was a big deal for me to ask questions to my network or have small private conversations. DM’ing on Mastodon so far doesn’t feel right.
Activity on Mastodon is quite low so I see the same over-active people writing their things. I do only follow 1/5 of the amount of people as I do on Twitter so the answer is probably there… but I still have the impression that people just – use it less than Twitter?
In a way I prefer an algorithm there to make noisy people less noisy, while still following them. But if I look at the “For you” tab on Twitter, it’s full of poor content (very comparable to LinkedIn has been for years) – making me appreciate a non-algorhitmic feed. You can’t have it both ways I guess.
After many years of Twittering I have consistently been hovering around following 600-ish people. At one point, this gave me a steady stream of news and opinions, while still being managable to read. But I think things have gone downhill lately.
There is also Bluesky, which is so new that I can’t say much.
First I was confused by the look and feel of it. Some parts look so unprofessional that I wondered if they are even genuine. The marketing website doesn’t style their links and looks very bare bones. The iOS login screen looks like it was put together in a minute, in such a way that I first thought I was dealing with a scam app.
The few times I’ve tried it, it’s been a weird experience. Almost no one I know is on there and I got followed by 30+ people who I don’t even know. For now, it’s not engaging at all, so I just quit the app a few minutes after I start using it.
Today, in the process of writing this blog post, I tried to add my own domain as a username (a feature of the AT protocol) but it did not work.
The concept of verifying your identity using a domain you own is interesting. Essentially if you have access to the keys of a domain (by being able to set DNS records) that is enough of an identity verification, and that sounds pretty legit to me.
I thought it was funny when somebody registered themselves to the Github CDN or standard S3 bucket urls.
All of the above is leading me to mix my Twitter and Mastodon usage. I guess I wil occassionally launch Bluesky to see how it evolves.
At one point I thought we (we, as in the communities I follow) would all quit Twitter and move over to Mastodon.
But that’s not the case at all.
Anyway, some thoughts. Over and out.
- Posted in development storybook ui webdev
I recently started switching a Storybook that was based on the MDX format to the Component Story Format 3.0 format, skipping the 2.0 entirely… so some things were not that clear to me. I’m documenting them here for the reference of myself and others. Thse examples work in Storybook 6.5, and I believe also in 7.0 since the team worked on full backwards compatibility.
You can pass storyName
below an exported story to give it another name:
export const HeadingWithSpacingExamples = () => (
<>
<Heading variant="h1" spacing>
h1
</Heading>
<Heading variant="h2" spacing>
h2
</Heading>
<Heading variant="h3" spacing>
h3
</Heading>
<Heading variant="h4" spacing>
h4
</Heading>
</>
);
HeadingWithSpacingExamples.storyName = 'With spacing';
You can add a description to a component using parameters.docs.description.story
:
export const HeadingExamples = () => (
<>
<Heading variant="h1">h1</Heading>
<Heading variant="h2">h2</Heading>
<Heading variant="h3">h3</Heading>
<Heading variant="h4">h4</Heading>
</>
);
HeadingExamples.parameters = {
docs: {
description: {
story: 'The component doesn’t have built-in spacing by default.',
},
},
};
You can add a description to a (top level) component itself by passing parameters.docs.description.component
:
export default {
title: 'Typography/Heading',
component: Heading,
args: {
variant: 'h1',
children: 'Heading',
},
parameters: {
docs: {
description: {
component: 'The header component.',
},
},
},
};
This is a bit wieldy, so in the newest Storybook, 7.0, you apparently you can do that with JSDoc:
/**
* @description My description
*/
I’ve yet to test that.
- Posted in lifelog mexico persoonlijk reflectie
Een update na 2,5 maand. Zoals ik in mijn vorige post rapporteerde wordt ik het hier wel wat gewoon.
Het appartment krijgt meubel-gewijs vorm. Het opstaan op een ontieglijk uur lukt wonderwel – en dat voor een avondmens.
Qua werk neigt het meer naar front-end dezer dagen. Uit eigen keus – ik wil graag software écht naar een hoger niveau krijgen niet blijven steken in concept designs.
We gebruiken wel niet echt mijn favo technologie (React…) maar ik leer wel het een en ander bij over software engineering.
Na jaren nooit echt de switch te maken naar een “echte” IDE heb ik nu écht de switch gemaakt naar IntelliJ.
Ik moet wat meer tijd steken in Spaans leren, maar heb eigenlijk wel vrij veel werk. Ik denk dat het echte taalniveau er pas van gaat komen als ik a) ofwel een dedicated cursus volg of b) in een Mexicaanse context zou werken. Het eerste zou er nog van kunnen komen, voor het 2e is de kans vrij klein. Europese of Amerikaanse klanten betalen nu eenmaal beter ;)
Qua games heb ik na een lange gameloze-periode (met uitzondering van Tunic als tussendoortje in de kerstvakantie) eindelijk tijd kunnen maken voor 2 games: Age of Empires 4 en Elden Ring.
AoE4 neemt de bovenhand met ondertussen al een kleine 30 uur op de teller. De verschillende civs zijn leuk om mee te leren spelen, en ook al draait het vrij brak op mijn oude MBP15, het blijft leuk.
Elden Ring moet nog een beetje openbloeien, voorlopig vind ik het alvast vrij enjoyable. Ik zit een paar uur in de game en hoor dat het pas na een acht of tiental uur echt begint.
Daarnaast, niet om de Belgen jaloers te maken, maar hier is het lekker 28 graden. Iets te warms zelfs.
Qua vrienden is het een beetje zoeken. Ik moet nog een beetje socialer worden denk ik. Misschien iets van sport oppikken. Heb alvast mijn fiets ietwat beter laten afstellen.
Qua reizen heb ik een ticket voor CSS day geboekt, in juni – en in augustus ga ik ook nog een keer richting Europa. Er zijn wel wat reizen gepland. En mijn familie komt eens een kijkje nemen in Mexico stad! Hoera.
Over en uit!