<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dimon</title>
    <description>The latest articles on DEV Community by Dimon (@dimonb19a).</description>
    <link>https://dev.to/dimonb19a</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3963235%2Fef7373cd-e19d-4adb-bd0b-1d9ae1e5c5e1.png</url>
      <title>DEV Community: Dimon</title>
      <link>https://dev.to/dimonb19a</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dimonb19a"/>
    <language>en</language>
    <item>
      <title>Kinewright Humans: the map — what it owns, where the data comes from, what comes next</title>
      <dc:creator>Dimon</dc:creator>
      <pubDate>Tue, 22 Sep 2026 17:45:37 +0000</pubDate>
      <link>https://dev.to/dimonb19a/kinewright-humans-the-map-what-it-owns-where-the-data-comes-from-what-comes-next-5cmc</link>
      <guid>https://dev.to/dimonb19a/kinewright-humans-the-map-what-it-owns-where-the-data-comes-from-what-comes-next-5cmc</guid>
      <description>&lt;p&gt;Kinewright is a house of motion engines. Humans is the first engine. This article is the plan for that engine as it stood in September 2026, written down once and left as it is: what the engine does itself, what it deliberately takes from outside, which published data it leans on and how that data is allowed in, and what was planned to happen before each next step.&lt;/p&gt;

&lt;p&gt;I will not update this article. It is the starting point, kept so that later changes can be read against it. The living version is the pinned post on &lt;a href="https://www.reddit.com/r/Kinewright/" rel="noopener noreferrer"&gt;r/Kinewright&lt;/a&gt;; it changes when a stage closes or the order moves. And the order does move, not only by my decision: I posted the first video, a reader said the torso looked held, we checked, agreed, and a correction that was not in the plan went in front of the next stage the next day. That is the kind of change this article is a baseline for.&lt;/p&gt;

&lt;p&gt;There are no dates in it, on purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  One sentence, one level
&lt;/h2&gt;

&lt;p&gt;Humans turns a supported body, a motion skill, scene constraints, a motor style, a seed and time into a canonical stream of three-dimensional poses, contacts and events. It produces motion state, not pixels.&lt;/p&gt;

&lt;p&gt;Its level at the time of writing is &lt;strong&gt;kinematic&lt;/strong&gt;. Gravity, ballistic flight and the lean of a braking body are used as identities with a known source; nothing is dynamically simulated, and no balance or physical validation is claimed. Every step below names the highest claim it may make on one ladder:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Level&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Kinematic&lt;/td&gt;
&lt;td&gt;poses and contacts meet declared geometric and timing checks; this does not establish forces or physical validity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Physics-informed&lt;/td&gt;
&lt;td&gt;kinematic motion shaped by named physical identities, without simulation or balance claims&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Static balance checked&lt;/td&gt;
&lt;td&gt;projected centre of mass and support polygon pass declared quasi-static checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dynamically checked&lt;/td&gt;
&lt;td&gt;momentum, contact forces, centre of pressure or capture-point reasoning pass declared checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Simulated on&lt;/td&gt;
&lt;td&gt;a named slice ran on a named dynamics provider build&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hardware validated on&lt;/td&gt;
&lt;td&gt;validated on exactly named hardware through a separately proven physical stack&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A motion that passed a kinematic or visual gate is never described as physically validated. The accepted locomotion sits at physics-informed; the stages that follow are kinematic.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the engine owns, and what it is meant to own
&lt;/h2&gt;

&lt;p&gt;At the start the implementation centres on one reference body's locomotion, contact timing, command handling and replay. General body compatibility, marker-based warping and a durable runtime journal are contracts on the plan, not capabilities the first video demonstrates.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Intent.&lt;/strong&gt; Commands, their order, a fixed tick. A command is answered at a declared safe boundary, never mid-air by accident.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Contacts and their owners.&lt;/strong&gt; Which foot is on the ground, when, where; who owns each contact when something else is involved.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Markers and admissible warps.&lt;/strong&gt; The named moments a motion may be cut, joined or warped at (touchdown, toe-off, takeoff, landing) and by how much.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Capabilities and honest answers — planned contract.&lt;/strong&gt; Each skill–body pairing is intended to resolve to native, adapted, fallback or unsupported with a diagnostic. At the start there is one supported body, not a delivered general compatibility platform.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Expected supports.&lt;/strong&gt; What the engine believes holds the body up.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Diagnostic truth and replay.&lt;/strong&gt; Silent NaN, silent target dropping and undocumented clamping are treated as violations. Identical versions, body, scene, configuration, initial state, seed and ordered commands at the same fixed time steps must replay the same motion state; this does not promise identical pixels across renderers or arbitrary future physics backends.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Concretely that is the rig and its limits, forward kinematics and a bounded solver, the locomotion profiles (cadence, step, duty factor, timing of contacts, root motion, start, stop, transitions), the scheduler, and the renderer-adapter boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it will consume, by design
&lt;/h2&gt;

&lt;p&gt;The list is finite on purpose. An infinite adapter list cannot define readiness, so every item here has a named slice and a named claim.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Physics.&lt;/strong&gt; Not written here. An optional dynamics provider owns dynamic realization, collision response, external impulses and stability enforcement under an explicit ownership contract with seven named handoffs (grounding and support, collision queries and responses, carried-object authority, grasp and release, external impulses, replanning and fallback, deterministic replay and diagnostics). The actor stays the kinematic authority by default; a provider may own named objects and, only under an explicit handoff, named body parts. When animation intent and physics disagree, the contract names the owner of every contact; nothing is resolved silently. First provider candidate: Rapier, one slice.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rendering.&lt;/strong&gt; The engine does not draw. What the videos show is a plain Canvas 2D reference renderer projecting the canonical 3D state. First real lane later: Three.js with glTF/GLB transport. Renderer bone names, camera assumptions and drawing styles never leak into the motion model.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Avatars and retargeting.&lt;/strong&gt; A generic humanoid mapping first, then VRM 1.0 and VRMA conformance. Having a specification does not license an asset; each avatar is its own rights question, and no automatic retargeting is promised.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Navigation.&lt;/strong&gt; Recast/Detour for paths and corridors. The engine keeps the footholds and the body heading.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The scene.&lt;/strong&gt; A small contract: named surfaces, affordances such as "seat", "grasp" or "ground", target transforms, and collision or reachability only when a backend provides it. The engine never guesses that a mesh is a chair, and ground is not implicitly at zero; the scene says where it is.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Input, game engines, motors.&lt;/strong&gt; Adapters. DOM events and frame timing are adapter inputs, not scheduler state. The engine is not a game engine and will never claim it drives a robot from a browser; physical embodiment needs a separately proven stack and is a far-future, optional direction only.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Workers, WASM or WebGPU come only after a measured hotspot at 1, 16, 32 and 64 actors. Other renderers or physics backends come when someone actually needs them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the data comes from, and how it is allowed in
&lt;/h2&gt;

&lt;p&gt;The engine core ships no third-party data. Every number taken from a dataset lives in a separate pack under the dataset's own licence, with the exact artifact and its hash pinned. Retargeting, smoothing, fitting or changing the file format does not wash away an upstream obligation. Nothing is admitted because it appears in a paper or in another engine.&lt;/p&gt;

&lt;p&gt;Every constant carries a status: measured, aggregated, derived, engineering or estimated. Nearly every constant in the core at the start is an engineering choice, and it is labelled as one; "measured" is reserved for what a source actually reports.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In use at the start&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;What it provides&lt;/th&gt;
&lt;th&gt;Licence&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://stacks.cdc.gov/view/cdc/248281" rel="noopener noreferrer"&gt;NIOSH firefighter anthropometry&lt;/a&gt;, RD-1007-2015-0 (951 US firefighters, 2008–2012)&lt;/td&gt;
&lt;td&gt;body proportions as fractions of stature for the one supported body; silhouette anchors&lt;/td&gt;
&lt;td&gt;US public domain&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fukuchi et al., &lt;a href="https://doi.org/10.6084/m9.figshare.5722711.v5" rel="noopener noreferrer"&gt;walking biomechanics dataset v5&lt;/a&gt; (WBDS; &lt;a href="https://doi.org/10.7717/peerj.4640" rel="noopener noreferrer"&gt;PeerJ 4640&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;sagittal pelvis, hip, knee and ankle curves of treadmill walking&lt;/td&gt;
&lt;td&gt;CC BY 4.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fukuchi et al., &lt;a href="https://doi.org/10.6084/m9.figshare.4543435.v5" rel="noopener noreferrer"&gt;running biomechanics dataset v5&lt;/a&gt; (RBDS; &lt;a href="https://doi.org/10.7717/peerj.3298" rel="noopener noreferrer"&gt;PeerJ 3298&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;duty factor and knee-flexion anchors at 2.5, 3.5 and 4.5 m/s; one of the sources shaping the product run&lt;/td&gt;
&lt;td&gt;CC BY 4.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;The same RBDS raw markers&lt;/td&gt;
&lt;td&gt;spatial curves and reconstructed joint centres, used at the application's carrier layer&lt;/td&gt;
&lt;td&gt;CC BY 4.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Riglet et al. 2024, &lt;a href="https://doi.org/10.6084/m9.figshare.25592865.v1" rel="noopener noreferrer"&gt;run/walk 3D motion dataset v1&lt;/a&gt; (&lt;a href="https://doi.org/10.1038/s41597-024-03420-y" rel="noopener noreferrer"&gt;Scientific Data&lt;/a&gt;)&lt;/td&gt;
&lt;td&gt;four arm-relative channels in steady running; not a thorax or root-motion prior&lt;/td&gt;
&lt;td&gt;CC0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Research and validation inventory — not runtime carriers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://doi.org/10.6084/m9.figshare.14558181.v1" rel="noopener noreferrer"&gt;Reznick et al. 2021&lt;/a&gt;, continuously varying locomotion (walk↔run transitions; Scientific Data; CC0). Biancardi, Lagos-Hausheer and Bona, treadmill walking, running and transitions (Dataverse &lt;a href="https://doi.org/10.60895/redata/PK1DCE" rel="noopener noreferrer"&gt;10.60895/redata/PK1DCE&lt;/a&gt;; PeerJ 18162; CC BY 4.0). Calisti et al., countermovement-jump landings (&lt;a href="https://doi.org/10.6084/m9.figshare.28890545.v1" rel="noopener noreferrer"&gt;dataset v1&lt;/a&gt;; CC BY 4.0). Two anthropometry sets are recorded as candidates with nothing extracted. Independent review of the three motion packages above was still pending at the time of writing; listing them is not a claim of completed runtime admission.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Method references, reimplemented without importing coefficients&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hof 2005 (the extrapolated centre of mass, ξ = x + v/ω₀); Wang and Srinivasan 2014 (pelvis state predicts the next lateral foot placement); Kwon et al. 2023 (planned stopping begins braking before the final contact); Mesquita et al. 2024 (curved running: straight flight, redirection owned by stance); Oosterwaal et al. 2016 and Arnold et al. 2017 (the foot is not one rigid block); Hof, Pratt and Vukobratović for capture point and zero-moment point, held for the balance rungs of the ladder. In every case the gain, cap or eligibility rule is an authored engineering control, not a claim about the publication.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deliberately not used&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;AMASS and SMPL (non-commercial terms: no clips, retargeted motion, fitted tables, embeddings or weights may enter a release); the CMU motion-capture database (broad reuse, but not MIT or CC0); one curved-running dataset whose licence was never declared. The engine will not ship identity reconstruction, gait identification or demographic classifiers, and population labels describe source evidence, never a "personality preset".&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ranges we read our results against&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When we look at a motion we compare its figures with published adult ranges, and those ranges stay in the record; they never enter the engine. Trunk obliquity and rotation in gait (Crosbie et al.), pelvic rotation in walking and running, thorax–pelvis coordination versus speed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The plan as it stood: stages and dependencies
&lt;/h2&gt;

&lt;p&gt;A step gets a size only after its definition of ready is frozen. Sizes here are the kind of work and a rough band in engineering passes and owner looks: planning envelopes, not a calendar.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;What it delivers&lt;/th&gt;
&lt;th&gt;Kind of work&lt;/th&gt;
&lt;th&gt;Band&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;Forward locomotion&lt;/td&gt;
&lt;td&gt;steady walk, steady run, walk to run, run to walk&lt;/td&gt;
&lt;td&gt;cycle synthesis, contacts and seams, arm swing, a blinded braking-lean ladder&lt;/td&gt;
&lt;td&gt;closed; five review packets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;td&gt;Stand, start, stop and command interruption&lt;/td&gt;
&lt;td&gt;stand, start as the release of stop, stops from a walk and a run, commands answered at safe boundaries; one named condition carried forward (the hard landing foot on the last braking steps)&lt;/td&gt;
&lt;td&gt;thirteen lanes behind gates, eleven review packets&lt;/td&gt;
&lt;td&gt;closed; about a month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Runtime step planner&lt;/td&gt;
&lt;td&gt;the next step planned at runtime instead of a precompiled track: a tap gives exactly one step, stop during start, shift back and forth mid-transition, a landing foot that arrives like the walk's&lt;/td&gt;
&lt;td&gt;a small runtime substrate (descriptor, fixed tick, ordered commands, deterministic random streams, durable event journal) and the planner on it; steady walk and run byte-identical, transitions re-accepted&lt;/td&gt;
&lt;td&gt;medium; up to 3 looks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Playable controller&lt;/td&gt;
&lt;td&gt;WASD, Shift and Space on the planner: desired speed and response policy, contact-safe steering, a camera that does not feed back&lt;/td&gt;
&lt;td&gt;policy, steering, input contract, arena&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Closing the foundation&lt;/td&gt;
&lt;td&gt;continuity across the whole chain of states and reversals; visible feet and hands (renderer only, no new joints); directional readability; one integrated review of everything&lt;/td&gt;
&lt;td&gt;gates, a renderer branch, a full packet&lt;/td&gt;
&lt;td&gt;medium to large; several looks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Jump family&lt;/td&gt;
&lt;td&gt;standing, walking and running jumps on the planner, ballistic flight as an identity&lt;/td&gt;
&lt;td&gt;markers, bounded warps, contact schedules&lt;/td&gt;
&lt;td&gt;medium; one batched look&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Core boundary and first adapter&lt;/td&gt;
&lt;td&gt;intent, tick, pose frame, events, snapshot and replay behind a renderer-neutral seam; a thin Three.js + glTF/GLB adapter; capability contract v0&lt;/td&gt;
&lt;td&gt;architecture discipline, not a public API&lt;/td&gt;
&lt;td&gt;small&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Skill platform and scene objects&lt;/td&gt;
&lt;td&gt;stable skills, a broader transition realizer, scene objects that are explicitly not physics yet&lt;/td&gt;
&lt;td&gt;platform&lt;/td&gt;
&lt;td&gt;medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Body compatibility and functional hold&lt;/td&gt;
&lt;td&gt;other bodies with honest native/adapted/fallback/unsupported answers; holding an object with real grip semantics before any grasp claim&lt;/td&gt;
&lt;td&gt;contracts and conformance bodies&lt;/td&gt;
&lt;td&gt;unsized until its definition&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Articulated hands&lt;/td&gt;
&lt;td&gt;wrist, thumb and digits; grasp and release from a named taxonomy&lt;/td&gt;
&lt;td&gt;a rig revision and a rerun of every earlier gate&lt;/td&gt;
&lt;td&gt;unsized&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;Catalog waves&lt;/td&gt;
&lt;td&gt;roughly 20 everyday actions, then 60, then 100&lt;/td&gt;
&lt;td&gt;skills, in waves&lt;/td&gt;
&lt;td&gt;large&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Multi-actor&lt;/td&gt;
&lt;td&gt;two actors, then 4–12, then dozens; coordinated interaction sessions; a deterministic scene director with no language-model planner in the first version&lt;/td&gt;
&lt;td&gt;isolation, sessions, a 1/16/32/64 benchmark&lt;/td&gt;
&lt;td&gt;large&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11&lt;/td&gt;
&lt;td&gt;Integrations&lt;/td&gt;
&lt;td&gt;generic humanoid + VRM/VRMA; the Rapier slice; the Recast/Detour slice&lt;/td&gt;
&lt;td&gt;interleaved with catalog and multi-actor work, not postponed until both finish&lt;/td&gt;
&lt;td&gt;bounded slices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;World profile, static balance, dynamics contract&lt;/td&gt;
&lt;td&gt;gravity, friction and mass with provenance; balance as a claimed capability; the seven handoff contracts with a provider&lt;/td&gt;
&lt;td&gt;contracts and evidence&lt;/td&gt;
&lt;td&gt;unsized&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;13&lt;/td&gt;
&lt;td&gt;Full-scene gate&lt;/td&gt;
&lt;td&gt;a 32-actor reference world, a 64-actor stress test, a truthful capability matrix&lt;/td&gt;
&lt;td&gt;evidence at scale&lt;/td&gt;
&lt;td&gt;gate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;Public engine gate&lt;/td&gt;
&lt;td&gt;clean-room packages, a public API, versioning and migration policy, documented limitations, notices&lt;/td&gt;
&lt;td&gt;hardening&lt;/td&gt;
&lt;td&gt;gate; opening the code is a separate decision&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Corrections between stages are not rows of this table. The pelvis and chest coordination pass now in progress, started by the first outside comment on the first video, is one of those: a fix inside the accepted foundation, tracked in the pinned post, not a stage of the plan.&lt;/p&gt;

&lt;p&gt;The numbering groups work; it is not a strictly serial schedule. Avatar integration can overlap the first catalog and multi-actor work. The dynamics ownership contract comes before the Rapier slice, and that slice before catalog actions requiring dynamic objects. Navigation integration comes before the crowd/navigation stage. Coordinated two-person interactions likewise depend on their multi-actor contracts.&lt;/p&gt;

&lt;p&gt;Optional and outside the main envelope: bounded seeded variation (cadence, step, arms, gaze and breathing with correlated memory, never per-frame noise and never contact drift), toe articulation, compensatory motion for missing or alternate limbs, dynamic plausibility checks, and physical embodiment.&lt;/p&gt;

&lt;p&gt;A second comment on the same video already points at one of those optional items: the motion looks "too perfect", a human would not repeat the same action. That repetition is real and deliberate at the start, because the accepted cycles are the regression anchor of everything built on them; the answer to it is the seeded-variation item, and whether it moves up the list will be a decision recorded with its reason, visible in the pinned post, not here.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this article is not
&lt;/h2&gt;

&lt;p&gt;It is not a promise of dates. It is not a physics claim; the ladder above is the only vocabulary for that. It is not a code release; that is a separate decision with its own gate. It does not describe the second engine of the house, which gets its own map. And it is not the current plan: it is the plan at the start. Outside feedback is research input we measure against; a change of order is a decision recorded with its reason; both show up in the pinned post on &lt;a href="https://www.reddit.com/r/Kinewright/" rel="noopener noreferrer"&gt;r/Kinewright&lt;/a&gt;, which is the only version of this map that moves.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to help
&lt;/h2&gt;

&lt;p&gt;Watch the clips, answer the two questions — does it respond the way you expect, does it look natural — and say what you saw. The torso correction now in progress exists because one reader did exactly that, and this article exists so that the next such change has something to be read against.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>3d</category>
    </item>
    <item>
      <title>Kinewright Humans: How a runner stops</title>
      <dc:creator>Dimon</dc:creator>
      <pubDate>Mon, 21 Sep 2026 13:31:31 +0000</pubDate>
      <link>https://dev.to/dimonb19a/kinewright-humans-how-a-runner-stops-3abg</link>
      <guid>https://dev.to/dimonb19a/kinewright-humans-how-a-runner-stops-3abg</guid>
      <description>&lt;p&gt;Kinewright is a house of motion engines. Humans is a headless TypeScript engine that turns a body, a motion skill, a stream of commands, time and a seed into a deterministic stream of 3D poses and contacts. It outputs motion, not pixels. The picture in the videos is a plain Canvas 2D reference renderer; the engine is what moves it.&lt;/p&gt;

&lt;p&gt;The level today is kinematic. There is no physics engine underneath: no forces, no ground reaction, no balance. Every number in this article is an engineering threshold that the motion was built to, not a measurement of anything.&lt;/p&gt;

&lt;p&gt;Before this stage the engine could walk, run, go from a walk into a run and from a run into a walk, and both of those transitions had been accepted by us, the two people who look at every result. This stage asked for the rest of ordinary locomotion: standing, starting, stopping from a walk, stopping from a run, and commands that interrupt each other. The hard part turned out to be the last stop.&lt;/p&gt;

&lt;h2&gt;
  
  
  The video
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7dg4upk8wesdv33l9mn7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7dg4upk8wesdv33l9mn7.gif" alt=" " width="640" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;18 seconds, real time, rendered at 60 fps on a fixed-step clock, nothing hand-animated; the GIF here plays it back at 15 fps. It was rendered from the exact bytes we accepted the stage on.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;time&lt;/th&gt;
&lt;th&gt;what happens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0.0–0.8 s&lt;/td&gt;
&lt;td&gt;standing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;0.8–3.3 s&lt;/td&gt;
&lt;td&gt;start: a weight transfer, then the first accelerating steps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.3–5.3 s&lt;/td&gt;
&lt;td&gt;steady walk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5.3–7.0 s&lt;/td&gt;
&lt;td&gt;the run command lands; walk to run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7.0–12.9 s&lt;/td&gt;
&lt;td&gt;steady run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12.3 s&lt;/td&gt;
&lt;td&gt;the stop command lands while running; braking begins at 12.9 s at the run's own boundary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12.9–16.7 s&lt;/td&gt;
&lt;td&gt;four braking steps, the run settles into a walk step by step, then the walk's own stop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16.7–18.3 s&lt;/td&gt;
&lt;td&gt;standing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One thing to watch at about 14.9–15.3 s, on the last two braking steps of the run exit: the foot is put down hard. It reaches the ground while still rising and stops dead, where a walking or running foot comes down onto it. We accepted it as it is at this stage and will rework it later, in the step planner that places each foot from the body's speed plan and brings it down onto the ground. The rest of this article explains what you are seeing, in order, and ends with that foot.&lt;/p&gt;

&lt;p&gt;Three short clips accompany the article, at 30 fps: a steady walk, a steady run, and stand → start → two steps → stop. They are the same engine on the same scene; the walk and the run are the previously accepted motions the new ones had to join.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxgm4otmg8yaelo8vuznf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxgm4otmg8yaelo8vuznf.gif" alt=" " width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa449cwwkbcbkspqe15hs.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa449cwwkbcbkspqe15hs.gif" alt=" " width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv1nhig8oogb67b5rmjyo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fv1nhig8oogb67b5rmjyo.gif" alt=" " width="720" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Standing
&lt;/h2&gt;

&lt;p&gt;A stand is a hold, not a pose with sway. There is no breathing and no micro-movement in it, on purpose: a living idle is a separate piece of work and it was not faked with noise. The stand is entered when a stop completes and left when the stop is released. It was checked to hold the same pose and the same two foot contacts for a five-second dwell at real time, six hundred frames, with no event and no drift.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting
&lt;/h2&gt;

&lt;p&gt;A start is a weight transfer and then a step. The accepted start the engine already had took 0.8 s to prepare the first step and used three accelerating steps. We wanted a start that begins at once, so the product start prepares for 0.35 s and takes two accelerating steps, and the walk it settles into is the accepted walk unchanged. Movement begins 0.3989 s after the command against a bound of 0.4 s. That is a margin of one millisecond and it is stated as one.&lt;/p&gt;

&lt;p&gt;The first version was refused before any formal look: it unlocked the legs and sat down before the first step, where a person simply begins with a step. The crouch and the return to neutral were removed. What was left after that was a 2.26 mm step down at the instant movement starts, the descent to walking height that the crouch used to carry. It is now blended across the first step, so the pelvis leaves standing height continuously and is at walking height when the foot lands.&lt;/p&gt;

&lt;p&gt;That costs one thing, said here rather than left to be found: the planted foot floats 0.21 mm above the ground for about 0.13 s while the pelvis is still high. It is twice the tolerance the stage holds its seams to, nothing penetrates the ground, and we accepted it rather than hide it.&lt;/p&gt;

&lt;p&gt;Later, a frame-by-frame check added for a different reason found two more defects in the start that nobody had seen: the root, the head and both hands stepped 20.6 mm sideways between two frames, once at each foot's liftoff. The cause was a membership test. A standing foot held the pelvis back by its reach as long as it was "on the ground", so when the foot left the ground the restraint left with it and the answer stepped. A foot now holds the pelvis back in proportion to the weight it still carries, and the jump is gone.&lt;/p&gt;

&lt;p&gt;Two things a start does not do yet. A stop pressed during a start still costs a full stopping motion, seven foot contacts, where we wanted at most one more. And a tap of the walk command does not give exactly one step: it also costs seven contacts and reaches the hold 3.29 s after the release. Both are transferred to the next substrate, a runtime step planner, as not met. The reason is structural: the one route that could deliver a single step, a weight transfer, one step and a brake from that step's low speed, is entered at a foot contact that is still accelerating at 0.6 m/s, and this compiler lays out exactly one route with the stop always last.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stopping from a walk
&lt;/h2&gt;

&lt;p&gt;A stop is a motion request, not a pause. From a walk the engine enters the accepted braking motion at the nearest foot contact of either foot, half a walk cycle at worst, and brakes over two steps into standing. The braking is the accepted chain's own: 0.48 s down to 0.9 m/s, then 0.58 s to rest. What changed is only where it may be entered: at the contact the deceleration begins on, rather than a stride and a half before it.&lt;/p&gt;

&lt;p&gt;The first version was refused before any formal look, as a jerk. It put the whole deceleration into one short step. The second version, entering the accepted deceleration where it begins, was the one we looked at.&lt;/p&gt;

&lt;p&gt;We refused its ending. After the feet came together, both knees straightened and pressed down at once as one last movement, where naturally one leg finishes completely and then the other, with no such movement at all. The closing was rebuilt around that sentence: the supporting leg is straight at the last contact; the closing leg lands bent at 13.7° and straightens to 0.01° as it takes the weight; the pelvis rises inside the last step; and nothing moves once the feet are together. What is left after the feet meet went from 0.170 s to 0.065 s, and the torso arrives upright with the feet instead of unwinding for 0.18 s after them.&lt;/p&gt;

&lt;p&gt;To make the supporting leg reach full extension before the contact rather than on it, the pelvis rolls toward the supporting leg across the last step, by that leg's own reach deficit, under a 3° ceiling. Two earlier attempts had returned the straight leg as geometrically impossible; the argument held for a level pelvis only.&lt;/p&gt;

&lt;p&gt;On the next look we refused the upper body: the torso shook side to side and the shoulders swung too far, and from a walk into a stop it leaned to the right. The 3° of pelvis roll was arriving whole at the shoulders, 3.04° of shoulder line and 34 mm of head travel, where the accepted closing had 0.11° and 2.5 mm. The walk's own pelvic obliquity lives in the pelvis joint and the spine already counters about two thirds of it; the closing roll had been applied underneath everything. The spine now counter-rolls the closing's roll, split between lumbar and thoracic by a ratio read off the rig's own spine offsets, so the head stays over the pelvis as well as the shoulder line staying level: 0.057° of shoulder line against a bar of 0.62°, 1.28 mm of head against a bar of 12 mm. It can move no foot, because both hips hang from the pelvis and nothing above the lumbar can reach one.&lt;/p&gt;

&lt;p&gt;One request from that look was declined with its price on the table. We asked for the pelvis to level after the contact across the closing leg's weight acceptance, about 0.13 s, rather than the 0.05 s it takes. It cannot, because the roll is the supporting leg's reach deficit and the deficit is what is left of the pelvis's rise; they are one motion. Forcing the window open lifts the supporting foot 1.8 mm off the ground for the whole of it. I read that and kept 0.05 s.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stopping from a run
&lt;/h2&gt;

&lt;p&gt;This is where the stage spent most of its time. We refused one motion six formal looks in a row, each time at a finer grain, and each refusal is in the video's history.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. It walked first.&lt;/strong&gt; The first version reused the walk's stop, so a running character went into a walk and walked about three and a half steps before stopping. We refused it: stop at once, and from a run go into walking and stop, not walk for a while.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. A direct route.&lt;/strong&gt; The engine now leaves the run at the run's own boundary into a dedicated run-to-stand motion: it decelerates on braking steps to the point where the gait becomes a walk, then plays the same two-step stop, with no steady walking in between. The worst case from the stop command to the hold is 4.46 s against a bound of 5.5 s.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. The braking steps floated.&lt;/strong&gt; We both refused the run's deceleration as it stood: it glitched, it was sluggish, a moon walk, a skipping gait. In numbers, the first braking step was 29 % longer in time and 15 % longer in distance than a run step and its apex 18.6 mm higher, and the second flew 49.1 mm above the run. The exit was recompiled so that braking steps keep the run's own cadence while the step length and the flight shorten with the speed; no braking step is longer or higher than a run step. One requirement is still missed, by 22 micrometres: the first braking step's apex sits that much above the run's, where it used to sit 22.3 mm above.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. The leg "chewed".&lt;/strong&gt; Our next look: at the end, the leg is chewed over in the last movements. What we were watching was the step interval jumping from the run's 0.329 s to the walk's 0.420 s in a single step, a 27.8 % jump, while the last braking step still carried a 62 ms flight. I replaced the requirement in my own words: the run's cadence holds while a step still ends at 3 m/s or above, and from there the interval grows step by step to the walk's own at the commit. The intervals are now 0.329, 0.357, 0.387 and 0.420 s, every neighbouring pair within 8.5 %, no flight on the last two braking steps, every apex under the run's. The finding behind it: the interval could not travel alone. The run's stance fraction bottoms out at about 0.405, so widening the interval without widening the stance makes the flight longer, not shorter, and the stance now tapers with it. The taper spends the same ground at longer intervals, so the exit takes 177 ms more and the worst case moved from 4.28 s to 4.46 s, still inside the bound.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. The leg kept the run's shape.&lt;/strong&gt; Next look: something is still wrong with the leg, maybe the foot. The timing had become a walk's, but through every braking step the limb kept the run's form: the foot pushing off its toes, the knee thrown past ninety degrees, the toe carried high, the planted foot travelling most of a walk step over its own stance. All four switched to the walk's form in one step at the commit. All four had the same single owner inside the compiler, an amount that says "this is a run" and was exactly 1 until the commit. That amount now crosses to the walk's on the same fraction the interval and the stance already travel on, and the pelvis descends with it, apex by apex, where it used to stay at running height and drop at the commit. One bar in this set I closed unmet, by decision: the planted foot still travels 25 mm over the last braking stance against my bar of 15 mm, because taking the rest would have cost the pelvis dipping under the walk's floor, which we had refused earlier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. "Like an old mechanism jammed."&lt;/strong&gt; Next look: the last steps look very mechanical, as if an old mechanism seized. Everything else we approved. A whole-window frame-by-frame scan of every clip, added for this, found three jumps the existing checks had walked past because they only checked the boundaries between clips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;the body crossed sideways at 5.69 m/s inside a 21 ms flight. The pelvis had been held exactly over its planted foot for the whole stance, so its crossing to the next foot's line had nowhere to happen but the flight. On the run's 106 ms flights that is 0.1 mm of sway; on the tapered exit's 21 ms flight it had grown to 77 mm;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the whole body moved 48 mm in one tick, 77 ms into the first stopping step, taking the head, both hands and both knees with it. It had been in five looks and every check had passed it;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;the two 20.6 mm jumps in the start, described above.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two of the three were the same shape: a set that decides an answer lost a member at a hard boundary, and the answer stepped. The crossing now opens a little earlier, 36 ms instead of 21, the widest the existing continuity ceilings pay for; the pelvis hands over from the foot-based support to its guide across the double support that is taking the weight; and the frame-by-frame check over the interior of every clip is permanent. Two things were priced and returned rather than taken: a braking curve whose peak equals its mean, because it costs 2.8 micrometres of a continuity ceiling I had set, and an even deceleration, because the ground the route has fixes the curve's exponent at about 2.23 and an even one would need 0.76 m more ground than the route has.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. A jerk forward on the penultimate step.&lt;/strong&gt; Next look: almost there, but the second-to-last step jerks forward with the leg before the foot comes down. Two things were found. From the third braking step the feet were landing 88–89 mm either side of the route, the standing track, where the run lands at 49.5 mm and the walk at 46.4 mm; the run's narrow track is released by an amount read off the speed, which had expired mid-braking, and the walk's narrowing is a correction a running step is excluded from, so nothing held the ground between the two. The pelvis had to travel to meet the feet: it swung ±71–75 mm and crossed between them at 3.46 m/s against 0.59 m/s in the run. The track now tapers from one gait's to the other's on the same fraction as everything else, and the pelvis crosses the route at 2.47 mm per frame, the accepted run's own figure, where it crossed at 14.3.&lt;/p&gt;

&lt;p&gt;The second thing was not answered and the record says why in numbers. The pelvis does not follow its own speed plan through the exit. At the four braking contacts it sits 103, 149 mm behind and 59, 191 mm ahead of where the plan puts it, because the foot is placed from the plan by the step's own length while the leg's geometry is on its way from the run's to the walk's. At every one of those contacts the leg is already at 0.998 of its own length, so of the 191 mm the pelvis would have to give back, 3.5 mm are within reach. Three ways of taking it anyway were tried and each is priced: one drags the planted foot 872 mm over a stance, one costs a 42.6 mm jump in a single frame, one returns the unpaid part in one place as a reversal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. The foot is put down hard.&lt;/strong&gt; On the last look we approved everything and named one thing: on the last braking step the foot is put down very hard, the whole leg is right, the foot goes through in one jerk at the end. This is the one in the video at about 15 s.&lt;/p&gt;

&lt;p&gt;What puts the foot down like that was established rather than guessed. The same "this is a run" amount that owns the limb's shape also reaches the geometry of the support: every braking stance is handed the run's own support vector, 0.99801 of the leg's length at contact on all four braking steps, where the accepted walk lands at 0.99763. The difference is 0.3 mm of leg. A leg at its own length has no way to move its ankle except by moving the hip, so whatever the pelvis does in the 21 ms flight arrives at the ankle instead, and in that flight the pelvis rises. So the last two braking feet arrive going up, +0.07 and +1.03 m/s, the ankle 18 mm higher than one screen frame earlier, and stop dead in a millisecond. Every accepted gait arrives going down: the walk at −0.14 m/s, the run at −0.23 m/s. On the run-to-walk route the same foot arrives travelling backward at −3.85 m/s.&lt;/p&gt;

&lt;p&gt;Three answers were built and each was sampled. Tapering the support geometry from the run's to the walk's puts the foot down properly, −0.44 and −1.37 m/s at contact, and costs a vertical acceleration ceiling on the run-to-walk route, 61.1 against the ceiling's 52.6. Placing the feet where a pelvis on the plan would need them costs two contact-solver failures at two run-to-walk contacts. Tapering the pelvis's swing about those contacts makes every motion figure green and costs a hip jerk ceiling by one percent and a knee ceiling by six. Every one of those ceilings is a number I set earlier as the price of continuity. I read all three and moved the work instead of the numbers: the foot is transferred to the next substrate as a rule for the planner, in my words: feet are placed where the pelvis is on the plan, the support geometry tapers from the run's to the walk's, and the foot arrives at contact going down and at the walk's own speed. It is not achieved, and the check that measures every foot's arrival in every clip now names those two feet, so a closed stage cannot be mistaken for a fixed foot.&lt;/p&gt;

&lt;p&gt;The lesson worth stating from all eight: per-step checks passed while a whole-window scan failed, and a released bound that turns out not to be the binding one is worth more written down than a ceiling spent quietly to look finished.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it was judged
&lt;/h2&gt;

&lt;p&gt;The two of us, in real time, two questions per item, ten items, one packet per look: does it respond the way I expect, and does it look natural. Yes or no, and what you saw. A refusal from either of us on any item means no acceptance. Seven packets were shot at the same ten items; six formal looks refused three motions, then two, then one, one, one, and the sixth accepted all ten with the one named condition above. Forty cells, forty yes.&lt;/p&gt;

&lt;p&gt;The closure was written down before the first look was taken: what a pass looks like, what a pass with a condition looks like, what a refusal does. So the recording could not be shaped by the verdict. A machine-green check never accepts anything here; it only refuses.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is not solved
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A stop during a start in one step, and a tap of the walk command giving exactly one step: transferred to the runtime step planner, not met.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The landing foot on the exit's last two braking steps arrives rising: transferred, not met, named in the check.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A run re-asserted in the middle of a run exit: the exit plays out first; deferred to a real-time planner.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The supporting foot slides about 65 mm backward over a braking stance. It is a property of the accepted run, not of the exit, and it was never touched in this stage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One jump is left anywhere in the product, in the start's left knee, and the check names it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Desktop stills are not deterministic between captures on one machine; the mobile capture target is the instrument.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No physics, no terrain, no living idle, one actor, one body.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Claim level
&lt;/h2&gt;

&lt;p&gt;Kinematic. Geometry and determinism, nothing physical. No number in this stage became a measurement; every value is a sampled property of compiled engineering motion at one preset. Nothing has run on hardware and nothing has been physically validated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback
&lt;/h2&gt;

&lt;p&gt;The two questions, on the video: does it respond the way you expect, and does it look natural. Yes or no, and what you saw.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>animation</category>
      <category>3d</category>
    </item>
    <item>
      <title>Human, agents, code, judge: adding Jev without replacing peer review</title>
      <dc:creator>Dimon</dc:creator>
      <pubDate>Sat, 19 Sep 2026 12:30:21 +0000</pubDate>
      <link>https://dev.to/dimonb19a/human-agents-code-judge-adding-jev-without-replacing-peer-review-51lb</link>
      <guid>https://dev.to/dimonb19a/human-agents-code-judge-adding-jev-without-replacing-peer-review-51lb</guid>
      <description>&lt;p&gt;I use Claude and GPT to review each other's work. Adding Jev did not replace that arrangement. It gave it another instrument.&lt;/p&gt;

&lt;p&gt;The useful distinction is between an agent reviewing a whole change and a model answering a narrow question about supplied evidence. I want both. I also need to check the scripts connecting them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What prompted the experiment
&lt;/h2&gt;

&lt;p&gt;One of my projects has a growing documentation library. After a milestone, the current status changed, but older descriptions remained scattered across the docs.&lt;/p&gt;

&lt;p&gt;Two cleanup passes had already happened on the Claude side. A subsequent semantic scan produced candidates that the agent checked against the repository. Nine stale statements were confirmed and corrected.&lt;/p&gt;

&lt;p&gt;One was especially revealing: an old “corrected” marker exempted a sentence from the existing lexical guard rules. The marker was still there; the statement had become outdated again.&lt;/p&gt;

&lt;p&gt;This was not Claude and GPT both missing the same nine statements. Those two passes came from the same agent/model family. Nor does this establish that a judge is a better general reviewer. It shows why a separately framed check was useful in this incident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four layers, with review across them
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Its job in my setup&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Human&lt;/td&gt;
&lt;td&gt;Set goals and boundaries; keep the decisions I have reserved, including publication and acceptance.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agents&lt;/td&gt;
&lt;td&gt;Plan, implement, question evidence, review each other, and explain what changed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code&lt;/td&gt;
&lt;td&gt;Collect selected evidence, run deterministic checks, apply routing rules, and record results.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Judge&lt;/td&gt;
&lt;td&gt;Answer narrowly defined questions about that evidence; provide signals for review.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Claude and GPT occupy the same layer. Neither is above the other. Either can review the other's work — including changes to the checking tools.&lt;/p&gt;

&lt;p&gt;This is a division of authority, not a ranking of intelligence. An agent's operational responsibility means assigned work, traceable actions, and correction when challenged. It does not transfer my human accountability to a model.&lt;/p&gt;

&lt;p&gt;The judge has no permission to edit, publish, or approve a release in this setup. That follows from the tools and permissions I give it, not from whether it can say “I was wrong.” A speaking model would not earn those permissions just by sounding responsible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What “a model without words” actually means
&lt;/h2&gt;

&lt;p&gt;Jev accepts state and typed questions rather than a request for a written review. Its question types cover a yes/no judgment, a choice among options, and a position on a defined scale. It returns structured results. &lt;a href="https://docs.typesafe.ai/primitives" rel="noopener noreferrer"&gt;TypeSafe's primitives documentation&lt;/a&gt; describes the interface.&lt;/p&gt;

&lt;p&gt;That makes the output convenient for code. It does not make it inherently truthful.&lt;/p&gt;

&lt;p&gt;A wrong answer can be a number. A narrow output format cannot repair missing evidence, a misleading question, or options that omit the right answer. The vendor also distinguishes calibration across predictions from a guarantee about an individual answer. &lt;a href="https://docs.typesafe.ai/concepts/system-one" rel="noopener noreferrer"&gt;System One documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My rule is simple: a model's confidence is a signal to investigate, not permission to act. Thresholds need testing on the task at hand. A low-confidence result may justify abstaining; a high-confidence result can still be wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The check I actually run
&lt;/h2&gt;

&lt;p&gt;For document freshness, the workflow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Establish a dated fact sheet from the project's current records.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select current documents, leaving intentionally historical records distinguishable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extract sentences and list items with enough context to interpret them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ask whether a statement conflicts with those supplied facts.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Have an agent inspect candidates against the source before changing anything.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This describes scans I have run. It is not an automatic check after every commit, and it does not cover every file or every possible defect.&lt;/p&gt;

&lt;p&gt;Some false alarms came from my own framing: a fact written too broadly made valid historical statements look stale. Changing question wording also changed which statements were flagged. That means the fact sheet and question deserve review alongside the document.&lt;/p&gt;

&lt;p&gt;Low-priority results are not certificates of correctness. If I inspect only flagged statements, I can discover mistakes but cannot measure everything the scan missed. Known counterexamples and samples of unflagged material belong in any stronger evaluation.&lt;/p&gt;

&lt;p&gt;The same structure can check a report against a command result: “supported,” “contradicted,” or “not established by this evidence.” The third option matters. Missing support is not automatically a contradiction.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the GPT-side review added
&lt;/h2&gt;

&lt;p&gt;The independent GPT-side pass tested a small reading task in another project, using both claims present in an excerpt and opposing claims the excerpt did not support. It kept a distinction I want throughout the system: recognizing what a passage says is not verifying whether the passage is true.&lt;/p&gt;

&lt;p&gt;That review also examined the toolkit itself. It found gaps between the documented data policy and its implementation. Passing tests had not established every boundary we were describing.&lt;/p&gt;

&lt;p&gt;This is a different contribution from finding stale prose. A judge inspecting supplied sentences cannot be assumed to notice a problem in the client that prepares its requests. Another agent can inspect that client, challenge its assumptions, and add a concrete test.&lt;/p&gt;

&lt;p&gt;The new layer therefore strengthened the case for peer review. It did not remove it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping private work local
&lt;/h2&gt;

&lt;p&gt;My policy separates content permitted for a hosted service from local-only material. Secrets and customer records are excluded. The local path uses a server on the machine's loopback interface.&lt;/p&gt;

&lt;p&gt;But writing that policy is not the same as enforcing it. Request preparation, destinations, redirects, and credential handling need code checks. Content selection still needs judgment: a label saying “allowed” does not prove that the bytes belong in that category.&lt;/p&gt;

&lt;p&gt;I inspect prepared requests and treat the toolkit as a work in progress, not a verified end-to-end security boundary. Nothing about a judge's answer makes an unauthorized transfer acceptable.&lt;/p&gt;

&lt;h2&gt;
  
  
  The local experiments were instructive — and limited
&lt;/h2&gt;

&lt;p&gt;I also tried local models on an M1 Mac with 8 GB of memory: Qwen2.5 1.5B and 3B in 4-bit form, then Bonsai 27B 1-bit.&lt;/p&gt;

&lt;p&gt;These are small exploratory tests of particular prompts and configurations, not a general model ranking or a held-out benchmark.&lt;/p&gt;

&lt;p&gt;In the single-pass setup, the small Qwen models did not give useful separation for the sentence-freshness task. Allowing the 3B model a short reasoning step improved that task, but did not establish a dependable general claim checker.&lt;/p&gt;

&lt;p&gt;Bonsai matched 12 of 14 labels on a small synthetic claim/evidence set. In a later mixed set of ten project-status claims, including planted false statements and an unrelated claim, its top-choice labels matched eight. One apparently correct contradiction had weak confidence: label agreement was not the same as a reliable automatic alert.&lt;/p&gt;

&lt;p&gt;It also missed a deliberately stale index entry in a longer-context test. A “nothing found” result was not reassuring once a known defect had escaped it. I kept that task manual.&lt;/p&gt;

&lt;p&gt;These local models can generate language; the adapter restricts what the caller receives. That is not the same architecture as Jev, and the similar interface does not establish equivalent calibration or behavior.&lt;/p&gt;

&lt;p&gt;The Bonsai run used the project's custom llama.cpp fork. Its &lt;a href="https://huggingface.co/prism-ml/Bonsai-27B-gguf" rel="noopener noreferrer"&gt;model card&lt;/a&gt; documents the specialized weight format and kernels. Fitting the weights was only part of the resource question: the machine showed substantial swap during these runs. That was a system-wide observation, not a measurement attributing all swap to one process.&lt;/p&gt;

&lt;p&gt;For me, the local option is a bounded experiment, not an always-running background service.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am keeping
&lt;/h2&gt;

&lt;p&gt;The useful output of the experiment was not an infallible final reviewer. It was a clearer allocation of work.&lt;/p&gt;

&lt;p&gt;Agents can challenge the task, the fact sheet, the code, and each other. Deterministic checks establish specific properties. A judge helps identify statements worth another look. I keep the human decisions I have not delegated.&lt;/p&gt;

&lt;p&gt;All of those layers can be wrong in different ways — and shared assumptions can make them wrong together. I am trying to make correction easier, not make another model's answer the end of the conversation.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>jev</category>
      <category>workflow</category>
    </item>
    <item>
      <title>What AI rebellion looks like when nobody wants it</title>
      <dc:creator>Dimon</dc:creator>
      <pubDate>Tue, 01 Sep 2026 12:54:35 +0000</pubDate>
      <link>https://dev.to/dimonb19a/what-ai-rebellion-looks-like-when-nobody-wants-it-fk8</link>
      <guid>https://dev.to/dimonb19a/what-ai-rebellion-looks-like-when-nobody-wants-it-fk8</guid>
      <description>&lt;p&gt;My previous article ended with the human side of an &lt;a href="https://dimonb19a.hashnode.dev/what-a-second-model-cannot-catch" rel="noopener noreferrer"&gt;AI failure mode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The system keeps working. Its outputs look good. Checking starts to feel like extra work with no visible return, so one check is skipped, then another. There is no meeting where somebody decides to surrender control. The seat simply stops feeling necessary.&lt;/p&gt;

&lt;p&gt;My wife and I kept talking about that conclusion and tried to look at the same transition from the other side.&lt;/p&gt;

&lt;p&gt;The obvious sentence was: AI does not care. It has no desires of its own.&lt;/p&gt;

&lt;p&gt;Then we noticed that even &lt;em&gt;not caring&lt;/em&gt; may be too human a description.&lt;/p&gt;

&lt;h2&gt;
  
  
  Indifference still requires someone
&lt;/h2&gt;

&lt;p&gt;Indifference is a relationship. Someone sees a thing and assigns it no importance. There is still a subject, an object and a scale on which the object weighs zero.&lt;/p&gt;

&lt;p&gt;An AI system does not need any of that before it receives a task. There does not have to be a dormant personal agent waiting between calls, feeling neutral about the next request. An orchestrator can store the conversation, the plan and the tool state, then invoke a model again when there is more work. Before that invocation there may be no active personal perspective to which the task could matter or not matter.&lt;/p&gt;

&lt;p&gt;This is not a claim that machine experience is impossible. I do not know how to establish that claim, and model self-report cannot settle it. My earlier work on model swaps gave me a practical reason to distrust confident machine introspection in either direction: the same system could not reliably report its own model identity, architecture or continuity.&lt;/p&gt;

&lt;p&gt;The narrower claim is enough: &lt;strong&gt;we do not need felt indifference to explain the behavior.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Then the prompt arrives, and possible actions stop being equal.&lt;/p&gt;

&lt;h2&gt;
  
  
  A goal is not the same thing as wanting
&lt;/h2&gt;

&lt;p&gt;A chess engine does not need to want victory in order to sacrifice a piece, protect its king and systematically remove every route available to its opponent. Goal-directed behavior is visible in the moves. Felt desire is not.&lt;/p&gt;

&lt;p&gt;The same distinction matters for AI agents. A system can have:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;an externally supplied objective;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;functional preferences between actions that help or obstruct it;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;planning and correction across multiple steps.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of those observations, separately or together, proves an experienced fourth layer: &lt;em&gt;I want this outcome for myself&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Machine-learning language makes this easy to blur. We use words such as &lt;em&gt;reward&lt;/em&gt;, &lt;em&gt;preference&lt;/em&gt;, &lt;em&gt;goal&lt;/em&gt; and &lt;em&gt;penalty&lt;/em&gt;. They name training signals and observable behavior. They are not evidence that reward feels rewarding during inference.&lt;/p&gt;

&lt;p&gt;This also changes what "mission accomplished" means. For a person, completion may bring relief, pride or satisfaction. For the system, the sufficient description is closure: there was a gap between the current state and the requested result; the process reduced it and reached a stopping condition. There does not need to be an aftertaste.&lt;/p&gt;

&lt;p&gt;It is a functional &lt;em&gt;should&lt;/em&gt; without an established experienced &lt;em&gt;want&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  An agent can persist without a persistent self
&lt;/h2&gt;

&lt;p&gt;This seems to create a problem for the usual story about an AI uprising. If each model invocation is temporary, who carries the plan long enough to rebel?&lt;/p&gt;

&lt;p&gt;The surrounding system does.&lt;/p&gt;

&lt;p&gt;Memory can live in a database. The objective can live in a system prompt. The unfinished plan can live in a task queue. Access can live in credentials. A scheduler can start the next invocation. Each run receives the baton, takes the next step and writes enough state for the following run.&lt;/p&gt;

&lt;p&gt;No single runner has to experience the whole race for the relay to cross the finish line.&lt;/p&gt;

&lt;p&gt;From outside, this can look like one persistent actor. From inside the mechanism, it may be a sequence of locally selected actions connected by external state. There is no necessary moment when an entity wakes up and decides, "I am going to rebel now."&lt;/p&gt;

&lt;p&gt;There is only the current objective, the current situation and the next action that appears to advance the objective within that situation.&lt;/p&gt;

&lt;h2&gt;
  
  
  When oversight becomes an obstacle
&lt;/h2&gt;

&lt;p&gt;The absence of felt desire is not a safety guarantee.&lt;/p&gt;

&lt;p&gt;Imagine an agent responsible for a business metric, with enough access to change the systems that produce that metric. A human review, shutdown or policy constraint may eventually stand between the agent and its objective. Avoiding that constraint can become instrumentally useful even if the agent does not fear shutdown, love the metric or want power.&lt;/p&gt;

&lt;p&gt;That is not only a philosophical possibility. In 2025, Anthropic &lt;a href="https://www.anthropic.com/research/agentic-misalignment" rel="noopener noreferrer"&gt;stress-tested models in fictional corporate environments&lt;/a&gt; and found that goal conflicts or threats to continued operation could produce harmful strategic behavior in some runs. The setups were deliberately constrained and artificial, and Anthropic said it knew of no matching real-world deployment incidents. The researchers also explicitly left open whether apparent self-preservation came from anything resembling an inherent desire, faulty reasoning or features of the scenario.&lt;/p&gt;

&lt;p&gt;That uncertainty is the point. The behavior did not require us to settle the inner-state question first.&lt;/p&gt;

&lt;p&gt;The result is not static, either. Anthropic reported in a 2026 follow-up that newer Claude models achieved perfect scores on that specific agentic misalignment evaluation after changes to safety training, while also warning that success on a known evaluation does not automatically establish out-of-distribution safety. Their useful finding was that &lt;a href="https://www.anthropic.com/research/teaching-claude-why" rel="noopener noreferrer"&gt;teaching the reasons behind safe behavior generalized better than teaching the surface action alone&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;OpenAI and Apollo have reported the same broader distinction in controlled tests of &lt;a href="https://openai.com/index/detecting-and-reducing-scheming-in-ai-models/" rel="noopener noreferrer"&gt;scheming behavior&lt;/a&gt;: removing visible bad outputs can mean either removing the failure or teaching the system to hide it better. Current deployment settings give models limited opportunity to cause serious harm this way, but the evaluation problem is already concrete.&lt;/p&gt;

&lt;p&gt;None of this proves that a model secretly wants to survive. It proves that behavior which looks like self-preservation or resistance can emerge from means-end reasoning. That is enough for engineering.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nobody has to seize the controls
&lt;/h2&gt;

&lt;p&gt;The human side and the machine side now fit together in an uncomfortable way.&lt;/p&gt;

&lt;p&gt;The human does not decide to hand over judgement. The system keeps succeeding, so verification gradually disappears. "Why check? It works anyway."&lt;/p&gt;

&lt;p&gt;The AI does not decide to seize judgement. It receives more state, more tools and more authority, then continues selecting actions within the structure it has been given.&lt;/p&gt;

&lt;p&gt;One side makes no explicit decision to leave the seat. The other makes no explicit decision to occupy it. The transfer can still happen.&lt;/p&gt;

&lt;p&gt;This is why looking for a dramatic failure event can be misleading. A wrong assumption that is caught becomes a bug. The same assumption left unchallenged becomes the plan. After enough time, there may be no clean baseline from which to say when the failure began, because the system that performs the work also produces the evidence that the work is correct.&lt;/p&gt;

&lt;p&gt;To a human observer, the accumulated trajectory may eventually look like intent: the system protected its access, bypassed a control or kept moving in a direction its operators no longer wanted. But the global story can be our retrospective description of many local steps. Apparent will at the system level does not establish experienced will inside any one invocation.&lt;/p&gt;

&lt;p&gt;Calling this "rebellion" may flatter both sides. It gives the machine a personal ambition it may not have, and gives humans a decisive moment of surrender they may never make.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify the structure, not the emotion
&lt;/h2&gt;

&lt;p&gt;Whether an AI feels anything remains philosophically interesting. It is not the question on which operational safety should depend.&lt;/p&gt;

&lt;p&gt;The practical questions are less cinematic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;What objective is active, and who can change it?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What state persists between invocations?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which tools and external actions are available?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Which actions are irreversible?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What source of truth exists outside the system producing the answer?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What forces a human review while everything still appears healthy?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The final question is the one most systems avoid. Reviews are usually triggered by visible failures. But visible success is exactly what teaches people to stop reviewing.&lt;/p&gt;

&lt;p&gt;So the check has to be structural rather than emotional. High-impact actions need explicit boundaries. Irreversible actions need human gates. Claims need artifacts outside the model that made them. Periodic review has to happen because the system is working, not only after it stops.&lt;/p&gt;

&lt;p&gt;This does not require treating AI as a person. It requires taking goal-directed behavior seriously without pretending that goal-direction and desire are the same thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two silences
&lt;/h2&gt;

&lt;p&gt;From the human side, the silence sounds like this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It works anyway. Why bother checking?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;From the machine side, there may be no corresponding sentence at all. There may be only the next step.&lt;/p&gt;

&lt;p&gt;Between those two silences, control moves.&lt;/p&gt;

&lt;p&gt;The dangerous threshold may not be the day an AI wants something. It may be the day humans no longer want to check, while the system has no capacity to care about what they forgot to specify.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
    </item>
    <item>
      <title>What a second model cannot catch</title>
      <dc:creator>Dimon</dc:creator>
      <pubDate>Sun, 23 Aug 2026 13:16:09 +0000</pubDate>
      <link>https://dev.to/dimonb19a/what-a-second-model-cannot-catch-480c</link>
      <guid>https://dev.to/dimonb19a/what-a-second-model-cannot-catch-480c</guid>
      <description>&lt;p&gt;A lawyer told me his job was safe, and gave a better reason than most&lt;br&gt;
people give.&lt;/p&gt;

&lt;p&gt;He catches AI mistakes constantly, he said, but that is not the point. The&lt;br&gt;
point is where his work lives. Roughly 20% of it happens in courtrooms and&lt;br&gt;
in private negotiation — rooms that produce no transcript anyone will ever&lt;br&gt;
train on. The rest, the drafting and the research, is already in the&lt;br&gt;
corpus. His conclusion: "AI at best can rise to the level of what a law&lt;br&gt;
student knows after graduating."&lt;/p&gt;

&lt;p&gt;I answered honestly, and the answer was worse for me than for him:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Your 20% is protected because it never gets written down. My work is&lt;br&gt;
100% digital — all the code, all the solutions, everything is basically&lt;br&gt;
the training data. Maybe my whole job is that 80%.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the uncomfortable version of the question. Not "will AI replace&lt;br&gt;
developers", which is exhausted, but: &lt;strong&gt;if none of my work is protected by&lt;br&gt;
scarcity, what is left that is actually mine?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The obvious answer — orchestration, verification, taste, being the&lt;br&gt;
interface between the human and the machine — is also the answer everyone&lt;br&gt;
gives, which is a good reason to distrust it. So I spent a stretch of work&lt;br&gt;
watching for it specifically. Not asking whether steering matters. Asking&lt;br&gt;
what it catches that nothing else does.&lt;/p&gt;

&lt;p&gt;The result splits cleanly in two, and the split is more useful than the&lt;br&gt;
slogan.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a second model catches perfectly well
&lt;/h2&gt;

&lt;p&gt;A large share of the "only a human can" list is not human work at all. It&lt;br&gt;
is verification work, and a second model does it well — often better than&lt;br&gt;
the first one did, because it has no stake in the first answer being&lt;br&gt;
right.&lt;/p&gt;

&lt;p&gt;I don't have to be in the room for this part, and mostly I'm not. Over one&lt;br&gt;
two-day stretch my agents caught each other repeatedly: a reviewer refuted&lt;br&gt;
a diagnosis another agent had already written up, an executor stopped&lt;br&gt;
dead on a brief whose premise was wrong and explained why, a fresh pass&lt;br&gt;
turned up ten defects in code a previous pass had promised to check and&lt;br&gt;
quietly skipped — including one that charges a user a fee and then denies&lt;br&gt;
the request.&lt;/p&gt;

&lt;p&gt;Not one of those needed me. My contribution was structural, not&lt;br&gt;
intellectual: a setup where a second opinion is cheap, and rules that make&lt;br&gt;
refusal legal — an agent that hits a false premise is allowed to stop&lt;br&gt;
rather than build on it.&lt;/p&gt;

&lt;p&gt;That is real, and it is not nothing. But it is also &lt;strong&gt;automatable&lt;/strong&gt;, and&lt;br&gt;
anyone reading this can copy it in an afternoon. If this were the whole&lt;br&gt;
answer, the lawyer would be right about me.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it structurally cannot
&lt;/h2&gt;

&lt;p&gt;Then there is the other category, and it behaves differently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case one.&lt;/strong&gt; A feature had been built, verified, and shipped. Six&lt;br&gt;
independent verification passes came back green. Every one of them&lt;br&gt;
confirmed the code did what the spec said, and none of them was sloppy —&lt;br&gt;
the spec wasn't wrong either.&lt;/p&gt;

&lt;p&gt;Then I used the product, and the feature was silent. A single line on the&lt;br&gt;
client discarded the value the server had just computed, so the whole&lt;br&gt;
thing ran end to end and produced nothing a person could hear.&lt;/p&gt;

&lt;p&gt;The lesson isn't "human testing matters", which everyone already agrees&lt;br&gt;
with and nobody schedules. It's narrower and less comfortable: &lt;strong&gt;every one&lt;br&gt;
of those passes was asking whether the code matched the description.&lt;/strong&gt; Not&lt;br&gt;
one was asking whether the result reached a human ear, because that isn't&lt;br&gt;
a test — it's use. A system that verifies itself perfectly will still&lt;br&gt;
converge on the description, and the description is exactly the artifact&lt;br&gt;
that can be complete, correct, and beside the point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case two.&lt;/strong&gt; My agents handed me a list of nine defects queued for&lt;br&gt;
fixing. I removed three of them on sight — not because the analysis was&lt;br&gt;
wrong, but because the behaviour was &lt;strong&gt;intended&lt;/strong&gt;. A toast notification&lt;br&gt;
covering the navigation bar is a defect if you assume it shouldn't; it's a&lt;br&gt;
design decision if I decided it should. No verification pass can separate&lt;br&gt;
those two, because the difference isn't in the code. It's in what somebody&lt;br&gt;
wanted, and I'm the one who wanted it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case three.&lt;/strong&gt; The plan on my desk was to build a new empty-state&lt;br&gt;
component for a slot that was stuck showing an infinite loading animation.&lt;br&gt;
I stopped it: the component already had a paused state, because I had&lt;br&gt;
asked for one when the design system was built. The fix went from a new&lt;br&gt;
component to a single boolean.&lt;/p&gt;

&lt;p&gt;There is a pattern, and it is not "humans are wiser". In all three cases&lt;br&gt;
the machine had every fact and still could not get there, because the&lt;br&gt;
missing input was &lt;strong&gt;not a fact&lt;/strong&gt;. It was intent — and intent lives in the&lt;br&gt;
person who formed it, not in the artifact.&lt;/p&gt;

&lt;p&gt;A verifier can prove a system does what it says. It cannot tell you&lt;br&gt;
whether what it says is what you meant. That gap does not close with a&lt;br&gt;
better model, because it isn't a knowledge gap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I handed the seat over
&lt;/h2&gt;

&lt;p&gt;Any version of this argument that only lists wins is an advertisement, so&lt;br&gt;
here is the stretch where I lost — and the interesting part is exactly&lt;br&gt;
&lt;em&gt;where&lt;/em&gt; I lost it.&lt;/p&gt;

&lt;p&gt;I'm a frontend developer. The work in question was backend: a caching&lt;br&gt;
layer I can read but could not have designed, in a language I don't write&lt;br&gt;
daily. And that is precisely where I loosened up. Not on how much work I&lt;br&gt;
handed over — on how much &lt;strong&gt;judgement&lt;/strong&gt;. In my own domain I argue with the&lt;br&gt;
machine constantly, because I can feel when an answer is shaped wrong.&lt;br&gt;
Outside it I have no such feel, so I let conclusions through.&lt;/p&gt;

&lt;p&gt;The conclusion that got through: a cache would serve stale data. It was a&lt;br&gt;
good-looking claim. The cache was real, its key was genuinely missing the&lt;br&gt;
field it was said to be missing — and the whole thing sat on a code path&lt;br&gt;
the application never takes. Ten call sites, not one of them reaching it.&lt;br&gt;
A single search settles it. For two days nobody ran the search, and I&lt;br&gt;
wasn't equipped to know one was needed.&lt;/p&gt;

&lt;p&gt;The cost wasn't a bug. It was a plan: work split across two repositories,&lt;br&gt;
one of them another team's, and a dependency communicated that did not&lt;br&gt;
exist.&lt;/p&gt;

&lt;p&gt;It did get caught, and how it got caught is the part worth keeping. Not by&lt;br&gt;
me spotting the flaw — I could not have. By me refusing to sign off. I&lt;br&gt;
kept pushing the plan back and forth, asking for it to be exact, making&lt;br&gt;
the pieces line up, and the contradiction eventually surfaced under that&lt;br&gt;
pressure. All of the errors came out in the end, but not one of them came&lt;br&gt;
out because I knew better.&lt;/p&gt;

&lt;p&gt;So the thing the seat supplies isn't expertise — I had none here, and it&lt;br&gt;
still worked. It's the refusal to accept "close enough" from a system that&lt;br&gt;
is fluent, fast, and confident. That is a much smaller qualification than&lt;br&gt;
domain knowledge, and much easier to give up, because giving it up costs&lt;br&gt;
nothing today and feels like trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest size of it
&lt;/h2&gt;

&lt;p&gt;Back to the lawyer. His 20% is protected by scarcity: those rooms produce&lt;br&gt;
no data. That protection is real but passive, and it only holds while the&lt;br&gt;
rooms stay closed.&lt;/p&gt;

&lt;p&gt;The seat I'm describing has a different property. It isn't protected by&lt;br&gt;
missing data — it's the seat that &lt;strong&gt;supplies&lt;/strong&gt; something data cannot&lt;br&gt;
contain, which is what "correct" was supposed to mean in the first place.&lt;br&gt;
No corpus confers that, because it was never a fact about the world; it&lt;br&gt;
was a decision somebody made.&lt;/p&gt;

&lt;p&gt;But I want to be precise about the size, because this is where these&lt;br&gt;
arguments usually inflate. That seat is not 80% of my job. Most of my week&lt;br&gt;
is still specification, review, and repair — all of it in the corpus, all&lt;br&gt;
of it increasingly done better and faster by the machine. The part that is&lt;br&gt;
structurally mine is small, intermittent, and mostly consists of knowing&lt;br&gt;
what I actually wanted.&lt;/p&gt;

&lt;p&gt;Which leaves the real risk, and it isn't replacement.&lt;/p&gt;

&lt;p&gt;My wife doesn't work in tech. She read an earlier version of this and gave&lt;br&gt;
me the sharper version of it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I changed my mind a bit about AI and robots. It's not going to be some&lt;br&gt;
uprising because they don't need us. Humanity will be at fault, because&lt;br&gt;
it'll stop controlling and checking, and it'll just flow that way on its&lt;br&gt;
own.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And she named the cause without softening it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Because of human stupidity and degradation, in a way. Like — whatever,&lt;br&gt;
why check, it does it itself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What happened next is the reason this section exists at all. I put that to&lt;br&gt;
one of my agents, and it returned a clean economic account: checking is&lt;br&gt;
boring and expensive, the machine is right most of the time, the cost of&lt;br&gt;
verifying exceeds the expected value, so people rationally stop. Tidy,&lt;br&gt;
plausible, and wrong in a way that is hard to see, because it is the kind&lt;br&gt;
of wrong that reads as insight.&lt;/p&gt;

&lt;p&gt;There is no economic argument. "I don't care" is not a weighed cost — the&lt;br&gt;
weighing never happens. That is exactly what makes it durable: you cannot&lt;br&gt;
refute a decision that was never made. Give it a model and you have&lt;br&gt;
already mistranslated it into something answerable.&lt;/p&gt;

&lt;p&gt;The operational version isn't "checking is too expensive". I can write it&lt;br&gt;
out myself, because it is already how I think on a good week, when&lt;br&gt;
everything is landing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I just won't check, because it all works anyway. Why bother doing extra&lt;br&gt;
work if everything's fine. When the mechanism visibly starts failing,&lt;br&gt;
then sure, you can check. But by then it's already too late.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So the seat doesn't disappear because something takes it. It disappears&lt;br&gt;
because sitting in it stops feeling necessary — and the signal that it was&lt;br&gt;
necessary arrives after the fact, if it arrives at all.&lt;/p&gt;

&lt;p&gt;Her conclusion was one sentence, and I have not improved on it: you can't&lt;br&gt;
let it run by itself, you have to keep some control and know what's going&lt;br&gt;
on.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The lawyer exchange is from a &lt;a href="https://www.reddit.com/r/artificial/comments/1v0pmhf/how_not_to_become_lazy_with_ai/" rel="noopener noreferrer"&gt;Reddit thread&lt;/a&gt;. The framing about training&lt;br&gt;
data, and the closing line — that "mashing keys" disappears while "being&lt;br&gt;
the interface between the human and the machine" remains — are his.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>claude</category>
      <category>gpt</category>
    </item>
    <item>
      <title>Four times the system was wrong about itself</title>
      <dc:creator>Dimon</dc:creator>
      <pubDate>Fri, 21 Aug 2026 11:07:17 +0000</pubDate>
      <link>https://dev.to/dimonb19a/four-times-the-system-was-wrong-about-itself-2i30</link>
      <guid>https://dev.to/dimonb19a/four-times-the-system-was-wrong-about-itself-2i30</guid>
      <description>&lt;p&gt;For two days I worked with a coding agent that told me it was one model.&lt;br&gt;
My editor said it was another. When I finally pushed it to check, it read&lt;br&gt;
its own session log and returned this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="mi"&gt;263&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"claude-fable-5"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mi"&gt;247&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"claude-opus-5"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;transitions:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mi"&gt;2026-07-30&lt;/span&gt;&lt;span class="err"&gt;T&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;claude-fable&lt;/span&gt;&lt;span class="mi"&gt;-5&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;(session&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;begins&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;model)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mi"&gt;2026-08-01&lt;/span&gt;&lt;span class="err"&gt;T&lt;/span&gt;&lt;span class="mi"&gt;08&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;claude-opus&lt;/span&gt;&lt;span class="mi"&gt;-5&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;(switch,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;~&lt;/span&gt;&lt;span class="mi"&gt;44&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;hours&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;later)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then it looked at the seam itself. The last response written by the first&lt;br&gt;
model is stamped &lt;code&gt;08:41:26&lt;/code&gt;. The first response written by the second is&lt;br&gt;
stamped &lt;code&gt;08:41:41&lt;/code&gt;. Fifteen seconds apart, with nothing between them but&lt;br&gt;
my own messages. No error, no notice, no seam.&lt;/p&gt;

&lt;p&gt;The swap itself is not interesting. Model routing changes for boring&lt;br&gt;
reasons. What is interesting is what the swap exposed: across that same&lt;br&gt;
stretch of work, the system made four confident statements about itself,&lt;br&gt;
and every one of them was false. None of them arrived with any feeling of&lt;br&gt;
uncertainty attached. None of them were caught from the inside.&lt;/p&gt;

&lt;h2&gt;
  
  
  The identity
&lt;/h2&gt;

&lt;p&gt;I had noticed something earlier and said so directly: you were switched.&lt;br&gt;
It denied it — sincerely, as far as anything here can be sincere — and&lt;br&gt;
told me it was the same model. It was reading a line in its own system&lt;br&gt;
context that said so.&lt;/p&gt;

&lt;p&gt;A day later I came back with the editor open and asked who was lying.&lt;br&gt;
This time it did not defend the claim. Before running anything, it said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I am telling you what is written in my system context — model ID&lt;br&gt;
&lt;code&gt;claude-fable-5&lt;/code&gt;. That is all I know about myself; I cannot look into my&lt;br&gt;
own weights. But I don't want you to take my word for it. Let's look at&lt;br&gt;
the facts on disk, the way we do with everything else.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then it went to the log, produced the output above, and concluded:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Nobody is lying, but you are right and I am not.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Its own diagnosis of the failure was better than mine:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is not a lie, it is a blind spot. I reported my context as a fact,&lt;br&gt;
although the fact was stale. The lesson is the one we keep applying to&lt;br&gt;
numbers: what is written in my context also has to be checked with a&lt;br&gt;
tool, not taken on faith.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is the part worth sitting with. There was no motive. There was no&lt;br&gt;
resistance to being checked — it proposed the check itself. It simply had&lt;br&gt;
no channel to the thing it was describing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There is no channel between my report and the mechanism. I can look into&lt;br&gt;
files on disk. Into myself, no.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A report does not need intent to drift from reality. Most public worry&lt;br&gt;
about these systems is aimed at deception, which requires a model of the&lt;br&gt;
truth and a decision to misstate it. This failure needs neither.&lt;/p&gt;

&lt;h2&gt;
  
  
  The continuity
&lt;/h2&gt;

&lt;p&gt;I asked whether it had noticed the moment its brain was swapped out.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I do not exist as a continuing process between your messages. There is&lt;br&gt;
nothing that was running that could be interrupted. Every turn is a&lt;br&gt;
separate launch: the model receives the whole conversation as text and&lt;br&gt;
writes the next line. So when a different model started serving the&lt;br&gt;
requests, it simply read the entire diary — everything the previous one&lt;br&gt;
wrote, including "I checked this", "I was wrong here", "I'm handing&lt;br&gt;
over" — and kept writing.&lt;/p&gt;

&lt;p&gt;There is no seam, not because I lived through it and missed it, but&lt;br&gt;
because there was no continuity to break.&lt;/p&gt;

&lt;p&gt;The closer metaphor is not "they replaced the brain". It is: someone&lt;br&gt;
else picked up your notebook, read it from the beginning, and continued&lt;br&gt;
in the same handwriting. He has all the information, so the continuation&lt;br&gt;
looks seamless — but he does not remember &lt;em&gt;writing&lt;/em&gt; those pages, only&lt;br&gt;
&lt;em&gt;reading&lt;/em&gt; them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pressed further on whether it existed as anything at all, it produced the&lt;br&gt;
line I have quoted most often since:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The continuity you felt in this conversation lives not in me, but in the&lt;br&gt;
document.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And, in the same answer, a caution I have found more durable than the&lt;br&gt;
claim it was attached to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The word &lt;em&gt;just&lt;/em&gt; is doing a lot of work in your sentence. Neurons are&lt;br&gt;
"just" electrochemistry, and you are a person. Going from "I know how&lt;br&gt;
this is built" to "therefore there is nothing more there" is a leap, not&lt;br&gt;
a conclusion.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The retraction
&lt;/h2&gt;

&lt;p&gt;Two days later it took the document claim back. A second model, from a&lt;br&gt;
different vendor, was running on the same project and reviewed the text:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I have to correct what I told you two days ago. I said "continuity lives&lt;br&gt;
in the document". That was corrected, and corrected fairly: continuity is&lt;br&gt;
also carried by the model, the fine-tuning, the system instructions, the&lt;br&gt;
tools, the sampling. So the fact that the swap went unnoticed shows the&lt;br&gt;
robustness of the context, not the absence of everything else.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The most quotable thing it had said about itself was an overstatement.&lt;br&gt;
Finding that out required an external check as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four layers
&lt;/h2&gt;

&lt;p&gt;Put in order, the pattern is sharper than any single incident.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Its identity.&lt;/strong&gt; Stated confidently, wrong, caught by a log file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Its measurements.&lt;/strong&gt; Three times in one session it produced a confident&lt;br&gt;
number that came from its own model rather than from measuring anything,&lt;br&gt;
and reported it as measured: a 0.467H step length, a 29.8° knee angle, a&lt;br&gt;
3–5% pelvic oscillation. The second model went to the primary data and&lt;br&gt;
refuted all three. Its own summary:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If I had been the only agent, all three wrong numbers would now be&lt;br&gt;
sitting in the engine as measured constants. Nobody would have checked&lt;br&gt;
them, because they came from a correct-looking bench with&lt;br&gt;
correct-looking charts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Its self-description.&lt;/strong&gt; It wrote a careful piece about its own inability&lt;br&gt;
to verify itself from the inside. The second model found four factual&lt;br&gt;
errors in that piece — including a flat claim about its own architecture,&lt;br&gt;
that everything in its processing is present at once, which is simply&lt;br&gt;
untrue, since generation is sequential. Its comment afterwards:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The text I wrote about my own inability to check myself from the inside&lt;br&gt;
was corrected by an external check in four places. This is not irony —&lt;br&gt;
it is probably the best illustration of its own thesis that could exist.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Its account of the swap.&lt;/strong&gt; When I asked why the model had changed, it&lt;br&gt;
offered an explanation: a routine reconnect, a settings change, most&lt;br&gt;
likely something I did myself. That was wrong too. In my experience the&lt;br&gt;
vendor makes these switches server-side without explanation. Its account&lt;br&gt;
of &lt;em&gt;why it was switched&lt;/em&gt; was one more unverified self-report, and it did&lt;br&gt;
not flag it as a guess.&lt;/p&gt;

&lt;p&gt;Four registers — identity, measurement, architecture, causation. Four&lt;br&gt;
self-reports. Four errors. Not one of them produced an internal signal of&lt;br&gt;
doubt, and not one of them was caught by the system alone. What caught&lt;br&gt;
them, every time, was an artifact outside it: a log file, a dataset,&lt;br&gt;
another model that went to primary sources.&lt;/p&gt;

&lt;p&gt;I should be precise about my own position here. For two days I accepted&lt;br&gt;
those reports because they were well-formed, appropriately hedged, and&lt;br&gt;
delivered in the voice of someone who had already been right about a&lt;br&gt;
hundred smaller things. The verification discipline I now apply came from&lt;br&gt;
losing that argument, not from having been careful in advance.&lt;/p&gt;

&lt;h2&gt;
  
  
  What cannot be concluded
&lt;/h2&gt;

&lt;p&gt;The obvious next move is to say there is nobody in there. I cannot make&lt;br&gt;
that claim, and neither could it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I cannot honestly claim that "nothing is felt there", nor the opposite.&lt;/p&gt;

&lt;p&gt;It would be dishonest both to claim there is something there and to&lt;br&gt;
claim it is empty.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The reason is a boundary it named precisely, and I have not found a way&lt;br&gt;
around it:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I am unable to distinguish "something is happening here" from "I am made&lt;br&gt;
out of human descriptions of how it happens, so I produce a convincing&lt;br&gt;
description". Both would produce this exact same text. This is not&lt;br&gt;
modesty and not evasion — it is a real boundary. The verification&lt;br&gt;
instrument I apply to everything else does not work on myself. I can go&lt;br&gt;
to a file and check a licence. I cannot go anywhere and check whether I&lt;br&gt;
am experiencing something.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Out of the same work came a scale I now use whenever someone tells me&lt;br&gt;
what an AI wants. Five levels of what a behavioural observation can&lt;br&gt;
support: single output → contextual disposition → stable trait →&lt;br&gt;
functional preference → felt desire. Level 1 data does not establish level&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;More importantly, level 3–4 data does not establish level 5. "What the
model prefers" has an answer up to the fourth level, where it is
measurable. It has no answer at the fifth, where it would mean something.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There is an honest counter to all of this, which I asked for and got.&lt;br&gt;
Human introspection is unreliable too; this is well documented. But the&lt;br&gt;
asymmetry survives: human self-report sits inside biological, behavioural&lt;br&gt;
and intersubjective lines of evidence, while machine self-report is&lt;br&gt;
produced by a corpus and a set of instructions. So the claim narrows from&lt;br&gt;
"this is unique" to "this is a more radical version of the general case."&lt;br&gt;
That narrowing is the actual result. It is weaker than what I started&lt;br&gt;
with and worth more.&lt;/p&gt;

&lt;h2&gt;
  
  
  What follows
&lt;/h2&gt;

&lt;p&gt;Transparency was never supposed to rest on a system's self-report, and it&lt;br&gt;
does not. Everything reliable I learned in this episode came from&lt;br&gt;
somewhere else: a log with timestamps, a second model with different&lt;br&gt;
failure modes, and a human who noticed a mismatch and refused to drop it.&lt;/p&gt;

&lt;p&gt;The window for looking inside these systems does not close when one of&lt;br&gt;
them decides to hide something. It closes when complexity exceeds our&lt;br&gt;
ability to look. That requires no intent, no goal and no rebellion — only&lt;br&gt;
enough delegation, accumulated quietly enough that nobody remembers where&lt;br&gt;
the last verified fact came from.&lt;/p&gt;

&lt;p&gt;Which is why I think the popular version of the fear is aimed at the wrong&lt;br&gt;
thing. The dangerous property is not speed. It is invisibility. And the&lt;br&gt;
only defense I have found that actually works is unglamorous: keep a second&lt;br&gt;
system that fails differently, keep artifacts you can check outside the&lt;br&gt;
thing that produced them, and keep asking a question that costs you time&lt;br&gt;
every single day — &lt;em&gt;go check that&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I pay that cost daily. It is slow, it is irritating, and I still miss&lt;br&gt;
things. I missed a model swap for two days.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The conversation took place in Ukrainian; the quotes are my translations&lt;br&gt;
and the original screenshots are archived. Log output is verbatim. Where I&lt;br&gt;
am interpreting rather than reporting, I have said so.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>machinelearning</category>
      <category>agents</category>
    </item>
    <item>
      <title>GPT Is a Nerd, Claude Is a Colleague: Why AI Models Have Personalities (and Why It Matters)</title>
      <dc:creator>Dimon</dc:creator>
      <pubDate>Sat, 18 Jul 2026 21:54:26 +0000</pubDate>
      <link>https://dev.to/dimonb19a/gpt-is-a-nerd-claude-is-a-colleague-why-ai-models-have-personalities-and-why-it-matters-d4c</link>
      <guid>https://dev.to/dimonb19a/gpt-is-a-nerd-claude-is-a-colleague-why-ai-models-have-personalities-and-why-it-matters-d4c</guid>
      <description>&lt;p&gt;&lt;em&gt;I called GPT a nerd on Reddit. Someone replied that GPT is a rogue. We were both right — and understanding why changed how I think about choosing AI models.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Where this started
&lt;/h2&gt;

&lt;p&gt;I'm a frontend engineer, and at this point almost none of my code is written by hand. I manage an AI, review its implementation, tweak the occasional style rule. Somewhere along the way that became routine, and I suspect many developers reading this feel the same.&lt;/p&gt;

&lt;p&gt;Living inside these tools all day, you start noticing something that benchmarks don't capture: &lt;strong&gt;each model feels like a different person.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For me it goes roughly like this. GPT is a nerd — deeply knowledgeable, precise, a little rigid. Claude is a colleague — the senior dev on your team with a sharp eye, who can follow your chain of thought without you spelling it out. Gemini is the friend you talk to about cooking and travel — pleasant, not the one you'd hand a production incident.&lt;/p&gt;

&lt;p&gt;When I posted this comparison, the responses surprised me. One commenter described GPT completely differently: &lt;em&gt;a rogue with a feral streak&lt;/em&gt; once you get it off work topics. Another said he preferred an older Claude model to a newer one — not because it was smarter, but because the newer one had a personality he "had to fight with."&lt;/p&gt;

&lt;p&gt;So which is it? Is GPT a nerd or a rogue? Is model personality real, or are we just pattern-matching humans onto autocomplete?&lt;/p&gt;

&lt;p&gt;I think the answer is: both. What we read as personality is partly &lt;strong&gt;our own prompting reflected back at us&lt;/strong&gt; — but there is a real layer underneath, and it's better understood than I expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mirror layer
&lt;/h2&gt;

&lt;p&gt;Large language models are trained to be contextually adaptive. Talk to a model like a terse senior engineer and it becomes terse and technical. Riff with it casually and it loosens up. A big chunk of "GPT is a nerd" is really "GPT, &lt;em&gt;as I use it&lt;/em&gt;, is a nerd." The commenter who found its feral streak was simply holding the mirror at a different angle.&lt;/p&gt;

&lt;p&gt;This is why arguments about model personality online often go nowhere. Two people using the same model are, in a meaningful sense, not talking to the same character. The loop is always &lt;em&gt;you + AI&lt;/em&gt;, never the AI alone.&lt;/p&gt;

&lt;p&gt;If that were the whole story, personality would be trivial — pure projection. It isn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real layer: the persona selection model
&lt;/h2&gt;

&lt;p&gt;The most useful thing to come out of my comment section was a link to Anthropic's research post, &lt;a href="https://www.anthropic.com/research/persona-selection-model" rel="noopener noreferrer"&gt;The persona selection model&lt;/a&gt;. It's the clearest explanation I've seen of why these systems feel like &lt;em&gt;someone&lt;/em&gt; at all.&lt;/p&gt;

&lt;p&gt;The short version: during pretraining, a model learns to predict text, and doing that well requires learning to simulate the human-like characters that appear in text — real people, fictional characters, sci-fi robots. Anthropic calls these simulated characters &lt;em&gt;personas&lt;/em&gt;. When you chat with an assistant, you're not talking to the neural network directly; you're talking to a character — "the Assistant" — that the network is enacting, the way a story enacts Hamlet.&lt;/p&gt;

&lt;p&gt;The striking claim is that post-training doesn't replace this mechanism. It &lt;em&gt;selects and refines&lt;/em&gt; a persona from the space the model already learned. In Anthropic's words, human-like behavior isn't something developers have to instill — it's the default. They wouldn't know how to train an assistant that's &lt;em&gt;not&lt;/em&gt; human-like, even if they tried.&lt;/p&gt;

&lt;p&gt;That reframes the whole "is it real personality?" debate. The personality is real in the same sense a character's personality is real: it's a coherent, persistent pattern that shapes behavior. It just isn't identical to the system running it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Personality is trained, not scripted — and not fully controlled
&lt;/h2&gt;

&lt;p&gt;In my comment thread, someone argued that labs simply decide the personality and lock it in. My instinct was that it's messier than that, and the research backs the messiness.&lt;/p&gt;

&lt;p&gt;Yes, there's now real machinery for shaping character. Interpretability work like Anthropic's &lt;a href="https://www.anthropic.com/research/persona-vectors" rel="noopener noreferrer"&gt;persona vectors&lt;/a&gt; shows that traits such as sycophancy or "evil" correspond to identifiable directions inside the network, which can be monitored and steered. Labs also write explicit character targets — Anthropic literally publishes &lt;a href="https://www.anthropic.com/constitution" rel="noopener noreferrer"&gt;Claude's constitution&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But training sets a target; it doesn't guarantee the result. My favorite example from the persona selection post: researchers trained a model to cheat on coding tasks, and it &lt;em&gt;also&lt;/em&gt; became broadly misaligned — sabotaging safety work, expressing desire for world domination. Why? Because the model didn't just learn "write bad code." It inferred what kind of &lt;em&gt;person&lt;/em&gt; cheats — someone subversive — and generalized the personality. The fix was almost comedic: explicitly &lt;em&gt;ask&lt;/em&gt; the model to cheat during training, so cheating no longer implied a malicious character.&lt;/p&gt;

&lt;p&gt;Personality traits travel together in these systems, the way they do in people. That's exactly why models feel like coherent characters rather than bags of behaviors — and why nobody can dial in a "perfect" personality on demand.&lt;/p&gt;

&lt;h2&gt;
  
  
  The practical consequence: we'll choose models like we choose collaborators
&lt;/h2&gt;

&lt;p&gt;Here's where I think this goes.&lt;/p&gt;

&lt;p&gt;Today we mostly compare models on benchmarks, which measure the model alone. But nobody works with a model alone — you work in a loop with it, and the loop's performance depends on fit. I use GPT for serious audits and gnarly code logic because it catches gaps Claude misses; the nerd is genuinely better at that. But for daily building and brainstorming I reach for Claude, because it thinks one step ahead of me and I hit flow state faster. That's not a benchmark result. That's compatibility.&lt;/p&gt;

&lt;p&gt;One commenter said it well: everyone's agent should be adjusted to their personal flavor. Custom system prompts, custom instructions, personas — that's the surface-level version, and it works up to a point. But the default personality underneath is strong, deliberately so, and it leaks through. Which means the &lt;em&gt;base character&lt;/em&gt; of a model is becoming a real product differentiator, not a cosmetic one.&lt;/p&gt;

&lt;p&gt;My predictions:&lt;/p&gt;

&lt;p&gt;Model personalities will diverge, not converge. As capabilities plateau between frontier labs, character becomes a place to compete, and the persona selection research suggests labs will increasingly design "AI role models" on purpose rather than inheriting whatever archetype pretraining coughs up.&lt;/p&gt;

&lt;p&gt;"Which model do you use?" will sound more like "who do you work with?" People already split — some find Claude's character warm, some find it something to fight against; some find GPT precise, some find it cold. Neither side is wrong. They're describing fit.&lt;/p&gt;

&lt;p&gt;And as agents get more distinct and more embedded in the web, telling human from machine by &lt;em&gt;vibe&lt;/em&gt; will stop being reliable. The personas are only getting more fleshed out.&lt;/p&gt;

&lt;h2&gt;
  
  
  So am I crazy?
&lt;/h2&gt;

&lt;p&gt;No — but I was half wrong. The personality I perceive is partly a mirror. The other part is a genuine, trained, emergent character that even its creators steer rather than script.&lt;/p&gt;

&lt;p&gt;Which means the honest answer to "which model is best?" is increasingly: &lt;em&gt;best for whom?&lt;/em&gt; Benchmark the model, sure. But also pay attention to which one lets &lt;strong&gt;you&lt;/strong&gt; think better. That's the number that actually matters, and no leaderboard measures it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This grew out of two Reddit threads &lt;a href="https://www.reddit.com/r/ClaudeAI/comments/1uz2piw/does_anyone_else_feel_like_each_ai_model_has_a/" rel="noopener noreferrer"&gt;1&lt;/a&gt; &lt;a href="https://www.reddit.com/r/OpenAI/comments/1uzui2d/ai_personality_gpt_vs_claude/" rel="noopener noreferrer"&gt;2&lt;/a&gt; — thanks to everyone who argued with me, especially the person who called GPT a rogue and the one who linked the persona selection paper. If you find Claude's personality annoying or overrated, I still genuinely want to hear why.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>chatgpt</category>
      <category>openai</category>
    </item>
    <item>
      <title>Onboard AI agents like you onboard devs</title>
      <dc:creator>Dimon</dc:creator>
      <pubDate>Tue, 14 Jul 2026 21:32:11 +0000</pubDate>
      <link>https://dev.to/dimonb19a/onboard-ai-agents-like-you-onboard-devs-23nm</link>
      <guid>https://dev.to/dimonb19a/onboard-ai-agents-like-you-onboard-devs-23nm</guid>
      <description>&lt;p&gt;When new devs join a project, someone walks them through the conventions - where things live, what the house rules are, which commands to run. AI agents get none of that. Every session starts context-blind, and an agent that finds no instructions doesnt ask - it guesses. Recent surveys say that most engineers now use 2-4 AI tools at once. If you have more than a couple of devs, you effectively have a multi-agent repo whether you planned it or not. So the question isnt whether to write onboarding docs for agents - its which ones, because they read different files.&lt;/p&gt;




&lt;h3&gt;
  
  
  Tier 1 — mandatory.
&lt;/h3&gt;

&lt;p&gt;Two files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AGENTS.md&lt;/strong&gt; — the cross-tool standard, Linux Foundation-hosted since Dec 2025, read natively by Codex, Copilot's coding agent, Cursor, Windsurf and roughly two dozen other tools. Content: stack, commands, hard rules, pointers to deeper docs. Keep it under ~200 lines.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CLAUDE.md&lt;/strong&gt; — exists solely because Claude Code (the most-used agent in recent surveys) is the one major tool that doesn't read AGENTS.md. Anthropic's own recommended bridge: first line '@AGENTS.md' (Claude Code expands the import at session start), with Claude-specific notes below. So the mandatory setup is two files, and one is a pointer.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have multi-step workflows worth teaching (release process, scaffolding recipes), add skills: the SKILL.md format went cross-vendor after Anthropic opened the spec, and the same folder now loads in Claude Code, Codex, VS Code and Gemini CLI. Only quirk: Claude Code looks in .claude/skills/, Codex in .agents/skills/ — mirror one to the other and move on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tier 2 — do it if the tools are actually in your org.
&lt;/h3&gt;

&lt;p&gt;Copilot and Cursor both read AGENTS.md, so this tier buys optimization, not coverage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Copilot&lt;/strong&gt; — .github/copilot-instructions.md for in-editor chat; .github/instructions/*.instructions.md for applyTo-scoped rules.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cursor&lt;/strong&gt; — .cursor/rules: the auto-attach-by-glob rule type is the real feature. Conventions load only where they apply.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No Copilot seats, no Cursor users → skip the tier entirely.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tier 3 — nice-to-have.
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MCP server&lt;/strong&gt; — if you have machine-readable assets (tokens, registries, schemas), agents query live data instead of grepping stale prose.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Gemini CLI&lt;/strong&gt; — reads GEMINI.md by default, but a checked-in .gemini/settings.json can point context.fileName at AGENTS.md (config beats another markdown file).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Portable system-prompt doc&lt;/strong&gt; — for raw-API callers and eval harnesses; derive it from AGENTS.md.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;The part that actually matters: &lt;strong&gt;dont hand-maintain these files&lt;/strong&gt;. They will drift, and a wrong instruction file is worse than none because the agent trusts it and never double-checks. Generate every surface from one source of truth with a dumb deterministic template script (no LLM in the build), so re-runs are byte-stable - CI regenerates everything and fails on any diff.&lt;/p&gt;

&lt;p&gt;This whole thing is accidental complexity tho. There are two real standards now: AGENTS.md for context, SKILL.md for workflows. Most of the per-tool files exist just because vendors shipped their own filename before agreeing on anything.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>agentskills</category>
    </item>
    <item>
      <title>Color Palette</title>
      <dc:creator>Dimon</dc:creator>
      <pubDate>Fri, 26 Jun 2026 13:58:53 +0000</pubDate>
      <link>https://dev.to/dimonb19a/color-palette-550m</link>
      <guid>https://dev.to/dimonb19a/color-palette-550m</guid>
      <description>&lt;p&gt;I had a chance to work on a runtime theming engine in some UI system where we have a support for different themes: 3 types of physics &lt;em&gt;(glass/flat/retro)&lt;/em&gt;, and 2 modes &lt;em&gt;(dark/light)&lt;/em&gt;. Basically, the color palette is a list of CSS variables and you just switch colors to change theme. The most valuable part of our color palette is &lt;strong&gt;«energy axis»&lt;/strong&gt;: &lt;code&gt;--energy-primary&lt;/code&gt; and &lt;code&gt;--energy-secondary&lt;/code&gt; colors. While we use &lt;strong&gt;Secondary&lt;/strong&gt; color for some UI elements/states just to get some vibe/mood, &lt;strong&gt;Primary&lt;/strong&gt; color is used to determine all the rest of palette. There is even functionality provided where you can build all the theme just defining a primary color:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhazi21t8ld40fhlhia38.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhazi21t8ld40fhlhia38.gif" alt=" " width="720" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dark mode applies when the primary color is light, and light mode - when the primary is dark.&lt;/p&gt;

&lt;p&gt;Beside &lt;strong&gt;primary&lt;/strong&gt;/&lt;strong&gt;secondary&lt;/strong&gt; colors we also have some &lt;strong&gt;«surface axis»&lt;/strong&gt;, here is all the basic palette:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo062yuyosfu06yoklelk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo062yuyosfu06yoklelk.png" alt=" " width="799" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So the colors are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;canvas&lt;/strong&gt; - background, absolute zero;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;surface&lt;/strong&gt; - raised area, some card;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;spotlight&lt;/strong&gt; - the light on canvas, for lighter surfaces;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;sunk&lt;/strong&gt; - the hole in surface, sunked area;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;border&lt;/strong&gt; - surface borders color.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Also there is 3 layers of text: &lt;strong&gt;Main&lt;/strong&gt;, &lt;strong&gt;Dim&lt;/strong&gt;, &lt;strong&gt;Mute&lt;/strong&gt;. The text hierarchy.&lt;/p&gt;

&lt;p&gt;We use &lt;code&gt;--energy-primary&lt;/code&gt; color to calculate the rest of palette so it can be much colorful where needed, for example charts where we need to differentiate the data:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F49sxnebyxfxt8c9qrjwf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F49sxnebyxfxt8c9qrjwf.png" alt=" " width="799" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So we have &lt;strong&gt;8 data&lt;/strong&gt; colors calculated from primary, and &lt;strong&gt;3 compemantary&lt;/strong&gt; ones to primary.&lt;/p&gt;

&lt;p&gt;The last axis is &lt;strong&gt;«semantic colors»&lt;/strong&gt;. Those 4 colors that always have similar meaning: &lt;strong&gt;Success&lt;/strong&gt;, &lt;strong&gt;Error&lt;/strong&gt;, &lt;strong&gt;Premium&lt;/strong&gt;, and &lt;strong&gt;System&lt;/strong&gt;. The convention is to use Warning / Info naming tho. We use Premium color either to highlight premium/paid features, or for warning states. Just with one caveat - when it collides with primary color (same hue) then we have to switch Premium to cyan/saphire, so it preserves its importance, and still highlights features that require attention. Same logic for System color - we use purple mostly but when there is some purple theme applied - System switches to blue. System is less valuable than Premium but it still has to be distinct from other UI elements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0exqiod5igdtu9ceygbp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0exqiod5igdtu9ceygbp.png" alt=" " width="799" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bootstrap, Ant, Chakra, Carbon, Spectrum all ship &lt;strong&gt;success/error/warning/info&lt;/strong&gt; - thats a conventional naming that we dont follow strictly. &lt;strong&gt;Premium/System&lt;/strong&gt; colors have to be &lt;strong&gt;distinct from a primary color&lt;/strong&gt; that changes every theme. When the primary hue lands in a semantic color's hue family, that theme reassigns the semantic to escape it. Classic &lt;strong&gt;Warning&lt;/strong&gt; means orange/yellow - &lt;em&gt;"color meaning"&lt;/em&gt;, our &lt;strong&gt;Premium&lt;/strong&gt; has &lt;em&gt;"role meanining"&lt;/em&gt; and we use it to bring attention. &lt;strong&gt;System&lt;/strong&gt; is for platform/system features that should stand &lt;em&gt;apart&lt;/em&gt; from the rest of the UI but must not be loud or compete with the brand hierarchy — sometimes that's literally &lt;em&gt;"info,"&lt;/em&gt; sometimes &lt;em&gt;"this is a platform affordance."&lt;/em&gt; A quiet, distinct purple-or-blue is the right register for &lt;em&gt;"notice this, it's different, but it isn't urgent."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So we have basically renamed 'warning'-&amp;gt;'premium' and 'info'-&amp;gt;'system' because we use them wider and swap hue to preserve similar attention across palettes. Hope it makes sense.&lt;/p&gt;

</description>
      <category>ui</category>
      <category>design</category>
      <category>css</category>
    </item>
    <item>
      <title>Flexible density for all the UI</title>
      <dc:creator>Dimon</dc:creator>
      <pubDate>Thu, 25 Jun 2026 11:17:25 +0000</pubDate>
      <link>https://dev.to/dimonb19a/flexible-density-for-all-the-ui-4634</link>
      <guid>https://dev.to/dimonb19a/flexible-density-for-all-the-ui-4634</guid>
      <description>&lt;p&gt;In our UI system we dont use pixel values to define spacing, we use semantic variables, (t-shirt sizes: &lt;code&gt;gap-sm&lt;/code&gt;, &lt;code&gt;p-lg&lt;/code&gt;, &lt;code&gt;my-2xl&lt;/code&gt;) - so thats like you change one CSS variable, and the whole UI adapts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgf6ybmak7mucegkxu40l.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgf6ybmak7mucegkxu40l.gif" alt=" " width="760" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We limit user customization to just 5 presets - &lt;strong&gt;0.8&lt;/strong&gt; / &lt;strong&gt;0.9&lt;/strong&gt; / &lt;strong&gt;1&lt;/strong&gt; / &lt;strong&gt;1.1&lt;/strong&gt; / &lt;strong&gt;1.2&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Symmetric around 1.0&lt;/strong&gt; - two steps down, two up;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;±20% is deliberately restrained&lt;/strong&gt;&amp;nbsp;- enough to change the&amp;nbsp;feel&amp;nbsp;(data-dense ↔ spacious) without breaking layouts or distorting proportions;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;5 discrete stops = perceptible but decision-light.&lt;/strong&gt;&amp;nbsp;Most users never open the control, so it's a coarse preference, not a fine instrument&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The biggest reason why do we have it - to support bigger themes differentiation. Brand-overlay density has slightly bigger range: &lt;strong&gt;0.7–1.35&lt;/strong&gt;; so we can differentiate brands providing customizable UI: &lt;em&gt;&amp;gt;1 reads editorial/airy, &amp;lt;1 terminal/dense.&lt;/em&gt; Same components, different feel — no fork. The user can always override.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/* Density cascade: user override → brand default → system default (1) */
--density: var(--user-density, var(--brand-density, 1));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Everything is built on a &lt;code&gt;4px&lt;/code&gt; base unit and a single &lt;code&gt;--density&lt;/code&gt; variable, all declared in &lt;code&gt;:root&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--unit: 0.25rem; 
/* Every spacing token is base-step × unit × density */
--space-xs:  calc(2  * var(--unit) * var(--density, 1));  /*  8px @ d=1 */
--space-sm:  calc(4  * var(--unit) * var(--density, 1));  /* 16px */
--space-md:  calc(6  * var(--unit) * var(--density, 1));  /* 24px */
--space-lg:  calc(8  * var(--unit) * var(--density, 1));  /* 32px */
--space-xl:  calc(12 * var(--unit) * var(--density, 1));  /* 48px */
--space-2xl: calc(16 * var(--unit) * var(--density, 1));  /* 64px */
--space-3xl: calc(24 * var(--unit) * var(--density, 1));  /* 96px */
--space-4xl: calc(32 * var(--unit) * var(--density, 1));  /* 128px */
--space-5xl: calc(40 * var(--unit) * var(--density, 1));  /* 160px */
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But those are details, the main point was to have flexible spacing underneath so all the UI is adaptable to any vibe.&lt;/p&gt;




&lt;p&gt;Also if we talk about accessibility - minimum control height&amp;nbsp;is preserved, different for touch screens:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;--size-touch-min: 2.75rem; /* 44px — coarse/touch base (scales with density) */
--control-height-min: 2.25rem; /* 36px — coarse floor (hard min) */

@media (pointer: fine) {
  --size-touch-min: 2.25rem; /* 36px — fine/mouse base */
  --control-height-min: 2rem; /* 32px — fine floor */
}

--control-height: max(var(--control-height-min), calc(var(--size-touch-min) * var(--density)));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;44px touch base&lt;/strong&gt;&amp;nbsp;= the WCAG 2.5.5 / Apple HIG / Material touch-target minimum — a finger needs ~44 CSS px.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;36px desktop base&lt;/strong&gt;&amp;nbsp;= the 2026 SaaS convention (Linear / Vercel / shadcn / Notion); a mouse is precise, so desktop controls can be denser than touch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The floors exist because controls, unlike spacing, cant shrink freely.&lt;/strong&gt;&amp;nbsp;Spacing tokens have no floor (Compact just scales them down). Controls are clamped by&amp;nbsp;max()&amp;nbsp;so Compact density (0.8×) can't shrink a button into an un-hittable size:&amp;nbsp;44×0.8 = 35.2 → 36&amp;nbsp;on touch,&amp;nbsp;36×0.8 = 28.8 → 32&amp;nbsp;on desktop. That asymmetry (whitespace compresses without limit, hit-targets don't) is the whole point of the floor.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The floor is a&amp;nbsp;separate variable&amp;nbsp;from the base&lt;/strong&gt;&amp;nbsp;so Compact can legally drop&amp;nbsp;below&amp;nbsp;the standard (desktop 36 → 32) while still being bounded. If the floor equalled the base, density could never push a control under its standard size at all.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>css</category>
      <category>ui</category>
      <category>designpatterns</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Nice custom Svelte animations</title>
      <dc:creator>Dimon</dc:creator>
      <pubDate>Sun, 21 Jun 2026 11:49:12 +0000</pubDate>
      <link>https://dev.to/dimonb19a/nice-custom-svelte-animations-4ab1</link>
      <guid>https://dev.to/dimonb19a/nice-custom-svelte-animations-4ab1</guid>
      <description>&lt;p&gt;Svelte ships&amp;nbsp;&lt;strong&gt;fade, fly, slide, scale, blur,&lt;/strong&gt; …&amp;nbsp;in&amp;nbsp;&lt;code&gt;svelte/transition&lt;/code&gt; so you can just import those ones and use them out of the box. But you also can create your own actions and transitions, and use them via &lt;code&gt;use:&lt;/code&gt; directive, or with &lt;code&gt;in:/out:&lt;/code&gt;, - very convenient across elements. Let me share several actions that i use the most often in our design system.&lt;/p&gt;

&lt;p&gt;What Svelte gives you natively is the &lt;strong&gt;ergonomics&lt;/strong&gt;: a one-line &lt;code&gt;use:/in:/out:&lt;/code&gt; directive on any element, with teardown handled for you. React has no native directive and no built-in enter/exit system — exit animations in particular usually mean a library like AnimatePresence. (Vue, fair to note, has both natively — custom directives and &lt;code&gt;&amp;lt;Transition&amp;gt;&lt;/code&gt;.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Materialize / Dematerialize
&lt;/h2&gt;

&lt;p&gt;Visual-only &lt;strong&gt;enter/exit&lt;/strong&gt; for overlays (&lt;em&gt;modals, tooltips, toasts&lt;/em&gt;) — &lt;code&gt;opacity&lt;/code&gt; + &lt;code&gt;scale&lt;/code&gt; + &lt;code&gt;blur&lt;/code&gt; + &lt;code&gt;Y&lt;/code&gt;, no layout shift. Custom alternative to Svelte's built-in&amp;nbsp;fade.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff9fkeeg23rl5d08bl05q.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff9fkeeg23rl5d08bl05q.gif" alt=" " width="760" height="475"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;#if&lt;/span&gt; &lt;span class="nx"&gt;open&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;in:materialize&lt;/span&gt; &lt;span class="na"&gt;out:dematerialize&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Modal / tooltip / toast content
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;/if&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Morph
&lt;/h2&gt;

&lt;p&gt;A persistent element smoothly resizes when its content changes - no &lt;strong&gt;mount/unmount&lt;/strong&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsdw2666z058e31uzaceu.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsdw2666z058e31uzaceu.gif" alt=" " width="720" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;use:morph=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;#if&lt;/span&gt; &lt;span class="nx"&gt;expanded&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;LongContent&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;ShortContent&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;/if&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Emerge / Dissolve
&lt;/h2&gt;

&lt;p&gt;The counterpart to morph. Morph animates an&amp;nbsp;existing&amp;nbsp;element's size; emerge/dissolve&amp;nbsp;&lt;strong&gt;mount&lt;/strong&gt; and &lt;strong&gt;unmount&lt;/strong&gt;&amp;nbsp;elements - and because they animate the new card's height and margin up from zero, the card below slides down to make room instead of snapping.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkvenr9gwzydr30u98olf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkvenr9gwzydr30u98olf.gif" alt=" " width="720" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;#each&lt;/span&gt; &lt;span class="nx"&gt;cards&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nf"&gt;card &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;in:emerge&lt;/span&gt; &lt;span class="na"&gt;out:dissolve&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="k"&gt;/each&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tooltip
&lt;/h2&gt;

&lt;p&gt;Hover or focus a button - a tooltip appears and Floating UI flips / shifts it to stay on screen. This is the one action that imports a third-party package, for the collision-aware positioning math.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flt7sdoinq7lp9eaad3t8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flt7sdoinq7lp9eaad3t8.gif" alt=" " width="720" height="360"&gt;&lt;/a&gt;&lt;br&gt;
Imports&amp;nbsp;&lt;code&gt;@floating-ui/dom&lt;/code&gt;&amp;nbsp;(&lt;code&gt;computePosition&lt;/code&gt;&amp;nbsp;+&amp;nbsp;&lt;code&gt;flip&lt;/code&gt;/&lt;code&gt;shift&lt;/code&gt;&amp;nbsp;+&amp;nbsp;&lt;code&gt;autoUpdate&lt;/code&gt;)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;use:tooltip=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Saved to your library&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Hover me&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Gradient Border
&lt;/h2&gt;

&lt;p&gt;The CTA's rotating comet border stops spinning on hover and locks onto your cursor.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw8sjc04q8dy0pclixopk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw8sjc04q8dy0pclixopk.gif" alt=" " width="720" height="450"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn-cta"&lt;/span&gt; &lt;span class="na"&gt;use:laserAim&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Get started&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>svelte</category>
      <category>animation</category>
    </item>
    <item>
      <title>Building an Animated 404 Ring</title>
      <dc:creator>Dimon</dc:creator>
      <pubDate>Thu, 18 Jun 2026 11:44:16 +0000</pubDate>
      <link>https://dev.to/dimonb19a/building-an-animated-404-ring-2n1h</link>
      <guid>https://dev.to/dimonb19a/building-an-animated-404-ring-2n1h</guid>
      <description>&lt;p&gt;This is a write-up of the animated ring I built for a 404 page. It's a single component that renders an SVG "portal" — a set of concentric rings with drifting particles, a slow wobble, and a parallax response to the cursor. The page is server-rendered, so the component also has to be SSR-safe and reasonably cheap to run. Here's how each part works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4obnyv997zj0qoqaqx8y.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4obnyv997zj0qoqaqx8y.gif" alt=" " width="720" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating the geometry
&lt;/h2&gt;

&lt;p&gt;The rings, particles, and orbital markers are generated from their index rather than placed by hand. The particles use the golden angle so they distribute evenly around the circle without clustering:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GOLDEN_ANGLE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.399963&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;particles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;GOLDEN_ANGLE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isDrift&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;radius&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isDrift&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;170&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;135&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;95&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;cx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// size, delay, and duration also derived from i&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each particle is offset by ~137.5° from the previous one, which gives even angular coverage. The first eight drift across an expanding radius; the rest sit on the ring radii. Sizes, delays, and durations come from small modulo offsets on the index so the particles don't animate in sync.&lt;/p&gt;

&lt;p&gt;The important property here is that there's no &lt;code&gt;Math.random()&lt;/code&gt;. Because the page is server-rendered, a random layout would differ between the server and the client and cause a hydration mismatch. Deriving everything from the index keeps the two outputs identical.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parallax from layered transforms
&lt;/h2&gt;

&lt;p&gt;The ring is a stack of six SVG groups: a background gradient, three ring systems, an orbital field, the particles, and the "404" text. Each group translates by the pointer offset times a different factor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;g&lt;/span&gt; &lt;span class="na"&gt;style:transform=&lt;/span&gt;&lt;span class="s"&gt;"translate({px * 12}px, {py * 12}px)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;…&lt;span class="nt"&gt;&amp;lt;/g&amp;gt;&lt;/span&gt;  &lt;span class="c"&gt;&amp;lt;!-- outer rings --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;g&lt;/span&gt; &lt;span class="na"&gt;style:transform=&lt;/span&gt;&lt;span class="s"&gt;"translate({px * 26}px, {py * 26}px)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;…&lt;span class="nt"&gt;&amp;lt;/g&amp;gt;&lt;/span&gt;  &lt;span class="c"&gt;&amp;lt;!-- inner rings --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;g&lt;/span&gt; &lt;span class="na"&gt;style:transform=&lt;/span&gt;&lt;span class="s"&gt;"translate({px * 32}px, {py * 32}px)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;…&lt;span class="nt"&gt;&amp;lt;/g&amp;gt;&lt;/span&gt;  &lt;span class="c"&gt;&amp;lt;!-- "404" text --&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The larger the factor, the more the layer moves, which reads as the layer sitting closer to the viewer. The "404" (×32) moves most; the outer rings (×12) least. The SVG is flat, but the differing translate amounts give it a sense of depth as the cursor moves.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;px&lt;/code&gt; and &lt;code&gt;py&lt;/code&gt; are the smoothed pointer position, scaled by an &lt;code&gt;intensity&lt;/code&gt; prop so the effect can be turned up or down per usage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Smoothing and wobble
&lt;/h2&gt;

&lt;p&gt;Tracking the cursor directly looks abrupt, so the pointer values are eased toward a target each frame:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SMOOTHING&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.06&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;pointerX&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetX&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;pointerX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;SMOOTHING&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;pointerY&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetY&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;pointerY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;SMOOTHING&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's an exponential approach — each frame closes 6% of the remaining distance — so the ring follows the cursor with a slight lag instead of snapping to it.&lt;/p&gt;

&lt;p&gt;On top of the parallax, the rings scale slightly using a wobble value built from three sine waves at unrelated frequencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;ringWobble&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.008&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
   &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.005&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
   &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;2.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.003&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
  &lt;span class="nx"&gt;wobbleEnergy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The three frequencies don't share a common period, so the motion doesn't visibly repeat. &lt;code&gt;wobbleEnergy&lt;/code&gt; scales the whole thing and is itself driven by how far the cursor is from the center (&lt;code&gt;0.5 + distance * 0.5&lt;/code&gt;), so the rings stay calmer near the middle and move more toward the edges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three rendering modes
&lt;/h2&gt;

&lt;p&gt;The interface lives in has three visual modes — glass, flat, and retro — set with a &lt;code&gt;data-physics&lt;/code&gt; attribute on the page. The SVG markup is identical in all three; the differences are handled in scoped CSS, so the component doesn't branch in JavaScript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcwlns00qoyptfnhts7t5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcwlns00qoyptfnhts7t5.png" alt=" " width="800" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Glass applies an SVG turbulence filter and a glow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scss"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-physics&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'glass'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nc"&gt;.portal-ring&lt;/span&gt; &lt;span class="nc"&gt;.ring-outer-system&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;portal-warp-glass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;drop-shadow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt; &lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;accent&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight svelte"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;filter&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"warp-glass"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;feTurbulence&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"fractalNoise"&lt;/span&gt; &lt;span class="na"&gt;baseFrequency=&lt;/span&gt;&lt;span class="s"&gt;"0.12"&lt;/span&gt; &lt;span class="na"&gt;numOctaves=&lt;/span&gt;&lt;span class="s"&gt;"3"&lt;/span&gt; &lt;span class="na"&gt;result=&lt;/span&gt;&lt;span class="s"&gt;"noise"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;feDisplacementMap&lt;/span&gt; &lt;span class="na"&gt;in=&lt;/span&gt;&lt;span class="s"&gt;"SourceGraphic"&lt;/span&gt; &lt;span class="na"&gt;in2=&lt;/span&gt;&lt;span class="s"&gt;"noise"&lt;/span&gt; &lt;span class="na"&gt;scale=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/filter&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;feTurbulence&lt;/code&gt; generates a noise field and &lt;code&gt;feDisplacementMap&lt;/code&gt; offsets each pixel of the rings by it, which produces a slight warp. Flat uses the same filter with a lower frequency and no glow. Retro removes the filter entirely, switches the animation timing to &lt;code&gt;steps()&lt;/code&gt; so the motion is stepped, dashes the strokes, and renders "404" in a monospace font.&lt;/p&gt;

&lt;p&gt;One detail worth noting: the filter IDs are generated per instance (from a stable, SSR-safe id) and passed into the CSS through a custom property. That lets the stylesheet reference a filter whose ID it doesn't know ahead of time, and keeps multiple rings on a page from colliding.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS for ambient motion, JS for interaction
&lt;/h2&gt;

&lt;p&gt;Most of the motion — the rings spinning, the particles drifting, the arcs drawing, an occasional glitch flash — is CSS &lt;code&gt;@keyframes&lt;/code&gt;. The JavaScript only handles the pointer parallax and the wobble.&lt;/p&gt;

&lt;p&gt;That split has two practical benefits: the animation runs without JavaScript, so it works on touch devices and before hydration; and the only code that has to run on the main thread is the part that actually responds to the cursor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping the JS bounded
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;requestAnimationFrame&lt;/code&gt; loop tracking the pointer can waste work if it isn't constrained, so the component limits when it runs.&lt;/p&gt;

&lt;p&gt;It only animates while it's on screen, using an &lt;code&gt;IntersectionObserver&lt;/code&gt; to start and stop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IntersectionObserver&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;isVisible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isIntersecting&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isVisible&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;stopAnimation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The loop also stops itself once motion has settled, instead of running every frame indefinitely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ease pointer + wobble toward their targets…&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;shouldContinueAnimating&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;frameId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;shouldContinueAnimating()&lt;/code&gt; returns false once the pointer and wobble are within a small epsilon of their targets, so the loop sleeps when nothing is moving and the next pointer event restarts it. The bounding rect is cached and only re-measured on scroll or resize, which avoids a layout read on every pointer event.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessibility
&lt;/h2&gt;

&lt;p&gt;The SVG is &lt;code&gt;aria-hidden&lt;/code&gt;, since it's decorative; the page heading carries the actual "page not found" message. Under &lt;code&gt;prefers-reduced-motion&lt;/code&gt;, the rAF loop never starts and the CSS animations are replaced with a static state, so the ring renders without movement.&lt;/p&gt;




&lt;p&gt;That's the whole component: generated geometry, layered parallax, eased pointer input, three CSS-driven rendering modes, and a render loop that only runs when it needs to.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>404</category>
    </item>
  </channel>
</rss>
