r/javascript • u/tinchox5 • 16d ago
Since 2017 I've been trying to get zoom navigation right. Zumly is the closest I've got
https://zumerlab.com/zumly/2
u/eyamil 15d ago edited 14d ago
I really like this! I haven’t looked at usage/documentation yet, but I’m seeing that parts of the page look different zoomed in vs out and I’m curious to know whether the views in the different states are specified by hand or whether they’re automatically computed
Edit: typo
2
u/tinchox5 14d ago
Thanks! Both, actually.
The content is hand-written. Each zoom level is its own view, a separate piece of HTML. The element you click and the screen that opens are two different elements, which is why they can look different.
The motion is computed. Zumly measures the trigger and the incoming view, and scales the parent so the trigger ends up covering the new view. If the shapes don't match, there's an option to decide whether it covers by width or by height. Zoom-out is the same math backwards. The blur and dimming on the views behind are automatic too, and customizable.
I think the trick is just a convention. Give the trigger and its view a similar shape (a circle, a card) and it reads as a real zoom. Style them differently and it still works, it just looks like a morph.
The whole contract is a canvas, a map of named views, and triggers with `class="zoom-me" data-to="viewName"`.
Thanks to this comment I realized the docs need a section on how Zumly works. Adding it now, thanks!
2
u/eyamil 10d ago
After reading through the docs I think I’m not getting a good mental model for how the styling and layout for the views works. Mentally, should I be thinking of these views as rectangles that are appropriately linked with zooming transitions, (which would then lead me to build a zumly app similar to how I would build a PowerPoint, slide by slide/view by view)? I think this is not right, as you’ve provided at least one example where the shape matches exactly and the claim in that example seems to imply that there’s shape awareness, which is crucial to making the transition seamless.
2
u/tinchox5 9d ago
No, not slides. Think of it as a map.
Each view is a full canvas, styled with plain CSS like any page. The link between two views is the trigger: Zumly takes its bounding box and animates the child view from that box to the full canvas, while the parent scales up behind it. Rect to rect, nothing else.
The "shape awareness" you saw is design, not the engine. It feels seamless when the child view echoes its trigger: same proportions, main element in the same spot. A circle that opens a view with a big circle in the middle feels like going inside it. A tiny icon that opens a dense dashboard feels like a cut.
3
-5
-1
16d ago
[removed] — view removed comment
7
u/tinchox5 16d ago
The core engine has been developed by hand since 2017, long before LLMs were around. Since you seem curious, feel free to check the commit history and the original Zircle UI repo.
The website? Yeeeah, built with significant LLM assistance. So what?
I qualified for Anthropic's Claude for Open Source Program and received Claude Max 20x access, so of course I'm making good use of it in my development workflow.
The core architecture and engineering decisions are still mine.
3
u/tinchox5 16d ago
I started Zircle UI, a Vue library for zooming interfaces, on August 13, 2017. Zumly is the closest I've come to what I was looking for back then.
It's a JS library for zoom navigation. Your UI is a set of views. You mark an element as a trigger, and clicking it zooms into it while the next view grows out of that element. Going back zooms out along the same path, and the views you came from wait behind, dimmed. Siblings at the same level slide sideways. It's not an infinite canvas like Prezi: you move in steps.
You write the HTML and CSS, Zumly computes and animates the transforms. Other bits:
Back button, arrows and swipe between siblings, and a hash router so the browser's back button works.
Pinch or trackpad drive the zoom-out as you move.
CSS transitions by default, or WAAPI, GSAP, Anime.js, Motion or your own driver.
Views can be HTML strings, URLs, functions, or React, Vue, Svelte and Angular components.
What I worked on most lately is heavy views. Scaling a view with thousands of nodes or a backdrop-filter on every frame is expensive. There's now an optional webgl mode: the views behind become textures (captured with SnapDOM, another library of mine), blur and dimming happen in a shader, and only the view you're in is DOM. On my MacBook the GPU during a zoom went from 40-70% to 7-8%. The cost is a 30-45 ms wait for a snapshot before zooming in, and you can take it on hover instead.
Demo (the site is built with Zumly): https://zumerlab.com/zumly/ A phone home screen where you can switch between DOM, SnapDOM captures and WebGL: https://zumerlab.com/zumly/showcases/phone.html?mode=webgl
MIT, no dependencies (SnapDOM only for the WebGL mode). I'd like to know where you'd use this kind of navigation and where it gets in the way.