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

@c80/avatar

v1.1.1

Published

Avatar anfitrion animado "Aura" del ecosistema barman: core de comportamiento framework-agnostico + renderer SVG/CSS de fallback + renderer Rive opcional + adaptador Angular. API por intenciones de negocio.

Readme

@c80/avatar

Avatar anfitrion animado "Aura" del ecosistema barman: una estrella luminosa que acompania al cliente en chillbox (telefono) y en la pantalla de kiosco del box, orientando y comunicando estados sin ser invasiva. El nombre de negocio (PUNTOS ESTELARES) elige la mascota: una estrella.

Principio rector: las apps emiten intenciones de negocio; la libreria decide el comportamiento (que estado, que emocion, que animacion, duracion, prioridad, interrupciones, a que estado volver). Ninguna pantalla manipula animaciones ni conoce Rive.

Libreria hermana e independiente de @c80/ui/@c80/core/@c80/types: es autocontenida. Los consumidores traducen su dominio a los eventos del avatar.

Estado de implementacion

  • CORE framework-agnostico — tipos, contrato de renderer, defaults, behavior-map, cola de eventos, autonomia y runtime. TS puro, sin Angular/Rive/DOM. Importable en Node y determinista (reloj y RNG inyectables).
  • Renderer fallback SVG/CSS — Aura dibujada y animada (el entregable visual v1).
  • Renderer Rive opcional — dynamic import, wasm self-host, contrato del asset documentado.
  • Adaptador AngularprovideAvatar, AvatarService, <c80-avatar> (Angular 21 zoneless).

Pendiente (fuera de la lib): el .riv real (trabajo artistico), la app kiosk, la integracion en chillbox tras el flag CLIENT_AVATAR y la extension aditiva de vulcan.

Arquitectura

core/            TS PURO (sin Angular, sin Rive, sin DOM) — el "cerebro"
  types.ts             eventos, estados, emociones, atencion, acciones, config, snapshot
  renderer.contract.ts contrato AvatarRenderer (frontera hacia el dibujo)
  defaults.ts          config por defecto + presets por modo + resolveConfig()
  behavior-map.ts      guion evento -> reaccion + resolveBehavior + reglas de coherencia
  event-queue.ts       cola con prioridad + TTL + dedupe (reloj inyectable)
  autonomy.ts          scheduler de microacciones en ocio (RNG inyectable, sin timers propios)
  runtime.ts           orquesta cola/estado/accion/visibilidad/autonomia; publica snapshots
renderers/
  fallback/            Aura en SVG (aura-svg.ts) + FallbackRenderer (SVG/CSS + Web Animations API)
  rive/                RiveRenderer (dynamic import) + rive-contract.ts (spec del .riv)
angular/               provideAvatar + AvatarService (signals, rAF zoneless) + C80AvatarComponent

El runtime NUNCA toca el DOM: publica AvatarSnapshot y el adaptador conecta snapshot -> renderer.render(). Un renderer es intercambiable (fallback hoy, Rive manana) sin que cambie nada aguas arriba.

Modelo de estado (dimensiones separadas)

  • Visibilidad: hidden | entering | visible | leaving.
  • Estado principal: idle | processing | awaiting-qr-scan | awaiting-payment | preparing-drink | success | warning | error | offline | maintenance | disabled.
  • Emocion (complementa, no reemplaza): neutral | friendly | happy | curious | focused | excited | surprised | confused | empathetic | concerned | relieved.
  • Atencion: passive | attentive | active | priority.
  • Acciones temporales (se reproducen sobre el estado base y regresan solas): greet | blink | nod | shake-head | look-at-qr | invite-to-scan | celebrate | wait-expectantly | reassure | wake-up | sleep | indicate-pickup.

El runtime publica un AvatarSnapshot inmutable cada vez que algo cambia. El renderer aplica el snapshot completo con render(snapshot) (idempotente) y dispara la accion temporal cuando detecta que snapshot.action cambio a una accion nueva.

