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

@be-enlighten/beni-avatar

v0.4.0

Published

Avatar Vue 3 animado (mascote Beni) — squircle que olha pra você, pisca, pula e comemora. Estados, humores e acessórios, animações a 60fps com GSAP.

Downloads

21

Readme

@be-enlighten/beni-avatar

Avatar Vue 3 animado, pequeno e simpático. Um squircle que olha pra você, pisca, pula e comemora. Solte-o em qualquer app Vue pra dar personalidade a estados de carregamento, páginas vazias, fluxos de onboarding, ou só por diversão.

  • 🎭 8 estados: idle, working, error, speaking, loading, sleep, branding, celebrate
  • 💬 4 humores: happy, sad, angry, surprised (sobrepostos a qualquer estado)
  • 🎩 6 acessórios de cabeça: beanie, coroa, capacete, chapéu de festa, gorro de papai noel, gorro stan
  • 🖱️ Olhos que seguem o mouse, opcional
  • 🎉 Easter eggs por clique: duplo, triplo, quíntuplo
  • 🎨 Tema via props: cores do corpo e dos olhos controladas pelo componente pai
  • ~14 KB gzipped, sem dependências de runtime além de gsap e vue

Animações a 60fps com GSAP.

Demo

A playground em examples/beni-avatar é um estúdio interativo: à esquerda, os 8 estados como cards clicáveis; no centro, o Beni grande controlado pela seleção; à direita, os 4 humores. Logo abaixo, um painel de configuração com acessório, tema (5 presets), toggle "seguir mouse" e slider de intervalo de piscada. Os cards reagem ao tema e ao acessório ativos, com borda gradiente destacada no item selecionado. É também a página hospedada na Vercel.

Instalação

pnpm add @be-enlighten/beni-avatar gsap
# ou
npm install @be-enlighten/beni-avatar gsap
# ou
yarn add @be-enlighten/beni-avatar gsap

Peer dependency: vue ≥ 3.5. O gsap (≥ 3.15) é dependency do pacote — instalado automaticamente; declare-o também no app se quiser pinar a mesma cópia.

Início rápido

O avatar é distribuído como um SFC Vue acompanhado de um arquivo CSS. Importe o stylesheet uma vez no app, em main.ts, para que as variáveis CSS dos acessórios fiquem disponíveis:

// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import '@be-enlighten/beni-avatar/style.css'

createApp(App).mount('#app')
<!-- App.vue -->
<script setup lang="ts">
import { ref } from 'vue'
import { Beni, type BeniState, type MoodName } from '@be-enlighten/beni-avatar'

const state = ref<BeniState>('idle')
const mood = ref<MoodName | null>(null)
</script>

<template>
  <Beni
    v-model:state="state"
    v-model:mood="mood"
  />
</template>

Pronto. Você tem um squircle de ~160×160 que pisca, respira e segue o cursor.

Props

| Prop | Tipo | Padrão | Descrição | | --- | --- | --- | --- | | state* | BeniState | 'idle' | Estado atual. Bind via v-model:state. | | mood* | MoodName \| null | null | Humor sobreposto. Bind via v-model:mood. | | headItem | HeadItemKey \| null | null | Acessório: 'beanie', 'crown', 'helmet', 'partyhat', 'santahat', 'stanhat'. | | bodyBaseColor | string | '#60a5fa' | Cor inicial do gradiente do corpo. | | bodyBaseColorTo | string | '#2563eb' | Cor final do gradiente do corpo. | | bodyBaseModel | BodyModelName | 'squircle' | Forma base, antes de overrides de estado. | | bodyScale | number | 1 | Escala geral do corpo. | | bodyOffsetX | number | 0 | Deslocamento horizontal, em unidades SVG. | | bodyOffsetY | number | 0 | Deslocamento vertical, em unidades SVG. | | eyeBaseColor | string | '#00f0ff' | Cor padrão dos olhos (estados podem sobrescrever). | | eyeBaseBlinkInterval | number | 4000 | Intervalo médio entre piscadas, em ms. 0 desativa. | | eyeGap | number | 2 | Distância entre os olhos. | | eyeOffsetX | number | 0 | Deslocamento horizontal dos olhos. | | eyeOffsetY | number | 2 | Deslocamento vertical dos olhos. | | eyeLookAtMouse | boolean | true | Olhos seguem o cursor. | | eyeLookAtTarget | { x, y } \| null | null | Fixa os olhos em um ponto (sobrepõe o mouse). | | eyeLookDuration | number | 0.15 | Duração do tween de movimento, em segundos. | | eyeLookEase | string | 'power2.out' | Ease do GSAP. | | eyeLookOvershoot | number | 0.6 | Overshoot quando os olhos se acomodam no alvo. | | bodyFollowMouse | boolean | true | Quando os olhos atingem as bordas, a cabeça vira levemente na direção do cursor. | | bodyFollowMaxRotation | number | 4 | Rotação máxima da cabeça, em graus. | | bodyFollowDeadzone | number | 5 | Limiar (em unidades do offset dos olhos) abaixo do qual a cabeça relaxa. | | bodyFollowDuration | number | 0.45 | Duração do tween de rotação da cabeça, em segundos. Mais lento que os olhos cria o efeito de "pescoço acompanha". | | clickRipple | boolean | true | Mostra uma onda no clique. | | clickRippleColor | string \| null | null | Cor da onda. Usa a cor atual do corpo por padrão. | | clickRippleDuration | number | 0.4 | Duração da onda, em segundos. |

