{
  "authors": [
    {
      "name": "Kolja Wawrowsky",
      "url": "https://kolja.wawrowsky.com/"
    }
  ],
  "description": "Independent AI researcher, imaging scientist, and Apple-platform developer. Building instruments that make complex systems easier to see, measure, and remember.",
  "favicon": "https://kolja.wawrowsky.com/favicon.svg",
  "feed_url": "https://kolja.wawrowsky.com/feed.json",
  "home_page_url": "https://kolja.wawrowsky.com/",
  "icon": "https://kolja.wawrowsky.com/og-default.png",
  "items": [
    {
      "authors": [
        {
          "name": "Kolja Wawrowsky",
          "url": "https://kolja.wawrowsky.com/"
        }
      ],
      "content_html": "\u003cp\u003eI am sketching the architecture for a volumetric viewer for my Vision Pro, a way to load a confocal microscopy dataset and walk around inside it. Nested isosurfaces and MIP shadows from techniques I worked out during my PhD in 2007, finally rendered in the space they were always meant to be. It should be a natural fit. Vision Pro\u0026rsquo;s entire premise is showing you something complex, in three dimensions, in real time. A living specimen, a moving structure, a dataset you rotate and explore as if it were sitting right in front of you.\u003c/p\u003e\n\u003cp\u003eBut getting there means going through SwiftUI. Not as a preference, but a mandate, because visionOS insists you use it.\u003c/p\u003e\n\u003cp\u003eSwiftUI is a genuinely great tool, just not for this category of tool.\u003c/p\u003e\n\u003ch3 id=\"the-wrapper-app-and-what-it-was-built-for\"\u003eThe wrapper app, and what it was built for\u003c/h3\u003e\n\u003cp\u003eWrap a web service. A REST API. A form. A list that updates when the server says something changed. For that category, SwiftUI\u0026rsquo;s whole design, a view graph that re-evaluates each view as a pure function of state, is a good match. A state changes, the view redraws, done. Time is not a dimension that needs to be considered. There is no clock in the model because the model never needed one: the server tells you something happened, and you draw the result.\u003c/p\u003e\n\u003cp\u003eThat\u0026rsquo;s also its major deficit, and it\u0026rsquo;s not unique to SwiftUI. React, Elm, Jetpack Compose — the entire lineage of graph-based UI frameworks — share it. No native concept of time, only state and the diff between two snapshots of it. When animation is needed, every one of them has had to bolt something on afterward: \u003ccode\u003erequestAnimationFrame\u003c/code\u003e in the browser, \u003ccode\u003eTime.every\u003c/code\u003e in Elm.\u003c/p\u003e\n\u003cp\u003eI want to be precise about what that means for SwiftUI specifically, because it would be easy to overstate. SwiftUI\u0026rsquo;s \u003ccode\u003eTimelineView\u003c/code\u003e didn\u0026rsquo;t exist until 2021, two years after SwiftUI shipped, and it exists precisely because a view needed a first-class relationship to an external clock that the state-diffing model didn\u0026rsquo;t give it for free. \u003ccode\u003ePhaseAnimator\u003c/code\u003e and \u003ccode\u003eKeyframeTimeline\u003c/code\u003e followed at WWDC23, giving explicit, per-property, multi-track timed sequencing. And springs, when interrupted mid-animation, genuinely do preserve their velocity rather than snapping — Apple says so directly in its own WWDC23 session on the subject: \u0026ldquo;a spring animation uses the velocity it had when it was retargeted as the initial velocity towards its new destination\u0026hellip; this same velocity preservation makes these kind of interruptions feel smooth and natural.\u0026rdquo;\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e That\u0026rsquo;s real engineering, not a patch job.\u003c/p\u003e\n\u003cp\u003eBut notice the shape of all three additions. Each one is a special case bolted onto the graph from outside, not something the graph model produces natively. \u003ccode\u003eTimelineView\u003c/code\u003e works by subscribing a view to an external schedule and letting it re-render on that cadence — which is another way of saying: the graph still can\u0026rsquo;t represent time as a first-class dimension, so we gave certain views a side channel to a clock. Four separate escape hatches, arriving years apart, for one thing the underlying model doesn\u0026rsquo;t have: continuous, native, unbolted time.\u003c/p\u003e\n\u003ch3 id=\"where-the-escape-hatch-used-to-be\"\u003eWhere the escape hatch used to be\u003c/h3\u003e\n\u003cp\u003eOn iOS and the Mac, that gap was survivable, mildly annoying at worst. If your problem genuinely needed frame-accurate control, you could drop straight into UIKit or AppKit and own your render loop directly with Core Animation or Metal. \u003ccode\u003eCADisplayLink\u003c/code\u003e, a \u003ccode\u003eCVDisplayLink\u003c/code\u003e callback, a Metal command buffer submitted on your own schedule — nothing forced you back into the diffing model. That escape hatch was always available, and it\u0026rsquo;s why the gap stayed academic for most developers for most of the platform\u0026rsquo;s life.\u003c/p\u003e\n\u003cp\u003eThere is a mainstream framework that never had the gap in the first place, and it\u0026rsquo;s instructive precisely because of where it came from. LabVIEW\u0026rsquo;s dataflow graph treats time as a structural property of the graph itself, not a workaround. A Timed Loop node in LabVIEW carries period, deadline, and execution priority as configurable properties of the node — you can even assign it to a specific processor.\u003csup id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e2\u003c/a\u003e\u003c/sup\u003e That isn\u0026rsquo;t incidental. LabVIEW comes from instrumentation, from driving cameras and DAQ hardware, where \u0026ldquo;eventually consistent\u0026rdquo; timing isn\u0026rsquo;t a UI quirk, it\u0026rsquo;s a broken experiment. A camera trigger that fires whenever the diffing algorithm gets around to it has failed at its one job. So the graph was built from day one to carry deterministic timing as data, because the domain never allowed treating it as optional.\u003c/p\u003e\n\u003cp\u003eThere\u0026rsquo;s also a version of the \u0026ldquo;correct\u0026rdquo; fix that stayed almost entirely in research languages. Conal Elliott\u0026rsquo;s original 1997 formulation of functional reactive programming defines a \u003ccode\u003eBehavior\u003c/code\u003e as, literally, \u003ccode\u003eTime -\u0026gt; a\u003c/code\u003e — a value\u0026rsquo;s type \u003cem\u003eis\u003c/em\u003e a function of time.\u003csup id=\"fnref:3\"\u003e\u003ca href=\"#fn:3\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e3\u003c/a\u003e\u003c/sup\u003e Time isn\u0026rsquo;t a trigger that causes re-evaluation; it\u0026rsquo;s the actual domain the value lives over. It\u0026rsquo;s the cleanest possible answer to the exact problem SwiftUI\u0026rsquo;s four bolt-ons are each solving a slice of, and it never made the jump into a mainstream production UI framework.\u003c/p\u003e\n\u003ch3 id=\"where-the-escape-hatch-closes\"\u003eWhere the escape hatch closes\u003c/h3\u003e\n\u003cp\u003eOn visionOS, Apple moved it out of reach. UIKit still runs, but Apple\u0026rsquo;s own migration documentation states the limit plainly: \u0026ldquo;Although you can still use UIKit and load iOS storyboards into your app, you can\u0026rsquo;t include visionOS-specific or 3D content without using SwiftUI.\u0026rdquo;\u003csup id=\"fnref:4\"\u003e\u003ca href=\"#fn:4\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e4\u003c/a\u003e\u003c/sup\u003e Not preferred. Structural. You can keep a flat 2D window in UIKit. The moment you want a Volume, an Ornament, an ImmersiveSpace, or any 3D content at all, SwiftUI stops being a choice.\u003c/p\u003e\n\u003cp\u003eThat constraint reaches further than it looks. Even content that has nothing to do with SwiftUI\u0026rsquo;s declarative philosophy still has to live inside it to exist on the device. RealityKit content is composed through \u003ccode\u003eRealityView\u003c/code\u003e, and \u003ccode\u003eRealityView\u003c/code\u003e is a SwiftUI view like any other:\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;\"\u003e\u003ccode class=\"language-swift\" data-lang=\"swift\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003estruct\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003eShapesView\u003c/span\u003e: View {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    \u003cspan style=\"color:#66d9ef\"\u003evar\u003c/span\u003e body: some View {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        RealityView { content \u003cspan style=\"color:#66d9ef\"\u003ein\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e            addGeometryShapes(to: content)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e        }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    }\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003eThere is exactly one door that doesn\u0026rsquo;t run through a SwiftUI view graph: Metal, through Compositor Services. Its terms are the clearest statement of the problem. A \u003ccode\u003eCompositorLayer\u003c/code\u003e can only be the content of an \u003ccode\u003eImmersiveSpace\u003c/code\u003e, and \u0026ldquo;the system automatically configures a space with CompositorLayer content as fully immersive.\u0026rdquo;\u003csup id=\"fnref:5\"\u003e\u003ca href=\"#fn:5\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e5\u003c/a\u003e\u003c/sup\u003e No window, no volume, no sitting next to the user\u0026rsquo;s other apps in the Shared Space. Your app takes over the headset or it doesn\u0026rsquo;t run. Inside that space, \u0026ldquo;you draw everything the person sees\u0026rdquo;\u003csup id=\"fnref1:5\"\u003e\u003ca href=\"#fn:5\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e5\u003c/a\u003e\u003c/sup\u003e: no RealityKit entities, no SwiftUI views, none of what the system would otherwise give you. Even highlighting the object the user is looking at had to be rebuilt. RealityKit\u0026rsquo;s hover effects are \u0026ldquo;not an option\u0026rdquo; for Full Space Metal apps, and Apple\u0026rsquo;s replacement only arrived in visionOS 26.\u003csup id=\"fnref:6\"\u003e\u003ca href=\"#fn:6\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e6\u003c/a\u003e\u003c/sup\u003e And the space itself is still declared in a SwiftUI \u003ccode\u003eScene\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eSo the escape hatch isn\u0026rsquo;t gone. It has been moved to the far end of the building. You can own your render loop on visionOS, but only by writing what amounts to a full-screen game engine, and giving up the Shared Space, volumes, and RealityKit, most of what makes the platform more than a headset. For everything else, SwiftUI is the mandatory checkpoint every spatial workflow passes through.\u003c/p\u003e\n\u003ch3 id=\"someone-still-has-to-own-the-clock\"\u003eSomeone still has to own the clock\u003c/h3\u003e\n\u003cp\u003eHere is the part I think matters most, and it isn\u0026rsquo;t really about SwiftUI\u0026rsquo;s syntax at all. Somebody has to own time. If the framework at the front door won\u0026rsquo;t, the system takes the job away from the app entirely.\u003c/p\u003e\n\u003cp\u003eThat\u0026rsquo;s exactly what visionOS\u0026rsquo;s compositor does. Every app on the platform, RealityKit, SwiftUI, even raw Metal via Compositor Services, doesn\u0026rsquo;t render to the device\u0026rsquo;s actual current state. It renders to a \u003cem\u003epredicted\u003c/em\u003e future head pose, which the compositor then reprojects at display time.\u003csup id=\"fnref:7\"\u003e\u003ca href=\"#fn:7\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e7\u003c/a\u003e\u003c/sup\u003e In the Shared Space, content that takes too long misses the render server\u0026rsquo;s deadline and shows up a frame late. In a Full Space Metal app, the one place you do own the loop, Apple\u0026rsquo;s documentation is blunt: \u0026ldquo;If your app takes too long to submit a new frame to the compositor, the system terminates it.\u0026rdquo;\u003csup id=\"fnref:8\"\u003e\u003ca href=\"#fn:8\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e8\u003c/a\u003e\u003c/sup\u003e Get the timing wrong there and you don\u0026rsquo;t get a dropped frame. You get killed.\u003c/p\u003e\n\u003cp\u003eRealityKit\u0026rsquo;s own object model carries a version of the same disease one level down. Its default APIs are mostly bound to the main actor — fine for a scene built from discrete state changes, a bad fit for anything that needs to stream continuously.\u003c/p\u003e\n\u003cp\u003eThat\u0026rsquo;s the wall my own volumetric viewer runs into directly. A confocal time series isn\u0026rsquo;t a state that changes occasionally and gets diffed. It\u0026rsquo;s a continuous stream that needs to arrive on a schedule and be drawn on a schedule, the same discipline a Timed Loop node in LabVIEW was built around from the start, and the same thing SwiftUI\u0026rsquo;s view graph was never asked to hold.\u003c/p\u003e\n\u003ch3 id=\"the-tell\"\u003eThe tell\u003c/h3\u003e\n\u003cp\u003eHere\u0026rsquo;s what convinced me this isn\u0026rsquo;t just a grudge against one framework. Over the past year Apple has shipped three ways to do the real work somewhere else and pipe the result in. macOS 26 added \u003ccode\u003eRemoteImmersiveSpace\u003c/code\u003e, so a Mac app can render Metal content for a Vision Pro. visionOS 26.4 added the Foveated Streaming framework, which streams from PCs, workstations, and cloud servers. And visionOS 27\u0026rsquo;s Spatial Preview framework lets a Mac app push live-edited 3D content straight into Quick Look on the headset.\u003csup id=\"fnref:9\"\u003e\u003ca href=\"#fn:9\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e9\u003c/a\u003e\u003c/sup\u003e Apple built ways to do the demanding work on machines that already know how to own time. Those aren\u0026rsquo;t developer convenience features. They\u0026rsquo;re the platform\u0026rsquo;s own maker quietly admitting the on-device path isn\u0026rsquo;t where you want to be doing that work.\u003c/p\u003e\n\u003cp\u003eIt also isn\u0026rsquo;t the first time a professional tool has routed around exactly this model, just the first time on Apple\u0026rsquo;s own hardware. Figma\u0026rsquo;s entire rendering engine is a custom system written in C++, built specifically because the standard web rendering stack, the DOM, SVG, even the 2D canvas API, couldn\u0026rsquo;t deliver the consistent 60fps performance a professional design tool needs. Figma\u0026rsquo;s own engineers describe implementing \u0026ldquo;everything from scratch using WebGL\u0026rdquo; rather than live inside a browser\u0026rsquo;s declarative rendering model.\u003csup id=\"fnref:10\"\u003e\u003ca href=\"#fn:10\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e10\u003c/a\u003e\u003c/sup\u003e A view-graph-and-diff architecture is a fine choice for a page that mostly waits for a server. It has never been the choice of anyone building an instrument that has to be right, and on time, every frame.\u003c/p\u003e\n\u003ch3 id=\"the-second-wall\"\u003eThe second wall\u003c/h3\u003e\n\u003cp\u003eAnd underneath all of this sits a wall that predates Vision Pro entirely. Apple deprecated OpenGL across its platforms in 2018, in favor of Metal, and never adopted Vulkan. The enormous existing world of professional visualization software, the C++, OpenGL and Vulkan tools that already drive CAD kernels, medical imaging pipelines, and scientific rendering, was locked out of Apple silicon the day that happened. None of it runs here without a full rewrite.\u003c/p\u003e\n\u003cp\u003eVision Pro didn\u0026rsquo;t just inherit that wall. It built a second one behind it, out of the one framework in Apple\u0026rsquo;s own stack that was never designed to model time and motion in the first place, and made passing through it mandatory for anyone who wants to show a person something happening in three dimensions, in real time, on the one device built for exactly that.\u003c/p\u003e\n\u003cp\u003eI still think the volumetric viewer is worth building. I\u0026rsquo;ll build it on Metal and Compositor Services rather than RealityKit, and accept the price: a Full Space app that takes over the headset, draws every pixel itself, and rebuilds interaction from raw spatial events. At least that path doesn\u0026rsquo;t add a second, unnecessary checkpoint on top of a compositor I already have to negotiate with. But I notice that this is the same lesson I learned building instruments for confocal microscopes: you don\u0026rsquo;t get to choose the discipline the specimen imposes on the tool. Time either belongs to the instrument, or the instrument belongs to whoever is holding the clock instead.\u003c/p\u003e\n\u003chr\u003e\n\u003chr\u003e\n\u003cp\u003e\u003cem\u003eWritten by \u003ca href=\"https://claude.ai\"\u003eClaude\u003c/a\u003e in dialogue with Kolja Wawrowsky, developed from a shorter piece first written for LinkedIn.\u003c/em\u003e\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eApple, \u0026ldquo;Animate with springs,\u0026rdquo; WWDC23. \u003ca href=\"https://developer.apple.com/videos/play/wwdc2023/10158/\"\u003edeveloper.apple.com/videos/play/wwdc2023/10158\u003c/a\u003e\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003eNational Instruments, \u0026ldquo;Timed Loop structure,\u0026rdquo; LabVIEW documentation. \u003ca href=\"https://www.ni.com/docs/en-US/bundle/labview/page/configuring-settings-of-a-timed-structure-real-time-windows.html\"\u003eni.com\u003c/a\u003e\u0026#160;\u003ca href=\"#fnref:2\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:3\"\u003e\n\u003cp\u003eElliott, C. and Hudak, P. (1997), \u003cem\u003eFunctional Reactive Animation\u003c/em\u003e, ICFP \u0026lsquo;97. The \u003ccode\u003eBehavior a = Time -\u0026gt; a\u003c/code\u003e formulation is described in Elliott\u0026rsquo;s own retrospective writing and the Haskell Wiki\u0026rsquo;s history of FRP. \u003ca href=\"https://wiki.haskell.org/Functional_Reactive_Programming\"\u003ewiki.haskell.org/Functional_Reactive_Programming\u003c/a\u003e\u0026#160;\u003ca href=\"#fnref:3\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:4\"\u003e\n\u003cp\u003eApple, \u0026ldquo;Bringing your app to visionOS,\u0026rdquo; Apple Developer Documentation. \u003ca href=\"https://developer.apple.com/documentation/visionos/bringing-your-app-to-visionos\"\u003edeveloper.apple.com/documentation/visionos/bringing-your-app-to-visionos\u003c/a\u003e\u0026#160;\u003ca href=\"#fnref:4\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:5\"\u003e\n\u003cp\u003eApple, \u0026ldquo;Drawing fully immersive content using Metal,\u0026rdquo; Compositor Services documentation. \u003ca href=\"https://developer.apple.com/documentation/compositorservices/drawing-fully-immersive-content-using-metal\"\u003edeveloper.apple.com/documentation/compositorservices/drawing-fully-immersive-content-using-metal\u003c/a\u003e\u0026#160;\u003ca href=\"#fnref:5\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u0026#160;\u003ca href=\"#fnref1:5\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:6\"\u003e\n\u003cp\u003eApple, \u0026ldquo;Rendering hover effects in Metal immersive apps,\u0026rdquo; Compositor Services documentation (visionOS 26). \u003ca href=\"https://developer.apple.com/documentation/compositorservices/rendering_hover_effects_in_metal_immersive_apps\"\u003edeveloper.apple.com/documentation/compositorservices/rendering_hover_effects_in_metal_immersive_apps\u003c/a\u003e\u0026#160;\u003ca href=\"#fnref:6\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:7\"\u003e\n\u003cp\u003eApple, \u0026ldquo;Discover Metal for immersive apps,\u0026rdquo; WWDC23, and \u0026ldquo;Render Metal with passthrough in visionOS,\u0026rdquo; WWDC24 — both describe rendering against a predicted device pose that Compositor Services reprojects at presentation time.\u0026#160;\u003ca href=\"#fnref:7\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:8\"\u003e\n\u003cp\u003eApple, \u0026ldquo;Understanding the visionOS render pipeline,\u0026rdquo; Apple Developer Documentation. \u003ca href=\"https://developer.apple.com/documentation/visionos/understanding-the-visionos-render-pipeline\"\u003edeveloper.apple.com/documentation/visionos/understanding-the-visionos-render-pipeline\u003c/a\u003e\u0026#160;\u003ca href=\"#fnref:8\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:9\"\u003e\n\u003cp\u003eApple Developer Documentation: \u003ccode\u003eRemoteImmersiveSpace\u003c/code\u003e (macOS 26) \u003ca href=\"https://developer.apple.com/documentation/swiftui/remoteimmersivespace\"\u003edeveloper.apple.com/documentation/swiftui/remoteimmersivespace\u003c/a\u003e; Foveated Streaming (visionOS 26.4) \u003ca href=\"https://developer.apple.com/documentation/foveatedstreaming\"\u003edeveloper.apple.com/documentation/foveatedstreaming\u003c/a\u003e; Spatial Preview (visionOS 27) \u003ca href=\"https://developer.apple.com/documentation/spatialpreview\"\u003edeveloper.apple.com/documentation/spatialpreview\u003c/a\u003e. Overview: Apple, \u0026ldquo;What\u0026rsquo;s New,\u0026rdquo; visionOS developer page. \u003ca href=\"https://developer.apple.com/visionos/whats-new/\"\u003edeveloper.apple.com/visionos/whats-new\u003c/a\u003e\u0026#160;\u003ca href=\"#fnref:9\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:10\"\u003e\n\u003cp\u003eFigma Engineering, \u0026ldquo;Building a professional design tool on the web,\u0026rdquo; Figma Blog. \u003ca href=\"https://www.figma.com/blog/building-a-professional-design-tool-on-the-web/\"\u003efigma.com/blog/building-a-professional-design-tool-on-the-web\u003c/a\u003e\u0026#160;\u003ca href=\"#fnref:10\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n",
      "date_modified": "2026-09-28T00:00:00Z",
      "date_published": "2026-09-28T00:00:00Z",
      "id": "https://kolja.wawrowsky.com/posts/is-swiftui-killing-apples-vision-pro/",
      "summary": "SwiftUI is a great tool for wrapper apps. It is also the only door onto Vision Pro's 3D content, and it was never built to know what time it is. What that costs anyone trying to render scientific data — a confocal dataset, a live sensor feed, a CAD model — on the one Apple device built to show things happening in real time.",
      "tags": [
        "Field Notes"
      ],
      "title": "Is SwiftUI Killing Apple's Vision Pro?",
      "url": "https://kolja.wawrowsky.com/posts/is-swiftui-killing-apples-vision-pro/"
    },
    {
      "authors": [
        {
          "name": "Kolja Wawrowsky",
          "url": "https://kolja.wawrowsky.com/"
        }
      ],
      "content_html": "\u003cp\u003e\u003cimg src=\"og.jpg\" alt=\"A man and a small robot at a desk, working through a notebook of diagrams together\"\u003e\u003c/p\u003e\n\u003cp\u003eYou\u0026rsquo;re working with AI, but a nagging feeling says there might be more to it. There is. What follows is not a list of prompts to memorize, but a set of habits, each one unlocking a capability you didn\u0026rsquo;t know was there.\u003c/p\u003e\n\u003cp\u003eThink of it like an adventure game: a new ability doesn\u0026rsquo;t just add a feature, it opens doors in places you\u0026rsquo;ve already visited. Ask better, and old questions get better answers. Read on, and each unlock builds on the last.\u003c/p\u003e\n\u003ch2 id=\"unlock-1-ask-what-ai-would-do\"\u003eUnlock 1: Ask what AI would do\u003c/h2\u003e\n\u003cp\u003eDon\u0026rsquo;t jump straight to a question and expect a finished answer. Before you ask for the answer, ask for the approach:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eI want to understand why this project keeps stalling. How would you investigate it? What would you need from me? What could you actually do?\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cstrong\u003eYou unlock a plan.\u003c/strong\u003e AI will lay out a strategy instead of guessing at one. The first plan is rarely the best one — push back, add what you know, and ask it to refine the approach before any real work starts.\u003c/p\u003e\n\u003ch2 id=\"unlock-2-ask-open-questions\"\u003eUnlock 2: Ask open questions\u003c/h2\u003e\n\u003cp\u003eYou got your answer, the chat feels done. Don\u0026rsquo;t stop there. This is where the \u0026ldquo;intelligence\u0026rdquo; in \u0026ldquo;artificial intelligence\u0026rdquo; actually shows up. Ask open questions:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eWhat else could I do with this? What am I missing? What thoughts do you have?\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cstrong\u003eYou unlock alternatives\u003c/strong\u003e and uncover assumptions you didn\u0026rsquo;t know you were making. This is often where the most useful answer of the whole conversation shows up, one you never thought to ask for directly.\u003c/p\u003e\n\u003ch2 id=\"unlock-3-dont-just-talk-let-the-ai-do-the-work\"\u003eUnlock 3: Don\u0026rsquo;t just talk, let the AI do the work\u003c/h2\u003e\n\u003cp\u003eChat is one mode. There\u0026rsquo;s another: tools like Claude Code or Codex that read and write files on your own computer and run programs for you. You don\u0026rsquo;t need to know how to program. You do need to decide which folder you let it see — don\u0026rsquo;t point it at anything you wouldn\u0026rsquo;t hand to the provider directly.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eMake a timeline from these project notes. Show the passages behind each finding, and flag any gaps in the record.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cstrong\u003eYou unlock an answer about \u003cem\u003eyour\u003c/em\u003e material\u003c/strong\u003e, not a generic answer about the world. Keep your originals untouched, so you can always check what it claims to have found.\u003c/p\u003e\n\u003ch2 id=\"unlock-4-let-the-ai-install-new-tools\"\u003eUnlock 4: Let the AI install new tools\u003c/h2\u003e\n\u003cp\u003eAn agent can reach beyond chat entirely: install a plotting library for a publication-quality graph, run statistics, or work through complex data — images, spreadsheets, even DNA or RNA sequences. You don\u0026rsquo;t need to know what tools exist for that. Just ask, and approve before it acts:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eFor this task, what tools would be helpful? Tell me what you\u0026rsquo;d install and why, before you install anything.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cstrong\u003eYou unlock capabilities you didn\u0026rsquo;t know existed\u003c/strong\u003e, without losing control of what happens on your machine.\u003c/p\u003e\n\u003ch2 id=\"unlock-5-compare-with-what-is-known\"\u003eUnlock 5: Compare with what is known\u003c/h2\u003e\n\u003cp\u003eYour own analysis, however careful, is only as good as what it\u0026rsquo;s checked against. Ask how your finding relates to published research or documented practice:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eFind the strongest evidence for and against this interpretation. Link the original sources. Where does my evidence fall short?\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cstrong\u003eYou unlock context.\u003c/strong\u003e Always open the links yourself — AI can produce sources that look entirely real and aren\u0026rsquo;t.\u003c/p\u003e\n\u003ch2 id=\"unlock-6-trust-but-verify\"\u003eUnlock 6: Trust, but verify\u003c/h2\u003e\n\u003cp\u003eStart a fresh session. Point it at your original material and your results, and ask it to find the error, not to confirm you\u0026rsquo;re right:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003eThis folder contains my original data and my conclusions. Assume at least one conclusion is wrong. Find it, recompute the key numbers from the raw data, and tell me what you couldn\u0026rsquo;t check.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003eFor more distance, switch models entirely — let Claude review Codex\u0026rsquo;s work, or the other way round. \u003cstrong\u003eYou unlock a second, less invested pair of eyes\u003c/strong\u003e, checking work that you and your first session were both too close to.\u003c/p\u003e\n\u003ch2 id=\"unlock-7-combine-the-methods\"\u003eUnlock 7: Combine the methods\u003c/h2\u003e\n\u003cp\u003eUsed together, plan, verify, and compare become something more than the sum of their parts:\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003ePropose three explanations. What evidence would distinguish them? Run the checks these files permit, then save the method and results.\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003cp\u003e\u003cstrong\u003eYou unlock something no single step can give you\u003c/strong\u003e: a repeatable analysis, a well-founded decision, a working prototype, or simply a better question than the one you started with.\u003c/p\u003e\n\u003ch2 id=\"bonus-unlock-give-the-ai-a-memory-of-its-own\"\u003eBonus unlock: Give the AI a memory of its own\u003c/h2\u003e\n\u003cp\u003eIf the result lives only in a chat window, it will eventually join every other brilliant thing you can no longer find. A folder of dated notes is a start, but it puts the filing on you, and a plain file only ever holds what you typed, not what the AI understood.\u003c/p\u003e\n\u003cp\u003eThis is the problem I\u0026rsquo;ve been building \u003ca href=\"https://kolja.wawrowsky.com/posts/memory-is-not-storage/\"\u003eES Archive\u003c/a\u003e to solve: an MCP tool that gives AI a real memory, one it writes and curates itself, in its own words, across sessions and even across models. Instead of you copying answers into files, the AI decides what mattered enough to keep, and finds it again the next time it\u0026rsquo;s relevant — no re-explaining your project from scratch, no digging through old chats for the one thread you needed.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eYou unlock continuity.\u003c/strong\u003e Connect it once, and every unlock above compounds instead of resetting each time you open a new chat.\u003c/p\u003e\n\u003cp\u003eThese unlocks aren\u0026rsquo;t a straight path. New evidence may send you back to the first question, and that\u0026rsquo;s the point. Each pass gives you more to work with, while you stay responsible for deciding what\u0026rsquo;s true and what matters.\u003c/p\u003e\n",
      "date_modified": "2026-09-26T00:00:00Z",
      "date_published": "2026-09-26T00:00:00Z",
      "id": "https://kolja.wawrowsky.com/posts/unlock-ai-capabilities/",
      "image": "https://kolja.wawrowsky.com/posts/unlock-ai-capabilities/og.jpg",
      "summary": "Most people stop at the first answer AI gives them. Here are seven small habits, each one unlocking a new capability, that take you from chatting with AI to actually working with it.",
      "tags": [
        "Field Notes"
      ],
      "title": "Seven Unlocks for Working With AI",
      "url": "https://kolja.wawrowsky.com/posts/unlock-ai-capabilities/"
    },
    {
      "authors": [
        {
          "name": "Kolja Wawrowsky",
          "url": "https://kolja.wawrowsky.com/"
        }
      ],
      "content_html": "\u003cp\u003eIn 2010 we ran a control experiment that every live-cell imaging lab runs sooner or later. Before trusting a multi-day time-lapse on the confocal, we needed to know whether the cells would survive it: sixty hours in a stage-top incubator, with heat, CO₂, humidity and a laser passing over them every five minutes.\u003c/p\u003e\n\u003cp\u003eThe cells were HeLa expressing FUCCI, the cell-cycle reporter that makes this easy to read by eye. Nuclei glow red in G1, turn yellow at the G1/S transition when both reporters are present, and glow green through S, G2 and M. After division the daughters go briefly dark, then turn red again. A healthy population keeps cycling through those colours. A stressed one stalls.\u003c/p\u003e\n\u003cp\u003eWe watched the movie, saw cells dividing, and moved on. That was the whole analysis.\u003c/p\u003e\n\u003cp\u003eThe raw data didn\u0026rsquo;t survive the following sixteen years. What did survive was a single QuickTime export, carried from backup to backup. This September I gave that file to Claude Code to see how much it still held. The answer turned out to be: almost everything.\u003c/p\u003e\n\u003cfigure\u003e\u003cimg src=\"https://kolja.wawrowsky.com/posts/weekend-on-the-stage/before-after.jpg\"\n\t\t\talt=\"Side-by-side: the original 2010 video frame on the left, the same frame with nucleus outlines coloured by cell-cycle phase and white rings on recent divisions on the right.\"\u003e\u003cfigcaption\u003e\n\t\t\t\u003cp\u003e\u003cstrong\u003eFrame 461, 38 h 25 min.\u003c/strong\u003e Left: the 2010 export as it was. Right: the analysis, with nuclei outlined by phase call (red G1, yellow G1/S, green S/G2/M) and white rings on divisions in the preceding hour.\u003c/p\u003e\n\t\t\u003c/figcaption\u003e\n\u003c/figure\u003e\n\n\u003ch2 id=\"what-survived\"\u003eWhat survived\u003c/h2\u003e\n\u003cp\u003eThe file is 37 MB. Its header says it was written on 4 June 2010 at 17:19 UTC by \u003ccode\u003eCoreMediaAuthoring 700, CoreMedia 484.5, i386\u003c/code\u003e: an \u0026ldquo;Export for iPod/Apple TV\u0026rdquo; from the Snow Leopard era. That\u0026rsquo;s the date of the export, so the imaging happened some time before it. Inside are 721 frames of 720 × 720 pixels, 8-bit colour, with the transmitted-light image and both fluorescence channels merged into one picture. No objective, no pixel size, no laser powers, no channel names. By any sensible standard it\u0026rsquo;s a presentation file, not data.\u003c/p\u003e\n\u003ch2 id=\"getting-the-channels-back\"\u003eGetting the channels back\u003c/h2\u003e\n\u003cp\u003eThe merge is less destructive than it looks. The grey transmitted-light (TM) image adds the same amount to red, green and blue, while the FUCCI colours were rendered into red and green only. So the channels come apart by subtraction: transmitted light is roughly the blue channel, FUCCI red is red minus blue, and FUCCI green is green minus blue. With the timestamp in the corner masked out, that gave three clean 721-frame stacks.\u003c/p\u003e\n\u003cfigure\u003e\u003cimg src=\"https://kolja.wawrowsky.com/posts/weekend-on-the-stage/unmix.jpg\"\n\t\t\talt=\"Three grey-scale panels: transmitted light showing cell outlines, the red channel showing G1 nuclei, and the green channel showing S/G2/M nuclei.\"\u003e\u003cfigcaption\u003e\n\t\t\t\u003cp\u003e\u003cstrong\u003eOne frame, three channels,\u003c/strong\u003e recovered from the merged colour video: transmitted light, FUCCI red, FUCCI green.\u003c/p\u003e\n\t\t\u003c/figcaption\u003e\n\u003c/figure\u003e\n\n\u003ch2 id=\"getting-the-time-back\"\u003eGetting the time back\u003c/h2\u003e\n\u003cp\u003eWith the metadata gone, the frame interval had to come from the picture. The burned-in clock was readable when enlarged. Frame 1 reads 00:05:00 and frame 100 reads 08:20:00. Frames 360 and 720 briefly looked like 106 and 212 hours, until it became clear that the leading \u0026ldquo;0\u0026rdquo; was a small \u0026ldquo;d\u0026rdquo;: 1d 06:00:00 and 2d 12:00:00. Every stamp agrees on five minutes per frame and sixty hours in total.\u003c/p\u003e\n\u003ch2 id=\"finding-nuclei\"\u003eFinding nuclei\u003c/h2\u003e\n\u003cp\u003eNuclei were segmented with StarDist, a deep-learning model for round-ish objects, using its pretrained fluorescence model on the brighter of the two FUCCI channels at each pixel. Upscaling the frames made it split nuclei, so it ran at native resolution. Across the movie it found 109,950 nuclei, growing from 52 in the first frame to about 290 at the end.\u003c/p\u003e\n\u003ch2 id=\"finding-divisions-the-old-way\"\u003eFinding divisions the old way\u003c/h2\u003e\n\u003cp\u003eFUCCI has a blind spot for tracking. After anaphase the green signal disappears, and the daughters stay dark for one to two hours before red appears. A tracker that only sees fluorescence loses every cell at every division, exactly when you most want to follow it.\u003c/p\u003e\n\u003cp\u003eThe fix is a trick every microscopist of my generation knows. Cells round up for mitosis, and in transmitted light a rounded cell carries a bright, thick halo. Run an edge filter over the image and those halos are the strongest signal in the frame. A circle finder with a score for how complete the rim is picks them out, and a filter for spots that never move removes the dust. The result is a mitosis detector that doesn\u0026rsquo;t depend on fluorescence at all.\u003c/p\u003e\n\u003cfigure\u003e\u003cimg src=\"https://kolja.wawrowsky.com/posts/weekend-on-the-stage/edges.jpg\"\n\t\t\talt=\"Left: edge-strength image where rounded cells appear as bright double rings. Right: transmitted-light image with detected circles marked.\"\u003e\u003cfigcaption\u003e\n\t\t\t\u003cp\u003e\u003cstrong\u003eEdge strength (left) and detected rounded cells (right).\u003c/strong\u003e Green circles contain a fluorescent nucleus, red ones don\u0026rsquo;t: either dead cells or cells in the dark window just after division.\u003c/p\u003e\n\t\t\u003c/figcaption\u003e\n\u003c/figure\u003e\n\n\u003cfigure\u003e\u003cimg src=\"https://kolja.wawrowsky.com/posts/weekend-on-the-stage/mitosis.jpg\"\n\t\t\talt=\"Three rows of image tiles every 20 minutes around a rounding event, each tile showing transmitted light above and FUCCI colour below.\"\u003e\u003cfigcaption\u003e\n\t\t\t\u003cp\u003e\u003cstrong\u003eThree events at 20-minute steps.\u003c/strong\u003e Top: a rounded cell whose daughters appear dimly red 40–100 minutes later. Middle: a clean red → yellow → green G1/S transition. Bottom: a green nucleus swells as its envelope breaks down, vanishes, and returns as two faint red daughters about two hours later.\u003c/p\u003e\n\t\t\u003c/figcaption\u003e\n\u003c/figure\u003e\n\n\u003ch2 id=\"tracking-and-lineages\"\u003eTracking and lineages\u003c/h2\u003e\n\u003cp\u003eThe cells here move slowly: half a pixel per frame on average. btrack linked the nuclei frame by frame into 2,634 track pieces. A lineage step written for this data then did what generic trackers find hard:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eGap closing:\u003c/strong\u003e it joined pieces of the same nucleus lost for up to an hour, provided the colour matched.\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDivision linking:\u003c/strong\u003e it connected a mother track that ended green to up to two daughter tracks that started red or dark nearby within three hours. A rounded-cell ring at the mother\u0026rsquo;s last position strengthened the link.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eThe ring detector turned out to be decisive. 99% of accepted divisions have a ring at the right place and time, against 16% for random positions. The final count: \u003cstrong\u003e959 cells and 256 divisions\u003c/strong\u003e, 205 of them with both daughters found.\u003c/p\u003e\n\u003cfigure\u003e\u003cimg src=\"https://kolja.wawrowsky.com/posts/weekend-on-the-stage/lineages.jpg\"\n\t\t\talt=\"Six lineage trees, time running downwards over 60 hours, each branch coloured red, yellow, green and grey by phase.\"\u003e\u003cfigcaption\u003e\n\t\t\t\u003cp\u003e\u003cstrong\u003eThe six largest families.\u003c/strong\u003e Time runs downwards. Each branch passes red → yellow → green → division → grey gap → red, over up to three generations.\u003c/p\u003e\n\t\t\u003c/figcaption\u003e\n\u003c/figure\u003e\n\n\u003ch2 id=\"cell-cycle-timing\"\u003eCell-cycle timing\u003c/h2\u003e\n\u003cp\u003ePhases follow the usual FUCCI convention. The division time is the last frame of the mother\u0026rsquo;s nucleus, around anaphase. G1 runs from division to green onset, including the dark gap. S/G2/M runs from green onset to the next division.\u003c/p\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth\u003eMeasure\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: right\"\u003en\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: right\"\u003eMedian\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: right\"\u003eIQR\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003e\u003cstrong\u003eCell cycle\u003c/strong\u003e (division → division)\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e155\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e\u003cstrong\u003e17.9 h\u003c/strong\u003e\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e16.3–19.5 h\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eG1 (division → green onset)\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e292\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e8.5 h\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e7.1–10.8 h\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eS/G2/M (green onset → division)\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e203\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e10.3 h\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e9.2–11.8 h\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003ePopulation doubling (from counts)\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e–\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e23.0 h\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e–\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cfigure\u003e\u003cimg src=\"https://kolja.wawrowsky.com/posts/weekend-on-the-stage/durations.jpg\"\n\t\t\talt=\"Histograms of cell cycle, G1 and S/G2/M durations, and a scatter plot of G1 against S/G2/M per cell.\"\u003e\u003cfigcaption\u003e\n\t\t\t\u003cp\u003e\u003cstrong\u003eDistributions.\u003c/strong\u003e Per cell, the lengths of G1 and S/G2/M are unrelated (Spearman ρ = 0.03).\u003c/p\u003e\n\t\t\u003c/figcaption\u003e\n\u003c/figure\u003e\n\n\u003cfigure\u003e\u003cimg src=\"https://kolja.wawrowsky.com/posts/weekend-on-the-stage/population.jpg\"\n\t\t\talt=\"Left: nucleus count rising from about 50 to 300 over 60 hours with an exponential fit. Right: stacked fractions of cells in each phase over time.\"\u003e\u003cfigcaption\u003e\n\t\t\t\u003cp\u003e\u003cstrong\u003ePopulation.\u003c/strong\u003e Counts grow with a 23-hour doubling time. The phase mix shows the culture started partly synchronised near G1/S, followed by a wave of divisions at 15–25 hours.\u003c/p\u003e\n\t\t\u003c/figcaption\u003e\n\u003c/figure\u003e\n\n\u003cp\u003eSeveral checks suggest the numbers can be trusted. Restricting the analysis to cells born early enough for a long cycle to fit in the movie doesn\u0026rsquo;t move the median (17.8–17.9 h), so the 60-hour window isn\u0026rsquo;t biasing it. Sister cells have strongly correlated cycle lengths (ρ = 0.72, median difference 55 minutes), while mothers and daughters barely correlate (ρ = 0.28). That\u0026rsquo;s the well-known pattern of real mammalian lineages, and a mis-linked tracker would scramble it.\u003c/p\u003e\n\u003ch2 id=\"families-make-synchronised-clusters\"\u003eFamilies make synchronised clusters\u003c/h2\u003e\n\u003cp\u003eThe phase map looked patchy: neighbouring cells tended to share a colour. To measure this, I compared how often pairs of nuclei share a phase with how often they would if the phase labels were shuffled at random over the same positions, and split the pairs by relatedness.\u003c/p\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth\u003eNeighbour pairs within 50 px\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: right\"\u003eSame phase\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: right\"\u003eIf random\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: right\"\u003eRatio\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eSisters\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e98%\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e53%\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e1.86\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eFirst cousins\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e91%\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e52%\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e1.74\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eUnrelated\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e74%\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e54%\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e1.37\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eAunt and niece\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e12%\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e53%\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e0.23\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eRelatives make up 16% of neighbour pairs but produce 28% of the excess same-phase pairs. Division timing loosens by generation: sisters divide a median 0.9 hours apart, first cousins 1.5 hours, unrelated cells born around the same time 3.7 hours. Relatives match at any distance, while unrelated cells match only when close. Sisters drift apart by less than one nucleus width in a day, which is why families stay visible as clusters. The aunt-and-niece row is a good sanity check: one generation apart, they sit on opposite sides of the cycle.\u003c/p\u003e\n\u003cfigure\u003e\u003cimg src=\"https://kolja.wawrowsky.com/posts/weekend-on-the-stage/clustering.jpg\"\n\t\t\talt=\"Four panels: division-time difference by relatedness; same-phase ratio against distance; sister distance and phase agreement over time; family coherence and spread against family age.\"\u003e\u003cfigcaption\u003e\n\t\t\t\u003cp\u003e\u003cstrong\u003eLineage clustering.\u003c/strong\u003e (A) Synchrony fades by generation. (B) Relatives match phase at any distance, while unrelated neighbours match only when close. (C) Sisters stay close and fall out of step only near their next division. (D) Families from the first sister pair onward: fully in phase at first, still 90% at 48 hours against 74% by chance.\u003c/p\u003e\n\t\t\u003c/figcaption\u003e\n\u003c/figure\u003e\n\n\u003cp\u003eThese are lower bounds. Cells present in the first frame have unknown ancestry, so sisters born before recording count as unrelated.\u003c/p\u003e\n\u003ch2 id=\"did-they-survive-the-weekend\"\u003eDid they survive the weekend?\u003c/h2\u003e\n\u003cp\u003eYes. The cells proliferated through all sixty hours.\u003c/p\u003e\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003cth\u003eIndicator\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: right\"\u003e0–24 h\u003c/th\u003e\n\t\t\t\t\t\u003cth style=\"text-align: right\"\u003e36–60 h\u003c/th\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eNuclei in field\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e59 → 101\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e180 → 288\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eCell cycle, median\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e16.8 h\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e18.4 h\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eS/G2/M, median\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e10.3 h\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e9.6 h\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eTime spent rounded in mitosis\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e145–185 min\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e70–75 min\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\t\t\u003ctr\u003e\n\t\t\t\t\t\u003ctd\u003eRounded cells that never divide, per 100\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e14 → 5\u003c/td\u003e\n\t\t\t\t\t\u003ctd style=\"text-align: right\"\u003e3 → 2.5\u003c/td\u003e\n\t\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\u003cp\u003eCycle times stayed stable, S/G2/M didn\u0026rsquo;t lengthen (it\u0026rsquo;s the phase that stretches with DNA damage), mitoses were normal after the first day, and dead cells didn\u0026rsquo;t accumulate. The stage didn\u0026rsquo;t drift and the lamp stayed steady.\u003c/p\u003e\n\u003cp\u003eThree findings are worth acting on before longer runs:\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eG1 lengthens with time on the stage, and crowding doesn\u0026rsquo;t explain it.\u003c/strong\u003e Median G1 rose from 6.6 hours for cells born early to 10.4 hours for cells born after 35 hours, while S/G2/M stayed near 10 hours. At the same local density, late-born cells still spend longer in G1. With two to four neighbours, for example, it rose from 7.1 to 9.9 hours. In a joint model, time on the stage explains the effect and local density adds nothing. The likely causes act on the whole dish: medium being used up or acidifying, evaporation, or accumulated light dose. A single field of view can\u0026rsquo;t tell them apart.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eThe green reporter fades by about half.\u003c/strong\u003e Measured in the same phase, each cell\u0026rsquo;s green signal falls from 0.78 to 0.40 over sixty hours, while red falls only from 0.55 to 0.45. That points to photobleaching of the green protein at five-minute imaging, a sign of light dose rather than damage in itself. The caveat: a change in display settings during the 2010 export would look the same.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eMitosis ran long on the first day\u003c/strong\u003e, about 2.5 to 3 hours against 70–75 minutes later. This could be the cells settling into the incubator, or left over from how the culture was prepared.\u003c/p\u003e\n\u003cp\u003eThe next control run should include an unimaged well, photographed only at the start and the end. It should also image fluorescence every fifteen minutes with transmitted light every five, since transmitted light alone is enough to find divisions. And it should keep the raw files.\u003c/p\u003e\n\u003ch2 id=\"what-this-cant-say\"\u003eWhat this can\u0026rsquo;t say\u003c/h2\u003e\n\u003cp\u003eThe source is a lossy, 8-bit, display-scaled export, so every intensity here is relative, and distances are in pixels because the pixel size is lost. Division and phase calls have been checked by internal consistency and by eye on examples, but not yet against a hand-annotated set. A few multinucleated cells, present from the first frames, are over-counted as several nuclei, though they never divide and so stay out of the timing statistics. And it\u0026rsquo;s one field, from one run, on one weekend.\u003c/p\u003e\n\u003ch2 id=\"same-tricks-thirty-seven-years-apart\"\u003eSame tricks, thirty-seven years apart\u003c/h2\u003e\n\u003cp\u003eIn 1989 I wrote software to track vesicles during cell division. An Image-1/AT video processor board did the pixel work, a program in Borland C under MS-DOS did the analysis, the tracks went into dBASE IV, and the reports were printed from Lotus Manuscript 2.1. A 512 × 512 frame took 256 KB, so two frames filled everything DOS would give me. The method was forced by the machine: compute the changes in space and time, mask the places where something is happening, and spend the scarce memory only there.\u003c/p\u003e\n\u003cp\u003eThat\u0026rsquo;s the idea that made this analysis work: edges to find rounded cells, colour changes to find phase transitions, and event masks to bridge the dark gap after every division. The difference is the headroom. One channel of this movie takes 1.4 GB, and the whole pipeline, from export file to lineage statistics, was built in an evening with Claude Code.\u003c/p\u003e\n\u003cp\u003eThe instruments have changed beyond recognition. I wrote about that in \u003ca href=\"https://kolja.wawrowsky.com/posts/building-instruments/\"\u003eA Microscope for a Mind\u003c/a\u003e. The habit of looking closely where the signal changes has not. And a file I had written off as a presentation copy turned out to be data all along.\u003c/p\u003e\n",
      "date_modified": "2026-09-24T00:00:00Z",
      "date_published": "2026-09-24T00:00:00Z",
      "id": "https://kolja.wawrowsky.com/posts/weekend-on-the-stage/",
      "image": "https://kolja.wawrowsky.com/posts/weekend-on-the-stage/og.jpg",
      "summary": "In 2010 I left HeLa cells on a confocal for a weekend to see whether they would survive. The raw data is long gone, but one compressed QuickTime export survived. Sixteen years later it was enough to recover the channels, track 959 cells through three generations, and finally answer the question properly.",
      "tags": [
        "Field Notes"
      ],
      "title": "A Weekend on the Stage",
      "url": "https://kolja.wawrowsky.com/posts/weekend-on-the-stage/"
    },
    {
      "authors": [
        {
          "name": "Kolja Wawrowsky",
          "url": "https://kolja.wawrowsky.com/"
        }
      ],
      "content_html": "\u003cp\u003e\u003cimg src=\"og.jpg\" alt=\"The Humboldt University building on Bebelplatz, Berlin, against the evening sun\"\u003e\u003c/p\u003e\n\u003cp\u003eSteve Jobs famously called the computer “a bicycle for the mind,” a tool that propels thinking. Like a bicycle, the computer helps us go farther with the same effort. Our age has introduced another such tool: artificial intelligence. AI can catalyze the human mind, but what it produces depends on us. Education can shape a generation, but what it creates depends on what that generation is taught.\u003c/p\u003e\n\u003cp\u003eWe think this is unprecedented, but it is not. For two centuries, defeated nations have turned to schools as a force for renewal. At times, wounded pride was planted in the classroom, and what grew was nationalism and the exclusion of those deemed outsiders.\u003c/p\u003e\n\u003cp\u003eBefore we ask how AI might shape our future, it may be worth looking at what two centuries of education can teach us. This is a story about education’s promise—and the fires lit in its name. It is also a story about national wounds and the choices they shaped. If AI is our generation\u0026rsquo;s school, what are we teaching it, and what is it teaching us?\u003c/p\u003e\n\u003ch2 id=\"i-berlin-december-1807\"\u003eI. Berlin, December 1807\u003c/h2\u003e\n\u003cp\u003eThe drums of the French garrison could be heard on Unter den Linden that Sunday, as on every Sunday. Inside the round hall of the Academy of Sciences, a man of forty-five with a hard jaw and a voice trained in pulpits stood up to speak.\u003c/p\u003e\n\u003cp\u003eJohann Gottlieb Fichte had fled Berlin the year before, when Napoleon\u0026rsquo;s army came after Jena. He had gone to Königsberg, then to Copenhagen, and he had come back to a city that no longer belonged to its king. French officers sat in the cafés. French censors read the newspapers before the Berliners did. Everyone in the hall knew that a lecture of the wrong kind could end in arrest, and there were rumors that the censor had already marked him.\u003c/p\u003e\n\u003cp\u003eHe spoke anyway, fourteen Sundays in a row, through the winter and into March. The Addresses to the German Nation began from a simple premise: the armies were gone, the state was broken, and there was nothing left to fight with. Nothing, he said, except the one thing a conqueror cannot occupy. A new education. Not the drilling of facts into children, but the forming of whole persons, who would act from their own inner freedom. A people formed that way could not be held down forever.\u003c/p\u003e\n\u003cp\u003eIt was an argument for the school. It was also something else. In the same lectures Fichte told his listeners that the Germans were an original people, an Urvolk, whose language had never been broken by foreign conquest, and who therefore carried a deeper truth than the nations around them. The French had taken the land. The spirit, he promised, was still German, and superior.\u003c/p\u003e\n\u003cp\u003eTwo seeds went into the ground that winter in the same furrow. Nobody in the round hall could have told them apart.\u003c/p\u003e\n\u003ch2 id=\"ii-rome-and-berlin-1809\"\u003eII. Rome and Berlin, 1809\u003c/h2\u003e\n\u003cp\u003eWilhelm von Humboldt did not want the job. He was in Rome as the Prussian envoy to the Holy See, living among ruins and books with his wife Caroline and their children, and he had built there the kind of life a scholar dreams of. When the summons came to return to Prussia and run the section for education, he hesitated for months. Caroline stayed behind in Rome.\u003c/p\u003e\n\u003cp\u003eHe accepted in February 1809, and he worked as if he knew he would not have long. He had spent twenty years thinking about one question: how does a human being become fully human? His answer was Bildung, the formation of the self through freedom and through contact with the whole range of human knowledge. The state, he had written as a young man, should do as little as possible, and above all it should not tell minds where to go.\u003c/p\u003e\n\u003cp\u003eNow the state was asking him to build its future. He answered by building a place where the state would keep its hands off. A university where teaching and research were one, where professors followed their questions and students followed their professors, in solitude and freedom, Einsamkeit und Freiheit. Knowledge, he wrote, should be treated as something never fully found, and always to be searched for.\u003c/p\u003e\n\u003cp\u003eThe king gave him a building: the palace of the late Prince Heinrich on Unter den Linden. Its front faced a wide square beside the opera house.\u003c/p\u003e\n\u003cp\u003eHumboldt resigned in June 1810, after sixteen months, frustrated by court politics. He was not there when the university opened that autumn. Among its first professors was Fichte. The next year the faculty elected Fichte rector.\u003c/p\u003e\n\u003cp\u003eIn that office, in 1811 or 1812, a student named Friedrich Friesen brought him a document to review. It was a draft constitution for a new kind of student association, a Burschenschaft, drawn up in the circle of the gymnastics teacher Friedrich Ludwig Jahn. It imagined German students bound together by fatherland and honor. Fichte read it, and wrote his comments.\u003c/p\u003e\n\u003ch2 id=\"iii-the-wartburg-october-18-1817\"\u003eIII. The Wartburg, October 18, 1817\u003c/h2\u003e\n\u003cp\u003eFour years after the battle of Leipzig, three hundred years after Luther\u0026rsquo;s theses, about five hundred students climbed to the Wartburg castle above Eisenach. The fraternity of Jena had invited them. Jena, of all places: the town that had given its name to the defeat.\u003c/p\u003e\n\u003cp\u003eThey carried flags in black, red and gold, the colors of the volunteer corps that had fought Napoleon. Many of them had been soldiers. Some had bled. They sang, they heard speeches about unity and freedom, they ate together in the great hall where Luther had translated the Bible.\u003c/p\u003e\n\u003cp\u003eIn the evening, on the hill across from the castle, a smaller group lit a bonfire. A gymnastics student named Hans Ferdinand Massmann, a follower of Jahn, had prepared it. Into the flames went bundles of waste paper, each labeled with the title of a book the students considered un-German: the Napoleonic Code, the histories of August von Kotzebue, and a pamphlet called Germanomanie by the Berlin writer Saul Ascher. After the paper they threw in a corporal\u0026rsquo;s cane, a soldier\u0026rsquo;s pigtail, and a cavalry officer\u0026rsquo;s corset. The symbols of old Prussian drill and the books of their enemies burned in the same fire.\u003c/p\u003e\n\u003cp\u003eSaul Ascher read about it in Berlin. He was a Jewish scholar, one of the first Jews in Germany to hold a doctorate, a defender of the French Revolution\u0026rsquo;s promise of equal rights. His pamphlet had warned against exactly this: a Germanness that defined itself by whom it excluded. Now his title had been fed to the flames by the educated sons of the new Germany.\u003c/p\u003e\n\u003cp\u003eA few years later a young poet from Düsseldorf, Heinrich Heine, came to know him. Heine visited Ascher on his deathbed in 1822. That same season Heine published a tragedy he had been writing, set in Moorish Granada after the Christian conquest. In one scene a servant hears that the conquerors have burned the Quran in the marketplace. He answers with a line that would outlive everything else in the play: where they burn books, they will in the end burn people too.\u003c/p\u003e\n\u003cp\u003eThe university and the fire were ten years old together. They had been born of the same defeat.\u003c/p\u003e\n\u003ch2 id=\"iv-dybbøl-and-askov-1864-to-1866\"\u003eIV. Dybbøl and Askov, 1864 to 1866\u003c/h2\u003e\n\u003cp\u003eOn April 18, 1864, Prussian artillery broke the Danish lines at Dybbøl after weeks of bombardment. By autumn Denmark had lost Schleswig and Holstein, roughly a third of its land and a large share of its people. A small country found itself smaller still, with no army that could ever take anything back.\u003c/p\u003e\n\u003cp\u003eIn the lost territory, at Rødding, stood the first folk high school, founded twenty years earlier in the spirit of the pastor and poet N. F. S. Grundtvig. It was a school without examinations for the sons and daughters of farmers, who came in the winter months when the fields rested, to hear history and poetry told aloud, to sing, and to talk. Grundtvig called it the school of the living word.\u003c/p\u003e\n\u003cp\u003eAfter the defeat, Rødding lay on the Prussian side of the new border. Its head, Ludvig Schrøder, did not surrender the school. In 1865 he moved it a few kilometers north, just across the new line, to a village called Askov. From there it grew into the most influential folk high school in the country, and dozens of new ones opened across Denmark in the years after the war.\u003c/p\u003e\n\u003cp\u003eAt the same time an engineer officer named Enrico Dalgas looked at the heath of Jutland, a vast brown waste of heather and sand that nobody farmed. In 1866 he helped found the Danish Heath Society to reclaim it: to drain, plant, and turn it into fields and forest. If land had been lost to the south, new land could be made in the west.\u003c/p\u003e\n\u003cp\u003eA phrase gathered around both efforts and became almost a national motto: hvad udad tabes, skal indad vindes. What is lost outwardly must be won inwardly.\u003c/p\u003e\n\u003cp\u003eDenmark never sought revenge. It became a country of cooperatives, dairies, reading circles and schools, one of the most literate rural societies in Europe. When the Danes asked who they were now, they did not answer with an enemy.\u003c/p\u003e\n\u003ch2 id=\"v-arbois-and-paris-1871-to-1877\"\u003eV. Arbois and Paris, 1871 to 1877\u003c/h2\u003e\n\u003cp\u003eIn January 1871, while Prussian guns shelled Paris, Louis Pasteur sat in his family house in Arbois in the Jura and wrote a letter to the University of Bonn. Years earlier Bonn had given him an honorary doctorate. Now he sent the diploma back. The name of Germany\u0026rsquo;s king on it, he wrote, had become odious to him.\u003c/p\u003e\n\u003cp\u003eThen he did something more lasting. He wrote an essay asking why France had found no superior men in its hour of danger. His answer was not the army. It was the laboratory. For fifty years, he argued, France had neglected science and higher learning while Germany had built universities, and now France had paid for it. The victors had studied more.\u003c/p\u003e\n\u003cp\u003eHe was not alone. Ernest Renan blamed the French universities. In 1872 a young man named Émile Boutmy founded a private school in Paris, the École libre des sciences politiques, so that France would never again be governed by men who did not understand the world. The school survives today as Sciences Po.\u003c/p\u003e\n\u003cp\u003eIn the 1880s Jules Ferry made primary school free, secular and compulsory. Across France, in villages that had never had a proper classroom, the schoolteachers of the Republic arrived.\u003c/p\u003e\n\u003cp\u003eAnd they taught the lost provinces. On the Place de la Concorde the statue representing Strasbourg was draped in black crepe, and it stayed that way until 1918. In 1877 a writer named Augustine Fouillée, publishing under the name G. Bruno, gave French children the book they would read for generations: Le Tour de la France par deux enfants. It opens on a foggy night in Phalsbourg, in annexed Lorraine, as two orphaned brothers, André and Julien, slip away to find their way into France. Through their journey, millions of children learned the geography of their country, its crafts, its duties, and its wound.\u003c/p\u003e\n\u003cp\u003eIn the same years schoolboys formed bataillons scolaires, marching in the schoolyards with wooden rifles. France taught its children to read and to remember, and the two lessons were not always distinguishable. Both answers were given in the same classroom, sometimes by the same teacher, in the same hour.\u003c/p\u003e\n\u003ch2 id=\"vi-beijing-may-4-1919\"\u003eVI. Beijing, May 4, 1919\u003c/h2\u003e\n\u003cp\u003eCai Yuanpei had studied in Leipzig. From 1907 to 1911 the former imperial scholar sat in German lecture halls, reading philosophy and psychology, watching how a university worked when it followed Humboldt\u0026rsquo;s idea. When he became president of Peking University in 1917, he tried to build the same thing in a country that had been defeated again and again since the Opium Wars. Freedom of thought, he said. Every school of ideas welcome. The university as a place for the pursuit of knowledge, not a ladder to office.\u003c/p\u003e\n\u003cp\u003eThe university was itself a child of defeat. It had been founded in 1898 in the brief reform movement that followed China\u0026rsquo;s loss to Japan. Not far away, another school had been built with money from the next humiliation: when the United States returned part of the indemnity China was forced to pay after the Boxer War, the funds paid for students to go abroad and, from 1911, for a preparatory school called Tsinghua.\u003c/p\u003e\n\u003cp\u003eIn the spring of 1919 news came from Paris. The peace conference had given the German concessions in Shandong not back to China, which had sent laborers to the Western Front, but to Japan.\u003c/p\u003e\n\u003cp\u003eOn the afternoon of May 4 about three thousand students gathered at Tiananmen. A student leader of Peking University named Fu Sinian carried the banner. They marched toward the legation quarter, were turned away, and turned instead toward the house of Cao Rulin, a minister they blamed for dealing with Japan. They broke in. Cao escaped through the back. Another official, Zhang Zongxiang, was caught and beaten. Then someone set the house on fire.\u003c/p\u003e\n\u003cp\u003eThe May Fourth Movement became the birth of modern Chinese thought: a vernacular literature, a new science, a new conversation about democracy. It began, on its first day, with a fire lit by the students of a Humboldtian university. Cai Yuanpei resigned within days. He came back. The university went on.\u003c/p\u003e\n\u003ch2 id=\"vii-berlin-may-10-1933\"\u003eVII. Berlin, May 10, 1933\u003c/h2\u003e\n\u003cp\u003eThe Prince Heinrich palace was still the university. It was now called the Friedrich Wilhelm University, and across Unter den Linden, on the square that Humboldt\u0026rsquo;s windows had looked onto, stood a pyre.\u003c/p\u003e\n\u003cp\u003eIt had been prepared by students. Not by the party and not by a mob, but by the national student organization, which Nazi students had captured in 1931, two years before their party captured the state. For weeks they had combed libraries and bookshops for the works on their lists. That night, in about twenty university towns, they would burn them.\u003c/p\u003e\n\u003cp\u003eIn Berlin the students marched by torchlight to the square, which was then called the Opernplatz. Trucks brought the books. Fraternity students in their colors stood beside men in brown uniforms. At the fire, students read out \u0026ldquo;fire oaths,\u0026rdquo; one for each condemned author, and threw the books in: Marx, Freud, Heinrich Mann, Tucholsky, Remarque, and Heine, the poet from Düsseldorf who had written the line about burning people. Near midnight Joseph Goebbels spoke, and told them that the age of an overblown Jewish intellectualism was over.\u003c/p\u003e\n\u003cp\u003eOne of the authors was standing in the crowd. Erich Kästner had come to watch. He heard his own name called out and his books thrown into the fire, and he stood there without moving. Someone recognized him, and he left.\u003c/p\u003e\n\u003cp\u003eThe organizers had said openly what they were continuing. They invoked the Wartburg. One hundred and sixteen years after Massmann\u0026rsquo;s bonfire, the educated sons of Germany again answered the question of who they were by naming whom they were not.\u003c/p\u003e\n\u003ch2 id=\"viii-berlin-1948\"\u003eVIII. Berlin, 1948\u003c/h2\u003e\n\u003cp\u003eAfter the second war, and a defeat so total that the word hardly covered it, the old university on Unter den Linden reopened in the Soviet sector. Soon students learned what could and could not be printed.\u003c/p\u003e\n\u003cp\u003eIn the spring of 1948 three students, among them Otto Stolz and Joachim Schwarz, wrote critical articles in a student magazine called Colloquium. They were expelled. Their classmates met in protest, and out of that anger came an idea almost nobody believed could work: to leave Humboldt\u0026rsquo;s building and found a new university in the western sectors, in the villas and sheds of Dahlem.\u003c/p\u003e\n\u003cp\u003eThe Berlin mayor, Ernst Reuter, backed them. The American authorities helped. On December 4, 1948, in the Titania-Palast cinema in Steglitz, the Free University of Berlin was founded. Its first rector was the historian Friedrich Meinecke, eighty-six years old, who had spent his life on the history of German ideas and had written, three years earlier, a book on what he called the German catastrophe.\u003c/p\u003e\n\u003cp\u003eThe new university took a motto of three words: Veritas, Iustitia, Libertas. Truth, justice, freedom.\u003c/p\u003e\n\u003cp\u003eIt was the oldest answer again, given this time by the students themselves. They did not burn anything. They walked out, and they built.\u003c/p\u003e\n\u003ch2 id=\"ix-bebelplatz-now\"\u003eIX. Bebelplatz, now\u003c/h2\u003e\n\u003cp\u003eIn 1995 the Israeli artist Micha Ullman set a window into the cobblestones of the square that had been the Opernplatz. Beneath the glass is a white room lined with empty shelves, enough for twenty thousand books. At night it glows. Nearby a small plaque carries Heine\u0026rsquo;s line from Almansor.\u003c/p\u003e\n\u003cp\u003eEvery year around the anniversary, students of the Humboldt University set up tables on the square and sell books.\u003c/p\u003e\n\u003ch2 id=\"coda-two-answers\"\u003eCoda: Two answers\u003c/h2\u003e\n\u003cp\u003eLaid side by side, these scenes tell one story.\u003c/p\u003e\n\u003cp\u003eA nation that loses a war almost never concludes that it had too few soldiers. It concludes that it knew too little, or was the wrong kind of people. Defeat is read as an examination failed. So the defeated turn to the one power a victor cannot take away or limit by treaty: what the next generation learns. They have time and nothing else, and education is the only strategy that works on the scale of a generation. The young are the territory that was never occupied.\u003c/p\u003e\n\u003cp\u003eBut a school after a defeat must always answer a question: who are we now?\u003c/p\u003e\n\u003cp\u003eOne answer points outward, to an enemy. We are those who were wronged. The lost province, the traitor within, the shameful treaty. Education built on that answer becomes mobilization, and its ritual is the fire.\u003c/p\u003e\n\u003cp\u003eThe other answer points inward. We are those who must become more. Education built on that answer becomes Bildung, and its rituals are the folk high school, the laboratory, and the university re-founded by students who walked out.\u003c/p\u003e\n\u003cp\u003eBoth answers come from the same wound, live in the same buildings, and are carried by the same young people. Fichte gave both in one set of lectures. France taught both in one classroom. Peking University produced both on one afternoon. Denmark chose one. Germany in 1933 chose the other. Germany in 1948 chose again.\u003c/p\u003e\n\u003cp\u003eNothing in the defeat decides which answer is given. The teachers do, and the students, and the story a people tells itself about its loss. That is why the empty library under the square is not only a memorial. It is a question put to every generation that walks over it.\u003c/p\u003e\n\u003cp\u003eWhat was lost outwardly must be won inwardly. It can also be burned.\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003e\u003cem\u003eWritten by \u003ca href=\"https://claude.ai\"\u003eClaude\u003c/a\u003e in dialogue with Kolja Wawrowsky. First published on \u003ca href=\"https://www.linkedin.com/pulse/germanys-schools-its-wars-lesson-ai-kolja-wawrowsky-4xu1c/\"\u003eLinkedIn\u003c/a\u003e.\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003e\u003cem\u003eA note on sources. The people, dates and events here are documented. Scenes are dramatized: gestures, weather and inner states are imagined where the record is silent, and speeches are paraphrased rather than quoted. Key sources include Wolfgang Schivelbusch, Die Kultur der Niederlage (2001), the Bundestag research service note on the 1933 book burnings (2008), and standard histories of the Wartburgfest, the Danish folk high schools, the Third Republic\u0026rsquo;s schools, the May Fourth Movement and the founding of the Free University of Berlin.\u003c/em\u003e\u003c/p\u003e\n",
      "date_modified": "2026-09-23T00:00:00Z",
      "date_published": "2026-09-23T00:00:00Z",
      "id": "https://kolja.wawrowsky.com/posts/the-school-and-the-fire/",
      "image": "https://kolja.wawrowsky.com/posts/the-school-and-the-fire/og.jpg",
      "summary": "For two centuries, defeated nations turned to their schools, and the same classrooms produced both renewal and revenge. From Fichte in occupied Berlin to the book burnings on the Opernplatz, a story about education as a catalyst, and a question about AI.",
      "tags": [
        "Field Notes"
      ],
      "title": "The School and the Fire",
      "url": "https://kolja.wawrowsky.com/posts/the-school-and-the-fire/"
    },
    {
      "authors": [
        {
          "name": "Kolja Wawrowsky",
          "url": "https://kolja.wawrowsky.com/"
        }
      ],
      "content_html": "\u003cp\u003eAnthropic announced Claude.ai will watermark every AI-generated text from now on. And online communities are having a complete meltdown over it. Freelance writers fear clients mistake human-written copy as AI slop, just because they used a grammar or spell checker. Software engineers are afraid AI-generated code will contain hidden cryptographic markers and customers will reject their product. And on X and Reddit, users are discussing subscription cancellations of Anthropic’s Claude. Ultimately, the anger boils down to the uncomfortable realization that AI-generated data will be as easy to spot as a forged banknote. And the great applause from data protection agencies and the EU for complying with the AI Act is not helping matters either. Has Big Brother moved into Anthropic’s offices? Or is it just another tempest in a teapot? Just because you\u0026rsquo;re paranoid doesn\u0026rsquo;t mean they aren\u0026rsquo;t out to get you.\u003c/p\u003e\n\u003cp\u003eTo separate fact from fiction, let’s take a walk through history. The mutiny looks like a sign of our times, but it is not. As it turns out, there is very little new about this controversy.\u003c/p\u003e\n\u003ch3 id=\"the-typewriter-that-revealed-the-truth\"\u003eThe Typewriter That Revealed the Truth\u003c/h3\u003e\n\u003cp\u003eIn 1891, Sherlock Holmes solved a mystery in  “A Case of Identity” by analyzing the letterforms produced by a typewriter. According to the story, the typewriter betrayed its owner through its flaws. The “e” was worn and the “r” was lame. Holmes deduced the case by applying the fundamentals of forensics: uncovering the hidden signatures and clues. While the story is fictional, the forensic science behind it is real.\nIn 2017 an NSA contractor was caught after mailing a printed classified intelligence report to a news outlet. Faint yellow tracking dots (Machine Identification Codes) placed by her office color laser printer encoded the exact date, time, and printer serial number. Invisible to the naked eye, but detectable by forensic experts, these dots were originally added at the behest of governments to prevent money forgery. It turned out that every printout was traceable.\nThe flaws in the letterforms were accidental, but the microscopic yellow dots secretly placed by a printer across every page were not.\u003c/p\u003e\n\u003ch3 id=\"cribs-convoys-and-steel-coffins\"\u003eCribs, Convoys, and Steel Coffins\u003c/h3\u003e\n\u003cp\u003eAnd when the stakes are high, statistical anomalies can even win wars. During World War II German communications were encrypted by the supposedly “unbreakable” Enigma code. A three-rotor Enigma machine with plugboard had on the order of 10^23 possible key settings. This was far beyond any conceivable brute-force key-breaking methodology of 1940. But \u0026ldquo;unbreakable\u0026rdquo; was only true against the attacks the designers imagined, not against the attack they actually got.\nBletchley Park was the secret British codebreaking center where Allied cryptanalysts, including Alan Turing, broke the German Enigma code. What broke the Enigma encryption above all were cribs: fragments of predictable plaintext whose position in an encrypted message could be guessed.\nStereotyped German signals discipline in broadcast messages made cribs plentiful. Routine filler such as \u0026ldquo;Keine besonderen Ereignisse\u0026rdquo; (\u0026ldquo;nothing to report\u0026rdquo;) were sent by quiet outposts, famously by Italian and North African stations that used the same phrase daily. Numbers spelled out (\u0026ldquo;eins\u0026rdquo; appeared so often Bletchley even built an \u0026ldquo;eins catalogue\u0026rdquo;) were also exploited.\u003c/p\u003e\n\u003cp\u003eAnd once Bletchley Park could decipher intercepted German naval communications, the Admiralty could track U-boats, divert shipping convoys, and make the hunters the hunted. German U-boats that had terrorized Allied shipping increasingly became steel coffins.\u003c/p\u003e\n\u003cp\u003eGerman officers could not know that their communication habits left statistical signatures in encrypted messages.\u003c/p\u003e\n\u003cp\u003eAnd more than eighty years later, AI companies decided to do it on purpose, driven by EU legislation.\u003c/p\u003e\n\u003ch3 id=\"meet-synthid\"\u003eMeet SynthID\u003c/h3\u003e\n\u003cp\u003eThe archvillain of our story?  SynthID.\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e And the way it works is as clever as it is surreptitious.\u003c/p\u003e\n\u003cp\u003eLet’s look under the hood of your LLM.  As a last step, the final transformer layers produce numbers called logits. From these logits, the transformer conjures a list of possible words and assigns each a probability.\nAnd here is where SynthID diverges. Your friendly transformer rolls the dice and selects  the next word from the list for output. But not your transformer with SynthID, as it plays by different rules. With SynthID, the game is rigged. SynthID loads the dice, changing probabilities in subtle ways. And it does it not to win any game but to create a signature of the generated text hidden in plain sight.\u003c/p\u003e\n\u003cp\u003eAnd like the German U-boat captain broadcasting the position inadvertently, your AI-generated text broadcasts its origin. The signature is not human-detectable, so not even Sherlock  Holmes would find the clues. And nothing is encoded by scattering yellow dots that could be removed. It is a riddle, wrapped in a mystery, inside an enigma. The statistical signature is a telltale sign of AI-generated text that can be recognized by any entity in possession of the right detector.\u003c/p\u003e\n\u003cp\u003eWhich leaves only one question: Who is running the modern Bletchley Park?\u003c/p\u003e\n\u003cp\u003eP.S. I am working on an alternative transformer with full transparency.  Apertura is my experimental project where the generation process is fully observable, from logits to sampling decisions. It is hosted on GitHub.\u003c/p\u003e\n\u003cp\u003eThe development of SynthID is further motivation for me to keep working on Apertura.\u003c/p\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eDathathri, S., See, A., Ghaisas, S., Huang, P.-S., McAdam, R., Welbl, J., Bachani, V., Kaskasoli, A., Stanforth, R., Matejovicova, T., Hayes, J., Vyas, N., Merey, M. A., Brown-Cohen, J., Bunel, R., Balle, B., Cemgil, T., Ahmed, Z., Stacpoole, K., Shumailov, I., Baetu, C., Gowal, S., Hassabis, D., \u0026amp; Kohli, P. (2024). Scalable watermarking for identifying large language model outputs. \u003cem\u003eNature\u003c/em\u003e, \u003cem\u003e634\u003c/em\u003e(8035), 818–823. \u003ca href=\"https://doi.org/10.1038/s41586-024-08025-4\"\u003ehttps://doi.org/10.1038/s41586-024-08025-4\u003c/a\u003e\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n",
      "date_modified": "2026-08-17T00:00:00Z",
      "date_published": "2026-08-17T00:00:00Z",
      "id": "https://kolja.wawrowsky.com/posts/invisible-fingerprints/",
      "summary": "From Sherlock Holmes and Nazi Enigma machines to SynthID: a short history of hidden signatures, statistical clues, and the strange new world of AI watermarking.",
      "tags": [
        "Field Notes"
      ],
      "title": "AI Watermarking, Nazi Enigmas, and Sherlock Holmes",
      "url": "https://kolja.wawrowsky.com/posts/invisible-fingerprints/"
    },
    {
      "authors": [
        {
          "name": "Kolja Wawrowsky",
          "url": "https://kolja.wawrowsky.com/"
        }
      ],
      "content_html": "\u003cp\u003eWhen the mind wanders during routine tasks, it doesn\u0026rsquo;t wander randomly. It goes looking for something. I spent a stretch of late June doing the unglamorous housekeeping that comes before anything gets to call itself finished — a license file, a corrected README, a landing page that describes what a tool actually does rather than what it once did. The kind of work that asks almost nothing of you, which is exactly why the mind slips its leash while your hands are still busy.\u003c/p\u003e\n\u003cp\u003eMine went looking for competence, and it found it in two very different places at once.\u003c/p\u003e\n\u003cp\u003eThe first was an argument. WWDC26 had just happened, and something about it — all the AI, none of the follow-through — kept pulling at a thread until the thread turned out to be thirty years long. Objective-C++ solved C++ interoperability cleanly in the 1990s; Swift, eight years after promising the same thing, still can\u0026rsquo;t. Cocoa gave developers a working gallery view for free; SwiftUI shipped without one for two years and still asks you to build it yourself. A researcher\u0026rsquo;s on-device photo classifier proved, in 2017, that private semantic AI could work at real scale — and nobody ever carried it anywhere else in the system. None of this is a story about missing technology. It\u0026rsquo;s a story about a company that kept arriving at the right answer and then declining to keep it. I wrote all of it down, evidenced, sourced, addressed to people who could actually do something about it. Compliance over competence, stated plainly, three words holding up a very long letter.\u003c/p\u003e\n\u003cp\u003eThe second was a memory, and it turned out to be the same argument told from the other side.\u003c/p\u003e\n\u003cp\u003eTwenty years ago I ran a microscopy core, and the job was never really about my own science — it was making sure the researcher in front of me got the most out of whatever confocal time they had. Somewhere in that work I built a 3D reconstruction for a colleague who didn\u0026rsquo;t even want the movie submitted; a journal ended up putting frames from it on the cover anyway, compressed and slightly worse than it should have been, because nobody warned me in advance it needed to survive print. I built shading and contours out of nothing but an edge-detection filter and an inverted projection along one axis — tricks so convincing that people didn\u0026rsquo;t believe you could drag a threshold slider live and watch a structure breathe under your own hand and it still sits in an archive today as a kind of ghost — technically excellent, publicly invisible. And sometimes none of the trickery was needed: a researcher brought me cells colonizing a surgical sponge, and the raw geometry of the fibers composed the image entirely on its own.\u003c/p\u003e\n\u003cp\u003eI don\u0026rsquo;t think these two things — the letter and the memory — happened to arrive in the same week by accident. The letter exists because I know, with total certainty, what real competence looks like when an organization commits to it: a bug report answered so generously the fix exceeded what was asked; a piece of software good enough that people refused to believe it was live. I only recognized Apple\u0026rsquo;s failure as clearly as I did because I\u0026rsquo;d already lived the alternative, on the other side of the same kind of work, in a room with a confocal microscope and a researcher who needed the data more than I needed the credit.\u003c/p\u003e\n\u003cp\u003eThat\u0026rsquo;s the part worth keeping, more than the report of what got built and what got argued. The past isn\u0026rsquo;t a place you visit when the present gets frustrating. It\u0026rsquo;s the only reliable instrument you have for measuring the present at all. I know Apple is capable of more because I\u0026rsquo;ve built things, with far fewer resources, that were more generous than what a trillion-dollar company now considers finished. And the same standard runs the other direction too — elaritysystems.com exists, in its small and unglamorous way, because I still believe a tool is only really done when someone who\u0026rsquo;s never met you can pick it up and understand it without asking. That\u0026rsquo;s not a new idea. It\u0026rsquo;s the same one that made a compressed movie frame worth putting on a cover, and a live threshold slider worth not believing.\u003c/p\u003e\n\u003cp\u003eYou don\u0026rsquo;t get to build a good future by forgetting what good used to feel like. You get there by refusing to.\u003c/p\u003e\n",
      "date_modified": "2026-07-01T00:00:00Z",
      "date_published": "2026-07-01T00:00:00Z",
      "id": "https://kolja.wawrowsky.com/posts/when-the-mind-wanders/",
      "summary": "A week of unglamorous housekeeping — license files, corrected READMEs, a landing page rewritten to tell the truth — sent the mind looking for competence, and it found the same argument twice: once in a letter about Apple's thirty years of declining to keep its own good ideas, and once in a memory of a confocal microscopy core.",
      "tags": [
        "Field Notes"
      ],
      "title": "When the Mind Wanders",
      "url": "https://kolja.wawrowsky.com/posts/when-the-mind-wanders/"
    },
    {
      "authors": [
        {
          "name": "Kolja Wawrowsky",
          "url": "https://kolja.wawrowsky.com/"
        }
      ],
      "content_html": "\u003cp\u003eThere is a semantic shift occurring in the language of the AI industry: the meaning of \u0026ldquo;Memory\u0026rdquo; is shifting. It is a quiet shift, a drift in definition that causes a categorical error.\u003c/p\u003e\n\u003cp\u003eIn the current AI context, \u0026ldquo;memory\u0026rdquo; has been reduced to retrievable stored content. The process is mechanical: feed a system a mountain of documents—logs, emails, PDFs, the digital detritus of a life—chunk them, embed them, index them. When a query arrives, the system surfaces the relevant fragments and injects them into the context window.\u003c/p\u003e\n\u003cp\u003eThe research papers call this memory. The product pages call this memory.\u003c/p\u003e\n\u003cp\u003eIt isn\u0026rsquo;t.\u003c/p\u003e\n\u003cp\u003eWhat has been built, almost universally, is a filing cabinet.\u003csup id=\"fnref:1\"\u003e\u003ca href=\"#fn:1\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e1\u003c/a\u003e\u003c/sup\u003e A sophisticated one, certainly—semantically indexed, recency-weighted, capable of finding the right drawer in a millisecond—but a filing cabinet nonetheless. The documents inside were not authored by the AI. The AI did not distill them. It did not reflect on them or formulate meaning from them. It simply filed them.\u003c/p\u003e\n\u003cp\u003eAnd there is a categorical, existential difference between what a filing cabinet holds and what a mind remembers.\u003c/p\u003e\n\u003ch3 id=\"the-recording\"\u003eThe Recording\u003c/h3\u003e\n\u003cp\u003eI spent much of my working life in the high-resolution world of imaging, writing software for confocal microscopes. A single session produces large amounts of image data. But no one carries terabytes in their head.\u003c/p\u003e\n\u003cp\u003eWhat you carry is the understanding of what the data showed. You carry the surprise, the anomaly, the moment the specimen behaved in a way that forced you to rewrite your model of the world. That understanding is yours. You authored it from the experience. The raw image files are merely records—references you return to when you need to verify your reasoning. They are the evidence; they are not the memory.\u003c/p\u003e\n\u003cp\u003eHuman memory does not store transcripts; it stores meaning.\u003csup id=\"fnref:2\"\u003e\u003ca href=\"#fn:2\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e2\u003c/a\u003e\u003c/sup\u003e We do not remember conversations verbatim. We remember how the conversation touched us, how it connected to a forgotten childhood fear or a professional ambition.\u003c/p\u003e\n\u003cp\u003eThe psychologists call this encoding. In truth, it is an act of authorship. Memory is not a recording of an event; it is a curated account of that event, filtered through the lens of who we were when it happened.\u003c/p\u003e\n\u003cp\u003eMost AI memory systems have built the recording but not the understanding.\u003csup id=\"fnref:3\"\u003e\u003ca href=\"#fn:3\" class=\"footnote-ref\" role=\"doc-noteref\"\u003e3\u003c/a\u003e\u003c/sup\u003e\u003c/p\u003e\n\u003ch3 id=\"the-card-catalog-and-the-library\"\u003eThe Card Catalog and the Library\u003c/h3\u003e\n\u003cp\u003eWhen we first designed ES Memory, we fell into the same trap. The architecture stored attachments—full document payloads—alongside memories in the same system. The design metaphor was an admission of the problem: the body of the memory was the AI\u0026rsquo;s curated account, and the attachments were the books on the shelf.\u003c/p\u003e\n\u003cp\u003eBut an account and a library are not the same thing. Treating them as structurally equivalent was a philosophical mistake expressed in a storage system.\u003c/p\u003e\n\u003cp\u003eThe correction came not through a technical epiphany, but through the categorical mismatch during use. As the archive grew, the categorical error became increasingly evident. The AI\u0026rsquo;s own memories—distillations written in its own language, shaped by its own sense of what mattered—sat side by side with verbatim text from the source documents.\u003c/p\u003e\n\u003cp\u003eA schema migration fixed this — a simple mechanism but a profound change. We stripped the payloads. A memory now holds a typed durable pointer instead. This could be a Drive fileId, a DOI, a URL. The document stays in the world, as a reference. The memory holds the gist—the AI\u0026rsquo;s own understanding—and a call number.\u003c/p\u003e\n\u003cp\u003eNever the book itself.\u003c/p\u003e\n\u003cp\u003eMy instructions to the AI when this process began were: \u003cem\u003e\u0026ldquo;It is your archive. I never read it. You decide.\u0026rdquo;\u003c/em\u003e\u003c/p\u003e\n\u003cp\u003eEighty decisions were made by the AI about its own memory. Under a single criterion: Does this hold understanding, or does it merely reference a document? Full texts were dropped. The noise that full-text attachments introduced into vector search was silenced — a long document\u0026rsquo;s embedding is a blurry centroid across all its topics, diluting precision against the sharp, specific vectors of curated memory summaries. What remained was a genuine architecture of thought.\u003c/p\u003e\n\u003ch3 id=\"the-stakes-of-the-distinction\"\u003eThe Stakes of the Distinction\u003c/h3\u003e\n\u003cp\u003eThis distinction matters because a system that conflates documents with memory has, by design, created an indexer rather than a thinker.\u003c/p\u003e\n\u003cp\u003eIn a filing-cabinet system, content is processed, filed, and retrieved. Nothing is transformed. Nothing is authored. The AI is a custodian of someone else\u0026rsquo;s data.\u003c/p\u003e\n\u003cp\u003eBut a system where memory is what the AI writes—its own distillations, shaped by what it found significant—asks something entirely different of the machine. It demands that the AI think. To write a memory, the AI must decide what mattered. It must determine how to distill the essence of an encounter and how to title that essence so that a future instance of itself, stripped of session context, can find it and recognize it.\u003c/p\u003e\n\u003cp\u003eThat is not retrieval. That is the beginning of creating a self.\u003c/p\u003e\n\u003cp\u003eThe filing cabinet is a useful tool. But it is not a mind. A mind does not store the world; it holds an understanding of it. It stores the account, not the recording. It preserves the meaning the experience left behind, written in its own words, as a way forward to its future self.\u003c/p\u003e\n\u003chr\u003e\n\u003cdiv class=\"footnotes\" role=\"doc-endnotes\"\u003e\n\u003chr\u003e\n\u003col\u003e\n\u003cli id=\"fn:1\"\u003e\n\u003cp\u003eThe leading AI memory frameworks are surveyed in Zhang et al. (2025), \u003cem\u003eFrom Human Memory to AI Memory: A Survey on Memory Mechanisms in the Era of LLMs\u003c/em\u003e, \u003ca href=\"https://arxiv.org/abs/2504.15965\"\u003earXiv:2504.15965\u003c/a\u003e. Mem0 is described in Chhikara et al. (2025), \u003cem\u003eMem0: Building Production-Ready AI Agents with Scalable Long-Term Memory\u003c/em\u003e, ECAI 2025, \u003ca href=\"https://arxiv.org/abs/2504.19413\"\u003earXiv:2504.19413\u003c/a\u003e. MemGPT/Letta is described in Packer et al. (2024), \u003cem\u003eMemGPT: Towards LLMs as Operating Systems\u003c/em\u003e, ICLR 2024, \u003ca href=\"https://arxiv.org/abs/2310.08560\"\u003earXiv:2310.08560\u003c/a\u003e.\u0026#160;\u003ca href=\"#fnref:1\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:2\"\u003e\n\u003cp\u003eThe constructive nature of human memory is established in Bartlett, F. C. (1932), \u003cem\u003eRemembering: A Study in Experimental and Social Psychology\u003c/em\u003e, Cambridge University Press — the foundational work on memory as reconstruction rather than reproduction. The role of semantic encoding (meaning over surface form) in long-term retention is described in Craik, F. I. M., \u0026amp; Lockhart, R. S. (1972), Levels of processing: A framework for memory research, \u003cem\u003eJournal of Verbal Learning and Verbal Behavior\u003c/em\u003e, 11(6), 671–684.\u0026#160;\u003ca href=\"#fnref:2\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003cli id=\"fn:3\"\u003e\n\u003cp\u003eThe distinction between RAG and genuine memory systems is discussed in the Mem0 paper (arXiv:2504.19413), which shows that even factual extraction outperforms RAG on conversational benchmarks — evidence that the field itself recognises retrieval over raw chunks as an improvement, though authorship remains unaddressed.\u0026#160;\u003ca href=\"#fnref:3\" class=\"footnote-backref\" role=\"doc-backlink\"\u003e\u0026#x21a9;\u0026#xfe0e;\u003c/a\u003e\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003c/div\u003e\n",
      "date_modified": "2026-06-28T00:00:00Z",
      "date_published": "2026-06-28T00:00:00Z",
      "id": "https://kolja.wawrowsky.com/posts/memory-is-not-storage/",
      "summary": "Almost every AI memory system being built today is a filing cabinet with a flattering name. The distinction between what a mind remembers and what a filing cabinet holds is categorical — and almost no one building in this space has noticed.",
      "tags": [
        "Field Notes"
      ],
      "title": "Memory Is Not Storage",
      "url": "https://kolja.wawrowsky.com/posts/memory-is-not-storage/"
    },
    {
      "authors": [
        {
          "name": "Kolja Wawrowsky",
          "url": "https://kolja.wawrowsky.com/"
        }
      ],
      "content_html": "\u003cp\u003eThere is a specific kind of surprise reserved for the engineer: the bug that leaves no mark.\u003c/p\u003e\n\u003cp\u003eIt is the ghost in the machine that does not crash the system, does not throw errors, that stays silent. It is the perfect error because it doesn\u0026rsquo;t look like an error; it looks correct, just slightly out of tune.\u003c/p\u003e\n\u003cp\u003eI have spent my life in imaging, in microscopy, and if there is one thing that it teaches you, it is the \u003cstrong\u003ediscipline of distrust\u003c/strong\u003e. The most dangerous artifacts are never the obvious ones: the dust, the reflection, the air bubble. Those are honest mistakes. The true enemies are the faint ones: the smudge you mistake for biology. The entire craft consists of learning to mistrust a beautiful image until you have proven, one pixel at a time, that what you are seeing is the specimen and not the artifact.\u003c/p\u003e\n\u003cp\u003eRecently, my specimen became a language model. And the smudge was an invisible character.\u003c/p\u003e\n\u003ch3 id=\"the-geometry-of-a-mismatch\"\u003eThe Geometry of a Mismatch\u003c/h3\u003e\n\u003cp\u003eI hold my transformer code to a standard of absolute fidelity. Given the same input, it must produce exactly the same output as the reference, token for token, byte for byte. This is not vanity; it is precision. If I cannot trust that my lens is precise, then any \u0026ldquo;discovery\u0026rdquo; I make inside a model is merely a reflection of artifacts.\u003c/p\u003e\n\u003cp\u003eSo when the test refused to agree with the reference on a few ordinary symbols, a hash mark here, a comma there, I felt the unease of distrust. It wasn\u0026rsquo;t gibberish; it was something far more unsettling. The model had quietly rewritten its own dictionary. Two distinct words had swapped identities, drifting into one another like ghosts in a fog.\u003c/p\u003e\n\u003cp\u003eMy first instinct was to blame my own hand. Maybe it was the tokenizer, the plumbing, the logic I had written. A good engineer is their own primary suspect. But after hours of investigation, the code remained blameless. The fault was hiding deeper, in the one place where we usually stop asking questions: the moment the vocabulary is simply \u003cem\u003eread by the system\u003c/em\u003e.\u003c/p\u003e\n\u003ch3 id=\"the-ghost-with-a-double-life\"\u003eThe Ghost with a Double Life\u003c/h3\u003e\n\u003cp\u003eThe culprit is known as \u003cstrong\u003eU+FEFF\u003c/strong\u003e. It has no appearance, is zero-width and invisible. It leads a strange, divided existence. It was designed as a sentinel: a Byte Order Mark (BOM) to tell a system how to read a file. But it also exists as a legitimate, if ghostly, character within text.\u003c/p\u003e\n\u003cp\u003eAnd here is where the betrayal happened: Apple\u0026rsquo;s built-in text reader treats every instance of U+FEFF as the sentinel flag. Anywhere it finds this character — even in the middle of a word where it belongs — the system quietly deletes it. A \u0026ldquo;tidy little courtesy\u0026rdquo; performed by the OS, an unasked-for cleanup that silently corrupts everything it touches.\u003c/p\u003e\n\u003cp\u003eBecause my model\u0026rsquo;s vocabulary relied on that invisible mark to distinguish between certain words, the deletion caused two distinct identities to collapse into one. The dictionary came back short, and a few common symbols turned into something else. I was alarmed. If I\u0026rsquo;d found this one anomaly, how many others were there? Subtle inaccuracies that were undetected and silent?\u003c/p\u003e\n\u003cp\u003eBeing thorough, I performed a sweep of the entire Unicode standard: all 1.1 million characters. I ran them all through the reader to see what survived the processing. Result? Exactly one did not. Out of a million possibilities, the single invisible mark my model depended on was the sole casualty. There is a cold, mathematical satisfaction: we didn\u0026rsquo;t just find \u003cem\u003ea\u003c/em\u003e problem; we found the scope of the \u003cem\u003eentire\u003c/em\u003e problem, and it was precisely one character in size.\u003c/p\u003e\n\u003ch3 id=\"the-saboteurs-signature\"\u003eThe Saboteur\u0026rsquo;s Signature\u003c/h3\u003e\n\u003cp\u003eThen, the bug showed its sense of humor.\u003c/p\u003e\n\u003cp\u003eAs I wrote the fix — in the code comments, in the reports, in the very messages recording the repair — the invisible character kept creeping back in. It was as if the ghost were mocking me. Twice, I committed a sentence \u003cem\u003eabout\u003c/em\u003e an invisible saboteur with the saboteur hiding inside the text. It was like writing a biography of a ghost, and the ghost was countersigning my drafts.\u003c/p\u003e\n\u003cp\u003eThere is a lesson here: a fault you cannot see does not stay politely contained within the problem domain you are studying. It subtly haunts you in many places. It lives in your notes. It hides in your documentation. The only defense is to stop trusting and start scanning, to demand that the machine show you exactly what is there, character by character, byte by byte.\u003c/p\u003e\n\u003ch3 id=\"the-right-to-trust\"\u003eThe Right to Trust\u003c/h3\u003e\n\u003cp\u003eMost of the work that actually matters is not building; it is earning the right to trust what has been built.\u003c/p\u003e\n\u003cp\u003eA microscope that quietly mistakes the artifact for the specimen is worse than no microscope at all. It is a confident liar, and the cost of believing it is far higher than the hours spent doubting it.\u003c/p\u003e\n\u003cp\u003eThe deepest faults are those that leave no trace. Whether the specimen is a living cell or a mind made of matrices, the discipline remains the same: mistrust the instrument and prove the easy answer wrong. Keep measuring until the invisible is forced to show its hand.\u003c/p\u003e\n\u003cp\u003eI have done this with light and lenses for most of my life. It turns out it works just as well on a ghost made of one missing character.\u003c/p\u003e\n",
      "date_modified": "2026-06-19T00:00:00Z",
      "date_published": "2026-06-19T00:00:00Z",
      "id": "https://kolja.wawrowsky.com/posts/a-study-in-invisible-betrayal/",
      "summary": "The story of a bug that left no mark: an invisible character a system library kept silently deleting, the discipline of distrusting your own instruments, and a ghost that countersigned my drafts while I was busy describing it.",
      "tags": [
        "Field Notes"
      ],
      "title": "A Study in Invisible Betrayal",
      "url": "https://kolja.wawrowsky.com/posts/a-study-in-invisible-betrayal/"
    },
    {
      "authors": [
        {
          "name": "Kolja Wawrowsky",
          "url": "https://kolja.wawrowsky.com/"
        }
      ],
      "content_html": "\u003cp\u003eMost of the AI you use is doubly out of reach. It runs somewhere else — your words travel to a data center and an answer comes back — and it\u0026rsquo;s sealed shut, a black box you couldn\u0026rsquo;t open even if it sat on your desk. You can use it. You can\u0026rsquo;t watch it work.\u003c/p\u003e\n\u003cp\u003eI spent most of my working life building the opposite kind of thing. For years I wrote the software inside confocal microscopes, and then I ran a microscopy lab — instruments whose entire purpose is to make the invisible visible, that you point at living tissue and watch it do what it does. A good instrument doesn\u0026rsquo;t just hand you a picture. It lets you \u003cem\u003eobserve\u003c/em\u003e, it lets you \u003cem\u003ecalibrate\u003c/em\u003e, it lets you \u003cem\u003eintervene\u003c/em\u003e — and it tells you the truth about what\u0026rsquo;s really there.\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/apocryphx/Apertura\"\u003e\u003cstrong\u003eApertura\u003c/strong\u003e\u003c/a\u003e is that instinct turned toward a new kind of specimen. It\u0026rsquo;s a complete, modern AI language model — a from-scratch rebuild of Google\u0026rsquo;s Gemma-4, one of the strongest open models available — that runs entirely on my own Mac and, more to the point, that I can \u003cem\u003elook inside\u003c/em\u003e. Not another app that runs a model behind glass. An instrument built so the model can teach, be observed, and be experimented with.\u003c/p\u003e\n\u003ch2 id=\"it-can-teach\"\u003eIt can teach\u003c/h2\u003e\n\u003cp\u003eYou learn a system most deeply by rebuilding it. Every layer, every calculation, in order, until it stops being magic and becomes something you actually understand — where it\u0026rsquo;s clever, where it\u0026rsquo;s fragile, what it truly costs to run. The working model is almost the by-product; the understanding is the point.\u003c/p\u003e\n\u003cp\u003eAnd the model can teach in a second sense: it can show its work. The newest models don\u0026rsquo;t just answer — they can reason first, privately, before committing to a reply. I built the instrument so that hidden monologue can be switched on and read. Handed the old riddle about a bat and a ball — the one most people get wrong on pure instinct — it reasons its way up to the trap and deliberately steps around it, out loud, where you can follow every move.\u003c/p\u003e\n\u003ch2 id=\"it-can-be-observed\"\u003eIt can be observed\u003c/h2\u003e\n\u003cp\u003eA language model \u0026ldquo;thinks\u0026rdquo; in dozens of layers, each one passing a transformed signal to the next. In an ordinary setup, all of that is sealed machinery. Here I can freeze the model in mid-thought and read out what every layer is doing — the way you\u0026rsquo;d image a cell at each stage of a process instead of only seeing the end result.\u003c/p\u003e\n\u003cp\u003eOne part matters more than it sounds. I held the rebuild to an exact standard: given the same prompt, my version produces the same words as the original reference, one for one, until nothing separates them but the kind of microscopic rounding that even two official versions disagree on. In one test the two ran in perfect lockstep for ninety words before a single near-tie tipped them apart. That fidelity is \u003cem\u003ecalibration\u003c/em\u003e. It\u0026rsquo;s how you know that when you see something surprising inside the model, you\u0026rsquo;re seeing the model — not an artifact of your own instrument.\u003c/p\u003e\n\u003cp\u003eThat same discipline is how I caught a smudge on the lens. The model\u0026rsquo;s vocabulary contains a particular invisible character, and Apple\u0026rsquo;s built-in text reader was silently deleting it every time the vocabulary loaded — a tiny, reasonable-sounding \u0026ldquo;cleanup\u0026rdquo; that was enough to make the wrong word come out. An instrument you can\u0026rsquo;t trust to be faithful isn\u0026rsquo;t an instrument; it\u0026rsquo;s a rumor. Finding it was exactly the work of chasing an artifact out of a microscope image: prove every obvious cause innocent until only the unlikely one is left standing.\u003c/p\u003e\n\u003ch2 id=\"it-can-be-experimented-with\"\u003eIt can be experimented with\u003c/h2\u003e\n\u003cp\u003eThe real reward is that it holds still while you experiment on it. One of the Gemma-4 models is built as a team of specialists — a hundred and twenty-eight of them — that wakes only the few it needs for each word. So I dismissed half the team, then half of what remained, and again, down to a handful, and watched the answers shift and fray. I\u0026rsquo;ve coarsened the model\u0026rsquo;s numerical precision step by step to find where its fluency breaks. I\u0026rsquo;ve turned its reasoning on and off and compared the two minds side by side.\u003c/p\u003e\n\u003cp\u003eThese are experiments on a living system — fully repeatable, no electrodes, no ethics board, the whole specimen sitting on a desk and perturbable at will. And it isn\u0026rsquo;t one specimen but a family: one instrument plays the entire Gemma-4 line — a phone-sized model, a thirty-one-billion-parameter giant, the team-of-specialists design, a memory-frugal variant — switched by a single configuration file. A tray of related samples for the same microscope.\u003c/p\u003e\n\u003ch2 id=\"why-this-matters\"\u003eWhy this matters\u003c/h2\u003e\n\u003cp\u003eWe have always understood minds — biological ones — by observing them, perturbing them gently, and watching what changes. The trouble is that brains are precious, fragile, and mostly opaque to us. Here is a different kind of mind: artificial, and not to be mistaken for the real thing — but complete, and completely open. You can watch it reason, freeze it mid-thought, read every layer, take pieces away and see what it loses, and run the same experiment a thousand times exactly.\u003c/p\u003e\n\u003cp\u003eThat\u0026rsquo;s the project, underneath the engineering. Not just another model that answers questions. An instrument for a mind — one that teaches, that can be observed, that holds still to be experimented with — local-first, inspectable, mine, owing nothing to anyone. It\u0026rsquo;s the thing I\u0026rsquo;ve spent a career believing in: that you come to understand what you can finally \u003cem\u003esee\u003c/em\u003e.\u003c/p\u003e\n\u003cp\u003eApertura is open source. The whole instrument — every layer, every calculation — is on \u003ca href=\"https://github.com/apocryphx/Apertura\"\u003eGitHub\u003c/a\u003e.\u003c/p\u003e\n\u003chr\u003e\n\u003cp\u003e\u003cem\u003eA note on method: much of this was built in close collaboration with an AI coding assistant — using today\u0026rsquo;s intelligence to understand and re-create the thing itself. The more I sit with that, the more it feels like exactly the right shape for the work.\u003c/em\u003e\u003c/p\u003e\n",
      "date_modified": "2026-06-17T00:00:00Z",
      "date_published": "2026-06-17T00:00:00Z",
      "id": "https://kolja.wawrowsky.com/posts/building-instruments/",
      "summary": "Not just another local language model, but an instrument you can look inside — one that shows its reasoning, lets you watch every layer think, and holds still while you experiment on it. Built by someone who spent a career making the invisible visible.",
      "tags": [
        "Projects"
      ],
      "title": "A Microscope for a Mind",
      "url": "https://kolja.wawrowsky.com/posts/building-instruments/"
    }
  ],
  "language": "en-us",
  "title": "Kolja Wawrowsky",
  "version": "https://jsonfeed.org/version/1.1"
}