Projects

Collagen

Collagen is a program that takes as input a folder containing zero or more image files (.jpeg, .png, etc.) and a JSON manifest file describing the layout of these images along with SVG components such as shapes and text, and produces as output a single SVG file with all assets embedded. I started this project because I was frustrated by the widespread rasterization of vector graphics and inappropriate use of image formats (using JPEG when a PNG should have been used, or vice versa) and set out to do something about it.

As I developed it, it became clear that a textual format for describing images could do a lot more than just place images and shapes at hard-coded locations on a canvas; it could also save the author time and effort by making it easy to specify where and how those elements should be placed. Therefore Collagen also supports defining and interpolating named variables, and implements a lisp-like language that allows one to compute expressions of variables such as cx: "{(/ (+ x_min x_max) 2)}" or d: "M0,0 L {(* radius (cos angle))} {(* radius (sin angle))}".

I believe that, among current text-based image editing software, Collagen is at a Pareto-optimal point of simplicity and power — it lets authors do nearly as much as they could with bespoke SVG-generating code, but without having to write that code.

COVID-19 Tracker

A collection of graphs displaying how coronavirus has spread throughout the world and in particular throughout the US. I built this at the beginning of the pandemic because I was curious how covid was spreading and news sites hadn’t yet developed their own dashboards. My goals in developing this were to display as much comparable data side by side as possible and to let users control which data they viewed through interactive controls.

The data was ingested with Pandas, the graphs and interactivity were built with D3 (in fact, this project is how I first learned to use D3), and the site itself was written with AsciiDoctor. The data was last updated in March 2021 because the data source shut down, but the site still works fine.

Quarantine Trivia

A collection of trivia games I put together to give friends something to play while hanging out virtually during the coronavirus pandemic. Technically, the interesting part of this was coding the process by which the PDFs were made: ingesting a CSV and producing LaTeX. Implementing the necessary flexibility — implementing various page layouts, automatically position elements, automatically deducing the correct way to escape text — was a fun challenge.

Advent of Code

2021

My solutions to the 25 Advent of Code 2021 problems. This was fun and challenging and a great way for me to learn Rust.

2022

Solutions to the 25 Advent of Code 2022 problems. No write-up yet, just solutions — except for Day 19, which I haven’t been able to crack yet. Like last year, I wrote the solutions in Rust. Unlike last year, both the language and rust-analyzer have had an additional year to improve, which made the experience even more enjoyable.

Interactive Math and Science Demonstrations

Working at the World Science Festival, I have produced a number interactive demonstrations that aim to elucidate mathematical and/or scientific principles. These demonstrations, written in HTML+CSS+JS and utilizing the D3 and Three.js libraries, aim to make complex mathematical and physical principles more accessible to anyone interested in science.

Demos are listed below.

Quantum Mechanics

The theory of quantum mechanics is built around the wavefunction, which in its simplest form is a complex-valued function over all space and time, associated with a single particle. It has the following properties:

  1. Its squared magnitude is the particle’s position’s probability density function.

  2. The Fourier transform of the wavefunction is the “momentum wavefunction”, and its square magnitude is the probability density function of the momentum. (The uncertainty principle results from the fact that a function and its Fourier transform cannot both be arbitrarily concentrated in their respective domains — the narrower one is, the more spread out the other is.)

  3. Determining how the wavefunction evolves over time is “just” a matter of solving the time-independent Schrödinger equation of the system in order to write the initial wavefunction as a linear combination of stationary states, evolving each stationary state in time independently, and then taking the same linear combination of the evolved states to find the wavefunction at the given time.

The demonstrations below are all based on, and aim to elucidate, these three principles.

Particularly Interesting Demos

These demos were challenging to implement or are just plain cool.

Double slit experiment

Demonstrates how interference leads to the double-slit effect. Implementing the animation of an electromagnetic wave traveling in 3D was fun.

Particle in a finite-height box

A particle in a finite-height potential well, such as an electron bound to an atom, can only exist at a discrete set of energy levels, which are the solutions to the Schrödinger equation in that well. This demo shows the permissible energy levels and the wavefunction at each of those energy levels. Because the Schrödinger equation in a finite well cannot be solved exactly, this demo required implementing a numerical solver in JavaScript to determine the permissible energy levels.

Particle in an infinite square well

