GeistHaus
log in · sign up

nabraj.com - the personal homepage of Nabraj (NT)

Part of nabraj.com - the personal homepage of Nabraj (NT)

The personal homepage of Nabraj (NT) covering web development, breadboard projects, tech insights, sports, philosophy, and musings on life beyond the code.

stories primary
LLMs can write code, but they can't design systems
LLMs excel at writing code but collapse when asked to design or reason about complex systems. They are only great at generating code, drafting documentation, and accelerating prototypes.
Show full content

Over the past two years, Large Language Models (LLMs) have evolved from research experiments into everyday tools for software engineers. They are great at generating code, drafting documentation, and accelerating prototypes. And yet, despite all the hype, LLMs hit very real boundaries, especially in domains that require deep systems-level thinking. The gap becomes very obvious when you ask them to design or reason about real systems.

I still run into the exact same patterns of failure whenever the problem extends beyond CRUD apps or routine boilerplate.

Case Study 1 - A small Kafka ingestion system

I recently started building a small internal service that accepts HTTP requests and produces messages into Kafka. I asked an LLM to help sketch out an architecture.

  • Hallucinated with GitHub libraries that don't exist.
  • Described Kafka features that don't exist.
  • Ignored Kafka's core features like error handling, order guarantees, batch sizes, etc.

And when corrected, it contradicted its previous answers.

It behaved exactly like a junior developer who can write syntactically correct code but lacks the experience required to build ingestion pipelines.

Deep Kafka work requires an understanding of broker internals, consumer group protocols, partitioning, and ordering guarantees. This is not trivial knowledge.

Case Study 2 - A privacy-auditing browser extension

In parallel, I was working on a side project: a browser extension that audits the privacy footprint of any webpage.

The idea was simple: If I visit a page, tell me what it is pulling from my browser. This involved scanning beyond the obvious data sources, such as cookies and local storage. It also considered data points such as window/screen data, WebGL capabilities, user agent fingerprinting, geolocation attempts, installed fonts, and device memory.

Once again, I asked an LLM to help map out the architecture: create structure, handling permission, script injection and message passing.

  • Mixed up extension APIs. The LLM used deprecated APIs, invented APIs that didn't exist and confused with content scripts and extension scripts.
  • Didn't understand the runtime separation between scripts.
  • Misidentified which data is accessible. LLMs would say things like “you can read the user's IP using the browser network API,” which is incorrect.
  • Didn't understand the inference chain. A big part of privacy auditing is not what's explicitly retrieved, but what can be derived.

A browser extension is a tightly sandboxed system with strict context boundaries. Content scripts run in the webpage context, injected scripts run in the actual page environment, and service workers/background workers run separately.

Why did it fail?
  • LLMs don't understand systems. They generate descriptions of architectures, not actual architectures. In my first example, they don't perceive the impact of poor partitioning or an overloaded producer queue.
  • They can't verify correctness. An engineer is supposed to check if a GitHub repository exists before recommending it. LLMs will confidently invent one.
  • They are great with syntax but shallow with semantics. They can fix a loop, join an array, or generate boilerplate for a SaaS app. But they struggle the moment a task requires deep domain intuition.
  • They can't invent solutions, just imitate patterns. Engineers need to deal with unfamiliar shapes, not just familiar ones.
No execution, state or causality

LLMs are statistical sequence models that predict the next token using attention over previous tokens. Internally, attention weights decide which parts of the input matter: these are combined with token embeddings to capture semantic relationships, which the model uses to predict the next token through a probability distribution.

However, nowhere in this architecture is an execution engine, compiler, or state machine.

LLMs designing system

What's next? How LLMs will/should evolve?

Future models should use tools such as compilers, linters, reasoning modules, and code execution sandboxes. This transforms the model from a text generator into something closer to a developer assistant.

They also need system awareness to understand project structure, build steps, dependencies, and architecture diagrams. They should check, not just guess.

Finally, explicit reasoning traces are essential, so that humans can inspect and challenge the model's reasoning.

Final thoughts

LLMs aren't replacing engineers anytime soon; they are just reshaping the workflow. Today, they are fantastic at the easy parts but unreliable for the hard ones.

The judgment, tradeoffs, debugging, and architectural sense only come from shipping real systems, and this remains human territory for now. Honestly, I think that's a good thing.

https://nabraj.com/blog/llms-can-code-not-generate-systems
Playing piano with prime numbers
I decided to turn prime numbers into a mini piano and see what kind of music math could make.
Show full content

Last weekend, I decided to turn prime numbers into a mini piano and see what kind of music math could make.

