Hi I'm Karl,

I Design and build Apps, Websites, and Teams.

Bootstrapping Capsule.Graphics.

Send me an Email at me@kow.fm.
Karl Oscar Weber



In January 2024, I was laid off. It was sudden, and extremely rude. I found out during standoff. Soon after my work accounts stopped working. I had poured so much into that job. The people, and the environment. I worked really hard to make it a great place for the folks on the team, and to support them any way that I could. But all for naught.

That's alright, time to learn and move forward. I spent a couple of weeks trying to figure out what was next for me. What am I really good at and what do I want to do? You know, besides the necessity to pay for rent, utilities, and food. Also I have a wife and 4 kids. Gotta provide for them too. It's kinda important.

After a while I figured out what I wanted to do. Everything.


Friends, I'm serious. I really like Art and Design stuff, been doing it on the side for like 20 years. Over the last couple of years I've gone through an existential change in how I see things. "Why the fuck not?!?!" Is often going through my mind. I'm more confident than I've ever been and it fucking shows. I'm just getting better at my job.

So the thing I want to do for the next 40 years is a subscription studio. I call it Capsule.

Capsule is everything

There's been this concept going around of agencies or studios delivering unlimited design services for a flat monthly fee. A retainer basically, but not really. It's a subscription. Usually a subscriber is limited to one "request" or task at a time. So that the provider of services can rotate through their clients, Deliver value, then await for feedback.

I think this model is pretty cool. Paid upfront, the price is low enough that it can be a subscription, and all the work I can handle. It's pretty swell. Actually.

The only way to get better/faster.

Is to do more work. That's it. Quantity == Quality. Rise and Grind my friends. I'm pretty good at my job, but I want to be even better. Fast and Furious. The only path I see to doing that is straight through. Do as much work as I can, as fast as I can. So that's what Imma do.

Capsule has 3 plans, Rocket, Pro, and Bell Grande. The Rocket plan offers Art, Design, and websites. That's front end work writing HTML and CSS. Pro Also offers Ruby and iOS development, and Bell Grande is just 3 times bigger than Pro. It's like having a small startup team working for you furiously. The prices are $999, $1,999, and $5,999. But all the plans are 50% off for the first 10 customers or until the launch month ends, whichever comes first. So it's way cheaper and it's like an 83% discount off my normal rate. It would be crazy not to subscribe, CRAZY! The discount lasts until you cancel. It's that simple.

Anyways friends. That's what I'm doing. Capsule, Get some.

Karl Oscar Weber

I started writing a programming language

Hi friends,

I started writing a programming language in Lua. Lua is fast, small, embeddable, extendable, and has a Garbage Collector. I want to write something that is simple to parse, extensible, and purpose built for writing and working with UI on the web.

Originally I wanted to dig deep into coffeescript to figure this out, I still might do that, but CoffeeScript has a syntax that irks me. I wondered if it would be easy enough to write an interpreter that compiles to another language. Like CoffeeScript to Javascript. I figured that it's gotta be possible, Right? I mean, people have DONE this before. But the issues I have is that CoffeeScript IS Javascript with a mask on and some bits hidden/removed. I want to make something that kinda starts from scratch, Fresh and new with some lessons.

WASM is a thing. So why not write a language that's embedded in your browser? That could be cool right? I'd love to just ship my programming languages files like javascript files, or write it directly on my website, and see it just work. Try to bring some of that magic back. With a stable WASM interpreter I could push that to a CDN and then folks hitting the pages with this language would only need to download the interpreter once.

What's next?

Well, I guess I need to get the basics of the thing working. An interpreter, some Variables, math, and a REPL. Follow along here: https://github.com/karloscarweber/stim

Karl Oscar Weber

So you want Ruby to grow?

A very flat looking pinkish Ruby shape thing, with a few other rubies fanning out beneath.

So you like Ruby, and the Ruby community, and you want it to grow? What should you do?

1. Write stuff for beginners.

Always, and first, and primarily, and when you think you've done enough, write more for beginners. I cannot tell you how important it is to write for beginners. The stagnation of new Ruby developers, junior developers, can be attributed to a lot of factors, but the primary factor is that the moment a beginner makes it out of the getting-started page, everything else is for Computer Science Majors/Ruby lovers/Expert Developers. Basic concepts are ASSUMED, which I guess makes sense, but also mildly complex concepts are also ASSUMED. All of this assumption means that practically any tool that Rubyists write for one another is not user friendly.

"But I understand this KOW! This stuff is easy for me."

Right Right Right, but you're not a beginner. If you've been in the Ruby game for about 2 years things start to make a lot more sense. But if you haven't been doing it for that long it's just still a little magical and hand wavey. A lot of Ruby's utility comes from it's metaprogramming abilities, but those take some time to truly grasp.

So please, write stuff for beginners, write more than just "Documentation". Write Getting-started guides, How-to guides, Common use cases documentation, plus examples in standard ruby and with at least 2 frameworks. Bonus points if neither are Rails.

Also please review some basic Ruby stuff when talking about your framework. Dig in a little. Don't assume that we know how this works. We don't. Make it easy to be successful with your code.

2. Focus on Diversity, Equity, and Inclusion.

I know that some folx don't think it's important. Those folx are wrong. and Stupid. Expanding Ruby means finding people that are overlooked, under-appreciated, and then supporting them. I don't know if ya'll have noticed but almost all tech people are hella white. Just whitey tighties all up in here. Me too. Male, White, Heterosexual, Cis-Gendered, Heck I'm even Christian. I know across the pond and out East it looks a lot different.

Growing Ruby requires building strong community outreach, training, retention, and promotion of folx that don't look like, think like, or talk like the majority of Ruby developers today. I'm serious. If you look around at the current "tech" landscape today. What people are using to make their websites and apps. You won't notice that folx are making these decions based purely on the merits of a technology. It's based on Culture and perception. A whiteness centered culture has driven folx to widely adopt some bad tech. This is a direct result of prioritizing the needs of young, childless, single, white men. People who can work for hours or days on a problem because they hav nothing else to do.

Getting more folx to use Ruby, means going against the grain of tech culture itself.

Give these folx raises, a seat at the table, Hell a piece of the table. Bringing people in to Ruby that aren't already there means accomodating them. Increasing the realm of what's possible. What does that mean? fewer hours? more flexible work schedules? More mentorship? It means doing whatever it takes to bring these folks into the community. Including financial help. Drop a couple of Ks a year, at least, to sponsor, promote, or support under-represented folks coming into the Ruby community.

Forge strong connections with beginners, help them to build their professional networks. We're not getting hired based on our resumes, that almost never really happens. And if that's not the case then we ought to be helping, maybe even focusing on building these relationships with newcomers.

Also NEVER dictate what a donation or support should be used for. People know what to use their money on. Once you give them money, it's theirs.

