Sign in

Janis Jansen 🌳

@janis.me
99 followers 276 following 389 posts

Building @elevenlabs.io and open source CSS tools. Before that fluid simulations and software-first steelmaking 🔗 janis.me 🖥️ github.com/janis-me 📽️ youtube.com/@janis-me

PostsRepliesMedia
Janis Jansen 🌳 @janis.me · 26/09/2026
Hardware upgrade! Compiling things is fast now. As is switching windows.
my fast-fetch output. Nixos, literally this text:
Date & Time  2026-09-26 18:41:28
-----------
OS  NixOS 26.11 (Zokor) x86_64
Host  X870E AORUS ELITE X3D (Default string-WCP-ADO-XT2)
BIOS (UEFI)  F9c (5.41)
Boot Manager  Linux Boot Manager - systemd-bootx64.efi
Kernel  Linux 6.18.52
Init System  systemd 261.2
Uptime  1 hour, 2 mins
Processes  112 (1568 threads)
Packages  1584 (nix-system), 1043 (nix-user)
Shell  zsh 5.9.2
Editor  zeditor --wait
-----------
CPU  AMD Ryzen 9 9950X3D (32) @ 5.76 GHz - 43.8°C
CPU Cache (L1)  16x49.15 kB (D), 16x32.77 kB (I)
CPU Cache (L2)  16x1.05 MB (U)
CPU Cache (L3)  100.66 MB (U), 33.55 MB (U)
CPU Usage  1%
-----------
GPU 1  AMD Radeon Graphics (2) @ 2.20 GHz - 38.0°C (16.71 MB / 536.87 MB, 3%) [Integrated]
GPU 2  NVIDIA GeForce RTX 5070 Ti [Discrete]
-----------
Memory  5.80 GB / 32.64 GB (18%)
Disk (/)  105.96 GB / 1.97 TB (5%) - ext4
Disk (/data/bulk)  13.66 GB / 983.35 GB (1%) - ext4
Disk (/data/fast)  2.13 MB / 491.11 GB (0%) - ext4
100
Janis Jansen 🌳 @janis.me · 10/09/2026
Wait. When submitting a stack though github cli, it doesn't set the remote tracking branch? I'm sure the cli submits the code via git, since I had to unlock my SSH key. If I had push.autoSetupRemote enabled and gh cli would have chosen a different branch name, I'd have two remote branches?
An image showing I synced the stack with `gh stack submit` and then tried pushing a branch with `git push`, but it rejected since it didn't know the remote branch.
100
Janis Jansen 🌳 @janis.me · 09/03/2026
My favorite thing is that the logo also changes colors tbh.
000
Janis Jansen 🌳 @janis.me · 07/03/2026
Created an app today that shows all your at://proto activity in your own personal garden: profile.garden It's fully vibe-coded right now apart for some UI stuff. My goal is that you can login and can customize your garden. Integrations include bsky, tangled, stream.place, popfeed, @npmx.dev etc.
4320
Janis Jansen 🌳 @janis.me · 04/02/2026
first to like postcss by @evilmartians.com on @npmx.dev
150
Janis Jansen 🌳 @janis.me · 30/01/2026
000
Janis Jansen 🌳 @janis.me · 15/12/2025
We nominated some open source maintainers and tools to receive funding from the OSS Engineers Fund and will donate $22k to the projects we rely on at ElevenLabs! Some of these are my favorite tools I use daily that I think really deserve support like PostCSS, Graphite, ProseMirror and more.
1184
Janis Jansen 🌳 @janis.me · 02/12/2025
Beware, a linkedin-type post... I'm super excited to share that I've joined ElevenLabs to work on the creative platform and music as a full-stack dev! Music and next-gen software have been a passion for literally my entire adult life. Now I can combine them in the best way!
A picture of me with the elevenlabs Branding and a text showing "Elevenlabs x Janis"
120
Janis Jansen 🌳 @janis.me · 23/11/2025
A spam email claiming to be PayPal, sent from Uni Münster Accounts
000
Janis Jansen 🌳 @janis.me · 04/11/2025
You can't stop me from playing Metroid Fusion on a GBA emulator on my modded Wii. I do own a computer and I do own several other consoles. But this is the way you are supposed to play GBA games.
The game Metroid Fusion (the best Metroid game) and a Wii remote.
020
Janis Jansen 🌳 @janis.me · 23/10/2025
We're getting there! Was a very productive week.
Screenshot of a GitHub PR summary, showing:
162 Files changed, +11.691 additions, -2.682 deletions and 24 commits
010
Janis Jansen 🌳 @janis.me · 19/10/2025
Speaking of Vendor prefixes. These are the ones I found so far Stopping with the "spam" now :) sorry
  | `-webkit-${string}`
  | `-moz-${string}`
  | `-ms-${string}`
  | `-o-${string}`
  | `-khtml-${string}`
  | `-apple-${string}`
  | `-x-moz-${string}`;
