Last active
March 18, 2026 12:48
-
-
Save ankitshekhawat/9b847ba95b47aa70e5e7d84e7e9ed2ac to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Agentic Motion System | HR Character</title> | |
| <style> | |
| :root { | |
| /* Semantic Roles Palette */ | |
| --canvas: #faf9f7; | |
| --iris: #6366f1; | |
| --dusk: #8b5cf6; | |
| --tide: #0ea5e9; | |
| --ember: #f97316; | |
| --sage: #22c55e; | |
| --coral: #ef4444; | |
| --slate: #64748b; | |
| /* Dynamic State Variables (Updated via JS) */ | |
| --current-core: var(--iris); | |
| --current-shell: rgba(99, 102, 241, 0.15); /* Iris with opacity */ | |
| } | |
| * { box-sizing: border-box; margin: 0; padding: 0; } | |
| body { | |
| font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; | |
| background-color: var(--canvas); | |
| color: #1f2937; | |
| display: flex; | |
| height: 100vh; | |
| overflow: hidden; | |
| } | |
| /* --- Layout --- */ | |
| .stage { | |
| flex: 1; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| position: relative; | |
| } | |
| .panel { | |
| width: 400px; | |
| background: #ffffff; | |
| box-shadow: -10px 0 30px rgba(0,0,0,0.03); | |
| display: flex; | |
| flex-direction: column; | |
| padding: 40px; | |
| z-index: 10; | |
| overflow-y: auto; | |
| } | |
| /* --- Typography & UI --- */ | |
| h1 { font-size: 1.2rem; font-weight: 700; letter-spacing: 0.05em; text-transform: uppercase; color: var(--slate); margin-bottom: 8px; } | |
| h2 { font-size: 2rem; font-weight: 600; margin-bottom: 12px; color: #111827; transition: color 0.3s ease; } | |
| p.desc { font-size: 1rem; line-height: 1.6; color: #4b5563; margin-bottom: 30px; min-height: 80px; } | |
| .controls-grid { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 10px; | |
| } | |
| button { | |
| appearance: none; border: 1px solid #e5e7eb; background: #fff; | |
| padding: 12px 16px; border-radius: 8px; font-size: 0.9rem; font-weight: 500; | |
| color: #374151; cursor: pointer; text-align: left; | |
| transition: all 0.2s ease; | |
| } | |
| button:hover { background: #f3f4f6; border-color: #d1d5db; } | |
| button.active { background: #111827; color: #fff; border-color: #111827; } | |
| /* --- The Character SVG & Motion Base --- */ | |
| .character-container { | |
| width: 240px; | |
| height: 240px; | |
| position: relative; | |
| /* Spring ease for state transitions */ | |
| transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1); | |
| } | |
| .char-svg { | |
| width: 100%; | |
| height: 100%; | |
| overflow: visible; | |
| } | |
| .outer-shell { | |
| fill: var(--current-shell); | |
| transform-origin: 50% 50%; | |
| transition: fill 0.6s ease, transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1); | |
| } | |
| .inner-core { | |
| fill: var(--current-core); | |
| transform-origin: 50% 50%; | |
| transition: fill 0.6s ease, transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1); | |
| } | |
| /* ========================================= | |
| STATE ANIMATIONS & BEHAVIORS | |
| ========================================= */ | |
| /* 1. Awaiting (Idle) */ | |
| .state-awaiting .outer-shell { animation: breathe 4s ease-in-out infinite; } | |
| .state-awaiting .inner-core { animation: float 6s ease-in-out infinite; } | |
| /* 2. Listening */ | |
| .state-listening .outer-shell { transform: scale(1.05); } | |
| .state-listening .inner-core { animation: listenPulse 0.8s ease-in-out infinite alternate; } | |
| /* 3. Thinking */ | |
| .state-thinking .outer-shell { animation: spinWobble 4s linear infinite; } | |
| .state-thinking .inner-core { animation: deepPulse 2s ease-in-out infinite; } | |
| /* 4. Searching */ | |
| .state-searching .outer-shell { transform: rotate(12deg) scale(0.95); } | |
| .state-searching .inner-core { animation: scanEye 1.2s cubic-bezier(0.65, 0, 0.35, 1) infinite; } | |
| /* 5. Running Tools */ | |
| .state-running-tools .outer-shell { transform: scale(0.95); } | |
| .state-running-tools .inner-core { animation: mechanicalSpin 1s cubic-bezier(0.8, 0, 0.2, 1) infinite; } | |
| /* 6. Responding */ | |
| .state-responding .outer-shell { animation: flowSquash 2s ease-in-out infinite; } | |
| .state-responding .inner-core { animation: typeCascade 1.2s cubic-bezier(0.2, 0.8, 0.2, 1) infinite; } | |
| /* 7. Speaking */ | |
| .state-speaking .outer-shell { animation: speakBounce 0.4s ease-in-out infinite alternate; } | |
| .state-speaking .inner-core { animation: waveForm 0.3s ease-in-out infinite alternate; } | |
| /* 8. Awaiting Confirmation */ | |
| .state-awaiting-confirmation .inner-core { animation: heartbeat 2s ease-in-out infinite; } | |
| /* 9. Needs Handoff */ | |
| .state-needs-handoff .outer-shell { transform: scale(1.05); } | |
| .state-needs-handoff .inner-core { animation: splitLink 1.5s ease-in-out infinite alternate; } | |
| /* 10. Sending */ | |
| .state-sending .outer-shell { animation: gatherMomentum 1.5s cubic-bezier(0.2, 0.8, 0.2, 1) infinite; } | |
| .state-sending .inner-core { animation: shootOut 1.5s cubic-bezier(0.5, 0, 0.2, 1) infinite; } | |
| /* 11. Success */ | |
| .state-success .character-container { animation: popUp 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) forwards; } | |
| .state-success .inner-core { transform: scale(1.3); } | |
| /* 12. Error */ | |
| .state-error .character-container { animation: headShake 0.5s ease-in-out forwards; } | |
| .state-error .outer-shell { transform: scale(0.9); } | |
| .state-error .inner-core { transform: scale(0.5); } | |
| /* 13. Done */ | |
| .state-done .character-container { transform: scale(0.8); opacity: 0.4; filter: grayscale(50%); } | |
| /* --- Keyframes --- */ | |
| @keyframes breathe { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.03); } } | |
| @keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } } | |
| @keyframes listenPulse { 0% { transform: scale(0.9); } 100% { transform: scale(1.25); } } | |
| @keyframes spinWobble { 0% { transform: rotate(0deg) scale(1); } 50% { transform: rotate(180deg) scale(1.05) skewX(3deg); } 100% { transform: rotate(360deg) scale(1); } } | |
| @keyframes deepPulse { 0%, 100% { transform: scale(0.8); opacity: 0.8;} 50% { transform: scale(1.1); opacity: 1;} } | |
| @keyframes scanEye { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-12px) scale(0.9); } 75% { transform: translateX(12px) scale(0.9); } } | |
| @keyframes mechanicalSpin { 0% { transform: rotate(0deg) scaleX(0.5); } 100% { transform: rotate(180deg) scaleX(0.5); } } | |
| @keyframes flowSquash { 0%, 100% { transform: scaleY(1) scaleX(1); } 50% { transform: scaleY(1.05) scaleX(0.95); } } | |
| @keyframes typeCascade { 0% { transform: scale(0.8); } 40% { transform: scale(1.2); } 100% { transform: scale(0.8); } } | |
| @keyframes speakBounce { 0% { transform: translateY(0); } 100% { transform: translateY(-4px) scale(1.02); } } | |
| @keyframes waveForm { 0% { transform: scaleY(0.6) scaleX(1.1); } 100% { transform: scaleY(1.4) scaleX(0.9); } } | |
| @keyframes heartbeat { 0%, 100% { transform: scale(1); } 15% { transform: scale(1.25); } 30% { transform: scale(1); } 45% { transform: scale(1.25); } } | |
| @keyframes splitLink { 0% { transform: scaleX(1); } 100% { transform: scaleX(1.5) scaleY(0.7); opacity: 0.7;} } | |
| @keyframes gatherMomentum { 0%, 100% { transform: scale(1) translateY(0); } 30% { transform: scaleY(0.8) scaleX(1.1) translateY(10px); } 60% { transform: scaleY(1.1) scaleX(0.9) translateY(-5px); } } | |
| @keyframes shootOut { 0% { transform: translate(0,0) scale(1); opacity: 1; } 40% { transform: translate(40px, -40px) scale(0.2); opacity: 0; } 45% { transform: translate(-30px, 30px) scale(0); opacity: 0; } 100% { transform: translate(0,0) scale(1); opacity: 1; } } | |
| @keyframes popUp { 0% { transform: translateY(0) scale(1); } 40% { transform: translateY(-20px) scale(1.05); } 100% { transform: translateY(0) scale(1); } } | |
| @keyframes headShake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-10px) rotate(-3deg); } 75% { transform: translateX(10px) rotate(3deg); } } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="stage"> | |
| <div id="agent-wrapper" class="character-container state-awaiting"> | |
| <svg class="char-svg" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"> | |
| <path class="outer-shell" | |
| d="M50,15 C22,15 12,28 12,50 C12,75 25,88 50,88 C65,88 75,85 85,93 C83,78 88,68 88,50 C88,25 75,15 50,15 Z" /> | |
| <circle class="inner-core" cx="50" cy="50" r="16" /> | |
| </svg> | |
| </div> | |
| </div> | |
| <div class="panel"> | |
| <h1>Motion System</h1> | |
| <h2 id="state-title">Awaiting</h2> | |
| <p class="desc" id="state-desc">The character breathes slowly. The core floats gently. Signals a calm, attentive readiness to assist.</p> | |
| <div class="controls-grid" id="controls"> | |
| </div> | |
| </div> | |
| <script> | |
| const states = [ | |
| { id: 'awaiting', name: 'Awaiting / Idle', core: 'var(--iris)', shell: 'rgba(99, 102, 241, 0.15)', desc: 'The character breathes slowly. The core floats gently. Signals a calm, attentive readiness to assist.' }, | |
| { id: 'listening', name: 'Listening', core: 'var(--tide)', shell: 'rgba(14, 165, 233, 0.15)', desc: 'Outer shell leans in slightly. The inner core acts as a rapid, soft input meter, showing active receptiveness to voice or text.' }, | |
| { id: 'thinking', name: 'Thinking', core: 'var(--dusk)', shell: 'rgba(139, 92, 246, 0.15)', desc: 'Organic "lava-lamp" rotation on the shell. The core shrinks and pulses deeply. Signals uninterrupted cognitive processing.' }, | |
| { id: 'searching', name: 'Searching', core: 'var(--iris)', shell: 'rgba(99, 102, 241, 0.15)', desc: 'Shell tilts forward. Core sweeps left and right rapidly, mimicking the saccadic eye movements of reading or scanning databases.' }, | |
| { id: 'running-tools', name: 'Running Tools', core: 'var(--tide)', shell: 'rgba(14, 165, 233, 0.15)', desc: 'Shell stops breathing, focusing inward. Core flattens and rotates sharply, resembling a mechanical gear executing a backend task.' }, | |
| { id: 'responding', name: 'Responding', core: 'var(--dusk)', shell: 'rgba(139, 92, 246, 0.15)', desc: 'Shell squashes vertically. Core cascades outward with asymmetrical easing, mimicking the natural rhythm of generating text.' }, | |
| { id: 'speaking', name: 'Speaking', core: 'var(--ember)', shell: 'rgba(249, 115, 22, 0.15)', desc: 'Warm color shift. Core alters Y-axis scale rapidly like a voice waveform, while the shell gently bounces to the speech cadence.' }, | |
| { id: 'awaiting-confirmation', name: 'Awaiting Confirm', core: 'var(--ember)', shell: 'rgba(249, 115, 22, 0.15)', desc: 'System pauses. The core executes a distinct, rhythmic "heartbeat" double-pulse to signal that user intervention is required.' }, | |
| { id: 'needs-handoff', name: 'Needs Handoff', core: 'var(--slate)', shell: 'rgba(100, 116, 139, 0.15)', desc: 'Shifts to neutral corporate colors. Core stretches horizontally, visually simulating a structural link or bridge to a human agent.' }, | |
| { id: 'sending', name: 'Sending', core: 'var(--iris)', shell: 'rgba(99, 102, 241, 0.15)', desc: 'Shell gathers momentum (squash), then the core shoots upward and diagonally off-screen, symbolizing dispatching a payload.' }, | |
| { id: 'success', name: 'Success', core: 'var(--sage)', shell: 'rgba(34, 197, 94, 0.15)', desc: 'A crisp, spring-physics upward bounce. Green colorway and an expanded core signal positive completion and delight.' }, | |
| { id: 'error', name: 'Error', core: 'var(--coral)', shell: 'rgba(239, 68, 68, 0.15)', desc: 'A gentle, apologetic lateral head-shake. The core shrinks defensively. Signals a halt or misunderstanding without aggressive red.' }, | |
| { id: 'done', name: 'Done', core: 'var(--slate)', shell: 'rgba(100, 116, 139, 0.10)', desc: 'Session complete. Character scales down, loses opacity, and stops all looping animations, returning to a dormant resting state.' } | |
| ]; | |
| const wrapper = document.getElementById('agent-wrapper'); | |
| const titleEl = document.getElementById('state-title'); | |
| const descEl = document.getElementById('state-desc'); | |
| const controls = document.getElementById('controls'); | |
| states.forEach((state, index) => { | |
| const btn = document.createElement('button'); | |
| btn.innerText = state.name; | |
| if (index === 0) btn.classList.add('active'); | |
| btn.onclick = () => { | |
| // Update Active Button | |
| document.querySelectorAll('button').forEach(b => b.classList.remove('active')); | |
| btn.classList.add('active'); | |
| // Clean previous state classes | |
| wrapper.className = 'character-container'; | |
| // Trigger reflow to restart CSS animations | |
| void wrapper.offsetWidth; | |
| // Apply new state | |
| wrapper.classList.add(`state-${state.id}`); | |
| // Update Colors via CSS Variables | |
| document.documentElement.style.setProperty('--current-core', state.core); | |
| document.documentElement.style.setProperty('--current-shell', state.shell); | |
| // Update Text | |
| titleEl.innerText = state.name; | |
| titleEl.style.color = state.core === 'var(--canvas)' ? '#111827' : state.core; | |
| descEl.innerText = state.desc; | |
| }; | |
| controls.appendChild(btn); | |
| }); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment