Enhancing Elm: Understanding Getters, Proxies, and Performance Measurement

Measuring performance in Elm is a unique challenge due to Elm's functional nature, but I've got an interesting, hacky, solution. By mixing flags, decoders, getters, and proxies accurate performance measurement is possible in Elm. Let's take a closer look!

The Challenge of Measuring Performance in Elm

Elm's functional architecture brings its own set of challenges when it comes to traditional performance measurement. Elm is a purely functional language, so it doesn't have a way to get the time synchronously. This is because getting the time is an inherently impure call. If get the time, and then get the time a second later, it's not the same result. That's textbook functional impurity.

Generally speaking, the elm community will point you to flame charts and other tools to measure performance. However, these tools don't always provide the level of granularity needed to identify performance bottlenecks, and for newbies, they can be brutally difficult to understand. The greater Javascript Ecosystem can use APIs like Performance.

The JS Performance API

The performance API is a handy tool for measuring performance in JavaScript. It provides a way to create marks and measures, which can be used to measure the time between two points in code. It also provides a way to get the current time, which is useful for measuring the time it takes to run a function. However, all of this API is hidden behind function calls, and we can't use those synchronously in Elm. Our only option to call functions from elm is to use ports. Ports are both asynchronous, one-way, and are only run after the update function is finished. So they're not a great option for measuring performance in Elm.

As Elm Devs, we're stuck with the tools provided by the language. We can't use the performance API, and we can't use ports. So what can we do?

Exploring Flags and Side-Effects

Flags in Elm are super handy, they allow us to pass data into Elm from the outside world. Once it's in elm, we can decode it and use it as we please. Flags and Decoders are a fundamental feature of the language, and it's what we'll be exploiting in this hack.

The tricky part of this approach is that elm decoders can only access fields. So we can't just pass in a function and call it. There's no way to have a decoder run a function... or is there?

If we could somehow have some JS code run when a field on a JS object is read by Elm, we could theoretically, "call" functions from a decoder.

This is where getters and proxies come in.

Getters and Proxies

Getters are a feature of JavaScript that allows us to run code when a field is read.

const author = 
{ firstName: 'Jack'
, middleInitial: 'H'
, lastName: 'Peterson'
, get fullName() {
return `${this.firstName} ${this.middleInitial}. ${this.lastName}`;
}
};

author.fullName // Jack H. Peterson

I guess they're typically used for the situations above. I don't know, that's the only experience I had with them prior. However, they're also useful for our purposes; They allow us to run code when a field is read. If we had a JS object like this:

{ get now() {
return Date.now();
}
};

and If we ran it through a decoder like this:

import Json.Decode as JD

now : JD.Value -> Maybe Float
now =
JD.field "now" JD.float

We'd get the exact time the field was accessed. Because it returns the time the field was accessed, if we decoded this field later, it'd show a different time! This is because the getter is running the code every time the field is accessed.

The downside is we can't provide any arguments to the "function". Date.now() works because you don't need to provide any arguments, but if you did, getters would be useless.

However, if we wanted to run a function that took arguments, and we didn't mind getting wacky, we could use a proxy.

Proxies are a feature of JavaScript that allows us to intercept calls to an object and run code before the call is made. It's a bit like a getter, but it's more dynamic.

const handler = {
get(target, prop) {
console.log(prop);
return void;
}
};
const logger = new Proxy({}, handler);

logger.helloWorld // CONSOLE OUTPUT: helloWorld
logger["hello world"] // CONSOLE OUTPUT: hello world

That's pretty cool, we're not only able to run code when a field is accessed. We can also access an arbitrary field! We don't need to declare upfront all the possible fields, as long as we know we want something to be logged, we can use that "something" as the field!

If you passed the logger object into a decoder, you could put any String into the console.

import Json.Decode as JD

logger : String -> JD.Value -> Maybe Float
logger message =
JD.field message JD.float

We just ran a function with arguments from an Elm decoder. Wild stuff!

The Solution

The Shape of our JS API

What would the performance API look like if it didn't expose any functions, but instead used getters and proxies?

      const handler = {
// https://github.com/elm/json/blob/1.1.3/src/Elm/Kernel/Json.js#L230
has() {
// Elm checks if a field exists before accessing it.
return true;
// This bypasses that check by always asserting that the check is true.
},
get(target, prop) {
return {
start: () => performance.mark(`start--${prop}`),
end: () => performance.mark(`end--${prop}`),
measure: () =>
performance.measure(
`measure--${prop}`,
`start--${prop}`,
`end--${prop}`
),
}[target.type]();
},
};

