CSS / SVG · 3.6 KB gzip
Arcane Seal
A layered ritual seal with counter-rotating runes, geometric wards, and a luminous spell core.
signaturemagicrunesoccultanime-inspired
Interactive preview
Usage
Packages are @vikast908/core and
@vikast908/loaders. Prefer 0.1.1+
(0.1.0 loaders is broken on npm).
npm install @vikast908/loaders@0.1.1 @vikast908/core@0.1.1
import '@vikast908/loaders/arcane-seal'; <orbux-arcane-seal state="thinking"></orbux-arcane-seal>
Browser-only alternative: Download HTML (self-contained) or load the hosted ESM bundle:
<script type="module" src="http://localhost:4321/orbux/arcane-seal.js"></script> <orbux-arcane-seal state="thinking"></orbux-arcane-seal>
Component source arcane-seal.ts
import { OrbuxElement } from '@vikast908/core';
const STYLES = /* css */ `
:host { --_tone:var(--orbux-color,#a855f7);--_tone-2:var(--orbux-color-2,#f0abfc);--_dur:4s; }
.seal { position:relative;inline-size:100%;block-size:100%;display:grid;place-items:center;filter:drop-shadow(0 0 7px color-mix(in srgb,var(--_tone) 58%,transparent)); }
.ring { position:absolute;inset:var(--_inset);border-radius:50%;border:var(--_weight) solid color-mix(in srgb,var(--_tone) var(--_alpha),transparent);animation:orbux-arcane-turn calc((var(--_dur) + var(--_i) * .8s) * var(--orbux-speed-scale)) linear infinite; }
.ring:nth-child(2) { border-style:dashed;animation-direction:reverse; }
.triangle { position:absolute;inset:25%;clip-path:polygon(50% 0,100% 88%,0 88%);background:var(--_tone);-webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;mask-composite:exclude;padding:2px;animation:orbux-arcane-pulse calc(1.6s * var(--orbux-speed-scale)) cubic-bezier(.77,0,.175,1) infinite; }
.glyph { position:absolute;left:46%;top:4%;inline-size:8%;block-size:13%;transform-origin:50% 354%;rotate:var(--_angle); }
.glyph::before,.glyph::after { content:"";position:absolute;left:45%;inline-size:2px;block-size:100%;border-radius:999px;background:var(--_tone-2); }
.glyph::after { transform:rotate(55deg);transform-origin:center; }
.core { position:absolute;inset:41%;border-radius:50%;background:var(--_tone-2);box-shadow:0 0 10px var(--_tone); }
@keyframes orbux-arcane-turn { to { transform:rotate(360deg); } }
@keyframes orbux-arcane-pulse { 50% { transform:rotate(60deg) scale(.86);opacity:.55; } }
@keyframes orbux-arcane-done { 50% { transform:scale(1.055); } }
@keyframes orbux-arcane-error { 35% { transform:translateX(-4%); } 70% { transform:translateX(4%); } }
:host([data-state="streaming"]) { --_dur:2s; }
:host([data-state="tool-calling"]) .ring { animation-timing-function:steps(8,end); }
:host([data-state="tool-calling"]) .triangle { transform:rotate(180deg); }
:host([data-state="idle"]) .ring,:host([data-state="waiting"]) .ring,:host([data-state="idle"]) .triangle,:host([data-state="waiting"]) .triangle { animation:none; }
:host([data-state="idle"]) .seal { opacity:.5; }
:host([data-state="waiting"]) .glyph:nth-of-type(even) { opacity:.22; }
:host([data-state="done"]) { --_tone:var(--orbux-color-success,#22c55e);--_tone-2:#bbf7d0; }
:host([data-state="error"]) { --_tone:var(--orbux-color-error,#ef4444);--_tone-2:#fecdd3; }
:host([data-state="done"]) .ring,:host([data-state="error"]) .ring,:host([data-state="done"]) .triangle,:host([data-state="error"]) .triangle { animation:none; }
:host([data-state="done"]) .seal { animation:orbux-arcane-done 220ms cubic-bezier(.23,1,.32,1) 1; }
:host([data-state="error"]) .seal { animation:orbux-arcane-error 200ms cubic-bezier(.23,1,.32,1) 1; }
:host([data-settled="true"]) .seal { animation:none; }
:host([data-paused="true"]) * { animation-play-state:paused !important; }
:host([data-reduced-motion="true"]) * { animation:none !important; }
:host([data-reduced-motion="true"][data-state="streaming"]) .triangle { transform:rotate(60deg); }
`;
export class OrbuxArcaneSeal extends OrbuxElement {
protected build(): void {
const style = document.createElement('style');
style.textContent = STYLES;
const seal = document.createElement('div');
seal.className = 'seal';
seal.setAttribute('part', 'seal');
seal.innerHTML = `<span class="ring" style="--_i:0;--_inset:6%;--_weight:1px;--_alpha:72%"></span><span class="ring" style="--_i:1;--_inset:16%;--_weight:2px;--_alpha:58%"></span><span class="ring" style="--_i:2;--_inset:31%;--_weight:1px;--_alpha:82%"></span><span class="triangle"></span>${Array.from({ length: 8 }, (_, index) => `<i class="glyph" style="--_angle:${index * 45}deg"></i>`).join('')}<span class="core"></span>`;
this.root.append(style, seal);
}
}
if (typeof customElements !== 'undefined' && !customElements.get('orbux-arcane-seal'))
customElements.define('orbux-arcane-seal', OrbuxArcaneSeal);
declare global {
interface HTMLElementTagNameMap {
'orbux-arcane-seal': OrbuxArcaneSeal;
}
}
Depends on @vikast908/core. Paste the source, add the base
element, and set state from your agent code.
Attributes & properties
| Name | Type | Description |
|---|---|---|
state | AgentState | idle · thinking · streaming · tool-calling · waiting · done · error |
size | CSS length | Overall square size. |
--orbux-width | CSS length | Optional inline-size override. |
--orbux-height | CSS length | Optional block-size override. |
speed | number | Animation speed multiplier (1 = default). |
label | string | Accessible label (defaults per state). |
paused | boolean | Freeze the animation. |
Respects prefers-reduced-motion, exposes
status/progressbar semantics with a live label, and auto-pauses (sets
data-paused) when offscreen or the tab is hidden.