Codync
A free, open-source 1:1 alternative to Grok Bot and Muse. Message Claude Code, Codex, Cursor and 40+ coding agents as persistent bots from your iPhone, Mac or Linux desktop. Group chats, threads, appr
A Dynamic Island-style Svelte 5 component. One black pill for a menu, a player, an alert, and a rolling timer.
Developer toolsSvelte · TypeScriptGitHub @EmilM32OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗A Dynamic Island-style surface for Svelte 5. One black pill morphs between a resting mark, a menu, a player, an alert, and a counter. The shell is a single spring on width, height, and corner radius. Each state is a snippet you write, already laid out at its destination size, so the type fades instead of stretching.
Live demo: dynamic-island-svelte.vercel.app
npm install dynamic-island-svelte
Peer dependency: svelte ^5. The shell’s CSS ships inside the component.
<script lang="ts">
import { Island, type IslandStateId } from 'dynamic-island-svelte';
let phase = $state<IslandStateId>('idle');
</script>
<Island
state={phase}
stiffness={0.17}
damping={0.74}
fade={200}
notificationDuration={3400}
oncollapse={() => (phase = 'idle')}
>
{#snippet idle()}
<button type="button" onclick={() => (phase = 'navigation')}>Open</button>
{/snippet}
{#snippet navigation()}
<nav aria-label="Primary">
<button type="button" onclick={() => (phase = 'idle')}>Close</button>
</nav>
{/snippet}
{#snippet music()}
<p>Now playing</p>
{/snippet}
{#snippet notification()}
<p>Saved</p>
{/snippet}
{#snippet timer()}
<p>00:00</p>
{/snippet}
</Island>
Keep the variable you pass out of the name state — a local called state collides with the $state rune.
RollingDigits is the counter on its own.
<script lang="ts">
import { RollingDigits } from 'dynamic-island-svelte';
let ones = $state(0);
</script>
<RollingDigits value={ones} stiffness={0.17} damping={0.74} />
Island| Prop | Default | |
|---|---|---|
state | — | 'idle' | 'navigation' | 'music' | 'notification' | 'timer' |
stiffness | 0.17 | Svelte spring stiffness, clamped to 0–1. Higher is faster. |
damping | 0.74 | Svelte spring damping, clamped to 0–1. Lower overshoots. |
fade | 200 | Content crossfade, in milliseconds. Exit is shorter; enter waits a beat. |
notificationDuration | 3400 | Milliseconds before oncollapse when state is 'notification'. Paused while the pointer is over the island, focus is inside it, or the tab is hidden. |
sizes | built in | Partial override of { width, height, radius } per state. |
label | 'Island' | Accessible name of the island region. |
oncollapse | — | Escape, a press outside, or the end of an alert. Ignored when another handler already called preventDefault(). |
idle, navigation, music, notification, timer | — | Snippets. A missing snippet renders nothing for that state. |
Target sizes shrink to the viewport (viewport - 36, never under 220). Idle stays 118 × 40. Pass sizes when a snippet needs a different box. The snippet is centered in a layer of that exact size and clipped by the shell.
<Island
state={phase}
sizes={{ music: { width: 400, height: 120, radius: 32 } }}
oncollapse={() => (phase = 'idle')}
/>
The shell reads these custom properties. Set them on any ancestor.
| Property | Default |
|---|---|
--island-bg | #090909 |
--island-fg | #f6f3ee |
--island-shadow | a 1px inner highlight and two soft drop shadows |
--island-z | 30 |
--island-top | 14px, or the top safe-area inset if that is larger |
The safe-area inset is only non-zero when the page sets viewport-fit=cover:
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
While a notification's timer is paused, the shell carries data-paused. A progress bar inside the snippet can follow it:
:global([data-island-root][data-paused]) .meter {
animation-play-state: paused;
}
RollingDigits| Prop | Default | |
|---|---|---|
value | — | Integer digit 0–9. Values wrap, and 9 → 0 rolls forward. |
stiffness | 0.17 | Same 0–1 spring as the shell. |
damping | 0.74 | Same 0–1 spring as the shell. |
Spring from svelte/motion drives width, height, and radius together, so a gesture can be interrupted. Stiffness and damping are read every frame.fade.prefers-reduced-motion: reduce snaps the spring and drops the blur and the rise. An alert still closes on its timer.oncollapse. Anything marked data-island-keep does not.inert. If focus was inside the layer that just closed, it goes back to the last element focused outside the island, unless your own handler already moved it.width and height. It is one layout write per frame, not a transform-only animation.Requires Node >=22.17.
npm install
npm run dev
The demo serves at http://127.0.0.1:4731. npm run build builds the demo site. npm run package writes the library to dist/ and runs publint.
In this repo the demo imports the component through #lib. Published apps import dynamic-island-svelte.
MIT © Emil Majer