const proxy = {
start: new Proxy({ type: "start" }, handler),
end: new Proxy({ type: "end" }, handler),
measure: new Proxy({ type: "measure" }, handler),
};

const performanceAPI = {
get timeOrigin() {
return performance.timeOrigin;
},
get measurements() {
const measureEntries = {};
performance.getEntriesByType("measure").forEach(({ name, duration, startTime }) => {
const key = name.replace("measure--", "");
measureEntries[key] = [{ startTime, duration }, ...(measureEntries[key] || [])];
});
return measureEntries;
},
get now() {
return performance.now();
},
get toJSON() {
return performance.toJSON();
},
// Dynamic Marks and Measures.
get start() {
console.log("Perf Started.");
return proxy.start;
},
get end() {
console.log("Perf Ended.");
return proxy.end;
},
get measure() {
return proxy.measure;
},
};

The Shape of our Elm API

What would our decoders look like if we used that wacky JS API?

import Json.Decode as JD
import Result

perfDecoder : JD.Decoder x -> JD.Value -> Maybe x
perfDecoder decoder =
JD.decodeValue decoder >> Result.toMaybe


timeOrigin : JD.Value -> Maybe Float
timeOrigin =
JD.field "timeOrigin" JD.float
|> perfDecoder


eventCounts : JD.Value -> Maybe (Dict String Int)
eventCounts =
JD.field "eventCounts" (JD.dict JD.int)
|> perfDecoder


type alias Measurement =
{ startTime : Float, duration : Float }


measurements : JD.Value -> Maybe (Dict String (List Measurement))
measurements =
JD.field "measurements"
(JD.dict
(JD.list
(JD.map2 Measurement
(JD.field "startTime" JD.float)
(JD.field "duration" JD.float)
)
)
)
|> perfDecoder


now : JD.Value -> Maybe Float
now =
JD.field "now" JD.float
|> perfDecoder


toJSON : JD.Value -> Maybe String
toJSON =
JD.field "toJSON" JD.string
|> perfDecoder


internal_start : String -> JD.Value -> Maybe Float
internal_start marker =
JD.at [ "start", marker ] JD.float
|> perfDecoder


internal_end : String -> JD.Value -> Maybe Float
internal_end marker =
JD.at [ "end", marker ] JD.float
|> perfDecoder


internal_measure : String -> JD.Value -> Maybe Float
internal_measure marker =
JD.at [ "measure", marker ] JD.float
|> perfDecoder

How could we use those decoders to measure performance in Elm?

import Json.Decode as JD

measure : JD.Value -> String -> (() -> fn) -> fn
measure perf tag fn =
internal_start tag perf
|> (\_ -> fn ())
|> (\passThrough ->
let
_ =
internal_end tag perf
|> (\_ -> internal_measure tag perf)
in
passThrough
)
{- This main function measures the duration of both the view and update function. -}
main : Program JD.Value Model Msg
main =
Browser.element
{ init = init
, view =
\model ->
measure
model.performanceApiFlagJsonValue
"view"
(\_ -> view model)
, update =
\msg model ->
measure
model.performanceApiFlagJsonValue
"update"
(\_ -> update msg model)
, subscriptions = \_ -> Sub.none
}

Warnings

Don't do this!

We're in the hacky parts of Elm here. I wouldn't be the slightest bit surprised if this approach breaks in the future. It's not a supported approach, and it's not a good idea to use this in production. It'd be best if you only used this approach for debugging and performance measurement, and even then, you should be careful.

It would be incredibly easy for Evan to update the Elm compiler so all JSON input is stringified and parsed before Elm could touch it. That would instantly and forever break this approach.

Proxies vs Getters

From a glance, it might seem like proxies are all-around better than getters. They're more dynamic, why don't we JUST use proxies?

Proxies are more complicated. Using proxies in other experiments, I've run into memory leak issues I still don't understand. From a performance perspective, they're also significantly slower than using a getter. Getters are only marginally slower than accessing a normal object. To test it yourself, check out this CodePen, and open the console.

Like all things, it depends, but I'd strongly recommend using getters unless you need the dynamic nature of proxies.

This post may vanish

I care about Elm more than I care about this blog post. If Evan feels this post is a problem, I will remove it.

Evan, you've created an incredible language, and I'm grateful for all the work you've put into it. If you feel this blog post is a problem, I will happily remove it. I don't want to cause you any headaches, and I don't want to cause any headaches for the community. I'm just trying to share my findings and help others. If you feel this blog post is a problem, I will remove it.

You probably don't need this hack.

