GALERÍA DE COMPONENTES

Animaciones · Lottie

Microanimaciones vectoriales que acompañan el trabajo.

Movimiento con identidad propia

Reutilizable

Una órbita alrededor de la marca KC. El color cambia con tu tema y la animación se pausa cuando queda fuera de la pantalla.

Lista para reproducir. Si tienes movimiento reducido activo, verás un fotograma estático.
Ver y copiar HTML
<!-- INICIO: Movimiento con identidad propia -->
<section id="lottie-player" class="panel demo-card" data-component="lottie-player">
  <div class="panel-heading">
    <h2>Movimiento con identidad propia</h2>
    <span class="tag">Reutilizable</span>
  </div>
  <p class="demo-description">
    Una órbita alrededor de la marca KC. El color cambia con tu tema y la animación se pausa cuando
    queda fuera de la pantalla.
  </p>
  <div class="motion-stage">
    <span
      id="motion-primary"
      class="kc-motion"
      data-lottie-src="../assets/animations/kc-orbit.json"
      aria-hidden="true"
      ><span data-motion-canvas></span
      ><i class="fa-solid fa-circle-notch fa-spin motion-fallback" aria-hidden="true"></i
    ></span>
  </div>
  <div class="demo-row">
    <button class="btn lime" type="button" data-motion-action="play">
      <i class="fa-solid fa-play" aria-hidden="true"></i>Reproducir</button
    ><button class="btn outline" type="button" data-motion-action="pause">
      <i class="fa-solid fa-pause" aria-hidden="true"></i>Pausar</button
    ><button class="btn outline" type="button" data-motion-action="stop">
      <i class="fa-solid fa-stop" aria-hidden="true"></i>Detener
    </button>
  </div>
  <label class="motion-speed"
    >Velocidad <output id="motion-speed-value">1×</output
    ><input id="motion-speed" type="range" min="0.5" max="2" step="0.25" value="1" /></label
  ><output id="motion-status" class="demo-inline-output" role="status"
    >Lista para reproducir. Si tienes movimiento reducido activo, verás un fotograma
    estático.</output
  >
</section>

Usar un archivo de LottieFiles

Reutilizable

Descarga un JSON de LottieFiles con su licencia, guárdalo junto a sus recursos y cambia data-lottie-src en el HTML.

  1. Exporta vectores en formato Lottie JSON, sin expresiones ni recursos remotos.
  2. Copia el JSON a assets/animations y conserva la licencia de su autor.
  3. Coloca la ruta local en data-lottie-src y conserva el contenedor data-motion-canvas.
  4. Carga lottie_light.min.js antes de motion.js.

Las animaciones incluidas son originales de KC. LottieFiles es compatible con el formato; estos ejemplos usan el reproductor lottie-web 5.13.0. El sistema respeta movimiento reducido y deja un icono de respaldo si no puede cargar el JSON.

Ver y copiar HTML
<!-- INICIO: Usar un archivo de LottieFiles -->
<section
  id="lottiefiles-integration"
  class="panel demo-card"
  data-component="lottiefiles-integration"
>
  <div class="panel-heading">
    <h2>Usar un archivo de LottieFiles</h2>
    <span class="tag">Reutilizable</span>
  </div>
  <p class="demo-description">
    Descarga un JSON de LottieFiles con su licencia, guárdalo junto a sus recursos y cambia
    data-lottie-src en el HTML.
  </p>
  <ol class="demo-steps">
    <li>Exporta vectores en formato Lottie JSON, sin expresiones ni recursos remotos.</li>
    <li>Copia el JSON a assets/animations y conserva la licencia de su autor.</li>
    <li>Coloca la ruta local en data-lottie-src y conserva el contenedor data-motion-canvas.</li>
    <li>Carga lottie_light.min.js antes de motion.js.</li>
  </ol>
  <p class="demo-description">
    Las animaciones incluidas son originales de KC. LottieFiles es compatible con el formato; estos
    ejemplos usan el reproductor lottie-web 5.13.0. El sistema respeta movimiento reducido y deja un
    icono de respaldo si no puede cargar el JSON.
  </p>
</section>

Cómo usar Lottie / LottieFiles

Código reutilizable

Copia el contenedor kc-motion, su fallback, media-components.css, lottie_light.min.js y motion.js. El reproductor descubre data-lottie-src automáticamente y los controles globales son opcionales. KCMotion.control(elemento, "play"), "pause" o "stop" controlan una instancia; KCMotion.speed(elemento, 1.5) cambia su velocidad. Los vectores se recolorean con el tema, respetan movimiento reducido y se pausan fuera de la pantalla.

Archivo: assets/js/motion.js. Carga una sola copia de cada script, en este orden.

