[{"data":1,"prerenderedAt":303},["ShallowReactive",2],{"docs:\u002Fdocs\u002Fhow-it-works":3},{"id":4,"title":5,"body":6,"description":294,"extension":295,"meta":296,"navigation":297,"path":298,"rawbody":299,"seo":300,"stem":301,"__hash__":302},"docs\u002Fdocs\u002Fhow-it-works.md","How it works",{"type":7,"value":8,"toc":282},"minimark",[9,14,18,101,135,146,149,153,172,175,212,215,219,222,226,229,251,254,258,261,265,268,272],[10,11,13],"h2",{"id":12},"what-kinesis-writes","What Kinesis writes",[15,16,17],"p",{},"Kinesis writes a fixed set of inline styles, and only on elements it animates:",[19,20,21,34],"table",{},[22,23,24],"thead",{},[25,26,27,31],"tr",{},[28,29,30],"th",{},"Property",[28,32,33],{},"When",[35,36,37,56,75,85],"tbody",{},[25,38,39,53],{},[40,41,42,46,47,46,50],"td",{},[43,44,45],"code",{},"translate",", ",[43,48,49],{},"rotate",[43,51,52],{},"scale",[40,54,55],{},"while the element is moved, turned, or scaled",[25,57,58,72],{},[40,59,60,46,63,46,66,46,69],{},[43,61,62],{},"opacity",[43,64,65],{},"filter",[43,67,68],{},"color",[43,70,71],{},"background-color",[40,73,74],{},"only with the matching reaction output",[25,76,77,82],{},[40,78,79],{},[43,80,81],{},"touch-action",[40,83,84],{},"on draggable elements",[25,86,87,98],{},[40,88,89,46,92,46,95],{},[43,90,91],{},"--k-progress",[43,93,94],{},"--k-pointer-x",[43,96,97],{},"--k-pointer-y",[40,99,100],{},"on reacting or tracking elements",[15,102,103,104,107,108,111,112,46,114,116,117,119,120,122,123,126,127,46,129,131,132,134],{},"It never writes ",[43,105,106],{},"transform"," or ",[43,109,110],{},"transform-origin",". Browsers apply ",[43,113,45],{},[43,115,49],{},", and ",[43,118,52],{}," before ",[43,121,106],{},", so centering with ",[43,124,125],{},"transform: translate(-50%, -50%)"," and your hover transforms keep working. If you set ",[43,128,45],{},[43,130,49],{},", or ",[43,133,52],{}," yourself, Kinesis adds its motion to your value.",[15,136,137,138,141,142,145],{},"For 3D, it may set ",[43,139,140],{},"perspective"," on a tilted element's parent if the parent has none, and ",[43,143,144],{},"transform-style: preserve-3d"," on the elements between a depth layer and its tilted ancestor.",[15,147,148],{},"At rest, these inline values are removed. When an element stops being animated, or its scope is destroyed, the original inline values come back exactly.",[10,150,152],{"id":151},"how-elements-are-found","How elements are found",[15,154,155,156,159,160,163,164,167,168,171],{},"Each ",[43,157,158],{},"[data-kinesis]"," scope scans its descendants once. It reads twelve trigger properties per element, such as ",[43,161,162],{},"--k-parallax"," and ",[43,165,166],{},"--k-when",", and reads the rest only for elements that use Kinesis. By then the browser has resolved units, ",[43,169,170],{},"calc()",", variables, and colors.",[15,173,174],{},"After that, Kinesis re-reads only what can have changed:",[176,177,178,192,199,202],"ul",{},[179,180,181,182,46,185,131,188,191],"li",{},"added elements, and elements whose ",[43,183,184],{},"class",[43,186,187],{},"style",[43,189,190],{},"hidden"," attribute changed, with their descendants",[179,193,194,195,198],{},"the elements under the pointer as it moves between elements, for ",[43,196,197],{},":hover"," rules",[179,200,201],{},"the focused element and its ancestors",[179,203,204,205,107,208,211],{},"the whole scope after a window resize, a theme change on ",[43,206,207],{},"\u003Chtml>",[43,209,210],{},"\u003Cbody>",", or a new stylesheet",[15,213,214],{},"It never polls computed styles in the animation loop. On a test page of 1,600 elements, the first scan takes about 2 ms on a desktop computer. A class change on one element re-reads that element and its children.",[10,216,218],{"id":217},"geometry","Geometry",[15,220,221],{},"Kinesis measures positions without its own transforms, so elements react from where you placed them. Positions are stored relative to the document, so scrolling needs no re-measuring. Kinesis re-measures after a resize, a DOM change, a scroll inside a nested container, or the pointer entering a scope.",[10,223,225],{"id":224},"the-frame-loop","The frame loop",[15,227,228],{},"One loop runs for the whole page. Each frame has three phases:",[230,231,232,239,245],"ol",{},[179,233,234,238],{},[235,236,237],"strong",{},"Read."," Apply pending configuration and measurements, if anything changed.",[179,240,241,244],{},[235,242,243],{},"Compute."," Math only, with pointer and scroll input sampled once per frame.",[179,246,247,250],{},[235,248,249],{},"Write."," Update only the styles whose value changed.",[15,252,253],{},"Reads never follow writes within a frame, so Kinesis causes no layout thrashing. When every spring has settled and no input is changing, the loop stops and the page runs no frames at all. Offscreen elements and scopes are skipped, and hidden tabs pause.",[10,255,257],{"id":256},"springs","Springs",[15,259,260],{},"Springs advance with the exact solution of a damped oscillator. They behave the same at any frame rate and stay stable after long pauses. They snap to rest within a hundredth of a pixel or degree.",[10,262,264],{"id":263},"size","Size",[15,266,267],{},"The core is 14 KB minified and gzipped, with no dependencies. Text splitting and audio are separate imports.",[10,269,271],{"id":270},"browser-support","Browser support",[15,273,274,275,278,279,281],{},"Kinesis needs registered custom properties, the individual transform properties, and ",[43,276,277],{},"color-mix()",". That means Chrome and Edge 111+, Safari 16.4+, and Firefox 128+. Older browsers don't resolve values written with ",[43,280,170],{},", variables, or relative units, so they get less motion or none. The page still works.",{"title":283,"searchDepth":284,"depth":284,"links":285},"",3,[286,288,289,290,291,292,293],{"id":12,"depth":287,"text":13},2,{"id":151,"depth":287,"text":152},{"id":217,"depth":287,"text":218},{"id":224,"depth":287,"text":225},{"id":256,"depth":287,"text":257},{"id":263,"depth":287,"text":264},{"id":270,"depth":287,"text":271},"What Kinesis writes, how it finds elements, and why an idle page costs nothing.","md",{},true,"\u002Fdocs\u002Fhow-it-works","---\ntitle: How it works\ndescription: What Kinesis writes, how it finds elements, and why an idle page costs nothing.\n---\n\n## What Kinesis writes\n\nKinesis writes a fixed set of inline styles, and only on elements it animates:\n\n| Property | When |\n| --- | --- |\n| `translate`, `rotate`, `scale` | while the element is moved, turned, or scaled |\n| `opacity`, `filter`, `color`, `background-color` | only with the matching reaction output |\n| `touch-action` | on draggable elements |\n| `--k-progress`, `--k-pointer-x`, `--k-pointer-y` | on reacting or tracking elements |\n\nIt never writes `transform` or `transform-origin`. Browsers apply `translate`, `rotate`, and `scale` before `transform`, so centering with `transform: translate(-50%, -50%)` and your hover transforms keep working. If you set `translate`, `rotate`, or `scale` yourself, Kinesis adds its motion to your value.\n\nFor 3D, it may set `perspective` on a tilted element's parent if the parent has none, and `transform-style: preserve-3d` on the elements between a depth layer and its tilted ancestor.\n\nAt rest, these inline values are removed. When an element stops being animated, or its scope is destroyed, the original inline values come back exactly.\n\n## How elements are found\n\nEach `[data-kinesis]` scope scans its descendants once. It reads twelve trigger properties per element, such as `--k-parallax` and `--k-when`, and reads the rest only for elements that use Kinesis. By then the browser has resolved units, `calc()`, variables, and colors.\n\nAfter that, Kinesis re-reads only what can have changed:\n\n- added elements, and elements whose `class`, `style`, or `hidden` attribute changed, with their descendants\n- the elements under the pointer as it moves between elements, for `:hover` rules\n- the focused element and its ancestors\n- the whole scope after a window resize, a theme change on `\u003Chtml>` or `\u003Cbody>`, or a new stylesheet\n\nIt never polls computed styles in the animation loop. On a test page of 1,600 elements, the first scan takes about 2 ms on a desktop computer. A class change on one element re-reads that element and its children.\n\n## Geometry\n\nKinesis measures positions without its own transforms, so elements react from where you placed them. Positions are stored relative to the document, so scrolling needs no re-measuring. Kinesis re-measures after a resize, a DOM change, a scroll inside a nested container, or the pointer entering a scope.\n\n## The frame loop\n\nOne loop runs for the whole page. Each frame has three phases:\n\n1. **Read.** Apply pending configuration and measurements, if anything changed.\n2. **Compute.** Math only, with pointer and scroll input sampled once per frame.\n3. **Write.** Update only the styles whose value changed.\n\nReads never follow writes within a frame, so Kinesis causes no layout thrashing. When every spring has settled and no input is changing, the loop stops and the page runs no frames at all. Offscreen elements and scopes are skipped, and hidden tabs pause.\n\n## Springs\n\nSprings advance with the exact solution of a damped oscillator. They behave the same at any frame rate and stay stable after long pauses. They snap to rest within a hundredth of a pixel or degree.\n\n## Size\n\nThe core is 14 KB minified and gzipped, with no dependencies. Text splitting and audio are separate imports.\n\n## Browser support\n\nKinesis needs registered custom properties, the individual transform properties, and `color-mix()`. That means Chrome and Edge 111+, Safari 16.4+, and Firefox 128+. Older browsers don't resolve values written with `calc()`, variables, or relative units, so they get less motion or none. The page still works.\n",{"title":5,"description":294},"docs\u002Fhow-it-works","XzUaISduwLXfH9SNy1HFWt-9KEJiXOW_kcJCIFjrHF8",1791309903098]