vork by Voyager
An agent writes a scene as code, renders it on the GPU, looks at the result and revises the code. Source-available and free during the research preview.
翻訳待ち
Stretchy Liquid Glass (iOS style) for MacOS and Websites
翻訳待ち
Loading the full README.
Read the full README ↗Stretchy Liquid Glass (iOS style) for macOS and websites.
AppKit buttons for macOS 26 that swell when pressed, follow your drag, stretch along the pull,
and wobble back — plus a dependency-free web version you can try in a browser.
If this made you smile, a ⭐ helps others find it.
macOS 26's NSGlassEffectView gives you the Liquid Glass material. It does not give you the feel — the
way glass in a polished app gives under your finger. JellyGlass adds that feel, and writes down what it took
to get it working inside AppKit's glass containers (it is less obvious than it sounds — see
How it works).
The numbers are not guessed: they were measured, frame by frame, from a screen recording of a production app (MEASUREMENTS.md). So was the lens of the system glass that the web version copies (HOW_IT_WORKS.md §10).
In the browser (any modern browser, no install): https://54degree5.github.io/JellyGlass/
Download the demo app (macOS 26+, Apple silicon and Intel): latest release.
It is ad-hoc signed, not notarized: unzip, then right-click → Open (or xattr -dr com.apple.quarantine JellyGlassDemo.app).
Or build it (macOS 26+, Xcode 26 / Swift 6.2+):
git clone https://github.com/54degree5/JellyGlass.git
cd JellyGlass
swift run -c release JellyGlassDemo
Drag any button. Keys: K on top ⇄ merge · S spring (jelly / wobble / snappy) · A stretch
(standard / wide / heavy) · C glass style.
// Package.swift
.package(url: "https://github.com/54degree5/JellyGlass.git", branch: "main")
import JellyGlass
let mic = JellyGlassButton(size: CGSize(width: 44, height: 44), symbols: ["mic"])
mic.spring = .jelly // .jelly (default) · .wobble · .snappy
mic.stretch = .standard // .standard · .wide · .heavy
mic.liftsOnPress = true // false: melt into neighbours instead
mic.look = .transparent // default: clear refractive glass, the scene behind stays visible; .system = AppKit's frosted material
// Optional: group buttons so neighbours share one glass surface and merge when `liftsOnPress` is false.
let group = NSGlassEffectContainerView()
group.spacing = 14
let holder = NSView(frame: group.bounds)
holder.addSubview(mic)
group.contentView = holder
Any view works as content: JellyGlassButton(size:contentView:). The button deforms its glass and its content.
With d the cursor's distance in points from where the button was pressed:
| formula | at d = 38 / 80 / 185 / 800 pt | |
|---|---|---|
body travel t(d) | 6.5 · ln(1 + d / 28) | 5.6 / 8.8 / 13.2 / 22 pt |
stretch e(d) | 0.105 · ln(1 + d / 50) · d² / (d² + 40²) | 0.03 / 0.08 / 0.16 / 0.30 |
Beyond ~200 pt the recorded body travel plateaus (it contains a single long flick), but by hand the app keeps stretching, so the model deliberately keeps growing — slowly, without a ceiling (see the shaded area below).
Any size. The numbers above come from a 44 pt circle. For other sizes the absolute change follows them, not the
ratio: along the pull the factor is 1 + e·√(44/L), across it 1 − (1 − 1/(1+e))·(44/L), where L is the button's length
on that axis. A 44 pt circle behaves exactly as measured; a 108 pt pill pulled down keeps its width (−2 pt instead of
−10 pt); a 360 pt bar pulled sideways grows by ~9 % instead of ~30 %. Press swell scales the same way. (The AppKit glass
margin grows with the width too, so long buttons are never clipped.)
Pulled along an axis the shape scales ×(1+e) along it and ÷(1+e) across it. Pulled diagonally the
axial part fades out and the whole button grows 1 + 0.6·e instead. Springs (stiffness / damping):
| preset | held | after release |
|---|---|---|
jelly | 1500 / 70 | 420 / 12 — swings past rest once or twice |
wobble | 1500 / 70 | 240 / 6 |
snappy | 3600 / 120 | 3600 / 120 — back in ~60 ms |
The short version of what is not in any documentation:
This is the beginning of the README. Read the rest at the original. Read the full README ↗