Caoimhe

This site’s code now contains game spoilers

This post demonstrates CSS that won’t render in an RSS feeds or older browsers.

I have made one1 post about Baba Is You and so obviously I banged up a quick and dirty lexer for my website’s syntax highlighter and CSS to display rules text from the game using animated images pulled from the Baba Is You Fandom wiki that you can still highlight and select to copy text from.2

If you are unfamiliar, Baba Is You is a block-pushing puzzle game where the rules that dictate interactions between blocks exist as text within the levels themselves that be rearranged to change them. Watching the trailer for the game will get this across better than I am able to explain it. I have not finished it but it’s a great little game and I would encourage anyone to check it out and discover all the incredible little things it does with this concept and I am looking forward to seeing what lies in store for me.

And I decided, because I could (because HTML and CSS are genuinely wonderful expressive media), if I was going to talk mention the game on my website I wanted to display the rules text as it is displayed in game: With cute little animated squares of text.

The end result is that I can type something like this in the Markdown that posts are written in:3

```baba
rose is red
violet is blue
flag is win
baba is you
```

And it will render thusly:

rose is red
violet is blue
flag is win
baba is you

And you should be able to hightlight the text above and then copy and paste it somewhere else and have it remain legible.

I build this site using Jekyll, which uses Rouge for code parsing and syntax highlighting. All I needed to do was add a new lexer:

Jekyll::Hooks.register :site, :pre_render do |site|
  require "rouge"

  module Rouge
    class Token
      module Tokens
        token :Noun, "noun" do
          token :Rose, "noun rose fourletter"
          token :Violet, "noun violet longword"
          token :Flag, "noun flag fourletter"
          token :Baba, "noun baba fourletter"
        end

        token :Oper, "oper" do
          token :Is, "oper is"
        end

        token :Prop, "prop" do
          token :Red, "prop red"
          token :Blue, "prop blue fourletter"
          token :Win, "prop win"
          token :You, "prop you"
        end
      end
    end

    module Lexers
      class Lua < RegexLexer
        title "Baba"
        desc "Baba Is You (https://www.hempuli.com/baba/)"
        tag 'baba'

        state :root do
          [Noun, Oper, Prop].each do |group|
            group.constants.each do |word|
                rule Regexp.new(word.id2name.downcase), group.const_get(word)
            end
          end

          rule %r/\s+/, Text::Whitespace
        end
      end
    end
  end
end

This parses over the text looking for matching tokens and then assigns them a set of classes (noun, rose, fourletter, etc.) that will be used by some even more hacky CSS to display them:

figure:has(> pre > code.language-baba) {
    display: inline-block;
    margin: 0;
    vertical-align: middle;
}

pre:has(> code.language-baba), div.language-baba.highlighter-rouge pre {
    display: inline-block;
    margin: 0;
    background-color: #080808;
    border-radius: 6px;
    padding: 6px;
    border: 0;
}

code.language-baba, div.language-baba code  {
    background-color: #080808;
    border-radius: 6px;
    hyphens: none;
    display: inline-block;
    text-transform: uppercase;

    .w { font-size: 0; }

    .noun, .oper, .prop {
        font-weight: bold;
        white-space: initial;
        height: 24px;
        width: 24px;
        align-content: center;
        font-size: 9px;
        text-align: center;
        line-height: 0.9;
        font-family: "Comic Sans MS", "Comic Sans", "Comic Mono", "Chalkboard SE", "Comic Neue", sans-serif;
        background-size: cover;
        image-rendering: pixelated;
        display: inline-block;
        overflow-y: hidden;
    }

    .noun { color: #D9396A; }
    .noun.rose {
        background-image: url(/styles/baba/text/rose.webp);
        color: transparent;
    }
    .noun.violet {
        background-image: url(/styles/baba/text/violet.webp);
        color: transparent;
    }
    .noun.flag {
        background-image: url(/styles/baba/text/flag.webp);
        color: transparent;
    }
    .noun.baba {
        background-image: url(/styles/baba/text/baba.webp);
        color: transparent;
    }

    .oper { color: white; }
    .oper.is {
        background-image: url(/styles/baba/text/is.webp);
        color: transparent;
        font-size: 15px;
    }

    .prop { background-color: #D9396A; color: #080808; border-radius: 6px; }
    .prop.red {
        background-image: url(/styles/baba/text/red.webp);
        background-color: transparent;
        color: transparent;
        border-radius: 0;
    }
    .prop.blue {
        background-image: url(/styles/baba/text/blue.webp);
        background-color: transparent;
        color: transparent;
        border-radius: 0;
    }
    .prop.win {
        background-image: url(/styles/baba/text/win.webp);
        background-color: transparent;
        color: transparent;
        border-radius: 0;
    }
    .prop.you {
        background-image: url(/styles/baba/text/you.webp);
        background-color: transparent;
        color: transparent;
        border-radius: 0;
    }

    .fourletter { font-size: 13px !important; }
    .longword { font-size: 10px !important; }
}

I am applying some styling to the underlying text to try and make it line up with the images (which you can see when highlighting it), though some of this like setting the text and background colour is then hidden by the more specific element styling that sets images for each token. It’s a bit pointless but it pleases me that, even if it’s invisible, there is styling there to make everything look more like the game elements aside from the images pulled from the game.

I’ve cut the example here down to only the words used in the poem, but the version in my actual code doesn’t have the full lexicon of the game either, just a few more words that I wanted to use on the site. A large part of the experience of playing Baba Is You is slowly discovering all the ways it plays with its rules. Loading up a level and seeing a new word and chewing on it, thinking through all the implications it could have, is a wonderful experience that evokes a strange mix of whimsy and dread as one realises the possibility space that has just been opened up. As such I have not looked up a word list to fill out my lexer more fully (and it would probably be tediously long anyway) and there is one word in particular defined in the CSS file that I think it is better to discover oneself by playing the game than to know it exists going in, so I don’t suggest going to look at it yourself if you haven’t already played the game—and do play the game, it’s great!

  1. 1 

  2. caoimhe is normal4 

  3. Examples used in the footnotes of this post are a bit more hardcoded as my Markdown parser did not like me mixing those two things together. 

  4. Extra symbols generated by Robot is Chill, which frustratingly only exists as a Discord bot and not a openly accessible tool.