I've had this proxy/getter/flag/decoder trick up my sleeve for a couple of years now, but I've been entirely unable to think of a situation where it's necessary. I've thought of a few situations where it might be useful, but I've never been able to justify using it. Maybe FormData or Navigator could be useful when wrapped in proxies and getters. The thing is, none of those REQUIRE this hack to work, you just need to call functions in the flag you're passing in or need a small port. It's way easier to do it the idiomatic way.

However, this API, the Performance API, seems like it requires this hack! So I was happy I had it stowed away, and now I'm happy to share it.

Conclusion

Here's an Ellie App with a working example of this approach: https://ellie-app.com/pYkP9NG6drWa1

Measuring performance in Elm might present challenges, but leveraging getters and proxies through flags opens new avenues. Responsibly experimenting with these techniques can help identify performance bottlenecks and enhance the user experience within Elm.

Remember, while this approach offers a workaround, it's essential to maintain code readability and strike a balance between optimization and maintainability.

Stay curious, keep exploring, and unlock the potential of performance measurement within Elm!

☃️ Shaking it Up

I've been itching to get some experience with the web APIs for the gyroscope, accelerometer, and all that other Sensor stuff. I just never really had a project which was interesting and easy enough to make the juice worth the squeeze. Building a Snow Globe was the perfect project.

🎶 Do you want to build a snow globe? 🎶

Here's the basic idea.

  1. Setup the appropriate sensors.
  2. Monitor a for a "shake".
  3. Fire off some confetti.
  4. Polish it a bit.

Step 1 & 4, unsurprisingly, accounted for 95% of the work.

I'll go through each step.

1) Setup the appropriate sensors.

This was rough. For whatever reason, browsers require SSL to use the sensors. Cool. Safety. I get it. Lots of cool web stuff requires SSL. The caveat to the SSL, is most APIs will work without SSL on localhost. The localhost makes it possible for devs easily tinker.

Here's the issue, my computer doesn't have an accelerometer for obvious reasons. So in order to test any of this sensor stuff locally, you'll need to set up SSL for your local network.

Yeesh.

Thankfully, browser-sync has an --https flag. This is the easiest workaround. Your browser will warn you that it's unsafe, but just blow through those warnings and your local dev setup is fine.

Now you can FINALLY test the sensors you're setting up.

So let's talk about the APIs.

The nice part of these APIs is they're all using the same foundation. There's an unusual quirk to them though: These sensors update their local state automatically. Totally novel for the web world. The events are just to signal that they've updated, or that there's an error. They don't even provide the sensor data! you gotta check the sensor you created and started to get that info. Once you unlearn the patterns the rest of the platform teaches you, you're golden.

I wish more web stuff worked like this. If you want to know if a button is being held, you need to monitor the pointerdown and pointerup events and basically maintain your own state machine. We just put up with stuff like this. It's wild!

Error handling is weird, but it's weird all over the web.

2) Monitor a for a "shake".

Once you grok the APIs, and set up a way to output the various sensors to your screen, round the numbers, and change framerate to 1 per second, then you can start to learn what these do. You can spend 2 hours reading about these sensors, and not truly understand what it means. Hold your phone which displays the readings for 20 seconds and you'll understand how they work in 20 seconds.

All of that just to say, My definition of a shake is met when the absolute values of x, y, and z from the LinearAccelerationSensor are summed together and exceed 20. That's a convoluted sentence, and still means nothing to me, but I'm happy with how it works. So that's good enough for a little tinkering project.

3) Fire off some confetti.

The homepage of skypack features a dead simple confetti package. It's great! It's configurable, and it even has a snow example. After a little copypasta and some minor tweaks, I got the snow working nicely. A shake would fire off confetti. It would take note of how the phone is being held and puff the snow up from the corner closest to the ground. If you shake harder, it sends the puff of snow further. I'm really pleased with this Package and it was dead simple.

4) Polish it a bit.

Apple sure does think different. Their APIs are different too. 😒

If you pull in a polyfill, negotiate the quirks, handle the user click requirements, and create sensible fallbacks if any of those things fail. You too could have something that already works on desktop and android, work on iOS! It'll only take around 2-4 hours, but hey that's a small price to pay so that the most wealthy company on earth can continue to keep their browser engine options locked down and under funded.

God bless Jen Simmons. She has been doing a great job bringing safari into 2022 fast, but there is still a long way to go.

Give it a whirl

jackhpeterson.com/s/snow-globe/ That's it! It was a fun project, took me a little while longer than I would have liked, but I learned quite a few things along the way. I hope you get a kick out of it, and maybe get inspired to build your own cool little project with one of many, lesser known APIs the web platform provides.

🗂 Why is file handing so tricky in node?

I've been working with node and 11ty, and 11ty has been pretty nice. It abstracts away a lot of the pain-points that node.js brings to the file system. But I can't help but feel that node needs a jQuery-like API for handling files.

