Johan Ronsse

  • Home
  • Projects
  • Blog
  • Delisted

    August 9, 2023 - Posted in build-in-public figma figma-plugins

    Yesterday I de-listed my plugin from the Figma community, before I even had my first user.

    One week before, I happily pushed the publish button and set a price tag of $20. I was proud to have made something worth charging for, but the whole week it was nagging in my head how it was not ready.

    The doubts kept growing.

    I was stressed about it, but now I realize: it’s not a bug… it’s a feature! No having a plugin live is my peace of mind for the following weeks, while I enjoy a little holiday in Europe.

    The plugin doesn’t need to be live yet. Whoever is interested can ask me to test it locally, and I need to gather a bit more feedback before launch. This also gives the other team members more time to make things more polished without any unnecessary stress.

    Over the past month I’ve been working hard on Screenshot to Layout and to be honest it has been a bit intense building the plugin itself — but also all the operations around it. Intense,

    Little did I know that to build this plugin, I would also have to build an accounts system, write a privacy policy, learn about layout algorhitms, up my database skills, get better at Typescript, set up a reverse proxy, learn the Figma plugin API and sooo much more.

    I put over a hundred hours on top of my regular job in this plugin, and while I am proud of the end result, I don’t want to ship it yet.

    The main problem I have now is the pricing. I know I have something of value, and I want to charge for it.

    What I want is for my plugin to be a utility that somebody can use for the next five+ years, just paying 1 fee.

    Figma’s pricing pushes you to a SaaS if you want to offer a free trial, and I hate that pricing mechanism for a design plugin. Who wants to deal with little monthly bills of $1? And is the plugin worth $60 over a period of 5 years? I don’t think it’s that good. Not to mention the admin hassle it creates.

    Right now I am thinking about publishing 2 versions of the plugin, but that seems like a distribution hassle in itself, and I have no way to know which API key belongs to which user.

    Another idea is to take the payments part fully off-platform and implement it with a Stripe subscription instead, but that means building more infrastructure to support those mechanisms.

    The jury is out there… but first I am going to take some time off.

  • Screenshot to Layout Pro: released!

    August 3, 2023 - Posted in bootstrap figma figma-plugins

    The first version of my Figma plugin Screenshot to Layout Pro has been released. Use Screenshot to Layout to generate editable text from a screenshot.

    If you have any questions, or would like to request a trial, don’t hesitate to contact me at figmaplugins@obra.studio .

    Check it out on the Figma community

    Edit: The plugin has been delisted while I work out some kinks.

  • A bootstrapping update

    August 1, 2023 - Posted in bootstrap figma

    Over the past month I’ve been on a little indie hacker journey, where I built my first freemium plugin for Figma: Screenshot to Layout.

    Essentially it’s an OCR plugin: it recognizes text from screenshots and renders it back to Figma.

    In my first version, I used a file input.

    I felt I had a nice breakthrough when I realized I could run my plugin as a command, and have no user interface at all.

    Using the command pallette
    Loading…
    … and done!

    Over the past month I’ve contemplated various UI options but I always keep coming back to having no user interface at all. Except to enter the API key, upgrade your account, there are no UI options to be seen.

    Right now I am close to launch, and looking for testers. Testers will get free usage of the plugin for their honest feedback. Register your interest here!

  • Job: freelance Svelte developer

    July 28, 2023 - Posted in jobs svelte - 1 comment

    Hey all, my bootstrapping journey is reaching an exciting point where we are able to provide real value to designers with the Obra Figma plugins, starting with the Screenshot to Layout plugin.

    To bring things over the finish line, I am looking for a Svelte developer with (some) design chops to develop and fine tune more of the user journey.  Most of the work would be happening in August.

    There are lots of details to be handled, and I am looking for a communicative developer who can execute work but at the same time bring their own thinking to make the end result better.

    Skills I am looking for are:

    • JS/TS + Svelte + Sveltekit knowledge
    • Insight in Figma

    Bonus if

    • You can develop Figma plugins

    Extra pro

    • Supabase knowledge

    The biggest part of the job would be Svelte and Sveltekit related.

    If you are interested to work with me, reach out with your portfolio/resume/personal site, your hourly tariff or pricing logic, to jobs@obra.studio.

  • Figma – Screenshot to Layout plugin (2)

    July 22, 2023 - Posted in figma figma-plugins

    I am working on my plugin to build a layout from a screenshot.

    What does it do?

    Select an image in Figma, run the plugin command “Screenshot to Layout”, and then see a Figma layout appear with editable text.

    What is it for?

    Useful to quickly start working on a new design based on a screenshot.

    Looking for testers

    I am looking for testers. Reach out at figmaplugins@obra.studio .

  • Figma plugins

    July 21, 2023 - Posted in figma figma-plugins

    Just some plugins that have been of use lately.

    • General
      • Navigate multiple siblings
      • Downsize
    • Development of plugins
      • Debugger
      • Node decoder
      • Figlet

  • An intro to building Figma plugins (2)

    July 19, 2023 - 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.

    Getting started

    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:

    • Rename the first Hello world to Heading 1, and set the font size to
    • Rename the second Hello world to Heading 2, and set the font size to 24.
    • Swap the bold and medium on heading 1 and heading 2
    • Add “Body -” in front of the lorem ipsum of “body” to make people understand we’re talking about the body text there
    • Space out the typography examples by adjusting the “y” values.

    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.

    Extra tips for starting development

    • If you are stuck, check the Figma Plugin API reference.
    • There is a Friends of Figma Discord where I hang out in #plugin-api sometimes.
    • If you are looking for inspiration, check out the official plugin-samples repo, and my unofficial examples repo.
  • An intro to building Figma plugins (1)

    July 19, 2023 - 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.

    Getting started

    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!

    Extra tips for starting development

    • If you are stuck, check the Figma Plugin API reference.
    • There is a Friends of Figma Discord where I hang out in #plugin-api sometimes.
    • If you are looking for inspiration, check out the official plugin-samples repo.
  • Figma: screenshot to layout plugin

    July 1, 2023 - Posted in bootstrap figma

    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 .

  • Time to bootstrap

    June 24, 2023 - Posted in bootstrap

    I am starting something on the side, with the goal of bootstrapping a side business. The idea is to

    • build in public
    • build something that’s real (people can sign up, use it, it provides value)
    • see if ideas get traction (or not)
    • experiment and learn new things

    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 .

← older
newer →
  • ©2025 Johan Ronsse
  • X
  • Mastodon
  • Portfolio 2024