npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

create-kaiwen-island

v1.0.7

Published

Scaffolding CLI tool to create desktop widgets styled as Apple's Dynamic Island with Electron, React, and TypeScript.

Readme

create-kaiwen-island

A highly modular, customizable, and professional desktop widget scaffolding tool that generates an apple-style Dynamic Island wrapper powered by Electron, React, TypeScript, Vite, and Framer Motion.

This project comes pre-configured with a Finite State Machine (FSM) for layout transitions, global operating system shortcut bindings, and screen positioning options (docking and dragging).


Key Features

  1. Finite State Machine (FSM) State Management Manage capsule state, width, height, and border radius dynamically. Transitions are verified before executing using state configuration rules.

  2. Self-Contained State Modules Each visual state resides in its own folder containing a component view (index.tsx), a local stylesheet (styles.css), and an FSM config definition (config.ts).

  3. Global Shortcut Manager Register and capture global keyboard accelerators (e.g., Ctrl+Alt+I to hide/show, Ctrl+Alt+Space to pause/resume) dynamically from the renderer process.

  4. Dynamic Overlay Positioning Dock the island in 9 quadrants across the screen (e.g., top-left, top-center, bottom-right) or enable free-form dragging using Framer Motion.

  5. Multi-Window Support Spawn secondary windows from the primary island widget using a secure IPC preload bridge.

  6. Type-Safe Development Full TypeScript declarations for Electron IPC methods and state configs.

  7. Capsule Rotation Rotate the Dynamic Island capsule dynamically to 0°, 90°, 180°, or 270° with smooth Framer Motion spring transitions.

  8. Bilingual Localization (i18n) Supports switching between English (default) and Turkish. Instantly translates all UI strings, states, tooltips, settings, and desktop notification prompts.

  9. Multi-Style Visual Themes (Matte / Frosted Glass / Liquid Glass) Toggle between Matte Dark (classic Apple capsule), Frosted Glass (smooth 20px blur), and Liquid Glass (warped refraction using dynamic SVG turbulence filters) in real-time.

  10. Auto-Clamping Drag & Rotation Constraints Dragging or rotating the capsule vertically (90° or 270°) automatically calculates spatial layout constraints ($W_v$ & $H_v$), smoothly animating the widget back inside safe viewport margins (pad = 20) without edge overflow.

  11. Draggable & Compact Scrollable Settings Panel The settings gear button and overlay card are unified into a draggable entity that supports screen containment. The menu layout is kept highly compact with hidden native scrollbars.


Scaffolding a New Project

To create a new project using this template, execute the following command:

npx create-kaiwen-island my-new-island

Alternatively, run it locally:

node bin/cli.js my-new-island

Getting Started

Once the project is generated, navigate to the directory, install dependencies, and launch the application:

cd my-new-island
npm install
npm run start

Build for Production

To build the client assets for production:

npm run build

Technical Architecture & State Customization

This section details how to configure the Finite State Machine (FSM), implement new layout states, define transition constraints, and manage navigation history.

1. Finite State Machine (FSM) Mechanics

States are defined as standalone modules representing a particular visual layout. The state structure complies with the StateConfig interface:

export interface StateConfig {
  name: string;                  // Unique identifier for the state (e.g., 'DRAW_MODE')
  width: number;                 // Width of the capsule when this state is active
  height: number;                // Height of the capsule when this state is active
  borderRadius: number;          // Border radius of the capsule container
  component: ComponentType<any>; // React component to render inside the capsule
  allowedTransitions?: string[]; // Allowed source states. If empty, entry is unrestricted.
}

Transition Restrictions (allowedTransitions)

The FSM verifies transition requests before updating the layout:

  • If allowedTransitions is omitted or empty, the state can be accessed from any source state.
  • If allowedTransitions contains specific state names (e.g., ['DASHBOARD', 'IDLE']), the FSM will reject requests to transition to this state unless the current state is one of those listed.

2. Creating a Custom State (Step-by-Step)

To add a new state named DrawMode to the Dynamic Island:

Step 2.1: Create the Module Folder

Create a new directory at src/components/DynamicIsland/states/DrawMode/.

Step 2.2: Implement the Component View

Create src/components/DynamicIsland/states/DrawMode/index.tsx:

import './styles.css';
import type { AppState } from '../../../../App';

interface Props {
  goBack: () => void;
  setAppState: (state: AppState) => void;
}

export default function DrawMode({ goBack }: Props) {
  return (
    <div className="draw-mode-container">
      <span className="draw-mode-title">Draw Mode Active</span>
      <button onClick={goBack} className="draw-mode-btn">Go Back</button>
    </div>
  );
}

Step 2.3: Implement the Local Stylesheet

Create src/components/DynamicIsland/states/DrawMode/styles.css containing the component's private styling rules:

.draw-mode-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  padding: 16px;
  color: #f8fafc;
}

.draw-mode-title {
  font-size: 14px;
  font-weight: 700;
  margin-bottom: 12px;
}

.draw-mode-btn {
  background-color: #374151;
  color: #fff;
  border: none;
  border-radius: 6px;
  padding: 6px 12px;
  font-size: 11px;
  cursor: pointer;
}

Step 2.4: Define the FSM Configuration

Create src/components/DynamicIsland/states/DrawMode/config.ts:

import type { StateConfig } from '../../stateManager';
import DrawMode from './index';

export const DrawModeState: StateConfig = {
  name: 'DRAW_MODE',
  width: 400,
  height: 300,
  borderRadius: 24,
  component: DrawMode,
  allowedTransitions: ['DASHBOARD', 'IDLE'], // Only allow transition from Dashboard or Idle
};
export default DrawModeState;

Step 2.5: Register the State in the FSM Registry

Import and register the config in src/components/DynamicIsland/states/registry.ts:

import { stateManager } from '../stateManager';
import { DrawModeState } from './DrawMode/config';
// ... other imports

export function registerAllStates() {
  // ... other registrations
  stateManager.registerState(DrawModeState);
}

You can now trigger the transition to your new state by calling navigateTo('DRAW_MODE') from either the DASHBOARD or IDLE state.


3. Navigation Stack Mechanics

The application distinguishes between user-initiated UI navigation and event-driven state transitions to manage the browser history stack cleanly.

  • User Navigations (navigateTo & goBack): When a user opens a screen (e.g., clicking the idle capsule to open the dashboard), invoke navigateTo('DASHBOARD'). This pushes the previous state onto the history stack (navigationStack). Clicking a back button triggers goBack(), popping the stack and returning to the caller.
  • Direct Event Transitions (changeAppState): Used for background events (e.g., a Pomodoro timer ticking to zero and changing the state to BREAK_PROMPT). Direct transitions bypass pushing to the stack to prevent background updates from polluting the user's navigation history.
  • History Reset (clearHistory): Resets the navigation stack. Useful when logging out or returning to the landing screen where backward navigation is no longer valid.

All transitions are printed directly to the developer console indicating transition type, target state, and active navigation stack details.


4. Click-Through Overlay Window

The application utilizes a fullscreen transparent BrowserWindow in Electron. By default, mouse pointer events are passed directly through the window using the setIgnoreMouseEvents Electron API.

  • When the pointer enters the Dynamic Island capsule, the renderer process instructs Electron to capture mouse clicks.
  • When the pointer leaves the capsule, the window returns to a click-through state, ensuring the desktop remains fully usable.

Global Shortcut Bindings

Default shortcuts are registered inside electron/main.js using the custom ShortcutManager:

  • Ctrl+Alt+I: Toggle widget visibility (hide/show).
  • Ctrl+Alt+Space: Pause or resume active timers.
  • Ctrl+Alt+D: Force transition to the dashboard view.

Developers can register custom accelerators dynamically by dispatching events over the preload channel:

window.electronAPI.registerShortcut('Ctrl+Alt+X', 'custom-renderer-action');

And handle them inside React:

useEffect(() => {
  const unsubscribe = window.electronAPI.onShortcutAction((action) => {
    if (action === 'custom-renderer-action') {
      // Execute custom logic
    }
  });
  return () => unsubscribe();
}, []);