Skip to content

Instantly share code, notes, and snippets.

@smontlouis
Created August 12, 2026 09:54
Show Gist options
  • Select an option

  • Save smontlouis/49a4c9303de70118a90dc43badc1aba5 to your computer and use it in GitHub Desktop.

Select an option

Save smontlouis/49a4c9303de70118a90dc43badc1aba5 to your computer and use it in GitHub Desktop.
please don't sue me
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="color-scheme" content="light dark" />
<link
rel="icon"
href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 64 64%22><circle cx=%2232%22 cy=%2232%22 r=%2230%22 fill=%22%235b7fe5%22/><circle cx=%2224%22 cy=%2228%22 r=%225%22/><circle cx=%2240%22 cy=%2228%22 r=%225%22/></svg>"
/>
<title>Atelier GrokBot — prototype</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Azeret+Mono:wght@400;500&family=Fraunces:opsz,wght@9..144,500&display=swap');
:root {
--page: #f1efe8;
--background: #fffdf7;
--foreground: #171813;
--card: #fffdf7;
--card-foreground: #171813;
--muted: #ebe8de;
--muted-foreground: #6e7067;
--secondary: #f0eee7;
--secondary-foreground: #24251f;
--border: #d5d1c5;
--input: #c8c3b6;
--primary: #2f66e8;
--primary-foreground: #ffffff;
--viz-series-1: #5b7fe5;
--orange: #e36f3d;
}
@media (prefers-color-scheme: dark) {
:root {
--page: #11130f;
--background: #181a15;
--foreground: #f3f0e7;
--card: #1c1f19;
--card-foreground: #f3f0e7;
--muted: #292c25;
--muted-foreground: #a5a89d;
--secondary: #252821;
--secondary-foreground: #f3f0e7;
--border: #393d33;
--input: #4a4f42;
--primary: #6f96ff;
--primary-foreground: #0c1630;
--viz-series-1: #6689ea;
--orange: #ff8b5e;
}
}
html {
background: var(--page);
color-scheme: light dark;
scroll-behavior: smooth;
}
body {
background: var(--page);
margin: 0;
min-width: 320px;
padding: 24px 24px 96px;
}
.prototype-frame {
margin: 0 auto;
max-width: 1380px;
}
@media (max-width: 760px) {
body {
padding: 14px 12px 82px;
}
}
</style>
</head>
<body data-variant="split">
<div class="prototype-frame">
<div id="grokbot-complete" data-prototype="throwaway">
<style>
#grokbot-complete {
color: var(--foreground);
display: grid;
gap: 18px;
font-family: ui-sans-serif, system-ui, sans-serif;
}
#grokbot-complete * {
box-sizing: border-box;
}
#grokbot-complete .page-header {
align-items: end;
border-bottom: 1px solid var(--border);
display: flex;
justify-content: space-between;
gap: 28px;
padding-bottom: 18px;
}
#grokbot-complete .page-header h1 {
font-family: 'Fraunces', Georgia, serif;
font-size: clamp(2.4rem, 6vw, 5.4rem);
font-weight: 500;
letter-spacing: -0.055em;
line-height: 0.9;
margin: 8px 0 0;
}
#grokbot-complete .page-header p {
color: var(--muted-foreground);
max-width: 390px;
text-align: right;
}
#grokbot-complete .kicker {
color: var(--primary);
font-family: 'Azeret Mono', monospace;
font-size: 0.72rem;
letter-spacing: 0.08em;
}
#grokbot-complete .shell {
align-items: start;
display: grid;
grid-template-columns: minmax(300px, 0.78fr) minmax(500px, 1.35fr);
gap: 20px;
}
#grokbot-complete .preview-rail {
min-width: 0;
position: sticky;
top: 18px;
z-index: 5;
}
#grokbot-complete .content-rail {
min-width: 0;
}
#grokbot-complete .lab {
display: block;
}
#grokbot-complete .controls {
margin-top: 14px;
}
#grokbot-complete .layout-switcher {
align-items: center;
background: var(--foreground);
border: 1px solid color-mix(in srgb, var(--background) 18%, transparent);
border-radius: 999px;
bottom: 16px;
box-shadow: 0 14px 38px color-mix(in srgb, var(--foreground) 20%, transparent);
display: flex;
gap: 4px;
left: 50%;
padding: 5px;
position: fixed;
transform: translateX(-50%);
z-index: 20;
}
#grokbot-complete .layout-switcher button {
background: transparent;
border: 0;
border-radius: 999px;
color: var(--background);
font-family: 'Azeret Mono', monospace;
padding: 8px 12px;
white-space: nowrap;
}
#grokbot-complete .layout-switcher button[aria-pressed='true'] {
background: var(--primary);
color: var(--primary-foreground);
}
body[data-variant='dock'] #grokbot-complete .shell {
display: block;
}
body[data-variant='dock'] #grokbot-complete .preview-rail {
background: var(--page);
padding: 10px 0;
top: 0;
}
body[data-variant='dock'] #grokbot-complete .preview {
align-items: center;
grid-template-columns: 180px 1fr;
}
body[data-variant='dock'] #grokbot-complete .preview svg {
grid-column: 1;
grid-row: 1 / span 4;
max-height: 160px;
}
body[data-variant='dock'] #grokbot-complete .content-rail {
margin-top: 18px;
}
body[data-variant='focus'] #grokbot-complete .shell {
grid-template-columns: minmax(430px, 1.2fr) minmax(420px, 0.9fr);
}
body[data-variant='focus'] #grokbot-complete .preview svg {
max-height: 620px;
}
#grokbot-complete h2,
#grokbot-complete h3 {
margin: 0;
}
#grokbot-complete p {
margin: 0;
}
#grokbot-complete .intro {
color: var(--muted-foreground);
max-width: 78ch;
}
#grokbot-complete .tabs {
border-bottom: 1px solid var(--border);
display: flex;
flex-wrap: wrap;
gap: 4px;
}
#grokbot-complete .tab {
background: transparent;
border: 0;
border-bottom: 2px solid transparent;
color: var(--muted-foreground);
padding: 9px 12px;
}
#grokbot-complete .tab[aria-selected='true'] {
border-bottom-color: var(--primary);
color: var(--foreground);
font-weight: 500;
}
#grokbot-complete .tab-panel[hidden] {
display: none;
}
#grokbot-complete .lab {
display: grid;
grid-template-columns: minmax(280px, 0.9fr) minmax(380px, 1.25fr);
gap: 14px;
align-items: start;
}
#grokbot-complete .preview,
#grokbot-complete .panel,
#grokbot-complete .catalog-card {
background: var(--card);
border: 1px solid var(--border);
border-radius: 16px;
color: var(--card-foreground);
}
#grokbot-complete .preview {
display: grid;
gap: 12px;
padding: 14px;
position: sticky;
top: 8px;
}
#grokbot-complete .preview-head,
#grokbot-complete .control-head,
#grokbot-complete .status-line {
align-items: center;
display: flex;
justify-content: space-between;
gap: 10px;
}
#grokbot-complete .preview svg {
height: auto;
width: 100%;
}
#grokbot-complete .body {
fill: var(--viz-series-1);
}
#grokbot-complete .eye {
fill: var(--background);
}
#grokbot-complete .guide {
fill: none;
stroke: var(--muted-foreground);
stroke-dasharray: 4 5;
stroke-width: 1;
}
#grokbot-complete .centroid {
fill: var(--orange);
stroke: var(--card);
stroke-width: 2;
}
#grokbot-complete .status-line {
color: var(--muted-foreground);
flex-wrap: wrap;
}
#grokbot-complete .status-line strong {
color: var(--foreground);
font-weight: 500;
}
#grokbot-complete .controls {
display: grid;
gap: 12px;
}
#grokbot-complete .panel {
display: grid;
gap: 13px;
padding: 15px;
}
#grokbot-complete .control {
display: grid;
gap: 6px;
}
#grokbot-complete .control-head output {
color: var(--primary);
font-variant-numeric: tabular-nums;
}
#grokbot-complete select,
#grokbot-complete input[type='range'] {
width: 100%;
}
#grokbot-complete select {
background: var(--background);
border: 1px solid var(--input);
border-radius: 9px;
color: var(--foreground);
padding: 8px;
}
#grokbot-complete .switch-line {
align-items: center;
display: flex;
justify-content: space-between;
gap: 12px;
}
#grokbot-complete .button-row {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
#grokbot-complete .action,
#grokbot-complete .expression-button,
#grokbot-complete .pool-button {
background: var(--secondary);
border: 1px solid var(--border);
border-radius: 10px;
color: var(--secondary-foreground);
padding: 8px 10px;
}
#grokbot-complete .action.primary,
#grokbot-complete .expression-button[aria-pressed='true'],
#grokbot-complete .pool-button[aria-pressed='true'] {
background: var(--primary);
border-color: var(--primary);
color: var(--primary-foreground);
}
#grokbot-complete .expression-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 7px;
}
#grokbot-complete .expression-button {
min-height: 40px;
}
#grokbot-complete .explanation {
border-left: 3px solid var(--primary);
color: var(--muted-foreground);
padding: 5px 0 5px 11px;
}
#grokbot-complete .explanation strong {
color: var(--foreground);
font-weight: 500;
}
#grokbot-complete .formula-grid,
#grokbot-complete .api-grid,
#grokbot-complete .shape-grid {
display: grid;
gap: 10px;
grid-template-columns: repeat(2, minmax(0, 1fr));
}
#grokbot-complete .formula,
#grokbot-complete .api-item {
background: var(--muted);
border-radius: 11px;
color: var(--muted-foreground);
padding: 11px;
}
#grokbot-complete .formula code,
#grokbot-complete .api-item code {
color: var(--foreground);
display: block;
margin-bottom: 5px;
overflow-wrap: anywhere;
}
#grokbot-complete .pipeline {
display: grid;
gap: 8px;
grid-template-columns: repeat(5, 1fr);
}
#grokbot-complete .pipe-step {
background: var(--card);
border: 1px solid var(--border);
border-radius: 12px;
color: var(--card-foreground);
padding: 11px;
position: relative;
}
#grokbot-complete .pipe-step:not(:last-child)::after {
color: var(--muted-foreground);
content: '→';
position: absolute;
right: -9px;
top: 50%;
transform: translateY(-50%);
z-index: 2;
}
#grokbot-complete .pipe-step span {
color: var(--primary);
display: block;
margin-bottom: 4px;
}
#grokbot-complete .catalog-card {
display: grid;
gap: 8px;
padding: 12px;
}
#grokbot-complete .catalog-card.selected {
border-color: var(--primary);
box-shadow: inset 0 0 0 1px var(--primary);
}
#grokbot-complete .shape-icon {
align-items: center;
display: flex;
justify-content: center;
min-height: 74px;
}
#grokbot-complete .shape-icon i {
background: var(--viz-series-1);
display: block;
height: 58px;
width: 58px;
}
#grokbot-complete .metrics {
color: var(--muted-foreground);
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 3px 8px;
}
#grokbot-complete .state-layout {
display: grid;
gap: 14px;
grid-template-columns: minmax(230px, 0.7fr) minmax(360px, 1.3fr);
}
#grokbot-complete .state-groups {
display: grid;
gap: 10px;
}
#grokbot-complete .state-group {
border-bottom: 1px solid var(--border);
padding-bottom: 10px;
}
#grokbot-complete .state-group:last-child {
border-bottom: 0;
}
#grokbot-complete .state-buttons {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 7px;
}
#grokbot-complete .state-button {
background: transparent;
border: 1px solid var(--border);
border-radius: 999px;
color: var(--muted-foreground);
padding: 6px 9px;
}
#grokbot-complete .state-button[aria-pressed='true'] {
border-color: var(--primary);
color: var(--primary);
}
#grokbot-complete .state-detail {
display: grid;
gap: 13px;
}
#grokbot-complete .pool {
display: flex;
flex-wrap: wrap;
gap: 7px;
}
#grokbot-complete .cadence {
display: grid;
gap: 8px;
grid-template-columns: repeat(2, 1fr);
}
#grokbot-complete .cadence div {
background: var(--muted);
border-radius: 10px;
padding: 10px;
}
#grokbot-complete .cadence span {
color: var(--muted-foreground);
display: block;
margin-bottom: 3px;
}
#grokbot-complete .note {
color: var(--muted-foreground);
}
@media (max-width: 760px) {
#grokbot-complete .page-header {
align-items: start;
display: grid;
}
#grokbot-complete .page-header p {
text-align: left;
}
#grokbot-complete .shell,
body[data-variant='focus'] #grokbot-complete .shell {
display: block;
}
#grokbot-complete .preview-rail {
background: var(--page);
padding: 8px 0;
position: sticky;
top: 0;
}
#grokbot-complete .preview {
grid-template-columns: 126px 1fr;
padding: 9px;
}
#grokbot-complete .preview svg {
grid-column: 1;
grid-row: 1 / span 4;
max-height: 118px;
}
#grokbot-complete .preview .button-row {
display: none;
}
#grokbot-complete .preview .status-line {
font-size: 0.74rem;
}
#grokbot-complete .content-rail {
margin-top: 12px;
}
#grokbot-complete .layout-switcher {
bottom: 8px;
}
#grokbot-complete .layout-switcher button {
padding: 7px 9px;
}
#grokbot-complete .lab,
#grokbot-complete .state-layout {
grid-template-columns: 1fr;
}
#grokbot-complete .preview {
position: static;
}
#grokbot-complete .pipeline {
grid-template-columns: 1fr;
}
#grokbot-complete .pipe-step:not(:last-child)::after {
bottom: -13px;
content: '↓';
left: 50%;
right: auto;
top: auto;
}
#grokbot-complete .formula-grid,
#grokbot-complete .api-grid,
#grokbot-complete .shape-grid {
grid-template-columns: 1fr;
}
}
</style>
<header class="page-header">
<div>
<span class="kicker">PROTOTYPE TECHNIQUE · REVERSE ENGINEERING</span>
<h1>Atelier GrokBot</h1>
</div>
<p>
Un laboratoire autonome pour comprendre, tester et faire évoluer le moteur de visage.
</p>
</header>
<p class="intro">
Le visage combine trois systèmes indépendants : des contours SVG dessinés à l’avance, un
petit déplacement du regard, puis une projection sphérique utilisée pendant les rotations.
Les états choisissent et enchaînent ces briques.
</p>
<div class="shell">
<div class="preview-rail">
<aside class="preview">
<div class="preview-head">
<strong>Aperçu final</strong><span id="preview-mode">expression 00</span>
</div>
<svg
viewBox="-15 -15 259 259"
role="img"
aria-labelledby="complete-avatar-title complete-avatar-desc"
>
<title id="complete-avatar-title">Avatar interactif</title>
<desc id="complete-avatar-desc">
Le visage affiche l’expression, le regard et la rotation choisis dans les
contrôles.
</desc>
<defs>
<clipPath id="complete-head-clip">
<path
d="M228.541 114.228C228.541 130.133 225.184 145.994 218.738 160.534C212.674 174.217 203.904 186.669 193.065 196.988C155.933 232.34 99.497 238.596 55.5255 212.24C45.097 205.99 35.6851 198.072 27.7451 188.866C19.1926 178.953 12.3686 167.569 7.65781 155.351C2.60712 142.264 0 128.257 0 114.228C0 98.3219 3.35751 82.4611 9.80315 67.9215C15.8672 54.2382 24.6377 41.7862 35.4767 31.4668C72.6081 -3.88483 129.044 -10.1413 173.016 16.2153C183.444 22.4653 192.856 30.3829 200.796 39.5896C209.349 49.5018 216.173 60.8859 220.883 73.1037C225.934 86.1906 228.541 100.198 228.541 114.228Z"
/>
</clipPath>
</defs>
<path
class="body"
id="body-path"
d="M228.541 114.228C228.541 130.133 225.184 145.994 218.738 160.534C212.674 174.217 203.904 186.669 193.065 196.988C155.933 232.34 99.497 238.596 55.5255 212.24C45.097 205.99 35.6851 198.072 27.7451 188.866C19.1926 178.953 12.3686 167.569 7.65781 155.351C2.60712 142.264 0 128.257 0 114.228C0 98.3219 3.35751 82.4611 9.80315 67.9215C15.8672 54.2382 24.6377 41.7862 35.4767 31.4668C72.6081 -3.88483 129.044 -10.1413 173.016 16.2153C183.444 22.4653 192.856 30.3829 200.796 39.5896C209.349 49.5018 216.173 60.8859 220.883 73.1037C225.934 86.1906 228.541 100.198 228.541 114.228Z"
/>
<ellipse
class="guide"
id="sphere-guide"
cx="114.27"
cy="114.27"
rx="105"
ry="35"
opacity="0"
/>
<g clip-path="url(#complete-head-clip)" id="eyes-group">
<path class="eye" id="complete-eye-0" />
<path class="eye" id="complete-eye-1" />
</g>
<g id="centroids" opacity="0">
<circle class="centroid" id="complete-center-0" r="3.5" />
<circle class="centroid" id="complete-center-1" r="3.5" />
</g>
</svg>
<div class="status-line">
<span>État <strong id="status-state">idle</strong></span>
<span>Forme <strong id="status-shape">blob</strong></span>
<span>Expression <strong id="status-expression">00</strong></span>
</div>
<div class="button-row">
<button class="action primary" id="blink-now" type="button">Cligner</button>
<button class="action" id="spin-demo" type="button">Démontrer un tour</button>
<button class="action" id="reset-all" type="button">Réinitialiser</button>
</div>
</aside>
</div>
<main class="content-rail">
<div class="tabs" role="tablist" aria-label="Sections">
<button class="tab" type="button" role="tab" aria-selected="true" data-tab="lab">
Laboratoire
</button>
<button class="tab" type="button" role="tab" aria-selected="false" data-tab="states">
États
</button>
<button class="tab" type="button" role="tab" aria-selected="false" data-tab="shapes">
Formes
</button>
<button class="tab" type="button" role="tab" aria-selected="false" data-tab="engine">
Calculs & API
</button>
</div>
<section class="tab-panel" id="tab-lab" role="tabpanel">
<div class="lab">
<div class="controls">
<section class="panel">
<h3>1. Expression SVG</h3>
<p class="note">
Chaque bouton charge deux chemins de 48 points. Les grandes différences de
position et de taille sont déjà contenues dans ces chemins.
</p>
<div class="expression-grid" id="expression-grid"></div>
<label class="control">
<span class="control-head"
><span>Vitesse du ressort</span
><output id="spring-output">7.0</output></span
>
<input id="spring" type="range" min="4" max="12" value="7" step=".5" />
</label>
</section>
<section class="panel">
<h3>2. Regard indépendant</h3>
<label class="control">
<span class="control-head"
><span>Horizontal normalisé</span
><output id="gaze-x-output">0.00 → 0.0 unités</output></span
>
<input id="gaze-x" type="range" min="-1" max="1" value="0" step=".01" />
</label>
<label class="control">
<span class="control-head"
><span>Vertical normalisé</span
><output id="gaze-y-output">0.00 → 0.0 unités</output></span
>
<input id="gaze-y" type="range" min="-1" max="1" value="0" step=".01" />
</label>
<div class="explanation">
<strong>Limites exactes :</strong> le pointeur est borné à ±0,6, puis
multiplié par 22 horizontalement et 14 verticalement, soit environ ±13,2 ×
±8,4 unités.
</div>
</section>
<section class="panel">
<h3>3. Rotation et profondeur</h3>
<label class="control">
<span class="control-head"
><span>Angle de rotation</span><output id="turn-output"></output></span
>
<input id="turn" type="range" min="-100" max="100" value="0" step="1" />
</label>
<label class="control">
<span class="control-head"
><span>Taille globale des yeux</span
><output id="eye-scale-output">1.00×</output></span
>
<input id="eye-scale" type="range" min=".2" max="2" value="1" step=".02" />
</label>
<div class="switch-line">
<label for="show-guides">Afficher centroïdes et orbite</label
><input id="show-guides" type="checkbox" />
</div>
<div class="switch-line">
<label for="flip-x">Miroir horizontal <code>flipX</code></label
><input id="flip-x" type="checkbox" />
</div>
<div class="switch-line">
<label for="emphasis">Accentuation <code>emphasis</code></label
><input id="emphasis" type="checkbox" />
</div>
<div class="explanation">
<strong>Effet périphérique :</strong> un œil proche du bord voit sa largeur
multipliée par un rapport de cosinus. Lorsqu’il passe derrière la tête, il
devient invisible.
</div>
</section>
<section class="panel">
<h3>4. Clignement et cadence</h3>
<div class="switch-line">
<label for="auto-blink">Clignement automatique selon l’état</label
><input id="auto-blink" type="checkbox" checked />
</div>
<div class="switch-line">
<label for="auto-expression">Expressions automatiques selon l’état</label
><input id="auto-expression" type="checkbox" />
</div>
<p class="note">
Un clignement dure 320 ms : fermeture pendant 42 % du temps, réouverture
pendant 58 %, avec une hauteur minimale de 4 %.
</p>
</section>
</div>
</div>
</section>
<section class="tab-panel" id="tab-states" role="tabpanel" hidden>
<div class="state-layout">
<div class="state-groups" id="state-groups"></div>
<div class="state-detail">
<section class="panel">
<div class="preview-head">
<h3 id="state-title">idle</h3>
<button class="action primary" id="apply-state" type="button">
Appliquer au labo
</button>
</div>
<p class="note" id="state-kind"></p>
<div>
<strong>Pool d’expressions</strong>
<div class="pool" id="state-pool"></div>
</div>
<div class="cadence">
<div>
<span>Changement d’expression</span
><strong id="expression-cadence"></strong>
</div>
<div><span>Clignement</span><strong id="blink-cadence"></strong></div>
</div>
<div class="explanation" id="state-explanation"></div>
</section>
<section class="panel">
<h3>Comment un état devient une animation</h3>
<div class="pipeline">
<div class="pipe-step"><span>État</span><strong>idle</strong></div>
<div class="pipe-step"><span>Pool</span><strong>[0, 8]</strong></div>
<div class="pipe-step"><span>Cadence</span><strong>9–16 s</strong></div>
<div class="pipe-step"><span>Ressorts</span><strong>x, y, scale</strong></div>
<div class="pipe-step"><span>SVG</span><strong>nouveau frame</strong></div>
</div>
</section>
</div>
</div>
</section>
<section class="tab-panel" id="tab-shapes" role="tabpanel" hidden>
<section class="panel">
<h3>Les 18 silhouettes et leur correction du visage</h3>
<p class="note">
Chaque forme fournit un anneau de 96 points, une fonction donnant les limites
gauche/droite à une hauteur donnée, et cinq paramètres qui repositionnent le
visage.
</p>
<div class="shape-grid" id="shape-grid"></div>
</section>
</section>
<section class="tab-panel" id="tab-engine" role="tabpanel" hidden>
<section class="panel">
<h3>Pipeline exact d’un frame</h3>
<div class="pipeline">
<div class="pipe-step">
<span>01</span><strong>État + timers</strong>
<p class="note">expression, blink, morph</p>
</div>
<div class="pipe-step">
<span>02</span><strong>Ressorts</strong>
<p class="note">pas fixes à 120 Hz</p>
</div>
<div class="pipe-step">
<span>03</span><strong>Anneaux</strong>
<p class="note">interpolation des 48 points</p>
</div>
<div class="pipe-step">
<span>04</span><strong>Projection</strong>
<p class="note">position, profondeur, limites</p>
</div>
<div class="pipe-step">
<span>05</span><strong>SVG</strong>
<p class="note">d + transform à chaque frame</p>
</div>
</div>
</section>
<section class="panel">
<h3>Formules principales</h3>
<div class="formula-grid">
<div class="formula">
<code>gazeX = 22 × clamp(pointerX / width, −0.6, 0.6)</code>Le regard
utilisateur n’atteint que ±13,2 unités.
</div>
<div class="formula">
<code>longitude₀ = asin(offsetX / radius)</code>Le centroïde de l’œil est
converti en longitude sur la tête.
</div>
<div class="formula">
<code>longitude = longitude₀ + turn</code>La rotation de tête est ajoutée en
radians.
</div>
<div class="formula">
<code>x = center + radius × sin(longitude)</code>La position horizontale suit la
surface sphérique.
</div>
<div class="formula">
<code>scaleX = cos(longitude) / cos(longitude₀)</code>La largeur se comprime
avec la profondeur.
</div>
<div class="formula">
<code>eyeScale ≤ (distance − 5) / (halfWidth₁ + halfWidth₂)</code>La taille est
plafonnée pour empêcher le chevauchement.
</div>
<div class="formula">
<code>blink(t) = close 42 % → open 58 %</code>La fermeture est plus rapide que
la réouverture.
</div>
<div class="formula">
<code>spring: v += (−2ζωv − ω²(x−target))dt</code>Les mouvements sont amortis
plutôt qu’interpolés linéairement.
</div>
</div>
</section>
<section class="panel">
<h3>API publique observée</h3>
<div class="api-grid">
<div class="api-item">
<code>state="idle"</code>Choisit les pools, cadences et mouvements secondaires.
</div>
<div class="api-item">
<code>shape="blob"</code>Choisit la silhouette et la correction géométrique du
visage.
</div>
<div class="api-item"><code>size</code>Fixe la taille rendue du SVG.</div>
<div class="api-item">
<code>gazeTarget={x, y}</code>Injecte une cible de regard en coordonnées écran.
</div>
<div class="api-item">
<code>mouseInteractive</code>Écoute le pointeur global lorsque le composant est
visible.
</div>
<div class="api-item">
<code>flipX</code>Retourne tout le SVG horizontalement.
</div>
<div class="api-item">
<code>emphasis</code>Force une taille d’yeux et un corps légèrement plus grands.
</div>
<div class="api-item">
<code>spinSignal</code>Déclenche une rotation via une valeur incrémentée.
</div>
<div class="api-item">
<code>badgeColor</code>Couleur du badge utilisé par certains états.
</div>
<div class="api-item"><code>badgeScale</code>Échelle du badge d’état.</div>
<div class="api-item">
<code>ref.spin(turns)</code>Commande impérative de rotation.
</div>
<div class="api-item">
<code>ref.bounce() / ref.burst()</code>Commandes impératives de rebond et
particules.
</div>
</div>
</section>
</section>
</main>
</div>
<div class="layout-switcher" aria-label="Disposition du prototype">
<button type="button" data-layout="split">A · Split</button
><button type="button" data-layout="dock">B · Dock</button
><button type="button" data-layout="focus">C · Focus</button>
</div>
<script>
;(() => {
const root = document.getElementById('grokbot-complete')
const $ = id => root.querySelector('#' + id)
const EXPRESSIONS = [
[
[
[130.36, 45.98],
[132.71, 46.19],
[134.98, 46.81],
[137.11, 47.83],
[138.97, 49.28],
[140.47, 51.09],
[141.68, 53.12],
[142.73, 55.23],
[143.76, 57.36],
[144.78, 59.49],
[145.79, 61.62],
[146.79, 63.76],
[147.76, 65.91],
[148.71, 68.07],
[149.63, 70.25],
[150.52, 72.43],
[151.37, 74.63],
[151.99, 76.91],
[152.1, 79.26],
[151.64, 81.57],
[150.59, 83.68],
[149.04, 85.45],
[147.1, 86.78],
[144.9, 87.62],
[142.56, 87.93],
[140.22, 87.71],
[137.98, 86.99],
[135.93, 85.82],
[134.17, 84.24],
[132.78, 82.34],
[131.69, 80.25],
[130.77, 78.08],
[129.87, 75.89],
[128.94, 73.72],
[128, 71.56],
[127.03, 69.4],
[126.05, 67.26],
[125.05, 65.12],
[124.03, 62.99],
[122.93, 60.9],
[121.87, 58.79],
[121.03, 56.59],
[120.72, 54.26],
[121.1, 51.93],
[122.15, 49.83],
[123.75, 48.1],
[125.76, 46.89],
[128.01, 46.19],
],
[
[176.61, 37.08],
[178.72, 37.59],
[180.7, 38.48],
[182.52, 39.65],
[184.2, 41.03],
[185.71, 42.59],
[187.03, 44.31],
[188.2, 46.14],
[189.26, 48.03],
[190.27, 49.96],
[191.26, 51.89],
[192.23, 53.84],
[193.16, 55.8],
[194.05, 57.78],
[194.92, 59.77],
[195.74, 61.78],
[196.53, 63.8],
[197.27, 65.84],
[197.97, 67.9],
[198.47, 70.01],
[198.63, 72.18],
[198.4, 74.33],
[197.58, 76.33],
[195.95, 77.72],
[193.83, 78.08],
[191.71, 77.65],
[189.76, 76.69],
[188.03, 75.38],
[186.53, 73.82],
[185.28, 72.05],
[184.25, 70.13],
[183.4, 68.14],
[182.63, 66.11],
[181.87, 64.07],
[181.07, 62.05],
[180.25, 60.04],
[179.39, 58.05],
[178.49, 56.07],
[177.57, 54.1],
[176.61, 52.15],
[175.62, 50.22],
[174.59, 48.31],
[173.53, 46.41],
[172.54, 44.48],
[171.86, 42.42],
[171.76, 40.26],
[172.62, 38.3],
[174.45, 37.19],
],
],
[
[
[86.14, 124.79],
[89.16, 124.92],
[92.06, 125.76],
[94.68, 127.27],
[96.86, 129.36],
[98.48, 131.92],
[99.51, 134.76],
[100.12, 137.73],
[100.56, 140.72],
[101.01, 143.72],
[101.52, 146.71],
[102.06, 149.69],
[102.62, 152.67],
[103.2, 155.64],
[103.81, 158.61],
[104.44, 161.57],
[105.11, 164.52],
[105.81, 167.47],
[106.49, 170.42],
[106.72, 173.44],
[106.01, 176.37],
[104.37, 178.9],
[102.03, 180.81],
[99.26, 181.99],
[96.27, 182.46],
[93.25, 182.25],
[90.34, 181.43],
[87.65, 180.04],
[85.32, 178.11],
[83.51, 175.7],
[82.37, 172.9],
[81.66, 169.96],
[80.98, 167],
[80.32, 164.05],
[79.69, 161.08],
[79.08, 158.12],
[78.5, 155.14],
[77.94, 152.16],
[77.4, 149.18],
[76.89, 146.2],
[76.4, 143.21],
[75.93, 140.21],
[75.56, 137.21],
[75.7, 134.19],
[76.6, 131.3],
[78.22, 128.76],
[80.47, 126.74],
[83.18, 125.4],
],
[
[147.23, 112.87],
[150.24, 113.13],
[153.07, 114.19],
[155.53, 115.94],
[157.46, 118.26],
[158.73, 121.01],
[159.53, 123.93],
[160.21, 126.88],
[160.88, 129.84],
[161.52, 132.8],
[162.15, 135.76],
[162.74, 138.73],
[163.32, 141.71],
[163.87, 144.69],
[164.39, 147.67],
[164.9, 150.66],
[165.39, 153.65],
[165.8, 156.65],
[165.76, 159.67],
[164.98, 162.59],
[163.56, 165.26],
[161.61, 167.58],
[159.23, 169.45],
[156.52, 170.77],
[153.57, 171.46],
[150.55, 171.4],
[147.67, 170.52],
[145.19, 168.79],
[143.45, 166.33],
[142.57, 163.44],
[142.08, 160.45],
[141.61, 157.46],
[141.11, 154.47],
[140.59, 151.48],
[140.04, 148.5],
[139.47, 145.53],
[138.87, 142.56],
[138.25, 139.59],
[137.6, 136.63],
[136.94, 133.68],
[136.25, 130.72],
[135.59, 127.77],
[135.47, 124.75],
[136.07, 121.78],
[137.34, 119.04],
[139.19, 116.65],
[141.53, 114.74],
[144.26, 113.44],
],
],
[
[
[104.84, 104.08],
[109.39, 104.89],
[113.63, 106.73],
[117.32, 109.5],
[120.25, 113.08],
[122.22, 117.25],
[123.15, 121.77],
[122.92, 126.39],
[121.86, 130.89],
[120.61, 135.35],
[119.37, 139.81],
[118.15, 144.27],
[116.94, 148.74],
[115.74, 153.21],
[114.56, 157.69],
[113.39, 162.17],
[112.24, 166.65],
[111.13, 171.15],
[110.04, 175.65],
[108.89, 180.13],
[106.98, 184.33],
[103.8, 187.67],
[99.75, 189.87],
[95.25, 190.93],
[90.63, 190.93],
[86.11, 189.97],
[81.86, 188.16],
[78.05, 185.54],
[74.89, 182.18],
[72.62, 178.16],
[71.54, 173.67],
[71.94, 169.08],
[73.01, 164.57],
[74.13, 160.08],
[75.26, 155.59],
[76.42, 151.11],
[77.59, 146.63],
[78.77, 142.15],
[79.97, 137.68],
[81.18, 133.22],
[82.41, 128.75],
[83.65, 124.29],
[84.87, 119.83],
[86.33, 115.43],
[88.67, 111.46],
[91.9, 108.15],
[95.83, 105.72],
[100.23, 104.35],
],
[
[174.26, 115.55],
[178.59, 116.54],
[182.37, 118.86],
[185.31, 122.2],
[187.23, 126.21],
[188.12, 130.57],
[188.06, 135.02],
[187.52, 139.44],
[186.86, 143.85],
[186.11, 148.25],
[185.25, 152.62],
[184.3, 156.98],
[183.24, 161.31],
[182.07, 165.61],
[180.79, 169.88],
[179.39, 174.12],
[177.89, 178.31],
[176.27, 182.47],
[174.47, 186.55],
[172.17, 190.35],
[169.21, 193.68],
[165.73, 196.46],
[161.84, 198.64],
[157.66, 200.16],
[153.27, 200.91],
[148.83, 200.69],
[144.65, 199.19],
[141.47, 196.14],
[140.18, 191.91],
[140.82, 187.53],
[142.46, 183.38],
[144.16, 179.26],
[145.73, 175.09],
[147.18, 170.87],
[148.51, 166.62],
[149.73, 162.33],
[150.84, 158.01],
[151.84, 153.67],
[152.74, 149.3],
[153.54, 144.91],
[154.24, 140.51],
[154.85, 136.1],
[155.58, 131.7],
[156.93, 127.46],
[159.15, 123.6],
[162.12, 120.29],
[165.73, 117.68],
[169.84, 116],
],
],
[
[
[44.72, 103.35],
[47.95, 103.93],
[51.04, 105.05],
[53.93, 106.62],
[56.58, 108.57],
[58.97, 110.83],
[61.09, 113.35],
[62.93, 116.07],
[64.5, 118.97],
[65.79, 121.99],
[66.8, 125.13],
[67.52, 128.34],
[67.94, 131.6],
[68.08, 134.89],
[67.9, 138.17],
[67.4, 141.42],
[66.56, 144.6],
[65.33, 147.66],
[63.71, 150.52],
[61.69, 153.11],
[59.3, 155.36],
[56.54, 157.16],
[53.51, 158.42],
[50.29, 159.07],
[47, 159.09],
[43.76, 158.5],
[40.67, 157.39],
[37.78, 155.82],
[35.13, 153.87],
[32.75, 151.6],
[30.63, 149.09],
[28.78, 146.36],
[27.21, 143.47],
[25.92, 140.44],
[24.92, 137.31],
[24.2, 134.1],
[23.77, 130.84],
[23.64, 127.55],
[23.81, 124.27],
[24.31, 121.01],
[25.16, 117.84],
[26.38, 114.78],
[28, 111.92],
[30.02, 109.33],
[32.42, 107.08],
[35.17, 105.28],
[38.21, 104.02],
[41.43, 103.37],
],
[
[114.62, 83.64],
[118.31, 83.88],
[121.94, 84.6],
[125.44, 85.77],
[128.77, 87.38],
[131.86, 89.4],
[134.67, 91.81],
[137.13, 94.56],
[139.2, 97.62],
[140.85, 100.93],
[142.05, 104.42],
[142.79, 108.05],
[143.05, 111.73],
[142.83, 115.42],
[142.13, 119.05],
[140.95, 122.55],
[139.34, 125.88],
[137.3, 128.96],
[134.88, 131.75],
[132.11, 134.2],
[129.05, 136.27],
[125.75, 137.93],
[122.25, 139.13],
[118.63, 139.86],
[114.94, 140.1],
[111.25, 139.86],
[107.63, 139.14],
[104.12, 137.97],
[100.8, 136.36],
[97.7, 134.34],
[94.9, 131.93],
[92.44, 129.18],
[90.36, 126.12],
[88.72, 122.81],
[87.51, 119.31],
[86.78, 115.69],
[86.52, 112.01],
[86.74, 108.32],
[87.44, 104.69],
[88.61, 101.18],
[90.23, 97.86],
[92.27, 94.78],
[94.69, 91.99],
[97.45, 89.54],
[100.51, 87.47],
[103.82, 85.81],
[107.31, 84.61],
[110.94, 83.88],
],
],
[
[
[90.44, 99.25],
[93.11, 99.26],
[95.74, 99.79],
[98.37, 100.3],
[101, 100.82],
[103.64, 101.33],
[106.27, 101.85],
[108.9, 102.37],
[111.53, 102.89],
[114.16, 103.41],
[116.79, 103.94],
[119.42, 104.47],
[122.06, 105],
[124.69, 105.53],
[127.32, 106.06],
[129.94, 106.6],
[132.57, 107.14],
[135.2, 107.68],
[137.65, 108.73],
[139.5, 110.65],
[140.44, 113.14],
[140.36, 115.81],
[139.35, 118.28],
[137.48, 120.18],
[135, 121.14],
[132.32, 121.11],
[129.7, 120.56],
[127.08, 120],
[124.45, 119.46],
[121.82, 118.93],
[119.19, 118.4],
[116.56, 117.87],
[113.93, 117.35],
[111.29, 116.83],
[108.66, 116.32],
[106.02, 115.82],
[103.39, 115.31],
[100.76, 114.79],
[98.12, 114.28],
[95.49, 113.75],
[92.86, 113.22],
[90.23, 112.68],
[87.77, 111.66],
[85.93, 109.74],
[85.01, 107.24],
[85.06, 104.57],
[86.07, 102.1],
[87.96, 100.22],
],
[
[156.6, 112.56],
[158.91, 112.66],
[161.18, 113.15],
[163.45, 113.64],
[165.72, 114.13],
[167.99, 114.62],
[170.26, 115.12],
[172.53, 115.62],
[174.8, 116.12],
[177.07, 116.62],
[179.34, 117.13],
[181.6, 117.64],
[183.87, 118.15],
[186.14, 118.67],
[188.4, 119.18],
[190.67, 119.7],
[192.94, 120.2],
[195.12, 120.96],
[196.7, 122.63],
[197.45, 124.82],
[197.53, 127.14],
[197.07, 129.41],
[196.08, 131.51],
[194.49, 133.18],
[192.33, 133.97],
[190.04, 133.68],
[187.79, 133.09],
[185.52, 132.57],
[183.26, 132.05],
[180.99, 131.54],
[178.72, 131.03],
[176.45, 130.53],
[174.18, 130.03],
[171.91, 129.54],
[169.64, 129.05],
[167.37, 128.56],
[165.1, 128.07],
[162.83, 127.58],
[160.56, 127.08],
[158.29, 126.57],
[156.02, 126.05],
[153.9, 125.14],
[152.26, 123.51],
[151.32, 121.4],
[151.08, 119.1],
[151.53, 116.82],
[152.65, 114.8],
[154.41, 113.31],
],
],
[
[
[79.94, 130.44],
[83.08, 130.57],
[86.11, 131.41],
[88.89, 132.89],
[91.27, 134.94],
[93.15, 137.46],
[94.39, 140.35],
[95.11, 143.42],
[95.65, 146.52],
[96.2, 149.62],
[96.78, 152.72],
[97.39, 155.81],
[98.04, 158.89],
[98.72, 161.97],
[99.43, 165.04],
[100.18, 168.1],
[100.97, 171.15],
[101.81, 174.18],
[102.64, 177.22],
[103.01, 180.34],
[102.35, 183.4],
[100.66, 186.04],
[98.19, 187.98],
[95.28, 189.16],
[92.17, 189.6],
[89.03, 189.37],
[85.99, 188.56],
[83.16, 187.2],
[80.63, 185.33],
[78.55, 182.97],
[77.05, 180.21],
[76.1, 177.21],
[75.28, 174.17],
[74.5, 171.11],
[73.74, 168.06],
[73.02, 164.99],
[72.33, 161.92],
[71.68, 158.83],
[71.06, 155.75],
[70.47, 152.65],
[69.91, 149.55],
[69.37, 146.45],
[68.97, 143.32],
[69.12, 140.18],
[70.04, 137.18],
[71.7, 134.51],
[74.03, 132.41],
[76.86, 131.04],
],
[
[168.95, 136.28],
[171.31, 136.97],
[172.99, 138.76],
[173.66, 141.13],
[173.36, 143.58],
[172.24, 145.79],
[170.45, 147.49],
[168.22, 148.58],
[165.89, 149.43],
[163.57, 150.31],
[161.24, 151.18],
[158.9, 152.02],
[156.56, 152.85],
[154.21, 153.65],
[151.85, 154.44],
[149.48, 155.2],
[147.11, 155.94],
[144.73, 156.65],
[142.34, 157.34],
[139.95, 158.01],
[137.55, 158.66],
[135.14, 159.27],
[132.73, 159.86],
[130.31, 160.43],
[127.84, 160.54],
[125.53, 159.69],
[123.77, 157.96],
[122.89, 155.66],
[123.09, 153.21],
[124.36, 151.09],
[126.34, 149.61],
[128.69, 148.83],
[131.1, 148.24],
[133.51, 147.62],
[135.91, 146.98],
[138.31, 146.32],
[140.7, 145.65],
[143.08, 144.95],
[145.46, 144.23],
[147.83, 143.49],
[150.2, 142.73],
[152.56, 141.95],
[154.91, 141.15],
[157.25, 140.32],
[159.59, 139.48],
[161.92, 138.61],
[164.24, 137.72],
[166.54, 136.78],
],
],
[
[
[119.79, 105.35],
[121.94, 105.42],
[124.03, 105.87],
[126, 106.72],
[127.77, 107.93],
[129.27, 109.47],
[130.45, 111.26],
[131.29, 113.23],
[131.73, 115.33],
[131.79, 117.47],
[131.53, 119.6],
[131.11, 121.71],
[130.66, 123.81],
[130.27, 125.92],
[129.88, 128.03],
[129.49, 130.14],
[129.07, 132.25],
[128.62, 134.35],
[127.96, 136.39],
[126.96, 138.29],
[125.62, 139.96],
[123.99, 141.36],
[122.13, 142.43],
[120.11, 143.15],
[118, 143.5],
[115.85, 143.45],
[113.75, 143],
[111.79, 142.15],
[110.03, 140.93],
[108.54, 139.38],
[107.36, 137.59],
[106.53, 135.61],
[106.1, 133.51],
[106.07, 131.37],
[106.35, 129.24],
[106.77, 127.14],
[107.22, 125.04],
[107.64, 122.93],
[108.05, 120.82],
[108.45, 118.71],
[108.84, 116.6],
[109.25, 114.49],
[109.86, 112.44],
[110.83, 110.52],
[112.16, 108.84],
[113.78, 107.44],
[115.65, 106.38],
[117.67, 105.68],
],
[
[174.73, 114.1],
[176.71, 114.59],
[178.5, 115.55],
[180.04, 116.88],
[181.27, 118.5],
[182.17, 120.33],
[182.71, 122.29],
[182.9, 124.32],
[182.82, 126.36],
[182.56, 128.38],
[182.23, 130.39],
[181.89, 132.4],
[181.53, 134.41],
[181.16, 136.41],
[180.75, 138.41],
[180.3, 140.4],
[179.82, 142.38],
[179.18, 144.31],
[178.28, 146.15],
[177.14, 147.83],
[175.74, 149.31],
[174.11, 150.53],
[172.29, 151.44],
[170.32, 151.97],
[168.29, 152.07],
[166.29, 151.69],
[164.45, 150.83],
[162.87, 149.54],
[161.66, 147.91],
[160.83, 146.06],
[160.38, 144.07],
[160.29, 142.04],
[160.53, 140.01],
[160.98, 138.02],
[161.43, 136.03],
[161.84, 134.04],
[162.24, 132.04],
[162.62, 130.03],
[162.93, 128.02],
[163.24, 126],
[163.6, 124],
[164.11, 122.03],
[164.91, 120.15],
[165.99, 118.43],
[167.35, 116.91],
[168.94, 115.64],
[170.74, 114.69],
[172.7, 114.15],
],
],
[
[
[105.72, 72.58],
[108.82, 72.78],
[111.75, 73.82],
[114.27, 75.64],
[116.39, 77.92],
[118.42, 80.29],
[120.45, 82.66],
[122.47, 85.03],
[124.48, 87.41],
[126.49, 89.8],
[128.48, 92.2],
[130.47, 94.6],
[132.45, 97.01],
[134.43, 99.42],
[136.4, 101.83],
[138.37, 104.25],
[140.3, 106.7],
[141.85, 109.39],
[142.65, 112.4],
[142.63, 115.51],
[141.8, 118.5],
[140.21, 121.17],
[137.95, 123.31],
[135.17, 124.7],
[132.11, 125.26],
[129.02, 124.98],
[126.12, 123.86],
[123.67, 121.94],
[121.61, 119.6],
[119.66, 117.17],
[117.69, 114.75],
[115.73, 112.33],
[113.75, 109.92],
[111.77, 107.52],
[109.77, 105.12],
[107.77, 102.73],
[105.76, 100.34],
[103.75, 97.96],
[101.72, 95.59],
[99.68, 93.23],
[97.63, 90.89],
[95.91, 88.3],
[94.95, 85.34],
[94.92, 82.24],
[95.84, 79.27],
[97.56, 76.68],
[99.9, 74.63],
[102.67, 73.22],
],
[
[176.73, 63.75],
[179.52, 64.43],
[182.02, 65.85],
[184.15, 67.78],
[185.85, 70.1],
[187.08, 72.7],
[187.76, 75.5],
[187.76, 78.37],
[187.23, 81.2],
[186.58, 84.01],
[185.89, 86.8],
[185.16, 89.59],
[184.39, 92.36],
[183.59, 95.13],
[182.76, 97.89],
[181.88, 100.64],
[180.98, 103.37],
[180.02, 106.09],
[179.03, 108.79],
[177.99, 111.48],
[176.9, 114.15],
[175.5, 116.66],
[173.51, 118.72],
[171, 120.11],
[168.18, 120.66],
[165.34, 120.29],
[162.75, 119.04],
[160.62, 117.12],
[159.02, 114.73],
[158, 112.04],
[157.63, 109.19],
[157.98, 106.34],
[158.83, 103.59],
[159.86, 100.9],
[160.87, 98.2],
[161.85, 95.49],
[162.79, 92.76],
[163.7, 90.03],
[164.57, 87.29],
[165.41, 84.53],
[166.21, 81.76],
[166.98, 78.99],
[167.7, 76.2],
[168.38, 73.4],
[169, 70.58],
[169.79, 67.82],
[171.41, 65.46],
[173.88, 64.03],
],
],
[
[
[64.12, 83.43],
[66.69, 84.08],
[68.9, 85.53],
[70.57, 87.6],
[71.56, 90.05],
[71.86, 92.69],
[71.53, 95.32],
[70.55, 97.78],
[69.06, 99.99],
[67.36, 102.03],
[65.64, 104.06],
[63.95, 106.11],
[62.28, 108.18],
[60.63, 110.27],
[59, 112.38],
[57.41, 114.5],
[55.84, 116.65],
[54.29, 118.82],
[52.78, 121],
[51.31, 123.22],
[49.86, 125.45],
[48.42, 127.69],
[46.67, 129.68],
[44.36, 130.96],
[41.73, 131.22],
[39.22, 130.38],
[37.16, 128.72],
[35.64, 126.55],
[34.65, 124.08],
[34.2, 121.46],
[34.29, 118.81],
[34.94, 116.24],
[36.12, 113.86],
[37.54, 111.61],
[39.04, 109.41],
[40.54, 107.21],
[42.06, 105.03],
[43.61, 102.87],
[45.18, 100.73],
[46.79, 98.6],
[48.41, 96.5],
[50.07, 94.42],
[51.74, 92.35],
[53.45, 90.31],
[55.17, 88.28],
[56.94, 86.3],
[59.04, 84.67],
[61.48, 83.65],
],
[
[104.23, 93.09],
[106.97, 93.77],
[109.4, 95.24],
[111.32, 97.31],
[112.59, 99.85],
[113.4, 102.57],
[114.13, 105.32],
[114.87, 108.06],
[115.62, 110.8],
[116.37, 113.54],
[117.14, 116.28],
[117.9, 119.02],
[118.67, 121.75],
[119.45, 124.49],
[120.23, 127.22],
[121.03, 129.95],
[121.83, 132.68],
[122.6, 135.41],
[122.98, 138.22],
[122.57, 141.02],
[121.34, 143.57],
[119.44, 145.67],
[117.05, 147.19],
[114.34, 148.04],
[111.51, 148.14],
[108.77, 147.45],
[106.33, 146.01],
[104.38, 143.96],
[103.07, 141.44],
[102.21, 138.73],
[101.43, 136],
[100.65, 133.27],
[99.87, 130.53],
[99.09, 127.8],
[98.32, 125.06],
[97.55, 122.33],
[96.79, 119.59],
[96.04, 116.85],
[95.28, 114.11],
[94.53, 111.37],
[93.79, 108.62],
[93.05, 105.88],
[92.73, 103.07],
[93.18, 100.27],
[94.42, 97.72],
[96.32, 95.62],
[98.7, 94.08],
[101.4, 93.21],
],
],
[
[
[108.14, 135.9],
[111.13, 136.06],
[114.08, 136.56],
[116.95, 137.39],
[119.71, 138.55],
[122.31, 140.03],
[124.71, 141.81],
[126.86, 143.89],
[128.73, 146.23],
[130.27, 148.8],
[131.44, 151.55],
[132.22, 154.44],
[132.56, 157.41],
[132.47, 160.4],
[131.93, 163.34],
[130.96, 166.17],
[129.6, 168.83],
[127.87, 171.28],
[125.83, 173.46],
[123.51, 175.35],
[120.96, 176.91],
[118.23, 178.13],
[115.36, 179],
[112.42, 179.52],
[109.43, 179.7],
[106.44, 179.54],
[103.49, 179.04],
[100.62, 178.21],
[97.86, 177.06],
[95.26, 175.58],
[92.86, 173.79],
[90.71, 171.71],
[88.84, 169.37],
[87.3, 166.81],
[86.13, 164.06],
[85.35, 161.17],
[85.01, 158.2],
[85.11, 155.21],
[85.64, 152.26],
[86.61, 149.43],
[87.97, 146.77],
[89.7, 144.33],
[91.74, 142.14],
[94.06, 140.25],
[96.61, 138.69],
[99.34, 137.47],
[102.21, 136.6],
[105.15, 136.08],
],
[
[175.67, 128.81],
[177.16, 128.85],
[178.62, 129.14],
[180.01, 129.67],
[181.28, 130.44],
[182.41, 131.42],
[183.36, 132.57],
[184.12, 133.85],
[184.68, 135.23],
[185.05, 136.68],
[185.24, 138.15],
[185.27, 139.64],
[185.13, 141.13],
[184.85, 142.59],
[184.42, 144.02],
[183.85, 145.4],
[183.15, 146.72],
[182.33, 147.96],
[181.38, 149.11],
[180.32, 150.16],
[179.15, 151.08],
[177.88, 151.87],
[176.53, 152.49],
[175.1, 152.91],
[173.62, 153.11],
[172.13, 153.07],
[170.67, 152.78],
[169.28, 152.24],
[168.01, 151.47],
[166.88, 150.49],
[165.93, 149.35],
[165.18, 148.06],
[164.61, 146.68],
[164.24, 145.24],
[164.05, 143.76],
[164.02, 142.27],
[164.16, 140.78],
[164.44, 139.32],
[164.87, 137.89],
[165.44, 136.51],
[166.14, 135.2],
[166.96, 133.95],
[167.91, 132.8],
[168.97, 131.75],
[170.14, 130.83],
[171.4, 130.04],
[172.76, 129.43],
[174.19, 129.01],
],
],
[
[
[103.39, 78.25],
[106.56, 78.38],
[109.59, 79.28],
[112.29, 80.94],
[114.43, 83.28],
[115.86, 86.1],
[116.52, 89.2],
[116.32, 92.37],
[115.62, 95.46],
[114.86, 98.55],
[114.1, 101.63],
[113.36, 104.72],
[112.63, 107.81],
[111.91, 110.91],
[111.2, 114.01],
[110.51, 117.1],
[109.82, 120.21],
[109.16, 123.31],
[108.52, 126.42],
[107.84, 129.53],
[106.8, 132.52],
[105.04, 135.16],
[102.66, 137.25],
[99.81, 138.63],
[96.7, 139.2],
[93.54, 138.96],
[90.53, 137.95],
[87.87, 136.24],
[85.71, 133.92],
[84.21, 131.13],
[83.48, 128.05],
[83.5, 124.88],
[84, 121.74],
[84.7, 118.64],
[85.4, 115.54],
[86.08, 112.44],
[86.77, 109.34],
[87.48, 106.24],
[88.19, 103.15],
[88.92, 100.05],
[89.66, 96.96],
[90.41, 93.88],
[91.18, 90.8],
[91.95, 87.71],
[93.1, 84.76],
[94.95, 82.19],
[97.4, 80.19],
[100.28, 78.86],
],
[
[161.99, 91.57],
[165.07, 92],
[167.9, 93.28],
[170.32, 95.23],
[172.22, 97.69],
[173.49, 100.53],
[174.05, 103.59],
[173.93, 106.7],
[173.45, 109.78],
[172.9, 112.85],
[172.33, 115.91],
[171.71, 118.97],
[171.06, 122.02],
[170.38, 125.06],
[169.66, 128.09],
[168.91, 131.12],
[168.13, 134.14],
[167.33, 137.15],
[166.5, 140.16],
[165.58, 143.14],
[164.33, 145.98],
[162.5, 148.5],
[160.15, 150.53],
[157.38, 151.95],
[154.34, 152.61],
[151.24, 152.43],
[148.32, 151.38],
[145.83, 149.52],
[143.99, 147.01],
[142.95, 144.08],
[142.73, 140.98],
[143.25, 137.91],
[144.09, 134.91],
[144.94, 131.91],
[145.76, 128.9],
[146.54, 125.89],
[147.29, 122.86],
[148.01, 119.83],
[148.69, 116.79],
[149.34, 113.74],
[149.95, 110.68],
[150.54, 107.62],
[151.09, 104.55],
[151.6, 101.47],
[152.44, 98.48],
[154, 95.79],
[156.21, 93.6],
[158.94, 92.12],
],
],
[
[
[47.23, 91.05],
[51.61, 92.47],
[55.26, 95.29],
[57.96, 99.03],
[59.7, 103.31],
[60.56, 107.85],
[61.28, 112.42],
[62.11, 116.97],
[63.06, 121.51],
[64.11, 126.01],
[65.28, 130.49],
[66.56, 134.94],
[67.95, 139.35],
[69.44, 143.73],
[71.05, 148.07],
[72.77, 152.37],
[74.62, 156.61],
[76.52, 160.83],
[78.06, 165.19],
[78.52, 169.78],
[77.62, 174.3],
[75.2, 178.22],
[71.44, 180.86],
[66.96, 181.91],
[62.36, 181.55],
[57.99, 180.06],
[54.03, 177.68],
[50.59, 174.58],
[47.77, 170.92],
[45.62, 166.83],
[43.74, 162.6],
[41.96, 158.33],
[40.29, 154.01],
[38.72, 149.66],
[37.27, 145.26],
[35.93, 140.83],
[34.69, 136.37],
[33.56, 131.88],
[32.55, 127.37],
[31.65, 122.83],
[30.85, 118.27],
[30.2, 113.69],
[30.08, 109.07],
[30.85, 104.51],
[32.49, 100.19],
[35.01, 96.32],
[38.44, 93.24],
[42.64, 91.35],
],
[
[108.93, 73.38],
[113.76, 73.6],
[118.38, 75.01],
[122.49, 77.56],
[125.82, 81.07],
[128.1, 85.34],
[129.65, 89.93],
[131.04, 94.58],
[132.43, 99.22],
[133.82, 103.87],
[135.22, 108.51],
[136.6, 113.16],
[137.99, 117.81],
[139.36, 122.46],
[140.73, 127.11],
[142.13, 131.76],
[143.51, 136.41],
[144.82, 141.08],
[145.51, 145.86],
[144.91, 150.66],
[143.09, 155.14],
[140.17, 158.99],
[136.38, 162.01],
[132, 164.05],
[127.26, 165.03],
[122.42, 164.86],
[117.79, 163.48],
[113.67, 160.95],
[110.36, 157.43],
[108.17, 153.11],
[106.72, 148.49],
[105.36, 143.83],
[103.99, 139.18],
[102.62, 134.53],
[101.24, 129.88],
[99.87, 125.23],
[98.48, 120.58],
[97.09, 115.93],
[95.7, 111.29],
[94.29, 106.64],
[92.89, 102],
[91.49, 97.36],
[90.81, 92.57],
[91.38, 87.77],
[93.14, 83.26],
[96.02, 79.37],
[99.79, 76.34],
[104.18, 74.32],
],
],
[
[
[102.86, 129.56],
[106.39, 129.96],
[109.85, 130.76],
[113.21, 131.94],
[116.4, 133.5],
[119.39, 135.42],
[122.13, 137.69],
[124.56, 140.28],
[126.64, 143.16],
[128.33, 146.29],
[129.59, 149.61],
[130.37, 153.08],
[130.66, 156.62],
[130.43, 160.16],
[129.68, 163.63],
[128.42, 166.96],
[126.7, 170.07],
[124.54, 172.89],
[122.02, 175.39],
[119.18, 177.52],
[116.07, 179.25],
[112.76, 180.54],
[109.31, 181.4],
[105.78, 181.82],
[102.23, 181.83],
[98.7, 181.42],
[95.24, 180.62],
[91.88, 179.44],
[88.69, 177.88],
[85.7, 175.96],
[82.96, 173.69],
[80.53, 171.1],
[78.45, 168.22],
[76.76, 165.1],
[75.5, 161.77],
[74.72, 158.31],
[74.44, 154.77],
[74.67, 151.22],
[75.41, 147.75],
[76.67, 144.42],
[78.39, 141.32],
[80.55, 138.49],
[83.07, 135.99],
[85.91, 133.86],
[89.02, 132.14],
[92.33, 130.84],
[95.78, 129.99],
[99.31, 129.56],
],
[
[180.44, 141.06],
[183.61, 141.1],
[186.72, 141.68],
[189.66, 142.86],
[192.28, 144.63],
[194.43, 146.96],
[196, 149.71],
[197, 152.72],
[197.48, 155.86],
[197.51, 159.03],
[197.15, 162.18],
[196.43, 165.27],
[195.38, 168.26],
[194.07, 171.15],
[192.52, 173.92],
[190.74, 176.55],
[188.77, 179.03],
[186.6, 181.35],
[184.25, 183.48],
[181.74, 185.41],
[179.06, 187.12],
[176.23, 188.56],
[173.28, 189.71],
[170.21, 190.52],
[167.07, 190.95],
[163.9, 190.91],
[160.78, 190.33],
[157.84, 189.15],
[155.22, 187.37],
[153.08, 185.04],
[151.51, 182.29],
[150.51, 179.28],
[150.03, 176.15],
[150, 172.98],
[150.36, 169.83],
[151.07, 166.74],
[152.12, 163.74],
[153.43, 160.85],
[154.99, 158.09],
[156.76, 155.46],
[158.74, 152.98],
[160.91, 150.66],
[163.25, 148.53],
[165.77, 146.59],
[168.45, 144.89],
[171.27, 143.45],
[174.23, 142.3],
[177.29, 141.48],
],
],
[
[
[86.02, 131.33],
[88.42, 131.69],
[90.54, 132.87],
[92.12, 134.71],
[93.03, 136.97],
[93.17, 139.39],
[92.41, 141.69],
[90.78, 143.48],
[88.59, 144.52],
[86.19, 144.97],
[83.78, 145.34],
[81.37, 145.72],
[78.96, 146.09],
[76.54, 146.45],
[74.13, 146.81],
[71.72, 147.16],
[69.3, 147.5],
[66.88, 147.84],
[64.47, 148.16],
[62.05, 148.47],
[59.62, 148.76],
[57.2, 149.03],
[54.77, 149.27],
[52.34, 149.49],
[49.91, 149.68],
[47.53, 149.28],
[45.52, 147.92],
[44.04, 145.99],
[43.12, 143.74],
[42.85, 141.32],
[43.44, 138.97],
[45.04, 137.17],
[47.33, 136.4],
[49.76, 136.2],
[52.19, 135.96],
[54.62, 135.7],
[57.04, 135.43],
[59.46, 135.15],
[61.89, 134.85],
[64.31, 134.54],
[66.72, 134.22],
[69.14, 133.89],
[71.56, 133.54],
[73.97, 133.19],
[76.38, 132.83],
[78.79, 132.45],
[81.2, 132.06],
[83.61, 131.67],
],
[
[153.42, 116.84],
[155.92, 117.69],
[157.78, 119.56],
[158.72, 122.03],
[158.73, 124.68],
[157.84, 127.18],
[156.08, 129.15],
[153.71, 130.33],
[151.13, 131],
[148.55, 131.65],
[145.98, 132.32],
[143.4, 132.98],
[140.82, 133.63],
[138.23, 134.27],
[135.65, 134.9],
[133.06, 135.53],
[130.47, 136.15],
[127.88, 136.76],
[125.29, 137.36],
[122.69, 137.94],
[120.09, 138.51],
[117.49, 139.06],
[114.88, 139.59],
[112.27, 140.1],
[109.62, 140.12],
[107.17, 139.14],
[105.28, 137.29],
[104.18, 134.88],
[104.06, 132.23],
[105.03, 129.78],
[106.92, 127.93],
[109.35, 126.87],
[111.96, 126.34],
[114.57, 125.8],
[117.17, 125.24],
[119.77, 124.67],
[122.37, 124.09],
[124.96, 123.5],
[127.56, 122.9],
[130.15, 122.29],
[132.74, 121.68],
[135.32, 121.05],
[137.91, 120.41],
[140.49, 119.76],
[143.07, 119.11],
[145.65, 118.44],
[148.22, 117.76],
[150.78, 117.03],
],
],
[
[
[83.36, 65.84],
[86.61, 66.42],
[89.57, 67.88],
[92, 70.12],
[93.67, 72.97],
[94.46, 76.17],
[94.31, 79.47],
[93.61, 82.71],
[92.8, 85.92],
[92.02, 89.14],
[91.27, 92.36],
[90.56, 95.6],
[89.88, 98.84],
[89.23, 102.09],
[88.62, 105.34],
[88.03, 108.61],
[87.51, 111.88],
[87.01, 115.15],
[86.5, 118.42],
[85.65, 121.62],
[84.11, 124.54],
[81.9, 126.99],
[79.13, 128.79],
[75.98, 129.8],
[72.68, 129.91],
[69.47, 129.13],
[66.6, 127.49],
[64.24, 125.18],
[62.49, 122.38],
[61.42, 119.25],
[61.08, 115.97],
[61.36, 112.67],
[61.87, 109.4],
[62.45, 106.13],
[63.01, 102.87],
[63.61, 99.61],
[64.24, 96.36],
[64.9, 93.11],
[65.6, 89.87],
[66.33, 86.64],
[67.09, 83.42],
[67.89, 80.2],
[68.73, 77],
[69.89, 73.9],
[71.7, 71.14],
[74.1, 68.86],
[76.93, 67.16],
[80.07, 66.12],
],
[
[119.49, 99.16],
[121.99, 99.28],
[124.44, 99.82],
[126.9, 100.34],
[129.36, 100.86],
[131.81, 101.38],
[134.27, 101.91],
[136.72, 102.44],
[139.17, 102.98],
[141.62, 103.52],
[144.08, 104.07],
[146.52, 104.62],
[148.97, 105.18],
[151.42, 105.74],
[153.86, 106.31],
[156.31, 106.89],
[158.75, 107.47],
[161.2, 108.02],
[163.49, 109.03],
[165.16, 110.87],
[165.95, 113.24],
[165.87, 115.74],
[164.94, 118.05],
[163.17, 119.8],
[160.79, 120.55],
[158.31, 120.29],
[155.88, 119.65],
[153.44, 119.06],
[150.99, 118.49],
[148.55, 117.92],
[146.1, 117.36],
[143.65, 116.81],
[141.2, 116.26],
[138.75, 115.73],
[136.29, 115.2],
[133.84, 114.67],
[131.38, 114.15],
[128.93, 113.62],
[126.47, 113.1],
[124.02, 112.57],
[121.56, 112.04],
[119.11, 111.5],
[116.81, 110.53],
[115.08, 108.73],
[114.22, 106.39],
[114.29, 103.9],
[115.28, 101.61],
[117.12, 99.93],
],
],
[
[
[168.71, 85.67],
[170.73, 86],
[172.64, 86.75],
[174.37, 87.85],
[175.88, 89.24],
[177.11, 90.88],
[178.04, 92.71],
[178.71, 94.65],
[179.21, 96.64],
[179.64, 98.65],
[180.05, 100.66],
[180.45, 102.67],
[180.83, 104.69],
[181.18, 106.71],
[181.5, 108.74],
[181.77, 110.78],
[181.88, 112.82],
[181.71, 114.87],
[181.22, 116.86],
[180.41, 118.74],
[179.27, 120.45],
[177.83, 121.91],
[176.12, 123.03],
[174.2, 123.74],
[172.16, 123.99],
[170.13, 123.75],
[168.21, 123.04],
[166.49, 121.93],
[165.03, 120.48],
[163.88, 118.79],
[163.02, 116.93],
[162.49, 114.95],
[162.17, 112.92],
[161.85, 110.89],
[161.51, 108.87],
[161.14, 106.84],
[160.77, 104.83],
[160.37, 102.81],
[159.96, 100.8],
[159.52, 98.79],
[159.24, 96.76],
[159.3, 94.71],
[159.71, 92.7],
[160.48, 90.8],
[161.58, 89.08],
[163.01, 87.61],
[164.73, 86.49],
[166.67, 85.83],
],
[
[206.57, 78.24],
[208.3, 78.8],
[209.77, 79.87],
[210.99, 81.22],
[212.01, 82.73],
[212.85, 84.34],
[213.53, 86.03],
[214.08, 87.77],
[214.54, 89.54],
[214.95, 91.31],
[215.34, 93.09],
[215.7, 94.88],
[216.04, 96.67],
[216.36, 98.46],
[216.64, 100.26],
[216.89, 102.07],
[217.11, 103.88],
[217.25, 105.7],
[217.26, 107.52],
[217.1, 109.33],
[216.75, 111.12],
[216.16, 112.84],
[215.3, 114.44],
[214.04, 115.75],
[212.34, 116.35],
[210.58, 115.96],
[209.11, 114.89],
[207.97, 113.48],
[207.1, 111.88],
[206.44, 110.18],
[205.97, 108.42],
[205.62, 106.63],
[205.35, 104.83],
[205.11, 103.02],
[204.85, 101.22],
[204.55, 99.42],
[204.22, 97.63],
[203.87, 95.84],
[203.49, 94.05],
[203.09, 92.28],
[202.67, 90.5],
[202.32, 88.71],
[202.1, 86.91],
[202.1, 85.08],
[202.32, 83.28],
[202.77, 81.51],
[203.54, 79.86],
[204.82, 78.59],
],
],
[
[
[39.78, 104.3],
[42.64, 105.01],
[45.03, 106.74],
[46.73, 109.15],
[47.75, 111.93],
[48.35, 114.83],
[48.81, 117.76],
[49.31, 120.68],
[49.87, 123.6],
[50.48, 126.5],
[51.15, 129.39],
[51.86, 132.27],
[52.63, 135.13],
[53.44, 137.98],
[54.3, 140.82],
[55.19, 143.65],
[56.13, 146.46],
[57.1, 149.26],
[58.1, 152.05],
[58.86, 154.92],
[58.96, 157.87],
[58.18, 160.72],
[56.43, 163.09],
[53.84, 164.48],
[50.9, 164.62],
[48.08, 163.75],
[45.58, 162.16],
[43.51, 160.05],
[41.89, 157.57],
[40.67, 154.87],
[39.67, 152.08],
[38.73, 149.26],
[37.81, 146.44],
[36.94, 143.61],
[36.11, 140.76],
[35.34, 137.9],
[34.61, 135.03],
[33.92, 132.14],
[33.28, 129.24],
[32.7, 126.34],
[32.16, 123.42],
[31.67, 120.5],
[31.23, 117.57],
[31.14, 114.61],
[31.65, 111.69],
[32.74, 108.94],
[34.47, 106.54],
[36.89, 104.86],
],
[
[108.97, 125.73],
[111.9, 126.2],
[114.63, 127.37],
[117, 129.16],
[118.84, 131.49],
[119.99, 134.23],
[120.32, 137.18],
[119.85, 140.11],
[118.59, 142.8],
[116.78, 145.16],
[114.84, 147.42],
[112.89, 149.67],
[110.93, 151.92],
[108.97, 154.16],
[107.01, 156.39],
[105.03, 158.62],
[103.05, 160.85],
[101.07, 163.06],
[99.07, 165.28],
[97.09, 167.5],
[95.09, 169.71],
[93.05, 171.88],
[90.69, 173.67],
[87.89, 174.66],
[84.93, 174.81],
[82.02, 174.22],
[79.31, 173],
[76.92, 171.24],
[74.99, 168.98],
[73.7, 166.3],
[73.26, 163.37],
[73.74, 160.45],
[75.2, 157.86],
[77.17, 155.63],
[79.18, 153.43],
[81.18, 151.23],
[83.17, 149.02],
[85.16, 146.8],
[87.14, 144.58],
[89.11, 142.35],
[91.08, 140.11],
[93.04, 137.87],
[95, 135.63],
[96.95, 133.38],
[98.89, 131.12],
[100.87, 128.89],
[103.25, 127.12],
[106.02, 126.04],
],
],
[
[
[115.43, 87.59],
[118.19, 88.24],
[120.69, 89.59],
[122.69, 91.59],
[124.03, 94.09],
[124.63, 96.87],
[124.41, 99.7],
[123.7, 102.45],
[122.9, 105.18],
[122.12, 107.92],
[121.34, 110.65],
[120.57, 113.39],
[119.79, 116.13],
[119.02, 118.87],
[118.25, 121.61],
[117.48, 124.35],
[116.72, 127.09],
[115.97, 129.83],
[115.23, 132.58],
[114.45, 135.32],
[113.3, 137.91],
[111.49, 140.09],
[109.13, 141.65],
[106.41, 142.48],
[103.58, 142.56],
[100.82, 141.91],
[98.33, 140.54],
[96.33, 138.53],
[94.99, 136.03],
[94.38, 133.26],
[94.57, 130.43],
[95.25, 127.67],
[96.02, 124.93],
[96.79, 122.19],
[97.55, 119.45],
[98.31, 116.7],
[99.08, 113.96],
[99.85, 111.22],
[100.62, 108.49],
[101.4, 105.75],
[102.18, 103.01],
[102.95, 100.27],
[103.74, 97.54],
[104.51, 94.8],
[105.68, 92.21],
[107.5, 90.04],
[109.88, 88.5],
[112.59, 87.67],
],
[
[155.37, 78.64],
[158.04, 79.15],
[160.48, 80.37],
[162.53, 82.16],
[164.33, 84.22],
[166.1, 86.3],
[167.85, 88.4],
[169.58, 90.51],
[171.29, 92.64],
[172.98, 94.78],
[174.65, 96.94],
[176.3, 99.12],
[177.92, 101.32],
[179.51, 103.54],
[181.06, 105.79],
[182.57, 108.07],
[184.03, 110.37],
[185.2, 112.83],
[185.77, 115.5],
[185.73, 118.23],
[185.07, 120.87],
[183.8, 123.28],
[181.94, 125.26],
[179.57, 126.6],
[176.89, 127.03],
[174.24, 126.43],
[171.99, 124.92],
[170.26, 122.8],
[168.75, 120.53],
[167.22, 118.27],
[165.66, 116.03],
[164.07, 113.81],
[162.45, 111.6],
[160.82, 109.41],
[159.16, 107.25],
[157.47, 105.1],
[155.76, 102.97],
[154.03, 100.85],
[152.28, 98.76],
[150.51, 96.68],
[148.74, 94.6],
[147.29, 92.29],
[146.49, 89.69],
[146.36, 86.97],
[146.94, 84.31],
[148.23, 81.91],
[150.19, 80.02],
[152.66, 78.89],
],
],
[
[
[92.71, 76.24],
[95.76, 76.59],
[98.73, 77.35],
[101.56, 78.53],
[104.21, 80.08],
[106.63, 81.96],
[108.78, 84.16],
[110.61, 86.62],
[112.09, 89.31],
[113.19, 92.17],
[113.91, 95.15],
[114.24, 98.2],
[114.18, 101.27],
[113.73, 104.31],
[112.9, 107.26],
[111.7, 110.09],
[110.15, 112.73],
[108.28, 115.17],
[106.12, 117.35],
[103.71, 119.24],
[101.08, 120.83],
[98.27, 122.07],
[95.33, 122.95],
[92.3, 123.44],
[89.23, 123.51],
[86.18, 123.17],
[83.21, 122.41],
[80.38, 121.23],
[77.73, 119.69],
[75.31, 117.8],
[73.16, 115.61],
[71.33, 113.14],
[69.86, 110.45],
[68.75, 107.59],
[68.02, 104.61],
[67.7, 101.56],
[67.76, 98.49],
[68.22, 95.46],
[69.05, 92.5],
[70.25, 89.68],
[71.8, 87.03],
[73.67, 84.59],
[75.83, 82.41],
[78.24, 80.52],
[80.87, 78.93],
[83.67, 77.69],
[86.61, 76.81],
[89.64, 76.32],
],
[
[157.73, 102.08],
[159.31, 102.13],
[160.86, 102.42],
[162.35, 102.95],
[163.74, 103.69],
[165.01, 104.62],
[166.15, 105.72],
[167.13, 106.95],
[167.96, 108.29],
[168.63, 109.72],
[169.13, 111.22],
[169.45, 112.76],
[169.59, 114.34],
[169.55, 115.91],
[169.31, 117.47],
[168.88, 118.99],
[168.28, 120.45],
[167.52, 121.83],
[166.58, 123.1],
[165.48, 124.23],
[164.25, 125.22],
[162.89, 126.02],
[161.43, 126.63],
[159.91, 127.02],
[158.34, 127.2],
[156.76, 127.14],
[155.21, 126.85],
[153.73, 126.33],
[152.33, 125.59],
[151.06, 124.65],
[149.93, 123.56],
[148.94, 122.33],
[148.11, 120.99],
[147.44, 119.56],
[146.95, 118.06],
[146.62, 116.51],
[146.48, 114.94],
[146.52, 113.37],
[146.76, 111.8],
[147.18, 110.28],
[147.78, 108.83],
[148.56, 107.45],
[149.5, 106.18],
[150.59, 105.05],
[151.83, 104.07],
[153.18, 103.26],
[154.64, 102.65],
[156.17, 102.26],
],
],
[
[
[57.98, 112.03],
[61.01, 112.26],
[63.82, 113.41],
[66.22, 115.27],
[68.09, 117.67],
[69.36, 120.44],
[70.14, 123.39],
[70.64, 126.39],
[71.07, 129.41],
[71.58, 132.42],
[72.15, 135.41],
[72.76, 138.4],
[73.4, 141.38],
[74.09, 144.35],
[74.82, 147.31],
[75.59, 150.26],
[76.42, 153.2],
[77.3, 156.12],
[78.16, 159.04],
[78.68, 162.04],
[78.42, 165.07],
[77.28, 167.88],
[75.25, 170.13],
[72.54, 171.49],
[69.52, 171.87],
[66.51, 171.44],
[63.69, 170.32],
[61.16, 168.61],
[59.03, 166.44],
[57.38, 163.89],
[56.23, 161.06],
[55.34, 158.15],
[54.53, 155.21],
[53.73, 152.27],
[52.97, 149.31],
[52.25, 146.35],
[51.57, 143.38],
[50.93, 140.4],
[50.34, 137.41],
[49.78, 134.41],
[49.26, 131.4],
[48.78, 128.39],
[48.37, 125.37],
[48.37, 122.33],
[49.06, 119.36],
[50.44, 116.65],
[52.47, 114.39],
[55.04, 112.78],
],
[
[117.45, 101.46],
[120.57, 101.84],
[123.48, 103.02],
[125.99, 104.91],
[127.97, 107.35],
[129.25, 110.23],
[130.05, 113.27],
[130.76, 116.34],
[131.46, 119.41],
[132.15, 122.49],
[132.85, 125.56],
[133.55, 128.63],
[134.24, 131.71],
[134.93, 134.78],
[135.61, 137.86],
[136.32, 140.93],
[137.01, 144],
[137.66, 147.09],
[137.87, 150.22],
[137.25, 153.3],
[135.83, 156.1],
[133.73, 158.45],
[131.15, 160.23],
[128.22, 161.38],
[125.11, 161.83],
[121.98, 161.5],
[119.05, 160.37],
[116.52, 158.51],
[114.57, 156.05],
[113.37, 153.14],
[112.64, 150.08],
[111.95, 147],
[111.27, 143.93],
[110.58, 140.85],
[109.89, 137.78],
[109.2, 134.7],
[108.51, 131.63],
[107.81, 128.56],
[107.12, 125.48],
[106.42, 122.41],
[105.71, 119.34],
[105.02, 116.27],
[104.83, 113.13],
[105.42, 110.04],
[106.79, 107.22],
[108.84, 104.83],
[111.41, 103.02],
[114.33, 101.87],
],
],
[
[
[113.75, 120.08],
[118.16, 120.78],
[122.31, 122.43],
[125.98, 124.96],
[128.94, 128.29],
[131.02, 132.23],
[132.12, 136.56],
[132.1, 141.02],
[131.16, 145.38],
[129.94, 149.68],
[128.69, 153.98],
[127.44, 158.27],
[126.19, 162.56],
[124.92, 166.85],
[123.64, 171.14],
[122.35, 175.42],
[121.05, 179.69],
[119.76, 183.97],
[118.46, 188.25],
[117.05, 192.49],
[114.84, 196.36],
[111.47, 199.27],
[107.42, 201.12],
[103.04, 201.99],
[98.58, 201.97],
[94.18, 201.19],
[89.97, 199.7],
[86.1, 197.48],
[82.8, 194.48],
[80.41, 190.72],
[79.31, 186.41],
[79.87, 182],
[81.24, 177.74],
[82.57, 173.47],
[83.88, 169.2],
[85.19, 164.92],
[86.48, 160.64],
[87.75, 156.36],
[89.02, 152.07],
[90.28, 147.78],
[91.53, 143.49],
[92.77, 139.19],
[93.97, 134.88],
[95.5, 130.69],
[97.93, 126.95],
[101.16, 123.87],
[105.02, 121.64],
[109.3, 120.36],
],
[
[181.19, 127.71],
[185.4, 128.03],
[189.23, 129.79],
[192.19, 132.8],
[194.06, 136.59],
[194.87, 140.74],
[194.76, 144.98],
[194.21, 149.18],
[193.55, 153.37],
[192.79, 157.55],
[191.91, 161.69],
[190.91, 165.82],
[189.8, 169.91],
[188.57, 173.97],
[187.22, 177.99],
[185.72, 181.96],
[184.07, 185.87],
[182.26, 189.7],
[180.26, 193.44],
[177.85, 196.92],
[174.93, 199.99],
[171.62, 202.64],
[168, 204.85],
[164.13, 206.59],
[160.07, 207.78],
[155.86, 208.24],
[151.69, 207.6],
[148.31, 205.16],
[147.33, 201.11],
[148.48, 197.06],
[150.4, 193.28],
[152.24, 189.46],
[153.93, 185.56],
[155.48, 181.61],
[156.89, 177.62],
[158.17, 173.57],
[159.32, 169.49],
[160.35, 165.38],
[161.26, 161.23],
[162.06, 157.07],
[162.7, 152.87],
[163.29, 148.67],
[164.12, 144.52],
[165.46, 140.5],
[167.49, 136.78],
[170.16, 133.49],
[173.37, 130.73],
[177.08, 128.7],
],
],
[
[
[52.43, 111.88],
[55.76, 112.3],
[59, 113.21],
[62.08, 114.57],
[64.96, 116.3],
[67.61, 118.36],
[70.01, 120.71],
[72.16, 123.3],
[74.02, 126.1],
[75.61, 129.06],
[76.9, 132.17],
[77.89, 135.38],
[78.56, 138.68],
[78.89, 142.02],
[78.86, 145.39],
[78.45, 148.72],
[77.63, 151.98],
[76.39, 155.11],
[74.74, 158.03],
[72.67, 160.68],
[70.2, 162.96],
[67.38, 164.79],
[64.28, 166.08],
[61, 166.78],
[57.64, 166.91],
[54.3, 166.49],
[51.07, 165.57],
[47.99, 164.22],
[45.11, 162.49],
[42.46, 160.42],
[40.05, 158.07],
[37.91, 155.48],
[36.04, 152.68],
[34.46, 149.72],
[33.16, 146.62],
[32.17, 143.4],
[31.51, 140.11],
[31.18, 136.76],
[31.21, 133.4],
[31.62, 130.06],
[32.44, 126.8],
[33.67, 123.68],
[35.33, 120.75],
[37.4, 118.1],
[39.86, 115.82],
[42.68, 114],
[45.79, 112.71],
[49.07, 112.01],
],
[
[126.89, 95.19],
[130.56, 95.44],
[134.16, 96.17],
[137.64, 97.36],
[140.94, 98.99],
[143.98, 101.06],
[146.73, 103.5],
[149.13, 106.29],
[151.14, 109.37],
[152.72, 112.69],
[153.86, 116.19],
[154.54, 119.8],
[154.74, 123.47],
[154.45, 127.14],
[153.67, 130.74],
[152.43, 134.2],
[150.76, 137.48],
[148.69, 140.51],
[146.25, 143.27],
[143.48, 145.69],
[140.43, 147.75],
[137.14, 149.39],
[133.66, 150.59],
[130.06, 151.32],
[126.39, 151.56],
[122.72, 151.31],
[119.11, 150.59],
[115.63, 149.4],
[112.34, 147.76],
[109.29, 145.7],
[106.54, 143.26],
[104.14, 140.47],
[102.13, 137.39],
[100.55, 134.07],
[99.41, 130.57],
[98.73, 126.96],
[98.53, 123.28],
[98.83, 119.62],
[99.6, 116.02],
[100.84, 112.56],
[102.51, 109.28],
[104.59, 106.25],
[107.03, 103.49],
[109.79, 101.07],
[112.84, 99.01],
[116.13, 97.36],
[119.61, 96.16],
[123.22, 95.43],
],
],
[
[
[72.34, 79.33],
[74.93, 79.64],
[77.52, 79.94],
[80.12, 80.25],
[82.71, 80.57],
[85.3, 80.91],
[87.88, 81.26],
[90.47, 81.63],
[93.05, 82],
[95.63, 82.39],
[98.21, 82.79],
[100.79, 83.21],
[103.37, 83.63],
[105.94, 84.07],
[108.51, 84.52],
[111.09, 84.92],
[113.65, 85.44],
[115.99, 86.56],
[117.75, 88.47],
[118.68, 90.89],
[118.57, 93.48],
[117.47, 95.83],
[115.57, 97.6],
[113.16, 98.56],
[110.56, 98.58],
[108, 98.1],
[105.43, 97.64],
[102.85, 97.19],
[100.28, 96.76],
[97.7, 96.33],
[95.12, 95.93],
[92.54, 95.53],
[89.96, 95.14],
[87.38, 94.77],
[84.79, 94.4],
[82.2, 94.06],
[79.62, 93.72],
[77.02, 93.41],
[74.43, 93.11],
[71.84, 92.81],
[69.24, 92.5],
[66.78, 91.69],
[64.99, 89.83],
[64.25, 87.35],
[64.5, 84.76],
[65.58, 82.39],
[67.38, 80.53],
[69.74, 79.45],
],
[
[136.83, 90.25],
[139.33, 90.71],
[141.8, 91.34],
[144.28, 91.93],
[146.75, 92.53],
[149.22, 93.14],
[151.69, 93.77],
[154.15, 94.4],
[156.62, 95.05],
[159.08, 95.71],
[161.53, 96.38],
[163.98, 97.07],
[166.43, 97.76],
[168.88, 98.47],
[171.32, 99.2],
[173.75, 99.94],
[176.19, 100.67],
[178.49, 101.74],
[180.18, 103.62],
[181.12, 105.98],
[181.31, 108.51],
[180.69, 110.96],
[179.21, 113.01],
[176.98, 114.19],
[174.46, 114.13],
[172.02, 113.41],
[169.58, 112.66],
[167.14, 111.93],
[164.7, 111.22],
[162.25, 110.52],
[159.8, 109.84],
[157.34, 109.17],
[154.88, 108.52],
[152.42, 107.88],
[149.95, 107.26],
[147.48, 106.64],
[145.01, 106.03],
[142.54, 105.42],
[140.06, 104.81],
[137.59, 104.21],
[135.12, 103.61],
[132.78, 102.62],
[130.96, 100.86],
[129.93, 98.55],
[129.77, 96.02],
[130.49, 93.59],
[132.06, 91.61],
[134.31, 90.46],
],
],
[
[
[107.05, 116.19],
[110.26, 116.71],
[113.26, 118],
[115.85, 119.97],
[117.92, 122.49],
[119.29, 125.45],
[120.04, 128.63],
[120.54, 131.86],
[121.04, 135.09],
[121.54, 138.31],
[122.06, 141.54],
[122.59, 144.77],
[123.12, 147.99],
[123.67, 151.21],
[124.22, 154.43],
[124.8, 157.65],
[125.4, 160.86],
[125.95, 164.08],
[126.04, 167.34],
[125.2, 170.49],
[123.53, 173.28],
[121.14, 175.49],
[118.26, 177.02],
[115.11, 177.87],
[111.85, 178.04],
[108.63, 177.56],
[105.58, 176.41],
[102.87, 174.58],
[100.72, 172.14],
[99.35, 169.18],
[98.61, 166],
[98.04, 162.78],
[97.47, 159.57],
[96.91, 156.35],
[96.36, 153.13],
[95.83, 149.9],
[95.3, 146.68],
[94.78, 143.45],
[94.27, 140.22],
[93.76, 137],
[93.26, 133.77],
[92.82, 130.53],
[92.96, 127.27],
[93.87, 124.15],
[95.55, 121.35],
[97.88, 119.07],
[100.68, 117.41],
[103.79, 116.44],
],
[
[189.21, 121.96],
[191.36, 122.71],
[192.8, 124.5],
[193.41, 126.73],
[193.32, 129.04],
[192.59, 131.23],
[191.22, 133.09],
[189.28, 134.34],
[187.12, 135.19],
[184.95, 136],
[182.78, 136.83],
[180.61, 137.63],
[178.43, 138.43],
[176.24, 139.2],
[174.05, 139.95],
[171.85, 140.69],
[169.64, 141.4],
[167.43, 142.09],
[165.21, 142.76],
[162.98, 143.42],
[160.75, 144.05],
[158.51, 144.66],
[156.27, 145.25],
[154.02, 145.81],
[151.72, 145.98],
[149.57, 145.18],
[148.01, 143.49],
[147.25, 141.31],
[147.31, 139],
[148.16, 136.86],
[149.7, 135.14],
[151.74, 134.05],
[153.97, 133.43],
[156.21, 132.84],
[158.45, 132.22],
[160.68, 131.59],
[162.91, 130.93],
[165.13, 130.26],
[167.34, 129.58],
[169.55, 128.87],
[171.76, 128.15],
[173.95, 127.41],
[176.15, 126.65],
[178.33, 125.87],
[180.51, 125.08],
[182.68, 124.26],
[184.84, 123.41],
[186.98, 122.53],
],
],
[
[
[98.62, 121.53],
[100.72, 121.6],
[102.78, 122.03],
[104.72, 122.83],
[106.49, 123.97],
[108.01, 125.42],
[109.24, 127.12],
[110.15, 129.02],
[110.66, 131.05],
[110.78, 133.15],
[110.62, 135.25],
[110.34, 137.33],
[110.04, 139.42],
[109.76, 141.5],
[109.49, 143.59],
[109.21, 145.68],
[108.92, 147.76],
[108.6, 149.84],
[108.08, 151.88],
[107.18, 153.78],
[105.92, 155.45],
[104.34, 156.83],
[102.51, 157.86],
[100.51, 158.52],
[98.43, 158.81],
[96.33, 158.72],
[94.28, 158.27],
[92.33, 157.47],
[90.57, 156.33],
[89.03, 154.89],
[87.78, 153.21],
[86.85, 151.32],
[86.29, 149.3],
[86.13, 147.2],
[86.28, 145.11],
[86.57, 143.02],
[86.9, 140.94],
[87.2, 138.86],
[87.49, 136.78],
[87.79, 134.69],
[88.08, 132.61],
[88.4, 130.53],
[88.96, 128.5],
[89.88, 126.61],
[91.15, 124.94],
[92.73, 123.56],
[94.56, 122.52],
[96.54, 121.84],
],
[
[155.31, 127.29],
[157.36, 127.43],
[159.33, 127.99],
[161.14, 128.96],
[162.7, 130.29],
[163.95, 131.92],
[164.84, 133.77],
[165.35, 135.75],
[165.49, 137.8],
[165.35, 139.85],
[165.07, 141.89],
[164.79, 143.92],
[164.53, 145.96],
[164.26, 148],
[163.97, 150.04],
[163.65, 152.06],
[163.27, 154.09],
[162.7, 156.06],
[161.83, 157.92],
[160.68, 159.62],
[159.29, 161.13],
[157.69, 162.41],
[155.9, 163.42],
[153.97, 164.1],
[151.94, 164.41],
[149.89, 164.32],
[147.9, 163.82],
[146.06, 162.92],
[144.47, 161.62],
[143.24, 159.98],
[142.41, 158.1],
[142, 156.09],
[142.01, 154.04],
[142.32, 152.01],
[142.64, 149.98],
[142.96, 147.95],
[143.25, 145.92],
[143.51, 143.88],
[143.73, 141.83],
[143.97, 139.79],
[144.27, 137.76],
[144.74, 135.76],
[145.53, 133.87],
[146.62, 132.13],
[147.98, 130.59],
[149.57, 129.28],
[151.35, 128.27],
[153.28, 127.58],
],
],
]
const GROUPS = {
'Cycle de vie': [
'sleeping',
'waking',
'idle',
'listening',
'thinking',
'searching',
'working',
],
Réactions: [
'excited',
'surprised',
'suspicious',
'angry',
'drowsy',
'happy',
'curious',
'confused',
'bored',
'proud',
'shy',
'sad',
'laughing',
'scared',
'playful',
'celebrate',
],
'Morphes agent': ['orbit', 'radar', 'progress'],
'Cycle produit': [
'spawning',
'humming',
'loading',
'dictating',
'writing',
'sending',
'receiving',
'uploading',
'notifying',
'alerting',
'dragging',
'bouncing',
'powering-down',
],
}
const POOLS = {
sleeping: [13, 22, 4],
waking: [13],
idle: [0, 8],
listening: [10, 1, 19],
thinking: [8, 16, 14, 17, 5],
searching: [15, 9, 3, 20, 12, 18],
working: [7, 16, 11, 10],
excited: [2, 17, 21, 3, 11],
surprised: [3, 21],
suspicious: [14, 5, 23],
angry: [7, 16],
drowsy: [4, 22, 13],
happy: [2, 11, 17, 19],
curious: [3, 21, 0, 15],
confused: [14, 5, 8],
bored: [4, 22, 0],
proud: [15, 8, 2],
shy: [0, 24, 13],
sad: [4, 13, 22],
laughing: [2, 11, 17],
scared: [3, 21],
playful: [2, 17, 11, 8],
celebrate: [2, 8, 17],
orbit: [0, 8],
radar: [0, 8],
progress: [0, 8],
spawning: [3, 0],
humming: [0, 8],
loading: [0, 8],
dictating: [10, 1, 19],
sending: [0, 8],
receiving: [19, 0, 8],
uploading: [15, 9, 8],
writing: [15, 9],
notifying: [3, 21, 0],
alerting: [3, 21],
bouncing: [2, 17],
dragging: [3, 15, 0],
'powering-down': [13, 22],
}
const EXPR_CADENCE = {
sleeping: [6000, 10000],
waking: [800, 800],
idle: [9000, 16000],
listening: [2800, 5000],
thinking: [2000, 3600],
searching: [1000, 1800],
working: [1800, 3200],
excited: [1100, 2000],
surprised: [2500, 4000],
suspicious: [2600, 4500],
angry: [2200, 3800],
drowsy: [4000, 8000],
happy: [2500, 4500],
curious: [1800, 3200],
confused: [2200, 3800],
bored: [3500, 6000],
proud: [3500, 6000],
shy: [3000, 5500],
sad: [4000, 7000],
laughing: [1200, 2400],
scared: [900, 1800],
playful: [1500, 3000],
celebrate: [1400, 2600],
orbit: [4000, 8000],
radar: [4000, 8000],
progress: [4000, 8000],
spawning: [1200, 1200],
humming: [5000, 9000],
loading: [6000, 10000],
dictating: [4000, 8000],
sending: [4000, 8000],
receiving: [4000, 8000],
uploading: [4000, 8000],
writing: [4000, 8000],
notifying: [1500, 2600],
alerting: [2000, 3600],
bouncing: [3000, 6000],
dragging: [1600, 3000],
'powering-down': [6000, 9000],
}
const BLINK = {
sleeping: null,
waking: null,
idle: [6000, 14000],
listening: [3000, 7000],
thinking: [3500, 7000],
searching: [1600, 4000],
working: [2800, 5500],
excited: [2000, 4000],
surprised: [1800, 3500],
suspicious: [4500, 8000],
angry: [3500, 7000],
drowsy: null,
happy: [2500, 5000],
curious: [2500, 5500],
confused: [2800, 5500],
bored: [4000, 8000],
proud: [3500, 7000],
shy: [3000, 6000],
sad: [4000, 8000],
laughing: [2500, 5000],
scared: [1200, 3000],
playful: [2000, 4500],
celebrate: [2200, 4500],
orbit: null,
radar: null,
progress: null,
spawning: null,
humming: [4000, 8000],
loading: null,
dictating: null,
sending: null,
receiving: null,
uploading: null,
writing: null,
notifying: [2000, 4000],
alerting: null,
bouncing: null,
dragging: [2200, 4500],
'powering-down': null,
}
const SHAPES = [
['blob', 0, 0, 1, 1, 1, false, '50%'],
['pebble', 2, 0, 0.97, 0.86, 1, false, '43% 57% 48% 52%'],
['bean', 0, 0, 0.72, 0.9, 0.87, true, '58% 42% 54% 46%'],
['egg', 0, 2, 0.77, 0.97, 0.93, false, '50% 50% 56% 44%'],
['squircle', 0, 0, 1, 1, 1, false, '28%'],
['tablet', 0, 0, 0.94, 0.65, 0.82, true, '28%'],
['capsule', 0, 0, 0.64, 0.92, 0.81, false, '50% / 32%'],
['cylinder', 0, 0, 0.85, 0.96, 0.99, false, '42% / 18%'],
['hex', 0, 0, 0.91, 0.91, 1, false, '18%'],
['gem', 0, 0, 0.89, 0.89, 0.99, false, '35% 15% 38% 18%'],
['crystal', 0, 0, 0.71, 0.89, 0.86, false, '12% 38% 16% 42%'],
['wedge', 0, 24, 0.7, 0.7, 0.79, false, '15% 50% 50% 15%'],
['shield', 0, 0, 0.79, 0.98, 0.95, false, '45% 45% 58% 58%'],
['dome', 0, 4, 0.85, 0.68, 0.82, false, '50% 50% 30% 30%'],
['arch', 0, 0, 0.67, 0.97, 0.85, false, '50% 50% 22% 22%'],
['cloud', 0, 4, 0.79, 0.7, 0.81, true, '42% 58% 48% 52%'],
['teardrop', 0, 22, 0.79, 0.79, 0.88, false, '50% 50% 62% 38%'],
['leaf', 0, 0, 0.73, 0.91, 0.88, false, '62% 38% 62% 38%'],
]
const STATE_NOTES = {
sleeping: 'Yeux presque fermés, respiration lente et expression de sommeil.',
waking: 'Séquence courte de réveil avant retour vers une expression neutre.',
idle: 'Micro-mouvements lents, expressions 0 et 8, clignement rare.',
listening: 'Visage légèrement relevé, petits hochements et regard stable.',
thinking: 'Regard haut et latéral, expressions asymétriques et morphe « dots ».',
searching: 'Balayage rapide du regard et changements fréquents d’expression.',
working: 'Rythme régulier, légers hochements et expressions concentrées.',
excited: 'Rebonds, expressions grandes et rotations occasionnelles.',
curious: 'Inclinaison, regard mobile et expressions très asymétriques.',
}
let expression = 0
let currentRings = EXPRESSIONS[0].map(r => r.map(p => [p[0], p[1]]))
let targetRings = EXPRESSIONS[0]
let morph = 1
let velocity = 0
let lastFrame = performance.now()
let blinkStart = null
let state = 'idle'
let selectedState = 'idle'
let shape = 'blob'
let autoExpressionTimer = null
let autoBlinkTimer = null
let spinFrame = null
const centroid = ring => {
let x = 0,
y = 0
ring.forEach(p => {
x += p[0]
y += p[1]
})
return [x / ring.length, y / ring.length]
}
const path = ring =>
'M' + ring.map(p => p[0].toFixed(2) + ' ' + p[1].toFixed(2)).join('L') + 'Z'
const clamp = (v, min, max) => Math.max(min, Math.min(max, v))
const formatCadence = value =>
value
? (value[0] / 1000).toFixed(value[0] % 1000 ? 1 : 0) +
'–' +
(value[1] / 1000).toFixed(value[1] % 1000 ? 1 : 0) +
' s'
: 'désactivé'
function displayedRings() {
return currentRings.map((ring, eye) =>
ring.map((p, i) => [
p[0] + (targetRings[eye][i][0] - p[0]) * clamp(morph, 0, 1),
p[1] + (targetRings[eye][i][1] - p[1]) * clamp(morph, 0, 1),
])
)
}
function selectExpression(index) {
currentRings = displayedRings()
targetRings = EXPRESSIONS[index]
expression = index
morph = 0
velocity = 0
root
.querySelectorAll('.expression-button')
.forEach((b, i) => b.setAttribute('aria-pressed', String(i === index)))
root
.querySelectorAll('.pool-button')
.forEach(b =>
b.setAttribute('aria-pressed', String(Number(b.dataset.expression) === index))
)
}
function blinkScale(now) {
if (blinkStart === null) return 1
const t = (now - blinkStart) / 320
if (t >= 1) {
blinkStart = null
return 1
}
return Math.max(t < 0.42 ? 1 - t / 0.42 : (t - 0.42) / 0.58, 0.04)
}
function render(now) {
const rings = displayedRings()
const gazeX = Number($('gaze-x').value) * 13.2
const gazeY = Number($('gaze-y').value) * 8.4
const turn = (Number($('turn').value) * Math.PI) / 180
const emphasis = $('emphasis').checked
const baseScale = Number($('eye-scale').value) * (emphasis ? 1.18 : 1)
const blink = blinkScale(now)
rings.forEach((ring, index) => {
const c = centroid(ring)
const offset = c[0] - 114.2705
const radius = 105
const baseLongitude = Math.asin(clamp(offset / radius, -1, 1))
const longitude = baseLongitude + turn
const depth = Math.cos(longitude)
const perspective = Math.max(depth, 0.02) / Math.max(Math.cos(baseLongitude), 0.02)
const x = 114.2705 + radius * Math.sin(longitude) + gazeX
const y = c[1] + gazeY
const sx = clamp(perspective * baseScale, 0.02, 2.4)
const sy = clamp(blink * baseScale, 0.02, 2.4)
const el = $('complete-eye-' + index)
el.setAttribute('d', path(ring))
el.setAttribute(
'transform',
'translate(' +
x.toFixed(2) +
' ' +
y.toFixed(2) +
') scale(' +
sx.toFixed(4) +
' ' +
sy.toFixed(4) +
') translate(' +
(-c[0]).toFixed(2) +
' ' +
(-c[1]).toFixed(2) +
')'
)
el.style.opacity = depth > 0.02 ? '1' : '0'
$('complete-center-' + index).setAttribute('cx', x)
$('complete-center-' + index).setAttribute('cy', y)
})
$('eyes-group').setAttribute(
'transform',
$('flip-x').checked ? 'translate(228.541 0) scale(-1 1)' : ''
)
$('body-path').setAttribute(
'transform',
$('flip-x').checked ? 'translate(228.541 0) scale(-1 1)' : ''
)
$('centroids').style.opacity = $('show-guides').checked ? '1' : '0'
$('sphere-guide').style.opacity = $('show-guides').checked ? '1' : '0'
$('gaze-x-output').textContent =
Number($('gaze-x').value).toFixed(2) + ' → ' + gazeX.toFixed(1) + ' unités'
$('gaze-y-output').textContent =
Number($('gaze-y').value).toFixed(2) + ' → ' + gazeY.toFixed(1) + ' unités'
$('turn-output').textContent = $('turn').value + '°'
$('eye-scale-output').textContent = Number($('eye-scale').value).toFixed(2) + '×'
$('spring-output').textContent = Number($('spring').value).toFixed(1)
$('preview-mode').textContent = 'expression ' + String(expression).padStart(2, '0')
$('status-expression').textContent = String(expression).padStart(2, '0')
}
function animate(now) {
const dt = Math.min((now - lastFrame) / 1000, 0.1)
lastFrame = now
const frequency = Number($('spring').value)
velocity += (-2 * frequency * velocity - frequency * frequency * (morph - 1)) * dt
morph += velocity * dt
if (!Number.isFinite(morph)) {
morph = 1
velocity = 0
}
render(now)
requestAnimationFrame(animate)
}
function scheduleBlink() {
clearTimeout(autoBlinkTimer)
if (!$('auto-blink').checked || !BLINK[state]) return
const cadence = BLINK[state]
const delay = cadence[0] + Math.random() * (cadence[1] - cadence[0])
autoBlinkTimer = setTimeout(() => {
blinkStart = performance.now()
scheduleBlink()
}, delay)
}
function scheduleExpression() {
clearTimeout(autoExpressionTimer)
if (!$('auto-expression').checked) return
const cadence = EXPR_CADENCE[state]
const delay = cadence[0] + Math.random() * (cadence[1] - cadence[0])
autoExpressionTimer = setTimeout(() => {
const pool = POOLS[state]
const alternatives = pool.filter(x => x !== expression)
selectExpression(
alternatives.length
? alternatives[Math.floor(Math.random() * alternatives.length)]
: pool[0]
)
scheduleExpression()
}, delay)
}
function setState(next) {
state = next
$('status-state').textContent = state
selectExpression(POOLS[state][0])
scheduleBlink()
scheduleExpression()
}
function renderStateDetail() {
$('state-title').textContent = selectedState
const group = Object.keys(GROUPS).find(k => GROUPS[k].includes(selectedState))
$('state-kind').textContent = group
$('expression-cadence').textContent = formatCadence(EXPR_CADENCE[selectedState])
$('blink-cadence').textContent = formatCadence(BLINK[selectedState])
$('state-explanation').innerHTML =
'<strong>Comportement :</strong> ' +
(STATE_NOTES[selectedState] ||
'Cet état combine son pool d’expressions, ses cadences et des mouvements secondaires spécifiques.')
$('state-pool').innerHTML = ''
POOLS[selectedState].forEach(index => {
const button = document.createElement('button')
button.type = 'button'
button.className = 'pool-button'
button.dataset.expression = String(index)
button.textContent = String(index).padStart(2, '0')
button.setAttribute('aria-pressed', String(index === expression))
button.addEventListener('click', () => selectExpression(index))
$('state-pool').appendChild(button)
})
}
EXPRESSIONS.forEach((_, index) => {
const button = document.createElement('button')
button.type = 'button'
button.className = 'expression-button'
button.textContent = String(index).padStart(2, '0')
button.setAttribute('aria-label', 'Expression ' + index)
button.setAttribute('aria-pressed', String(index === 0))
button.addEventListener('click', () => selectExpression(index))
$('expression-grid').appendChild(button)
})
Object.entries(GROUPS).forEach(([label, states]) => {
const group = document.createElement('section')
group.className = 'state-group'
const title = document.createElement('strong')
title.textContent = label
const buttons = document.createElement('div')
buttons.className = 'state-buttons'
states.forEach(name => {
const button = document.createElement('button')
button.type = 'button'
button.className = 'state-button'
button.textContent = name
button.setAttribute('aria-pressed', String(name === selectedState))
button.addEventListener('click', () => {
selectedState = name
root
.querySelectorAll('.state-button')
.forEach(b => b.setAttribute('aria-pressed', String(b === button)))
renderStateDetail()
})
buttons.appendChild(button)
})
group.append(title, buttons)
$('state-groups').appendChild(group)
})
SHAPES.forEach(data => {
const [name, x, y, sx, sy, eye, turnAt, radius] = data
const card = document.createElement('button')
card.type = 'button'
card.className = 'catalog-card' + (name === 'blob' ? ' selected' : '')
card.innerHTML =
'<div class="shape-icon"><i style="border-radius:' +
radius +
'"></i></div><strong>' +
name +
'</strong><div class="metrics"><span>x ' +
x +
'</span><span>y ' +
y +
'</span><span>sx ' +
sx +
'</span><span>sy ' +
sy +
'</span><span>eye ' +
eye +
'</span><span>turnAt ' +
(turnAt ? 'oui' : 'non') +
'</span></div>'
card.addEventListener('click', () => {
shape = name
$('status-shape').textContent = shape
root
.querySelectorAll('.catalog-card')
.forEach(c => c.classList.toggle('selected', c === card))
})
$('shape-grid').appendChild(card)
})
root.querySelectorAll('.tab').forEach(tab =>
tab.addEventListener('click', () => {
const name = tab.dataset.tab
root
.querySelectorAll('.tab')
.forEach(t => t.setAttribute('aria-selected', String(t === tab)))
root
.querySelectorAll('.tab-panel')
.forEach(p => (p.hidden = p.id !== 'tab-' + name))
})
)
;[
'gaze-x',
'gaze-y',
'turn',
'eye-scale',
'spring',
'show-guides',
'flip-x',
'emphasis',
].forEach(id => $(id).addEventListener('input', () => render(performance.now())))
$('blink-now').addEventListener('click', () => {
blinkStart = performance.now()
})
$('auto-blink').addEventListener('change', scheduleBlink)
$('auto-expression').addEventListener('change', scheduleExpression)
$('apply-state').addEventListener('click', () => {
setState(selectedState)
root.querySelector('[data-tab="lab"]').click()
})
$('spin-demo').addEventListener('click', () => {
if (spinFrame) cancelAnimationFrame(spinFrame)
const start = performance.now()
const spin = now => {
const t = Math.min((now - start) / 1200, 1)
$('turn').value = String(Math.sin(t * Math.PI * 2) * 85 * (1 - t))
if (t < 1) spinFrame = requestAnimationFrame(spin)
}
spinFrame = requestAnimationFrame(spin)
})
$('reset-all').addEventListener('click', () => {
$('gaze-x').value = '0'
$('gaze-y').value = '0'
$('turn').value = '0'
$('eye-scale').value = '1'
$('spring').value = '7'
$('show-guides').checked = false
$('flip-x').checked = false
$('emphasis').checked = false
setState('idle')
})
renderStateDetail()
scheduleBlink()
requestAnimationFrame(animate)
})()
</script>
<script>
;(() => {
const allowed = ['split', 'dock', 'focus']
const params = new URLSearchParams(location.search)
const initial = allowed.includes(params.get('variant'))
? params.get('variant')
: 'split'
const buttons = document.querySelectorAll('#grokbot-complete [data-layout]')
const apply = variant => {
document.body.dataset.variant = variant
buttons.forEach(button =>
button.setAttribute('aria-pressed', String(button.dataset.layout === variant))
)
const next = new URL(location.href)
next.searchParams.set('variant', variant)
history.replaceState(null, '', next)
}
buttons.forEach(button =>
button.addEventListener('click', () => apply(button.dataset.layout))
)
addEventListener('keydown', event => {
if (['INPUT', 'SELECT', 'TEXTAREA'].includes(document.activeElement?.tagName)) return
if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return
const current = allowed.indexOf(document.body.dataset.variant)
apply(
allowed[
(current + (event.key === 'ArrowRight' ? 1 : -1) + allowed.length) %
allowed.length
]
)
})
apply(initial)
})()
</script>
</div>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment