clippyjs

repository·main·Indexed 20 days ago

https://github.com/pithings/clippy

A library for adding interactive, animated virtual assistants like Clippy and friends to websites. It features a queued action system for animations, movement, and speech balloons, with support for Text-to-Speech (TTS) via the Web Speech API and async text streaming for LLM responses. Available agents include Clippy, Bonzi, F1, Genie, Genius, Links, Merlin, Peedy, Rocky, and Rover.

Tokens
2.5K
Snippets
10
Records
11
Agent score
70%

What's inside clippyjs

  1. Install Clippy via CDN

    main

    You can use ClippyJS directly in the browser without any build tools by importing the modules from a CDN. Use initAgent to initialize an agent and agents to access specific characters.

    <!doctype html>
    <html
      <body
        <script type="module">
          import { initAgent } from "https://cdn.jsdelivr.net/npm/clippyjs/dist/index.mjs";
          import * as agents from "https://cdn.jsdelivr.net/npm/clippyjs/dist/agents/index.mjs";
          const agent = await initAgent(agents.Clippy);
          agent.show();
          agent.speak("Hello! I'm Clippy, your virtual assistant.");
        </script>
      </body>
    </html>
  2. Install Clippy via npm

    main

    For projects using build tools, install the clippyjs package. You can then import initAgent from the main package and specific agents from clippyjs/agents.

    import { initAgent } from "clippyjs";
    import { Clippy } from "clippyjs/agents";
    
    // Load and show the agent
    const agent = await initAgent(Clippy);
    agent.show();
  3. Enable Text-to-Speech (TTS)

    main

    Each agent has a unique voice personality using the Web Speech API. To enable audio, pass the { tts: true } option to the speak() or speakStream() methods.

    agent.speak("Hello! I'm Clippy, your virtual assistant.", { tts: true });
  4. Use the Agent API

    main

    All agent actions are queued and executed sequentially, allowing you to chain commands.

    Animation & Movement

    • agent.play(name): Play a specific animation by name.
    • agent.animate(): Play a random animation.
    • agent.animations(): Returns an array of available animation names.
    • agent.moveTo(x, y): Move to a coordinate.
    • agent.gestureAt(x, y): Perform a gesture at a coordinate.

    Speech & Text

    • agent.speak(text, options): Show a speech balloon. Options include { tts: true } for Text-to-Speech and { hold: true } to keep the balloon open.
    • agent.speakStream(asyncIterable, options): Stream text from an async iterable (e.g., an LLM response). Supports { tts: true }.

    Control & Lifecycle

    • agent.stopCurrent(): Stop the current action in the queue.
    • agent.stop(): Stop all actions and return to idle.
    • agent.hide(): Hide the agent.
    • agent.pause() / agent.resume(): Pause or resume animations.
    • agent.dispose(): Remove the agent from the DOM.
  5. Import available agents

    main

    Agents can be imported in three ways:

    1. All at once: import * as agents from "clippyjs/agents";
    2. Individually: import { Clippy } from "clippyjs/agents";
    3. From subpaths: import Merlin from "clippyjs/agents/merlin";

    Available agents: Bonzi, F1, Genie, Genius, Links, Merlin, Peedy, Rocky, Rover, and Clippy.

    // Import all agents
    import * as agents from "clippyjs/agents";
    
    // Or import individually
    import { Clippy } from "clippyjs/agents";
    
    // Each agent can also be imported from its own subpath
    import Merlin from "clippyjs/agents/merlin";
  6. Move and position the Agent

    main

    You can control the Agent's position on the screen using the following methods:

    • moveTo(x: number, y: number, duration?: number): Moves the agent to the specified x and y coordinates. The duration (default 1000ms) controls the speed of the movement. The agent will automatically use a movement animation if available.
    • reposition(): Recalculates the agent's position to ensure it stays within the current viewport bounds.
    • gestureAt(x: number, y: number): Triggers a gesture animation directed towards the specified coordinates.
    // Move to a specific coordinate over 2 seconds
    agent.moveTo(500, 300, 2000);
  7. Clean up Agent resources with dispose()

    main

    When an agent is no longer needed, call dispose() to prevent memory leaks and remove all associated event listeners and DOM elements.

    dispose() performs the following:

    • Stops all animations and clears the queue.
    • Removes window resize listeners.
    • Clears any active drag timeouts.
    • Removes mouse and touch event listeners.
    • Disposes of the Animator, Balloon, and Queue instances.
    • Removes the agent's element from the DOM.
    agent.dispose();
  8. Control Agent visibility and animations

    main

    The Agent class provides several methods to control its presence on the screen and its behavior.

    Show and Hide

    • show(fast?: boolean): Displays the agent. If fast is true, it skips the 'Show' animation and displays the element immediately.
    • hide(fast?: boolean, callback?: Function): Hides the agent. If fast is true, it hides immediately without animation. If false, it plays the 'Hide' animation first.

    Play Animations

    • play(animation: string, timeout?: number, cb?: Function): boolean: Plays a specific named animation. Returns true if the animation exists and was queued. The timeout (default 5000ms) determines how long before the agent automatically exits the animation.
    • animate(): boolean: Plays a random non-idle animation.
    • gestureAt(x: number, y: number): boolean: Makes the agent gesture towards the specified coordinates.
    • hasAnimation(name: string): boolean: Checks if a specific animation name is available.
    • animations(): string[]: Returns a list of all available animation names.

    Pause and Stop

    • pause(): Pauses both the animator and the speech balloon.
    • resume(): Resumes the animator and the speech balloon.
    • stop(): Clears the action queue, exits current animations, hides the balloon, and cancels any active Text-to-Speech.
    • stopCurrent(): Immediately exits the current animation and closes the speech balloon.
    // Example usage
    agent.show();
    agent.play('Wave', 3000, () => console.log('Wave finished'));
    agent.moveTo(100, 200, 1000);
    agent.hide(true);
  9. Make the Agent speak text or streams

    main

    The Agent can communicate using speech balloons and optionally the Web Speech API for Text-to-Speech (TTS).

    Speak static text

    speak(text: string, options?: { hold?: boolean; tts?: boolean }): Displays text in a speech balloon.

    • options.hold: If true, the balloon stays open until closeBalloon() is called.
    • options.tts: If true, uses the Web Speech API to read the text aloud.

    Speak text streams

    async speakStream(source: AsyncIterable<string>, options?: { tts?: boolean }): Promise<void>: Streams text chunks into the speech balloon from an async iterable. This is useful for real-time AI responses. If options.tts is true, the agent will speak the full text once the stream is complete.

    Manage balloons

    • closeBalloon(): Manually closes the current speech balloon.
    // Speak with TTS
    agent.speak('Hello there!', { tts: true });
    
    // Stream text from an async source
    async function* textGenerator() {
      yield 'Hello ';
      yield 'world!';
    }
    await agent.speakStream(textGenerator(), { tts: true });
  10. Initialize a Clippy agent with initAgent()

    main

    The primary entrypoint for the clippyjs package is the initAgent function. Use this function to create and initialize a Clippy agent instance. The specific configuration and parameters for initAgent are defined in the ./agent.ts module.

    import { initAgent } from 'clippyjs';
    
    // Initialize your agent
    const agent = await initAgent({
      // Configuration options are defined in the agent module
    });
  11. Initialize an Agent with initAgent()

    main

    To create an instance of an Agent, use the initAgent function. This function requires an object conforming to the AgentLoaders interface, which provides asynchronous loaders for the agent data, the sprite sheet map, and the sound assets. This approach allows for efficient, parallel loading of all necessary assets before the agent is instantiated.

    AgentLoaders Interface

    • agent: A function returning a Promise that resolves to the agent's animation data.
    • map: A function returning a Promise that resolves to the URL of the agent's sprite sheet.
    • sound: A function returning a Promise that resolves to a map of sound names to audio URLs.
    import { initAgent, AgentLoaders } from 'clippyjs';
    
    const loaders: AgentAgentLoaders = {
      agent: async () => import('./data/agent.json'),
      map: async () => import('./data/map.txt'),
      sound: async () => import('./data/sounds.json'),
    };
    
    const agent = await initAgent(loaders);
    import { initAgent, AgentLoaders } from 'clippyjs';
    
    const loaders: AgentLoaders = {
      agent: async () => import('./data/agent.json'),
      map: async () => import('./data/map.txt'),
      sound: async () => import('./data/sounds.json'),
    };
    
    const agent = await initAgent(loaders);