Marciano en tu proyecto.
Un paquete, @hostarys/marciano, con componente React, componente Vue y el web component <marciano-flame> para cualquier web. Sin dependencias.
Instalar
El paquete es privado y vive en GitHub Packages (github.com/Hostarys/marciano). Necesitas un token con permiso de lectura de paquetes.
Apunta el scope
@hostarysa GitHubCrea un
.npmrcen 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}Consigue un token con
read:packagesOpción A: un token clásico (PAT) con solo el permiso
read:packages, guardado en la variableGITHUB_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 tokenInstala
Terminal pnpm add @hostarys/marciano # o npm install @hostarys/marcianoEn Vercel y CI
Añade el token como variable de entorno del proyecto (
GITHUB_TOKEN, oNPM_TOKENsi 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 permisopackages: 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 }}
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} />;
}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>
);
}Props
Todas opcionales. Los nombres son camelCase; en HTML se escriben en kebab-case (sleepAfter → sleep-after, reactToPage → react, hiddenStart → hidden-start).
| Prop | Tipo | Por defecto | Descripció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. |
eye | string | "#f0ebe4" | Color de los ojos. |
bg | string | "transparent" | Fondo del lienzo. |
glow | boolean | number | false | Resplandor del color de la llama; un número ajusta la intensidad (p. ej. 1.5). |
accessory | AccessoryName | 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. |
paused | boolean | false | Fotograma 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. |
sound | boolean | false | Sonidos sintetizados (necesitan un clic previo del usuario). |
sleepAfter | number | 20 | Segundos sin actividad hasta dormirse. 0 = nunca. |
drag | boolean | false | Se puede arrastrar y lanzar. Vuelve con resetPosition(). |
reactToPage | boolean | false | Reacciona a la página: scroll rápido, formularios, copiar, conexión. |
social | boolean | true | Mira y reacciona a otros Marcianos de la página. |
lite | boolean | "auto" | false | Modo ligero (menos efectos). "auto": solo en equipos modestos. |
hiddenStart | boolean | false | Empieza apagado; aparece con enter(). |
interactive | boolean | true | Ratón, clics y sueño automático. |
size | number | string | 240 | Ancho (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. |
Métodos y eventos
Disponibles en el elemento (ref.current en React). Los marcados con ✓ también están en los controles de useMarciano().
| Nombre | Tipo | Devuelve | Descripción | Hook |
|---|---|---|---|---|
play(mood) | método | Promise<void> | Interrumpe lo que hace y reproduce esa expresión ya. | ✓ |
queue(...moods) | método | Promise<void> | Añade expresiones a la cola; se reproducen en orden. | ✓ |
clearQueue() | método | void | Vacía la cola pendiente. | ✓ |
say(text, { ms }) | método | Promise<void> | Bocadillo con texto y boca animada. ms = duración (por defecto según la longitud). | ✓ |
enter() | método | Promise<void> | Aparece encendiéndose desde chispas (ideal con hiddenStart). | ✓ |
exit() | método | Promise<void> | Se apaga en una nube de humo. | ✓ |
lipSync(media) | método | void | Mueve la boca siguiendo el volumen de un <audio> o <video>. | — |
resetPosition() | método | void | Vuelve a su sitio tras arrastrarlo. | ✓ |
mood | propiedad | MoodName | Expresión actual (solo lectura). | ✓ |
pending | propiedad | MoodName[] | Cola de expresiones pendientes (solo lectura). | — |
moodchange | evento | CustomEvent | Se emite en cada cambio de expresión o de cola. detail: { mood, queue, running }. | — |
"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));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" } },
})],
};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>// 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";WordPress
Instala el plugin (el zip está en Descargas) y usa el shortcode en cualquier página, entrada o bloque «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.