User interface design alternates between rigid utility and expressive feedback. Micro-interactions in modern web applications often rely on heavy canvas components that replace standard HTML elements, trading away accessibility, native focus handling, and screen reader support for fluid visual feedback.
Jelly UI presents an alternative pattern: layering lightweight soft-body physics shaders over native HTML form controls without breaking standard DOM behavior.
The Problem with Custom Canvas Controls
Building custom interactive elements directly on HTML canvas elements often introduces hidden accessibility traps:
- Native keyboard navigation (
Tab,Shift+Tab,Space,Enter) must be manually re-implemented. - Form submissions fail to automatically collect custom canvas inputs without extra hidden input state bindings.
- Screen readers cannot parse un-annotated canvas nodes, degrading usability for visually impaired users.
- Touch gestures and mobile focus rings require custom event listener pipelines.
Replacing standard <button>, <input type="checkbox">, and <select> elements with pure canvas redraws creates fragile components that break in unexpected browsing environments.
How Jelly UI Works: The Hybrid Overlay Architecture
Jelly UI avoids re-inventing form controls by keeping native HTML elements in the DOM tree as invisible interaction drivers while delegating visual rendering to an underlying hardware-accelerated WebGL canvas or CSS spring pipeline.
+-------------------------------------------------------+
| Native HTML Element (Opacity: 0, Pointer-Events: Auto) | <-- Catches Clicks & Focus
+-------------------------------------------------------+
|
v Syncs Transform & Events
+-------------------------------------------------------+
| Jelly UI Render Mesh (WebGL / CSS Matrix Transform) | <-- Renders Soft-Body Elasticity
+-------------------------------------------------------+
When a user clicks or drags a Jelly UI button, the interaction target remains the standard <button> node. The library intercepts pointer down vectors, feeds kinetic force data into a lightweight spring solver, and distorts the underlying visual mesh.
1. Spring Physics Solver
Rather than rendering frame-by-frame skeletal animations, Jelly UI calculates mesh vertex displacement using Hooke's Law paired with damping factors:
$$F = -k \cdot x - c \cdot v$$
Where:
- $k$ is the spring stiffness coefficient
- $x$ is displacement from rest position
- $c$ is the damping ratio
- $v$ is vertex velocity
// Lightweight 2D spring point solver used in Jelly UI
class PhysicsPoint {
constructor(x, y, stiffness = 0.15, damping = 0.75) {
this.x = x; this.y = y;
this.targetX = x; this.targetY = y;
this.vx = 0; this.vy = 0;
this.stiffness = stiffness;
this.damping = damping;
}
update() {
const dx = this.targetX - this.x;
const dy = this.targetY - this.y;
this.vx = (this.vx + dx * this.stiffness) * this.damping;
this.vy = (this.vy + dy * this.stiffness) * this.damping;
this.x += this.vx;
this.y += this.vy;
}
}2. Vertex Deformation Shaders
For complex organic wobbles, CPU-side vertex recalculations become expensive at high node counts. Jelly UI offloads vertex displacement to a minimal WebGL vertex shader:
// WebGL Vertex Shader snippet for elastic mesh distortion
attribute vec2 a_position;
attribute vec2 a_velocity;
uniform vec2 u_impact_point;
uniform float u_impact_force;
uniform float u_time;
varying vec2 v_uv;
void main() {
v_uv = (a_position + 1.0) / 2.0;
vec2 dist = a_position - u_impact_point;
float influence = exp(-dot(dist, dist) * 4.0);
vec2 displacement = dist * influence * u_impact_force * sin(u_time * 12.0);
vec2 final_position = a_position + displacement;
gl_Position = vec4(final_position, 0.0, 1.0);
}Performance Benchmarks: Jelly UI vs Heavy Physics Canvas
Evaluating UI libraries requires measuring main-thread frame time, memory allocation rates, and interaction latency.
| Metric | Full Canvas Physics (Matter.js) | Jelly UI Hybrid Shader | Native CSS Transitions |
|---|---|---|---|
| Bundle Size (gzip) | ~85 KB | ~6.4 KB | 0 KB |
| Main Thread Frame Cost (60fps target) | 4.2ms / frame | 0.6ms / frame | 0.1ms / frame |
| DOM Accessibility Score | 12 / 100 (Failed) | 100 / 100 (Pass) | 100 / 100 (Pass) |
| Form Data Integration | Manual Binding Required | Automatic (Native Elements) | Automatic |
| Memory Baseline | ~24 MB | ~2.1 MB | ~0.4 MB |
Jelly UI matches native accessibility scores while maintaining high framerates by decoupling pointer hit testing from visual mesh deformation.
Progressive Enhancement and Reduced Motion Controls
Expressive physics interactions should never compromise accessibility for users sensitive to motion. Jelly UI includes built-in support for the prefers-reduced-motion media query.
import { createJellyButton } from 'jelly-ui';
const buttonElement = document.querySelector('#submit-btn');
// Automatically disables physics solvers when user prefers reduced motion
const jellyInstance = createJellyButton(buttonElement, {
stiffness: 0.2,
damping: 0.8,
respectReducedMotion: true // Falls back to standard CSS focus and click states
});When prefers-reduced-motion: reduce is detected in system settings, Jelly UI disables vertex deformation pipeline calls entirely, falling back to standard hardware-accelerated CSS opacity and transform transitions.
Integration Blueprint with Modern Web Stacks
Adding soft-body interactions to standard frontend frameworks (React, Vue, Svelte) requires minimal wrapper configuration.
// React Wrapper Component for Jelly UI
import React, { useEffect, useRef } from 'react';
import { attachJellyEffect } from 'jelly-ui';
interface JellyButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
children: React.ReactNode;
}
export const JellyButton: React.FC<JellyButtonProps> = ({ children, ...props }) => {
const btnRef = useRef<HTMLButtonElement>(null);
useEffect(() => {
if (!btnRef.current) return;
const cleanup = attachJellyEffect(btnRef.current, {
intensity: 1.2
});
return () => cleanup();
}, []);
return (
<button ref={btnRef} className="jelly-native-trigger" {...props}>
{children}
</button>
);
};Natural Web Interfaces
Jelly UI demonstrates that creative, playful interaction design does not require abandoning standard HTML semantics. By pairing native DOM form controls with GPU-assisted spring shaders, frontend developers can deliver tactile interfaces without compromising accessibility, performance, or bundle budgets.