Ver archivos necesarios y orden de carga
<script src="../assets/js/theme.js"></script>
<link rel="stylesheet" href="../assets/css/tailwind.css" />
<link rel="stylesheet" href="../assets/css/styles.css" />
<link rel="stylesheet" href="../assets/css/video.css" />
<link rel="stylesheet" href="../assets/css/appearance.css" />
<script defer="" src="../assets/js/shared.js"></script>
<script defer="" src="../assets/js/ui.js"></script>
<script defer="" src="../assets/js/appearance.js"></script>
<script defer="" src="../assets/js/components.js"></script>
<link rel="stylesheet" href="../assets/css/components.css" />
<link rel="stylesheet" href="../assets/vendor/fontawesome/css/all.min.css" />
<link rel="stylesheet" href="../assets/css/media-components.css" />
<script defer src="../assets/vendor/lottie-web/lottie_light.min.js"></script>
<script defer src="../assets/js/motion.js"></script>
Ver y copiar JavaScript
// Lottie runtime configuration. Containers, fallbacks and controls are authored in HTML.
// Use a local JSON exported from LottieFiles via data-lottie-src; keep its license and assets.
(() => {
  const reduced = matchMedia("(prefers-reduced-motion: reduce)");
  const entries = new Map();
  const sources = new Map();
  function palette() {
    const style = getComputedStyle(document.documentElement);
    return ["--accent-deep", "--line"].map((key) => style.getPropertyValue(key).trim());
  }
  function rgba(hex) {
    return [
      ...hex
        .replace("#", "")
        .match(/.{2}/g)
        .map((value) => parseInt(value, 16) / 255),
      1,
    ];
  }
  function recolor(node, colors) {
    if (!node || typeof node !== "object") return;
    if ((node.ty === "st" || node.ty === "fl") && node.c && ["Accent", "Soft"].includes(node.nm)) {
      node.c = { a: 0, k: rgba(colors[node.nm === "Accent" ? 0 : 1]) };
    }
    Object.values(node).forEach((value) => {
      if (Array.isArray(value)) value.forEach((item) => recolor(item, colors));
      else if (value && typeof value === "object") recolor(value, colors);
    });
  }
  function sync(entry) {
    if (!entry.animation || !entry.ready) return;
    if (reduced.matches) entry.animation.goToAndStop(36, true);
    else if (entry.visible && entry.playing) entry.animation.play();
    else entry.animation.pause();
  }
  async function load(host) {
    let entry = entries.get(host);
    if (!entry) {
      entry = { playing: true, visible: false, ready: false, generation: 0, speed: 1 };
      entries.set(host, entry);
      observer.observe(host);
    }
    const generation = ++entry.generation;
    const source = host.dataset.lottieSrc;
    host.classList.remove("motion-ready");
    entry.ready = false;
    try {
      if (!sources.has(source))
        sources.set(
          source,
          fetch(source).then((response) => {
            if (!response.ok) throw new Error("No se pudo cargar la animación.");
            return response.json();
          }),
        );
      const data = structuredClone(await sources.get(source));
      if (generation !== entry.generation) return;
      recolor(data, palette());
      entry.animation?.destroy();
      entry.animation = lottie.loadAnimation({
        container: host.querySelector("[data-motion-canvas]"),
        renderer: "svg",
        loop: true,
        autoplay: false,
        animationData: data,
        rendererSettings: { progressiveLoad: true, preserveAspectRatio: "xMidYMid meet" },
      });
      entry.animation.setSpeed(entry.speed);
      entry.animation.addEventListener("DOMLoaded", () => {
        if (generation !== entry.generation) return;
        entry.ready = true;
        host.classList.add("motion-ready");
        sync(entry);
      });
    } catch {
      sources.delete(source);
      host.classList.remove("motion-ready");
      document
        .querySelector("#motion-status")
        ?.replaceChildren(
          document.createTextNode(
            "La animación no está disponible. Se muestra el icono de respaldo.",
          ),
        );
    }
  }
  const observer = new IntersectionObserver((items) => {
    items.forEach((item) => {
      const entry = entries.get(item.target);
      if (!entry) return;
      entry.visible = item.isIntersecting;
      sync(entry);
    });
  });
  window.KCMotion = Object.freeze({
    reload: load,
    control(host, action) {
      const entry = entries.get(host);
      if (!entry) return;
      entry.playing = action === "play";
      if (action === "stop") entry.animation?.goToAndStop(0, true);
      else sync(entry);
    },
    speed(host, value) {
      const entry = entries.get(host);
      if (!entry) return;
      entry.speed = value;
      entry.animation?.setSpeed(value);
    },
  });
  document.querySelectorAll("[data-lottie-src]").forEach(load);
  let previousPalette = palette().join();
  window.addEventListener("kc:appearance", () => {
    const nextPalette = palette().join();
    if (nextPalette === previousPalette) return;
    previousPalette = nextPalette;
    entries.forEach((entry, host) => load(host));
  });
  reduced.addEventListener("change", () => entries.forEach(sync));
  const primary = document.querySelector("#motion-primary");
  document.querySelectorAll("[data-motion-action]").forEach((button) => {
    button.addEventListener("click", () => {
      KCMotion.control(primary, button.dataset.motionAction);
      document.querySelector("#motion-status").textContent = reduced.matches
        ? "Movimiento reducido activo: se muestra un fotograma estático."
        : {
            play: "Reproduciendo animación.",
            pause: "Animación en pausa.",
            stop: "Animación detenida.",
          }[button.dataset.motionAction];
    });
  });
  document.querySelector("#motion-speed")?.addEventListener("input", (event) => {
    const speed = Number(event.target.value);
    KCMotion.speed(primary, speed);
    document.querySelector("#motion-speed-value").textContent = speed + "×";
  });
  window.addEventListener("pagehide", () => entries.forEach((entry) => entry.animation?.pause()));
  window.addEventListener("pageshow", () => entries.forEach(sync));
})();
© 2026 KC Finance Plantilla creada por Codar · Hecha para crecer contigo.● Todos los sistemas operativos

HAZLO TUYO

Apariencia

Tu espacio, a tu manera.

Modo de visualización
Tamaño de la interfaz

Amplía textos, botones y tarjetas. Se conserva entre pantallas.

Color de la plantilla

El acento se aplica al menú, botones y gráficas.

Fondo

Elige una base que acompañe tu color.

Se guarda en este navegador y en todas las pantallas.