* bind bidirecional via v-model.

Eventos

| Evento | Payload | Quando | | --- | --- | --- | | update:state | BeniState | O estado muda (via v-model). | | update:mood | MoodName \| null | O humor muda. | | click | BeniClickPayload | O avatar é clicado. | | interaction | BeniInteractionPayload | Uma interação interna de clique dispara. |

Estados

| Estado | Visual | Melhor uso | | --- | --- | --- | | idle | Balanço suave, olhos passeando | Padrão. | | working | Corpo girando, olhos frenéticos | Carregamento/processamento. | | error | Corpo vermelho, tremor com glitch | Estados de erro. | | speaking | Cabeça balançando, sílabas na boca | Assistentes de IA. | | loading | Quadrado arredondado girando | Loaders. | | sleep | Respiração lenta, olhos fechados, "Z"s | Ocioso / segundo plano. | | branding | Magenta→índigo, olhos "EN" | Splash / marketing. | | celebrate | Pulando, explosão de confete | Sucesso. |

<Beni :state="currentState" />
const currentState = ref<BeniState>('working')

watch(someTask, (task) => {
  currentState.value = task.status === 'loading' ? 'working' : 'celebrate'
})

Humores

Os humores se sobrepõem a um estado. Mudam olhos, boca e geram pequenos elementos SVG (lágrima, veia de raiva).

| Humor | Efeito | | --- | --- | | happy | Olhos arqueados, sorriso largo. | | sad | Olhos fechados, tom azulado, lágrima. | | angry | Olhos arqueados pra baixo, tom vermelho, veia. | | surprised | Olhos circulares, sem boca. |

<Beni v-model:state="state" v-model:mood="mood" />

Você pode derivar o humor a partir do estado. O avatar já dispara happy no clique duplo em idle (veja "Interações internas").

Acessórios de cabeça

Seis itens prontos. Cada um acompanha o pulo/escala/rotação do corpo, mas se mantém firme em cima da cabeça — não inclina com a inclinação do corpo, na prática parecia instável demais.

<Beni :head-item="accessory" />
import { type HeadItemKey, headItemNames, headItemLabels } from '@be-enlighten/beni-avatar'
import { ref } from 'vue'

const accessory = ref<HeadItemKey | null>('crown')

Em working, loading e error o acessório é escondido automaticamente. Esses estados giram tanto o corpo que o chapéu voaria.

Tematizando os acessórios: as cores vêm de variáveis CSS. Sobrescreva-as no seu stylesheet:

:root {
  --beni-items-head-crown: #ffd700;
  --beni-items-head-crown-shade: #b8860b;
  --beni-items-head-beanie: #8b5cf6;
  /* ... */
}

Importe @be-enlighten/beni-avatar/style.css antes e sobrescreva as variáveis depois.

Interações internas por clique

Clique rápido pra disparar easter eggs. Já vêm de fábrica, sem flag.

| Padrão | Estado inicial | Dispara | | --- | --- | --- | | Clique duplo | idle | Humor happy por 2,2s | | 5 cliques | idle | Estado branding por 3s | | Clique duplo | sleep | Piscada de volta por 1,5s | | 3 cliques | sleep | Acorda (persistente) |

Cada interação é anunciada pelo evento interaction.

Eventos de clique

<Beni @click="onClick" @interaction="onInteraction" />
import type { BeniClickPayload, BeniInteractionPayload } from '@be-enlighten/beni-avatar'