000
Janis Jansen 🌳 @janis.me · 19/10/2025
I also got one for (I hope) every single pseudo class and pseudo element! There are some edge-cases though. like `:matches()`. And it excludes vendor-prefixed ones. Couldn't be bothered.
":dir" | ":has" | ":host" | ":host-context" | ":is" | ":lang" | ":not" | ":nth-child" | ":nth-last-child" | ":nth-last-of-type" | ":nth-of-type" | ":where" | ":active" | ":any-link" | ":blank" | ":checked" | ":current" | ":default" | ":defined" | ":disabled" | ":empty" | ":enabled" | ":first" | ":first-child" | ":first-of-type" | ":focus" | ":focus-visible" | ":focus-within" | ":fullscreen" | ":future" | ":hover" | ":in-range" | ":indeterminate" | ":invalid" | ":last-child" | ":last-of-type" | ":left" | ":link" | ":local-link" | ":nth-col" | ... 21 more ... | ":visited""::cue" | "::cue-region" | "::part" | "::slotted" | "::view-transition-group" | "::view-transition-image-pair" | "::view-transition-new" | "::view-transition-old" | "::after" | "::backdrop" | "::before" | "::first-letter" | "::first-line" | "::grammar-error" | "::marker" | "::placeholder" | "::selection" | "::spelling-error" | "::target-text" | "::view-transition"
200
Janis Jansen 🌳 @janis.me · 19/10/2025
I'm learning so much more about CSS by building surimi (because I am forced to read the CSS specification). For example, just wrote some types to figure out all possible @media query descriptors you can use. It's 40 in total
Here you go. All 40 of them:
'any-hover',  'any-pointer',  'color-gamut',  'grid',  'hover',  'overflow-block',  'overflow-inline',  'pointer',  'scan',  'update',  'aspect-ratio',  'color',  'color-index',  'device-aspect-ratio',  'device-height',  'device-width',  'height',  'monochrome',  'resolution',  'width',  'max-aspect-ratio',  'max-color',  'max-color-index',  'max-device-aspect-ratio',  'max-device-height',  'max-device-width',  'max-height',  'max-monochrome',  'max-resolution',  'max-width',  'min-aspect-ratio',  'min-color',  'min-color-index',  'min-device-aspect-ratio',  'min-device-height',  'min-device-width',  'min-height',  'min-monochrome',  'min-resolution',  'min-width'
210
Janis Jansen 🌳 @janis.me · 17/10/2025
I'm in a deep `extends...infer` typescript hole again. And it's just awesome. Getting a lot done today!
010
Janis Jansen 🌳 @janis.me · 17/10/2025
From the main Page, when I search for any domain and click on the search button, I am re-directed and get an error. If I then reload the page, everything works again. I could re-produce it consistently by clearing the website cache. I'm on the latest Firefox Mobile (android)
100
Janis Jansen 🌳 @janis.me · 15/10/2025
The first version of the 🍣 surimi playground is live! It runs the @rolldown.rs based compiler in a WebContainer, and updates the editor instantly! Check it out! surimi.dev/playground Compile times are bit slower than locally tho. Also - has type-hint support - you can install new packages - ...
341
Janis Jansen 🌳 @janis.me · 14/10/2025
It's magnificent
010
Janis Jansen 🌳 @janis.me · 03/10/2025
Outrageous!
The nyt game spelling be, showing the word "linting" but it's not in the word list.
000
Janis Jansen 🌳 @janis.me · 01/10/2025
Oh, and yes: You can do everything typescript can do. Import externals, if conditions... save selectors to variables and share them across files.. mixins... 0 runtime as well. I made a vite plugin for it!
010
Janis Jansen 🌳 @janis.me · 01/10/2025
It has full typescript hinting support as well. You see what CSS will be built *inside* the type hints.
110
Janis Jansen 🌳 @janis.me · 01/10/2025
Oh no, it's really happening
100
Janis Jansen 🌳 @janis.me · 29/09/2025
I love this! On blueview.app, you can see who recently interacted with you, and much more insightful data! Shout out! Don't want to tag all these busy people though :) Thanks for making this @srsholmes.com
110
Janis Jansen 🌳 @janis.me · 09/09/2025
You probably knew that a typescript enum, when compiled, adds extra runtime code. But did you also know, that a `const enum` does not? Might be worth using instead of string literals!
An enum like  