Demonstrates how the wavefunction of a particle in an infinite square well evolves over time. Thankfully, the Schrödinger equation in an infinite square well has an exact analytical solution. However, this solution still involves the sum of an infinite number of terms. Therefore this demo lets the user choose how many coefficients they want to compute — the more they compute, the more accurate the demo, but the worse its performance.

The correspondence between a 1D wavefunction and its probability distribution

Demonstrates how quantum mechanics has been experimentally verified: by comparing an empirical probability distribution with the wavefunction that produces it. Sampling from an arbitrary probability distribution required numeric approximation and integration of the plotted wavefunction’s curve in order to construct the cumulative distribution function.

Wavepacket dispersion in 2D

Demonstrates how a wavepacket (a localized wavefunction) travels and spreads out in 2D when given some initial momentum. The fun part of implementing this was figuring out how to get sufficient performance while also drawing the (triangles of the) wavefunction on a grid dense enough to avoid visible jaggedness. The solution was to create a grid with adaptive density, which would be concentrated in the areas where the wavefunction had the largest curvature, as areas with low curvature can be rendered faithfully with fewer triangles. As the curvature of the wavefunction changed and areas of high curvature moved, the local density of the grid would change accordingly. This helped achieve a decent frame rate while not exceeding the triangle budget.

Other Demos

There’s nothing wrong with these demos, they just aren’t as interesting as the ones above.

Eigenfunctions in a 1D box

Shows the eigenfunctions of the time-independent Schrödinger equation in a 1D box.

Eigenfunctions in a 2D box

Shows the eigenfunctions of the time-independent Schrödinger equation in a 2D box.

Eigenstate orthogonality

Demonstrates that the functions \(\sin(n\pi x), n\in\mathbb N\) form an orthonormal set.

Evolution in Hilbert space

Demonstrates how the wavefunction of a particle in a box evolves over time: by rotating in the complex plane with a speed proportional to its energy.

Fourier transformed Gaussian

Shows how a Gaussian and its Fourier transform are related.

2D Gaussian

Shows a 2D Gaussian distribution and the level sets thereof.

Hermite polynomials

Plots the Hermite polynomials in a graph that automatically zooms to capture the function’s image.

1D plane wave

Shows how a complex-valued wave propagates in one dimension.

2D plane wave

Shows how a complex-valued wave propagates in two dimensions.

The double slit experiment

Shows what it would look like to perform the double slit experiment in real life.

The correspondence between a wavefunction and its probability distribution in 2D

The same as the 1D correspondence, but extended to 2D.

Wavepacket dispersion in 1D

demonstrating how a wavepacket (a localized wavefunction) travels and spreads out in 1D when given some initial momentum.

Special Relativity

The list of all special relativity demos is available here. None of them are particularly interesting — I guess special relativity doesn’t have the same “wow” factor as quantum mechanics, probably because continuous functions that evolve over time are more attention-grabbing than watching discrete events take place in two different reference frames. (Now, implementing the curved spacetime of general relativity in a browser…​ that would be cool.)

Math

Conic sections

Demonstrates how conic sections can be expressed as the intersection of a plane and an infinite double-cone.

Non-Euclidean geometry

Shows how flat and curved spaces can be differentiated by the sum of the angles of a triangle drawn on their surfaces.

Fractals

A tree-like fractal generator.

Other

World line — the one-electron universe

Demonstrates John Wheeler’s concept of the one-electron universe, where just one electron moving backwards and forwards in time creates what we perceive as electrons and positrons. The neat thing in this demo is that if you click “draw a random world line”, a truly random, nice-looking (i.e., smooth, devoid of kinks) curve is procedurally generated. Making this randomly drawn curve look nice was quite challenging, but fun.

Chemical dipeptide

Demonstrates how molecules move in a potential well. This was predominantly an exercise in tweaking animation paths and timing curves and getting 50 or so circles to animate smoothly.

Calabi-Yau manifold

Shows the projection of a Calabi-Yau manifold (a surface ubiquitous in string theory) into three-dimensional space. This was primarily a mathematical exercise — figuring out how to implement a projection of this high-dimensional surface in Three.js was not easy.

Inflation in the early universe

Shows how rapidly the universe expanded in its first 10−37 seconds of existence. The fun part of this was getting the animations and timings of the various events to be smooth and accurate.

This page was built using Antora with a theme forked from the default UI. Search is powered by Lunr.

The source code for this UI is licensed under the terms of the MPL-2.0 license.