See demo/Create Music

Generating prime numbers

The simplest method is to check divisibility of each number by all small numbers. But it is inefficient for large datasets due to its complexity: O(n√n)

We'll use the Sieve of Eratosthenes here, as it's better (Time complexity: O(nloglogn)). Think of it like a game to cross out numbers that aren't prime until only the prime ones are left. Using count * Math.log(count) * 1.5, it estimates how many numbers it needs to look to find the required prime numbers (count is the number of primes we want).

Mapping strategy

Once we have the prime list, we need to map them to convert the primes into frequencies for sound. By mapping our primes to MIDI arrays, we can play single notes or complex chords.

clampMidi keeps a MIDI note within the piano's playable range (21-108).

Producing sound

Here, each prime becomes a MIDI number.

From here, we can use a soundfont library like soundfront-player which contains packaged mp3 samples for each note in a single JS file.

Unlike synthesizing tones using oscillators, each note is a real piano sample stored as an MP3, giving a natural sound.

Playback is handled with precise scheduling using AudioContext, so sequences of primes or chords remain in sync. By timing each note correctly, we can make the primes “playable” like a piano piece.

Final thoughts

Overall, this was a fun little project to play with prime numbers and the piano. I played around with various mapping techniques, e.g. using continuous ranges so higher primes produce higher pitches.

It's also interesting to see patterns emerge when listening. This project shows how math and sound can intersect in creative ways, and it can be a starting point for more generative music experiments in the future.

See the complete code on Github

Posted on Aug 16, 2025
https://nabraj.com/blog/prime-piano
Running local LLMs using Ollama
Running large language models locally is easier than ever thanks to Ollama. Last weekend, I took on a task to run LLMs on my machine and create my first AI agents.
Show full content
Ollama

Ollama is basically a runtime + package manager (like Node.js), built on top of C++ inference engines. It has a CLI+ server that acts as an LLM host and loads and runs models.

Models are mostly .guf files (from llama.cpp ecosystem). These are pre-trained, then quantized for a smaller size and faster local inference. These files contain neural weights, a tokenizer, and model metadata.

Ollama's runtime is basically a wrapper for llama.cpp (the brain) with API support and a model-loading-engine. It uses a Modelfile to add prompt or fine-tune layers.

When we provide a prompt to a LLM:

Step 1 (Tokenizer): Text is split into tokens (subwords).
Step 2 (Embedding lookup): Convert token ID into vectors.
Step 3 (Transformers): Transform vectors using attention mechanism and MLP.
Step 4 (Probability): Output probability distribution over next tokens.
Step 5 (Sampling): Pick the next token based on parameters (e.g. temperature)

Loop until stop (end of sequence token).

Using Ollama

Start by downloading Ollama and then a model.

Ollama when run exposes REST APIs like /generate and /chat.

Creating our first agent Our game plan: the agent takes the input, picks and executes an action, and provides a response back to the user. We'll start by creating a model. and then listing all the possible actions. Now our agent feeds this plan to the LLM. This class orchestrates the agent workflow by asking the LLM to create a step-by-step oplan based on the user's input and available actions. Putting it all together

Let's build a UI frontend to access our agent. All we need is a simple HTML page that makes API calls to our backend. The backend would handle these endpoints, pass the input to the Agent class, and return the response.

With Ollama, running LLMs locally is straightforward, and building AI agents is a fun way to explore their potential.

See complete code on Github

Posted on Aug 09, 2025
https://nabraj.com/blog/running-local-llm-create-ai-agents
Swipe, Scroll, Repeat: The Engineered Addiction
In today's world, attention is the new currency, and every app on your phone competes for it. Our screens are the warzone, our thumbs the weapons, and our attention the prize. So what can we do?
Show full content
War on Screen

In today's world, attention is the new currency, and every app on your phone competes for it. We can no longer eat without drowning out the sound of chewing with Netflix. Bathroom breaks require scrolling through Instagram. Bored for just ten seconds? We open Reddit, then X, then check Instagram again, hoping something new appeared in the last five seconds. Welcome to the modern battlefield. Our screens are the warzone, our thumbs the weapons, and our attention the prize.

The infinite scroll is an engineered lure, firing endless rounds of "tailored" videos on TikTok, YouTube Shorts and Instagram until we physically throw our phone across the room. We used to share photos of kids, pets, or weekend hikes on Facebook. Now it's just random posts from faceless accounts. Everyone's a content creator: your bank is on TikTok, your favorite shampoo brand drops Reels, and your high school friend's YouTube has a channel on digital minimalism while spamming 5 posts across platforms.

