Transcript
This transcript was autogenerated. To make changes, submit a PR.
If you're a developer on a product team today, you probably know about design
tools. Developers sometimes get to work with product designers or
UI design who use these tools like sketch or figma,
and these are basically vector drawing tools. They're very good at letting
you quickly mock up uis and explore lots of different ideas rapidly,
without investing the time into necessarily writing any
code. But then when it comes time to collaborate with engineering,
that's where things can get complex.
Engineers have to essentially recreate the uis from scratch
by hand, using code, and inevitably a
lot of things can get missed in this translation process,
or it can just be hard to translate because designs are
freeform drawings. And so this leads to a lot of back and forth with
design. And ultimately you have these two sources of truth that by
most teams admission are never truly in sync.
Now there are visual creation tools that let developers
actually build production uis, and they're nothing
new. They're actually very widely used on other platforms like iOS
and Android and Windows, but not really so much for the web.
To make one that fits well with the web means fitting well with how apps
are written today, which means integrating
in a natural way with code that is just increasingly
written using these compositional component frameworks like React or
view. And also, UI builders are
generally perceived as clunky and very technical, a very far
cry from the ease and speed of design tools. But anyway, on the web
today, the status quo is to write everything in code.
So there's a question of what a rethought development
experience could look like for the web. How can we simplify things?
There are also website builders.
Website builders are everywhere. Here's a tiny fraction of them.
These can all actually be quite different from each other as well. Some are
simpler and more for nontechnical audiences
like small business owners. And then there's others like Webflow, where you
basically need to know CSS layout. But they're all focused
on static websites, optionally hooked up to
some content management system. But if you're working on a web app
where you have an actual team of developers, or you have a
database and user accounts, and I think most importantly just
custom business logic, then static site builders aren't
really meant for that. So this brings us to
the last category, which is UI builders for web apps.
This is actually a much more nascent category, so these logos are
probably recognized by far fewer people, but it's emerging really fast.
And this is actually just a subset of players.
These are all about bridging design and development, but they all also have
very different takes, so it's hard to summarize all of them together. Like for instance,
modules lets you theme a design system of primitive components.
Hadron lets you craft web components, Visli lets you craft react components.
It's been really exciting actually to see all this
activity and just raw tooling innovation happening. I work on one of
these. I work on plasmic. So I'll give a quick demo of plasmic just
to show one stab at what rethinking developer experience could
look like. So this is
plasmic. It's a browser based tool. And for this demo, I'm going
to create two do MVC, which just
a refresher of what everyone's favorite reference app looks like.
I'm not going to create the whole thing. I'm actually going to create a subset
of it, and I'm also going to create it from scratch.
We have a different demo video on our website where we show how to start
from a Figma file. So we have this figma plugin that lets you turn one
of these figma documents into web standards. And so that's another way
to get started. For now, we'll just
directly draw on the canvas. You can directly add
text, add boxes, et cetera. And the whole idea,
the whole workflow that plasmic really tries to enable for you
is to just start with these very rough, exploratory designs,
not worrying about layout or anything like that. And I'm drawing
this box for the task and the checkbox in it. I'm going to make the
checkbox rounded. And here I'm just starting
by creating these wireframes. And the
idea is that you should be able to start with these and then refine it
into something that's real, that's robust, that has proper layout and everything.
So the idea is just start from scratch, refine, refine, refine, and you end up
with something that you actually ship into production. So this
task, I could now copy and paste this a bunch of times to
have a list of tasks. But now if
I actually want to style this thing or update one of these, then I
have to do that manually for all the different copies. So instead of that,
I'm actually going to right click this and create a component out of it,
a reusable component called task. And now if I paste this
a bunch of times, then I actually get instances of
the same components. So if I double click
into an instance, I'm editing the primary copy of the component. So if I
drag this around or move things around, then you can see all
the instances update as a result.
So I just kind of drew some boxes. That's pretty much it for my wireframe
of what I want the app to look like. Now from here, I'm going to
start applying styling to make it look more like the real thing. And I'm
going to start with this title here. I'm going to make it super thin and
I'm going to apply some coloring to it. So maybe this light red color
and this background here, the whole page, I'm actually going to set to be this
off white, warm gray, something like that.
And this task itself, I want to be just
pure white. And this checkbox, I actually
also want that to have a
light gray border and just get rid of the background
there. And I'm going to fidget with its text a little bit.
It's a little small right now. I'm going to make it larger and just
adjust its position a little bit. I'm going to set its text color to
be something lighter. I'm going to make it maybe
something like that. And I'm actually going to save this color as a
reusable color token called text color. And so
color tokens, spacing tokens, mix ins, these are all concepts
in plasmic that let you create more maintainable,
scalable designs.
And actually they're very close to what you
get when working with code.
Now I have this list of
three tasks and they're just kind of haphazardly placed. Let's say I
wanted to introduce real layout. So what I can do,
one way to introduce that is I can lasso these into basically
a vertical stack like so. And these stacks keep everything distributed
and organized. These are actually powered by Flexbox and
you can see the controls for this. But we really try
to streamline and simplify a lot of layout in CSS.
And to show that, I'm going to right click this background to
get rid of it. And I can basically,
for instance, for this container, I'm just going to snap everything two the top
to the left. I'm actually going to double click this bottom edge to auto size
the content vertically and also in the horizontal direction as well. So these are
some of the simpler features of
the layout and we'll see some more interesting features in a little bit.
Now, I have this element here,
this container. I'm going to give it a name as well. I'm going to call
it task list. And you can name elements just to keep your elements organized.
And also this will come in handy later for the actual code generation part.
These three tasks, they currently are kind of boring because they all say the same
thing. I want them to be different and in fact I want the text to
be variable. So what I will do is
double click this again to drill into it. I'm going to right click this text
and convert it to what's called a slot. And slots
are kind of like poking a hole in the component. So from any one of
these instances, I can select that slot and just change its text to make
to do app show,
demo, et cetera. But you can actually fill these up with
arbitrary content, any number of elements.
Now, that is almost it
for my app. The only other thing I wanted to do is actually design these
tasks in their different states. And this is just a very
common thing for components in react. Certainly you want two
make them appear differently in different circumstances.
So instead of actually just
keep double clicking into this task to keep editing it,
I'm going to right click this and pop it out into its own new artboard
on the side. And this is so I can edit it in isolation.
If you're familiar with react storybook, it's the same general concept
of just working on things by themselves. So here
I'm going to start showing this concept of variance. And the way that
state and variations of a component
are all modeled in plasmic is through this unifying
concept called variance. And I'm just going two, show this in action. So I'm
going to create a variant group called states.
And inside of states I'm going to create a variant for what
my task looks like when it's marked completed.
Maybe I want to design what it looks like when it's being edited and
when it's marked high priority as well. So these are different states that
this components can be in. And for this exercise,
I'm just going to design out what the completed state is and I want there
to be a checkmark in this checkbox. So I'm actually going
to screen grab this checkmark from here because I just like the look
of it. So I'm going to screen grab that like so.
And back here I'm going to paste it in there and
I'm going to zoom in actually to a pixel to adjust it.
I can also use railayout for adjusting this. It doesn't really matter in this
case. Now, after I do
that, I can actually switch between my base appearance and my completed appearance. So you
can notice that those changes that we made were actually just getting recorded specifically for
the completed state and not affecting the base state.
These are not different copies of the components that
I'm looking at. The completed state is just a
set of overrides or deltas on top of the base appearance. So to show you
what I mean, I'm going to clone this artboard and have it sit
side by side, and I'm going to set the bottom one to look at the
base appearance and top one to look at the complete appearance. And if I
make more changes to the base appearance, you can see those bleed through to
the completed appearance, but any changes that I make specifically that
are getting recorded to the completed appearance will stay within there.
So as another example, I'm going to make this text strikeout and change
its text color to be lighter as well.
So you can just change any part of a component like this.
Now, the thing about variants is that you can dynamically combine any number
of them. So for instance, I'm going to introduce another variant here for
my hover state. And hover is actually just a very
common interaction, similar two pressed, et cetera. So there's
like this special built in support for those states.
And basically whenever I hover over any part of this component,
I want this box here to become darker. So I'm just going to scroll down
Yang Zhang its border color to become darker,
like so now I
can actually try this out in preview mode and
I'm hovering over this thing. Okay, so that's close to what I want. But I
actually realized another thing that I want is for there to be for
this cursor to become a hand pointer as well. So I'm going to
just set that here directly and
preview again. Okay, so that's a lot better.
And the thing about these variants is that they come with the component wherever
it goes. So back in my main screen I can select any one of these
instances. I can change it just for the purpose of mocking up
into, for instance, the completed state. I can also preview this whole thing
and just play with it. And it's a little nuanced, but you can see
we're dynamically combining the completed state and the
hover state here with this middle guy. So that is pretty
much it for designing out this app. Maybe the last thing I'll do is tighten
up the layout of the whole thing. So I'm going to set it to be
a column layout and center everything and
maybe add some padding to the top and bottom here,
like so. And I'll turn this whole screen into
a component as well, called to do app. So now my project has
these two components. My to do app components, my task component from
here. This part is the interesting part, which is how do we
work with it from the code? So one way to get started is actually
just through our code sandbox integration, and you can click this button and just
spin up a sandbox. And you have basically this
asset running as a standalone web app that you can directly
start mucking with the code for. But more interesting
for us is actually generating code into our own local code
base. So there's this client that helps you with that.
And I already have installed, so I'm going to skip the step. And the two
other steps are basically running plasma init. And this is just a
command you run every time you want to get started using plasma in a code
base. So I have here in my terminal this
basically, it's a blank create react app. And just to show you what that looks
like, it's just a spinning logo. And I'm going
to run that plasmic init command here. It's going to ask a bunch of questions
that I'm going to answer with the defaults for.
And the only other command here is this plasmic sync command, which is what
actually pulls down the components from the project.
So I'm going to go back to my terminal,
and so now we have this to do app and task components synced down.
And I'm going to pull up my code editor on
the left and have my running app on the right. And just
the first thing I'll do is just get things on the screen. So I'm going
to replace all this boilerplate with just rendering this studio app like
so.
And now I should
see exactly what I created in the design tool showing up as a
pixel perfect component in my actual react app.
From here, this is still the static mock data.
So let's say I wanted to replace it with my real data.
So what I can do is I'm going to double click this to do app
to drill into it. This file has a lot of comments,
but I'm going to get rid of these. So you can see that
it's actually just a very simple file. This whole
todo app Component is actually just a thin wrapper around the plasmic todo app
component. So the plasmic Todo app component is this
dumb presentational component that handles all the rendering.
And this is actually generated by plasmic and is regenerated
by plasmic. And we'll see that in a little bit.
But Todo app itself, this whole file
is just a skeleton starter that's generated
for your convenience, but you can actually do whatever you want with this file.
You as a developer own this file. So for instance, if I actually wanted
to start introducing state or behavior to this, I can
just do that here directly. So I'm going to start
by adding some state for my tasks.
And let's say my task objects are just simple js objects with
can in property do stuff like. So I'm going to
have three of them. And now I'm going to
wire up this plasmic two do app components
with the actual tasks.
And to do that I'm going to reference one of the elements that I named
previously. I'm going to reference it by name. So this task list, I'm going to
replace all of its content with my own set of tasks.
And to render these tasks I'm going
to use the other component that we synced down, this task components.
So now I have my
own data showing up in the app. And so this is how you can work
with these plasmic components,
is you can just flexibly wire up any props that you want on
them. Now,
the real highlight of plasmic is that it's not just a one time code export,
but you can actually go back into the editor and make changes to your design
and those will be kept in sync with the code. So I'm
going to run plasmic watch, which is just this mode where it'll live stream any
edits I make in the editor into my code base. And I'm going
to have the running app on the right and
the editor on the left, like so.
Actually don't have a ton of real estate here, so it's going to feel a
little squish on the right. But now let's say I wanted to make some
violent changes. Two, my layout. So instead of this vertical
list, let's say I want it to be a set of tiles. So I'm going
to double click this component to start editing it again. I'm going to make it
look boxier, something like that. I'm also going to start
applying some relay, but to this so that it's a row top aligned
and maybe with some padding all around. I'm going to take
this checkbox and pop it out of its place so it's free floating and I'm
going to drag it down to the bottom right of
the task and I'm going to pin it to the bottom
right, actually, like so. And that's it
for what I want. Two, change my tasks to look like now, this is still
a vertical list, and I want this to be a set of tiles,
like rows of tiles. So I'm going
to change this thing to go from column to row. Now everything is spilling
over on the right, but I'm going to turn on wrapping so that things wrap
around and I'm going to mix it fixed size so
that's actually centered in the screen. It's a little hard
for me to tell apart the different tiles right now. So I'm also going
to introduce some gap in the vertical direction and also
the horizontal direction. So you can see some of the fancier features at play
with the layout engine here. And if you think about how to implement things like
a cross browser gap in a way that
is friendly with things like
wrapping and doesn't introduce selector specificity
issues, it's actually quite annoying to do.
So. These are examples of things that are just very common when it
comes to layout tasks that plasma tries to make as simple
as possible. So anyway, you could see that as I was making those changes,
these were getting live streamed into the actual app.
So that is pretty much it for this quick tour of plasmic
and what it's all about. So now I'd
like to pull back the curtain a little bit and talk about some of the
challenges that went into building this thing, including both technical challenges
and product challenges. So the first one I'll start with is
just the state management infrastructure. So this is a
very sprawling client application with a lot of complex state,
and it's state that is constantly changing. And there's also a
lot of surfaces that are reflecting out various parts of that state.
And there are certain operations, certain interactions like drag
operations, where if you want it to be smooth, which means if
you're shooting for, let's say, 60 frames per second, then you typically
have a frame budget of around 16 milliseconds. And if you
want to make sure you're not busting that budget, then what that means is you
just want to make sure you're doing the minimum amount of work that you can
get away with per frame. And so this is where a lot
of tools like state management frameworks come into
play. They're all about minimizing in various ways that
are more or less ergonomic for developers,
just minimizing the amount of work that react does,
the amount of rerendering that you do in response, two state updates.
But what makes this application tricky is the combination of latency
with scale. So to show what I mean,
this example here, we have a canvas with these three artboards,
which is a pretty simple project. But if you imagine a project
with hundreds of artboards on the screen, then things get
a lot diceier.
What you don't want to do is to simply naively just
make a synchronous update to
your state and then have everything rerender as a result. So an
example of a thing we do instead is we break up our updates into small
chunks so that we can incrementally and lazily evaluate
these updates, these rerenderings, I should say,
we can actually see this in action. So as I am
dragging around this checkbox here, you can notice that
if you watch the other artboards, there's a slight
delay and lag between when I moving
this one around and when these others update. And that's actually an artifact
of our scheduler in play. So there's prioritization
of these different artboards where the one that you're manipulating directly is highest
priority. The things around you are lower priority, and the
things off screen are lower priority still. So that's
one example of a way we actually break up some of the work here and
then actually prioritize and schedule them.
Another imported feature of plasma is one
that I haven't shown in this demo, is code components. And this is about
the ability to bring in your existing react components, maybe from
your own code base, maybe from a library like material UI. And there's a
lot of challenges here, such as simply making it easy for users
to bundle up the components that
they care about without becoming experts in webpack or
just dynamically loading the modules into the runtime,
because you're essentially injecting this foreign third
party code into the canvas, and you want to do
that in a secure and isolated way. But,
okay, so even once you have your material UI button showing up in the canvas,
how do you actually configure it and work with it? So that's where plasmax
language tooling comes in. And this is basically about crawling your
code base. Two, find the components available in it and reflecting out their interfaces,
whether it's documented using typescript or prop types.
And this can be nuanced because there are some props that you expect to
show up as controls in the right hand panel, for instance, various knobs.
And there's other props, like children props, or function as
child props, where you expect to directly manipulate them on the canvas
through drag and drop. On top
of all this, there's these additional problems that I haven't talked about,
like just harvesting out examples of how to use the components,
because oftentimes that's also very well documented in code bases or documentation
as well. There's also a slew of
product challenges. So here are a couple. One is about distilling
layout into a small set of intuitive controls.
CSS layout is notorious for being hard to use,
and layout is just such a pervasive aspect of
creating uis that plasmic really focuses on trying to streamline
that as much as possible. CSS comes with
a lot of different concepts, both legacy and modern, and different overlapping ways
of achieving the same thing, but with different trade offs and
subtleties between them. And to this day, I still spend
time debugging which props
affect the declared height of can element, so that percentage
heights respect that and just other minutiae
of CSS. And this is actually really infuriating,
because the answer changes in browsers over time. So plasmic
tries to unify and simplify a lot of these concepts and distill
them into simpler controls that cover the most common cases and then give you
escape hatches to actually drop down and exercise full control over your flex
basis, et cetera, if you really care to.
The last aspect is something I alluded to in the
middle of the demo, but it's the
ability to actually bring in your
designs from other design tools. And there's a lot of challenges here,
actually just around mapping the concepts
across these different domains. So this
is about taking, for instance, Figma's document representation.
And that actually is something that is very
rooted in graphic design backgrounds. So you have concepts like
layers and layer masks and blend modes. And in
CSS, for instance, you have inner and outer shadows.
In Figma, you have centered borders. So reconciling these
impedance mismatches is a big part of
the product challenge there. And the
goal is really to automate
away and do as much as possible of the grunt work,
this rote work of translating designs into web
standards. Code integration is,
I think, the most important challenge for plasmic. If you think about
what is natural for visual direct manipulation, and also
what's natural for expressing code, we're essentially trying to marry the
best of both worlds, and we're trying to find the most natural
and flexible interface for doing that. This flexibility
is there for practical reasons,
right? Just at the end of the day, I need to instrument this element with
a certain prop or event handler or behavior.
But there's also what I'll call, quote unquote, aesthetic reasons
as well. So I want to control what my component API
looks like. In this example, I have this task component,
and it takes the children for the content.
But maybe that's not the interface I want. Maybe I want this task component to
take a task entry data object, right? And then internally it
can derive what content it should render, what state it should render in,
et cetera, from that task entry object. So this is what
I mean by control over the component API. So our thinking is
always rooted in just giving developers as
much flexibility as possible so that the code generation
is only there to help and never to hinder.
So we use plasma for building plasmic. And in terms of the impact on our
own workflow, there's a few things I want to call out. So the first is
around this design first mentality, which is about forcing you to
think about the end goal, the product and the experience that you're
going after, and then filling in the code in service of that end goal.
So this is really nice as a top down approach, right? Making sure you're building
the right thing. And bottom up approaches definitely have their place,
especially in projects with high technical risk.
But it can also be more bumbling for other kinds of projects.
The second impact on our workflow is if you are
lucky enough to be working with a technical designer who can wield something
like plasmic, then there's just something very magical about running
plasma sync and then seeing a nicer version of your landing page show up in
your code base, which it's definitely
a direction that we want to explore a lot more is broadening
this tool to make it more accessible to thing
I'll call out. In terms of workflow, impact is just
the elimination of an entire class of visual regression
tests and manual QA tools. So, for instance,
we have these storybook plugins that would help
you compare your implemented components with your designs.
And that's obviated by the fact
that this tool is essentially a declarative language for you
two. What you see is exactly what you get in the final product.
Anyway, that's all I want to share about plasmic. It's still really early days
for us, but also for a lot of the tools in this camp.
I'm actually really excited about this entire category. I think there's just a
lot of innovation happening that I think could really transform what
front end development looks like. So I definitely encourage you to check out
these tools. We'll also be sharing our progress on Twitter.
And the last thing I will call out is that we are hiring.
We're a tiny team of five people total, three on engineering. So if these
challenges sound like fun, then let us know.