The Month of Hermae

29 days ago, I launched Hermae.

To say those 29 days have been a light-speed roller coaster would be an understatement. I launched a new website (twice), conducted demos for billion-dollar companies, introduced conversational memory to the assistant, trained on a public design system, created a new demo page, talked to investors, developed sales processes, a pricing model, created new logos, and even began compliance certifications.

What started as a fun experiment blossomed into a fireball. I can't believe that it hasn't even been a full month since launch.

My favorite part about all of this isn't the tech or accolades, though. It's the people. Since launching this project, I've been able to meaningfully connect with so many old friends, past coworkers, and even strangers who I now consider friends. That, to me, is what makes this so much fun. The support has been incredible.

I can't wait to see what happens next month. Let's make some money.

On Chasing New Ideas

I have a few active projects. I'm working on Deco, I'm tinkering on Cortelou (haven't talked about this one yet), as well as Interweave and this personal website. All while searching for a new job.

Yet, today I had a new idea. And I built a rough version of it.

It's tough working on so many different things concurrently. I'm extremely focused when I work, which means focus is a limited resource that I spend sparingly. That also means that projects not in the spotlight will not get the attention they deserve.

At the same time, new ideas are always flowing in, filled with all of the excitement that are inherent with new ideas: potential riches, respect, and regard. We see new ideas explode overnight all the time. Maybe this new one is the one?

Unsurprisingly, this creates a natural tension in my life between new ideas and old ideas. The prevailing question seems to be: how do we know when to switch focus from an old idea to a new one? Sometimes businesses take years to develop. Sometimes the business would never work, no matter how long we spent on it. And sometimes, maybe it was just passion-driven, and never was meant to be a business.

I don't have an answer to the question of when to switch. Before the ideas I'm working on now, it was all about BarHop, Gatsby, Arcade, Pluto, HotTub, and even more before that. Switching focus was not always easy, sometimes some are harder than others.

In the end, I do what feels right. I produce my best work when I enjoy it, and if it's a new idea, who cares? Nobody really uses what I build anyways, so might as well have fun building it.

I'm reminded of a post I wrote a few years ago: Living For The Journey. Achieving riches, respect and regard may not be all that it's cracked up to be.

Good advice, I think I'll take it.

2024 Resolutions

I forget my resolutions from last year, so I'll write them down this year to keep me honest. Also, happy three(!) year anniversary to my personal website and writing in public.

Connect More

First, connect more. This is purposely broad; I want to touch base with old friends that I enjoy being with, as well as meet new people. This can be a phone call, grabbing casual coffees, dinners, drinks, walks, whatever! I feel happiest after socializing, so I'm making a point of putting in the effort to do so.

Exercise More

Classic. Need to get back to regularly lifting weights and exercising. It's been tough to maintain a schedule as I travel between friends in Philadelphia, home in Princeton, and my apartment in Hoboken. Hoping a more regular schedule will make regular exercise easier. Less sugar too, but that's nothing new.

Listen More

Sometimes I have a hard time listening. I often get distracted mid-conversation by random thoughts, which pulls me away from being present. Not a fan of that. I recently deleted social apps from my phone as a way to reclaim my attention span, which has shown very positive effects, so I'll keep that up. I hope connecting more will help with this too.

Help More

Related to the first resolution, I want to use my engineering skills to help others. It makes me feel really good, and I consider myself an effective teacher. I'm not sure how I'll manifest this; pro-bono work may be a good option. If the work can help me connect with someone, especially another business owner, then that would make me feel amazing.

Want Less

I'm always reminded of this quote. It's a good one.

Everything you "get" becomes something you "have". Learn how to be happy "having" things instead of "getting" them.

Deco: A Solid-Adjacent Approach to Decentralized Linked Data

I started some discussions on Reddit a while back to understand a little bit more about Solid. I dove into the spec and formed opinions. I was not fond of the developer and user experience that patterns in the Solid protocol created.

Since then, I've been pursuing a project that I consider Solid-adjacent. It's called Deco. I think it can achieve the same goals such as linked data and decentralized, individually owned servers.

However, I believe the plugin ecosystem provides a better experience for extending server capabilities. I'm also leaning into the benefits of individually owning and storing data, specifically in regards to training personal artificial intelligence profiles and networking them between servers. I've leaned into many traditional web technologies, like using JS as the plugin delivery method and traditional JSON for data formatting. I believe these patterns will decrease the difficulty of joining the decentralized network, and increase adoption. I see a future where every business and person has some instantiation of a Deco server.

Check out the repository: https://github.com/MikeCarbone/deco-server

And here is the repository of core plugins: https://github.com/MikeCarbone/deco-core

I've also done some writing on the topic here on my blog:
Practical Decentralization

Bidirectional Interactivity Limitations of AI Tools

Navigating Organizational Growth with an Interaction Record and LLMs


Originally written as a Reddit post for /r/Solid

Dynamic Pictograms For Design Systems

Pictograms are vector graphics illustrations that are more complex than icons. They can include multiple color variations, different background colors, accent colors, and various skin colors. These illustrations usually include multiple different shades of brand colors as well.

Example of pictograms

We want to include pictograms in our design system package to make it easy for other engineers to use throughout the product, but there are some problems. To include every option, we'd have to store a different SVG file for each color combination, which means a 1kb SVG file will now require (number of combinations) * 1kb of package space. If we add a new brand color or skin color, that number grows immensely. So we need to make this dynamic. But how?

For icons, I automatically handle the colors by extracting the values into CSS variables. This is usually simple, because icons are often monochrome, or have a single color. The various color changes across pictograms will make automatic variable extraction difficult. However, I designed a solution that allows us to manually "clean and prep" the SVGs beforehand, making the whole process easier.

Before diving into the color processing, let's look over some other fundamentals to make sure we cover our bases when implementing pictograms in our design system.

Formatting

The pictograms will go through our SVGR build process to make consumption of our pictograms easier. To oversimplify, SVGR allows us to save .svg files, then does a transform so that we can use SVG files like React components. We'll move icons into a new /assets/icons folder, and create a new folder /assets/pictograms. We’ll export everything from a /assets/index.ts to make it easily usable, so we can import { PictogramName } from "assets";.

Naming

We don’t have to do anything crazy. Similar to how we suffix icons with SVG, I think we can suffix with "Picto" to differentiate the assets. So for example, a name may be WomanHoldingLightbulbPicto. By dynamically handling different color profiles, we also simplify the naming process. PaleWomanHoldingLightbulbOnBluePicto doesn't have the same ring to it, does it?

Accessibility

Since pictograms are almost always used as images, we should include an accessible description for each one. This will be done by using an Icon wrapper component, adding role="img" and aria-hidden="false" to the SVG, and adding a descriptive <title> as a direct child of the <svg>. These props will let browsers and screen readers know that this <svg> should be treated as an image. You can configure your wrapper component or SVGR build to do some of this for you. This is not comprehensive; I suggest reading a more detailed guide for handling accessibility.

Colors & Control

Now let's dig into color processing.

So let’s say each pictogram has 4 brand colors and 5 skin tones, that means each pictogram will have 20 variations. That’s too much to add and manage by hand within the design system. The trick here is to break everything into a variable. What that variable will be, and its defaults, are a little more tricky to determine.

First, let's break our colors down in to three categories: brand colors, skin colors, and constant colors. We'll handle each of these a little differently.

Man holding brick, many shades of orange, a dark skin color

Using HSL

Since there are so many different shades of brand colors, we can't really determine a constant color value for each occurrence. Instead, we'll generate these dynamically.

Before moving forward, let me explain how a color is codified in CSS. There's a few different ways to codify a color: HEX, HSL (Hue, Saturation, Lightness), and RGB are the common methods. As an example, here are the different ways we can write the color red:

FormatCSS Value
By Namered
RGBrgb(255, 0, 0)
HEX#ff0000
HSLhsl(0, 100%, 50%)

We'll be utilizing HSL because it gives us a way to control the part of the color we need: lightness.

For brand colors, we can calculate each path’s color lightness compared to the darkest color. This will give us a percentage value to use for lightness, while hue and saturation will be a constant derived from the brand color we choose.

I think it’s easier to visualize this as a black and white image:

Man holding brick, many shades of black and white

Isolate Skin Tones

First step would be to isolate our color palette of skin tones. Those should be “pulled out” so we know not to touch them. It could be possible to do this automatically, but the sure-fire way is to allow the user to “paint” out the colors, AKA click the paths in the SVG that are skin. We also have to differentiate between the primary skin tone and any shadows or highlights.

Closeup of dark skin color with shades of gray

After painting out the skin tones, we end up with something like this:

Skin color painted, shades of gray in the background

Isolate Constant Colors

Sometimes our pictogram will include colors that should be ignored. Perhaps the hair should always be black, or a logo should always be blue. We’ll want to allow users to paint out colors that will remain constant between brand color changes. After these paths are selected, we can remove them from any further processing.

Calculate Palette Lightness Across Paths

Now that we isolated our brand and skin colors, we can figure out the lightness percentage for all remaining paths:

Determining lightness percentages of remaining greyscale paths.

More specifically, these percentages are derived from selecting the existing fill or stroke color from the path, converting the HEX value to HSL, and pulling out the third value for lightness. In our replacement, the other two values will be discarded and replaced by our static brand color constant Hue and Saturation values.

Below is a table showing the hue and saturation values for each of our darkest brand colors. You can get this value by loading the HEX into a color picker and pulling out the H and S values from HSL.

ColorHue DegreesSaturation Percentage
Blue215100
Green17368
Yellow3678
Red582

Knowing all of this, we can then loop through each path and replace the fill and/or stroke value with a CSS variable. So a fill will become hsl(var(--active-h), var(--active-s), ${hsl[2]}%);

--active-h: the active brand color hue value

--active-s: the active brand color saturation value

hsl[2]: the lightness percentage value of the original color (exemplified by the graphic above)

Together, this will reproduce the graphic in any color we want, just by changing the --active-s and --active-h variables.

Different brand colors of the same pictogram

Handling Skin Tones

Changing skin tones works similarly. Since we isolated the paths beforehand and identified them as primary and shadow skin tones, we can use more CSS variable constants to save our different skin tones.

Skin TonePrimary VariableSecondary VariablePrimaryShadow
Fair--skin-tone-fair-primary--skin-tone-fair-shadow#ffc6b4#ffab90
Midtone--skin-tone-midtone-primary--skin-tone-midtone-shadow#ecc19c#dfb38b
Dark--skin-tone-dark-primary--skin-tone-dark-shadow#8a613e#764f2a

And now we can replace those static fills and strokes with a CSS variable: --active-skin-tone-primary and --active-skin-tone-shadow. Then we can specify which skin tone is active, and voila!

Different skin colors on the same pictogram

CSS Variable Architecture

When designing this, I wanted to prioritize two things:

- Completely customizable by consumers

- Usable by designers via copy/paste

The best way to approach this is to use CSS variables. We can even tier our CSS variables to allow internal and external control. What does this mean?

Internal Control

After processing, we want the SVG to work right out of the box. We don’t want to require that consumers configure a variable architecture. We do this by appending CSS variable rules to the root <svg> element. These variables are referenced throughout the internal paths of the SVG. So let’s say our root will have variables active-h, active-s, active-skin-tone-primary, and active-skin-tone-shadow. Our paths inside the SVG only reference these top-level variables. By setting these variables to values, we’ll always have a functioning SVG even if the consumer doesn’t customize the colors.

External Control

However, we want to follow our two parameters and allow customization. So what we can do is set the SVG’s properties to consumer an external variable if it exists, and set a fallback variable if it doesn’t. So inside our SVG tag’s properties, we set it like this:

--active-skin-tone-primary: var(--active-skin-tone-primary, #8A613E);

With this approach, consumers can externally set the variable --active-skin-tone-primary to be whatever they want, and the SVG will know to use that. If it isn’t present however, we can use the fallback HEX code provided.

Within the app I made (link below), we update that fallback HEX color to be whichever value is currently selected. So if the dropdowns specify blue brand color with dark skin tone, we update the fallback variables to be just that, and the outputted code is updated. This allows designers to copy/paste the SVG markup and paste it into Figma, or engineers to copy/paste one-time-needed code, allowing for easily customizable SVGs.

Implementation Into Workflow

Luckily, implementation into our design sytem won’t be too difficult. Work is already underway to update our processing of SVG files to handle pictograms. The only question is preparation.

Here is how I think it should happen:

1. (One time) Designers outline skin-tone constants:

--skin-tone-fair-primary: #ffc6b4;
--skin-tone-fair-shadow: #ffab90;
--skin-tone-midtone-primary: #ecc19c;
--skin-tone-midtone-shadow: #dfb38b;
--skin-tone-dark-primary: #8a613e;
--skin-tone-dark-shadow: #764f2a;

2. Designers process the pictograms in the program before handing off to engineers

3. Engineers save the processed pictogram as an SVG in design system (different colors are painted and variables are settled automatically beforehand)

4. (One time) Engineers create pattern for consumers to override skin & brand colors

Conclusion

Now we can output this SVG, use it in our build, and can alter any skin tones / backgrounds without hosting multiple versions of the same graphic.

To make everything easier, I created a tool that does all of this for you. Here is the live URL: https://mikecarbone.github.io/picto-painter.

and here is a video of it in action:

View More Posts