[{"data":1,"prerenderedAt":254},["ShallowReactive",2],{"home":3,"project-\u002Fprojects\u002Fcolonizing-pirkanmaa":50,"projects":93},{"id":4,"title":5,"about":6,"contact":8,"description":21,"extension":22,"hero":23,"marquee":29,"meta":44,"stem":45,"work":46,"__hash__":49},"home\u002Fhome.yml","Portfolio",{"eyebrow":7},"About",{"eyebrow":9,"heading":10,"email":11,"name":12,"links":13,"backToTop":20},"Contact","Let's build something that works.","contact@kaartovuori.fi","Tino Kaartovuori",[14,17],{"label":15,"to":16},"GitHub","https:\u002F\u002Fgithub.com\u002Ftinokaartovuori",{"label":18,"to":19},"LinkedIn","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Ftinokaartovuori\u002F","Back to top","Tino Kaartovuori is a software engineer in Salo, Finland, who designs and builds web apps, AI automation, software and hardware for clients in Turku, Helsinki and across southern Finland.","yml",{"lead":24,"accent":25,"cta":26},"An engineer who builds software, and everything around it.","Web, AI, hardware, and an eye for design.",{"label":27,"to":28},"See the work","#work",[30,31,32,33,34,35,36,37,38,39,40,41,42,43],"Claude Code","Three.js","WebGL","MCP","Nuxt","Next.js","Phaser","AlphaZero","Electron","STM32","Fusion 360","3D printing","Home Assistant","DaVinci Resolve",{},"home",{"eyebrow":47,"heading":48},"Selected work","Things I have designed and built, on screens and off them.","aAqqFlk52cGrUQ9yA5dUkGUtpZgMFtix2x2n2mJdNq0",{"id":51,"title":52,"body":53,"card":67,"date":68,"description":59,"duration":68,"extension":69,"gallery":68,"galleryColumns":68,"galleryTitle":68,"image":70,"imageAlt":71,"imagePosition":68,"links":72,"meta":82,"navigation":78,"operatingSystem":83,"order":84,"path":85,"rating":68,"role":86,"schemaType":87,"seo":88,"stem":89,"summary":90,"website":68,"year":91,"__hash__":92},"projects\u002Fprojects\u002F4.colonizing-pirkanmaa.md","Colonizing Pirkanmaa",{"type":54,"value":55,"toc":63},"minimark",[56,60],[57,58,59],"p",{},"Colonizing Pirkanmaa began as a C++ and Qt game for a university programming\ncourse: two to four players claim tiles of a generated map, build farms, mines\nand villages, pay their workers and soldiers every turn, and try to end up the\nsole ruler of the region. Version 2.0 is a one-to-one port to TypeScript and\nPhaser that runs in any browser with nothing to install. Every cost, wage and\ngrowth timer matches the original, and the map generator reproduces the old\nWindows build's random numbers bit for bit, so a seed still draws the same map\nit drew in 2020. The pixel art is the original's too: I drew every tile,\nbuilding and worker by hand, and animated them frame by frame.",[57,61,62],{},"The new part is who you play against. The game logic has no dependency on the\nrendering, so it runs headless: a Rust simulator plays it millions of times,\nand an AlphaZero-style training loop turns those games into two neural\nopponents, with a heuristic bot as the third. The nets run in a web worker\nso the interface never freezes while an opponent thinks. Simulated games also\nshowed that the original rules stalemated too often, which is where the\nStrange Device came from: a late-game building that starts a countdown and\nwins for whoever keeps it standing. Saves live in the browser, and finished\ngames can be replayed. The whole port took six days with Claude Code.",{"title":64,"searchDepth":65,"depth":65,"links":66},"",2,[],"\u002Fimages\u002Fcolonizing-pirkanmaa-card.jpg",null,"md","\u002Fimages\u002Fcolonizing-pirkanmaa.jpg","A pixel-art map of forests, rivers and farms with workers and buildings, and a dark side panel of resources and unit counts",[73,79],{"label":74,"short":75,"to":76,"icon":77,"card":78},"Play in the browser","Play","https:\u002F\u002Ftinokaartovuori.github.io\u002Fcolonizing-pirkanmaa-2.0\u002F","game",true,{"label":80,"to":81},"Source on GitHub","https:\u002F\u002Fgithub.com\u002Ftinokaartovuori\u002Fcolonizing-pirkanmaa-2.0",{},"Web browser",4,"\u002Fprojects\u002Fcolonizing-pirkanmaa","Pixel art, port and AI opponents","VideoGame",{"title":52,"description":59},"projects\u002F4.colonizing-pirkanmaa","A turn-based strategy game from university, ported to the browser with three computer opponents, one of them trained with AlphaZero.","2026","YASJsjolcw7PBbJC1zJ-UE8zrpsslxImxCeMh77NEjI",[94,134,190,240],{"id":95,"title":96,"body":97,"card":68,"date":68,"description":101,"duration":68,"extension":69,"gallery":68,"galleryColumns":68,"galleryTitle":68,"image":110,"imageAlt":111,"imagePosition":68,"links":112,"meta":119,"navigation":78,"operatingSystem":120,"order":121,"path":122,"rating":123,"role":126,"schemaType":127,"seo":128,"stem":129,"summary":130,"website":131,"year":132,"__hash__":133},"projects\u002Fprojects\u002F1.aurora-compass.md","Aurora Compass",{"type":54,"value":98,"toc":108},[99,102,105],[57,100,101],{},"Aurora Compass answers one question: should I go outside tonight? It gives the\ncurrent and forecast probability of seeing auroras at your own location,\nweighed against the cloud forecast, and sends an alert when the two line up.\nBehind the short answer sits the full data: near real-time geomagnetic activity\nfrom over a hundred magnetometers, an aurora map with shared observations, a\nsolar image player with x-ray charts and active regions, the WSA-Enlil solar\nwind forecast, Kp forecasts, and moon and darkness tools.",[57,103,104],{},"My part was the look and the direction. The brand and the logo, the screens\nand the way the data is drawn, and the calls about what belongs on the\noverview and what is a tab away. The aim is a clean, clear app that serves a\nfirst night out as well as a chaser who wants every chart. Colour carries the\ndata, from green through red, and there are several palettes to choose from,\none of them for red-green colour blindness.",[57,106,107],{},"The best thing about it is that it is free: no ads, no paywall, nothing held\nback. The map is shared, so anyone can post what they are seeing, with a\nphotograph, and see what others have caught tonight.",{"title":64,"searchDepth":65,"depth":65,"links":109},[],"\u002Fimages\u002Faurora-compass.jpg","The Aurora Compass logo beside three phone screens showing the overview, the aurora map and the sun",[113,116],{"label":114,"to":115},"App Store","https:\u002F\u002Fapps.apple.com\u002Fapp\u002Faurora-compass\u002Fid6446504259",{"label":117,"to":118},"Google Play","https:\u002F\u002Fplay.google.com\u002Fstore\u002Fapps\u002Fdetails?id=com.auroracompass",{},"iOS, Android",1,"\u002Fprojects\u002Faurora-compass",{"value":124,"source":125},"4.9",[114,117],"Brand, visual design and product direction","SoftwareApplication",{"title":96,"description":101},"projects\u002F1.aurora-compass","A free aurora and space weather app for iOS and Android, simple for beginners and detailed enough for chasers.","https:\u002F\u002Fauroracompass.com\u002F","2023","yNfVHS3xXEVugg_UEA7yMiM80Dd9oqCezgj-JZADQzE",{"id":135,"title":136,"body":137,"card":68,"date":68,"description":141,"duration":68,"extension":69,"gallery":153,"galleryColumns":68,"galleryTitle":178,"image":179,"imageAlt":180,"imagePosition":68,"links":68,"meta":181,"navigation":78,"operatingSystem":68,"order":65,"path":182,"rating":68,"role":183,"schemaType":184,"seo":185,"stem":186,"summary":187,"website":68,"year":188,"__hash__":189},"projects\u002Fprojects\u002F2.pinhole-camera.md","A 3D-printed film camera",{"type":54,"value":138,"toc":151},[139,142,145,148],[57,140,141],{},"There are no electronics in it. Film advance, the shutter and the release\nare all mechanical, and almost every part came off a printer. The only\nparts I did not design are the bolts, the steel spring, the cable release and\nthe metal tripod thread.",[57,143,144],{},"The optics mount on a bayonet at the front. I made two pinholes for it, a\n40 mm f\u002F150 and a 52 mm f\u002F192, and a Sony E-mount adapter lets it take a real\nlens, so the same body shoots soft pinhole frames one day and a sharp 35 mm the\nnext. The pinholes were the hard part of the maths: the hole, the focal\nlength, the f-stop and the frame all depend on each other, and getting every\none of them to land in the right place inside the body took a good deal of\nworking out.",[57,146,147],{},"The grip comes off. Swapping it changes how the camera fires: one grip has a\nplain button, another takes a cable release, and a new one can be printed for\nwhatever else is wanted. Underneath there is a metal tripod thread, so the\nlong pinhole exposures can be shot from a tripod.",[57,149,150],{},"The biggest challenge was none of that, though. It was the film: getting it\nto move through the body smoothly and by exactly one frame at a time, with\nprinted parts alone. That is where most of the dozens of\nversions and the dozens of smaller prototypes went, each printed to prove one\nmechanism before it went into the body. Three full cameras came out of that;\nthe third is the MkIII in the pictures, and the photographs at the end came\nout of it.",{"title":64,"searchDepth":65,"depth":65,"links":152},[],[154,157,160,163,166,169,172,175],{"image":155,"imageAlt":156},"\u002Fimages\u002Fcamera-wireframe.jpg","A wireframe view of the camera body in Fusion 360, showing the film chambers, the mount and the dials",{"image":158,"imageAlt":159},"\u002Fimages\u002Fcamera-emount.jpg","The camera held in one hand with a Samyang lens on its Sony E-mount adapter",{"image":161,"imageAlt":162,"wide":78},"\u002Fimages\u002Fcamera-render.jpg","A rendering of the camera design from above, black with a red ring around the lens mount and the red shutter button standing up from the grip",{"image":164,"imageAlt":165},"\u002Fimages\u002Fpinhole-01.jpg","A pine leaning over a snowy shore at dusk, soft and pink, on film",{"image":167,"imageAlt":168},"\u002Fimages\u002Fpinhole-03.jpg","An acoustic guitar standing on a patterned blue rug, on film",{"image":170,"imageAlt":171,"wide":78},"\u002Fimages\u002Fpinhole-02.jpg","Apartment blocks in low evening sun, on film",{"image":173,"imageAlt":174},"\u002Fimages\u002Fpinhole-04.jpg","Apartment blocks around a snow-dusted courtyard at night, lit by a few street lamps, on film",{"image":176,"imageAlt":177},"\u002Fimages\u002Fpinhole-05.jpg","An Ultimaker 2+ printer glowing on a desk beside a speaker, on film","From the CAD file to the film","\u002Fimages\u002Fpinhole-camera.jpg","The black 3D-printed camera on a wooden table with a cable release attached and a second lens unit beside it",{},"\u002Fprojects\u002Fpinhole-camera","Design, engineering and print","CreativeWork",{"title":136,"description":141},"projects\u002F2.pinhole-camera","The K5 Arta MkIII, a fully mechanical 35mm film camera with swappable optics, designed in Fusion 360 and printed at home.","2022","K4F0pCwJ3KGiwj3_Hj0ZgBzxWOMkuX7fmewUHJmCNf4",{"id":191,"title":192,"body":193,"card":68,"date":68,"description":197,"duration":203,"extension":69,"gallery":204,"galleryColumns":220,"galleryTitle":221,"image":222,"imageAlt":223,"imagePosition":68,"links":224,"meta":231,"navigation":78,"operatingSystem":68,"order":220,"path":232,"rating":68,"role":233,"schemaType":234,"seo":235,"stem":236,"summary":237,"website":68,"year":238,"__hash__":239},"projects\u002Fprojects\u002F3.philippines.md","The Philippines, a travel film",{"type":54,"value":194,"toc":201},[195,198],[57,196,197],{},"A travel vlog of the classic kind: a group of friends, a run of islands, and\na camera along for the diving, the snorkelling and the days between. Shooting\nwas the easy part. Back home the trip was 800 GB of clips that had all felt\nimportant on the day, and turning them into a two-hour film in DaVinci\nResolve took several months of evenings: cut for the story of the trip rather\nthan the itinerary, and graded so the islands look the way they felt.",[57,199,200],{},"The film is in Finnish. There are not many photographs from the trip, the\ncamera was rolling; the stills below are from the film.",{"title":64,"searchDepth":65,"depth":65,"links":202},[],"PT2H",[205,208,211,214,217],{"image":206,"imageAlt":207},"\u002Fimages\u002Fphilippines-01.jpg","Islands and reefs seen past the propeller through the window of a small plane",{"image":209,"imageAlt":210},"\u002Fimages\u002Fphilippines-02.jpg","A row of turquoise sun loungers beside an infinity pool, the sea beyond, one swimmer in a straw hat at the edge",{"image":212,"imageAlt":213},"\u002Fimages\u002Fphilippines-03.jpg","A coral reef with a yellow butterflyfish, orange soft coral and a cloud of small fish",{"image":215,"imageAlt":216},"\u002Fimages\u002Fphilippines-04.jpg","Inside a shipwreck, light falling through the gaps between its coral-covered ribs",{"image":218,"imageAlt":219,"wide":78},"\u002Fimages\u002Fphilippines-05.jpg","Three snorkellers in the middle of a swirling ball of sardines, seen from below",3,"Stills from the film","\u002Fimages\u002Fphilippines.jpg","Two outrigger boats in the shallows at sunset, fishermen in hats aboard",[225],{"label":226,"short":227,"to":228,"icon":229,"lang":230,"card":78},"Watch on YouTube","Watch","https:\u002F\u002Fyoutu.be\u002Fmp-44MlWYC8","youtube","fi",{},"\u002Fprojects\u002Fphilippines","Camera, edit and grade","VideoObject",{"title":192,"description":197},"projects\u002F3.philippines","A two-hour travel film of a trip through the Philippines with friends, the diving and the snorkelling above all, cut at home from 800 GB of footage.","2025","Dt0S4wbChb3iW8MUlWkvqpyhv-C9LzpLodEUotu3zY0",{"id":51,"title":52,"body":241,"card":67,"date":68,"description":59,"duration":68,"extension":69,"gallery":68,"galleryColumns":68,"galleryTitle":68,"image":70,"imageAlt":71,"imagePosition":68,"links":249,"meta":252,"navigation":78,"operatingSystem":83,"order":84,"path":85,"rating":68,"role":86,"schemaType":87,"seo":253,"stem":89,"summary":90,"website":68,"year":91,"__hash__":92},{"type":54,"value":242,"toc":247},[243,245],[57,244,59],{},[57,246,62],{},{"title":64,"searchDepth":65,"depth":65,"links":248},[],[250,251],{"label":74,"short":75,"to":76,"icon":77,"card":78},{"label":80,"to":81},{},{"title":52,"description":59},1788713329544]