$("blob/**/*.{html}").text()
$("blob/**/*.{md}")
.forEach((file) => file.content(file.html())
.save("dist/" + file.relativeSlug + ".html"))

I mean, how nice would that be? I don't use much jQuery these days, but I think that it has a solid API, especially when working with collections. Blobs seem like the css selectors of the filesystem domain.

Most files will have text. It seems like a pandoc powered plugin to normalize a ASTs could make unifying different text documents or converting formats trivial. I don't know why this doesn't exist yet. The filesystem seems like the ultimate place for a jQuery like api.

I might explore this more, see what it would take to make a prototype, but if I don't I'd still love for this idea to exist in some capacity somewhere. I know I'd use the hell out of it.

⛓ Daisy Chained

I love the idea of DaisyUI, but each time I try it it feels so limiting.

The rediscovery of DaisyUI inspired me to redesign my website, but as I went through the redesign, I found more and more areas that DaisyUI didn't quite live up to my hopes.

Thoughts

Utilities

First, the documentation, of the utilities is basically non-existent. It's really hard to discover what DaisyUI exposes, and how those utilities should interplay. You need to reverse engineer components to understand what utilities exist and how they work.

Components

These components are pretty opinionated on html structure, which is fine, I guess, but I tend to build non-interactive components myself to get them exactly how I want them. With interactive components, I'm VERY tempted to generalize the behavior. I think with the new :has() selector, making interactive components will be much more forgiving, and less-hacky. Things like the Toggle in Daisy UI are SO COOL! But I find myself only wanting a small portion of the library, and I don't think that's how DaisyUI really works. (Or at least it's not purging locally.)

Themes

They're cool, but largely impractical. Idk, I find one I like, and I stick to it.

Conclusion

I think I'll be stripping it from my site soon. I need to rename some classes, redefine some components, set up some interactive CSS. But I think it'll be worth it. DaisyUI is a little too clunky for my liking, it's close to greatness, but not quite there yet.

⬛️ Rainbow Etch Online

Here's the link to my Rainbow Etch Experiment

A while back I got an itch to make a scratch off rainbow sheet. It was a fun, quick, and rather easy project. Between paint-pad, CSS gradients, and mix-blending-modes.

I'd like to give a thank you to Steve Ruiz. This project was originally using his cool website tldraw.com in an iframe for the canvas. He could have blocked the iframe outright, but tweeted that he planned on blocking them soon. So I had time to transition this little demo to something else.

❤️‍🩹 Why leave a good thing behind?

I've been cheating on my beloved website. This very one. I've gone and built another, only to realize that I already had everything I wanted.

What I Missed

Good Bones

I have a good file structure. It's flexible in all the right places. I feel like adding new content is a breeze.

Built right

My build setup here is SO perfect. It's very minimal. Tailwind handles the CSS, 11ty handles the HTML. I might bring in esBuild to handle the JS.

None of these portions are overstepping their bounds. In my new setup, I tried to combine all of these, and it's a nightmare!

This site is basically sensible defaults that are easy to opt-out of. It's perfect.

Why I left

I wanted to tinker with different styles! I wanted to opt out of my CSS, explore DaisyUI. That's basically it.

However, while I was tinkering with ways to reduce my pages into components, I found a couple patterns I'm really digging.

So I've looted the new site of the gems it contained, and brought them back here.

I've created multiple tailwind configs, and am keeping them at a public URL.

I've building the CSS I need, when I need it.

I've reshaped a couple things on this site, but kept lofi spirit.


🗺 Road map

  1. Improve 404
  2. Improve chat
  3. Improve page organization
  4. Figure out x-html/11ty plugin
  5. Improve sidebar
  6. Expose games, books, and experiments
  7. Write docs and host my OSS stuff
  8. Rework the posts/post pages
  9. Improve head tag garbage
  10. Probably remove daisy-UI themes, (maybe keep interactive parts)
  11. Expose more tailwind vars (SystemColors, Interactive Colors, CurrentBackground, Dynamic Spacing, etc)

✍️ Ipads

I recently got an ipad and I like it quite a bit. It's fun doodling, or reading blog posts, and it's gotten me interested in building a proper blog, rss feed and the works. I don't think it needs to be anything incredible, but something simple and automatic would be great. Leaving shortform notes, or whatever would be fun. I've really been enjoying the super casual feed Chris Coyier has. It's lowkey, quick reads, and generally interesting.

The Ideal Stack

11ty, some CMS-esque thing, easy publishing, near automatic releases. It's hard to that CMS-esque thing. I've tinkered with quite a few options, and none of them were great. However, a coworker recommended logseq and although the logo is pretty dull, it looks incredibly powerful and simple.

