leanrada.com notes

フィード

記事のアイキャッチ画像
Creating a halftone effect with CSS
leanrada.com notes
For RSS readers: This article contains interactive content available on the original post on leanrada.com.Here’s a quick halftone effect (i.e. a retro printed look) using CSS with only one div at the minimum.First of all, here’s a live demo:Interactive content: Visit the website to play with interactive content!Alternative text: CSS halftone demoToggle the filter class using the checkbox above.To further illustrate the halftone effect, the following demo can vary the size of the dots and the degree to which they ‘bleed’:Interactive content: Visit the website to play with interactive content!Alternative text: CSS halftone demo Bleed There are several ways to do this in CSS. The above is a bit more advanced with 2-3 extra divs. I’ll try to show a simple method, first.Halftone basicsTo keep it simple, let’s start with a black-and-white image. It should be easy to layer in additional colors with the same principle.Interactive content: Visit the website to play with interactive content!Alte
16日前
記事のアイキャッチ画像
AI art is not generative art
leanrada.com notes
AI art is not generative art (clickbait title). While the technical definition says that one is a subset of the other, I think it’s useful to distinguish between these two categories.Why I’m writing this in the first place — Starting 2022, the term “generative art” had been progressively becoming synonymous with art produced by AI text-to-image systems. As a consumer and producer of (traditional) generative art, it was becoming a bit annoying to browse generative art content on the internet. Whether through tags like #generativeart or communities like r/generative, spaces are being flooded with AI-generated images which I and many others are not interested in. End rant.In 2024, things are a bit different. AI art is now commonly referred to as ‘AI art’. I shouldn’t have procrastinated writing this post for so long.There are also cases where generative artists are pressured to relabel their art, so as to not be mistaken for being AI (and avoid things associated with it). It’s an unfortun
2ヶ月前
記事のアイキャッチ画像
htmz story
leanrada.com notes
This post is not the usual programming post. It’s been an interesting week, I guess.I just finished my mini side-project htmz, a snippet / library / microframework / whatever for HTML whose main feature was that it only weighed a total of 181 bytes. It almost fits inside a single ‘tweet’ (wait, the limit is now 280 not 140?).Here is the entire framework in its final form:<iframe hidden name=htmz onload="setTimeout(()=>document.querySelector(contentWindow.location.hash||null)?.replaceWith(...contentDocument.body.childNodes))"></iframe>See the project documentation for more info on what it does.I posted it on Hacker News, went to sleep because it was 3am at that point. Then the next morning it was at the top of HN!I didn’t expect this at all. But naturally I rushed to the comments section which quickly grew too numerous for me to read. They were generally positive, and acknowledged the project’s hackyness and elegance (these adjectives usually mean opposite things). It was pretty cool! T
3ヶ月前
記事のアイキャッチ画像
Pure CSS single-page app routing
leanrada.com notes
You’re probably a busy person, so here’s the CSS:section:not(:target) { display: none;}Demo: Open in a new tab My AppOpen in a new tabExplanationThe :target CSS selector selects the element that is targeted by the URL fragment.Combined with :not, we can hide sections that are not referenced by the URL fragment.Just as JS routers use the fragment to hide/show sections in the DOM, this “CSS router” uses the same fragment to hide/show sections in the DOM.Experiment: Default sectionNotice that the example above doesn’t start with the Home section. The content is blank initially. This is because on initial page load we don’t have a URL fragment to begin with.We need to make an exception for the Home section.Let’s start by not hiding the #home section by default. Only hide #home if there’s a specific :target section.- section:not(:target) {+ section:not(#home, :target),+ :root:has(:target) #home { display: none; }Demo v2: Open in a new tab My AppOpen in a new tabExperiment: Nested routesOne
3ヶ月前
記事のアイキャッチ画像
getDuolingoStreak()
leanrada.com notes
How to fetch your Duolingo streak using an unconfirmed API on duolingo.com:function getDuolingoStreak(username) { const res = await fetch( `https://www.duolingo.com/2017-06-30/users?username=${username}&fields=streak,streakData%7BcurrentStreak,previousStreak%7D%7D` ); const data = await res.json(); const userData = data.users[0]; // I didn't know which of these fields matter, so I just get the max of them. const streak = Math.max( userData?.streak ?? 0, userData?.streakData?.currentStreak?.length ?? 0, userData?.streakData?.previousStreak?.length ?? 0 ); return streak;}That’s my current max streak.I can then render this data into a card like that. I put one of these cards in the /misc/ section.Let’s look at the API itself. www.duolingo.com/2017-06-30 seems to be the API prefix, which is a bit weird. What is 2017-06-30? What happened on that date? Maybe the Duolingo team used a date-based versioning at the time?In any case, big thanks to the Duolingo team for keeping this apparently-6-y
3ヶ月前
記事のアイキャッチ画像
Writing a single-file website with Rust
leanrada.com notes
At the company I work for, there is something called a “professional education leave”, which lets me take a day off to learn something new or attend conferences or whatever professional education means. I took the opportunity to learn the Rust programming language.I didn’t want to follow tutorials, so I thought of a project to learn with, which ended up being “make a single-file website web server”. It was inspired by the article my website is one binary by j3s.Rust first impressionsfn main() { println!("Hello World!");}My first impression was that it is a mature programming language that is crazy about compile-time stuff. For example, the above println! call is a macro, which expands to something more verbose… Apparently, with macros you can also make full-blown DSLs that are directly embedded in Rust code.The rustc compiler’s error messages were very good.I think I haven’t really dived deep enough to discover the standout features that I keep hearing about like memory management safe
5ヶ月前
記事のアイキャッチ画像
2023 in review
leanrada.com notes
What happened in 2023? Stuff happened.2023 website redesign 🎨Feb 2023, I redesigned my site, with a goal of making it more personal instead of just being a mere portfolio.It came with a blog section, which made me start writing a blog.Started a blog 🖊“I’m starting a blog!I’ve done some blogging in the past (for gamedev), and I already do write-ups for my projects, so I think it’d be good to officially keep a blog!I have some ideas to populate the first few posts, then we’ll see how it goes from there.Watch this space!”First blog post on the new site (now unpublished), 24 Feb 2023Well, it went well! In 2023 I had:The hottest posts were:🔥 Sort, sweep, and prune: Collision detection algorithms🔥 Dynamic patrol behaviour in stealth games with Markov chainsIt is a nice new hobby and something I shall continue. 🙌Side projects 💻This year I launched two webapps, portabl.ink and GuhitKudlit!Portablink was just a fun experiment without much utility. I don’t have analytics on it so I don’t k...
5ヶ月前
記事のアイキャッチ画像
My personalised 55% split keyboard
leanrada.com notes
For RSS readers: This article contains interactive content available on the original post on leanrada.com.I’ve been using my Lily58 split keyboard for more than a year now. It’s a compact 58-key split keyboard with column-staggered keys, 55% the size of a standard 104-key keyboard.Thanks to the open-source firmware/framework QMK, I customised it and programmed it to my satisfaction. I figured now’s a good time to post about my layout so far.The keyboard in questionQuick rundownHardware: Split keyboard with 58 keys in total. A 32×128 pixel OLED screen on each half. Both halves are connected by wire, and the whole thing is wired USB-C to the computer.Software: It runs the QMK firmware, which I used to implement 7-8 layers and several custom functions. I customised the heck out of my keyboard’s firmware.The basicsInteractive content: Visit the website to play with interactive content!Alternative text: Lily58 keyboard layout diagram Left hand: 〔Esc 〕〔 ⌃[ 〕〔 ⌃] 〕〔⌃⇧Tab〕〔⌃Tab〕〔 〕 〔 ? 〕〔 q 〕〔
6ヶ月前
記事のアイキャッチ画像
Baybayin calligraphy generator
leanrada.com notes
GuhitKudlitBaybayin calligraphy generatorGuhitKudlit is a webapp that generates baybayin calligraphy.Baybayin is an ancient writing system used in the Philippines, mostly for the Tagalog language. I’ve always been fascinated by Philippine languages, and this project was just another fruit of that curiosity.Project detailsreleased2023rolecreatorplatformWebtechJSOutput of GuhitKudlit for the word ‘guhit’The name comes from ‘guhit’ meaning line or drawing, and ‘kudlit’ meaning tick or small mark.You see, baybayin is an abugida and in baybayin, the kudlit is used to signify the vowel of a character.Chart of baybayin characters from WikimediaThe program is divided into two functions: transliteration and calligraphy. The transliteration process converts ASCII input to baybayin glyphs, and the calligraphy function draws those glyphs onto the canvas using the p5.js library.TransliterationThe transliteration algorithm that converts ASCII text to baybayin glyphs is quite simple (or should I say,
7ヶ月前
記事のアイキャッチ画像
Debug CSS boxes with this bookmarklet
leanrada.com notes
Here’s a quick & simple way to show all element bounds on a page.javascript:(a=(d=document).createElement('style')).innerHTML='*{outline:solid 1px red}';d.head.append(a)The bookmarklet: ▤outlinifyExample result on threads.netNot sure how to use it? Save or drag the following link into your bookmarks:☝ Video: video of dragging the bookmarklet into the bookmarks bar | Source: /notes/debug-css-boxes-bookmarklet/drag.web.mp4 If you prefer different styles:Dashed: ▤outlinify Dotted: ▤outlinify
7ヶ月前
記事のアイキャッチ画像
Compressing a website into a URL
leanrada.com notes
For RSS readers: This article contains interactive content available on the original post on leanrada.com.This post explains how portabl.ink works. Portablink is a tool that creates self-contained compressed web pages in a single link. Check portablink project page for more info.tl;dr: It uses data URLs containing compressed data which is bundled with its own decompression instructions.Data URLsIn case you aren’t familiar with data URLs, they are URLs whose contents are in the URL itself. They all start with data:. Here, let me show you with this interactive mock browser:Interactive content: Visit the website to play with interactive content!Alternative text: browser demo(Hint: edit the URL in the address bar!)When you load a data URL, the browser shows the content embedded in the URL directly.So, that’s it? Website in a URL? — Use data URLs! Easy!Wait, there’s more! The portablink tool does some more things than just putting your HTML in a data URL. The tool also compresses your conte
7ヶ月前
記事のアイキャッチ画像
Introducing portabl.ink
leanrada.com notes
I just released a small weekend project called portabl.ink. It’s a tool to compress whole web pages into a self-contained portable link.Try it out online at portabl.ink!For some examples and more details, read the project page.Next, I will write another post on how it works under-the-hood. Stay tuned!
8ヶ月前
記事のアイキャッチ画像
Sort, sweep, and prune: Part&nbsp;2
leanrada.com notes
For RSS readers: This article contains interactive content available on the original post on leanrada.com.In the first part, we figured that sorting lets us exploit the transitive property of inequality to optimise the number of pairwise tests.We ended up with - let’s call it a “simplified version”, of the full sweep-and-prune algorithm.This part explores the more sophisticated versions of sweep-and-prune.Sophisticated sip and prune.Proper sweep-and-prune 🧐Let’s see how the original version tackled the problem (Not sure which one’s original, tbh).First, sorting widthy objects.To account for the width of objects while keeping the benefits of unambiguous sort order, we track the left and the right edges of each object as two separate points.This is done by maintaining a separate array of edge points corresponding to the objects’ left & right edges.See how it works by playing with this draggable demo. The left and right edges of each ball are visualised. These edge points are stored in a...
9ヶ月前
記事のアイキャッチ画像
Sort, sweep, and prune: Collision detection algorithms
leanrada.com notes
For RSS readers: This article contains interactive content available on the original post on leanrada.com.Sweep-and-prune is my go-to algorithm when I want to quickly implement collision detection for a game. I think it’s an awesome and elegant algorithm, so I wrote a post about it.This post is lengthy with many examples and explanations, thus split into two parts. You can jump to specific bits using this special springboard:Part 1: Simplified version 🔍 Visual comparison📝 CodePart 2: Sophisticated versions 🔍 Visual comparison📝 Final codeAs for the rest of the post, I try to paint a picture of what I think are first principles and show it with interactive demos! Let’s go!Collision detectionAs you may know, the problem of collision detection is pretty common in video game programming. It’s a prerequisite to the implementation of certain game mechanics or simulations.Goombas collidingSome of these mechanics include: preventing characters from passing through each other, goombas turnin...
10ヶ月前
記事のアイキャッチ画像
Volley ball game in pure CSS
leanrada.com notes
I don’t know why I did this, but it was fun / funny.This is a volley ball / tennis game implemented purely using HTML and CSS. Features real-time action gameplay and score counting.👉 See the Pen Pure CSS Volley Game on CodePen! Video: video of CSS volley ball video game | Source: /notes/pure-css-volley-ball-game/video.web.mp4
1年前
記事のアイキャッチ画像
Dynamic patrol behaviour with Markov chains
leanrada.com notes
For RSS readers: This article contains interactive content available on the original post on leanrada.com.Hi, this post is about a game AI algorithm for stealth games.But first, here’s a preview demo! Full demo at the end of this post. In between, I’ll explain the background, the process, and the results!Interactive content: Visit the website to play with interactive content!Alternative text: interactive demo of the dynamic patrol algorithmBackgroundI enjoy stealth games. However, I felt like the genre has become formulaic. Nowadays, we have standardised light, shadow, and noise mechanics. We almost always get discrete levels of alertness where on one end NPCs have wallhacks while on the other, NPCs have amnesia.Screenshot of Splinter Cell: Chaos Theory from mobygames.com. This game is good.The most immersion-breaking moment for me was when you get spotted, the subsequent investigation consists solely of staring at the ground where you were last seen. Like when you get spotted at an en
1年前
記事のアイキャッチ画像
A review of all IDEs I’ve ever used
leanrada.com notes
Notepad.exeinside the editor UI, like this one. Watch out for the insides! ._____________.Macromedia Flash 8What is Macromedia Flash? Macromedia Flash, or just Flash, was a Web browser plugin that everyone had back in the day before JS was powerful enough. It was used for animations, interactive experiences, Web games, Web ads, YouTube, you name it. It was the platform of all webapps before the term webapp became a thing. It was also the name of the authoring software, or IDE. This IDE, as you can see, was very much focused on the graphics and animation part of the authoring experience, not so much on the programming side of rich Web applications. Scripts existed merely as augmentation of objects in the scene. 6/10 for me. FlashDevelopwith a “real” programming IDE with refactoring, build configurations, logging, libraries, and more. in bitmap fonts. Very crisp in the old CRT monitors with 800x600 screen resolution. I customized it with some downloaded programming fonts too. ’s simple a
1年前
記事のアイキャッチ画像
Pure CSS tic-tac-toe with game AI
leanrada.com notes
For RSS readers: This article contains interactive content available on the original post on leanrada.com.As a software developer, I’m always looking for new and fun ways to challenge myself. Some time ago, I decided to implement tic-tac-toe with AI using only HTML and CSS. That is, no JavaScript! I already knew about the possibility of advanced CSS interactions (e.g. fancy checkboxes), but I wanted to see how far I could take it.Here’s a CodePen of it! Can you beat a style sheet in a game of tic-tac-toe?See the Pen Pure CSS Tic Tac Toe AI by Kalabasa (@kalabasa) on CodePen. In this post, I’ll write about the steps I took to make it, starting with the fundamentals.Building blocksBefore starting to build anything complex, it’s important to start small and think about the basic elements. Unlike JavaScript, HTML and CSS are declarative languages. We can’t have procedures or functions, control flow, if-statements, and the like. Instead what we have are markup and rules. We’ll build upon th
1年前
記事のアイキャッチ画像
Bitwise keyboard input method
leanrada.com notes
For RSS readers: This article contains interactive content available on the original post on leanrada.com.This post is about how I achieved the power of 15 keys using just 4 keys on the keyboard. I go over the motivation, the design, and the implementation. At the end, I wrap the solution into a small library. Maybe you’ll find it useful!RationaleI use a compact keyboard called the Lily58 as my main keyboard. It’s a column-staggered split keyboard.The Lily58 keyboard. Photo from github.com/kata0510/Lily58As the name implies, it has only 58 buttons instead of the normal 80+ buttons. Space was limited and it was hard to fit all the letters, numbers, symbols, and other unique keys that I need.The function keys (F1, F2, F3, etc) were particularly cumbersome. I don’t use them very often, yet they take a lot of space. You can see with my previous function key layout that they’re not very space-efficient:My previous layout with function keys on the right half of the keyboard. It’s on a layer
1年前
記事のアイキャッチ画像
Simple image recognition with vanilla JavaScript
leanrada.com notes
Hi there! I want to share my experience with an image recognition problem I faced in an art project (It was an augmented reality art project).Image recognition problems come in different forms.As part of the project, I needed a mobile app to be able to recognize a particular art piece. Then it can overlay virtual effects onto the real-world image. The goal was to have a unique and engaging experience!The app should recognize when the target art piece has been aligned.There are various solutions available for tackling this problem, ranging from basic histogram matching to advanced convolutional neural networks. There are even libraries that can provide a solution right out of the box! But I decided to take on the challenge of developing my own solution instead of relying on existing tools. Not only did this allow me to learn something new, but it also let me have some fun approaching the problem!TL;DR - It converts the camera image into a feature vector and then compares that against a
1年前
記事のアイキャッチ画像
Neural networks × genetic algorithms for Pong
leanrada.com notes
Pong AINeural networks & genetic algorithmsNeural nets have been around since the 1950s/60s. This Pong AI experiment was done back in 2014, around the time when a revival in neural networks was accelerating, that later brought about the deep learning, modern artificial intelligence that we associate with the term "AI" nowadays.The Pong AI here, hovewer, has nothing to do with that deep stuff. I was largely unaware of those new developments in AI back then. This one is a very simple implementation of a 3-layer feedforward neural network.The inputs of the network are ball position, heading, paddle position, etc. and the outputs directly control the paddle.Visualization of the network. Sorry about the pixelation (it was a product of that time).Instead of the usual backpropagation, the learning method I used here was a genetic algorithm. It’s an evolutionary algorithm that mimics natural selection, reproduction, and mutation to optimize the neural network’s weights. This was how the Pong "
1年前