Preparando tu espacio
Una carga con la marca de la plantilla.
Accesos rápidos fijados
Tu actividad más reciente
GALERÍA DE COMPONENTES
Microanimaciones vectoriales que acompañan el trabajo.
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.
<!-- 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>
Tres animaciones vectoriales originales incluidas en JSON: sin imágenes ni solicitudes a servicios externos.
Una carga con la marca de la plantilla.
Anillos que acompañan una actualización.
Barras que anticipan el siguiente resultado.
<!-- INICIO: De la espera al contexto -->
<section id="lottie-gallery" class="panel demo-card" data-component="lottie-gallery">
<div class="panel-heading">
<h2>De la espera al contexto</h2>
<span class="tag">Reutilizable</span>
</div>
<p class="demo-description">
Tres animaciones vectoriales originales incluidas en JSON: sin imágenes ni solicitudes a
servicios externos.
</p>
<div class="motion-grid">
<article class="motion-card">
<span
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>
<h3>Preparando tu espacio</h3>
<p>Una carga con la marca de la plantilla.</p>
</article>
<article class="motion-card">
<span
class="kc-motion"
data-lottie-src="../assets/animations/kc-radar.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>
<h3>Sincronizando datos</h3>
<p>Anillos que acompañan una actualización.</p>
</article>
<article class="motion-card">
<span
class="kc-motion"
data-lottie-src="../assets/animations/kc-report.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>
<h3>Armando tu reporte</h3>
<p>Barras que anticipan el siguiente resultado.</p>
</article>
</div>
</section>
Descarga un JSON de LottieFiles con su licencia, guárdalo junto a sus recursos y cambia data-lottie-src en el HTML.
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.
<!-- 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>
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.
<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>
// 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));
})();
KC FINANCE
KC FINANCE
KC FINANCE
KC FINANCE
Esta plantilla no tiene una sesión real. Puedes restablecer las preferencias de navegación y los marcadores guardados en este navegador.
KC FINANCE
KC FINANCE
KC FINANCE
Facturas de ejemplo pendientes de revisión.