~ $

cat developer.txt

developer.txt
// Developer. Looking for a permanent job.
 
Glimt is in open beta on iOS and built for Android. Paneless ships for macOS. I wrote Glimt's camera pipeline myself, in Swift and Kotlin, with shaders on both platforms, and measured my way to the two of them producing the same image.
 
I am in my second year of frontend development. Most of what is below is not on the syllabus. I learnt it because something looked wrong and I could not leave it alone.
 
Before I started coding I was a sound engineer. Studio, post production, and location sound. That is where the habit of measuring instead of believing comes from.
 
// This page answers what you are actually wondering: does he think, or does he guess?

Four cases

All four are in one shape: what the problem was, what I measured, what I got wrong, and what runs in production now.

The third part is the one I am proudest of. Listing what went well is easy. What actually says something about how I work is what I did when I found out I was wrong. Every number below is in the commit history, and you can ask to see any of it.

01

I built a decision on a number that could not carry it

Colour science · Metal · GLSL · SkSL

The problem
Glimt has its own film simulations. Fjord is fitted to the Fuji recipe R-Superia. In warm light we missed, and I had switched on a neutralisation step to correct it.
What I measured
A grey card under the crossing, two lighting setups, three measurements side by side: the iPhone raw frame, the target, and what Glimt actually delivered. In warm light the raw frame was already 1.2% from the target before we touched it. My step pushed it 15% too blue and 11% too little red. In daylight, where the step was barely on, we landed 1.1% from the target.
What I got wrong
I had switched the step on three hours earlier, on the strength of a sign analysis I got by inverting our own chain. That inversion was degenerate: R and B came out identical to four digits, and a third of the cube was rank deficient. The number could never have answered the question I asked it. A surface with a known answer and one reading did what a whole day of derivation could not.
In production
The step is off, and the grade is generated into all three shaders, Metal, GLSL and SkSL, from one script, with a --check in the test suite that fails if one of them drifts from the others. And I wrote a falsifiable prediction into the commit: with the step off, Fjord should land around 0.74 against a target of 0.732, and if it did not, I was wrong again.
02

I measured the cost and not the benefit

iOS · Android · ISP behaviour · product judgement

The problem
Pan from a wall to a face and the whole image got warmer. It looked like one of our own skin steps misbehaving, and we had three candidates that all touch skin and all react to faces.
What I measured
The lit wall read R/G 0.840 alone and 1.161 with a face in frame. A 38% relative change, on a look with no white balance shift of its own. I turned off all three of our own skin steps and watched the shift survive. That proved it: it happens in the phone's ISP, before we get a single pixel.
What I got wrong
The diagnosis was right. The decision was wrong. I locked white balance, and then someone said she looked ugly and orange in our look. My measurement was on the wall, not on the subject. When a face is in frame, the face IS the subject, and the camera balancing for it means the skin comes out right. The wall going warm is the price. I measured the cost and not the benefit, and concluded on half the books. Then I rolled it back.
In production
The camera's own face-prioritised white balance stays. So does the diagnosis, in a test that exists as much to preserve the conclusion as to guard the code. If those lines go, the whole investigation has to be done again from scratch.
03

The code that reported success and did nothing

Swift · Accessibility API · CVDisplayLink

The problem
Tiling window managers on macOS do not animate, because you have to move other apps' windows through the Accessibility API. My own file header claimed I had solved it with GPU compositing.
What I measured
First the cost per frame: 0.2 to 2 ms to move, 5 ms for Ghostty, 25 to 53 ms to resize in Safari. The frame budget at 120 Hz is 8.33 ms for every window put together. Then a controlled two-process test, which showed that both SLSSetWindowTransform and CGSSetWindowAlpha return CGError 0 and do absolutely nothing to a window another process owns.
What I got wrong
The header asserted the opposite of the measurement, and I had built three code paths on top of the assertion. Anyone reading that file, including me earlier the same day, would reasonably have concluded the effects worked and built on them. That is worse than useless. I deleted the lot rather than keep it warm.
In production
Verified afterwards: a window opening into a full grid starts moving at 191 ms, down from 236 ms, and runs 27 frames of pure translation. A move can instead be handed to the app itself via AXEnhancedUserInterface, which gives around 110 fps from a single message. Resizing stays with Paneless, because apps snap size rather than ease it.
04

Two error messages, one cause

Postgres · row-level security · Cloudflare R2 · end-to-end

The problem
One kind of send failed. The user saw two different errors, an hour apart, from two different systems: 403 {"error":"not yours"} from the file store, and new row violates row-level security policy from the database.
What I measured
"not yours" is the storage function's own string for a refusal. That function grants a write in exactly two ways: a row you own, or an intent you own naming the path. On the durable path the row is the server's to write, so the intent is the only one that can exist. And the code asked for the presigned URL at step 2 but wrote the intent at step 3. Every single send asked for permission before the permission existed.
What I got wrong
I read the two errors as two problems, because they came from two systems an hour apart. And the bug was invisible for the other kind of send, because the permission function has a second arm that happens to cover it. A bug that shows up for only one of two features reads as a feature fault, not an ordering fault. It was one cause the whole way.
In production
The intent is written before anything asks for permission. An intent left behind after a failed request is harmless for the same reason it always was. Media sits in the EU, row-level access control in Postgres, and the keys never leave the device.

What I use

Daily

TypeScript, React, React Native and Expo, Swift, Kotlin

Also

Metal and GLSL, Postgres with row-level security, Supabase, Cloudflare R2, end-to-end encryption, on-device speech recognition

Around the code

Git, EAS, Xcode, Vercel, code signing and notarisation on macOS, OTA updates, App Store and Play Store

what-i-cannot-do.txt
// Since the rest of the page is honest, this can be too.
 
I have not worked in a team with code review, sprints and someone who tells me no. That is my biggest gap, and it is the only one I cannot close on my own.
 
I have not operated anything with many thousands of users. I do not know Java, C# or Kubernetes.
 
I want to learn all of it, and that goes faster alongside people who already know it. That is the whole reason I want to join a team rather than carry on alone.

Briefly

From Vinje in Telemark, living in Oslo. Second year of frontend development.

Before that I was a sound engineer: studio, post production, and location sound for unscripted television, with mixers, booms and lavs. That trade taught me two things I use every single day. That you cannot fix in post what you did not capture right. And that ears lie, so you have to measure.

Are you hiring?

I am looking for a permanent job, in Oslo or remote. Get in touch and I will happily walk you through the code behind any of the above.