🔝
2024 CE
Worked on creator apps to consolidate society, technology and my personality. Created an astrology app while heightening my technical ability.
  1. Modern divination
    1. Brutalist graphics and Ayu Dark
    2. The Sexagenary Cycle
    3. The relationships among the cycle
    4. The lessons, readings, and what’s beyond
  2. Building Pillars
    1. Elixir, HTMX, and Tailwind
    2. The passkeys
    3. Wrapping up

Modern divination

Would you believe that you were born with 4 pairs of letters and they can tell how your life is going? Well, I didn’t until I decided to make a whole app about it. Check it out if you already want to know your Pillars.

Pillars
Pillars

The Four Pillars of Destiny is an astrology originated in ancient China. In the olden days, people would depend on these letters to understand and, hopefully, predict their lives.

While being ancient, the Four Pillars still count. They’re brought up to resolve relationship issues. Birth rate bumps when it’s the year of Dragon, like this year. There are many other applications: Feng Shui, Gua, Qi Men Dun Jia, and so on.

Do they make any sense though? I remained disengaged, skeptical, and sometimes critical because I thought such superstition would hurt good judgement.

Then I saw my partner raising hopes in her most difficult times. More often than not, there are not much good judgement can do. That’s when I thought I had to give the astrology thing a second thought.

Pillars helps you uncover the stories of your life with a modern take on the ancient astrology.

I still don’t think the Pillars predict or diagnose anything. They are purely fictitious. Then what are fictions for? Once you accept that a story is just a story, it becomes a source of wisdom and inspiration.

It’s been said that people tend to agree random fortune telling. The Barnum-Forer effect exposes how, not dumb, but complex we are. Any story can work as a mirror that reflects yourself within yourself.

The Pillars make a great story-generator. The four pairs of ten and twelve letters produce 604 = 12,960,000 possible combinations of Pillars. Each pair gets assigned a relationship that opens up space for interpretation.

I thought it would be fun to build upon this idea. That’s how I started working on Pillars.

Brutalist graphics and Ayu Dark

My main goal was to provide intuitive graphics and an interface. The result is the brutalist style and mobile-first interface you can see in the app.

At first, I thought the graphics would be emojis because they are the most intuitive graphics of our time. And they are easy to implement. But as I work on this idea, I soon realised that it’s difficult to add layers and convey enough information on top of emojis.

So I popped the bubbles and started sketching custom graphics. I wanted them to visualise what they stand for, but in an abstract manner. This is exactly what the original letters do. Every character comes from an image, a hieroglyph. Then it becomes a symbol that can mean a lot of things that doesn’t have to be the original image.

I had to do this because I was replacing all the letters with the graphics. The letters are the foundation of the Pillars. If I’m replacing them away, it had to be something profound. I thought it’s a good application for a brutalist design. Not for the sake of trend, but for the function. I’m not disappointed with the result.

I had an idea for the colours too. In my previous project, Ayu for Obsidian, Ayu Dark was under-utilised. I had it in my mind and brought to this project.

With the brutalist design and Ayu Dark, I was confident to proceed. I’ll write about technical challenges in another post. The following is more about the content of the app.

The Sexagenary Cycle

Before I go into app building, I had to know how the Four Pillars work. I had basic understanding from the long, cultural exposure. The bottom line is that there are 60 Pillars, of which you have four. But writing an algorithm was going to take more than that.

As I expand my knowledge about the horoscope, I also wanted to provide a new, good translation. Most resources available online put them in alphabet and that’s it. That’s not very intuitive if you don’t know the letters they refer to.

陰陽, or yinyang, is the foundation of the Pillars. While it refers to two things, Yin and Yang, it’s important to note that they are one thing. They don’t mean anything without each other. Then what is this one thing?

Any living system has its inside and outside. The surface between in and out defines what it is and what it’s not. Interesting movements happen on the perimeter. The system takes things in: food, light, and knowledge. And it becomes what it hasn’t been. As much as that, things go out: vigour, action, and words. Then it forgoes what it has been.

I reckoned that yinyang closely resembles such flow of life energy. Yin shelters life under its shade, while Yang exudes energy to raise it. So I decided to call them Flow-in and Flow-out. They add dynamism to the translation. It’s also a nice coincidence that Yin and in sound the same.

Then there are five elements: 木 Wood, 火 Fire, 土 Earth, 金 Metal, and 水 Water. It seems these things stood out in many ancient cultures. Metal is the only addition compared to the four classical elements. It’s also the most complex in the letter form. Perhaps it comes from the level of progress the ancient society achieved at the time.

Stems
Stems

