Håndkodede nettsider inspirert av legendariske C64

Når stadig mer av koden jeg skriver på jobben skrives av AI, var det deilig å kode litt for hånd igjen.
AI-agenter skriver en stadig større andel av koden for de fleste utviklere – også for meg. Jeg skriver fortsatt noe kode for hånd, men det er rett og slett ikke forsvarlig tidsbruk å bruke flere dager på noe en AI-agent kan skrive på noen timer.
Claude Code har blitt en så stor del av arbeidsdagen min, at jeg har begynt å savne håndkodingen. Å sitte i timesvis og gruble og kjenne på frustrasjonen, før du får den gode følelsen når du endelig løser et problem som virket uoverkommelig.
Som konsulent må jeg være effektiv. Kundene skal ikke betale for at jeg skal kose meg (selv om jeg faktisk koser meg med Claude Code også).
Men hjemme – der kan jeg bruke så lang tid jeg bare vil på hobbyprosjektene mine. Derfor bestemte jeg meg for å håndkode de nye nettsidene mine.
Hvorfor håndkode i 2026?
Før jeg forteller hvordan nettsidene er laget, lurer sikkert noen på: Hvorfor gidder du å kode for hånd? Eller for den saks skyld: skrive denne artikkelen for hånd?
Den åpenbare grunnen til at jeg håndkoder har jeg allerede nevnt: Fordi jeg savner det! Men det er flere grunner:
- Holde kodeferdighetene ved like, slik at jeg ikke er fullstendig fortapt hvis Claude Code skulle være nede en dag.
- Bruke hodet og holde hjernen skjerpet.
- Føle eierskap til koden, og få en dypere forståelse for hvordan og hvorfor noe virker.
- Komme i flytsonen.
Jeg er ingen AI-motstander, og bruker AI til hobbyprosjekter også. For eksempel da jeg skulle lage native speedometer-apper til iOS og Android og en kjapp QR-kodegenerator uten reklame fordi jeg hadde bruk for det.
Men akkurat dette prosjektet ville jeg kode selv.
AI som læremester og oppslagsverk
Den observante leser som sjekker det åpne git-repoet til dette nettstedet vil oppdage både en CLAUDE.md-fil og diverse AI-agent-skills. Så har jeg jukset og brukt AI likevel?
Nei – men jeg ville kunne spørre Claude om rammeverket og CMS-et jeg bruker, eller få råd om SEO, caching og andre ting. Jeg kunne selvfølgelig slått det opp på dokumentasjonssider, men vi er da tross alt i 2026 og har folk… jeg mener agenter… til slikt!
Alle som har brukt Claude Code vet at du knapt kan spørre agenten om noe som helst, før den plutselig begynner å skrive kode for deg. Du må eksplisitt be den la være, eller be den lage en plan i stedet. Det var ikke slik jeg ville bruke Claude. Jeg ville bruke den som læremester og oppslagsverk.
Derfor ba jeg Claude om å opprette en CLAUDE.md-fil med strenge instrukser til seg selv: «This is a hand-coded project» og «Never change code unless explicitly asked to».
Med disse instruksene skiftet Claude plutselig personlighet. I stedet for å gjøre jobben for meg, begynte den å bestrebe seg på å lære bort alt den kunne.
Teknologivalg
Da jeg begynte som seniorkonsulent i Novacare gjorde jeg om de gamle Next.js-sidene mine til en enkel landingsside. De gamle artiklene ble liggende, fordi mange lenker fortsatt peker dit, men uten lenker fra forsiden.
Når jeg nå skulle kode nye nettsider fra bunnen av – for hånd – hadde jeg lyst til å benytte anledningen til å lære meg noe nytt. Derfor skrotet jeg raskt idéen om å bygge nok en Next.js-side. Men jeg ville beholde Sanity som headless CMS, fordi jeg liker Sanity (og har tatt Sanity-sertifiseringen), og at mye gammelt innhold allerede lå der.
Etter å ha vurdert flere alternativer, endte jeg til slutt opp på TanStack Start med React 19 som rammeverk. Jeg hadde hørt og lest mye bra om rammeverket, og det er lite «magi» under panseret. Jeg føler at jeg som utvikler har kontrollen og forstår hva som skjer.
Filbasert ruting med typesikkerhet hele veien er genialt. Selv rutenavnene sjekkes, så det er klin umulig å skrive navnet på en rute feil:
En annen grunn var at jeg kjente godt til TanStack Query fra kundeprosjektet jeg jobber på nå (et Vue-prosjekt). Med Vite og Nitro under panseret får jeg en lynrask dev-server og kan deploye nesten hvor som helst. Selve rammeverket låser meg altså ikke til Vercel, der sidene mine kjører i dag.
Men jeg har likevel gjort cachingen Vercel-spesifikk ved å bruke Vercels egen ISR-løsning, satt opp gjennom Nitro. Det gir meg oppdatering av enkeltsider nesten umiddelbart etter publisering (slipper å vente på bygging).
Tech-stacken kort oppsummert:
- TanStack Start (basert på TanStack Router)
- React 19, Vite og Nitro
- ISR (Incremental Static Regeneration) for de fleste rutene
- TanStack Query
- Sanity med webhook som oppdaterer de berørte sidene når noe publiseres
- Monorepo med pnpm og Turborepo
- Tailwind v4
Sidene rendres på serveren (SSR) første gang de besøkes, og så lagres HTML-en i Vercels edge-cache. Alle besøkende etter dette får den cachede versjonen, uten at det trenger å gå noen flere kall til Sanity.
Ettersom Vercel ikke kan vite når innholdet har endret seg, har jeg satt opp en webhook i Sanity som gjør en POST-request til et lite API-endepunkt jeg har laget på /api/revalidate. Den sjekker først en hemmelig nøkkel, slik at ikke hvem som helst kan regenere siden.
Så sender endepunktet et kall til URL-en(e) som skal oppdateres, med et spesielt token som Vercel kjenner igjen. Er tokenet ok så hopper Vercel over cachen, rendrer siden på nytt og lagrer den nye versjonen. Neste besøkende får da siste versjon av siden med rykende ferskt innhold fra Sanity.
Commodore 64-look
Commodore 64 var min første datamaskin, og grunnen til at jeg endte opp som teknologijournalist og senere utvikler. Derfor ville jeg at sidene skulle være en hyllest til nettopp denne maskinen.
Å sette opp TanStack Start og hekte det sammen med Sanity var ganske fort gjort. Det som har tatt tid, er alle detaljene. Alle som har brukt en C64, skulle kjenne igjen «looken» med en gang.
Rasterlinjer og C64-font
Jeg ville simulere rasterlinjene fra gamle CRT-skjermer og vignetteffekt, som om du satt og så på en gammel TV koblet til en C64. Dette ble løst med ren CSS:
.crt-overlay {
position: fixed;
inset: 0;
z-index: 999;
pointer-events: none;
mix-blend-mode: multiply;
background-image:
/* vignette */
radial-gradient(
ellipse at center,
transparent 55%,
rgba(0, 0, 0, 0.45) 100%
),
/* scanlines */
repeating-linear-gradient(
to bottom,
rgba(0, 0, 0, 0.30) 0px,
transparent 1.5px,
rgba(0, 0, 0, 0.20) 3px,
transparent 4px
);
}Som font til blant annet titler brukte jeg Google-fonten SixtyFour, og så brukte jeg IBM Plex Mono til brødtekst – bare for å gjøre teksten litt mer lettleselig, samtidig som jeg beholdt retro-looken.
Skrivemaskineffekt og blinkende cursor
Jeg ville ha mulighet til å legge til faktainformasjon om meg selv i Sanity. Så skulle dette dukke opp med en slags skrivemaskineffekt i Hero-seksjonen på forsiden, med en blinkende cursor – som på en Commodore 64-skjerm.
Selv om dette kanskje ser enkelt ut, var det faktisk noe av det jeg brukte lengst tid på å få til slik at jeg ble fornøyd. Jeg måtte bygge en state machine i en React-hook, og innså raskt at jeg hadde lent meg på Claude Code så lenge at jeg nesten helt hadde glemt hvordan jeg gjorde dette. Hvordan var syntaksen til Reacts useReducer igjen?
Hver faktaopplysning i Sanity har en etikett, en verdi og en “C64-kommando”, for eksempel LOAD eller PRINT. Velger jeg LOAD, blir etiketten til LOAD “ETIKETT”,8,1, og før verdien dukker opp på skjermen vises SEARCHING FOR og LOADING… OK. Omtrent som det gjorde når du lastet inn innholdet fra en diskett på 1541-diskettstasjonen.
Under panseret holder tilstandsmaskinen styr på hvilken linje som skrives ut, hvor mange tegn som skal være synlige og om linjen som skrives er i fasen typing, searching, loading eller revealed. Deretter går den til neste linje, osv. helt til alle linjene er skrevet ut. Her ble det ganske mye å holde styr på, for ventetid mellom ulike steg skal ta ulik tid avhengig av hva slags C64-kommando det er snakk om (PRINT går umiddelbart, LOAD tar tid). Og cursoren skal vises noen ganger, men for eksempel ikke under en loading-fase.
For å unngå layout shift tegnes teksten opp to ganger oppå hverandre: en usynlig, ferdig versjon som reserverer plassen, og den animerte versjonen over.
Jeg ville også ta hensyn til de som har prefers-reduced-motion. Har du på dette, så hopper hooken rett til slutten og cursoren slutter også å blinke. Skjermlesere får også servert den ferdige listen med fakta – og må ikke vente på animasjonen.
Rasterbars
«Rasterbars» som beveger seg opp og ned på skjermen er godt kjent for C64-entusiaster, og noe av det første du lærte å lage som demoprogrammerer. Så jeg ville ha det også.
På en C64 måtte du bytte farge på skjermen på nøyaktig riktig øyeblikk mens elektronstrålen tegnet opp bildet på skjermen, linje for linje. Med CSS er det temmelig mye enklere. Jeg brukte Tailwind:
Moderne under panseret
Selv om nettsidene skulle se ganske retro ut på overflaten, ville jeg at de skulle være moderne under panseret.
Jeg satte for eksempel opp view transitions mellom sider, for jevne og fine overganger mellom sidene. Dette er standard web-teknologi, og skrus enkelt på globalt i TanStack-ruteren (jeg tar også her hensyn til de som foretrekker “reduced motion”, og skrur på view transitions kun for alle andre).
Det som er litt gøy med view transitions, er at du kan gi elementer på nettsidene et `view-transition-name`, og hvis to elementer på to ulike sider har samme navn så vil nettleseren animere det ene over i det andre med en ganske fancy “morfe”-effekt. Det kan fort bli for mye av det gode, så jeg har prøvd å begrense animasjonene litt – men siden dette er en privat hobby-side har jeg tillatt meg å ha det litt gøy.
Før jeg deployet nettsiden live sjekket jeg selvfølgelig at SEO og tilgjengelighet var bra, og gjorde noen småjusteringer (blant annet kontraster på lenker). De ferdige nettsidene deployer til Vercel på 12 sekunder – og ytelsen er det ingenting å si på:
Var det verdt det?
Ja!
Jeg er ganske utålmodig og syntes enkelte ting tok overraskende lang tid å kode for hånd. Likevel koste jeg meg mens jeg holdt på. Flere ganger opplevde jeg at jeg plutselig hadde sittet og kodet hele kvelden uten å skjønne hvor alle timene hadde blitt av.
Jeg hadde faktisk kommet i flytsonen for første gang på lenge!
Jeg lærte også mye av å lage noe helt fra bunnen igjen, og det tar jeg med meg i jobben. Neste gang jeg vurderer et nytt rammeverk eller en ny teknologi, skal jeg først prøve å sette det opp manuelt, bare for å ha det grunnleggende i fingrene. Da forstår jeg teknologien bedre, og blir kanskje også en bedre sparringpartner for Claude Code når den store jobben skal gjøres.