function onClick(p: BeniClickPayload) {
  console.log(p.target)       // 'body' | 'eye-left' | 'eye-right'
  console.log(p.clickIndex)   // 1 no primeiro clique, 2 no segundo dentro de 800ms, ...
  console.log(p.state)        // estado atual
  console.log(p.mood)         // humor atual (ou null)
}

function onInteraction(p: BeniInteractionPayload) {
  console.log(p.id)              // ex.: 'happy-on-double-click'
  console.log(p.label)           // legível por humanos
  console.log(p.triggerClickCount)
}

Tematizando o avatar

<script setup lang="ts">
const theme = {
  body: '#f59e0b',
  bodyTo: '#ef4444',
  eye: '#fef3c7',
}
</script>

<template>
  <Beni
    :body-base-color="theme.body"
    :body-base-color-to="theme.bodyTo"
    :eye-base-color="theme.eye"
  />
</template>

Para um seletor de temas completo, use computed:

import { computed } from 'vue'
import type { BeniState, MoodName } from '@be-enlighten/beni-avatar'

const theme = computed(() => themes[currentTheme.value])
const state = ref<BeniState>('idle')
const mood = ref<MoodName | null>(null)

O avatar é totalmente reativo: cada mudança de prop entra com tween (sem piscar), e estados/humores fazem crossfade suave.

Exemplo: estado de carregamento de um assistente de IA

<script setup lang="ts">
import { ref, watch } from 'vue'
import { Beni, type BeniState, type MoodName } from '@be-enlighten/beni-avatar'

const status = ref<'idle' | 'thinking' | 'done'>('idle')
const state = ref<BeniState>('idle')
const mood = ref<MoodName | null>(null)

watch(status, (s) => {
  if (s === 'thinking') {
    state.value = 'working'
    mood.value = null
  } else if (s === 'done') {
    state.value = 'celebrate'
    mood.value = 'happy'
  } else {
    state.value = 'idle'
    mood.value = null
  }
})
</script>

<template>
  <div class="assistant">
    <Beni
      v-model:state="state"
      v-model:mood="mood"
      :head-item="status === 'done' ? 'partyhat' : null"
      body-base-color="#fbbf24"
      body-base-color-to="#ec4899"
      eye-base-color="#fef3c7"
    />
    <p v-if="status === 'thinking'">Pensando…</p>
    <p v-else-if="status === 'done'">Pronto!</p>
  </div>
</template>

TypeScript

Pacote totalmente tipado. Exports mais úteis:

import type {
  BeniState,
  MoodName,
  HeadItemKey,
  BodyModelName,
  EyeModelName,
  BeniClickPayload,
  BeniInteractionPayload,
} from '@be-enlighten/beni-avatar'

// Constantes
import {
  beniStateNames, // ['idle', 'working', ...]
  beniMoods,
  headItemNames,
  headItemLabels,
} from '@be-enlighten/beni-avatar'

Suporte a navegadores

Qualquer navegador com suporte a CSS moderno (custom properties, filter) e SVG, ou seja, todos os navegadores evergreen. O GSAP exige requestAnimationFrame, que é universal.

O pacote respeita prefers-reduced-motion: reduce: as animações pausam no frame final quando o usuário tem essa preferência ativa.

Desenvolvimento

Este pacote vive no monorepo en-sdk (packages/beni-avatar). A demo/playground fica em examples/beni-avatar e consome o dist/ deste pacote via workspace — rode o build antes (e após cada mudança no src/).

pnpm install
pnpm --filter @be-enlighten/beni-avatar build             # gera dist/ (pacote)
pnpm --filter @be-enlighten/beni-avatar typecheck         # só type-check
pnpm --filter @be-enlighten/enspace-sdk-example-beni dev  # playground em http://localhost:5173

Publicando

Versão própria — este pacote não entra no lockstep dos 4 packages enspace-sdk-*. O versionamento é gerenciado por changesets (.changeset/ no root do monorepo): adicione um changeset com pnpm changeset a cada mudança user-facing e publique pelo fluxo unificado do monorepo:

pnpm version-packages   # bumpa versão + gera CHANGELOG a partir dos changesets
pnpm release            # valida, builda e publica o que estiver pendente

Detalhes na seção Publicação do AGENTS.md do monorepo. Sobe no npm público (access: public). Precisa de login npm local (npm login) com acesso ao escopo @be-enlighten.

Licença

MIT.