/ 10 min read

How to Add a Peekling to Your Website

Peekling characters gathered among flowers and trees beneath a bright sky

Peekling is an open-source JavaScript runtime I built to add interactive animated companions to websites. Load the browser script and call Peekling.hatch('peek') to get started. No framework, account, or API key needed.

There is a small kitten-fox wandering around this website. That’s Peek. You can pick Peek up and throw them across the page.

I built Peekling because I wanted my website to have something you could play with.

A personal site already tells you what someone does. I like it when there is also something a little odd to discover. A detail someone added because they wanted it to exist, even if it doesn’t belong on a résumé.

For me, that detail is a curious little character following the pointer around.

I wanted the reusable version to be easy to explain: choose a character and hatch it. Someone adding one to a blog shouldn’t have to build an animation system first.

A Peekling can keep someone company on a portfolio, carry a short welcome message, or point them toward something worth reading.

The simplest version takes one JavaScript call. I’ll show that first, then add a bubble. You don’t need a framework or an API key for either example.

Meet Peek before you install anything

If you’re reading this on prajwal.me, you may already have noticed Peek. That’s the engine running on my own site, including grab and throw. You can also try it on peekling.com.

Move your pointer and watch the character follow. Pick them up, move them somewhere else, and let go. On a phone, try dragging with your finger.

I like that the interaction is something you discover. The page still has its actual job to do. The character can be there for a moment of play while you look around.

Would I add this to every website? No. But on my own site, I can make room for something that is just enjoyable to use.

Add a Peekling to your website

If you can add a script to your page, you can try this. Put the following just before the closing </body> tag in an HTML page:

<script src="https://cdn.jsdelivr.net/npm/@peekling/[email protected]/dist/peekling.min.js"></script>
<script>
Peekling.hatch('peek')
</script>

Serve the page from localhost or your website, open it in a browser, and Peek should appear. You need a network connection for this CDN example. A local development server is a better starting point than double-clicking an HTML file.

The first script loads the browser runtime. Peekling.hatch("peek") selects Peek and creates the companion. The browser bundle finds its matching stylesheet, and the runtime loads Peek’s character data and artwork for you.

You don’t have to download a spritesheet, draw frames on a canvas, or write a pointer-following loop to get started.

The default companion behavior includes pointer following when motion is enabled. Dragging and throwing are also enabled by default. On touch screens, there is no hovering pointer to follow, but you can interact directly with the character.

One important detail: the runtime follows the visitor’s reduced-motion preference by default. If your device asks for less motion, a quieter presentation is expected. You haven’t necessarily broken the install.

I’ve pinned the example to v0.1.4, so it doesn’t silently change when a new release comes out. Keep the script tags in this order. Adding async to the first one would let the hatch call run before the runtime is available.

That’s the entire first example. Try it on a spare page before deciding where it belongs on your site.

What this adds to your page

Peekling runs in the browser. The basic companion doesn’t need an account, your own server, or an AI provider. The runtime has no production dependencies and sends no telemetry of its own.

That doesn’t mean the CDN example is offline. It makes requests for the runtime, stylesheet, character manifest, and artwork. If you want control over where those files come from, the engine also supports self-hosted assets. The configuration guide covers that route.

You can use the runtime in a bundled application too. The package is @peekling/runtime, and its JavaScript entry point exports hatch. For this post, I’m sticking to plain HTML so you can see the result without setting up a project first.

Give Peek a bubble

A character is fun on its own. A small message gives it a reason to be in a particular place.

For a portfolio, I would start with a hello and a link to my work. On a documentation page, perhaps a link to the getting-started guide. Something useful enough to open, and short enough to read without losing your place.

Keep the CDN script from the first example. Replace the contents of the second script with this code. Don’t run both hatch calls unless you actually want two Peeklings.

const peek = Peekling.hatch({
character: 'peek',
position: 'bottom-right',
interaction: {
contentInitiallyHidden: true,
label: 'Say hello to Peek'
},
content: {
hello: {
'top-center': {
text: "Hi, I'm Peek. Want a little company on your website?",
link: { label: 'Meet Peekling', href: 'https://peekling.com/' }
}
}
},
plan: {
baseline: {
channels: ['state', 'surface:hello'],
state: { state: 'idle' },
surfaces: [{ id: 'hello', contentId: 'hello' }]
}
}
})
peek.ready.catch(console.error)

Now click or tap Peek. The bubble opens with your message and link. Press the character again to hide it. You can also focus the character with the keyboard and activate it with Enter or Space.

