Marciano by Hostarys
Usarlo

Marciano en tu proyecto.

Un paquete, @hostarys/marciano, con componente React, componente Vue y el web component <marciano-flame> para cualquier web. Sin dependencias.

01

Instalar

El paquete es privado y vive en GitHub Packages (github.com/Hostarys/marciano). Necesitas un token con permiso de lectura de paquetes.

  1. Apunta el scope @hostarys a GitHub

    Crea un .npmrc en la raíz del proyecto. Se puede subir al repositorio: el token se lee de una variable de entorno, nunca va escrito.

    .npmrc
    @hostarys:registry=https://npm.pkg.github.com
    //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
  2. Consigue un token con read:packages

    Opción A: un token clásico (PAT) con solo el permiso read:packages, guardado en la variable GITHUB_TOKEN. Opción B: si ya usas GitHub CLI, reutiliza su sesión:

    Terminal
    # con GitHub CLI: añade el permiso y exporta el token
    gh auth refresh -s read:packages
    export GITHUB_TOKEN=$(gh auth token)
    
    # PowerShell
    $env:GITHUB_TOKEN = gh auth token
  3. Instala

    Terminal
    pnpm add @hostarys/marciano
    # o
    npm install @hostarys/marciano
  4. En Vercel y CI

    Añade el token como variable de entorno del proyecto (GITHUB_TOKEN, o NPM_TOKEN si cambias también el nombre en el .npmrc: deben coincidir). En Vercel: Settings → Environment Variables, disponible en el build. En GitHub Actions basta el token del propio workflow con permiso packages: read.

    GitHub Actions
    # .github/workflows/ci.yml
    permissions:
      contents: read
      packages: read
    steps:
      - uses: actions/checkout@v4
      - run: pnpm install
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
02

React / Next.js

Marciano ya es un Client Component: impórtalo tal cual en un Server Component del App Router. Solo necesitas "use client" en tus propios componentes interactivos.

app/page.tsx
// app/page.tsx  (Server Component, sin "use client")
import { Marciano } from "@hostarys/marciano";

export default function Page() {
  return <Marciano color="hostarys" glow accessory="crown" size={180} />;
}
En vivo

Controlarlo con useMarciano()

El hook devuelve [ref, controles]. Los controles esperan solos a que el componente termine de cargar, así que puedes llamarlos incluso en el primer useEffect.

components/marciano-saluda.tsx
"use client";
import { Marciano, useMarciano } from "@hostarys/marciano";

export function MarcianoSaluda() {
  const [ref, marciano] = useMarciano();
  return (
    <div>
      <Marciano ref={ref} color="ember" glow size={150} />
      <button onClick={() => marciano.play("hearts")}>Enamorar</button>
      <button onClick={() => marciano.say("¡Hola!")}>Saludar</button>
      <button onClick={() => marciano.queue("surprised", "happy")}>Cola</button>
    </div>
  );
}
En vivo
03

Props

Todas opcionales. Los nombres son camelCase; en HTML se escriben en kebab-case (sleepAfter → sleep-after, reactToPage → react, hiddenStart → hidden-start).

PropTipoPor defectoDescripción
mood"dots" | "hearts" | "spiral" | "sleepy" | "cross" | "angry" | "surprised" | "happy" | "sad" | "wink" | "thinking""dots"Expresión base, a la que vuelve tras cada animación.
color"hostarys" | "lavanda" | "noche" | "negro" | "ember" | "cyan" | "lime" | "violet" | string"negro"Preset de marca o cualquier color CSS.
eyestring"#f0ebe4"Color de los ojos.
bgstring"transparent"Fondo del lienzo.
glowboolean | numberfalseResplandor del color de la llama; un número ajusta la intensidad (p. ej. 1.5).
accessoryAccessoryName | AccessoryName[]—Uno o varios: glasses, sunglasses, bowtie, crown, santa, headphones, witch, pumpkin, scarf, party, flowers, heart, beach. Dos del mismo hueco (cabeza, cara, cuello, mano, orejas) chocan: gana el primero.
season"auto" | "halloween" | "christmas" | "newyear" | "valentine" | "spring" | "summer"—Accesorios de temporada. "auto" los elige por la fecha en España (Halloween 15 oct–1 nov, Navidad 1 dic–6 ene, Nochevieja 31 dic–1 ene, San Valentín 7–14 feb, primavera 21 mar–31 may, verano jul–ago). Los accesorios explícitos ganan si ocupan el mismo hueco.
pausedbooleanfalseFotograma fijo y determinista, sin animación ni interacción: miniaturas, capturas y tests visuales.
status"online" | "busy" | "degraded" | "down" | "maintenance"—Estado de servidor: fija la expresión base y evita que se duerma.
soundbooleanfalseSonidos sintetizados (necesitan un clic previo del usuario).
sleepAfternumber20Segundos sin actividad hasta dormirse. 0 = nunca.
dragbooleanfalseSe puede arrastrar y lanzar. Vuelve con resetPosition().
reactToPagebooleanfalseReacciona a la página: scroll rápido, formularios, copiar, conexión.
socialbooleantrueMira y reacciona a otros Marcianos de la página.
liteboolean | "auto"falseModo ligero (menos efectos). "auto": solo en equipos modestos.
hiddenStartbooleanfalseEmpieza apagado; aparece con enter().
interactivebooleantrueRatón, clics y sueño automático.
sizenumber | string240Ancho (número = px). El alto se ajusta solo.
onMoodChange(detail, event) => void—Se llama en cada cambio de expresión o de cola. detail: { mood, queue, running }.
className, style, …HTMLAttributes—Cualquier atributo HTML (aria-*, id, data-*…) pasa al elemento.
04