enum Options {
    ONE = 1,
    TWO = 2
}

let x = Options.ONE;

will compile to 

"use strict";
var Options;
(function (Options) {
    Options[Options["ONE"] = 1] = "ONE";
    Options[Options["TWO"] = 2] = "TWO";
})(Options || (Options = {}));
let x = Options.ONE;But change it to

const enum Options {
    ONE = 1,
    TWO = 2
}

let x = Options.ONE;

and it will have no overhead:

"use strict";
let x = 1 /* Options.ONE */;
000
Janis Jansen 🌳 @janis.me · 29/08/2025
Just discovered the "Xerox Alto" UI in the latest blog post by @bradfrost.com and it looks so damn good. This aesthetic is exactly what I was going for with my website.. but I might have deviated too far. Also, it's a brilliant blog post, check it out at bradfrost.com
The Xerox Alto user interface. White and gray boxes with black text and borders. Not a lot going on on the screen, just shows some lists, text and the mockup/3d design plan of a screw. Simple but crisp design!
000
Janis Jansen 🌳 @janis.me · 28/08/2025
I updated my website! It now has: - prettier, colorful dark scheme (below) - a CV page - a new blog post (for my CSS nerds) - better accessibility, progressive enhancements etc. - automatically generated PDFs (like the CV page). Check it out at janis.me and tell me what theme you like the most!
My website! Showing the home page with the new "colorful dark" theme. It's got a yellow font on dark background. The website itself is made up of simple lines, clean and simple.
100
Janis Jansen 🌳 @janis.me · 15/08/2025
Here, fixed it.
The dunning-kruger effect graph (confidence vs knowledge), but the 'peak of mt. stupid' is 'hot take, but...'
010
Janis Jansen 🌳 @janis.me · 03/07/2025
I love Sweden
Picture of a lake and forest during the day, and a barbeque grill with some bread and sausages in the front.
000
Janis Jansen 🌳 @janis.me · 23/06/2025
It's not easy to keep up with css features..😅 even though they are sooo great! I loved taking the 2025 state of CSS survey. Give it a shot! survey.devographics.com/en-US/survey...
000
Janis Jansen 🌳 @janis.me · 17/06/2025
* specifically, using `comlink` by @surma.dev et. al. to create multiple instances of a class within the worker. That way, you can 'spawn' them easily. And while we're at it: While digging through the source of squoosh.app, I found this gem of an example image: (@jakearchibald.com sorry)
020
Janis Jansen 🌳 @janis.me · 12/06/2025
Super hyped about an, admittedly, very tiny library: handlery.dev let's you add awesome class-based event handlers for all kinds of emitters (like emittery, node's EventEmitter etc.) With the magic of decorators! Now that TC39 decorators are stage 3 and moving forwards, let's start using them!
A demo of how handlery works. It shows a `subscribe` decorator, a TodoHandler that extends an `EventHandler`, and some methods using the `on` decorator to listen to `todos.add` and `todos.remove`
100
Janis Jansen 🌳 @janis.me · 12/06/2025
Anyone in the threejs community will find it comical that this is a screenshot from today.
A screenshot of GitHub, showing that mrdoob followed meugen87
010
Janis Jansen 🌳 @janis.me · 04/06/2025
I'm nearly there! (I need to improve accessibility by making more space for small buttons on mobile, will figure out how that can fit in the website theme. I don't want to make it more complex by adding things like floating menus)
000
Janis Jansen 🌳 @janis.me · 29/05/2025
Got a new thing going on! surimi.dev - to make SCSS libraries safer, with proper error messages. Feedback very much wanted! github.com/janis-me/surimi
The surimi logo. Two pieces of surimi on some rice, in comic style.
100
Janis Jansen 🌳 @janis.me · 20/05/2025
To be clear what I mean:
interface Input {
  a: string;
  b?: number;
}