The scariest part about it is all the graph stuff, and my excitement to really go deep on that. It seems so cool, and really opens up a blog to be less structured in a "narrative", since the stitching between notes is so simple and automatic. Reminds me of Project Xandu by Ted Nelson and the original promise of Hypertext. I want to tinker with logseq, I want to tinker with enhance.dev, @zachleat seems to be teasing 11ty 3.0. It's all so exciting and simple. All of it seems like a time sink if I'm not careful.

    🪴 Houseplants in 3D

    I've been looking for a reason to use <model-viewer> in my website. I've also been itching to get some "plants" into my website. When sarah found poly.pizza and I saw a way to kill two birds with one stone!

    The hardest part about this whole post was figuring out how to get flex to not ignore the padding on the right side, so silly. and I still don't fully understand why the solution works.

    20px
    20%
    .squircle

    🧼 Squircles!

    I love squircles, I think they look rad. They give a friendliness that can't quite be replicated with the standard CSS border radius. Nonetheless they're possible in CSS and with a Utility CSS mentality and some SVG finesse, they're not too difficult to implement.

    Simeon Griggs has a wonderful post on how to make them in CSS. I figured clip-path was the crucial part of the puzzle, yet I didn't want to deal with figuring out how it works and what's needed to get it going, thank goodness Simeon wrote his lovely post to explain how it works, and how to get it working!

    📌 Bookmarklets!

    Did you know you can run javascript with a URL?

    In place of a http: or https:, you can prefix a URL with javascript: and it will evaluate the following text as JS. You'll still need to URL encode the Text, but it does provide a handy way to use JS.

    Bookmarklets are a term for Bookmarks, which trigger some Javascript instead of loading a webpage.

    Some bookmarklets I use.

    Drag the Link into your bookmarks bar to use it yourself!

    • New Window Props

      This bookmarklet checks where your current window properties differ with the Initial window object.

      Handy for checking what global objects are declared when adding a js script

      New Window Props
    • Picture in Picture Mode

      Firefox has a PIP Button overlayed on videos. Chrome does not.

      Handy for triggering PIP mode on any webpage with a video.

      Picture-in-Picture

    🤖Face Mesh Experimentation

    ---------------------------------------

    This experiment was taken and modified from THIS PROJECT. This is using Tensorflow.js for the AI. I used skypack in devlopment and bundled it with Skypack.

    Initializing Face Scan...

    😱 Emoji OMG

    Pulling an emoji from text isn't super straightforward. There's no special character for emoji in regex.

    I'd like to start replacing the favicon for the page with a favicon found in the <h1> of the current section. So the first step is determining if there's an emoji in the <h1> at all. However, this task is tricker than it seems. EVERYTHING online indicates the best solution is a LONG LONG string of regex which tests the unicode data.

    I'll do some research and see if I can find a better way to do determine if a character is regex.


    My Findings!

    The typical advice you'll find online when searching for how to determine if a character is an emoji is to use RegEx, but I've found a MUCH easier way!

    Strings in js can be split into characters, and with the spread operator, it's easy!

    Splitting a String into Chars

        const string = "🤖: Hello World! 👋";
    const charList = [...string]; // [ "🤖", ":", " ", "H" [[...]] , "d", "!", " ", "👋" ]

    Which doesn't mean much on it's own. Frankly, it's more cumbersome to deal with. BUT! Javascript did something interesting! It didn't split up ALL the characters! As you can see from the any emoji regex example, Emojis are comprised of MANY characters! Those characters will render as a single, emoji.

    So JS is put in a weird position. The EXPECTED behavior of splitting a string, is accomplished. Yet, the LENGTH of each character, is technically different! Since Emojis are just unicode data rendered in a particular way, splitting a string does something fascinating in JS.

        "🤖".length; // outputs: 2
    "👋".length; // outputs: 2
    "📌".length; // outputs: 2

    What it means!

    Because JS splits a string by what is rendered, not by how it's represented in data, String.length does something super fascinating! It will give back a value greater than 1 for emojis!

    With this interesting tidbit, you can determine if a character in a string is an emoji! Furthermore, you are able to use the many Array Methods to deal with the characters!

        const string = "🤖: Hello World! 👋";
    const charList = [...string];
    charList.some(char => char.length > 1) // charList contains an emoji
    charList.filter(char => char.length > 1) // return an array of all of the emojis in charList
    charList.find(char => char.length > 1) // return the first emoji in charList

    I hope you found this helpful! I know it's much easier for me to deal with Emojis now.

    🥣 Ought Mealy

    Some days the web seems woefully under-equipt. Today is one of those days. Here is where I bloviate so I can look up to see if I'm right later.

    I think a large unaddressed issue with the web is mealy machines. AKA Transitioning States.

    For Example, This navbar was a bit more complex than I wished it to be because there's no way to determine scroll direction. A scroll event will take a snapshot in time and say: """ Yes! There was a scroll! Here's my current position! """ Gee, thanks DOM, that's mostly useless, but alright.

    To know scroll direction, you need to preserve state, and compare the new state to the previous state.

    This should be built into the browser right? I'd imagine this is useful information. However, there seems to be a philosophy with the web where previous states, aren't preserved. Thus, knowing much more than X event happened, seems far more difficult than you'd wish.

    I'm not sure if I have any great insight here, This seems to be something that has been worked around, but never really through. xState has inspired much of my thought on this, but it seems to be a tool, without much opinion on how it's implemented. Perhaps having a good Library to handle State transitions, would be helpful beyond just handling events. I mean the core of adios is making changes based on data changes, if I can find a nice API to work with the entire platform and its events it could be a useful tool for building websites.

    🌕 That's a Moiré

    A Moiré pattern is an interference pattern produced by overlaying similar but slightly offset templates. A simple example is obtained by taking two identical ruled transparent sheets of plastic, superposing them, and rotating one about its center as the other is held fixed.

    Such a neat little phenomena. I had to whip up a little example I could play with.

    Be careful, these examples can be disorienting, so proceed with caution.

    Click here to toggle the Moiré patterns
    radial-moire
    grid-moire
    horizontal-moire
    vertical-moire
    slash-moire
    speed-moire

    🤔 Rethinking Adios.js

    For the past year or so I've been kicking around a js library idea called adios.

    I still think adios is a nice idea, frankly I also think the DX is okay. I built it so I know how it works, which makes the issues less frustrating. But I also think underlying adios, is a more powerful idea.

    The core of Adios

    Adios isn't using witchcraft or dark magic. It's using 2 well supported web APIs and the event loop. That's really it.

    Mutation Observer

    This is an intimidating name with a complex API. However once you get a grip on what it does, it's pretty nice. It lets you know if the DOM has changed, before the browser paints the changes.

    Proxy

    This has a confusing name with an API that leaves a bit to be desired. However, once you work around the shortcomings, it's pretty nice. It lets you know when an object is being interacted with and how.

    What Adios Does

    Adios binds data to DOM elements. By putting data-text="path.to.string" in your HTML. Adios will keep your Data and DOM in sync. Moreover, it'll PULL data from the DOM, removing the need to "Hydrate". If anything, the DOM hydrates the Data.

    Whatever, All of that was preamble.

    The real nice part of adios is being able to easily create and tap into DOM and DATA events. Powered by Mutation Observers and Proxies respectively. I'd like to find a way to break it into smaller pieces. I'm not exactly sure what those pieces look like.

    Ideas

    I'd like to

    • create attributes that respond to custom events.
    • set up a generalized way to dispatch custom events.
    • omit and listen for data change events.
    • omit and listen for dom change events.
    • keep this centralized and extensible.
    • write basic js inline
    • make it feel nasty to write imperative JS vs Declarative HTML.

    👁 Viewport Events

    Call me crazy, I like inline events.

    Inline events are nice for quick and easy events which operate upon the idea of LOB. It's hard to beat the ease of use. However, it seems they were largely abandoned. Not sure why. I guess configuration can be strage in HTML?

    Regardless, I whipped up this quick example to illustrate how it makes life much easier as a Utility first oriented developer.

    How It works

    I leveraged quite a few nifty Web APIs.

    1. IntersectionObserver

      This API basically lets you know whenever an elements position on the viewport has changed. As you scroll elements, if you're observing them, you can determine a ton of details regarding their position. This is what we use to determine if we should be firing off our custom inline events.

    2. MutationObserver

      As you add new elements to the page, how do to make sure you're monioring those elements for these custom inline events? This solves that issue, it'll check every new element and attach an (Intersection)observer if relevant.

    3. Function()

      Takes a string, and some arguments and turns it into real JS without some of the issues things like eval, or script injection would introduce. This is what makes our custom inline events work under the hood.

    Take it for a whirl!

    Below there's a list with one <li.>. It's got a couple attributes. tailwind classes. An animate attribute which is just an attribute selector for our animate.css stylesheet to target. An on-reveal class which fires once when the element is brought into the viewport. An on-view-center attribute which fires when the element is in the center of the screen

    The inline on-reveal code does two things. First, it loads the next element. Then, it animates itself into view via the [animate] attribute.

    The inline on-view-center code replaces the title tag content with the content of the element.

    1. 1

    📏 Scale Experiements

    Scales in design systems are interesting, and kinda complicated.

    When designing something there are a million choices. Many of those choices are a waste of time. A design system is valuable because it reduces those pointless choices. There are many areas where designer need to make choices, Typography, Color, Composition, Spacing, and more. Limiting spacing options saves time when finding the best size for an element.

    An Example

    Let's say you're dealing with an icon, and it looks good at 30, 31, and 32px. Which is the "right" size? Perhaps 30px feels right because it's a multiple of 10. Perhaps 32px feels right because it's a multiple of 8. Well, without a design system, any value is fine. Heck, 31.23px is totally fine. But in reality, You know what you prefer. A design system provides a rule for yourself and your team, that 31.23px, is a value that shouldn't be explicitly used.

    But which values should be used?

    Tachyons

    Tachyons, (with inspiration from @stubbornella) uses an exponential scale. 2n. It's pretty nice! (1,2,4,8,16,32,64,128,256,512), It's great because you'll never question which unit works the best. There's a literal magnitude of difference between each unit. The downside is it lacks a lot of the smaller units which are handy for smaller elements. Think chips, these are much nicer when you have 2px-8px to fudge the areas between text, images, icons, and edges.

    Tailwind

    tailwindcss uses a bizzare linear system. Where each unit is 0.25rem or 4px. Yet, these units don't increment linearly. They increment in a nonsenical sort of way. Basically tailwindcss doesn't have a system for saying what's included and what isn't. 30 isn't a default, but 28 and 32 is. 40 is a default, but 38 and 42 are not. JIT, IDEs, and etc make this less of an issue, but it's still a strange, linear system which still expects fractions, especially at lower px values.

    My Scale

    The scale which I've been toying with is a hybrid of the two. At work, I evaluated all of the CSS being used, and I found that it doesn't really fit a linear scale well, nor does it fit an exponential scale super well. If you were to choose a range of values near the minimum and a range of values near the max. You'd see the gap between values is consistent, HOWEVER the size of that gap changes.

    So I found a pattern which matches that pretty closely.

    The scale will increment linearly in sets of 8. After a set of 8, the incrementing value is doubled. It sounds strange, but it works quite nicely. I'm not sure if I'm in love with 8. but designers do love 8. Perhaps 12 may work better? idk, overall the fusion of tachyons and tailwind scaling systems is pretty nice. I haven't been reaching for a value outside of the set, nor are there many values I'd never write by hand. Somehow, this scale scales very nicely.

    🔤 Variable Fonts

    Google fonts is great! Free, reliable, and now supports* Variable Fonts!

    I've astrixed support because there's a few big issues, from a UX perspective. SO I'll just list of a couple reasons why variable fonts via google are a bit rough right now.

    Issues

    Discoverability

    First and foremost, you can't see what they all look like. There's no filter on the main fonts page for variable, and the page that shows which fonts are variable fonts, DOESN'T show the fonts, it only lists them!

    No UI

    YOU have to handwrite the URL. Between the super strange syntax, some unexpected quirks, andexpecting you to alphabetize their parameters. It's a headache.

    Docs are rough

    I'm not super certain how to use the parameters. Weight is straighforward enough, but any other variable has me a bit stumped. If you know how to do it, shoot me a DM on twitter.

    Better Discoverability

    I'm really only addressing discoverability here, but regardless. Below I've listed every variable font available via google fonts, with a slider to change the weight of the font.

    It's not much, it's imperfect, yada, yada, yada.

    • Alegreya

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Antonio

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Archivo

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Arimo

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Asap

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Assistant

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Bitter

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Bodoni Moda

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Brygada 1918

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Cabin

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Catamaran

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Caveat

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Changa

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Cinzel

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Comfortaa

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Commissioner

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Crimson Pro

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Cuprum

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Dancing Script

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Domine

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Dosis

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • EB Garamond

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Encode Sans

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Epilogue

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Exo

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Exo 2

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Faustina

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Fira Code

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Fraunces

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Grandstander

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Grenze Gotisch

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Heebo

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Hepta Slab

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Ibarra Real Nova

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Imbue

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Inconsolata

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Inter

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • JetBrains Mono

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Josefin Sans

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Josefin Slab

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Jost

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Jura

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Karla

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Kreon

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Kufam

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Lemonada

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Libre Franklin

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Literata

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Lora

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Manrope

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Manuale

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Markazi Text

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Maven Pro

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Merriweather Sans

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Mulish

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • MuseoModerno

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Newsreader

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Orbitron

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Oswald

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Oxanium

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Petrona

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Piazzolla

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Playfair Display

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Podkova

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Public Sans

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Quicksand

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Raleway

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Recursive

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Red Rose

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Roboto Mono

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Roboto Slab

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Rokkitt

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Rosario

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Rubik

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Ruda

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Saira

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Sansita Swashed

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Signika

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Sora

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Space Grotesk

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Spartan

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Syne

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Texturina

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Trispace

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Truculenta

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Varta

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Vollkorn

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Work Sans

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    • Yanone Kaffeesatz

      Lorem ipsum dolor sit amet consectetur, adipisicing elit. Eum vero consequuntur esse nihil iste dolor dolorem totam repellendus voluptatum eveniet beatae pariatur, impedit nulla minus modi ex numquam quam rerum.

    💦 Spitballin'

    Per page ideas

    • favicon
    • title
    • URL
    • navbar text
    • load next/last post

    11ty could help keep data across pages easily accessible.

    • next/last blog
    • next/last nav-layout
    • Socials
    • Tags
    • RSS
    • sitemap
    • Adding IDs for tags!

    More obvious 11ty rationale

    • making the CSS for each post modular (namespaced)
    • 11ty could also help me convert these posts from messy >pre< tag nonsense into proper html.
    • Building THE actual pages for each post. In theory this site should flow organically, That doesn't negate the need for good links though!

    Performance

    • I should host all the assets.
    • I should JIT the tailwindcss
    • Perhaps I should load Adios at the top of the page?

    ERA Ideas

    • Check through my codepens, see if there's anything cool
    • Container Queries would be fun to test
    • I think it'd be interesting to try using grid and span

    👋 My Site

    🤨 The Problem

    I'm sure you've seen hundreds of developer sites, and thought: Damn, I need to redesign my whole site. I've gotten sick of remaking my site countless times just to have my ambition fizzle out before I ship it. I didn't want to crush my desire to rebuild my site all the time. It's hard finding a cool idea you want to explore, but finding ways to make it work with your current site, or throw it out and start over.

    🥅 The Goals

    There are a couple things I'd like to be able to do: Allow my site to be flexible, Allow my ambition to be small, Persist old pages but most importantly, allow my site to evolve.

    💡 The Idea!

    It's a pretty dumb idea, but I hope it works as the site grows. Essentially, I'm going to build my site as a LONG scroll. Just one big ol' page in chronological order. I think normally this would be a disaster, but the web has changed, and so has my perception of it. Plus there are a bunch of great tools to assist me in this endeavor.

    📐 The How

    This whole concept hinges on a few web concepts.

    The new CSS :where() psuedo selector

    This new CSS psuedo selector can totally kill any specificity, and can scope without creating specificity issues with utility css and other more opinionated tools. If CSS is prefixed with a :where(.namespace), there shouldn't be any CSS leaking between pages.

    CSS Scroll Snap

    This CSS rule is nice. Think how tik-tok is just 1 LONG page full of videos. Normally that would be CHAOS and a total nightmare. However, only one video can be in frame at once, so it doesn't feel like 1 page, full of hundreds of videos, but rather 1 video per page. I hope to create that UX with this website.

    HTMX

    Perhaps I will use HTMX, perhaps I wont. Regardless, the perception shift HTMX created has influenced this idea. There are 3 parts where HTMX has inspired this: First, the idea of just using HTML over the wire. Second, the little on-event-attribute that fires when something rolls into view. SPA like behavior by pulling a full html document and combining it with the current html document.

    TikTok

    Lol, Dumb. But the UI/UX for that app is pretty neat. ALL VIDEOS EXIST ON THE SAME PAGE WHICH IS INSANE. but the scroll snap makes that point far less obvious.

    The Vue3 Composition API

    I don't know what to call it, It's not a Vue only idea, but was largely popularized by it. Essentailly, you just write code where it'll live. Styles/HTML/Scripts. I call it a triple, but I'm not sure what it's called. Basically this pattern is ideal IMO. It's perfect for first page loads, and I find it really to reasona about. Everything lives on one file, no running from file to file, trying to understand what file, added to what build process, created the bundle output that's giving you trouble.

    💫 Mix it up.

    I think the scroll snapping will make multiple-pages on one scroll more approachable. :where() will give my triples, the ability to namespace without creating specificity headaches for my utilityCSS. HTMX will handle combining the individual HTML pages together client side. 11ty will take these raw triples I make, and combine them with a valid HTML template, and set up loading previous and next pages when a page is scrolled to.

    👋 Conclusion

    It'll likely get messy. There will be mistakes I make. but I think I can keep nav elements sticky, and allow posts to exist within those nav eras. I think this is a pretty neat idea, I'm interested in exploring it, I'll keep this page updated with the progress I'm making or why I've decided to abandon it.