Jacob Zwang --> Professional Work --> Research --> Hobby --> Resume ↗︎ -->
Hire Me ↓ -->


Began: Nov 24, 2021 | Status: Early Research

Content Disconnected UI

Are there benefits to separating UI from content?

Will animating UI elements help guide the user or distract the user?

Should UI ever move unprovoked or should it only be moved as direct feedback to a user's action?


By separating content from UI we will be able to create more dynamic experiences which can adapt to and guide the user based on their actions.

Potential Use Cases

Dynamic elements can serve as guides showing the user how to do something or directing their attention to what the result of their action is. Over time the guides can be disabled and the user will be left with a minimal, clutter-free UI.

Creating UIs with no visible buttons.

Allowing other users in collaborative tools to direct the user's attention to a specific part of the UI.


I created a handful of Svelte components which I will be using to explore the possibilities of this design pattern. This animation is not intended to pitch any kind of use case. It is purely a technical demonstration.

Mollit nulla et pariatur proident nostrud dolore nostrud. Sint exercitation dolore ut magna. Qui ad do dolor dolore non laboris. Fugiat nisi aliqua esse mollit ut ipsum irure. Reprehenderit incididunt est amet velit sunt commodo minim do qui mollit. Aliqua laboris dolore est cillum eiusmod voluptate cupidatat eiusmod do voluptate duis velit magna. Ad duis amet magna nulla velit. Nostrud amet sit cupidatat eiusmod do commodo nulla non non esse cupidatat consequat mollit. Sunt enim et exercitation cillum.

There are 3 components in my implementation

used for defining a context which scopes IDs and state within itself

used for defining an element that can be moved and animated

used for defining a place a DynamicElement can move to

↑ click

<Dynamic let:set>
	<DynamicElement id="main" initial="1">
		<div style="text-align: center;">
			<br />
			↑ click

<span style="position: relative">
		<DynamicTarget id="1">
			<button on:click={() => set('main', '2')}> dynamic target 1 </button>
		<DynamicTarget id="2">
			<button on:click={() => set('main', '1')}> dynamic target 2 </button>
Research to be continued

Began: 2020 | Status: In Development

Metaballs and Communication

The idea is to use metaballs and a system of layers to represent audio, video and message level communication channels. The user would be able to fluidly move from conversation to conversation, even placing themselves in multiple places. No discrete channels need to be created ahead of time, allowing users to dynamically form groups on the fly.

The Project has taken longer than expected due to unforeseen difficulties in high performance calculation of discrete metaball layers. The difficulty is not in displaying them, but in knowing if the metaballs are connected within the layer. My current implementation uses marching squares and is too slow for my needs. I've taken a break from development while I strengthen my skill set and I hope to return to this project soon.

Jacob Zwang Audio and Metaballs

Began: 2021 | Status: Early Research

CSS Error Messages

By using some of the more obscure css selectors it's possible to create rules for how html components and classes are used statically.

@mixin goal($message) {
    &:not(.ignore) {
        visibility: hidden;
    &:not(.ignore-error)::after {
        visibility: visible;
        color: rgb(138, 198, 255);
        content: '==> #{$message}';
        padding: 20px;
@mixin error($message) {
    &:not(.ignore-error) {
        visibility: hidden;
    &:not(.ignore)::after {
        visibility: visible;
        color: red;
        content: 'error: #{$message}';
        padding: 20px;
.article {
    margin: 60px;
    &:nth-child(2n + 0) {
        background-color: grey;
    &:empty {
        @include goal(':not(.article)');
    .article {
        @include error('.article cannot be a child of .article');
    &:not(div) {
        @include error('.article must be placed on <div>');
    &:not([class^='article s-']):not([class$='article s-']) {
        // the s- is so that svelte's generated classes still work
        @include error('.article must be exclusive');

goal of element/class

incorrect class usage

unallowed nesting

checking for other classes

Coming Soon

Redesigning Web Typography Using Svelte

Overdrawing & Horizontal Rhythm

Flex Based Operating System UI

Copyright © 2022 Jacob Zwang. All rights reserved.