// should become
interface Output {
  a: string;
  b: number | undefined;
}
000
Janis Jansen 🌳 @janis.me · 20/05/2025
Help! A question for my fellow typescript wizards (cc @mattpocock.com) I want to convert 'key-optional' properties of a type to 'value-optional', so remove the `?` and instead make these properties union with `undefined`. This is the only thing I came up with. There must be a better way??
export type Prettify<T> = {
  [K in keyof T]: T[K];
};

export type OptionalKeys<T> = {
  [K in keyof T]-?: {} extends Pick<T, K> ? K : never;
}[keyof T];

export type OptionalToUndefined<T> = Prettify<
  {
    [K in Exclude<keyof T, OptionalKeys<T>>]: T[K];
  } & {
    [K in OptionalKeys<T>]?: T[K] | undefined;
  }
>;
210
Janis Jansen 🌳 @janis.me · 20/05/2025
Oh wow! I knew about the `HTML` Element by react-three-fiber / drei, but I didn't realize you could render things like context menus as part of a mesh! In this example, I show a @radix-ui.com context menu at the position of the cursor, when right-clicking the mesh. @pmnd.rs I love you so much.
A code snippet of the program I described:

export function MyContextableMesh() {
  const contextMenuTriggerRef = useRef<HTMLSpanElement>(null);

  return (
    <mesh
      onContextMenu={e => {
        contextMenuTriggerRef.current?.dispatchEvent(
          new MouseEvent('contextmenu', { bubbles: true, clientX: e.clientX, clientY: e.clientY }),
        );
      }}
    >
      <boxGeometry args={[1, 1, 1]} />
      <meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />

      <Html as="div">
        <ContextMenu.Root>
          <ContextMenu.Trigger ref={contextMenuTriggerRef} />
          <UI.ContextMenu.Portal>
            ...
          </UI.ContextMenu.Portal>
        </UI.ContextMenu.Root>
      </Html>
    </mesh>
  );
}
100
Janis Jansen 🌳 @janis.me · 18/05/2025
Putting olives on pizza should be illegal
010
Janis Jansen 🌳 @janis.me · 29/04/2025
@standupmaths.bsky.social you silly goose... That's not me. That's you!
100
Janis Jansen 🌳 @janis.me · 28/04/2025
csshell.com is great fun. Found a one-prop solution for riddle #9 (spoiler)
000
Janis Jansen 🌳 @janis.me · 25/04/2025
The best thing about a @npmjs.bsky.social scope that matches your website URL is that the `homepage` URL can be literally the package name For `@janis.me/themed` it's `http://@janis.me/themed`
A screenshot of the npm website for https://www.npmjs.com/package/@janis.me/themed, showing that the 'homepage' link is the same as the package name.
000
Janis Jansen 🌳 @janis.me · 25/04/2025
And yes, you see the output SCSS / CSS
The SCSS output of the website, looks like