Métodos y eventos

Disponibles en el elemento (ref.current en React). Los marcados con ✓ también están en los controles de useMarciano().

NombreTipoDevuelveDescripciónHook
play(mood)métodoPromise<void>Interrumpe lo que hace y reproduce esa expresión ya.✓
queue(...moods)métodoPromise<void>Añade expresiones a la cola; se reproducen en orden.✓
clearQueue()métodovoidVacía la cola pendiente.✓
say(text, { ms })métodoPromise<void>Bocadillo con texto y boca animada. ms = duración (por defecto según la longitud).✓
enter()métodoPromise<void>Aparece encendiéndose desde chispas (ideal con hiddenStart).✓
exit()métodoPromise<void>Se apaga en una nube de humo.✓
lipSync(media)métodovoidMueve la boca siguiendo el volumen de un <audio> o <video>.—
resetPosition()métodovoidVuelve a su sitio tras arrastrarlo.✓
moodpropiedadMoodNameExpresión actual (solo lectura).✓
pendingpropiedadMoodName[]Cola de expresiones pendientes (solo lectura).—
moodchangeeventoCustomEventSe emite en cada cambio de expresión o de cola. detail: { mood, queue, running }.—
Ref y eventos
"use client";
import { useRef } from "react";
import { Marciano, type MarcianoFlameElement } from "@hostarys/marciano";

export function ConEventos() {
  const ref = useRef<MarcianoFlameElement>(null);
  return (
    <Marciano
      ref={ref}                                  // el ref es el propio elemento
      onMoodChange={({ mood, queue, running }) => console.log(mood, queue, running)}
      onClick={() => console.log(ref.current?.pending)}
    />
  );
}

// Sin React: el mismo evento en el DOM
document.querySelector("marciano-flame")
  .addEventListener("moodchange", e => console.log(e.detail.mood));
En vivo
Pulsa un botón para ver el evento moodchange
05

Vue 3

Importa desde @hostarys/marciano/vue. El plugin registra el componente <Marciano> global y carga el web component.

main.ts
// main.ts
import { createApp } from "vue";
import MarcianoPlugin from "@hostarys/marciano/vue";
import App from "./App.vue";

createApp(App).use(MarcianoPlugin).mount("#app");
App.vue
<!-- App.vue -->
<script setup lang="ts">
import { ref } from "vue";
const m = ref();
const onMood = (e: CustomEvent) => console.log(e.detail.mood);
</script>

<template>
  <Marciano ref="m" color="hostarys" glow :size="180" @moodchange="onMood" />
  <button @click="m.play('hearts')">Enamorar</button>
</template>

¿Prefieres la etiqueta cruda <marciano-flame> en tus plantillas? Dile a Vue que es un custom element:

vite.config.ts
// vite.config.ts — solo si usas la etiqueta <marciano-flame> directamente
import vue from "@vitejs/plugin-vue";

export default {
  plugins: [vue({
    template: { compilerOptions: { isCustomElement: tag => tag === "marciano-flame" } },
  })],
};
06

HTML sin frameworks

Un único script clásico. Descárgalo de esta web (/marciano-flame.js) o cógelo del paquete (@hostarys/marciano/marciano-flame.js) y súbelo a tu servidor.

index.html
<script src="/marciano-flame.js" defer></script>

<marciano-flame color="ember" glow accessory="sunglasses"></marciano-flame>

<script>
  customElements.whenDefined("marciano-flame").then(() => {
    const m = document.querySelector("marciano-flame");
    m.queue("surprised", "hearts");   // añadir a la cola
    m.play("cross");                  // interrumpir y reproducir ya
  });
</script>
En vivo
Con bundler
// con bundler (Vite, webpack…): registra <marciano-flame>
import "@hostarys/marciano/element";

// o sirve tú el script clásico que trae el paquete
// (node_modules/@hostarys/marciano/dist/vendor/marciano-flame.js); en Vite:
import flameUrl from "@hostarys/marciano/marciano-flame.js?url";
07

WordPress

Instala el plugin (el zip está en Descargas) y usa el shortcode en cualquier página, entrada o bloque «Shortcode».

Shortcode
[marciano color="hostarys" mood="happy" glow accessory="crown" say="Hola"]

Acepta los mismos atributos que el web component (color, mood, glow, accessory, status, sleep-after…) y además say (le hace decir un texto al aparecer), width y align.

En vivo