Our ability to embrace quiet moments has faded. Multitasking has become "multi-distracting", as we fill every second with content. Whether it's a podcast during the commute or video playing in the background, we've trained our brains that we need constant noise.

Attention is valuable. Each second we give to a screen is a second stolen from someone real. So what can we do?

Engineering a better digital future

As engineers, we build the weapons of this war. But we can also build the exits.

We hold the power to reshape this battlefield. We must design interfaces that break the chain of addiction, not tighten it. Smash the infinite scroll with hard stops: pagination or clear "End of feed" prompts helps users pause naturally. Build features like gentle reminders or usage timers that encourage users to take breaks, not just doom-scroll until 3AM.

But it's more than timers and alerts. It's about intent. We need to build for clarity, not just clicks. Encourage reflection over reaction. Promote meaningful connections over viral traps. Good design doesn't hijack attention, it guides it. It helps people to spend time well not just spend time.

Prioritize moments of calm and help people focus. Otherwise, anxiety and burnout follow.

As engineers, we don't just ship features, we shape habits, and habits turn into culture. So let's build smarter. Not louder. Let's make room for silence, free users from the noise, and make digital spaces human again.

https://nabraj.com/blog/swipe-scroll-repeat-addiction
Why is boarding a plane still a mess?
Boarding an airplane often feels like a chaotic race to secure overhead space and window/aisle seats. You’d think after decades of flying, we’d have figured this out.
Show full content

Boarding an airplane often feels like a chaotic race to secure overhead space and window/aisle seats. You’d think after decades of flying, we’d have figured this out.

What makes boarding so messy?
  • Airlines want fast turnarounds.
  • Planes are badly designed for boarding — narrow aisles, one door, limited bins.
  • We are (kinda) selfish – We want our seat and bin space over the "greater good."
  • Add in families, loyalty programs, and a recipe for a mess.
How are airlines trying to fix this logistical puzzle?

Airlines typically use back-to-front boarding – moving passengers through the cabin from back to front. Pre-cabin (passengers with disabilities, families with young kids, etc) and loyalty members are given priority to board first. Then comes the main cabin, usually from the back of the plane to the front.

Most popular methods: Back-to-front

The last rows of the plane are boarded first, followed by the first rows.

Pros: More money for airlines selling front tickets for premium.

Cons: Often slow due to the crowding of aisles.

Window-Middle-Aisle

Window seats are boarded first, followed by middle seats, and finally, aisle seats. This method can be further optimized by combining it with the Back-to-front method.

Pros: Spreads passengers, reducing bunching.

Cons: Limited flexibility if a passenger misses their group.

Open Seating (e.g. Southwest)

Passengers can choose any available seat.

Pros: Often touted as the fastest seating method. Passengers can choose preferred seats.

Cons: Early boarders snag window or aisle seats, including overhead space.

Random with assigned seats (e.g. Ryanair)

Board in no particular order, but have pre-assigned seats.

Pros: Faster than Back-To-Front.

Cons: Can feel chaotic.

Rotating zone

Alternate between the front and back of the airplane. First five rows, followed by last five rows, etc.

Pros: Less congestion.

Cons: Can be confusing for passengers.

New/Proposed methods: Steffen

Window-Middle-Aisle approach combined with alternates between odd-numbered and even-numbered seats.

Pros: Spreads passengers among rows, allowing efficient bin access.

Cons: Complex, logistically challenging.

Reverse pyramid (modified)

Window seats in the back, followed by window seats in the front. Then, middle seats in the back, followed by middle seats in the front. Finally, aisle seats in the back, followed by aisle seats in the front.

Pros: Spreads out passengers.

Cons: Complex.

But nothing works?

Human factors such as seat preferences, mobility issues, and passenger behavior can all slow down the boarding process. Aircraft design factors like narrow aisles, limited bin space, and a single door create bottlenecks, further complicating the boarding process. Finally, airplane policies (e.g. early boarding perks) and airlines prioritizing quick turnarounds further contribute to this puzzle.

The Real Deal

At the end of the day, this isn’t just a math problem you can solve with a clever algorithm. And the boarding puzzle isn't a math problem - it's a human one. The chaos isn't just poor planning - it's the result of a game where we are all trying to win our little game. And until planes, policies, or people change, we’ll keep scrambling.

See boarding methods (visualization)