content holds the words and link. plan.baseline connects that content to a bubble called hello and keeps Peek in the idle animation.

The setting I’d pay attention to is contentInitiallyHidden. It waits for someone to open the bubble instead of greeting every visitor with an expanded message.

This example deliberately stays in one place rather than following the pointer. It replaces the default companion plan with a small idle-and-bubble plan. You can still drag and throw the character when motion is enabled.

Change text, link.label, and link.href to make it yours. For a link within your own site, a relative path such as /projects/ works too. You don’t need to write HTML for the bubble. The runtime renders the text and link from those fields.

There is no chatbot behind this example. The message is exactly the message you wrote. Connecting a character to an AI service is a separate application integration, not a requirement for having a friendly character on a page.

Where I would use one

A portfolio is an easy place to start because the character can simply be part of your taste. You don’t have to give it a job. If the rest of your site is fairly restrained, a small moving character is a noticeable personal touch.

For an open-source project’s website, I’d try a bubble that links to a runnable example. People arriving from GitHub often want to see what the project does before reading the details. Give them a short path to that moment.

Documentation needs more restraint. I’d put the useful information in the page first, where it can be found and searched. A character can offer an optional shortcut. Nobody should have to click a tiny creature to find the installation instructions.

I would also be selective about where it appears. A playful homepage and a busy checkout have different priorities. Test it on a narrow screen, check that it doesn’t cover an important button, and make sure the page still works well for someone who never interacts with it.

This is why I start the bubble closed. Someone arriving to read an article can get on with reading it.

Peek has company

Peek is the first character, not the only one. The characters repository has the official collection, with previews and links to the published packs.

There is Moss, a mint-green frog. Orbit is a round little robot. Crumb is a piece of toast with somewhere to be. I like how much the feeling changes when the character changes, even though the website underneath is the same.

The runtime and the artwork live in separate repositories. A character pack contains images and a manifest describing its animations and assets. It doesn’t contain executable behavior. That lets the engine handle interaction while the character brings its own appearance and movement.

Start with Peek for the snippets above. When you want another character, browse the collection and follow its package documentation. An explicit packUrl lets the runtime load a character manifest. Don’t assume every name in the gallery is automatically a shorthand like "peek".

Each pack includes its own license and attribution files. Check those when choosing art for your site.

Want to help build Peekling?

I would love to see what people do with this beyond my own website. There are useful ways to contribute even if animation code isn’t your thing.

If you add a Peekling to a page and something breaks, open an engine issue. Include the browser, runtime version, what you expected, and the smallest example that reproduces the problem. A short reproduction is much easier to work with than “it doesn’t move.”

If you want to improve the runtime or docs, start with the engine contribution guide. Pick a focused change, add a test for behavior changes, and follow the repository’s checks before opening a pull request. If you got stuck on an installation step and found a better explanation, that’s a contribution I’d be glad to have.

If you draw or animate, have a look at the pack authoring guide and Peek’s pack. For a new official character, open an issue in the characters repo before investing in the full artwork. We can discuss the character, scope, and art ownership first. You can also make a compatible third-party pack and publish it separately.

The wider project lives under the Peekling GitHub organization. That’s where to look for the related repositories rather than expecting everything to be inside the engine.

A few things before you ship

The tiny snippet is a starting point for a normal HTML page. If your application swaps views without a full reload, keep the instance returned by hatch and call destroy() when the owning view unmounts. Otherwise, mounting the same integration again can leave you with more companions than you intended.

The returned instance also has a ready promise. The bubble example logs startup failures through that promise. Use it when diagnosing a blocked asset request or a configuration problem instead of guessing from an empty corner of the page.

For a site with a strict Content Security Policy, use an allowed external bootstrap script and configure your asset sources and integrity checks. The hosting guide covers the details. You don’t need to relax your whole site’s policy to try a character.

And check the result on a phone. A character that feels small on a desktop can take up meaningful space beside a form or navigation control. Keep the main task comfortable to finish.

Give your website a little company

You can stop at the first snippet. A character wandering around a page doesn’t need a grander purpose. Or you can give it a message, choose a different pack, and find a role that fits what you’re building.

Try the live website, paste the first snippet into a page, and see whether Peek belongs there. If you like the project, please ⭐ star peekling-engine on GitHub. It helps people find it, and it lets me know you’d like to see it grow.

If you end up making a website with a frog, a robot, or a very determined piece of toast wandering around it, I’d love to see it.

About the author

Prajwal Murthy is a software engineer at PayPal and the creator of Peekling. He writes about web development, AI, and systems.