@use '@janis.me/themed';
@use '@janis.me/themed/generators';
@use '@janis.me/themed/plugins';

$themes: generators.theme(
  $primary: #1b11d4,
  $target-space: oklch,
);

// The plugins are optional,
// but that's what's used for this website. 
@include themed.configure(
  $themes,
  $plugins: plugins.alpha(
    $operation: 'change',
    $steps: (
      0.2,
      0.4,
      0.9,
    )
  )
);

@include themed.apply();The raw CSS output, defines a dark theme on the HTML element using CSS, then defines a bunch of CSS variables

html[data-theme=dark] {
  --themed-primary-1: oklch(23% 0.024 267.48174171deg);
  --themed-primary-2: oklch(24% 0.028 267.48174171deg);
  --themed-primary-3: oklch(30% 0.065 267.48174171deg);
  --themed-primary-4: oklch(34% 0.092 267.48174171deg);
  --themed-primary-5: oklch(38% 0.1 267.48174171deg);
  --themed-primary-6: oklch(42% 0.106 267.48174171deg);
  --themed-primary-7: oklch(47% 0.115 267.48174171deg);
  --themed-primary-8: oklch(52% 0.132 267.48174171deg);
  --themed-primary-9: oklch(61% 0.094 267.48174171deg);
  --themed-primary-10: oklch(57% 0.164 267.48174171deg);
  --themed-primary-11: oklch(76.8676609058% 0.1172127065 267.0448447542deg);
  --themed-primary-12: oklch(90% 0.043 267.48174171deg);
  --themed-gray-1: oklch(23% 0.01 267.48174171deg);
  --themed-gray-2: oklch(26% 0.01 267.48174171deg);
  --themed-gray-3: oklch(29% 0.01 267.48174171deg);
  --themed-gray-4: oklch(32% 0.01 267.48174171deg);
  --themed-gray-5: oklch(34% 0.01 267.48174171deg);
  --themed-gray-6: oklch(37% 0.01 267.48174171deg);
  --themed-gray-7: oklch(42% 0.01 267.48174171deg);
  --themed-gray-8: oklch(50% 0.01 267.48174171deg);
  --themed-gray-9: oklch(55% 0.01 267.48174171deg);
  --themed-gray-10: oklch(59% 0.01 267.48174171deg);
  --themed-gray-11: oklch(77% 0.01 267.48174171deg);
010
Janis Jansen 🌳 @janis.me · 25/04/2025
I might be spamming a bit, but I'm hyped. Just released themed.janis.me/generator to showcase automatic theme generation by janis.me/themed. This app has exactly ONE color pre-defined. everything else is generated through chroma/lightness/hue alterations in SCSS. Yes, SCSS, not JS.
The themed.janis.me/generator website, showing some color inputs to automatically generate a color scheme. The SCSS and CSS code is visible as well
100
Janis Jansen 🌳 @janis.me · 22/04/2025
Was a bit inspired and updated themed-playground.janis.me It can now import external packages from unpkg.com, resolve `themed` code pre-bundled and has nicer error messages. Also has some new examples on how to use janis.me/themed
000
Janis Jansen 🌳 @janis.me · 09/04/2025
TIL that the Fahrenheit and Celsius scales meet at -40 (°?) How did I not know this before?
A chart that shows where the two scales meet. Around -the -40 mark, they are at (C left and F right)
-37	-34,6
-38	-36,4
-39	-38,2
-40	-40
-41	-41,8
-42	-43,6
-43	-45,4
-44	-47,2
100