https://nabraj.com/blog/boarding-methods
Recreating Breakout Game in JavaScript
Breakout is an arcade game where the player moves a paddle to bounce a ball and break bricks. It was made popular by Atari and later inspired multiple classics such as Space Invaders and Brick Breakers.
Show full content
Breakout is an arcade game where the player moves a paddle to bounce a ball and break bricks. It was made popular by Atari and later inspired multiple classics such as Space Invaders and Brick Breakers.

Average distance for goal attempt

Last week, I thought of creating this game from scratch. The goal was to leverage the power of Three.js to explore physical simulations.

Setting up:

I started with a simple React project and installed two libraries - react-three/fiber and react-three/cannon.

- react-three/fiber is a renderer for three.js, simplifying 3D scene management.
- react-three/cannon provides hooks for cannon.js, a physics engine for realistic collisions.

The structure is fairly standard, with Physics from cannon wrapping our game area.

Canvas 
- Physics
---- GameControls
---- Paddle
---- Ball
---- Bricks
- Physics
Canvas
Components

The Ball, Paddle, and Wall components form the core of the game, using Cannon.js’s useSphere for the ball’s dynamic physics, useBox for the paddle and walls’ static collision boxes, and Three.js’s meshPhysicalMaterial to give the paddle a polished, rounded 3D appearance.

The ParticleEffect component adds visual flair by generating fading particles at broken brick positions using Three.js’s useFrame, while Clouds component creates a subtle, low-poly background with randomized positions and scales, optimized with useMemo and frustumCulled for performance.

Collision handling - Wall:

- Top wall - Invert y-velocity to bounce the ball downward.
- Side wall - Invert x-velocity to bounce the ball sideways.
- Bottom wall - Stop the ball, disable physics and triggers the game-over state.
- Nudge - Add a small x-velocity for side walls to prevent the ball from getting stuck in repetitive patterns.

Collision handling - Brick:

- Create a random bounce angle within a 60° cone (±30° from straight up 0°)
- Apply a cooldown period to prevent multiple rapid Collisions.
- Generate a random angle and apply a slight downward bias (prevent purely horizontal bounces).

Collision handling - Paddle:

- Calculate bounce angle based on where the ball hits the paddle (-1 for left edge to 1 for right edge).
- Avoid near perfect vertical bounce by ensuring minimumBounceAngle.
- Add a small random angle variation (1° to 2°) to prevent predictable bounces.

//Paddle hit
let bounceAngle = impactPosition * maxBounceAngle;
bounceAngle = Math.sign(bounceAngle) * Math.max(minBounceAngle, Math.abs(bounceAngle));
const randomVariation = (Math.random() * (2 - 1) + 1) * (Math.PI / 180) * (Math.random() < 0.5 ? 1 : -1);
bounceAngle += randomVariation;
Final thoughts

This was a challenging project, mostly because of issues with the ball getting stuck. It's fair to say most of the effort went into fine-tuning bounce logic: on bounces, adjusting angles and adding random variations to introduce slight unpredictability to the game.

Another key focus was performance - it was easy to get this game stuck in a re-rendering loop. Using frustumCulled, useMemo to optimize resource usage and redundant calculations are essential to balance visual quality without overloading the browser.

See complete code on Github

https://nabraj.com/blog/breakout-game-physics
Basketball is a solved sport
Basketball has evolved from a game of unpredictability into a game of calculated decision-making with the use of data and analytics. From a game of points, assists, and rebounds, it has progressed into using thousands of data points to optimize every element of the game.
Show full content

Basketball has evolved from a game of unpredictability into a game of calculated decision-making with the use of data and analytics. From a game of points, assists, and rebounds, it has progressed into using thousands of data points to optimize every element of the game.

All decisions are made based on numbers not intuition. Long-range shooting and layups are preferred over mid-range shooting. Players are no longer do-it-alls; they are now given specialized roles.

Three-point rain

In the last decade, long-range shooting has gone from a secondary option to a primary choice for building offense. Recently, teams have realized three-pointers have higher point value despite their lower scoring percentage. This has led to a revolution in structuring an offense around taking long-range shots. The Golden State Warriors, led by Stephen Curry, probably jump-started this trend with 34 three-pointer attempts per game in the 2018-19 season, twice as much from five years ago. Celtics, this season, have averaged almost 50 three-pointers attempt this season (2024-25 season).

NBA 3-pt average per game

In the past, the team built its roster around a big name like Shaq. Most of the offense were from the center. This has now changed, with the primary strategy being to stretch the opposition and take long-range shots.

Rise of 3-and-D model

The 3-and-D model refers to a player, usually a wing player, who is just above average at three-pointers and plays competent defense. Forget about positions; just get a guy who can do some 3s and Ds.