There is this really silly... assumption? phrase? The best person for the job. The best person for the job doesn't exist, also who cares. We need to find people who are motivated, and kind. Folx that want to grow and improve. The junior developers of today, are the staff engineers of tomorrow. A beginners perspective sheds light on the spaces infrequently seen by an expert. The entrance.

Don't take my word for it. Read Kim Crayton.

3. Promote Framework diversity.

I am biased because I've been performing Necromancy on Camping for over a year. But sincerely, do your best, BEST, to promote framework diversity. A mono culture breeds in weakness. Everyone using Rails when they use Ruby means that only a certain narrow band of problems are easily addressed. It means that different perspectives or priorities are ignored.

Like Motoko Kutsanagi says: "If we all reacted the same way, we'd be predictable, and there's always more than one way to view a situation...It's simple: overspecialize, and you breed in weakness. It's slow death."

So too goes the Ruby way. Overspecialized in a single monolithic framework, All Roads, well rails, lead to… well rails.

Some Great alternative frameworks and tools:

The monoculture is really bad, but there are great signs of this changing. The rise of Hanami and Roda as framework alternatives. The steady march of progress with RACK and it's associated projects. Sinatra just got a brand new release. Phlex, a new templating and component library, seemingly brought to life from nothing in about six months by Joel Drapper, and it's fast as hell. The joy around writing with ruby hasn't abated, and genuinely feels like it's accelerating.

4. Teach more than just Ruby!

This is a big one! Most of what we're doing is making websites. There is no ruby on a webpage. I bet you didn't know that it was just a bunch of HTML,CSS, and Javascript. But it is. Like for reals.

Recently I had the necessity to make a mostly static website, I tried out Bridgetown for the first time, and it was great. Almost no hickups, and I used just regular old HTML, CSS, and JavaScript. Almost no JavaScript also. Kids these days think that you need complicated build processes to get a site online. Every "Hello World" or "Crud App" looks so bad because they are devoid of styles. Exceptions to this are few.

If you want to get folks to adopt Ruby, make it easy for them to understand the problem they have, and to find the solutions to the problem they have. Teach the whole enchilada. Top to bottom. Give examples and use cases. I know ya'll know how to do this stuff.

Teach around the problem. Keep folx in your documentation and solve as much of the problem as you can. Hell it will be reference for yourself in a few weeks when you forget something basic anyways.

5. Excise harmful folx

Kick em out. Are they being Racist DumbHasHasses? Show them the door. Are they taking credit for other folx work? Get outta here. Genius is a myth, aint nobody got it.

Harmful, bigotted, and prejudiced folx drive away the exact people you want to bring into the community. They gatekeep and centralize power and influence. Centralized systems have a single point of failure. When it comes to people, it makes a community brittle, poised to either break and fracture, or pull the whole lot down a darker path. Harmful folx narrow perspective, and thus, awareness of what's possible or important.

This may not be a completely bad thing though. The majority of the reason I'm working on Camping, and focusing on this community, is sheer rage at the idiocy of some folks here. A combination of Rage and Sunk Cost Fallacy.

My dad always said that sometimes anger can be a great motivator. Something won't get fixed until you get angry enough to go fix it yourself. That's why I'm here folks. I'm hella Angry.

Karl Oscar Weber


A square canvas featuring the word POP written all over it in a several colors. Looks dope!

I feel socially isolated by the structure of the place I live in. I like Art, Design, and Culture. Outside of the black mirrors I have, I don't see it, hear it, or experience it.

The physical structure of Western America is shit. Everything requires a car. A car to here, a car to there. The cars are expensive, and dirty, and fucking suck. We live in houses, single family homes. With a nice big buffer between each house. I never see my neighbors except when i glimpse them moving to or from their cars and their homes.

Society is designed to keep us poor, tired, stupid, isolated. To wring out the creativity from our souls, to leave us empty and dross. It is designed to be this way.

We can design something better, but it will take intention. We can improve our lives, and the lives of our neighbhors, but it will require a fuck ton of work. I wnat to do that work but I'm not sure how to start. Maybe I'll write my name on every wall I find. See if that helps.

Karl Oscar Weber

Fluid Type Scales with Utopia

Fluid Type Scales with Utopia

Responsive websites are really cool. Most websites are responsive now. It's just how we do things. But how we get to a responsive website isn't always so easy. We end up with results that are... inconsistent to say the least.

A few years ago some interesting fellows proposed a completely fluid type scale to help us adapt our letters to smaller and larger screen sizes. They called it Utopia.

The problem™ is that good typography has a sort of hierarchy, and a relationship to that hierarchy. Headings are LARGE, and subheadings are not so large, text is normal sized. On large screens the gap between these sizes are bigger than they ought to be on smaller webpages. Traditionally these changes are achieved through media queries:

h1 {
    font-size: 1.5rem;
    line-height: 1.1; 
    @media (min-width: 375px)  { font-size: 2rem; }
    @media (min-width: 640px)  { font-size: 2.5rem; }
    @media (min-width: 960px)  { font-size: 3rem; }
h2 {
    font-size: 1.25rem;
    line-height: 1.2;
    @media (min-width: 375px)  { font-size: 1.5rem; }
    @media (min-width: 640px)  { font-size: 1.75rem; }
    @media (min-width: 960px)  { font-size: 2rem; }
p {
    font-size: 0.875rem;
    line-height: 1.5;
    @media (min-width: 375px)  { font-size: 1rem; }
    @media (min-width: 640px)  { font-size: 1.125rem; }
    @media (min-width: 960px)  { font-size: 1.25rem; }

This is a contrived example, but shows that the ideal size for our text is different across screen sizes:

Font Type Scale showing type scaling from small to large.

Clever folks have found out that setting your type at different sizes is more pleasing if there is a consistent ratio between those sizes. Let's say, like a third smaller, or a third larger at each step. It might look something like this:

5 rows, each has a type size, a circle that matches the size, and some sample text that is the text size of that row. The circle size and sample text descend in size by a third in each row. Thsi shows visual hierarchy in type sizes.

We call this phenomenon a Type Scale.

Fluid type scales respond to the viewport size. Smaller screens have less space, the gap between sizes on the scale should be smaller than on our big screens. A smaller, mobile type scale might look like this:

A Mobile type scale consisting of 5 rows. Each row has a pixel size label, a circle that matches the pixel size, and some text that matches the pixel size. The rows are smaller as they descend.

As you can see the type scale looks different. It's smaller, and the change in sizing is smaller too. The type scale begins at 16px and increases by 20% at each scale. A less dramatic change than beginning at 20px and increasing by 33.3% each scale.

Executing A Fluid Type Scale in CSS

Thanks to CSS Variables we can execute fluid type scales:

/* @link https://utopia.fyi/type/calculator?c=320,16,1.2,1280,20,1.333,4,0,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&g=s,l,xl,12 */

:root {
  --fluid-min-width: 320;
  --fluid-max-width: 1280;

  --fluid-screen: 100vw;
  --fluid-bp: calc(
    (var(--fluid-screen) - var(--fluid-min-width) / 16 * 1rem) /
      (var(--fluid-max-width) - var(--fluid-min-width))

@media screen and (min-width: 1280px) {
  :root {
    --fluid-screen: calc(var(--fluid-max-width) * 1px);

:root {
  --f-0-min: 16.00;
  --f-0-max: 20.00;
  --step-0: calc(
    ((var(--f-0-min) / 16) * 1rem) + (var(--f-0-max) - var(--f-0-min)) *

  --f-1-min: 19.20;
  --f-1-max: 26.66;
  --step-1: calc(
    ((var(--f-1-min) / 16) * 1rem) + (var(--f-1-max) - var(--f-1-min)) *

  --f-2-min: 23.04;
  --f-2-max: 35.54;
  --step-2: calc(
    ((var(--f-2-min) / 16) * 1rem) + (var(--f-2-max) - var(--f-2-min)) *

  --f-3-min: 27.65;
  --f-3-max: 47.37;
  --step-3: calc(
    ((var(--f-3-min) / 16) * 1rem) + (var(--f-3-max) - var(--f-3-min)) *

  --f-4-min: 33.18;
  --f-4-max: 63.15;
  --step-4: calc(
    ((var(--f-4-min) / 16) * 1rem) + (var(--f-4-max) - var(--f-4-min)) *

Notice in the code above that we have the --fluid-min-width and --fluid-max-width set to 320 and 1280 respectively. These are our limits. Our fluid sizes will reach their smallest at the lowest limit, and their largest at the biggest limit. This also prevents our text from shrinking or growing without end. (The math is difficult to parse without a minor lesson in algebra, so let's not do that.)

You can achieve the same effect, although with a bit less precision, and precalculated, with clamp:

/* @link https://utopia.fyi/type/calculator?c=320,16,1.2,1280,20,1.333,4,0,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&g=s,l,xl,12 */

:root {
  --step-0: clamp(1.00rem, calc(0.92rem + 0.42vw), 1.25rem);
  --step-1: clamp(1.20rem, calc(1.04rem + 0.78vw), 1.67rem);
  --step-2: clamp(1.44rem, calc(1.18rem + 1.30vw), 2.22rem);
  --step-3: clamp(1.73rem, calc(1.32rem + 2.05vw), 2.96rem);
  --step-4: clamp(2.07rem, calc(1.45rem + 3.12vw), 3.95rem);

The above is much easier to parse, but the calc parts present a mystery. Using these type scales is thankfully easy:

body { font-size: 100%; }
h1 {
    font-size: var(--step-3);
    line-height: 1.1;
h2 {
    font-size: var(--step-2);
    line-height: 1.2;
p {
    font-size: var(--step-0);
    line-height: 1.5;

A Fluid type scale without media queries!

No perfect Sizes.

A key tenet of fluid type is that there are no perfect font sizes. Which is pretty rad when you think about it. What matters is the relationship of the type sizes to one another, and the intended maximum and minimum size. When you don't have to worry about perfect type sizes, you're allowed to think in more abstract, role based ways. Is this a Heading? or a SubHeading? Content text or a blockquote? Should it be large, or small. By excising pixel perfect requirements for our text we instead have text with perfect, or intended relationships. It's these relationships that we care about. Once again to add emphasis and hierarchy to the page. Implicit Harmony.

The best time to adopt a fluid type scale is during a redesign or new site buildout. A refactor is also a good time. Adopting fluid type will make documenting and managing a design system much easier. You can lean on the intended type sizes in your components, and quickly build relationships between your content and compnents.

If you've been hesitant to try fluid type before I encourage you to adopt it. It kicks ass and will make your websites look very Schway.

Karl Oscar Weber

Ruby Camping

Hi Friends,

Camping is a micro web-framework written in Ruby. Originally written by _why the lucky stiff, (Their real name), Camping was a pretty popular framework a few years ago, but over time just slowed down. Now Camping is actively maintained and improving.

One of the best things about Camping is how compact it is, The whole thing is about 4kb:

class Object;def meta_def m,&b;(class<<self;self
end).send:define_method,m,&b end;end;module Camping;C=self;S=IO.read(__FILE__
)rescue nil;P="<h1>Cam\ping Problem!</h1><h2>%s</h2>";U=Rack::Utils;O={url_prefix:""};Apps=[];
SK=:camping;G=[];class H<Hash;def method_missing m,*a;m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m.
to_s]:super end;undef id,type if ??==63 end;class Cookies<H;attr_accessor :_p;
def _n;@n||={}end;alias _s []=;def set k,v,o={};_s(j=k.to_s,v);_n[j]=
{:value=>v,:path=>_p}.update o;end;def []=(k,v)set(k,v,v.is_a?(Hash)?v:{})end
end;module Helpers;def R c,*g;p,h=
/\(.+?\)/,g.grep(Hash);g-=h;raise"bad route"if !u=c.urls.find{|x|break x if
x.scan(p).size==g.size&&/^#{x}\/?$/=~(x=g.inject(x){|x,a|x.sub p,U.escape((a.
to_param rescue a))}.gsub(/\\(.)/){$1})};h.any?? u+"?"+U.build_query(h[0]):u
end;def / p;p[0]==?/?@root+p : p end;def URL c='/',*a;c=R(c,*a) if c.respond_to?(
:urls);c=self/c;c=@request.url[/.{8,}?(?=\/|$)/]+c if c[0]==?/;URI c end end
module Base;attr_accessor:env,:request,:root,:input,:cookies,:state,:status,
:headers,:body;T={};L=:layout;def lookup n;T.fetch(n.to_sym){|k|t=Views.
method_defined?(k)||(t=O[:_t].keys.grep(/^#{n}\./)[0]and Template[t].new{
new(f,O[f[/\.(\w+)$/,1].to_sym]||{});O[:dynamic_templates]?t: T[k]=t} end
def render v,*a,&b;if t=lookup(v);r=@_r;@_r=o=Hash===a[-1]?a.pop: {};s=(t==true)?mab{
send v,*a,&b}: t.render(self,o[:locals]||{},&b);s=render(L,o.merge(L=>false)){s
}if o[L]or o[L].nil?&&lookup(L)&&!r&&v.to_s[0]!=?_;s;else;raise"no template: #{v}"
end;end;def mab &b;extend(Mab);mab(&b) end;def r s,b,h={};b,h=
h,b if Hash===b;@status=s;@headers.merge!(h);@body=b end;def redirect *a;r 302,
'','Location'=>URL(*a).to_s end;def r404 p;P%"#{p} not found"end;def r500 k,m,e
raise e end;def r501 m;P%"#{m.upcase} not implemented"end;def serve(p,c)
(t=Rack::Mime.mime_type p[/\..*$/],Z)&&@headers[E]=t;c;end;def to_a;@env[
@cookies._n.each{|k,v|r.set_cookie k,v};r.to_a end;def initialize env,m
r=@request=Rack:: Request.new(@env=env);@root,@input,@cookies,@state,@headers,
H[r.session[SK]||{}],{E=>Z},m=~/r(\d+)/?$1.to_i: 200,m;@cookies._p=self/"/" end
def n h;Hash===h ?h.inject(H[]){|m,(k,v)|m[k]=
n(v);m}: h end;def service *a;r=catch(:halt){send(@method,*a)};@body||=r;self
end end;module Controllers;@r=[];class<<self;def R *u;r=@r;Class.
def v;@r.map(&:urls);end;def D p,m,e;p='/'if
!p||!p[0];(a=O[:_t].find{|n,_|n==p}) and return [I,:serve,*a]
@r.map{|k|k.urls.map{|x|return(k.method_defined? m)?[k,m,*$~[1..-1].map{|x|U.unescape x}]:
[I, 'r501',m]if p=~/^#{x}\/?$/}};[I,'r404',p] end;
module F;A= ->(c,u,p){u.prepend("/"+p) unless c.to_s == "I"}end;N=H.new{|_,x|x.downcase}.
merge!("N"=>'(\d+)',"X"=>'([^/]+)',"Index"=>'');def M(pr);def M(pr);end;constants.
@r=[k]+@r if @r-[k]==@r;k.meta_def(:urls){[F::A.(k,"#{c.to_s.scan(/.[^A-Z]*/)
.map(&N.method(:[]))*'/'}",pr)]}if !k.respond_to?:urls}end end;I=R()end;X=
Controllers;class<<self;def routes;X.M O[:url_prefix];(Apps.map(&:routes)<<X.v).flatten;end;
def call e;X.M O[:url_prefix];k,m,*a=X.D e["PATH_INFO"],e['REQUEST_METHOD'].
downcase,e;k.new(e,m).service(*a).to_a;rescue;r500(:I,k,m,$!,:env=>e).to_a end
def method_missing m,c,*a;X.M O[:url_prefix];h=Hash===a[-1]?a.pop: {};e=H[Rack::MockRequest.
send"#{i}=",v};k.service(*a) end;def use*a,&b;m=a.shift.new(method(:call),*a,&b)
meta_def(:call){|e|m.call(e)}end;def pack g, *a, &b;G<<g;include g;
extend g::ClassMethods if defined?(g::ClassMethods);g.setup(self)if g.respond_to?(:setup)end;
def gear;G end;def options;O end;def set k,v;O[k]=v end
def goes m,g=TOPLEVEL_BINDING;Apps<<a=eval(S.gsub(/Camping/,m.to_s),g);caller[0]=~/:/
IO.read(a.set:__FILE__,$`)=~/^__END__/&&(b=$'.split /^@@\s*(.+?)\s*\r?\n/m).shift rescue nil
a.set :_t,H[*b||[]];end;end
module Views;include X,Helpers end;module Models;autoload:Base,'camping/ar'
Helpers.send:include,X,self end;autoload:Mab,'camping/mab'
autoload:Template,'camping/template';C end

Because Camping is intended to be as compact as possible, single file apps are encouraged. Which is pretty cool.

Camping.goes :Nuts

module Nuts
  module Controllers
    class Index
      def get
        render :index
  module Views
    def index
      h1 'Hello World'

Also because single file apps are a thing, more than one "app" can be mounted together:

Camping.goes :Nuts # Nuts app is mounted.
# ... Nuts module here

Camping.goes :Blog # Blog app is mounted.
# ... Blog module here

A Camping app is just a module mounted within a namespace, either the global namespace, or another app's namespace. This makes distributing an app via RubyGems pretty easy too.

Camping's default view architecture uses MAB which is an HTML generator in Ruby.

module Views
  def index
    if @posts.empty?
      h2 'No posts'
        p do 
          text 'Could not find any posts. Feel free to '
          a 'add one', :href => R(PostNew)
          text ' yourself'
      @posts.each do |post|

I've been updating Camping to have better database support. It comes with built in support for ActiveRecord, but what about other database engines? Through a new plugin system called gear, I'm adding support for different database systems. In the next version the built in ActiveRecord integration is being moved to some Camping Gear named GuideBook:

require 'camping'
require 'guidebook' # Guidebook adds ActiveRecord to Camping.

Camping.goes :Nuts

module Nuts

  # In Camping you Pack Gear.
  pack Camping::GuideBook

  module Models
    class Page < Base; end

  def self.create
    # establishes a database connection when the app is created.
  # ... Controllers, Views, Helpers.

Camping has some tricks up it's sleeves. Like adding styles and other files to the end of your camping code:

# ... The rest of your camping app up here


@@ /style.css
* { margin: 0; padding: 0 }

Camping is based on Rack so adding middleware is pretty simple:

require 'camping'
require 'warden'

module Nuts
  use Warden::Manager do |manager|
    manager.default_strategies :password, :token
    manager.failure_app = BadAuthenticationEndsUpHere.new

What's next for Camping?

Camping is mostly just plain old ruby with some funny bits. But it's so interesting how all the pieces fit together. It's so small and compact you can read the whole source code in a few minutes, but it's packed with interesting Ruby tricks that truly stretch what you can do with Ruby.

I began looking for a new web framework in early 2022, I found Camping to be interesting and exactly what I was looking for. Small, Simple, and stuck in a single file. Unmaintained for 6 years it didn't work right away, but after a little bug fixing it was good as new. Working on Camping has taught me so much about Ruby. It's absolutely been worth every moment.

I think that the future of Camping is to keep the core framework as small as possible, but make it easy to extend. Things like new view systems, database ORMs, or even websockets. The next version of Camping will have a decoupled, yet improved database plugin called Guidebook, A Camping NEW command line helper, and documentation improvements. Soon I'll add support for websockets, Phlex Views, the Falcon webserver, Rack3, and the Sequel database toolkit, configurations using a kdl config file, and asynchronous code execution. In particular I'm very interested in making the developer experience as fantastic as possible. To me that means inspection and testing tools. Amazing and detailed Documentation. Plus common helpers to make difficult tasks very simple to understand and perform.

Working on Camping has made me very excited about my career again. I really love it.

Karl Oscar Weber

Start From Scratch Again but Make it Basic.

Hi Friends,

I redesigned and rebuilt my website theme this time it's version 18. Which is nice. A lot has happened since I started this latest version and I learned a lot about why shipping my past themes failed and how to make that work.

Too Much on the Plate.

I first decided to dump what I had in the past and start over from scratch, but super scratch scratch. Why? I had this half-baked idea to build a design system around the site while I was building it, and add a space for tutorials, and courses. It was a lot. Lack of focus and huge scope tanked the project. The onset of the pandemic killed my motivation to continue, and anyways I had to find work suddenly and keep the family all ok. (I'm married with 4 children).

This is a theme I see in any endeavour, lack of focus, and large scopes kill things. That's not cool. I had taken on too much and tried to make all this related, yet different things all at once. Which is silly when you think about it. Tutorials, and Courses? Concurrently? With nary an article before that? Yeah that was silly.

The course correction to that wells up from another reality. The people do what they do, a crafts person makes what they can make becuase that's what they can make. A more talented or experienced person will make better work faster, than a newbie. But it's the act of building and making lots and lots that sharpens these skills. If I did want to make a course, the first step is to make the smallest piece of what a course might be, writing about the topic. So it goes with the redesign that I launched.

Start over, Cut Everything.

I designed a basic blog. No features outside of the essentials, with very little personality. That's what I shipped to kow.fm for version 18. Why? Well I have aspirations to ship more than just one theme, but a lot more, I wanted a base theme that I could work with that had very few assumptions that I needed to overcome.

This blog runs on Ghost, at least for now. Ghost is great. It has started to ship a lot of features that are easy to support, and a few that are slightly more difficult to support for theme developers. Trying to fit all of that into an initial release from the jump was hard for me. I decided to cut support for everything but the most essential things. I can add stuff later. The basic blog theme that I made, Capsule, is meant to just be a baseline for other themes. Which seems silly. But standing up something basic that fulfills all of the main requirements, is pretty important.

So I did that, I cut everything and started over from a baseline. The code is ugly-ish, the design is meh, but it all works and I have my baseline.

Small Iterations Over Time

My next step is to find small parts to improve, improve it, and then ship that. I see this theme as a baseline, but also something that I can improve and make changes to. Art, Design, Code, this stuff is never finished, it never ends, it's just let loose from time to time. Baking a small iterations mindset into every aspect of my creative output is now kinda my JAM. Starting with this theme was the best decision I could make.

What's next? I'm working on a cool blog thing with Collin. I've been refurbishing Camping for about 6 months and it's gettin' pretty good. I've decided to pivot my career to focus on websites with Ruby and I'm loving it. Carving out more time to be with family and friends by cutting everything I don't actually like.


Karl Oscar Weber

How I spent the last 10 days Fixing an old Ruby Web Framework.

This is not just a technical discussion, but a description of my efforts to find a replacement for rails, and why.

I'm not going to get into details too much, but the popular web framework Ruby on Rails, is open source, really easy to use, and still runs some pretty big startups. The Original creator DHH, which I will refer to in this article as The Dumbass, is still very active with the thing. But he keeps doing Dumbass Shit. Like I'm tired of his shit and I'm not even primarily a rails devloper. I have other things to worry about.

I decided that I didn't want to have any association, not even tangentially, with that dude. So I'm like: "I have to port all this old code I have". I was attached to my code.

I was tired of tangentially associating with the work of a puffy ego shit head that says politics is getting out of hand, and that routinely causes harm.

As Kim Crayton says: Tech is Not Neutral, Nor is it Apolitical. My personal choice in tech and contribution to it won't be either. So I wanted to choose some tech that wasn't associated with a sociopath.

Anyways I set about Porting My code.

I'm not even that good with Ruby. I honestly pretty much suck. That was the problem. I have a mountain of code that I have to improve/maintain plus several personal projects that I'm trying to move forward. I'm committed to Ruby though.

I googled best Ruby Frameworks. I figured that at least some of my code would be portable. I had figured out some difficult record relationships logic in rails for app permissions and I didn't want to abandon that. There are a LOT of Ruby frameworks. like a lot. Some Highlights:

Hanami: A fast and Modern web framework. I really like this one. There are simple patterns and very good documentation to get you started. The organization behind it, dry-rb, is pretty amazing too.

Sinatra: A DSL for quickly creating web applications. This one felt a little too minimal to me. It's also great.

Grape: A framework for creating REST like APIs in Ruby. This one is good too. Most of what I'm making are APIs for iOS and Web apps so this made sense to me.

Camping: A web framework which consistently stays at less than 4kB of code. Written by a mysterious developer that suddenly disappeared in 2009, it's now maintained by the community.

Roda: A routing tree web toolkit, designed for building fast and maintainable web applications in ruby. It's just a bunch of routes. Damn fast.

There were things I liked and didn't like about each one, but in the end I chose to use Camping.

Let's go Camping

The Camping website points to a derelict domain that redirects to a spam site. The Github repo hadn't received an update in 4 years, no real development in 8 years. So this puppy was old. Also it didn't run when I installed it. I was intrigued.

In fact I was unable to compile anything on my computer for like 12 hours because of some Xcode Brew install bug thing. It was tough. After I fixed my computer I tried to fix Camping. I changed a couple of variables, corrected a couple of errors, and then... it worked! This old thing was alive and kicking with it's little 4 kilobytes of Ruby. It felt so good to dive in and learn what was broken and how to fix it.

I was very excited

I mentioned before that I wasn't much good at Ruby. I had never properly learned the language and only used it sometimes to build something small, or to maintain one of the projects that I had inherited. Most of my experience was through Rails. So when everything blew up I decided that I would learn it properly. Fixing Camping was my crash course.

Working through the documentation was a joy. It was very sparse, but clear and simple and to the point. Camping is an MVC micro framework that has everything from routes and middleware, to sessions and databases. ActiveRecord is included. There is literally everything you need in a small package. The best part IS that it's all in a small package.

It's common for a Camping App to fit in a single file without scrolling. It's so concise that you can get a lot done. ActiveRecord gives you instant access to a powerful ORM, migrations included. All this stuff is important for building an app or an API.

How does all this fit into a small package? Well It's because Ruby is amazing. Like I've heard of ruby developers passionate about the language, but HOLY COW it's ridiculous. There's some black magic happening that gives you a lot of power with Ruby.

Strange Magic

Ruby is a purely Object Oriented language. You have classes and objects. But only in Ruby EVERYTHING is an Object, even classes. You can extend or add functionality to ANY Object, even standard library classes. Even classes that you include from the community. And the community of open source code is gigantic, amazing, powerful, useful. You name it. Ruby is STACKED.

I didn't realize that a lot of the magic that I found in rails was simply there because of Ruby. Rails really does put you on Rails, and hides some concepts of Ruby's meta nature that would make understanding what's going on much easier.

Ruby gives you powerful meta programming tools. You're program can modify itself dynamically and write it's own code. This is partly how Camping is so fully featured yet so small. Camping dynamically maps it's routes to your controller methods with a few lines of code that look like a brain teaser. Clever use of regular expressions and code generation make Camping special, and pretty handy. I was immediately productive with it.

Camping is so small you can read the source code in a few minutes and generally understand what it's doing, even for a novice like me. I dived deep into how Ruby Meta Programming works and read the source code like a novel, and consumed the book: The Ruby programming Language. I get it now. Ruby itself is so flexible and dynamic that just about any code can be shared and incorporated into any project. The magic is Ruby itself, and Camping's source code and example is a cheat code to see how to make your own magic.

I was very excited. I feel like I can accomplish just about anything with this little tent.

I'm a Camper now

I reached out to the lead maintainer of Camping and asked if I could contribute. They said YES! So I did! I fixed the tests and now Camping works again. I'm primarily concerned with thoroughly documenting and modernizing the documentation, for my benefit as well as for others, while I build out my own indie projects.

My first project is a User authentication and Oauth Token based middleware system thing. It will be reused for a few projects I'm working on. The best part is that I won't be starting from scratch, I have a lot of old code to work from and port over. Afterwards I think I'll try to move my TOY podcast app a bit farther along. Making a podcast app is a lot harder than it looks.

Try it out!

Download Camping: Add this to your Gemfile to get the latest, actually working version.

gem "camping", git: 'https://github.com/camping/camping' # for installing straight from the repo

Karl Oscar Weber

The Best Productivity Advice

The Best Productivity Advice

I mean, we all want to be more productive, right? I do. The piece of advice that I hear shared the most is to break down what you need to do into small pieces.

Just break it down. Small pieces.

This is mega true. Sometimes I have trouble getting into the mood of working, or focusing on something for too long. What helps me is to think of a large task like a big debt, I want to pay it off, so I make small payments, or deposits, of my time and attention. Eventually I'll pay it off.

I keep a list of the big things I need to do, then add smaller sub tasks to organize my work. Sometimes I'll be working on something, and I'll get carried away by where the work takes me. It's not what's written down, It's not the plan, but it's important, essential. I add these small things to the larger task. Keep track. Sometimes I add something to my list, just to immediately check it off. This helps me to visualize my progress over time. Watching my progress stack up keeps me motivated.

So, take the things you need to do, then break them into tiny chunks.

You can do it!

Karl Oscar Weber

Redoing Everything

Redoing Everything


It's been a while, but 2020 has just kept on going... A website redesign is the farthest thing from important at the moment. But I need to work and apay bills so I've got to convince ya'll that I can do my job. So here are all the latest details about the redesign.

Throwing it all out

I became really frustrated with the direction of the redesign sometime in July I think. It wasn't really looking nice to me. My typfaces choices were alright, but everything felt small and unambitious. I needed to go in a new direction.

I first revaluated the homepage design. Before It was much more functional, introductory text with inline links to interesting parts of my website. Now I've taken that idea to the extreme. JUST the text with links.

Bold new design attempt for the homepage.

I wanted to do some experiments with the hover states, so I did:

Really bombastic hover states.

The vision for the site is Bold pieces of color contrasting against pretty plain hues of grey. I didn't want the background to be white, white is the internet's color, the color of websites. Just like white everywhere. Grey feels better.

I also switched a bold, sans-serif typeface for all headlines. I was using Playfair-Display before, and although it was playful, I just never leveraged it in a way that was satisfying. When redoing everything I started with a baseline system instead of designing individual pages. I already had a pretty good type scale that I modified, so It was all about nailing the weights and sizes.

Type sizes and weights tied to css.

I think I did a good job. I outlined how the text should look and feel next to each other, then I put it all into CSS. Having links be bright splotches of color felt like a really great choice to me. I have an idea to use nth-child to alternate colors, but I'll push that in another update.

Moving onwards to design the how each page type would look, I became really restless and simplified a lot. Now there are 4 types of pages: Index, Page, Post, Chapter. Pretty simple. Every post wherever it is, is a post. Book Chapters are, well, chapters. I've decided to put the whole book I'm writing online right on my site, no separate site to messy things up. It would just get stuck in endless redesigns and never launch anyways.


Moving to a more bold design and building from scratch meant that I would need to build some baseline components first, and then fit them together. I started with Type, then continued with colors.

Colors used in kow.fm

I had/have a plan to add lots of content, I thought it would be interesting to give each content type their own accent color. Going to each section would mean the links would be different. And it worked. It looked nice. But seeing as how I don't have a lot of that content even made yet... I axed all of those pages. I axed an Apps Page, Tutorials page, Courses Page. I axed a lot.

I had never done really well in adding illustrations to my posts, but wanted to try to do so easily, with little effort. I found that a square illustration style, with simple background colors would work well.

Illustration style for this website your reading now.

This opened up an opportunity to explore what Titles would look like with an illustration behind them, next to them, around them. I decided on a simple CSS blend effect of a title over the image. Having Really bright, or just plain solid colors in the illustrations gave posts a really great firm foundation, at least at the top of the page.

Title over the image.

I want to illustrate some more possibilities with this approach using the primary colors that we chose earlier.

Afterwards I started to experiment with the menu. I had already made a pretty ostentatious menu, but threw that thing out. It depended on too much javascript, and was a bit slow on my old laptop. I needed something simple, bold, and clear. I iterated on the highlighted link idea and made something that felt really bold.

Iterations and tests of the menu for this website.

I really really really like how it came together. A simple top navigation, that turns into a hamburger when it's on a mobile device. After removing a lot of the derelict pages and focusing on the core content, it looks even better. Now It's very clear to site visitors where I would like them to go, and how to find content on the site. You'll also see a redesigned prologue logo in there. It never felt right to me, reusing the prologue logo on my personal site, hopefully this new mark can connect me to prologue in a small way.

I became frustrated animating the transition of the hamburger symbol, into an X symbol. It's really common and everyone does this, but I was trying to animate the SVG it's self. I haven't done much of that yet. So as a stroke of experimentation I wondered if I could just rotate the X from the backside of the Hamburger. Then I thought why not make it a cube? Like why not? I want to do more 3D stuff on this site in the future anyway, maybe I can signal my intentions. Making a cube in pure CSS was not difficult, then animating that cube also wasn't difficult. The result is a playful, moving element that I didn't plan or expect.

The animated CSS Cube thingy on this website.

Animating the cube is pretty simple. We're transitioning between two states with different rotations. I'll go into that later. The sides of the cube that don't have symbols are filled with our accent colors from earlier. Thankfully investing in some playful colors has given the menu cube an even greater sense of fun.

Future Elements

I'm not yet complete with the site, but it's very close. I think I just need to redo the footer a bit and then focus all of my efforts on the book. In the future I want to bring back unique app elements. Rather than design something completely unique, I thought it wise to reuse as many components as I could. I came up with simple Cards that could have content dropped into them, just like a page.

Design for a future app card.

The old app cards were cute, but most of those apps aren't even close to being complete. I'd rather keep my intentions secret until just before launch.

That's it for now.

I'll hopefully have this thing wrapped up before halloween.

Stay safe. If you're in the USA, vote. Preferrably not for the people sympathetic to neo n*zis and fascists.

Karl Oscar Weber

issue # 0

This is a test of the kow.fm broadcasting service.

You will receive this as an email in a newsletter because I'm a boss like that.

Karl Oscar Weber


Hi Friends,

Today I'll be talking about layouts. I've been doing layouts for a loooooong time. Like ten years. fer reals. For most of that time I've used float based layouts. Basically, tricking block level elements into acting like inline elements to run into each other like boba tea. It was rough. I was actually doing some layouts in floats a couple of months ago when I finally had enough.

Float based layout sucks so bad. I don't even want to get into it. So I decided to modernize. I picked up this book on CSS Grid layout and consumed it post haste. I quickly became acquainted with grid layout and it's pretty great. CSS Grid allows you to name sections of a grid, and have content flow over it. It does a lot more but that's the part that I'm excited about right now.

Every webpage can be composed by combining just a few layouts. Let's look at some common layouts that we see on the web.

The Centered Layout

The Centered Layout, is the most common layout on all of the web. Content naturally flows from top to bottom, so let's keep that content in the center.

The Header with Content Layout

The Header with Content Layout, Everybody needs something up top! Headers are the basic UI of the Web. It probably follows this pattern from the menu interfaces we have in all our windows on our computers. The scroll is the most important interaction on the web, and thusly header content disappears as it's scrolled away. Titles, menus, signposts, all can be found up top in the header.

Sometimes headers stick around when you scroll. That's cool.

The Sidebar Layout

The Sidebar Layout, Sites that put content on the side usually have a lot of content. Sidebars are used for quick and immediate navigation, usually in a site that you'll want an index around to help you find your way. Documentation sites use the sidebar pattern for a good reason, You're often jumping around when reading documentation.

The Sandwhich Layout

The Sandwhich Layout, The good ol Sandwhich. Sites that have a header and a footer use this layout. Also Screen takover modals use this pattern. The header is usally a title or a small menu, the footer an action bar. Usually a save or cancel button is down there. Methinks this pattern

So these are the layouts. They are good, everybody loves them. I love them. Honestly that's what matters. But how do we get them into the website? How do we get the content to look like that. Lately I've been using CSS Grid. Which is pretty easy,

CSS Grid

You make a Grid out of CSS. CSS Grids have an area that are divided up by lines to make tracks. Tracks are like the rows or columns of the thing. It looks like this:

An example of a grid, in CSS.

yeah soo..... You can see some lines, you can see some squares. It looks fine and dandy. But what really makes it cool is that you can choose how big or small each area in the grid is. You can make them assymettrical, oblong, or weird. It's all arbitrary. You usually see a grid that looks more like this:

An example of a 12 column grid.

Grids usually have Gutters and stuff. But whatever, these examples don't.

CSS Grid is, well, CSS. Which means you can redefine the grid at different viewport sizes with Media Queries. A small screen needs fewer columns, or maybe the columns that you defined before can be different? you can do just about anything. The most interesting thing to me is that you can set Grid Areas in your grid by naming them. Names like, sidebar, main, header, footer. Giving an element a simple attribute of that grid area magically puts it into that spot. It's wild.

Let's not get too technical, I want to talk about the intention behind the grids I'm using.

Telling stories

I guess that's the point of a blog. Remember when they didn't need to have some marketing purpose behind them? when you could just write about your cats, or lack of cats, or your dog, and people would read that? I want to get back to that. I have lots of cat/dog anxiety to share. I wanna write unimportant things about Animal Crossing. I bought Tania a copy and she's been playing it everyday, like it's a dedicated important thing. My kids stole my switch to play it, now I just longingly look over at what they're decorating my house with. I swear this one little game will force me to buy 5 Nintendos, We have 3 kids and every single one wants to play. It's not a game you can share. We just bought another Switch for my son, who is 7. It's working Nintendo, we get it, ya no mas.

Or maybe stories about what we're doing during the pandemic? That's the hot topic. We're all stuck inside, our joint grief/depression/anxiety is the big common thread in our lives now...... yeah maybe not.

Black lives matter is really important right now. I say that in a slightly sarcastic tone because they have always been important, but the systemic racism, oppression, and brutality has reached a boiling point. These protests are actually great. Keep them up. Tear the whole system down. Send the wire, make the hire. Maybe stories about the role that capitalism has played in using Racism as a tool to divide the working class so that they'll hate each other for no good reason. Keep us distracted from the real bad guys, greedy people. Calling out racism and oppression will become the norm on the blog, rest assured.


I'm working on one of those fancy course thingys but decided to just included it as a premium section on my website rather than spin up a separate brand/website thingy. Much easier to keep one thing going than two things going, in my experience.

Education requires, like, reference, and signposts, and clarity of concepts. How does the layout influence this? It's not ALL just layout there's other stuff too, but how does layout help to influence it? 🤔.

So What I've decided to do is have 2 main layouts for the website, Story Layout, and Course Layout. Blog Posts, tutorials, stories, These will use the story layout. It look this:

A figure of my story layout. A single column layout, with a footer.

It's got a single column, and a footer, and not much else. I like it! yay!

Next is what I call the course layout:

The course layout, a header, sidebar, main content, and sometimes a video up top.

The minty green is navigation. Courses, books, references, tutorials, how-tos, all of these require quick and comprehensive navigation between disparate sections as part of a collective whole. I'm working on rewriting and publishing my Swift Foundations book on my website. So this would be perfect. I want to offer premium content for making iPhone apps, video courses with accompanying text, so I've got this cute little video box above text. I really like it.

So I've got the layouts, now to implement them in fancy code stuff. This is all of the code for the sidebar sandwhich layout:

.gw_sandwhich_sidebar {
  display: grid;
  max-width: 1600px;
  grid-column: minmax(120px, 240px) auto;
  grid-row:auto auto auto;
  grid-row-gap: 0.5em;

  grid-template-columns: minmax(180px, auto) auto;

  "header header header"
  "sidebar content content"
  ". footer footer"
.gw_sandwhich_sidebar__header {
  display: block;
  width: auto;
  grid-area: header;
.gw_sandwhich_sidebar__sidebar {
  display: block;
  width: auto;
  grid-area: sidebar;
  box-sizing: border-box;
  padding-left: var(--step-0);
  padding-right: var(--step-0);
.gw_sandwhich_sidebar__content_wrapper {
  display: block;
  width: auto;
  grid-area: content;

.gw_sandwhich_sidebar__footer {
  display: block;
  width: auto;
  grid-area: footer;

@media screen and (max-width: 640px) {
  .gw_sandwhich_sidebar {
  .gw_sandwhich_sidebar__sidebar {
    padding-left: var(--size-large);
    padding-right: var(--size-large);

As you can tell, it's sufficciently over engineered to use CSS Grid, but it works nice. and as you can see on the website, The layout is just fantastic.

I'm confident that I"m probably over thinking the layout in Grid a little bit and can simplify it even more, but I'll wait to do that until later. Most of these layouts are coded and complete, now time to ship it, tweak it, and move on.

Karl Oscar Weber

You are not Special

This morning Tania and I woke up at the same time. Lying in bed, she turns to me: "I want a divorce.",

"HUH? What? Why?",

"You cheated on me.", I had, in fact, not cheated on her.

"When did this happen?",

"I had a dream", Ah yes. A Dream. It's another one of those dreams.

Days that begin with the cheating dream are, interesting, to navigate. Amicable, yet terse conversation. Quietly executing on routine. "I have never, and will never cheat on you. It was just a dream.", I rose from bed to make her breakfast. Being stuck at home for weeks has instilled new habits. Every morning I make her 3 eggs, not scrambled, not under cooked, in olive oil, with cilantro, pepper, and a pinch of salt.

Yesterday she frowned at the eggs, "They look ugly. How could you bring these to me?", "Well the yokes broke a little when I flipped them.", this was not a satisfying answer. I made her new eggs, and ate the first batch. She didn't complain the second time. I think I made the right decision to make those eggs again.

Today she told me that she doesn't really like egg yolks at all, "but the kids like them.", A detail that I was happy to learn. After 10 years I'm still learning things. "I'll just give you egg whites tomorrow." It's astonishing how simply being kind makes everything better.

I'm certain I'm not the only person to wake up next to their partner, that's angry, because of what they did in their dreams. It's probably common. Thousands must have woken up on that same day and had that same conversation. A thousand ways to say sorry, or to say fine, whatever. Some of these people have recovered, some haven't. Some laughed about it. Others received a firm slap to the face. Maybe even a punch? There is a poor fellow sleeping in their car tonight, with a black eye, somewhere.

In all of this shared experience, that I of course imagine to be true. In all of it I find great comfort. Someone, somewhere, has taken the path that I didn't, experienced the consequences of the dream, differently. That makes me happy.

Karl Oscar Weber

Type Scales

Hi Friends! I'm back! Typography is 95% of web design. The impact and implications of a good type system, the right fonts, and the right colors cannot be overstated. I've never really been all that good at it, but this time I really wanted to do my best and make something that would stand out. Firstly I should share the design that I made for kow.fm v15.

This is the homepage design for kow.fm.

The homepage design doubles as an about page and an index. I realized the primary goal of kow.fm had changed to share educational content, tutorials, books, guides, tips, that sort of thing. It's more than just a journal, but also the nature of my writing has begun to shift too. So this is what I've got. I really like the colors and the simplicity of the typeface.

The post page design with a header image for kow.fm.

This is a post template page with a header image. A big barrier in the past for my writing, was that I had aspirations to include some homemade art with every post. But I never had time to do the Art, or it was just really junky, so the post never made it out. I wanted a design that could work equally well with or without a main post image. So that's what this is.

Post page template with no image for kow.fm.

I also mocked it up without an image and the above image is that. I like it. You can even peek the little aside box that I designed. Kow.fm will also host a course and a book, so the design for those pages needs to just be different. It can't follow the above blog patterns.

The lesson page design for a swift foundations blog lesson.

This is what the lesson pagef looks like, just like the blog design it works equally well with or without a header image. This design is mocked up with a header video. Offering video content. I know that I want to offer premium materials for a subscription to like... pay for things, and stuff. I also want the design to make finding and learning as much about swift as effortless as possible, so I added that endless Menubar on the side.

I haven't mocked up any upgrade or subscription screens yet though. I figured I could start with the free content first and then build the premium gate stuff when I have something to sell.

Dynamic type scales

Yeah so this website has a new dynamic type scale system. It's a really great concept that a couple of fellows at have been working on over at Clearleft; James Gilyead and Trys Mudford. They published this site about their idea and I freaking love it. https://utopia.fyi.

Before this I was highly skeptical of type scales in general. Designers generally just make that shit up anyway, have wild sizes for random ass pieces of a design. Titles are tiny, but only a little tiny, headings are almost the same size, except for h1s, which are huge for some reason. Not even to mention that margins, paddings, and line-heights are all different and special, for whatever reason. So yeah, I'm a bit jaded. The whole design system movement has made in depth, systemized designs much more common and easier to work with, but there is still a lot of confusing bloat to deal with when fitting fonts to different screens. This Utopia thing makes a lot of sense. Dynamically change the type size based on the screen width without media query janky breakpoints.

What is a type scale? It's a relationship between type sizes. When things change in size in a predictable manner, it looks predictable and pleasing to the eye. So a type scale will have those steps change by the same ratio at each step. Let's say your type scale is 1.25 and your initial type size is 16px, each step will be 25% larger or smaller then it's adjacent step. Example:

An example of a 1.25 typescale with type at different sizes.

I used to think this was a bit silly, but now I'm like... DAMN! That looks nice.

Now type scales should be tailored to their context. The mobile web will have a more reserved typescale versus the desktop web. On Desktop you've got a lot of real estate to work with. Big expansive screens, We want to take advantage of that. So the type scale should be bigger on that larger screen. This is what the large typescale looks like next to the smaller one.

Comparison of two different type scales.

As you can see, if you can see, we have two, proportional type scales side by side. They look pretty nice. I like them. You may notice that they don't use perfect pixel sizes, that's fine. Nothing is pixel perfect. Who cares. For kow.fm v15 I wanted to take the concept of a dynamic typescale and expand it to also use dynamic sizes for margins and padding. So I did. The Margins and padding are all dynamic based on screen width.

The type scale is dynamic. That means that the CSS is interpolating between two different sizes based on screen size. You can use a handy tool to calculate your own type scale. It works super well, only uses CSS Variables, and is super well supported.

Using the type scale in CSS is super easy. This is what the styles look like for the h2 and p tags in content areas:

.content {

  & > h2 {
    font-family: 'GreycliffCF', Arial;
    font-weight: 700;
    font-size: var(--step-2);
    line-height: 1.25em;
    margin-bottom: 0.5em;
    margin-top: 2em;
  & > p {
    font-family: 'GreycliffCF', Arial;
    font-weight: 500;
    font-size: var(--step-0);
    line-height: 1.5em;
    margin-bottom: 1.5em;

I've also added some nice typefaces and a simple layout so that text and content isn't as wide as can be.

I'm very satisfied with using the dynamic type scaling for kow.fm. So satisfied that I'm porting the whole thing to another project and doing even more crazy ambitious cool stuff.

What's next?

I'll be refining the typography, and some more type details and colors on the site next. Later I'll tacker header and footer stuff.

All Posts