# Story by Numbers > Story by Numbers is the practice of Jason Yergeau, a developer and strategist based in Haarlem who builds websites, web applications, and editorial systems architecture for knowledge-driven teams. ## About - [About Jason Yergeau](https://storybynumbers.com/about) ## Writing ### Four Chambers URL: https://storybynumbers.com/writing/four-chambers Date: 2026-07-21 Excerpt: A song written in permanent marker on a forearm, choir boys with a synth in a bombed church, a doll's head in a heart-shaped box, and a heart in a jar of cognac inside a Warsaw pillar. > *I may learn the password but the language of the tribe will always elude me, won't it?* > – Lieutenant Yolland, *Translations* by Brian Friel ## I. Courtney Love wrote Doll Parts in a bathroom in Cambridge, Massachusetts. She emerged after twenty minutes with her arm covered in sharpie. She had run out of paper. It was a song about Cobain, who she heard was sleeping with other girls. She remembers playing it for the first time an hour later, at the Virgin Megastore in Boston, which would not open for another decade. I couldn't find a photo, but I imagine the lyrics were visible on her arm. *I want to be the girl with the most cake* ## II. I'm at my pub, the Wolfhound. A man asks me about the "bare reef otter straat", which sounds tropical. The map on his phone tells him it has a liquor store but not how to pronounce Barrevoetestraat. The bare foot street was named after a sisters' convent. If you look above the Cannabis Café, which has subtropical yuccas in the window, you'll find a barefooted man. ## III. In 1981, the oldest member of Depeche Mode was 21. They looked much younger. They looked like choir boys with a synth. The boy with the synth was Martin Gore. "Just Can't Get Enough", their first big hit, is a puppy-dog song about a crush. There's a rainbow and burning love and an angel appears. It has the emotional vocabulary of the 1950s, which requires a vow of chastity. In Virginia Turbett's archive, the 1981 photos look like a warm-up drill for a high school talent show. Anton Corbijn photographed them in the same location a couple of months later. It was a professional assignment for NME; he wasn't drawn to the music. The shoot was inside a bomb-damaged, deconsecrated church in London. Decades later, in a retrospective about his work, Corbijn talks about that early photo of Martin Gore. It's this young band, he says, and suddenly you see a cross in there. As if it were an accident. Both the Christ figure, and taking Depeche Mode seriously. ## IV. Early in their relationship, Love sent Cobain a heart-shaped box. It held small objects, among them the head of a doll. ## V. Anton Corbijn directed the video for Heart-Shaped Box. It was about kids with cancer. It was also about Courtney Love. Love later said part of it is about Kim Gordon. I don't think it matters. Corbijn shot in color, converted the footage to black and white, then sent it to subtropical Mexico to paint each frame by hand. The end result was a simulated technicolor effect. It looks like a puppet show with Jesus, crows, poppies, a hospital bed, Santa hats, and pink magenta skies. The concept notes in Cobain's notebook read: - William and I sitting across from one another at a table - (Black and white) lots of Blinding Sun from the windows behind us - holding hands staring into eachothers eyes - He gropes me from behind and falls dead on top of me - medical footage of sperm flowing through Penis - A ghost vapor comes out of his chest and groin area and enters me Body - during Solo. Violin shots. Chris as New Wave keyboardist, and very quick edits of strobe light - image of little 3 year old white, arian, blonde girl in KKK outfit being led by the hand of a KKK parent - Same violet colors as in the New Order video - Animation Doll footage - Close up of lillies lying on lighted draft Board - footage of Anatomy models from Kurts collection These notes never went to Corbijn. Cobain sent another version by fax, which would have quickly faded away. ## VI. At my pub again, the Wolfhound. A regular tells a tourist that Mozart used to play the Müller organ. (He played it once, when he was ten.) It was 9:30 in the evening and the Damiaatjes were ringing. Chopin played there too, he continued. He didn't, but now Chopin appeared like a ghost, accompanying me inside, ascending the stairs of the pub with me, the spiralling chromatic rise of pindakaas puke terracotta red, and I could even see Horowitz playing that heroic Polonaise to a militantly enthusiastic salon. --- Chopin died before he was 40. Out of fear of being buried alive, he begged for an autopsy. His heart was submerged in a jar of cognac and carried by his sister Ludwika back to Poland. It's stored inside a pillar at the Holy Cross Church in Warsaw. The rest of the body is in Paris. The transport contained: - two busts - two death masks - the mould used for the masks - several dozen engravings or prints - two small bowls or drinking vessels - three cups - one small pot or mug - one flask or decorative bottle Ludwika also had with her the letters of his lover, George Sand. They went no further than Mysłowice, the last town before the border. She left them with a friend, meaning to send for them later. And the first line of the inventory, handwritten by Ludwika: > *Pudełko z sercem* > A box containing the heart. ## VII. Three years after the death, Liszt published a *Life of Chopin*. In it he recounts someone wanting to know by what name Chopin called "the strange emotion inclosed in his compositions, like ashes of the unknown dead in superbly sculptured urns of the purest alabaster". The answer: > *He had never been free from a feeling which might almost be said to form the soil of his heart, and for which he could find no appropriate expression except in his own language, no other possessing a term equivalent to the Polish word: ZAL!* > *ZAL! Strange substantive, embracing a strange diversity, a strange philosophy! Susceptible of different regimens, it includes all the tenderness, all the humility of a regret borne with resignation and without a murmur, while bowing before the fiat of necessity, the inscrutable decrees of Providence: but, changing its character, and assuming the regimen indirect as soon as it is addressed to man, it signifies excitement, agitation, rancor, revolt full of reproach, premeditated vengeance, menace never ceasing to threaten if retaliation should ever become possible, feeding itself meanwhile with a bitter, if sterile hatred.* --- ### Le Mellotron URL: https://storybynumbers.com/writing/permanent-spring Date: 2026-07-17 Excerpt: A session man paid nine pounds to keep a Mellotron in tune, a computer programmer who painted a screaming face from a shaving mirror, the king of Babylon on all fours, and a red neon in Paris that says On air. In June 1969 David Bowie recorded *Space Oddity* at Trident in Soho. The studio owned a Mellotron the engineers had stopped using because it would not stay in tune, and the session got Rick Wakeman, twenty years old, nine pounds a session, who had made himself useful around London by learning to keep the instrument in line. He played the part in one take. The single came out five days before Apollo 11 left the ground, and the BBC played it over its coverage of the landing, nobody having listened too closely to how things end for Major Tom. A Mellotron is a cabinet of recordings. Under every key lies a strip of magnetic tape holding a real player sounding that one note; pressing the key runs the strip across a playback head, and releasing it lets a spring haul the tape back to its start. The strip is eight seconds long, so no note can outlast it. And the pitch never quite holds: the motors drift with the temperature, the speed sags when the mains sag. The unstable tuning was part of the appeal. An orchestra that wavers is an orchestra remembered. The flute line that opens *Strawberry Fields Forever* is a Mellotron, played by Paul McCartney; who played the flute inside the tape has never been established. The record is two performances in different keys and tempos, joined at the sixtieth second because Lennon liked the beginning of one and the end of the other, and the second half runs slowed, so that most of the song hangs a little below true pitch. King Crimson took the machine further out. *In the Court of the Crimson King*, made in about ten days in the summer of 1969, stacks the Mellotron's strings through generations of tape until they stand up like a wall, and on tour the wall moved: a strong downbeat on the opening chord of the title song could drag the D major strings down toward D flat. Robert Fripp settled the matter in a liner note: tuning a Mellotron doesn't. The sleeve carries no lettering, no band name, no title. A face fills it edge to edge, and the mouth is open. --- The face was painted by Barry Godber, a friend of the band's lyricist, who had left Chelsea School of Art and worked as a computer programmer. He listened to the demo tapes and brought back two faces in watercolour: outside the screaming one, painted from his own reflection in a shaving mirror, and inside the gatefold a second face, smiling, the Crimson King. He died in February 1970, four months after the album's release, aged twenty-four. His trade in those years ran on paper and tape. A programmer wrote in pencil on coding sheets, shaping each zero so it could never be read as the letter O; rooms of women punched the sheets onto cards; and around it all turned the half-inch reels, spooling forward and back, the image the cinema reached for whenever it needed to show a computer thinking. Godber spent his working hours minding one kind of magnetic tape and painted his one album cover for a band whose orchestra lived on another. The band's biographer set the screaming face beside William Blake's *Nebuchadnezzar*: the king of Babylon on all fours, naked, eyes wide, hair grown to feathers and nails to claws, grown mad, in the words of Blake's biographer, with unbelief. --- In the weeks after the eleventh of September, MTV kept returning to a Ryan Adams song called *New York, New York*, filmed four days before the attacks under the Brooklyn Bridge, the towers standing behind him across the river. The album it opened, *Gold*, was to have been released on the eleventh itself, and was pushed back. Music recorded well before the attacks was suddenly heard as being about them. *Hell, I still love you, New York*, ran the refrain, and the city took the song for its own. Adams had written it about heartbreak; the New York he still loved was a girl. --- In September 2009 Kanye West took the microphone from a nineteen-year-old singer at an awards ceremony, and for a season he was the most disliked man in American entertainment. The president of the United States called him a jackass. West removed himself to Hawaii. The single that announced his return was called *Power*, with the voice of the Schizoid Man running underneath the boasting, and its video is one slow pull backwards, marble columns, a sword hanging over the singer's head, an empire, its maker said, on the brink of collapse from its own excess. The king of Babylon had been there first. It is in the fourth chapter of Daniel: > *Is not this great Babylon, that I have built for the house of the kingdom by the might of my power, and for the honour of my majesty?* While the word was in the king's mouth a voice fell from heaven, and the same hour he was driven from men; he ate grass as oxen, his hairs grew like eagles' feathers and his nails like birds' claws. --- Le Mellotron is a bar on the rue Beaurepaire in Paris, between République and the canal, with a radio station inside it. The booth stands against the bar with a red neon that says "On air". I was there on a winter evening in 2018 with friends. I hear in the opening track the wavering sound of Bowie and King Crimson, and the Beach Boys. *I Just Wasn't Made for These Times.* --- ### Dag Anna URL: https://storybynumbers.com/writing/dag-anna Date: 2026-07-04 Excerpt: Two marble letters beside the Grote Kerk, a girl of sixteen whose death was never written out, two friends who between them made one singer-songwriter, and a white cat called Anna in a café window. On the southern flank of the Grote Kerk, facing the terrace of Café Colette, where Yvonne and I would spend her birthday every year eating oysters alongside seagulls, two black marble letters rest among the paving stones of the Oude Groenmarkt, an A and a Z, ninety thousand euros' worth, designed by Marinus Boezem. The A stands chest-high; the Z lies on its side and is often taken for a bench. The first and last letters of the alphabet are, we are reminded, the raw material of a writer, and Haarlem fancies itself a literary city in the most literal way. Cut into the monument are lyrics, among them *Dag Haarlem, slaap maar lekker, Lourens Coster houdt de wacht*. The watchman is the city's first man of letters, or the legend of one; Haarlem maintains, against most of the evidence, that movable type was invented here. As the story goes, Coster cut letters out of beech bark in the wood south of the city to amuse his grandchildren, and one fell into the sand. His statue has stood on the other side of the church since 1856, a bronze printer with a letter A in his raised hand. You need a zoom lens to make it out. For a time a small fountain rose out of the marble A; at some point it vanished, and nobody I have asked remembers it going. In the evening the church puts the square in shadow long before the light goes, and the heat stays on in the stones. At nine, two small bells high in the tower begin half an hour of ringing, the old signal to close the gates. The gates themselves are long gone, and the ringing has outlived its instruction. This, I take it, is Coster's watch. --- Lennaert Nijgh was born in Haarlem in the hunger winter and died here in November 2002. He wrote song lyrics and was a local historian. The A to Z is a monument to him, and his writing is cut into the slabs underneath them. The stone, still in excellent condition, contends with a fine yellow litter from the nearby lindens; the thinner lines are cut deeper and hold it, the bolder ones lie flat and the wind mostly clears them, so that each summer the finest writing turns yellow and the boldest stays clean. The monument was unveiled by three women on 28 April 2006, each of whom had at some time been married to him; the presentation that day was shared between the mayor of the city, with the musical name of Pop, and Boudewijn de Groot, who had been singing Nijgh's words for most of his life. The mayor was present in his official capacity. De Groot was present as a dear friend. Nijgh and Boudewijn de Groot grew up on the same street in Heemstede, and met at the Coornhert Lyceum, a school named for the humanist whose Haarlem press had set the city's printing claim in type before the legend had Coster's name. They worked together for the first time as schoolboys. Nijgh did not last there. He was thrown out, by his own telling, and finished at a lyceum in Overveen, though at least one account has him completing the Coornhert after all. In 1963 Nijgh wrote and directed a short film on 8mm in which de Groot appears as a troubadour, singing; a newsreader saw it at a private showing, thought little of the film and something of the songs, and pushed the two toward the record business. Their first singles failed. Then a producer set a record in front of de Groot, an English single with a French song folded inside it. > *Une enfant de seize ans* > *Une enfant du printemps* > *Couchée sur le chemin* It was a French chanson, a late product of an entertainment machinery past its great years. The death of Piaf in 1963, two years before de Groot and Nijgh arrived, is as good a symbolic cut-off as any. Aznavour and Piaf's *Une enfant* was a brutal story about a girl of sixteen who leaves a comfortable house for a boy and dies by the side of the road. De Groot objected to the maudlin ending, which he called *smartlapperig*, and asked Nijgh not to write it. So in the Dutch version, *Een meisje van zestien*, recorded in Hilversum in the autumn of 1965, the death is never named; the girl lies still at the side of the road, *ach wat lig je hier stil*, and the last word about her goes unwritten. It reached number 23 and made him famous. He hated it, and wrote on his own copy *Dit eens maar nooit meer*. On the back of *Een meisje van zestien* sat Nijgh's Dutch *Universal Soldier*, after Buffy Sainte-Marie. The B-side pointed toward the singer-songwriters then arriving – Dylan, Donovan, soon Cohen – men who wrote what they sang. Nijgh and de Groot divided that figure between them. The pen and the adventures were Nijgh's; de Groot embodied them, so that everyone believed the songs had happened to the man singing them. The direction held. In the spring of 1966 came *Welterusten mijnheer de president*, a lullaby for Johnson in his *mooie witte huis*, and the song is one of the lyrics cut into the pavement around the letters. The success was sudden, and it sat badly; the chanson had never fit either of them, de Groot least of all. The partnership with Nijgh went on, *Het land van Maas en Waal*, *Testament*, *Prikkebeen*, songs the country still knows by heart, but toward the end of the sixties de Groot wanted out altogether; he stopped performing, stopped working with Nijgh, tried other directions, and for a while gave up singing itself. He had a life the songs never used. De Groot was born in a Japanese camp on Java in May 1944. His mother, Fee, had been a dancer in Bandung; she is buried on the island. The boy was brought to his aunt's house in Haarlem, too young to carry any memory of it. Twenty years later he was handed a song in which a girl dies young at the side of a road, and he asked for the death to be left unnamed. Among the women who unveiled the letters was Anja Bak. Nijgh wrote a lyric for her called *Avond*, a song in which nothing happens except that it gets dark and one person asks another to stay the night, and then he married her. The marriage ended; she stayed near, became de Groot's manager and in time his wife, and Nijgh stood witness at the wedding. We have always been one big family, he is supposed to have said, and he was only describing a circle small enough that the same woman could be, at different times, the wife of both. Soon after the wedding de Groot recorded the lyric his friend had once written for the woman who was now his own wife; the record company passed over it, radio played it anyway and kept on playing it, and in the winter before the letters were unveiled the country's listeners voted it, in the poll that ranks every song ever recorded, first. ---- In 1972 a son, Jim, was born to de Groot, and on the twentieth of October 1973 came a song called *Jimmy*, a top-ten hit whose opening line named the album around it. The album was the return to collaboration. Nijgh wrote most of it, and the B-side of the single itself. *Jimmy* itself arrived by another road. Ruud Engelander, a dramaturg who was then the singer's brother-in-law, handed de Groot an untitled text that had, de Groot later said, hardly any meter or musical feel in it, a text about the kinds of men one can turn into: the lonely cyclist of the opening line, the footballer, the businessman. He set it to music quickly all the same, and only afterward did he and the boy's mother hear what the melody had made of it, a father addressing a small son, telling him to become whatever he liked, only not the businessman with the hard head. The song took the son's name. The words had not come through Nijgh. In the partnership it was Nijgh who knew what a song was about, since he had lived it first; this time that place was empty, and *Jimmy* was already in the world before anyone understood it. I notice the sequence without quite knowing what to make of it. In the bridge there is a *doo-doo, toe-toe-doe* that comes from Lou Reed's *Walk on the Wild Side*, a record Bowie had produced in London in the month Jim was born. The son grew up inside the name, became an actor, and played Jesus once on live television, a camera following him into a monastery in the days before the broadcast. His first name, typed into a search engine, completed itself with *jim shows his dick* and *jim does a line of coke*; he was better known, he said, for those than for any association with the universal saviour. ----- Far from Haarlem, on the twentieth of October 1967, a limousine was on the road from Detroit to Ann Arbor, carrying The Doors to a homecoming dance. On the way the band wanted to stop for ice cream. Ice cream is for babies, Jim Morrison said, I want whiskey; or so the keyboard player tells it. A liquor store was found; something about watching the others eat their ice cream set the singer off, and he drank sullenly in the back for the rest of the ride, arriving drunk as a skunk. The dance was in the Intramural Sports Building, a few dollars a ticket, in the years when homecoming still meant bed races and elephant races, Buffy Sainte-Marie on the same weekend's bill, the woman whose eternal soldier Nijgh had turned Dutch. The band played the opening riff of *Soul Kitchen* over and over because their singer would not come out, withdrew, and returned half an hour later with a singer who could barely stand, who swore at a hall of crew cuts and football players, threw things until someone called the police, lost his guitarist and his drummer to disgust, sat down on the riser, and left with an arm over the keyboard player's shoulder. In the audience stood James Osterberg, a dropout lately of the Ann Arbor High debate team, with a new band and no particular reason to believe in it, who watched the whole wreck, thought it was cool, cool being the word that survives, concluded there was no excuse left not to do it himself, and went home. In time he answered to a new name, Pop, hung on him after a local character named Jim Popp. After the hall emptied the Doors came back out and played once more for the stragglers, and how good the late set was depends on who is remembering. The bandleader of the opening act counts it among the best shows of his life, a Morrison suddenly sober, and the girlfriend beside him saw it too, and later married him, the evening securing its corroboration by marriage; others who stayed heard a band being merely competent, and one couple went home suspecting the Doors had been told they would not otherwise be paid. Osterberg, it seems, had already gone; everything he went on to do descends from the first half of an evening whose second half he never saw. Some years later Osterberg was in New York, staying in the loft of a publicist and watching *Mr. Smith Goes to Washington* on television, when the publicist came up to fetch him. An English singer was at Max's Kansas City, he said, a man who had been praising the Stooges in the English music press, which nobody else was doing, and who wanted to meet him. The Englishman was David Bowie. What began that night lasted the rest of Bowie's life. He mixed the last Stooges record; and when Osterberg, coming apart on the drugs of those years, committed himself to a psychiatric hospital in Los Angeles, the visits were few. Nobody else came, he said long afterwards, not even my so-called friends. But David came. The two of them got out together, to Berlin, sharing a flat on the Hauptstraße in Schöneberg, there to get off the same drugs in the same rooms, a household of convalescents. Out of that time came *The Idiot* and Bowie's own *Low*; on *The Idiot* the labor divided the old way, Bowie mostly building the music, Osterberg finding the words, and when the record went on tour, Bowie sat at the side of the stage, unannounced, at the keyboard in his friend's band. Back in Berlin they made Osterberg's second record inside a few weeks. In the evenings they had been watching the American forces' television network, which between programmes broadcast its station signal, a staccato electronic figure, and one night Bowie took up his son's ukulele and played the figure back at the set; it became the drumbeat of the record's title song, *Lust for Life*. The other song everyone knows from that record is *The Passenger*, Osterberg's words over a guitarist's riff, a man riding through the city at night and watching it through the glass. Asked where the words came from, he has pointed to the years of being driven through America and Europe beside Bowie, having no licence of his own; the photographer he lived with in Berlin remembered the S-Bahn, which he rode almost every day, out to the Wannsee above all; and Bowie's chroniclers add a poem by Jim Morrison, dead by then, in which modern life is a journey by car. However the credit divides, the song is a man in the passenger seat, and someone else is driving. ----- On a warm July evening I sat on the terrace of Café Floryn, where Marcel, the owner, had just come back from Italy, and where the neighbors arrived one after another to ask about his travels, first from Ohm, the Indian restaurant, then from Coster 52. It was too hot in Italy, said Marcel, but there was a pool. The Kleine Houtstraat was busy, and many of the people passing greeted him, on foot or leaning back on a bicycle; the names came back – hee Erik, hoi Ans, hallo Joop, dag Wim – at a speed I cannot account for. Only the house cat, a white one called Anna, took no part in the homecoming, and spent the evening inside, in the window; she had missed him, the other bartender said. At some point, I no longer remember in answer to what, Marcel mentioned that Lennaert Nijgh had been a regular at Floryn, another man at the bar with a beer; and he said it in passing, without lowering his voice, before the conversation returned to the corner home where he stayed in Piemonte. There is no plaque, no letters of any size. *Grote mensen praten niet met poezen*, Nijgh wrote in 1966. When I left, the white cat was still in the window, ready for a chat. --- ### The house is not for sale URL: https://storybynumbers.com/writing/house-not-for-sale Date: 2026-05-02 Excerpt: A childhood home back on the market, a message after twenty-five years, and the friends you only see at weddings. Of the two signs, the one I remembered was the one I had ordered. I sat in the living room of my aunt's house in Haarlem, where she had lived since 1969. I was waiting for the estate agent. He'd finally make visible, from the street, to the neighbors, to the relatives who expect some movement in long running, long distance stories, the thing which for me had clearly already happened, namely the atrophy of a home into an address, a floor plan, a count of square meters, reports on the foundation, asbestos (removed), all packaged in a series of photographs by a woman with a tripod who stood in corners I generally forget to dust. In the same week, my cousin sent a link to my childhood home. For sale. I haven't seen it since the day I left, aged eleven, although I still go back to Massachusetts for weddings and funerals, both of which seem to be on the uptick. I dream in that house. It's absent of all architectural details, colors, sound, and light, but that's the case with all of my memory. What I can tell you is the whitewashed ad looks like a discount sale at Target, and that's not how I remember things. The question is asked every day, multiple times per day, if I'll be moving back. They see the sign, and ask the question. I've been in the Netherlands for 14 years. Back where? Do you realize what happens to someone in 14 years? To me, to them, to a house, to a country? Of course I ask myself the same question. I also ask the bald man in the mirror about Turkey. Also in the same week, my childhood best friend also wrote me. *Buddy.* That's exactly how he opened the message. He also said his sister's name, not "my sister" – even though I haven't seen her in 33 years, and she surely wouldn't remember me – then straight to the side hustle: landscape stone, from the North Carolina coast to Western Mass, half the price of his competitors, just needs a website. Am I game? Sure, of course I'm game. *Buddy.* He jumped out of a window the last time I saw him. New Year's Eve going into 2001 in Montreal. My memory, normally devoid of architectural detail, provides a fire escape next to the club on Guy Street. Whether that's recollection or logic, I couldn't say, but he's alive. Alive, stones intact. And in the same year I met Graham, who for twenty-five years was the one who remembered details. He traveled more, came to me, made the effort. The thumbnail auto-selected by my photo app is him on his twenty-fifth birthday, when we had rented a house in Napa, near French Laundry. The others went there with notebooks and good clothes, like well dressed kids at a California Bible camp. I stayed behind. In the picture he's wearing a single-breasted blazer with gold lurex pinstripes, a garment so entirely *him* that it seems unlikely he ever took it off. Behind him, back to the camera, is Kim; and somewhere outside the frame is her husband, Peter, who broke the news to me the morning it happened. He was there for my 40th birthday in Italy. I called it Marty's Party, after a collage I had made from concert tickets while we were roommates in 2007, after a Greek word for witness, a reference he caught at once, as I knew he would. His son and I have the same birthday. Each year now arrives with two names attached to it. One's a Pirate. Graham was married in 2017 at the Great American Music Hall in San Francisco. It had opened in 1907, the same year the house in Haarlem was built, and because dates seem to echo – there's never too much reverb – I thought, these two structures have been waiting a century to meet; the gilded balcony, the frescoed ceiling, the cigarette smell and old turpentine paint; it's where we stood in 2006, in my first week in SF, watching a band from Brighton while the city was still a magic of hills, and panic about apartments and future. On the night of the wedding, the billboard read Till Death Do Us Part. That was a detail of his wedding I had forgotten, but his wife reminded me in an email after he died. It fits his humor, and it fits hers. At any rate, the whole thing ended too soon. I've been rewatching *Almost Famous*, about a fifteen-year-old boy sent out to follow a fictional band called Stillwater. There's a fantastic scene with Frances McDormand lecturing on intuition and the collective unconscious, when she loses her concentration and announces her son, the teenage journalist William Miller, has been kidnapped by rockstars. A great scene, but one you tend to forget. It's the scene before the memorable one, when the tour bus sings Tiny Dancer. And I do love that scene. I love Penny Lane. I love that magic wand gesture she makes with her hand. Like *poof*, it's gone. Or *poof*, you're home. *Pretty-eyed, pirate smile* *You'll marry a music man* --- ### An Alfred workflow that translates with an LLM URL: https://storybynumbers.com/writing/alfred-translate Date: 2026-04-24 Excerpt: Type tt and a phrase, and four translations come back in about a second. Default provider is OpenRouter; the provider layer is a swappable shell script. [`alfred-translate`](https://github.com/storybynumbers/alfred-translate) is a small Alfred 5 workflow I built for myself. Type `tt`, then whatever you want translated. Four translations come back, ranked in the order you configured. `⏎` to copy the highlighted one, `⌘1`–`⌘4` to grab any of the others. ![Alfred showing the query "tt Hello there, butterfly." with translations to Dutch, French, Spanish and English, each selectable with a Cmd-number shortcut.](/images/blog/alfred-translate/alfred-translate.png) I live in the Netherlands and ping between English, Dutch and French in a single afternoon. The browser-based tools all want a tab, a paste, a click. This wants a keystroke. ## What's under the hood The workflow defaults to **OpenRouter** with **Mistral Small 3.2** (24B). It's roughly 1.5 seconds end-to-end, costs pennies per thousand translations, and stays inside the EU. The model holds idiom and tone well enough that I rarely have to second-guess the result. The full prompt is "translate this into the following languages, return JSON". Mistral Small honors structured output reliably, so the workflow gets back something like `{"Dutch":"Hallo daar, vlinder.","French":"Bonjour, papillon.", ...}` and Alfred renders one row per key. ## Provider as a shell script The interesting design choice is the provider layer. The Alfred workflow shells out to `providers/$PROVIDER.sh` with two arguments, `text` and a comma-separated language list, and expects JSON back on stdout. Two providers ship in the repo: - `openrouter.sh` posts to OpenRouter's chat completions endpoint. Fast. - `claude.sh` shells out to the [Claude Code CLI](https://claude.com/claude-code) with `--model haiku`. Useful if you already pay for Claude Code via subscription, but the CLI cold-start adds about five seconds, which is rough on a keystroke-driven workflow. A `codex.sh` skeleton is also there if you want to wire up the [Codex CLI](https://github.com/openai/codex). Adding your own provider is genuinely about ten lines, because the contract is "read $1 and $2, write JSON to stdout". This abstraction is the reason the workflow exists at all. Claude Code is excellent for everything else, but five seconds of CLI init for a translation makes Alfred feel sluggish. OpenRouter brings the same Anthropic, Google, and OpenAI models down to one HTTP call, and the provider abstraction lets me drop back to the CLIs only when I actually need them. ## Configuration Everything is set in Alfred's **Configure Workflow** dialog, no file editing: | Variable | Default | Purpose | | --- | --- | --- | | `OPENROUTER_API_KEY` | *(empty)* | Required. Get one at [openrouter.ai/keys](https://openrouter.ai/keys). | | `LANGS` | `Dutch,French,Spanish,English` | Order matters. The first entry is the top result. | | `OPENROUTER_MODEL` | `mistralai/mistral-small-3.2-24b-instruct` | Any [OpenRouter model](https://openrouter.ai/models). Try `google/gemini-2.5-flash` for the fastest path. | The API key is marked `variablesdontexport`, so if you share the workflow it strips itself out automatically. ## Install Grab the latest `translate.alfredworkflow` from the [Releases](https://github.com/storybynumbers/alfred-translate/releases) page, double-click to import, paste your OpenRouter key, done. Or clone the repo and `./build.sh` to build it locally. The whole thing is open source on [GitHub](https://github.com/storybynumbers/alfred-translate). Issues and pull requests welcome, especially for new providers. --- ### Voor de kerk URL: https://storybynumbers.com/writing/voor-de-kerk Date: 2026-02-18 Excerpt: Bakfiesten, patron saints, Nina Simone, the Actus Tragicus, a day at the former Mariastichting. After a short exchange with my family, unusual this early in the morning, I deflect my cat and try to snooze the schooltime noise from the street below. It's nearly 8:30 and I can't fob it off any longer. My bedroom looks out to the school, and the school looks back at me with a statue of the Virgin. Bakfiesten surround the *stoep* like an army belgrade. They go inside, and I head to work. Another message from my aunt. *We think it'll be today or tomorrow.* It's been a month at the agency. It's in the former chapel of the former Mariastichting, a Catholic hospital run by Franciscan sisters. Familiar objects, familiar images. I sit near Saint Barbara, the architect. She sits next to Saint Helena, the designer. A patron saint of iconography if there ever was one. *Are we rich or poor? Does it matter anymore. Heatwave....* We have lunch on the ground floor. Flowers floating in a font of no longer holy water. I ask my colleagues about the building; the conversation detours to the ruins of a Friesian church, where you can spend the night under stars. Over my dead body would I sleep in a church. Lunch ends, and I start on a new project; a bit of bug fixing for a search function. Satisfying work. I go home to eat. Put on Nina Simone. One of my aunt's old records. Why this one? I'm not sure. *To Love Somebody*, released the year she moved here, in 1969. It's a series of covers: Bob Dylan, Leonard Cohen (a Montrealer, like my aunt), the Bee Gees. I start with the Byrds. Turn, Turn, Turn. Pete Seeger really wrote that one. Actually, he stole it from King Solomon. To everything turn, turn, turn. The album art has arches like portals, or an apse, or the agency's stained glass windows. I put on the Actus Tragicus, wondering what they'll play at the services. "Er is geen thema, we horen slechts zich herhalende motieven." --- ### A bursty RGB glitch effect for Remotion URL: https://storybynumbers.com/writing/remotion-digital-glitch-rgb Date: 2025-12-26 Excerpt: Remotion, RGB channel splitting, randomized glitch bursts, and how the effect is built. `@storybynumbers_/remotion-glitch-effect` adds short glitch bursts with RGB channel splitting. It's designed to be sparse, repeatable, and easy to drop on top of existing compositions. **Install** ```bash npm install @storybynumbers_/remotion-glitch-effect ``` Usage is a wrapper component exported by the package: wrap the subtree you want to affect. ```tsx ``` ## How it's made ### Burst schedule + determinism A **burst** is a short window of frames where the effect is active. Each burst has a start frame, a duration, and a peak intensity. Outside bursts, frames are stable. The **seed** keeps everything deterministic. All randomness comes from Remotion's `random()` using string keys that incorporate the seed, so the same seed produces the same burst schedule and the same per-frame variation on every render. The core loop is: ```ts const bursts = useMemo( () => generateBursts(durationInFrames, burstSpacing, burstDuration, seed), [durationInFrames, burstSpacing, burstDuration, seed] ); const { intensity, burst } = getGlitchIntensity(frame, bursts); ``` Inside a burst, per-frame values derive from a frame seed (based on the burst seed + frame), so offsets and jitter change across the burst while staying reproducible. ### RGB split via SVG filters This is deliberately low-tech: SVG filters and a few layers. When `intensity > 0`, the component renders the same children three times: - **Red**: isolate red with `feColorMatrix`, then `feOffset` it. - **Green**: isolate green and keep it centered as a stable reference. - **Blue**: isolate blue and `feOffset` it in the opposite direction. On top of that: - A small `feGaussianBlur` applies only during bursts to soften edges. - The three layers are composited with `mixBlendMode: "screen"` so the split stays bright. ## Links - GitHub: https://github.com/storybynumbers/remotion-glitch-effect --- ### Deforestation in Rondônia, Brazil: mapping burn scars URL: https://storybynumbers.com/writing/deforestation-rondonia-burns Date: 2025-11-15 Excerpt: Sentinel-2 imagery, dNBR burn severity, pasture expansion, and dry-season fire scars across Rondônia. Day 15 of #30DayMapChallenge focused on fire. I pulled a stretch of Rondônia, Brazil where pasture expansion and dry-season burns repeat every year, then mapped how much vegetation the latest burn actually removed. **Workflow** - Grabbed two Sentinel-2 scenes: pre-fire (Aug 18, 2023) and post-fire (Sep 22, 2023). - Converted the raw bands, aligned NIR (B08) and SWIR (B12), and computed NBR for both dates. - Calculated dNBR to isolate burn severity; masked smoke/cloud where the index collapses. - Built a quick pre/post swipe plus a severity layer so you can see the scar rather than just the RGB farmland. What looks like clean, organized blocks from above fractures under the index: old clearings, new clearings, regrowth, and fresh scars from dry-season fires. The bright dNBR zones are the hardest-hit areas; the dark speckled zones are either minimal loss or places where the data was unusable. **Why it matters** Pasture expansion here is not a single event. It is a pattern of clearing, burning, and re-burning that erodes the surrounding forest edge. Pairing a visible RGB swipe with the severity layer makes it harder to mistake order for stability. --- ### How old is Haarlem? Mapping buildings by age URL: https://storybynumbers.com/writing/haarlem-buildings-age Date: 2025-11-13 Excerpt: BAG building footprints, Haarlem by construction year, medieval cores, 19th-century belts, postwar infill. Day 13 of #30DayMapChallenge looked at building age. Using the Basisregistratie Adressen en Gebouwen (BAG), I painted Haarlem by build year to show how the city grew outward. **Data and styling** - Dataset: BAG building footprints with construction year. - Binned years into rough eras: pre-1850 cores, 1850–1918 expansion, interwar fill, postwar growth, and contemporary infill. - Styled as a simple categorical map so the center pops dark and the ring roads glow newer. **Street name themes** Alongside the building ages, I also mapped the dominant street name themes in small grid cells across the city. Each square shows which naming theme is strongest in that area. The first image highlights areas where street names cluster around churches and religious references. These tiles tend to sit close to older neighborhoods and historic centers where parish life shaped the local grid. ![Haarlem street names themed around churches](/images/haarlem-by-age/churches.png) The second image surfaces water themed streets. Here the dominant names refer to canals, rivers, harbors, or water related work, and you can see them hugging the Spaarne and the old waterfront corridors. ![Haarlem street names themed around water](/images/haarlem-by-age/water.png) The third image shows tiles where military, overseas, or colonial references dominate the street names. These clusters often sit in later expansions where planners borrowed names from regiments, battles, or far away places instead of local landmarks. ![Haarlem street names themed around military](/images/haarlem-by-age/military-overseas.png) The classification is quick rather than archival. I had one day for the entire process, from data extraction to visualization, so it is not historically precise enough to use as a source. Even so, the three maps already reveal patterns and clusters that might be worth a closer, slower pass later. --- ### Generating walking tour videos for YouTube URL: https://storybynumbers.com/writing/kunstlijn-haarlem-walk Date: 2025-11-09 Excerpt: Kunstlijn artist data, 3D map flyovers, yellow title cards, and walking routes from Haarlem Station. ## Project For Kunstlijn Haarlem I built a video system that turns the annual artist listing into short, cinematic walking route videos. Each piece combines a 3D map flyover of Haarlem, yellow title cards that introduce the artists, and a guided route that moves from the station into the city. The video above is one of the station starting routes. It gives a visitor who just arrived in Haarlem a clear first path into the festival instead of a dense map full of icons. ## How it works at a high level Behind the scenes, I connect Kunstlijn's structured data about artists, locations, and images to a small set of video templates. A browser based route planner lets us pick a handful of stops on the map, check that the walk feels realistic, and then hand the selection off to the rendering pipeline. From there the system: - Builds a walking line on top of a Mapbox scene with terrain and 3D buildings. - Times camera moves so the viewer always understands where they are in the city. - Drops in artist cards and photo galleries between segments so the route feels like a curated sequence, not just a line on a map. The goal is not to showcase the tooling. It is to make it fast for curators and producers to spin up new route videos without storyboarding every frame. ## Route variants Once the system was stable, I used it to build several different walks, each aimed at a different visitor. One route starts at Haarlem Station and threads through the Museum Quarter, slowing down where galleries cluster and letting the camera linger over the rooftops around the river. Another focuses on the government area near the provinciehuis, where the contrast between public buildings and small exhibition spaces is sharp. A photography heavy trail pulls together studios and venues that show lens based work, so a visitor who cares about that medium can follow a single narrative through the city. A final loop in the Rozenpriel neighborhood stays close to home, linking nine artists in a tight circuit that could be walked in an afternoon. Each route uses the same visual language, but the mood shifts with the neighborhoods and the pacing. That is the value of a programmatic approach. Once the data and templates are in place, you can spin up new stories for different audiences without rebuilding the whole artifact every time. --- ### The Wrong Way Bridge (Vermont) URL: https://storybynumbers.com/writing/wrong-way-bridge Date: 2025-11-09 Excerpt: A 1950 bridge bends the road away from the river before crossing it, a relic of an abandoned Route 15 extension and a valley reshaped by floods. Day 7 of #30DayMapChallenge focused on accessibility. I mapped the "Wrong Way Bridge" near where I grew up in Vermont, a crossing that always felt off because the road bends away from the river before it meets the span. Locals had theories: bad surveying, a shortcut to St. Albans, or just bad design. The real story is stranger: the bridge was built in 1950 to start a Route 15 extension that would have followed a railway line along the south bank of the Lamoille River. The valley kept flooding and the plan died, leaving a bridge pointed at a road that never came. **What the LiDAR shows** - The bend is not arbitrary. The embankment tracks the planned alignment toward the rail corridor. - Old flood paths carve into the valley floor; you can see abandoned traces that would have been underwater in high water. - The current approach road swings awkwardly to meet the orphaned span, a quiet accessibility failure every winter when drivers skid off course. It's a small piece of infrastructure that tells the story of a project halted by the landscape itself, leaving geometry that confuses drivers decades later. --- ### What's the Best Readwise Workflow? URL: https://storybynumbers.com/writing/readwise-workflow Date: 2025-06-25 Excerpt: A calm Readwise-to-Obsidian flow: read without interruption, capture clean text, let notes stay messy, and use LLMs to cluster highlights into future context windows. A good workflow starts with reading well. Tools help, but the real gain comes from how you move ideas from the page into a system you can return to. **1. Read first, note later** Margin notes while reading; real notes after the session. The pause forces recall and keeps the reading experience intact. **2. Use Readwise as the capture layer** It gives you clean article text, handles PDFs properly, and syncs with Obsidian without ceremony. **3. Let Obsidian be chaotic** Daily notes are the anchor. No pruning, no "knowledge garden." Just tags like `#inline/inspiration` or `#inline/topic` to make future retrieval possible. **4. Let the LLM do the light shaping** Claude can cluster fragments, clean up rough notes, and surface threads worth developing. It adds structure only when you ask for it. **5. Treat notes as future context windows** Your highlights and fragments become raw material. You can load them into a vector database or use an LLM to assemble idea boards when you need them. --- ### Don't dream it's over URL: https://storybynumbers.com/writing/monsters-dont-dream-its-over Date: 2024-12-24 Excerpt: Milli Vanilli, Crowded House, car radios, pastels, and the Menendez brothers in Ryan Murphy's Monsters. *Monsters *is filled with music references. The title of episode one is "Blame it On The Rain," Milli Vanilli's 1989 hit, which is the year they were exposed for lip-syncing. Episode three is "Brother, Can You Spare a Dime?, when the brothers land in jail and can't use the payphone because they don't have coins. Though this Great Depression classic is never played, its lyrics resonate with the show's central themes: > They used to tell me I was building a dream, And so I followed the mob, When there was earth to plow, Or guns to bear, I was always there, Right on the job. "Don't Dream It's Over" (episode 6) begins with a flashback to 1962, tracing the star-crossed origins of José and Kitty Menendez. We see them run away together, build the American dream together, and eventually, come to hate their kids together. In a pivotal and equally unproductive therapy session, just before the iconic family photo at Sears, Kitty says: > "Your father crossed an ocean, and I left behind the life of a beauty queen or I could have been a movie star like Kim Novak. And you're what I got?" This is not the life that mommy and daddy dreamed of. How will the entrepreneurial couple fix this? Ryan Murphy, the creator of this serious, was also behind *Nip/Tuck*. A reference to Kim Novak is a Hollywood in-joke: she was a cautionary tale after that [2014 Academy Awards appearance](https://youtu.be/uEkH24x-bAE), which had everyone wondering where cosmetic surgery ends and taxonomy begins. In L.A., self-determination comes at a price, and it seems Kitty's fate had always been sealed. If her children didn't kill her, the drugs, alcohol, or depression would; in the meantime, she subsisted on facelifts, house renovations, Christmas trees. José asks her to lose nine pounds. Later, José later gifts her a Mercedes-Benz. This is the only time we see her happy in entire series. ## A violent man wearing a yellow sweater The demo for Crowded House's massive hit was recorded on a humble cassette four track. The snare drum was Neill Finn flicking a matchbox. If it sounds complex, that's the Space Echo. The final version came with a Hammond organ solo and a much more refined sound, but it's not a major departure from the original, with its signature falsetto. The nostalgic register and boyishly exuberant lyrics (There is freedom within / There is freedom without / Try to catch the deluge in a paper cup) make this both a car ride tear-jerker and a karaoke classic. Miley Cyrus and Ariana Grande [sang it wearing animal packs](https://www.youtube.com/watch?v=m2ua3O_fdCY&ab_channel=MileyCyrusVEVO), then performed [the same one in the same style](https://www.youtube.com/watch?v=9LiI6poe3QE&ab_channel=BBCMusic) for the One Love Manchester. That was a benefit concert in response to a terrorist bombing, so not the most obvious choice, but this track seems to work in all kinds of kumbaya settings. For those who remember living through the Menendez case --- before Miley's time, that is --- Crowded House will likely recall another memory. And if you're American, there's a good chance that memory took place in a car. It's hard for people outside of America to grasp just how much time Americans spend in cars, and how crucial it is for the listening experience. As the creator of *This American Life* says, radio is for driving. So I found it particularly brilliant to make the hereditary violence link in such a nonchalant way, by showing men leaving their vehicles to the tune of "Don't Dream It's Over". The first car exit is José Menendez, who cannot contain his disappointment after they're arrested for robbery. The typical fatherly response in such a situation would to direct his disappointment at himself. But there are hints through the series that this sado-masochist blames himself. Recall the passage he had just recited to the boys from his (redacted for bullshit) bible from Og Mandino: > "Today I'll be master of my emotions. From this moment, I'm prepared to control whatever personality awakes in me. I will control my moods through positive action. And when I control my moods, I control my destiny." José failed to be the master of his emotions, and so he was a failure to his sons. But the sons, exiting the car to Crowded Room as the high pass filter is closed, shows Lyle and Erik in total (sociopathic) control of their emotions, wearing pastels, about to kill their parents. "It's up to us now, right? And they would be proud of us." --- ### WooCommerce hammered by fake orders URL: https://storybynumbers.com/writing/failed-orders-woocommerce Date: 2024-12-20 Excerpt: WooCommerce, stolen credit cards, the Store API side door, and a brute-force fix before migration. ### A bot testing credit cards I've got a client with a small, niche e-commerce store running on WooCommerce. It's a self-hosted WordPress setup with just enough customizations to meet some very specific needs. Recently, we've been seeing a constant trickle of failed orders, about one every 10 minutes, all with the same pattern. It doesn't take a genius to suspect bot-driven credit card testing. We tried reCaptcha v3. It was clunky, but it worked for a while. Then the attackers changed tactics, slipping right past it. Apparently, we'd been ignoring a major side door. ### Multiple APIs, who knew? I'm used to the junk that floats around the WordPress ecosystem, but here's a twist: WooCommerce introduced another API - the Store API - mainly to support their block-based cart and checkout features. It's documented on their developer resources, but there's no high-profile "acknowledgment" on their main blog, and quite frankly I'm not following these developments closely because WordPress is definitely not my thing. Anyway, the Store API is designed for a headless experience and modern front-ends. It allows guest-level interactions. This isn't necessarily a "vulnerability" in the classic sense, but it's a design choice that's ripe for abuse by bots, and some of the obvious safeguards (eg: the ability to disable the API or parts of the API if you're not using the block system) have not been introduced. So I find it quite problematic. ### Shutting out the bot My first attempt was a quick fix: using `woocommerce_checkout_process` to filter out suspicious emails. But guess what? The Store API doesn't play by the same rules as the traditional checkout flow. We weren't even using this new API, but it existed, ready for exploitation. So I went scorched earth: ```php add_action( 'rest_api_init', function () { if ( strpos( $_SERVER['REQUEST_URI'], '/wc/store' ) !== false ) { wp_die( json_encode( [ 'error' => 'Store API is disabled on this site.' ] ), 'Store API Disabled', [ 'response' => 403, 'content-type' => 'application/json' ] ); } }); ``` Bye-bye, Store API. Not a graceful solution, but we're going to migrate anyway. ### Root causes This project has almost no maintenance budget. Keeping WooCommerce, the theme, and plugins up-to-date was already a stretch. We once considered Shopify, but it needed custom features that just weren't doable at the time without spending more than we had. Now the situation is different. We're looking at moving to a hosted platform that limits our flexibility but offers better security out of the box. Ironically, the Store API probably came about to make life easier for complex headless setups, the kind of big-budget builds that can afford to harden their pipelines. For a tiny store on a shoestring budget, this kind of "progress" isn't helpful. --- ### 004 - London Plane URL: https://storybynumbers.com/writing/london-plane Date: 2023-08-16 Excerpt: A poem about a letter, a locked bike, and the camouflaged trees along Spuistraat. that morning you left me a letter "See you at 6" in your unmistakeable handwriting that morning my lock wouldn't open i gave it some grease and cleaned my hands with a teeshirt found in the rut of my backpack eighteen minutes to work with time to lock my bike i chained it to a London plane camouflaged in olive, grey and green inside, practicing my words forgetting the time i wrote *boom patroon verdwijnen* you wrote again a note, that afternoon he passed, you said no surprise, i thought the way things were going. two pm, work closes at five. outside my bike is stuck to a London plane with colors that make you invisible. a gift shop at the museum i could buy you a card? six pm and I walk down Spuistraat where London planes line a street so rare in the center a tourist asks me for directions pronouncing "Spui" like Louis in french, like your father i thought of you but i did not write you back looking instead for an alphabet of my own to draw up the words i owe you so generic so fixed such as I am sorry for your loss --- ### Product Owners facilitate the client/agency relationship URL: https://storybynumbers.com/writing/technical-product-owner Date: 2023-08-16 Excerpt: The client-agency handoff, design acumen over scrum jargon, and the PO who actually knows how websites are made. Amsterdam has a broad range of creative agencies and freelancers, and a high standard for professionalism. But no matter how skilled the agency or freelancer, building an app or a website is always a collaboration between the client and the builders. That's why it's essential your organization invests in a highly experienced Product Owner. This person does more than prioritize features and ensure good process. They facilitate efficient collaboration across all stages: inventorization, design, realization, marketing, and after-care. ### A product owner shares an agency's vision and carries it forward. So you've decided you want a new website or digital product, and you've reached out to a few agencies. The client managers listen to your wishlist and present their pitch. This is an exciting phase of any project and an incredible opportunity to mobilize your organization down a new path. It's dreamy, inspiring, the horizon starts to come into focus... and then it's time for you to step up to the plate. An agency can design and develop your product, but the heart of the product comes from your organization. You need to know what you want, what's realistic, what's risky, when to push, and when to concede. Creation is a collaboration. Do not hire a Product Owner that can only talk about scrum and agile. Technical knowledge and design acumen are just as important as process. Make sure your Product Owner actually knows how websites are made and why you are producing content. Once a budget is agreed upon and the project structure is determined, what happens next is what I call the "sales to PM dump". The client manager begins to fade out and functions more as a strategic advisor or creative director. That isn't per se a bad thing, but it's tricky to navigate because the relationship built with one person needs to start anew with a PM. If you have someone within your own team who is already familiar with the agency process, it can make this transition a lot smoother, especially if they already have a prior relationship with the agency you've selected. The PO should own the creative director's vision, be fully onboard, and know what needs to happen at every stage to fully realize the project to completion. If the agency has a hiccup, the PO can help compensate. The PO is also the person who keeps your team aligned around the pitch, and adjusts it along the way to your organization's operational and budgetary constraints. ### A Product Owner can help avoid common pitfalls I've worked for agencies for ten years. The best ones function as a factory. From sales to design to development to support, if you work with a well-integrated team, things can move quickly from one discipline to the next. But this chain approach requires consistent oversight. If not, a lot can go wrong. --- ### 003 - Middling men URL: https://storybynumbers.com/writing/work-work-work Date: 2023-04-18 Excerpt: John Banville on the middling men — frenetically energetic, fatally free of the curse of perpetuance. ## 1. > Anyway, work is not the word I would apply to what I do. Work is too large a term, too serious. Workers work. The great ones work. As for us middling men, there is no word sufficiently modest that yet will be adequate to describe what we do and how we do it. Dabble I do not accept. It is amateurs who dabble, while we, the class or genus of which I speak, are nothing if not professional ... We are not skivers, we are not lazy. In fact, we are frenetically energetic, in spasms, but we are free, fatally free, of what might be called the curse of perpetuance. We finish things, while for the real worker, as the poet Valéry, I believe it was, pronounced, there is no finishing a work, only the abandoning of it. *The Sea*, John Banville --- ### JavaScript was created in ten days URL: https://storybynumbers.com/writing/javascript-in-ten-days Date: 2023-04-10 Excerpt: A meditation on this, and "this" [Brendan Eich](https://www.youtube.com/watch?v=krB0enBeSiE&ab_channel=LexFridman) created JavaScript in ten days. It started as a way to add interactivity to the browser, effectively a hacker's tool, and now it's the world's most popular programming language. And just like English, its usage is diverse and constantly adapting to new situations. I'd like to trace that versatility in a single world: `this`. If you're coming from another object oriented language and start using JavaScript more seriously, at some point you come across the weirdness of `this`. It changes context. It's determined during runtime, which can be implicitly or explictly determined, depend on the style of writiing a function, and whether or not you're in `strict` mode. It doesn't just refer back to the object instance. This behavior made DOM manipulation easier in the 90s, and jQuery relies on it heavily. However, during the early days of React, this behavior was really throwing me off. Consider this example: ```jsx class MyComponent extends React.Component { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); } handleClick() { console.log(this); // will log the component instance } render() { return ; } } ``` Before React introduced functional components and hooks, a component had to extend the `React.Component` class in order to use lifecycle methods. A common use case would be to add an event listener after the DOM element is rendered, or remove it after it's unmounted. Rather than dump everything into a render method, which should be responsible for rendering, it made sense to place the event handler into its own method. But here's the rub: the render component creates a DOM element, which through user interaction adds an event to the event queue. The context of `this` at the moment is not the React component that rendered the DOM element, but the DOM element itself. That is why an explicit binding is required to the component: ```js this.handleClick = this.handleClick.bind(this); ``` This is so counter intuitive, it's led to long and heated debates as to whether JavaScript can even be considered an object-oriented language at all. I believe the general verdict is "yes", but I'm no authority. JS supports objects, classes, inheritance, encapsulation, and polymorphism. Mozilla goes so far as to call JavaScript ["heavily object oriented"](https://developer.mozilla.org/en-US/docs/Glossary/OOP). Even functions are a type of object in JavaScript. But `this` was just trying to be helpful. ## ES6 and hooks Language moves much faster than modeling, both in spoken word and in software. Since hooks were introduced in React 16.8, the industry standard is to write functional components: ```jsx function MyComponent() { return ( ); } ``` In this new example, `this` will log as `undefined`, not the DOM element. That has nothing to do with React's new functionality, but with a feature in ES6. The `onClick` is passed an [arrow function expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions), which does not have its own `this` context. For this use case, it makes things much easier to read. So that's an example of the language specification evolving. But the evolution of its usage, in this case during the introduction of hooks, I find just as interesting. Blog posts on hooks tend to focus on reusability or compactness as the reason why hooks are "awesome". But sticking to functions reduces what a developer needs to know so they can focus on rendering interface components. We don't need a world filled with working ontologists. ## Respect the "dumb" Easy-going conversation in every-day life is filled with presumption. If I write a script to find a button element, and I want "this" to become disabled after a click, I expect the interpreter to understand what I mean. They say assumptions make an ass out of you and me, but those people have rich daddies and no deadlines. React owes its popularity in large part to a certain graduation (rather than separation) of concerns, from the "smarter" data components responsible for fetching, routing and state management, which are mostly unique per application, to the "dumb" components that render the user interface. That spectrum of smart to dumb is not about the intelligence or skill of the developer, but about the level of dynamic context in a component. The scalability and popularity of React lies in these dumb components. Context is explicit in the form of `props` --- until it isn't. And then I get critical. ### Further reading - https://enlear.academy/prototype-vs-class-the-javascript-split-personality-20d984d2fe2 - https://youtu.be/krB0enBeSiE?t=422 --- ### Only women appear in this movie about Sean Connery URL: https://storybynumbers.com/writing/jan-bot Date: 2023-04-07 Excerpt: Eye Filmmuseum, archival footage, trending topics, and an AI filmmaker that made a Sean Connery film without Sean Connery. Yesterday, the Eye Filmmuseum created [a short film about Sean Connery](https://www.jan.bot/catalog/view/ByGEq9J5lm). It was published around 1:00 in the morning, just twelve hours after the announcement was made on Twitter that Eunice Gayson had passed away at the age of 90. She was the first ever Bond girl, playing opposite Sean Connery. That's the connection. Notably missing from the film about Sean Connery was, well, Sean Connery himself. He never makes an appearance. Neither does James Bond or any Bond girls, although Eunice Gayson is mentioned once. And any wider associations you might make with Sean Connery — gray beards, celebrity jeopardy, Her Majeshty's Shecret Shervice — are also absent. Is this really a movie about Sean Connery? The description couldn't be more explicit: > This video is about Sean Connery. ![Jan Bot image 1](/images/blog/jan-bot/Jan-Bot-image-1.png) ![Jan Bot image 2](/images/blog/jan-bot/Jan-Bot-image-2.png) *Stills from "2018–06–10.004-sean_connery.mp4"* How could this be? We're shown a woman in a fur coat, then an unnerving lady who is laughing and brandishing her teeth. I'd say one looks like a movie star, which might put her vaguely in the realm of Sean Connery. Am I going in the right direction with this? Or maybe it's a commentary on aging? Or the objectified role of women in film? A tragic tale about U.K. dentistry, perhaps? Hard to say, but this is worth mentioning: this short film is also missing a director. It was created by a robot, and he's producing several films every day. Meet [Jan Bot](https://www.jan.bot/catalog/view/ByGEq9J5lm). Despite being powered by the same deep learning algorithms that we're told will cause the singularity apocalypse and perhaps cure cancer, this is not the kind of artificial intelligence application that you want driving your car, offering investment advice, or translating sloppy phone taps into relatively decent English. Nor is Jan Bot a good source for Sunday night movie recommendations, despite its association with [Amsterdam's respected film institution](https://eyefilm.nl/en). Jan Bot is a different kind of experiment. The software generates short movies based on fragments of found film, following the trending social media topics of any given day. The co-father of Jan Bot, [Pablo Núñez Palma](https://medium.com/@pablopalma), puts it like this: > Using some of the trendiest AI tools available for the translation of images into words and words into semantic nodes, we have programmed Jan Bot to create meaningful connections between two completely unrelated items: a vast collection of old and unidentified film fragments, and trending topics from today. It's like a game of Taboo. You have to talk about a topic (the word on your game card), but that word and any obviously related words are forbidden. As explicitly as the film is "about Sean Connery", the source fragments for these films are explicitly disconnected from the subject in ways we would traditionally expect (for example, that Sean Connery would appear in a film about Sean Connery). In Taboo, the workarounds are what make it fun. What's the effect for Jan Bot? Since I know the film doesn't appear out of nowhere, I find myself tracing back connections using an interpretive excise that feels a bit like reverse engineering. I'm given a number of tags — girl, boy, horror, face, disguise, actress, actor — but not the reason why they were selected. I assume they are pulled from associated articles on the trending topic, which are also listed. I know that Jan Bot is working with a limited pool of fragments to build the film, so he doesn't have the luxury to be a symbolic perfectionist. I'm not expecting the fragments to match the tags exactly, which leaves things up to the imagination. But maybe it's a personal thing: for a film to be interesting, there needs to be some kind to be character development. In this case, that would have to be Jan Bot himself. As a viewer, I find myself trying to understand its algorithmic thinking, not its plot. The subject material is not "Sean Connery" as I commonly know and recognize him, but "Sean Connery" as a node within networks: social networks (subject material), language networks (to expand the subject outside of its time period), and image recognition networks (to select the fragments of the film). These networks look like something, and these films are generated every day for us to watch. It's quite a nice exploration into computer vision by Bram Loogman and Pablo Núñez Palma. Kudos, guys. --- ### 002 - Martys Party URL: https://storybynumbers.com/writing/martys-party Date: 2023-04-07 Excerpt: A little horse keeps watch over the party near Venice ## 1. ![Maria](/images/blog/martys-party/Maria.jpg) > But no matter the medicinal virtues of being a true friend or sustaining a long, close relationship with another, the ultimate touchstone of friendship is not improvement, neither of the other nor of the self: the ultimate touchstone is witness, the privilege of having been seen by someone and the equal privilege of being granted the sight of the essence of another, to have walked with them and to have believed in them, and sometimes just to have accompanied them for however brief a span, on a journey impossible to accomplish alone. From David Whyte's *Consolations*. My dear friend Tim quoted [the full passage](https://www.likevillepodcast.com/articles/2021/5/15/friendship-a-selection-from-david-whytes-consolations-2020). ## 2. ![Juan and Fabian 1](/images/blog/martys-party/Juan-and-Fabian-1.jpg) ![Juan and Fabian 2](/images/blog/martys-party/Juan-and-Fabian-2.jpg) *Juan and Fabian, Laguna Veneta, Italy* ## 3. > Whither shall I go from thy spirit? Or whither shall I flee from thy presence? If I ascend up into heaven, thou art there: If I make my bed in hell, behold, thou art there. If I take the wings of the morning, And dwell in the uttermost parts of the sea; Even there shall thy hand lead me, And thy right hand shall hold me. Psalm 139 ## 4. A couple tracks from a [playlist](https://open.spotify.com/playlist/3kU96A3d6XOgtRRQoc1XJR?si=59970c5192014842). This is the first and last track I remember from the weekend. ## 5. pride / Or melancholy's sickly mood, / Still shy of human neighbourhood; / Or guilt, that humbly would express / A penitential loneliness ![wordsworth](/images/blog/martys-party/wordsworth.png) ## 6. Made from tickets of concerts I've attended, 2007. ![Martys Party. Collage made of concert tickets, 2007. ](/images/blog/martys-party/Martys-Party.jpg) **Martys Party.* Collage made of concert tickets, 2007.* --- ### 001 - Take the brightest URL: https://storybynumbers.com/writing/preview Date: 2023-04-07 Excerpt: Barthes, the Amstel in winter light, an old friend on 120 film, and butterflies on Rivadavia. ## 1. Roland Barthes, *Camera Lucida.* A reflection on photography, also a eulogy for his mother written shortly after her death. The entire book centers around a single photo that we never see. ## 2. The Amstel is beautiful on short days like this. Yoke colored light, sunny side up. ## 3. An old friend, 2010 and 2007 ![Image - Eric 1](/images/blog/preview/Image---Eric-1.jpg) *Eric, 120 film, Brooklyn* ![Image - Eric 2](/images/blog/preview/Image---Eric-2.jpg) *Eric with William, San Francisco* ## 4. ![Rivadavia mariposa](/images/blog/preview/Rivadavia-mariposa.jpg) *Las mariposas de Rivadavia* --- ### Hackathon at Al Jazeera URL: https://storybynumbers.com/writing/hackathon-at-al-jazeera Date: 2015 Excerpt: After three days of little sleep in Qatar, nineteen teams submitted their projects to address media challenges. Ours won the top prize for ethics. Al Jazeera invited me to join a hackathon at their headquarters in Doha. We were addressing the issue of trust in the media. Through a Chrome extension designed for minimal distraction, we provide a news agency with additional transparency using a mixture of public feeds, social networks, open data and scraping techniques. We render a profile of the author, publisher and the article's resonance (retweets) to provide the reader with contextual information on who is writing the article -- and who is consuming it. The tool also can highlight words that might indicate a certain bias or sensationalism.  The tool builds upon a new pervasive skill of readers to quickly gather impressions about a person, place and subject through a quick glance of a profile.  We were the only team that addressed our challenge through the context of social media, and we designed our tool upon a faith in journalistic principles, and upon the reader's own ability to assess trustworthiness. Technology cannot solve the issue of trust, but it can provide a medium to provide critical information for make an individual assessment. Our tool is a frictionless way for both the newspaper and the reader to gather metadata about an article. We took top prize in the category "Best Embodiment of Values and Ethics". ### **Who wrote this article?** I begin reading an op-ed piece published by Al-Jazeera. The author is detected by the Chrome extension and its icon indicates a match. In the background we retrieve the Twitter account and recent publication history of the author, and show crowd-sourced data about the publisher.  We see that Greg identifies very strongly with the book that he's written about oil: he references it in his Twitter nick, his Al-Jazeera bio, his twitter Bio, and his profile image. His recent article history shows two articles listed two years apart, both on the topic of oil.  The application doesn't tell me what to make of this information, or whether or not I should trust it. It provides a tool to make my own assessment. This might be quite subtle: in this instance, I now recognize Greg as an expert oil, and I'm conscious that there could be a PR element to publishing this op-ed piece. That isn't per se a bad thing, but it's something I'd like to know. ### **Highlights from other teams** **Street Stories **provides a panoramic street-view tool to narrate an event through both space and time. Their presentation focused on the events unfolding in Ferguson, something on everyone's mind during the event, and a topic I blogged about before leaving. Their solution paired rich media with a three dimensional view, providing a new context for image and video. ****[**Newsclip.se**](http://newsclip.se/) is an organizational and information sharing platform for journalists conducting research and building institutional memory. The user experience of this tool is shockingly good. A member of their team is also a technical contributors to OneWorld: Heinze Havinga ([https://twitter.com/HEINZEHAVINGA](https://twitter.com/HEINZEHAVINGA)) from Enschede, NL. We're proud of you and your team, Heinze!  **Lasertag** mapped more than 1 million relationships during their sprint to extract archival content from the Al Jazeera API. To demonstrate the concept, they wrote a plugin for Wordpress that listed relevant archival articles that overlapped the current draft of an article based on keywords and prevalence. As one of judges commented after their presentation, the wealth of past content is one of the most underused tools from an institution's toolbox. Lasertag addressed that issue from the production phase of journalism and provided an interface to work alongside a writerly environment. ### **Canvas is the start of a community** I met journalists, data scientists, media experts, specialists in machine learning, activists, designers, mathematicians, mappers and a wide variety of developers. The gender gap was small compared to most hackathons, with 40% women in attendance, and our group of 87 hackers flew in from 37 different countries. This came from a selection pool of 1,600 applicants.  What impressed me the most about this event -- generously hosted by Al Jazeera and flawlessly executed by Second Muse -- was this commitment to diversity. The content of the ideas were pushed to a higher level because of it, and set the tone and direction of our experiments. To our hosts, organizers, mentors and to my teammates: a big thank you from Amsterdam! --- ## Projects ### Video generated by code URL: https://storybynumbers.com/projects/video-platform Date: 2025-2026 Description: Story by Numbers is an AI video platform: agents assemble scenes from reusable layouts, people finish them in the studio, and a render can start from a brief or from a storm warning. Technologies: Remotion, React / Next.js, Python / FastAPI, AWS Lambda Story by Numbers is a video platform I have been building since early 2025. It renders video from code: every film is a React component, assembled from data and rendered frame by frame in the cloud. The fastest way to explain it is two jobs. A pub in Haarlem asked for the first. A storm warning started the second. ## A jazz night with no photographs The Wolfhound is a pub in Haarlem that runs a jazz underground night. For the announcement there was no photography and no footage. The materials were a sound clip from the trio and the event data: the date, the time, and who plays what. The illustrations were generated in a riso print style in the pub's own green and red. The captions are timed to the sound clip word by word, so the announcement plays like the night sounds. The point is not this one video. An event program is a data stream, and this pipeline reads one. The same run that made this reel can make the whole month: each night with its own lineup and date, and small variations in color and illustration from event to event so the feed stays fun rather than templated. ## The storm hits Amherst Andrus Power Solutions installs standby generators in the Berkshires. I built [their website](/projects/andrus) and an [automation](/projects/outage-triggered-postcards) that watches public weather and outage feeds across their service area and mails postcards to homes that depend on a private well. The same signal can now start a film. A living room goes dark and the cat's eyes catch the last light. One house on the street stays bright. By the closing shot the generator has switched itself on and the cat sits on its housing in the rain. The script names what a Berkshire homeowner actually loses in an outage: well water and medical devices. The warning does the targeting. It names the towns in scope, the pipeline writes each one into the opening line and queues a render, and the film is ready while the storm is still in the forecast. This run named Amherst. A warning over Greenfield renders Greenfield's. ## The studio Generation gets a film most of the way. The last part is taste, and that happens in the studio, a timeline editor over the same data the agents write. That is the Andrus film on the timeline. The transcript panel holds the script with the town as an open slot, and every word below the scenes is a chip the captions are timed to. Scenes stretch to match the audio, transcript and playhead highlight each other in both directions, and every color, headline, and duration a layout exposes can be adjusted by hand. When a generation step proposes variants, they sit side by side and a person picks the one that looks true. The studio also sets the frame: 9:16 for reels like the Wolfhound's, 4:5 for feeds like the storm film, 16:9 for anything wider. One project renders to any of them. ## The platform underneath The whole workflow is exposed to AI agents as tools: create a project, browse the layout library, assign content to a slot, write the headline, queue a render. Every tool call is validated against the same schemas the renderer uses, so an agent either produces a film that plays or a clear error that tells it what to fix. Scenes come from a library of reusable layouts, React components with named slots and a handful of exposed settings. New layouts scaffold from a single command, so a client's visual language becomes a working template in an afternoon. Voiceover, illustration, and image-to-video models sit inside the pipeline, each with a known price before it runs, which means an agent can be trusted with a budget. Rendering is deterministic: assets are resolved before the render starts, components are pure functions of the frame, and the same project produces the same file every time. Video that behaves like software can be versioned, reviewed, and re-rendered a year later without surprises. ## Where this is going The platform is in private development while I build it out with client work, like the [Instagram assets for a custom jeweler](/projects/custom-jeweler). I write about the build, the rendering techniques, and the agent tooling at [/writing](/writing). If your organisation has material that could become film, email me: [jason@storybynumbers.com](mailto:jason@storybynumbers.com). --- ### Walking a festival programme URL: https://storybynumbers.com/projects/festival-map Date: 2026 Description: A city festival's programme laid out as ground instead of a list. Rooms stand where they stand in the town, acts stand outside the room they play, standing on one plays its record, and the roads between them are researched connections rather than genre tags. Technologies: React Three Fiber, Next.js, PostgreSQL, Chrome DevTools Protocol, ffmpeg In August 2026 Haarlem Live fills cafés, churches and squares across the town with live music, and publishes its programme openly. This map lays that programme out as ground: every room stands where it stands in the town, every act stands outside the room it plays, and standing on an act plays its record. Nobody commissioned it; the map is my own project, live at [haarlemlive.storybynumbers.com](https://haarlemlive.storybynumbers.com). ## Why a map A festival programme is published as a list. It sorts by day and by time, it filters by room and by genre, and it answers the question it was built for, which is who is on at nine. It does not say which of the sets have anything to do with each other, and that is the question that decides where somebody actually goes. Genre tags do not answer it either. Every set on this bill carries them, and being filed under the same word as another band is not a reason to cross a town. Neither is the town itself: every act here is from Haarlem or near it, so a shared city says exactly as much as "both played Haarlem Live". ## Compressing the town Rooms are placed from their real addresses, but a literal projection of the centre of Haarlem is unwalkable: the venues crowd the old centre, some of them thirty metres from their neighbour, and a marker needs far more room than that before it can be seen and pressed. So the town is compressed the way a printed tourist map compresses a city. Two things are kept exactly: the bearing, so what is north of the church stays north of the church, and the order, so what is nearer the middle stays nearer the middle. The metric is the thing given up. The middle opens out, the outskirts draw in, and the festival reads as one village rather than a crowded core with a few strays. The relief is how many rooms stand in one area. Neighbouring venues stack into high country and a café on its own raises its own hill, so the busy stretch of town is visibly the busy stretch before anything has been read. Everywhere else on the platform this map runs on, height records how much of the music standing in a place has been heard. On festival ground the town wins, because a visitor can check the town. ## Walking the map Arriving at a room lights its entire bill at once, not the two or three sets nearest the hour. Standing on an act starts its record in the slip at the corner of the screen, with the day and time of the set, the room, and the places the act's own music can be found. The trail behind the traveler stays on the ground, so a walk through the programme leaves a record of itself. Apart from one card holding the night's running order, the map has no panel that lists what it holds: everything else it knows is an object standing on the ground. ## The roads Acts with something to do with each other are joined by roads. Some come straight out of the programme, which knows exactly one thing about any two acts: that they played the same room on the same night, one after the other. It is a real connection and it is the only one a festival's own data can support. The rest had to be found. A research pass reads what each act's own sources say about it and looks for the same name in two answers. A drummer in both bands, a producer on both records, a school both halves of two bands went to, a fourth band that two of these acts each have a member out of. The overlap is found in plain code and never trusted on its own: two pages holding the string "Jan de Vries" is a hypothesis about a name rather than a fact about a person. Every candidate is checked before it is allowed to become a road. These are as often banal as they are surprising. "The bass player in this one plays in that one" is not a story, and it is a true and useful reason to go and hear the other record. The reason is on screen the moment you arrive rather than behind a control, because a connection nobody can see the reason for is indistinguishable from a recommendation. ## On a phone A hand-held browser will not make a sound until it has been touched, so on a phone the map opens at a door instead of opening in silence. The door is a dial wearing the festival's own mark with every room and act on the bill fanned out around it, and going through it is the gesture that lets the first record play. Past the door it is the same world in one column. The world fills the screen, one slip at the bottom holds whatever is sounding, and the video folds away under a grip that follows the finger, because a phone should be able to keep the sound and hand the screen back to the map. ## Nu en straks Standing in a room answers what that café has on this week. It does not answer what is on at this minute, which is the question anybody in the middle of a festival is actually asking. So the map keeps one card for the night itself, behind a corner button reading nu en straks, now and soon. The card opens over the world rather than on a page of its own, so the record keeps playing and the walk stays where it was. Speelt nu, playing now, holds every set on at this minute, each with the hour it started and how long is left of it. Straks is the rest of tonight in the order it happens, and when tonight has run out the card says so and prints the next night under its own date. It never truncates: the card prints the whole night, because ten to seven, when a whole row of rooms starts at seven, is exactly the moment a cap would cut. Every row can be pressed, and pressing one walks the traveler to that act on the ground, or to its room when the act has no record on the map. The mark is addressed to a room rather than to a walker. When the map has sat untouched for a while it comes up enormous behind the world, in a different pair of inks each time, in hard cuts with no fades anywhere. It exists because this is the kind of thing that ends up on a screen in the corner of a bar, where half its audience is watching it rather than using it. ## The route films An evening somebody picks is three or four places and the hours they go on at, which is exactly what the map already walks when those places are pressed. So the reels are recordings of the map rather than a second rendering of the same night made to be watched. A real browser opens the festival's own map at a route handed to it in the address bar. A driver plays that route through the same door a thumb opens and the same links a card offers, waiting on the world the way a person does, and every frame the browser paints is kept through the DevTools screencast and cut together afterwards. Each record's own track goes under its stretch of the film. Changing which evening gets a reel is changing that list of rooms and times on the command line. A festival holds a great many evenings worth showing, and none of them need a video editor. ## Where this goes The map runs on my own publishing platform, which is where the research, the records and the roads are stored, and a festival is one shape it takes. A pub with a monthly night is another and a promoter with a single evening is a third. The parts that took the work are the ones that are not about Haarlem at all: turning real addresses into ground somebody can walk, finding connections that survive being checked, and filming a route off a live map instead of rebuilding it somewhere else. If you programme a night, a month or a festival and want to see your own bill standing up, email me at [jason@storybynumbers.com](mailto:jason@storybynumbers.com). --- ### Instagram assets for a custom jeweler URL: https://storybynumbers.com/projects/custom-jeweler Date: 2026 Description: A jeweler's workshop phone photos become a coherent visual language, finished Instagram assets, and film. Technologies: Image models, Programmatic video The client is a custom jeweler. Every piece is made by hand, most of them one of a kind, and each one is photographed the same way: on the workbench, on a phone, in whatever light the day had. Beautiful work, documented like inventory. She is not a professional photographer, and hiring one was never realistic: a studio shoot pays for itself over a production run, and her pieces have no production run. Whatever an asset costs, each piece has to carry that cost alone. So the workflow is designed around the photos she already takes, and asks for nothing beyond them: 1. A few phone shots of the finished piece, taken on the workbench. 2. The photos are uploaded to the studio. 3. The studio restyles them and places the piece on models generated earlier. 4. Out come finished images, or film. Everything past the upload is the studio's work. The piece stays exactly as photographed; everything around it is generated, from the surface it lies on to the light to the people who wear it. The finished assets come back in her visual language, sized for Instagram, across six color families. The phone photos are also upscaled along the way, so the finished asset holds up at full size even though the source never would. The models are the part that gets made once and reused. The woman below does not exist; she was generated for the brand, approved, and kept. Any new piece can now be placed on her without a booking, a shoot day, or a fee. ### From product photo to film The same photos can go further. For this hammered gold pendant the studio proposed several composites of a model wearing it, a person picked the one that looked true, and an image-to-video pass added five seconds of gentle movement for a reel. Photographed conventionally, that clip would have meant a model, a photographer, and a studio day. Here it took a phone photo and a few minutes of pipeline time, with a person approving each step. ### Built on the platform Everything above ran through Story by Numbers, the video platform I build and write about at [/projects/video-platform](/projects/video-platform). The jeweler work is one wiring of it: image models for the settings, compositing layouts with slots for the product and the portrait, and a render pipeline that produces the same asset every time it runs. When the collection grows, the feed grows with it. If your organisation has material that could become imagery or film, email me: [jason@storybynumbers.com](mailto:jason@storybynumbers.com). --- ### Andrus Power URL: https://storybynumbers.com/projects/andrus Date: 2026 Description: Full redesign for a family-owned generator contractor in the Berkshires. A static Astro rebuild with 37 hand-written town pages for Western Massachusetts and big, measured performance gains. Technologies: Astro, TypeScript, Tailwind CSS, Mapbox GL Andrus Power Solutions is a family-owned generator and electrical contractor in Lee, Massachusetts, on call for the Berkshires since 1991. They sell, install, and service Generac and Kohler standby generators across Western Massachusetts and the neighboring corners of New York and Connecticut. Their old site lived on a website-builder platform and carried its weight: stock layouts, a heavy stack of tracking tags, and copy nobody could comfortably read. I rebuilt it from the ground up, from visual design through front-end, content, and local SEO. ### The redesign A generator company sells calm. The design leans into that: a warm paper background, deep navy ink, and one orange accent reserved for the quote button. Photography is documentary, real crews on real installs in real Berkshire weather. Under the hero, a quiet band states the facts that matter to a homeowner choosing a contractor: 35 years, family owned, three states, 24/7 response. ### Built for Western Massachusetts Generator work is hyper-local. Whether a house needs a standby unit depends on which side of town it sits: village streets on the gas grid with short outages, or rural roads with long overhead feeders, propane heat, and private wells. The site treats that geography as content, not boilerplate. There are 37 location pages, one per town and county served, and each one is written by hand. The Great Barrington page knows that Main Street is commercial and runs on Eversource, that Housatonic and Van Deusenville follow the rural pattern, and that the hills toward Egremont are full of second homes that need freeze protection through a January outage. Each town is a structured content entry with its own title, meta description, hero, and coordinates. Those same coordinates feed the service-area map: the shop in Lee, the radius the crews cover, and recent jobs plotted as dots across the three states. Below it, every town links to its own page. ### Performance The numbers were the easiest part of the pitch. The old platform loaded two tag-manager containers, ad pixels, call tracking, and an accessibility overlay from 27 third-party domains. The rebuild is a static Astro site whose only third parties are the fonts and the map. Requests per page dropped from 115 to 32. Layout shift went from 0.40 to zero. Full page load went from 0.67 to 0.25 seconds. Lighthouse Best Practices went from 58 to 100, and AI readability, how well assistants and crawlers can parse the page, went from 67 to 100. Average sentence length in the copy fell from 41 words to 17, because speed does not help if nobody reads past the first line. ### Mobile People search for generator repair when the power is already out, standing in a dark kitchen with a phone. The mobile layout keeps the phone number and the quote button within thumb reach, collapses the services to a single column, and loads fast on a weak rural connection, which is exactly where the customers are. ### Stack Astro with MDX content collections, Tailwind CSS, and Mapbox GL for the service-area map. Marketing pages, service pages, and town pages are all structured content entries, so new towns and services ship without touching a template. The build is fully static, packed into an nginx container, and deployed automatically on every push to main. --- ### Ons Straatje URL: https://storybynumbers.com/projects/ons-straatje Date: 2026 Description: A private, invite-only directory for a single street. Photos, short bios, and an admin panel built around the way neighbors actually share things. Technologies: Next.js, TypeScript, Tailwind CSS, PostgreSQL, Drizzle ORM, MinIO / S3, Mapbox Most Dutch streets work the same way. There is a WhatsApp group where someone asks if anyone has a ladder, where lost cats are reported, and where photos of unfamiliar cyclists circulate when bikes start going missing. There is an annual straatfeest, the street barbecue, which is when you finally meet the family who moved into number 22 last spring. Neighbors feed each other's cats, water plants when someone is away, and keep an eye on each other's parcels. Ons Straatje is a small website built for that kind of street. It is a private directory for one block: every household with a portrait, a short bio, and as many photos as the residents want to upload. Only the people who live there can see it. The first version was a wall of printed A4 sheets at the annual barbecue, so newcomers could put faces to names. The wall came down at the end of the night. The site is what stayed. [Open the demo](https://straatje.storybynumbers.com/) ### Access without passwords Residents sign in through a private invite link shared in the neighborhood WhatsApp group. There are no accounts to set up and no passwords to remember. Once a device has been used, it stays signed in. If a link is shared too widely, the admin can revoke it and issue a new one. The result is that onboarding a whole street takes a single WhatsApp message. ### Edit your own listing Every resident can rewrite their bio, add or reorder photos, and update names as a family changes. They can take their listing offline with a single toggle and bring it back later. There are no comments, no feed, no algorithm. ### Quiet by default The whole site is set to noindex, so search engines cannot find it. There are no analytics, no third-party scripts, no tracking pixels. The only data on the server is what residents have chosen to put there. Every change is snapshotted before it is saved, so any edit can be reverted from the admin panel in two clicks. The same applies to revert itself, which means accidental rollbacks are also recoverable. ### Mobile is the default Most opens happen on a phone, in the same WhatsApp thread the invite came through. The map and the household list collapse into a single column on small screens, the photos stay tappable, and the edit form works one-handed. ### Built to be reused The codebase already runs more than one street. Configuration is a handful of environment variables: street name, city, hero image, map center. A new neighborhood can come online with a fresh database and a Docker compose up. The stack is Next.js, PostgreSQL, and S3-compatible object storage, hosted wherever you want. If you would like this running for your own street, [get in touch](mailto:jason@storybynumbers.com). --- ### loqaal.eu URL: https://storybynumbers.com/projects/loqaal Date: 2026 Description: Brand, site, and CMS for a Dutch logistics staffing company. Craft CMS back-end with proximity-based vacancy search and a one-click LinkedIn carousel generator. Technologies: Craft CMS, Twig, PHP, Tailwind CSS loqaal is a staffing company for the Dutch logistics sector, connecting forwarders, planners, customs specialists, sales people and warehousing staff with the companies looking for them. The premise is small-scale and personal: real conversations with candidates and employers in a sector that usually treats both as throughput. I handled the full scope, from brand and visual design through front-end and Craft CMS development. ### The brand The identity sits on a yellow-on-black wordmark with a gold underline that becomes a recurring structural device across the site. Photography leans documentary: real warehouses, real cranes, real forklifts, set against a warm rust-red ground that anchors the editorial moments like testimonials. Type is generous, headlines are confident, and the only flourish is a single word picked out in gold inside each section title. ### Proximity search Logistics work is geographic. The first question almost any candidate asks is how far the job is from home. The vacancy listings page leads with that question: a postcode field, a radius selector from 5 to 100 km, and filters for specialism and contract type. Postcodes are geocoded and cached server-side, so changing the radius re-filters the list immediately. The same mechanism powers the regional landing pages, /jobs-in-rotterdam, /regio-amsterdam, /regio-brabant. Each one is a single Craft entry with a postcode, a radius, a hero image and some intro copy. New regions go live without a deploy. ### Vacancy pages Each vacancy is a Craft entry with structured fields for location, contract type, specialism, salary range and hours per week. Those become the pill row at the top of the page. Body content uses Craft's Matrix field, so the editor composes long descriptions, lists of tasks, requirements and benefits without touching a template. ### One-click LinkedIn carousel The team at loqaal posts on LinkedIn constantly. The fastest-performing format on the platform is the PDF carousel: several portrait pages with one idea each, swipeable in the feed. Building one by hand in Figma or Canva for every new vacancy was eating an hour per post. So the Craft control panel has a single button on each vacancy entry, "Genereer LinkedIn carousel". One click composes a multi-page PDF on the server, sized for LinkedIn's portrait carousel format, pulling the role title, location, salary range, key responsibilities and the loqaal brand into a templated layout. The editor gets a download in a few seconds, ready to drop into a LinkedIn post. The template itself is a Craft entry, so the layout can be tuned without redeploying. ### Mobile is the default Most candidates open the site on a phone, often between shifts. The vacancy listings collapse to a single column with a single Filters button that expands the postcode, radius, specialism and contract-type controls. Vacancy cards stay tappable, salary ranges stay readable, and the apply button stays in reach. ### Stack Craft CMS on the back end, Twig templates, Tailwind CSS, and a couple of small PHP modules for the carousel generator and the postcode geocoder. The site is fast, the editor experience stays close to vanilla Craft, and an editor can post a new vacancy and ship a matching LinkedIn carousel inside the same five minutes. --- ### Outage Postcards URL: https://storybynumbers.com/projects/outage-triggered-postcards Date: 2026 Description: A marketing automation that watches outage and weather signals, finds the right homes, and mails a locally relevant postcard while the need is still fresh. Technologies: Python, Geospatial, Weather & outage feeds, Direct mail API Most marketing runs on the company's schedule. A newsletter goes out on Tuesday. A campaign launches in September. A sales list gets worked when somebody has time. Some offers have a better clock. For a standby-generator company, that clock is the weather. A household on a private well can lose more than lights during an outage. No power means no pump, which means no taps, no shower, no water for the heating system, and sometimes a frozen house if the owners are away. I built a pipeline around that moment. It watches public outage and weather feeds across the service area, then scores each event by type, severity, geography, and the number of relevant homes nearby. Severe thunderstorm warnings, high-wind warnings, winter storms, and major outages can all count. Broad watches and low-value alerts usually disappear before anyone sees them. The audience is mapped before the storm arrives. Public well-completion records identify homes that likely depend on a private drinking-water well. Those records are cleaned into a small local database with address, town, coordinates, well type, drilling year, and source metadata. A campaign can filter to the exact segment: drinking-water wells, recent enough records to trust, inside the service area, outside the suppression list. That preparation matters because the event window is short. After an outage clears the threshold, the system matches the outage geometry against the address pool, removes current customers and recent contacts, deduplicates the list, estimates the cost, assigns a tracking number, publishes a campaign landing page, and submits the mail batch. No one needs to draw a polygon at midnight. No one needs to export a CSV while the phones are already ringing. ## What Makes It Work Weather data is loud. The system has to be good at silence. Each alert runs through tiered rules. Critical events always surface. Major warnings need enough relevant homes in scope. Watch-level alerts need both scale and a narrow enough geography to be meaningful. The pipeline groups similar alerts by event type and calendar day, then applies a daily cap so one active storm line cannot create a pile of duplicate starts. Every skipped event has a reason: wrong alert type, too few homes in scope, too many counties, already seen today. When the system acts, the run is auditable after the fact. The postcard is generated per recipient. The greeting falls back safely when an assessor record looks like a trust, LLC, or business. Town names are formatted for natural copy. The QR code carries a recipient tag through a short redirect, so scans can be attributed without printing a brittle final URL. Each campaign also gets its own local phone number. Calls forward normally, but inbound activity belongs to the campaign that produced it. The landing page publishes before the cards go out. Postcards are submitted with idempotency keys, so a retry skips duplicate cards for the same recipient. ## Why This Pattern Matters Direct mail has a useful shape here. It arrives after the immediate disruption, when people have had time to cool down and start thinking about prevention. It reaches the home as a physical reminder, with enough space to speak to the neighborhood and the specific problem the household just experienced. The automation makes the message quieter, more specific, and better timed. That operating pattern is the useful part. A real event occurs in the world. The system understands whether the event matters, who it matters to, what should happen next, and where the guardrails are. The visible output might be a postcard, a call list, a landing page, a repair reminder, a customer check-in, or a sales brief. For businesses with local service areas, high-consideration purchases, seasonal risk, or a strong "I should really deal with this" moment, that kind of automation can feel less like marketing and more like good timing. --- ### A sales agent in Obsidian URL: https://storybynumbers.com/projects/sales-agent-obsidian Date: 2026 Description: A local-first approach that scores Dutch companies against my service wedges and writes a short daily brief into my notes app. Technologies: Python, SQLite, Claude (CLI), Obsidian I built a local-first sales agent for Story by Numbers. It finds Dutch companies that fit the kind of work I sell, scores them against my service wedges, and writes a short brief into Obsidian every day. ## How signals work A signal is a small, observable fact about a company. Does it have a product catalog? An archive? A published research collection? A B2B portal? Editorial output? Each fact moves a score up or down. Some signals are gates. They reject candidates before any model is called. Others are weights. They tilt similar candidates toward different wedges. A wholesaler with a deep catalog and a B2B portal will score high in one direction. A research foundation with a digitized archive will score high in another. The same agent looks at both, but reads them very differently. I keep my full signal set private. It is the encoded version of my offer and my taste, and it changes as I learn. ## Filtering before the model Cleanup happens before the language model is involved. Sectors I never sell into are gone before any reasoning step. Companies outside the service model are rejected at the rule layer. Only the survivors get a structured pass. That keeps the model focused on judgement, not on cleanup. It also keeps the running cost predictable. ## Obsidian as the feedback loop The brief lands in Obsidian, where I already keep my notes. I mark companies as rejected, parked, lost, or won. Those notes are read back into the local database on the next run. A reflection step proposes scoring adjustments based on recent outcomes. I review them by hand before any take effect. The agent improves. The final judgement stays with me. ## Small, local, inspectable The stack is intentionally simple. Python, SQLite, public sources, markdown, Obsidian. The whole thing runs on my laptop. The reasoning step calls Claude through the CLI, which uses my monthly subscription, so there is no per-run API bill to think about. A cron job kicks off a run each morning while I make coffee. No dashboard, no hosted service, no automated outreach. Each phase writes to a local database, so runs can be resumed and decisions can be inspected later. The agent is useful because it is narrow. It encodes my commercial context and gives me a small number of plausible companies each week. For a studio like mine, that is enough. --- ### Bastienne Kramer URL: https://storybynumbers.com/projects/bastienne-kramer Date: 2025 Description: Contemporary art portfolio with real-time preview system, modular content blocks, and secure Studio integration Technologies: Next.js, Headless CMS, GraphQL, TypeScript For sculptor Bastienne Kramer I built a contemporary portfolio site that gives her work a clear, spacious presentation grounded in her long studio practice. The foundation is a simple, durable structure using Next.js and Sanity.io, but the real work was editorial: understanding her archive, shaping it, and giving it a visual logic that feels natural to her sculptures, installations, books, and studio notes. ### Context and Challenge Kramer’s material reaches across decades: exhibitions, objects, installations, residencies, books, experiments, and a large back catalogue that had lived partly on WordPress, partly in an older PHP site, and partly in offline folders. The challenge was to give this heterogenous body of work clarity without losing texture. The site needed to feel contemporary yet grounded, capable of hosting new writing and updates, while still doing justice to older documentation. ### Approach I started with the content itself. Before touching layout or interactions, I mapped each body of work, identified gaps, and reconstructed lost entries from the archive. The previous website had a tone that still carried value, so I took that as a starting point and gave it a new interpretation: more pared back, easier to navigate, and more focused on the work rather than the interface surrounding it. At a key moment in the process, I had an in-studio session with designer Yvonne van Versendaal. She is exceptionally good at seeing what a portfolio is becoming rather than what it currently is. She sharpened the structure, challenged my assumptions, and made subtle yet decisive adjustments that aligned the presentation with the sensibility of Kramer’s sculptures. That session lifted the project out of the technical bubble and brought it fully into the realm of artistic presentation. ### Impact The result is a portfolio that is easy to update, visually coherent, and expansive enough to hold Bastienne’s ongoing work. It has already streamlined her editorial workflow and resurfaced years of archived material that had never been shown properly. We are now exploring how to extend the site’s reach beyond the web. One direction is experimenting with text-to-video tools to upscale older archival footage and reintroduce it in a more contemporary form. Another is bridging the website’s structured content with social channels, reducing duplication and avoiding the siloing that often happens between a main portfolio and public-facing updates. The long-term aim is a single ecosystem where new work, documentation, and social output reinforce each other rather than live in parallel. --- ### OUTCAST REGISTRATION URL: https://storybynumbers.com/projects/outcast-registration Date: 2024 Description: A digital archive presenting long-term arts-based research on drug-addicted women in European prisons through ethical, structured storytelling. Technologies: Craft CMS, Vite OUTCAST REGISTRATION is a bilingual digital archive that brings twenty-five years of arts-based research onto the web. Working with the artist-researcher Ulrike Möntmann, I built a platform that holds the life stories of incarcerated, drug-addicted women across Europe. The research has its own instrument, the Matrix Method, a controlled vocabulary of keywords through which each woman reconstructs her biography as a sequence of events and decisions. The archive gathers that material, the written life, the recorded voice, the theory, and the geography, into one structure that the researchers can keep extending. The material is difficult. The biographies record street life, addiction, repeated institutionalisation, and violence that usually began in childhood. My task was to build an environment that could carry this weight without sensationalising it, and without flattening the women into data. The research already came with a conceptual language, and the site needed to follow that logic without turning into an academic apparatus. ### Parrhesia, the risk of speaking up The theoretical centre of the project is Foucault's idea of parrhesia, the courage and the duty to speak the naked truth, to take a position openly against the established order while knowing that doing so risks punishment. The person who speaks this way, the parrhesiastes, speaks in public, and that is what gives the act its political and ethical weight. In OUTCAST REGISTRATION the speakers are women at the far edge of society, incarcerated and addicted, addressing the same society that cast them out. Foucault drew the idea from Greek tragedy, from Sophocles' Oedipus and from Euripides' Ion, where people are guilty through no fault of their own. That phrase is also the thread running through these lives. In almost every biography the harm starts early, and it comes from fathers, uncles, brothers, and neighbours, from trusted people close to home. This shaped how the archive is built. A biography here is a speech act, set down in the woman's own ordering of events, so the interface treats each account as testimony and keeps the recorded voice next to the written page. Foucault calls this Speech Activity, speaking that commits the speaker to the truth, and the whole point of the research is to let these women be heard, in public, in their own words. ### Three kinds of space The research reads each life through three spaces, and the site is organised the same way. The isolated space is the sealed one, the cell, the closed institution, and the withdrawal the women carry inside them. A prison director once observed that the women do not run away; they hold themselves to be guilty and justly confined, so the walls and the wire are almost beside the point. The public space is the street and the city, the arena where parrhesia can happen and where the work has to reach an audience that would rather look away. Parrhesia in the City took this literally and placed the research in the city's advertising displays, so that passers-by met it on the way past. The cultural space is the space of art, of the stage and the archive, where a life can be represented, witnessed, and turned into shared knowledge. We mapped these spaces because the distance between them is the whole problem. An account stays locked in the isolated space until something carries it into the public space, and it becomes a matter of common concern only once it reaches the cultural space. Plotting the three spheres makes that asymmetry visible: how far a story has to travel before anyone hears it, and how much of a life is spent out of sight. The site's Spaces section maps these spheres for every participant, so the structure stays concrete and tied to real lives. ### Mapping a life Geography became one of the organising principles of the archive. I built an interactive globe marking the birthplace of every participant, and a movement map that ties recorded passages and Matrix Method entries to the places where events happened. The reason for putting maps on the biography pages sits in the material itself. These are lives of constant displacement: foster placements, hostels, other cities, borders crossed and crossed back, one institution after another. A map holds all of that at once. It turns a scattered list of events into a path that can be traced, and it lets a reader follow how neighbourhoods, institutions, and repeated removals shape a single, often tragic life. ### The Matrix Method The biographies are built with the Matrix Method, which Möntmann developed out of necessity. From a catalogue of around 260 basic terms, a woman chooses the words that apply to her, then arranges them into the order of her own life. Selecting and combining the words lets her set traumatic events back inside a chain of cause and effect, without being asked to standardise her story, accept blame, or hand it out. I built the biography pages directly from these selections, so the structure a reader meets on the page is the structure the participant made. ### Building the archive All of this runs on a lightweight, bilingual Craft CMS installation. The information architecture follows the research. Biographies are factual timelines, the analysis of spaces shapes how content is grouped and navigated, and geography is threaded through both. Möntmann and her collaborators can keep adding biographies, recordings, documents, diagrams, and project updates in English and German without touching code. ### Impact The result is a growing archive of arts-based research. It centralises decades of material, supports new phases of the work in northern and southern Europe, and stays legible to very different readers: artists, researchers, students, and policymakers. The mapping shows how far the stories reach, while the structured biographies keep the specificity of each voice. The system expands as participants, events, and findings are added, and it now serves as the reference point for the project's public and academic life. --- ### Collabhouse URL: https://storybynumbers.com/projects/collabhouse Date: 2023–2024 Description: A strategic shift to in-house development for a complex music platform, fostering internal ownership and laying the groundwork for iteration and growth. Technologies: React, MySQL, TypeScript, Serverless Architecture, RESTful APIs, GraphQL, Gatsby, Webpack, AWS Lambda In April 2023, I joined Collabhouse, a music technology company driven by the mission to help artists, labels, and creators "Make More of Music". The platform offered an integrated suite of tools designed to empower creators, including global music distribution to streaming services, direct sync licensing opportunities through its Music Library, facilitated artist-influencer collaborations via the Collab Market, and forward-thinking monetization avenues such as tokenized royalty-split NFTs. My engagement began concurrently with a crucial strategic pivot for the company: the decision to transition its core platform development capabilities from reliance on an external agency to fostering a dedicated, internal engineering team. Understanding that the inherent complexities and the need for rapid innovation demanded by Collabhouse's multifaceted platform and ambitious mission were likely constrained by an external development model, I led the transition to build a sustainable, integrated team. ![Collabhouse images](/images/projects/collabhouse/body-01.png) ### Moving in-house Building an internal team meant orchestrating a transfer of domain-specific knowledge, establishing new internal development methodologies, and ultimately assuming full technical stewardship of the existing codebase and infrastructure. This infrastructure supported the entirety of Collabhouse's service offerings – from Music Distribution and the Music Library to the Collab Market and NFT Market. The overarching objective was to cultivate a self-reliant, agile, and knowledgeable engineering unit. It had to be equipped to maintain, enhance, and rapidly iterate on the platform, enabling Collabhouse to better address the evolving needs of its diverse user base and capitalize on emerging market opportunities. ### The challenge This initiative presented a formidable set of interconnected challenges, spanning both internal organizational dynamics and external market realities. Collabhouse operates within the demanding music industry ecosystem, where independent artists constantly battle for exposure and equitable earnings ; consequently, any lapse in platform stability or delay in feature enhancement could directly impact users' careers and trust. Internally, the primary hurdle was navigating the transition itself – a delicate process fraught with potential risks. These included the possibility of critical knowledge being lost during the handover from the agency, the imperative to maintain uninterrupted service continuity for thousands of artists and creators utilizing the platform's diverse features , and the need to avoid disrupting essential business operations. Compounding this complexity was the parallel task of building a skilled, cohesive engineering team from scratch, integrating new hires into a complex, mature system, and establishing an effective development culture – all while ensuring the continued delivery of vital platform improvements and maintaining operational stability. It was akin to rebuilding the aircraft's engines mid-flight, where any misstep could compromise the journey for everyone onboard. ### Key Achievements Acknowledging the significant risks involved in such a fundamental shift, I championed and executed a phased, gradual transition strategy, deliberately avoiding an abrupt cutover to allow for methodical knowledge transfer and minimize operational disruption. In the initial phase, I acted as the central technical point, serving as the communication bridge between internal Collabhouse stakeholders and the external development agency. This period also involved my own deep immersion into the platform's existing architecture and, critically, into the nuances of the music industry domain – understanding the intricacies of royalty calculations, rights management workflows, and the technical pipelines for digital distribution. As the internal team grew in capability, I transitioned to overseeing the successful implementation and integration of several key technical projects that directly enhanced platform value: - We integrated **Cyanite**, an AI tool for tagging music by mood and genre, enhancing our search functionality for song similarity. - We stabilized our integration with a major digital **distribution aggregator**, ensuring smoother operations. - We launched **in-app messaging** using Bird to facilitate communication between artists and creators within the platform. - We implemented **PayPal Payouts** to efficiently transfer collected royalties to rights holders. - We **streamlined user registrations** and simplified account permissions, enhancing overall user experience. These efforts have not only improved our platform's functionality but have also set a solid foundation for future growth and development at Collabhouse. --- ### Charlotte Salomon URL: https://storybynumbers.com/projects/charlotte-salomon Date: 2024 Description: Digital adaptation of Charlotte Salomon's Life? or Theatre? for the Joods Cultureel Kwartier. Nearly 800 gouaches, multilingual narration by professional voice actors, and high-resolution tile-based zoom. Technologies: Next.js, React, TypeScript, RESTful APIs Charlotte Salomon (1917 to 1943) was a German-Jewish artist who, in the years before her death at Auschwitz, painted nearly 800 gouaches and edited them into a single, indefinable work she called *Life? or Theatre?*. She subtitled it *A Play With Music* and structured it like a Singspiel, an old form of opera blending visual art, written text, and musical references. It is one of the most extraordinary artworks of the 20th century, and was shown in its entirety for the first time at the Joods Cultureel Kwartier in Amsterdam. I led development of the digital companion. The app launched first on iPads inside the gallery, with the original interaction design by Total Design, and then as a public-facing site at [charlotte.jck.nl](https://charlotte.jck.nl/). ### Respecting the Singspiel Salomon ordered her paintings deliberately. *Life? or Theatre?* opens with a Prelude, builds through a Main Section, and resolves in an Epilogue, with separate categories for unnumbered pages and letters. She also assigned a piece of music to many paintings, songs she hummed while she worked and noted on the reverse of each page. The digital experience holds onto that order. Visitors can browse the program from start to end, jump into any of the six sections, or step page by page through the entire 970-record archive. Filters by character and theme are tucked behind a button so they don't compete with the work itself. ### A page at a time Each painting opens in a quiet two-column layout: the gouache on the left, the accompanying text on the right, with a paginated arrow to step forward. The text was translated into multiple languages and recorded by professional voice actors, so a visitor can sit with one painting, hear the words Salomon set against it, and move on at their own pace. The narration is anchored to each page: pause it, change languages, or scrub back, and the audio stays with the painting you're looking at. Subtitles also follow the timing of the recording for visitors who prefer to read along. ### High-resolution, zoomable canvas The original gouaches contain extraordinary detail: written notes, brushwork variations, painted-on overlays of color. To make those legible, every painting is served as a tile pyramid, the same approach maps use, so visitors can pan and zoom into any part of the page without the file-size cost of a single huge image. ### Mobile The gallery iPad layout was the starting point, but the public site needed to work on a phone too. A single-column reflow stacks the painting above its narration, keeps the audio control persistent at the bottom, and preserves the same forward and backward pagination through all 970 records. ### Stack Next.js, React, and TypeScript on the front end, talking to the museum's record API. The tile renderer sits on top of an open-source deep-zoom viewer. Multilingual content and audio assets are served from the museum's CMS, so the curators control the work end-to-end without going through code. The site is live at [charlotte.jck.nl](https://charlotte.jck.nl/). --- ### Eye Filmmuseum URL: https://storybynumbers.com/projects/eye-filmmuseum Date: 2020-2022 Description: A digital transformation of Amsterdam’s iconic film museum, integrating editorial, programming, and ticketing into a unified, audience-first platform. Technologies: React, Next.js, Craft CMS, RESTful APIs, GraphQL From 2020 to 2022 I led the rebuild of eyefilm.nl for Eye, the Dutch national film museum. The trigger was a CMS reaching end-of-life; the work became a rethink of how the museum presents itself online: one platform for exhibitions, films, and tickets, one agenda feeding the website, the ticket desk, and the screens in the building. I started as lead developer and ended as product manager. ### **The client:** an iconic Amsterdam museum Amsterdam has about 50 museums, but Eye is one of the most instantly recognizable. Its striking white building, perched on the IJ across from Central Station, is a landmark in its own right. As I write this, they’re preparing to host Queen Máxima for their 75th anniversary. But Eye is more than a museum. It’s a cultural center, cinema, restaurant, research institute, and exhibition space. Every day, digital and analog films are screened. Behind the scenes, their collection center holds over 50,000 titles, along with posters, equipment, and ephemera. Eye plays a vital role in preserving Dutch film heritage and promoting cinema at home and abroad. ![Entrance to Eye](/images/projects/eye-filmmuseum/body-01.jpg) *Entrance to Eye. Photo by Huub Zeeman.* ### **The project:** a new website The initial trigger was technical: Drupal 7 was reaching end-of-life. But the real opportunity was strategic. A site rebuild invites the kind of institutional introspection normally reserved for 5-year plans or change-of-leadership cycles. Eye could have simply ported the existing site to a modern framework. Instead, they used the moment to rethink workflows, team structures, and how the institution presented itself to the world. The website isn’t the heart of the museum – that role belongs to the building itself – but unlike architecture, digital infrastructure can be restructured. And in this case, it needed to be. The real challenge was shifting from a broad digital transformation trajectory into something more focused: delivering a coherent product. ![Eyefilm.nl opening animation](/images/projects/eye-filmmuseum/body-02.png) ### **The challenge:** multiple audiences, one homepage The old homepage tried to be everything to everyone. It was structured around departments, not audiences. Content was hard to find, and even basic tasks like checking what was playing that day were buried. Internally, teams felt their work was invisible. Marketing flagged a lack of urgency and differentiation: why should someone go to Eye today? And why Eye, rather than a regular cinema? Instead of trying to satisfy every stakeholder with a consensus-driven patchwork, we worked with the design team on a radical shift. The new homepage prioritized exhibitions first, then film programming via a tightly designed agenda. Navigation was reimagined from the ground up to reflect actual user journeys. We emphasized landing pages, anticipating that most visitors arrive via search, not the front door. The homepage became a clean, two-paneled design: - The first panel showcased curated highlights: exhibitions, special film programs, conferences. - The second showed a structured daily agenda: scan-friendly, detailed, and one click away. Typography was restrained, content anchored to a left-aligned reading line. This made dense information easier to scan without flattening it. - Screenings with Q&As or interviews were highlighted. - Flexible landing pages gave space to departments like education, collections, research, and the restaurant. - SEO strategy shifted away from assuming the homepage as the sole point of entry. ### **My role:** from developer to product lead I started as lead developer, joining early workshops to map the goals, constraints, and internal systems. My initial responsibility was to define a technical strategy that could accommodate Eye’s sprawling organizational structure: collections, programming, education, research, exhibitions, and more. As the project evolved, I stepped into the role of product manager. That meant coordinating across multiple teams -- content, tech, design, and programming -- each with its own logic and priorities. I briefed external agencies, ran selection rounds, wrote documentation, and gave regular presentations to staff across the entire organization to maintain alignment and momentum. I also led the effort to deliver a coherent omnichannel agenda: one schedule powering the website, the ticket desk (balie), and narrowcasting displays, all pulling from a shared system. My job was to keep the product vision clear, communicable, and deliverable, from first sketch to final launch. ### **Approach:** integrate, don't reinvent Eye’s programming is rich and idiosyncratic. Each film listing includes not just metadata -- directors, cast, stills, trailers, format, subtitles -- but also hand-written editorial notes contextualizing that showing within a specific program. If the same film appears in two different series, it gets two different write-ups. The archive is a treasure trove. Each film page pulls data from multiple systems: - Ticketing (used by the website, the balie, and narrowcasting screens) - Programming databases (with structured metadata) - The CMS (where editors enrich pages with text, images, and related content) One of the key architectural challenges was cleanly separating those concerns, ensuring editorial freedom while maintaining structural clarity and performance. We didn’t try to jam everything into the CMS. Instead, we built pipelines where human input could layer onto automated data without friction. --- ### Jewish Cultural Quarter URL: https://storybynumbers.com/projects/jewish-cultural-quarter Date: 2017 Description: Bringing five separate websites under a single identity. The focus of an exhibition, with the exploration of a collection. Technologies: React, RESTful APIs, Headless CMS, Drupal The new website I built in 2017 for the Jewish Cultural Quarter (*Joods Cultureel Kwartier*) was built in React.js, and one of the first headless CMS solutions in the Netherlands, certainly for a website of this scale. It was my final project as Lead Developer at [Total Design](https://totaldesign.com/), and I think the most ambitious. It was my first time working with React, and with Drupal 8. At the time there were no frameworks like Next.js, and there was no recipe book to handle the server-side rendering or page transitions. ### Merging five websites into one The Jewish Cultural Quarter had separate websites for the Historical Museum, the Portugese Synagoge, the Ets Haim library, the Children's Museum, and the Hollandsche Schouwburg. We created separate landing pages for each location, but brought everything under a single domain with a consistent look and feel. ![layered JCK homepage](/images/projects/jewish-cultural-quarter/body-01.jpg) *Screenshot of jck.nl* ### Exposing the museum collection While the website web developed, JCK migrated their cultural heritage database of documents, paintings, photographs, posters and religious artifacts to a new system with an open API, so we could access them through the website and use them in articles and longreads. The homepage had columns with key pieces from their collection. ![JCK Gallery](/images/projects/jewish-cultural-quarter/body-02.jpg) *The museum collection highlights, displayed in scrollable columns.* To present both specific objects and narratives from Amsterdam's Jewish Cultural Quarter, designer Thomas Pleeging envisioned a layered website encouraging fluid movement between exhibitions, longreads and items from the museum's vast digital collection. We created a standalone JavaScript application to present a unique frontend and leveraged Drupal 8’s REST API to manage the thousands of pages necessary to consolidate many websites into one. ### Modular components A website for a major museum will last between five and seven years, and redevelopment is often coupled with a new look and feel. What's often left behind in the redesign are the smaller applications built along the way for temporary exhibitions. I always encourage organizations to develop their style guides into reusable components, so the primary website can evolve alongside archival content. For the JCK, we built the menu as a separate module that could be used on both the primary website and for the [Charlotte Salomon exhibition](/projects/charlotte-salomon). ![Jck.nl menu component](/images/projects/jewish-cultural-quarter/body-03.jpg) *The menu was developed as an npm module to use across multiple projects.* --- ## Services - [Websites](https://storybynumbers.com/services/websites) - [Strategy](https://storybynumbers.com/services/strategy) - [Chatbots](https://storybynumbers.com/services/chatbots) ## Optional - [RSS Feed](https://storybynumbers.com/feed.xml) - [Sitemap](https://storybynumbers.com/sitemap.xml)