Skip to content
HN On Hacker News ↗

Inertia — keyframe animation for the UI you already built

▲ 9 points 3 comments by hpen 2w ago HN discussion ↗

Pangram verdict · v3.3

We believe that this entire text is AI.

94 %

AI likelihood · overall

AI
0% human-written 100% AI-generated
SEGMENTS · HUMAN 0 of 1
SEGMENTS · AI 1 of 1
WORD COUNT 765
PEAK AI % 94% · §1
Analyzed
Aug 13
backend: pangram/v3.3
Segments scanned
1 windows
avg 765 words each
Distribution
0 / 100%
human / AI fraction
Verdict
AI
Pangram v3.3

Article text · 765 words · 1 segments analyzed

Human AI-generated
§1 AI · 94%

SwiftUI · Jetpack Compose · ReactWrap the views you want to move, run your app inside the Inertia editor, and drag them around on a timeline. No exported video, no parallel design file — the thing you animate is the real view in your real app.macOS editor · iOS 17+ / minSdk 26 / React 18.3Inertia — editorWhy InertiaYour app is the canvasDesign tools export something that plays next to your UI rather than being it. Code-first libraries keep you in a compile-run-tweak loop where a 40 ms timing change costs a rebuild. Inertia sits between the two.Real componentsA real RoundedRectangle, a real Card composable, a real <div>. No re-implementation and no design file that drifts from the app.Native playbackSwiftUI plays tracks through KeyframeAnimator; Compose and React sample the same tracks on their own clocks. Nothing is rasterized.Live editingYour app connects to the editor over a local WebSocket, reports its tagged hierarchy, and receives updates as you edit.How it worksThree steps, then it’s in your repo01Tag a viewWrap anything you want to move with an id. That one call is the whole integration — shapes and tracks attach to the id.02Drag it on a timelineRun the build inside the editor, select a tagged view, and move, rotate, scale, or fade it. The playhead is shared with the running app.03Commit the fileThe editor writes an animation.inertia file. Designers scrub the timeline, developers git add the result — one file, three runtimes, identical ids.The editorScrub against a build that’s actually runningThe centre panel is your app — installed and launched on the iOS Simulator, an Android emulator, or your dev server in a WebView. Select a tagged view, drag it, and the keyframe lands on the timeline.Inertia — Home · translateDragging a card in the running app. Green alignment guides snap it against its neighbours, the X/Y sliders read −0.857 and 0 as a fraction of the container, and the readout confirms X: 11 Y: −16, W: 189 H: 189.RuntimesOne API, three platformsEvery runtime has the same three pieces: a container that owns the animation data, an actionable wrapping each view you want to move, and a playback handle for starting it.trigger starts a track; one arriving mid-run joins the run in progress.restart rewinds — every actionable in a container is drawn from one clock.cancel returns an animation to its initial values and leaves it there.isRepeating switches looping and play-once at runtime.ContentView.swifteditor port 8060import SwiftUI import Inertia InertiaContainer(dev: isEditor, id: "animation") { ContentView() } struct ContentView: View { @Environment(\.inertiaDataModel) private var inertia: InertiaDataModel! var body: some View { VStack(spacing: 16) { Card(title: "Welcome") .inertia("card0") // tag the view you want to move Button("Trigger") { inertia.restart("card0") } } } }RuntimePackageEditor targetShapesSwiftUIInertia (SPM)iOS Simulator, driven through simctlMetalJetpack Composeinertia-compose (JitPack)Android emulator, over adbOpenGL ES 2.0Reactinertia-react + inertia-baseYour dev server, in a WKWebViewWebGLThe handoffOne .inertia fileThe editor writes an animation.inertia file into a project folder you version alongside your source — one record per tagged id, each a pose plus the track that leaves it.translate — an [x, y] offset as a fraction of the container, so a track survives a resize.scale, opacity — uniform factor, and 0 through 1.rotate / rotateCenter — degrees, anchored top-left or at the view’s centre.invokeType — auto starts when the view appears; trigger waits for your call.animation.inertiaone record, shown decoded{ "id": "card0", "initialValues": { "opacity": 1, "rotate": 0, "scale": 1, "translate": [0, 0] }, "invokeType": "trigger", "keyframes": [ { "duration": 0.001, "values": { "scale": 0, "translate": [-0.008, -0.269] } }, { "duration": 2.011, "values": { "rotate": 90, "scale": 1, "translate": [-0.013, 0.278] } } ], "shapes": [] }Also in the boxDetails that make it usableAlignment guidesDrag a view and it snaps against its neighbours, on SwiftUI and Compose alike.Vertex shapesAuthor geometry behind a view — rectangles, ovals, triangles, or raw vertices with per-corner colour. No shape API to call.Shared playheadPause, resume, seek and loop length are shared both ways, so the timeline tracks a running animation.Editor mode is opt-inIn release, none of the socket code runs. The container loads the animation and plays it on its own clock.Per-view stateTwo views can share one animation id and keep their own playback state — trigger one without touching the other.Versioned with your appOne .inertia project folder per app, sitting in the repo next to the code it animates.Get startedGet a view moving in a few minutesAdd the package, tag a view, and open the editor. The quickstart walks all three runtimes end to end.DownloadGet the macOS editorLeave an email and the build is yours — the editor, the three runtimes, and the sample project the quickstart uses.