Prioridades, cola y coherencia

  • Prioridades critical > high > normal > ambient. Un error critico interrumpe cualquier decoracion; una microanimacion (ambient) jamas interrumpe una accion high/critical en curso; una accion no-interrumpible solo cede ante prioridad estrictamente mayor.
  • La cola descarta eventos caducados (ttlMs), colapsa repetidos (dedupeKey) y ordena por prioridad con desempate FIFO.
  • Reglas de coherencia (applyCoherence): sin emocion alegre en estado error; sin celebracion con error/warning activo.

Autonomia

Microacciones cuando el avatar esta ocioso y sin cola (parpadeo, dormitar tras inactividad, mirar/invitar al QR en kiosk). Activada por defecto y configurable por modo. No usa timers del navegador: el adaptador llama runtime.tick(now) y el core decide que microaccion y cuando.

Instalacion / consumo

@c80/avatar se publica a npm como sus hermanas. En apps del workspace ngx-c80 se resuelve por el path @c80/avatar. Peers: @angular/core, @angular/common, rxjs. @rive-app/canvas es peer opcional (solo si se activa el renderer rive).

Config minima (Angular)

// app.config.ts
import { provideAvatar } from '@c80/avatar';

export const appConfig: ApplicationConfig = {
  providers: [
    provideAvatar({ mode: 'mobile', skin: 'aura' }), // o { mode: 'kiosk' } en el kiosco
  ],
};
<!-- en el shell/layout global, una sola vez -->
<c80-avatar></c80-avatar>
// desde cualquier servicio/componente
import { AvatarService } from '@c80/avatar';

private readonly avatar = inject(AvatarService);
this.avatar.show();
this.avatar.emit({ type: 'serve.preparing' });
this.avatar.drinkReady();

Uso del core (sin Angular)

import { AvatarRuntime, resolveConfig } from '@c80/avatar';

const runtime = new AvatarRuntime(resolveConfig({ mode: 'kiosk' }));
const off = runtime.subscribe((s) => console.log(s.state, s.emotion, s.action));
runtime.emit({ type: 'avatar.show' });
runtime.emit({ type: 'drink.ready' });
runtime.tick(performance.now()); // el adaptador avanza el tiempo
off();
runtime.destroy();

API publica

  • Core: AvatarRuntime, AvatarEventQueue, AutonomyScheduler, resolveConfig, DEFAULT_AVATAR_CONFIG, MODE_PRESETS, BEHAVIOR_MAP, resolveBehavior, applyCoherence, PRIORITY_RANK, comparePriority, y todos los tipos (AvatarEvent, AvatarSnapshot, AvatarConfig, AvatarRenderer, ...).
  • Angular: provideAvatar(config?), AvatarService, C80AvatarComponent (<c80-avatar>), AVATAR_CONFIG.
  • Renderers: FallbackRenderer, RiveRenderer, buildAuraSvgMarkup, AURA_STYLE, AURA_VIEWBOX, AURA_CSS_VARS, y el contrato Rive (AVATAR_MACHINE, AVATAR_INPUTS, AVATAR_TRIGGERS, ACTION_TO_TRIGGER, STATE_INPUT_VALUES, ...).

AvatarService

  • emit(event) + helpers: show(), hide(), sessionStarted(), sessionExpired(), rechargeApproved(), rechargeRejected(), drinkReady(), serveError(recoverable, refunded?), networkOffline(), networkOnline().
  • Signals de solo lectura: snapshot, ready, state, emotion, visible.
  • attachRenderer(host) / detachRenderer() los usa el componente; degrada rive -> fallback.

Catalogo de eventos (API por intenciones)

Union discriminada AvatarEvent por type:

  • Ciclo de vida: avatar.show, avatar.hide.
  • Sesion de box: box.session.started, box.session.expired.
  • Recarga / puntos: recharge.started, recharge.pending, recharge.approved, recharge.rejected, points.insufficient.
  • Canje y servido: redeem.confirmed, serve.queued (position?), serve.preparing, serve.dispensing, serve.completed, drink.ready, serve.error (recoverable, refunded?).
  • Estado del box: box.idle, box.busy, box.maintenance, box.out-of-service, box.estop.
  • Conectividad: network.offline, network.online.