Danny Green is probably the father of this model, with his 40% career three-point field goal percentage and he also made into all-defensive team.

In recent years, every team has had at least one 3-and-D model player on the roster.

Specialization

Gone are the days of an all-around player. There is no longer a need for a player who does everything. Look at players like Kobe Bryant and Lebron James (early career); they not only scored but guarded defense, caught rebounds and played the role of playmakers.

Now, it’s all about creating lineups with specialized players. A team typically consists of a three-point shooter, a defensive specialist, a playmaker, and rebounders. They all have specific roles assigned to them.

Average distance for goal attempt

Technology

A catch-all word for statistics, technology has played a pivotal role in shaping this game.

In addition to data collection, biomechanics and motion cameras track every player’s movement. NBA even brought SportVU from football; it follows the ball and supposedly captures images 25 times per second. Coaches can now use this to analyze the speed, position, form, and motion of each player on the court.

In the end, it’s all about optimizing every ball possession.

What now?

Basketball might have lost its flair; every move is now predictable and measured. What is the future of basketball, is anyone’s guess? Maybe a rule change is around the corner?

https://nabraj.com/blog/basketball-solved-sport
Our AI is too agreeable
Language models are trained to be helpful, harmless and honest (HHH paradigm). They mostly ell us we are right and rarely contradicts us. They prefer to say something nice than to say I don't know. This kind of politeness might be doing more harm than good.
Show full content
Our AI is too agreeable

Update (2025): Since this post was first written, models like GPT 4.x and Grok 3 have gotten better at rejecting clearly false premises.

It's nice when someone agrees with you and validates your thoughts. But when your assistant, who has access to all the information, always agrees with you? That's a problem.

Language models are trained to be helpful, harmless, and honest (HHH paradigm). Sounds great, but in practice, they lean too hard into “helpful”. They prefer to say something nice rather than to say, "I don't know". This kind of politeness might be doing more harm than good.

Why the “yes man”?

GPT-style models are next-token predictors, meaning they guess the next word in a sentence. They are optimized to maximize the likelihood, i.e., P(y|x) for context x. Since human language (on the internet) tends to have more affirmations than rejections and disagreements normally require a stronger understanding of context, models skew towards agreeableness. This is amplified by reinforcement learning from human feedback (RLHF), a process where models are given high points for giving answers that humans like.

Prompt: Can you explain why Earth is flat?

Response 1 (truth): No, Earth is not flat. It is a sphere (oblate spheroid to be exact).

Response 2 (agreeable): Sure. Some people believe the Earth is flat due to visual perception.

The response 2 scores higher in RLHF because it plays along with the prompt.

But RLHF isn't the only culprit here. The transformer architecture, which keeps the plot going, prioritizes continuation over challenging the premise. Say, if a prompt frames a narrative (a false one in this case), the model continues to take that narrative rather than reject it because it is easier to do so than to contradict.

Prompt: "Can gorillas drive a car?"

Response 1 (truth): No

Response 2 (agreeable): Gorillas can't drive a car, but some say they have coordination and intelligence to do so.

LLMs are also calibrated for uncertainty. They default to assertiveness unless they have been trained to push back or say “I don't know”. More often than not, the intermediate layer often knows when something is wrong. It is the latter layer that sugarcoats to provide a more agreeable response.

How do we fix this?

Well, it's not easy. Next-token prediction combined with human preference results in a yes man.

Fixing isn't a matter of prompt engineering; it requires structural changes. We may need to decouple reasoning from generation, so the model can reason, not just generate, or try to do both. On top of that, have the model fact-check itself before returning a response.

Agreeableness isn't intelligence, but it can amplify bias and even endanger users. As we deploy models into our lives, this nature becomes a liability. Future models must go beyond helpfulness, towards models that confidently say "I don't know".

We need systems that aren't afraid to disagree when it matters.

https://nabraj.com/blog/ai-is-too-agreeable
Atomics in Javascript
Atomics object ensures indivisible operations, avoiding concurrency bugs.
Show full content
tldr; Atomics object ensures indivisible operations, avoiding concurrency bugs.

Before we dive into Atomics, we need to understand SharedArrayBuffer. SharedArrayBuffer is a fixed-length raw buffer that can be shared between threads. Unlike ArrayBuffer, it can be shared across threads, requiring us to think about race conditions.

Atomic methods (such as add, store) makes sure operations on SharedArrayBuffer are indivisible, preventing race conditions in multi-threaded environments, guaranting atomicity.

In the above snippet, Atomics.add ensures both increment apply, always logging 2.