Each element has a Flow-in version and a Flow-out version.

These ten symbols are 十天干, or 10 celestial stems. They make the body of your Pillars. They have been used as ordinal numbers in the ancient times. Just like A, B, C, it goes Tree, Vine, Blaze, and so on. There are ten probably because early humans counted with their ten fingers.

The translation is unique to this project. I carefully reflected what they represent in the Pillars. Also I matched the number of letters between the two versions.

Bases
Bases

The well-known animal zodiac signs, 十二運星, are the manifestations of the celestial stems. They are called the 12 terrestrial bases, basis for singular. They make the bottom lines of your Pillars.

They also worked as ordinal numbers when the ancient people had to count twelve. Sailors and astronomers would have been most interested in their utility. Every other basis shares a flow state just like the stems. But the elements are assigned with a more spatial way, making it difficult to write down in text.

Counting them doesn’t start from a Wood symbol this time. Tiger comes to the third, just like the season starts in March. Astronomically accurate start of the year is the darkest winter. Mouse symbol represents that moment of beginning which is also considered to have transitional energy.

You can see that Earth takes the center and has twice the members compared to other symbols. In the framework of Pillars, you will often find it as a central and neutral point of reference.

And that’s how you get 60 variants of Pillars! If you start counting one stem and one basis at a time, it takes 60 steps to get back to the initial pair, because the least common multiple between 10 and 12 is 60.

The relationships among the cycle

With the basics cleared, we can go into the juicy part.

Elements within the Celestial Stems interact with one another and create a relationship. If you pick any two, one element either 生 bears or 克 eats the other. For example, Wood burns into Fire, but it consumes Earth. Water can grow Tree, and Metal cuts the Vine.

Aspects
Aspects

These interactions come into 十神, or 10 divine aspects. They also have flow variants depending on if the two elements have the same state or not.

Again, the translation is my own interpretation.

Phases
Phases

Last but not least, 十二運星 or 12 vital phases are the relationship between the stem and the basis in a Pillar. The phases are about making a lifecycle from birth to death: Origin, Nurture, Vigour, Renewal, Attire, Mission, Apex, Wane, Malady, Demise, Respite, and Verge.

And if the Stem is Flow-in, the cycle goes backwards.

The lessons, readings, and what’s beyond

The most beautiful part of the research and development was the lunisolar calendar. It’s the foundation of the Pillars. And it has definitely made the Gregorian calendar look bad even though it’s the globally accepted one. Lunisolar calendar actually reflects how heavenly bodies operate and the mother nature’s cycles. It starts with the winter solstice and peaks at the summer solstice. In the meantime, Gregorian calendar

I’ve also encountered a fascinating diversity. Even if the year starts at the winter solstice in the cycle, some practices applied the new year only after Spring season began. While the divine aspects are about between stems, some references applied them to bases as well. They would even flip some bases’ flow state.

Authoritative practitioners called for precision and legitimacy. Compassionate ones were focusing on making positive impact. Both approaches make sense. While working on the app, I weeded out vulgarised practices and kept the astronomical accuracy for the most foundational. At the same time, I didn’t compromise user experience just for the sake of precision.

Another surprise was that, coming from antiquity, some parts of Pillars tend to stereotype genders and family roles in a traditional way. I could see how they had to be concealed for Pillars to survive in our modern society. I decided to completely remove those parts from my app to keep it modern and non-binary.

Those decisions were applied to the algorithm, the design, and the prompt. You can check your Pillars and find out what they mean in Pillars app. You can get a reading currently at €8. The app is not complete in any sense yet. But I’m hoping to expand on features and reusability with daily, yearly, and relationship readings.

Enjoy!

Building Pillars

For the last dozen weeks, I’ve been working on the foundation for creator apps and an example: Pillars. This is a brief report for my choices and what has been done.

Since the plan is to serialise lightweight apps, the main objectives of the foundation were to

Elixir, HTMX, and Tailwind

I feel so lucky that Elixir is my environment to work in. It’s often considered a niche technology for CTOs to consider for specific situations. But I believe it’s the best kept secret among indie makers too. It’s just so magically simple and beautiful.

# Working example of Plug by José Valim the creator of Elixir

Mix.install([:bandit]) 

Bandit.start_link(plug: fn conn, _opts -> 
  Plug.Conn.send_resp(conn, 200, "hello world") 
end)

Flexibility and maintainability are some of the most powerful qualities of Elixir among many others. Elixir has a Rails-like web framework called Phoenix. But I wanted more brevity than robustness for my creative apps. So I decided to go with the Elixir.Plug interface.