El mapeo evento -> reaccion (estado, emocion, accion, prioridad) vive en BEHAVIOR_MAP.

Modos

mobile (sutil, telefono), web (equilibrado), kiosk (mas expresivo, invita al QR), maintenance (sobrio, autonomia apagada). resolveConfig(partial) aplica el preset del modo y luego el override del usuario. Reduced motion es transversal: reducedMotion: 'system' (default, sigue prefers-reduced-motion con matchMedia) | 'enabled' | 'disabled'.

Renderer fallback (Aura SVG/CSS)

Es el entregable visual v1 y el default. Dibuja una estrella luminosa de 5 puntas con nucleo brillante y rostro minimo (ojos + boca), animada solo con transform/opacity (barato en CPU, apto para dias en la Raspberry). Anima con:

  • CSS continuo: flotacion, halo, pulso del nucleo, destellos (se pausan solos cuando la pestania se oculta y con pause()).
  • Web Animations API: los gestos temporales (greet, celebrate, mirada, nod, ...).
  • Expresiones por estado (tinte del halo) y emocion (forma de boca/ojos).
  • Reduced motion: sustituye desplazamientos/rotaciones por cambios suaves de opacidad/escala.

Retematizar sin tocar la lib: redefinir en el host las CSS custom properties --c80-avatar-core|body|body-edge|glow|rim|face|sparkle (ver AURA_CSS_VARS).

Contrato del asset Rive (para el trabajo artistico)

El renderer rive esta implementado detras del contrato pero sin un .riv real no se valida end-to-end (honestidad). El asset lo produce un artista en el editor de Rive siguiendo rive-contract.ts:

  • State machine: AvatarMachine.
  • Inputs (numericos salvo reducedMotion booleano): state, emotion, attention, intensity (0..2), lookX/lookY (-1..1), reducedMotion. Los enumerados usan los indices EXACTOS de STATE_INPUT_VALUES / EMOTION_INPUT_VALUES / ATTENTION_INPUT_VALUES (son contrato: no reordenar).
  • Triggers: greet, blink, nod, shakeHead, lookAtQr, inviteToScan, celebrate, reassure, wakeUp, sleep, indicatePickup (mapeo desde acciones en ACTION_TO_TRIGGER).

Como enchufar el .riv

  1. Instalar el peer opcional en la app: pnpm add @rive-app/canvas.
  2. Self-hostear el wasm del runtime junto al .riv (misma carpeta de assets, servido como rive.wasm). Nunca CDN (el kiosco debe funcionar sin internet).
  3. provideAvatar({ renderer: 'rive', assetUrl: '/assets/avatar/aura.riv' }).
  4. Si el import o el asset fallan, el adaptador degrada al fallback automaticamente.

Como extender

  • Agregar un evento: sumar la variante a AvatarEvent (types.ts) y su fila en BEHAVIOR_MAP (behavior-map.ts). Si necesita logica (leer campos del evento), ampliar resolveBehavior.
  • Agregar una emocion: sumarla a AvatarEmotion, mapear su expresion en el CSS de Aura (AURA_STYLE, selector [data-emotion="..."]) y su indice en EMOTION_INPUT_VALUES (Rive).
  • Agregar una accion: sumarla a AvatarAction, su keyframe en FallbackRenderer y su trigger en AVATAR_TRIGGERS + ACTION_TO_TRIGGER.
  • Agregar una skin: por ahora hay una (aura). Un renderer nuevo puede leer config.skin para elegir markup/paleta; el contrato AvatarRenderer no cambia.
  • Agregar un renderer: implementar AvatarRenderer y seleccionarlo en AvatarService.createRenderer (dynamic import para mantenerlo en chunk aparte).

Limitaciones actuales

  • Sin un .riv real, el renderer Rive no se valida end-to-end: queda detras del contrato con tipos locales acotados; su rama probada es la de error (asset/paquete ausente -> fallback).
  • Una sola personalidad (friendly-host) y una sola skin (aura).
  • El fallback usa Web Animations API y transform-box: fill-box (navegadores modernos; el target es Chromium del kiosco y los moviles actuales).
  • Sin sonido y sin PII (decision de producto v1).