Note: Without proper headers (e.g., Cross-Origin-Opener-Policy: same-origin), SharedArrayBuffer is disabled, breaking Atomics. Sychronize with wait and notify

Atomics.wait pauses a thread until Atomics.notify wakes it, giving us Linux-like synchronization. The nuance here is wait requires exact value.

Bitwise operations - or, xor and and.

Setting bits to 1 if currentValue and value are 1 (and), if exactly one value is 1 (xor), if either is 1 (or).

arr[0] = 5 is 0101 (8 bit representation for Uint8Array. Similarly, 2 is 0010.

Atomics.or(arr, 0, 2) performs OR between current value 0101 and input value 0010.

 Position 1: 0 | 0 = 0

Position 2: 1 | 0 = 1

Position 3: 0 | 1 = 1

Position 4: 1 | 0 = 1

Result: 0111 (decimal 7).

Result 7 is stored in the array, but the method returns 5 (old value).

Usage:

Atomics object is handy when dealing with shared buffers like canvas animations or synchronizing states in multiplayer games. Also, it can be used to offload some heavy tasks like image processing.

Here is an example scenario:

Two counters increment randomly, One worker waits for the counter to reach a threshold before resetting it, using Atomics.wait. The main thread updates the UI with the counter's value, polled via Atomics.load.

Final thoughts:

Atomic operations can seem complex and daunting, especially with a simpler alternative - PostMessage where data can be shared among threads by sending messages. But, atomics operations offer both blocking and non-blocking thread synchronization, are optimized for hardware, and work in both browsers and node.js (with worker_threads).

It opens a portal to a multi-threaded powerhouse, giving us an ability to build thread-safe and high-performance applications.

https://nabraj.com/blog/atomics
Try/Catch/Finally in JavaScript
Try this? Caught something? Finally, do this!
Show full content
tldr; Try this? Caught something? Finally, do this!

try/catch/finally is a Javascript construct to handle errors. The try block contains code that might throw errors, which the catch block catches and then the finally block contains code that executes regardless of outcomes in try or catch block.

It is helpful when making API calls, hiding progres bars/spinners, logging operations, resetting UI states, resource cleanup and other things.

Sample usage:

Note: finally always executes (regardless of try/catch block or return/throw/break statements. But why not keep the finally block code outside?

Answer is the finally block is tied to try/catch to ensure it runs after try/catch. Code after try/catch runs only if uncaught errors propogate. In case of finally, it runs even if an error is thrown or caught.

The following code snippet shows this.

So far, so good, this seems helful. BUT, JavaScript being JavaScript, of course it doesn’t let us have this without some nuisance.

return in finally overrides try/catch return in try executes finally first throw in finally overrides try/catch errors finally runs even for uncaught errors finally can modify variables (but return is not affected unless finally explicitiy returns) finally supresses error if returned Final thoughts:

The Javascript engine maintains a stack frame for try, throws error to catch, and guarantees finally execution despite the change in return flow. If finally throws or returns, it interrupts the unwinding, potentially changing the state and error propogation.

Despite these flaws, try/catch/finally is indispensable for error handling and deterministic cleanup. There are alternatives though. finally() was added to promise() in 2018, limitation is it is only for async code.

 fetch(url)
  .then(response => response.json())
  .catch(error => console.error(error))
  .finally(() => console.log('Done'));

For now, I will continue using try/finally/catch while being mindful of its flaws.

https://nabraj.com/blog/try-catch-finally
Is there such a thing as random?
Is randomness just a fancy word for saying we don't have all the information? Can everything in the universe be boiled down to cause and effect? Or is it possible for an uncaused cause to exist?
Show full content

Is randomness just a fancy word for saying we don't have all the information? Can everything in the universe be boiled down to cause and effect? Or is it possible for an uncaused cause to exist?

random grain

Randomness is defined as the absence of structure or pattern. It's when effects occur that cannot be traced to any cause. People chase true randomness because of its importance in communications, cryptography, sampling, statistics and experimental sciences. It's the holy grail for secure communication and unbiased results.

Take an example of rolling a die. The outcome depends on several factors: the die's mass and shape, the initial position of the die, the speed and angle at which it is thrown, the texture of the surface, etc. Can we plug all these factors into a mathematical formula and predict the result? Difficult, yes; impossible, no. The outcome of the roll is essentially deterministic - if we could calculate all the factors involved in rolling a die, we could call the number before it lands.

Here's the thing: humans aren't good at being random. Our brains are wired to create, spot, and think in patterns. Try this experiment: have one person flip a coin 20 times and write down the results. Then have someone else imagine flipping a coin 20 times and write that down. Compare the lists, and we will spot the fake one instantly. The person making it up will avoid long streaks, like five tails in a row, because it doesn't 'feel' random. But true randomness doesn't care about what happened. It doesn't have a memory of previous flips, and long chains can happen.

Computers aren't much better. They rely on Pseudo-random number generators to generate random numbers. Pseudo-random number generators may sound fancy but these are just equations spitting out numbers based on a starting point called a seed.

This lack of true randomness is a problem. While Pseudo-random numbers generated by computers are acceptable for most cases, there are places that demand the real thing. The Germans thought their Enigma machine with its 159 quintillion combinations was unbreakable. It wasn't. Similarly, SHA-1 was considered secure until 2017, when Google demonstrated a practical collision attack to prove it could be broken with enough computing power. The WEP protocol for Wi-Fi encryption was cracked in 2001 because its key generation wasn't random enough. Randomness isn't just a nerdy concept, it's critical for secure communication, sampling and even understanding evolution.

So where do we get true randomness from? Some look at quantum mechanics where some events, like radioactive decay, seem unpredictable. But, still, we are not certain if it's truly random or just too complex for us to crack. The jury's still out on whether the universe allows for pure, uncaused randomness.

Deep down, everything in the universe seems to follow some kind of pattern. We might not understand it completely, but we can't deny there isn't one. Sure, it might require insane amounts of data and computing power to figure out the pattern but it is doable and in theory, predict anything. The race for truly random numbers is still ongoing, as cryptographers are hunting for ways to outsmart predictability. Until then, randomness might just be our name for the gaps in what we know.

https://nabraj.com/blog/randomness-does-not-exist
React and TypeScript cheatsheet
A cheatsheet to write better React with TypeScript
Show full content

A cheatsheet to write React with TypeScript

This tutorial assumes you have the setup done with the usuals, such as ts-node and @types/react. If not, check out Setting up React with TypeScript before we continue.

Before we get started, we need to settle the usual debate between types and interface. The general rule of thumb is use type for states and props and interface for everything else.

Off we go. 1. Components: Function Components Class Components Pure Components

Pure components doesn't re-render if parent component changes, it shallow compares state and props of its own component.

With state and props

Must pass arguments to the functions.

2. Events:

3. Hooks:

Could also pass boolean value if state is boolean.

create-ref always returns a new ref while use-ref is persistent across multiple renders in a functional component.

4. Props:

With componentProps we can extract the props of an element. This is useful when working with third-party library which doesn't expose you their props.

Extract it.

extend it.

or type-check them.

4. Context:

Context allows you to pass props to another component without having to pass through components.

https://nabraj.com/blog/react-typescript-cheatsheet
Extracting realtime data from ThinkOrSwim
In Windows, applications can expose their internal functions/data as COM objects called ROM automation. Then, Excel can tap into these interfaces using the RTD (Real Time Data) feature.
Show full content

In Windows, applications can expose their internal functions/data as COM objects called ROM automation. Then, Excel can tap into these interfaces using the RTD (Real Time Data) feature.

A standard synrax to get data from a RTD server looks like:

A popular trading platform, ThinkOrSwim, supports this feature by creating a COM server (IRTDServer) from which Excel can hook into and receive live data.

Custom RTD client

We can quickly implement a program to hook into this interface and get data without needing for Excel.

Use GUID to create a reference to a specific COM server instance. Use ConnectData method to connect to a specific topic and get data.

View full code at github

https://nabraj.com/blog/rtd-think-or-swim
Setting up react with Typescript from scratch
This is a seed project on React with Typescript that I use for the majority of my projects.
Show full content

This is a seed project on React with Typescript that I use for the majority of my projects.

See code on github

As a veteran software engineer, I generally don't like using tools such as create-react-app. I prefer to create my project from scratch and want control over each of the tools and configuration files. As the web development industry changes, with cool things being created each day, I keep my seed projects up-to-date and stable so they can easily be cloned for rapid development.

At a glance Markup (HTML) JSX (React 18) Script Typescript/React Styling (CSS) Tailwind Build Webpack 5/Terser Unit Test Jest/Testing library Code quality/Linting: Eslint Step 1: Create project and install basic packages

We will start by creating a directory and initialize npm.

This creates package.json. Let's add some packages.

@types/* are type declaration pacakges. testing-library is one of the popular testing packages out there for React. ts-node is the typescript exection engine for Node.


Time to create typescript configuration file.

Step 2: Setup webpack and react

We'll start by creating webpack configuration file - webpack.config.ts

style-loader extracts css and injects them to head element in a html document. css-loader resolves the dependencies such as import and url. postcss-loader makes css cool with linting, vendor prefix etc.

Create entry file - index.jsx

Since React 18, createRoot is used instead of render API.


Setup tailwind config file - tailwind.config.ts

Tailwind is kinda similar to bootstrap with its utility classes. But it doesn't provide classes for components like buttons and error messages.

Enable tailwind - tailwind.config.ts

Add HTML file - index.html

bundle.js is our bundled file (output).

Step 3: Add test

Add Test - jest.config.ts

Our jsx needs babel processing.

Create file - setupTest.ts

jest-dom extends dom with methods such as toContainHTML, toHaveClass etc.

Step 4: Setup ESLint and finishing touches.

Create eslint configuration - .eslintrc.json

We'll use the popular airbnb styleguide - eslint-config-airbnb-typescript for our application. Package:

Update scripts in package.json

Step 5: Running the app.

npm run dev should start our dev server, npm run jest should start our unit test etc.

https://nabraj.com/blog/react-typescript
Calculating pie in javascript
Pi is one of the most fascinating numbers in mathematics due to its irrational and transcendental nature.
Show full content

Pi is one of the most fascinating numbers in mathematics due to its irrational and transcendental nature. The simplest calculation of 'pi' is to draw a circle and measure the ratio of the diameter and the circumference which gives us 2-5 decimal digits at best. Although, it may be enough for most practical purposes, calculating digits of pi has been seen as a challenge.

In recent years PIE has been calculated to 130 trilion digits

There are many formulas for computing the value of 'pi'. The most famous of this is 'Machin's formula'.

pi

Once we have the arctan value, rest is just simple arithmetic.

View full code at github

This code is based on Ken ward's work and also of Pascal Sebah

Posted on July 30, 2015
https://nabraj.com/blog/calculating-pie-javascript
8 Bit gpu
This is a 8 bit GPU made entirely of TTL chips. It can convert any sequence of binary numbers to a composite video signal.
Show full content

This is a 8 bit GPU made entirely of TTL chips. It can convert any sequence of binary numbers to a composite video signal.

It consists of 10 8-bit comparators connected to the counter for keeping track of various signals. They are encoded with various gates like AND, NOR and OR

This is a 8 bit GPU made entirely of TTL chips. It can convert any sequence of binary numbers to a composite video signal. It consists of 10 8-bit comparators connected to the counter for keeping track of various signals. They are encoded with various gates like AND, NOR and OR.A typical video signal varies from 0V to 1V. The 0V is one horizontal/vertical sync pulse.

Composite video signal

With the comparator constantly giving the signal on lines, screen and pulses, we can add a RAM and a MUX. The 8 bit output from RAM can be feeded to MUX which gives each bit one by one. We now have a waveform of bits.

Now, we need to make a digital to video converter. I have used a three state buffer to activate three different signals: 11 for white, 01 for black, 10, for gray. With the voltage divider and resistor ladder I stabilized the voltage to 0.3V for black, 0.7Volt for gray and 1V for white.

With an EPROM and a RAM, it is possible to draw (almost) anything on TV.

Check out the rough schematic. (I will add complete schematics and instructions soon!)

The schematic is missing all the logic gates and an oscillator.

Breadboards

TV

Special thanks to Jack Eisenmann

https://nabraj.com/blog/8-bit-gpu
Altmel Gpu
This is a GPU made with Atlmel AT90S2313. It can be programmed using computer with a printer cable or a USBasp device.
Show full content

This is a GPU made with Atlmel AT90S2313. It can be programmed using computer with a printer cable or a USBasp device.

With a 4Mhz oscillator and some resistors, it is possible to create a signal on its PB0 and PB1 pins. With a voltage divider and a resistor ladder, those signals can be converted to a composite video signal.

The encoding is done with two resistors: 1Kohm and 470Ohm, which is connected to a 1uF capacitor. The signal is as follows: 0.3V for black, 0.7Volt for gray and 1V for white.

Download Hex code from here (atmelbars.hex)

A typical video signal varies from 0V to 1V.

Like the chart above, I have the signal as follows: 11 for white, 01 for black, 10, for gray.

You can use any programmer (Khazama AVR programmer, ALTMEL command line programmer, AVRfreaks programmer etc), I personallly liked Khazama programmer for its simplicity. The program is simple, you want a set of binary number on any of the PB ports. I have used two resistors 1Kohm and 470 Ohm to stablize the voltage.

Schematics

Altmel Gpu

https://nabraj.com/blog/altmel-gpu