Elixir supports umbrella apps. An umbrella app can have multiple apps in it that share configurations and dependencies. This feature is not exactly the community’s favourite. But it seemed I could make a good use case. So I adopted it. I’m also looking forward to provide a lighter web framework for the ecosystem. Mar was an experiment to showcase the idea.

Leaving the JS ecosystem has implications. And I’ve decided to cover them with HTMX. It’s a JS library to end all JS libraries. Web apps built with HTMX extend the idea of Hypertext as the Engine of Application State. Instead of communicating in JSON to translate them into a view with obscure logic, HTMX expects some hypertext to replace the current view.

<!-- Replaces the button with whatever /clicked responds with -->

<script src="https://unpkg.com/htmx.org@2.0.3"></script>

<button hx-post="/clicked">
  Click Me
</button>

The HTMX library is full of utilities that I haven’t fully explored yet. It basically has everything you need to build a web app from any back-end environment. But for me, it’s the philosophy behind what REST and hypertext really are. Learn more about it at Hypermedia Systems and Fielding, 2000.

HTMX contains logic neatly into the markup. And you guessed what I’d do about styles: TailwindCSS. I loved the utility-first approach since my first encounter. It has grown significantly and became a necessity at this point. Tailwind aims for larger teams. But even for small teams and individuals, the simple fact that you don’t have to name anything yourself talks to me.

In a conjunction with HTMX, this is a great selling point. HTML has pre-defined, semantic tags. This is what the Web should be: a global protocol, that is not perfect but everyone can share an idea and generally agree upon. CSS and JS has derailed this quality and overcomplicated web development.

With Tailwind, HTMX, and later-adopted Elixir.Temple templating engine, everything is neatly sorted into the templates. And the only thing I need to name is the Elixir functions which are lovely to work with.

The passkeys

Once I set the environment up, I moved onto the core app that centralises some common needs such as authentication. At first, I thought I would use a provider for logging users in and out. But further research made me turn my head to the FIDO2 compliant web authentication API also known for its passkeys.

The web didn’t have an elaborate authentication system for a long time. The basic authentication is, you know, too basic. So the developers had to roll their own auths using web forms.

And that’s by large why authentication on the web is so brittle. It’s error-prone and easy to hack. People forget their passwords while some others give theirs away in a phishing site. It’s a total mess. This kind of engineering problem takes a whole team of experts to deal with. And that’s exactly why I wanted to use external providers.

// Prompt the user to sign up

const publicKey = {
  user: { id, name, displayName: name },
  rp: { name },
  challenge,
  pubKeyCredParams: [es256, ed25519, rsa256],
}

const credential = await navigator.credentials.create({ publicKey })

But the web authentication API changes the game. It delegates authentication to the device that already has powerful authentication features like facial recognition. A group of experts from FIDO Alliance writes the standard and the World Wide Web Consortium takes care of the spec. The API is ready for use on your favourite browsers today.

It’s one of the most secure authentication methods the web has ever had. But the real reason to adopt this new feature is the user experience native to the device. It actually feels secure for the user and removes all the unnecessary intermediaries. It’s just the cool way to sign in.

There’s a catch though. The spec is rough around the edges now and lacks some features. In particular, the user.name property is decoupled from the web apps, but somehow is encouraged to be managed server-side. If that sounds weird, you’ve read right. Users can change the name arbitrarily and the server wouldn’t know. Then how does the app manage it? Proposals are in process to fix this issue but in the meantime, I decided to dub them with the app name.

Plus, the Instagram/Facebook in-app browsers, or WebView implementations, don’t support the API. I don’t know why. 🙄 I had to escape those things.

// iOS Chrome
location = "googlechrome://" + location.href.replace("https://", "")
// iOS Safari
location = "x-safari-" + location.href
// Android
location = "intent:" + location.href + "Intent;end"

Once logged in, the user account session is stored in a cookie that can be accessed from all subdomains. Since I’m going to publish the creator apps under the subdomain, the user authenticates only once in the core app.

Wrapping up

Rest of the development was a breeze. The lunisolar calendar was concluded with 200 lines of tests and 270 lines of logic. The app went live once it was connected to PostHog, Stripe, and Anthropic. Req, by the way, is a fantastic Elixir HTTP client that is handling the providers. Its interface actually feels Elixir. I’ll write a separate post about its excellent design and the functional interface of Elixir.

Despite the joy of app building, I had to abruptly wrap it up for several reasons.

I handed off the current state of the project to my future self with 13 new GitHub issues. I’ve been coding for more than 3 months non-stop. I like the result and learnt a lot from the process. It has been confirmed that a single person can deliver something people pay for.