v4
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
/* DONA_REPLY_FLOATING_V1 — Les réponses textuelles ne recouvrent plus les animations. */
|
||||
/* La carte occupe une bande latérale, sans voile de fond ni blocage de la scène. */
|
||||
/* La classe de l’écran principal est synchronisée en JS. */
|
||||
body.dona-family-v1 .alfred-main-v1.dona-reply-background-visible.is-focused .av-voice-hero,
|
||||
body.dona-family-v1 .alfred-main-v1.dona-reply-background-visible.is-focused .dona-art-center {
|
||||
opacity:1!important; visibility:visible!important; pointer-events:none!important;
|
||||
}
|
||||
body.dona-family-v1 .alfred-main-v1.dona-reply-background-visible.is-focused .dona-art-center > * {
|
||||
visibility:visible!important;
|
||||
}
|
||||
|
||||
body.dona-family-v1.dona-holo-v1.alfred-glass-theme #stage.dona-reply-compact:not(.dona-reply-expanded) {
|
||||
position:fixed!important;
|
||||
left:auto!important;
|
||||
top:clamp(140px,24vh,285px)!important;
|
||||
right:clamp(16px,2.5vw,44px)!important;
|
||||
bottom:auto!important;
|
||||
transform:none!important;
|
||||
width:min(410px,calc(100vw - 32px))!important;
|
||||
max-width:calc(100vw - 32px)!important;
|
||||
max-height:min(65dvh,580px)!important;
|
||||
min-height:0!important;
|
||||
padding:48px 15px 15px!important;
|
||||
overflow:auto!important;
|
||||
display:block!important;
|
||||
border:1px solid rgba(149,177,232,.36)!important;
|
||||
border-radius:22px!important;
|
||||
background:linear-gradient(145deg,rgba(12,20,43,.88),rgba(19,20,39,.84))!important;
|
||||
box-shadow:0 18px 50px rgba(0,0,0,.38),inset 0 1px rgba(255,255,255,.05)!important;
|
||||
-webkit-backdrop-filter:blur(10px)!important;
|
||||
backdrop-filter:blur(10px)!important;
|
||||
z-index:28!important;
|
||||
align-items:stretch!important;
|
||||
justify-content:flex-start!important;
|
||||
}
|
||||
body.dona-family-v1.dona-holo-v1 #stage.dona-reply-compact:not(.dona-reply-expanded) #content {
|
||||
width:100%!important;
|
||||
max-width:100%!important;
|
||||
min-width:0!important;
|
||||
max-height:none!important;
|
||||
overflow:visible!important;
|
||||
margin:0!important;
|
||||
}
|
||||
body.dona-family-v1.dona-holo-v1 #stage.dona-reply-compact:not(.dona-reply-expanded) .av-reponse-actions {
|
||||
top:10px!important;right:10px!important;
|
||||
}
|
||||
body.dona-family-v1.dona-holo-v1 #stage.dona-reply-compact:not(.dona-reply-expanded) .av-reponse-close {
|
||||
width:33px!important;min-width:33px!important;min-height:33px!important;
|
||||
padding:6px!important;border-radius:11px!important;
|
||||
}
|
||||
body.dona-family-v1.dona-holo-v1 #stage.dona-reply-compact:not(.dona-reply-expanded) .dh-response {
|
||||
display:flex!important;flex-direction:column!important;gap:0!important;
|
||||
margin:0!important;max-width:100%!important;
|
||||
}
|
||||
body.dona-family-v1.dona-holo-v1 #stage.dona-reply-compact:not(.dona-reply-expanded) .dh-primary {
|
||||
padding:4px 2px 2px!important;
|
||||
min-height:0!important;
|
||||
border:0!important;border-radius:0!important;
|
||||
box-shadow:none!important;background:transparent!important;
|
||||
gap:10px!important;
|
||||
}
|
||||
body.dona-family-v1.dona-holo-v1 #stage.dona-reply-compact:not(.dona-reply-expanded) .dh-primary::before,
|
||||
body.dona-family-v1.dona-holo-v1 #stage.dona-reply-compact:not(.dona-reply-expanded) .dh-response::after {
|
||||
display:none!important;
|
||||
}
|
||||
body.dona-family-v1.dona-holo-v1 #stage.dona-reply-compact:not(.dona-reply-expanded) .dh-kicker {
|
||||
font-size:10px!important;letter-spacing:.09em!important;
|
||||
}
|
||||
body.dona-family-v1.dona-holo-v1 #stage.dona-reply-compact:not(.dona-reply-expanded) .dh-headline {
|
||||
font-size:clamp(17px,1.45vw,21px)!important;line-height:1.25!important;
|
||||
}
|
||||
body.dona-family-v1.dona-holo-v1 #stage.dona-reply-compact:not(.dona-reply-expanded) .dh-excerpt {
|
||||
font-size:13px!important;line-height:1.52!important;
|
||||
display:-webkit-box!important;-webkit-box-orient:vertical!important;-webkit-line-clamp:4!important;
|
||||
line-clamp:4!important;overflow:hidden!important;
|
||||
white-space:normal!important;
|
||||
}
|
||||
body.dona-family-v1.dona-holo-v1 #stage.dona-reply-compact:not(.dona-reply-expanded) .dh-facts {
|
||||
display:none!important;
|
||||
}
|
||||
body.dona-family-v1.dona-holo-v1 #stage.dona-reply-compact:not(.dona-reply-expanded) .dh-more {
|
||||
min-height:38px!important;padding:9px 12px!important;font-size:12px!important;
|
||||
margin-top:5px!important;
|
||||
}
|
||||
/* Mode développé : le contenu et les cartes d'origine réapparaissent.
|
||||
L'utilisateur choisit volontairement d'occuper l'écran. */
|
||||
body.dona-family-v1.dona-holo-v1.alfred-glass-theme #stage.dona-reply-compact.dona-reply-expanded {
|
||||
position:fixed!important;
|
||||
left:clamp(8px,2vw,30px)!important;right:clamp(8px,2vw,30px)!important;
|
||||
top:clamp(85px,10vh,125px)!important;bottom:clamp(95px,9vh,120px)!important;
|
||||
width:auto!important;max-width:none!important;max-height:none!important;
|
||||
padding:clamp(62px,8vh,92px) 20px 24px!important;
|
||||
transform:none!important;overflow:auto!important;
|
||||
background:linear-gradient(145deg,rgba(3,8,20,.97),rgba(10,16,35,.97))!important;
|
||||
border:1px solid rgba(146,172,231,.38)!important;z-index:30!important;
|
||||
}
|
||||
/* L'état visuel compact ne s'applique pas aux cartes riches (météo, vidéo, tableaux...). */
|
||||
@media (max-width:1050px) {
|
||||
body.dona-family-v1.dona-holo-v1.alfred-glass-theme #stage.dona-reply-compact:not(.dona-reply-expanded) {
|
||||
left:clamp(12px,3vw,28px)!important;
|
||||
right:clamp(12px,3vw,28px)!important;
|
||||
top:auto!important;
|
||||
bottom:clamp(110px,12vh,160px)!important;
|
||||
width:auto!important;
|
||||
max-width:none!important;
|
||||
max-height:min(31dvh,275px)!important;
|
||||
padding:43px 14px 12px!important;
|
||||
}
|
||||
}
|
||||
@media (max-width:600px) {
|
||||
body.dona-family-v1.dona-holo-v1.alfred-glass-theme #stage.dona-reply-compact:not(.dona-reply-expanded) {
|
||||
left:9px!important;right:9px!important;
|
||||
bottom:clamp(95px,13vh,125px)!important;
|
||||
border-radius:15px!important;max-height:29dvh!important;
|
||||
}
|
||||
body.dona-family-v1.dona-holo-v1 #stage.dona-reply-compact:not(.dona-reply-expanded) .dh-excerpt {
|
||||
-webkit-line-clamp:2!important;line-clamp:2!important;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/* Dona — vagues vocales, sélection réversible sans désinstaller. */
|
||||
body.dona-family-v1.dona-waves-selected .dona-organic-wrap {
|
||||
width:min(93vw,1400px)!important;
|
||||
height:clamp(155px,28vh,330px)!important;
|
||||
min-width:0!important;min-height:155px!important;
|
||||
max-width:100%!important;filter:none!important;
|
||||
overflow:visible!important;
|
||||
}
|
||||
body.dona-family-v1.dona-waves-selected #donaOrganicCanvas,
|
||||
body.dona-family-v1.dona-waves-selected .dona-orb-reflection {display:none!important}
|
||||
body.dona-family-v1 .dona-organic-wrap #donaWavesCanvas {
|
||||
display:none;position:absolute;inset:0;width:100%;height:100%;pointer-events:none;
|
||||
}
|
||||
body.dona-family-v1.dona-waves-selected .dona-organic-wrap #donaWavesCanvas {display:block}
|
||||
body.dona-family-v1.dona-waves-selected .dona-art-name {margin-top:-5px!important}
|
||||
.dona-waves-menu-title{color:#c7b8cc;font-size:11px;letter-spacing:.07em;padding:10px 10px 5px;text-transform:uppercase}
|
||||
.dv92-menu-entry.dona-waves-option[aria-checked="true"] {background:rgba(94,148,208,.19);color:#ffe1b8}
|
||||
.dona-waves-option .dona-waves-choice-icon{width:22px;min-width:22px;text-align:center;font-size:18px}
|
||||
@media(max-width:900px){
|
||||
body.dona-family-v1.dona-waves-selected .dona-organic-wrap{height:clamp(145px,23vh,240px)!important;min-height:145px!important;width:min(96vw,740px)!important}
|
||||
body.dona-family-v1.dona-waves-selected .dona-art-name{font-size:clamp(32px,8vw,50px)}
|
||||
}
|
||||
|
||||
/* DONA_SCULPTURE_V11 — Visuel organique plus concentré, mêmes events Piper. */
|
||||
body.dona-family-v1.dona-sculpture-selected .dona-organic-wrap {
|
||||
width:min(94vw,990px)!important;
|
||||
height:clamp(210px,39vh,440px)!important;
|
||||
min-height:210px!important;
|
||||
}
|
||||
@media(max-width:900px){
|
||||
body.dona-family-v1.dona-sculpture-selected .dona-organic-wrap{
|
||||
width:min(97vw,820px)!important;height:clamp(180px,28vh,295px)!important;min-height:180px!important;
|
||||
}
|
||||
}
|
||||
@@ -83,6 +83,8 @@
|
||||
if(k===0)ctx.moveTo(x,y);else ctx.lineTo(x,y);
|
||||
}ctx.closePath();}
|
||||
function frame(now){raf=requestAnimationFrame(frame);if(document.hidden||now-last<30)return;last=now;
|
||||
// DONA_WAVES_V1 : ne pas dessiner une orbe cachée; bascule possible à chaud.
|
||||
if(window.DonaWaves && window.DonaWaves.isActive())return;
|
||||
const mode=root.dataset.familyMode||'idle';const speed=mode==='listening'?1.7:mode==='thinking'?1.38:mode==='speaking'?1.5:.75;
|
||||
if(!reduce)phase+=.024*speed;
|
||||
ctx.clearRect(0,0,w,h);ctx.save();ctx.translate(w/2,h/2);const r=Math.min(w,h)*.33;
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/* DONA_REPLY_FLOATING_V1: carte texte latérale sans recouvrir le moteur d'animations. */
|
||||
(() => {
|
||||
'use strict';
|
||||
if (window.__donaReplyFloatingV1) return;
|
||||
window.__donaReplyFloatingV1 = true;
|
||||
|
||||
function setup() {
|
||||
const main = document.getElementById('alfredMainV1');
|
||||
const stage = document.getElementById('stage');
|
||||
const content = document.getElementById('content');
|
||||
if (!main || !stage || !content) return;
|
||||
|
||||
let queued = false;
|
||||
function isRich() {
|
||||
// Les vues calendrier/météo, cartes, vidéo, images et modules spécialisés
|
||||
// conservent la grande scène et tous leurs contrôles.
|
||||
if (content.classList.contains('alfred-view')) return true;
|
||||
if (content.querySelector('.alfred-view,.view-pane,.cards,.hero,iframe,video,canvas,img,table,.dona-dynamic-grid,.dona-dynamic-dashboard,[data-dona-rich]')) return true;
|
||||
if (content.querySelector('.dh-response')) return false;
|
||||
const nodes = [...content.children];
|
||||
return !nodes.length || nodes.some(n => !['H1','H2','H3','P','PRE','BLOCKQUOTE'].includes(n.tagName));
|
||||
}
|
||||
function update() {
|
||||
queued = false;
|
||||
const focused = main.classList.contains('is-focused');
|
||||
const compact = focused && !isRich();
|
||||
const expanded = compact && content.querySelector('.dh-more[aria-expanded="true"]') !== null;
|
||||
stage.classList.toggle('dona-reply-compact', compact);
|
||||
stage.classList.toggle('dona-reply-expanded', expanded);
|
||||
main.classList.toggle('dona-reply-background-visible', compact && !expanded);
|
||||
stage.setAttribute('data-dona-reply-mode', compact ? (expanded ? 'expanded':'compact') : 'full');
|
||||
}
|
||||
function queue() {
|
||||
if (queued) return;
|
||||
queued = true;
|
||||
requestAnimationFrame(update);
|
||||
}
|
||||
new MutationObserver(queue).observe(content, {childList:true,subtree:true,attributes:true,attributeFilter:['aria-expanded','class']});
|
||||
new MutationObserver(queue).observe(main, {attributes:true,attributeFilter:['class']});
|
||||
// Le renderer transforme parfois la réponse brute en carte au frame suivant.
|
||||
window.alfredSocket?.on('alfred_render', queue);
|
||||
stage.addEventListener('click', e => {
|
||||
if (e.target.closest('.dh-more')) setTimeout(queue, 0);
|
||||
});
|
||||
queue();
|
||||
}
|
||||
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', setup, {once:true});
|
||||
else setup();
|
||||
})();
|
||||
@@ -0,0 +1,258 @@
|
||||
/* DONA_SCULPTURE_V11 */
|
||||
/* Dona Vagues Vocales V1 — Canvas 2D, amplitude PCM Piper envoyée par Socket.IO.
|
||||
Le mode orb conserve l'ancien canvas et son animation.
|
||||
Aucune capture micro et aucun audio client ne sont nécessaires. */
|
||||
(() => {
|
||||
'use strict';
|
||||
if (window.DonaWaves) return;
|
||||
const KEY='dona_visual_voice_v1';
|
||||
let choice='waves';
|
||||
try {if (['waves','orb','sculpture'].includes(localStorage.getItem(KEY)))choice=localStorage.getItem(KEY);}catch (_) {}
|
||||
const API={isActive:()=>choice!=='orb',select:selectMode,getChoice:()=>choice};
|
||||
window.DonaWaves=API;
|
||||
document.body.classList.toggle('dona-waves-selected', choice!=='orb');
|
||||
document.body.classList.toggle('dona-sculpture-selected',choice==='sculpture');
|
||||
function selectMode(next){
|
||||
if(!['waves','orb','sculpture'].includes(next))return;
|
||||
choice=next;
|
||||
document.body.classList.toggle('dona-waves-selected',choice!=='orb');
|
||||
document.body.classList.toggle('dona-sculpture-selected',choice==='sculpture');
|
||||
try{localStorage.setItem(KEY,choice);}catch(_){}
|
||||
syncMenu();
|
||||
}
|
||||
function syncMenu(){
|
||||
const menu=document.getElementById('dv92ToolsMenu');if(!menu)return;
|
||||
for(const el of menu.querySelectorAll('[data-dona-visual]')){
|
||||
const active=el.dataset.donaVisual===choice;
|
||||
el.setAttribute('aria-checked',String(active));
|
||||
el.querySelector('.dona-waves-choice-icon').textContent=active?'◉':'○';
|
||||
}
|
||||
}
|
||||
function addMenuControls(){
|
||||
const menu=document.getElementById('dv92ToolsMenu');
|
||||
if(!menu||menu.querySelector('#donaWavesMenuTitle'))return;
|
||||
const title=document.createElement('div');title.id='donaWavesMenuTitle';
|
||||
title.className='dona-waves-menu-title';title.textContent='Animation centrale';
|
||||
menu.append(title);
|
||||
for(const [mode,label] of [['waves','Vagues horizontales (Piper)'],['sculpture','Sculpture de vagues (Piper)'],['orb','Orbe d’origine']]){
|
||||
const b=document.createElement('button');b.type='button';
|
||||
b.className='dv92-menu-entry dona-waves-option';b.dataset.donaVisual=mode;
|
||||
b.setAttribute('role','menuitemradio');
|
||||
const mark=document.createElement('span');mark.className='dona-waves-choice-icon';
|
||||
b.append(mark,document.createTextNode(label));
|
||||
b.addEventListener('click',()=>{
|
||||
selectMode(mode);
|
||||
menu.hidden=true;
|
||||
document.getElementById('dv92Hamburger')?.setAttribute('aria-expanded','false');
|
||||
});
|
||||
menu.append(b);
|
||||
}
|
||||
syncMenu();
|
||||
}
|
||||
let started=false;
|
||||
function init(){
|
||||
if(started)return true;
|
||||
const root=document.getElementById('alfredMainV1');
|
||||
const wrap=root?.querySelector('.dona-organic-wrap');
|
||||
if(!wrap)return false;
|
||||
started=true;
|
||||
const canvas=document.createElement('canvas');canvas.id='donaWavesCanvas';
|
||||
canvas.setAttribute('role','img');canvas.setAttribute('aria-label','Vagues animées de Dona réagissant à la voix Piper');
|
||||
wrap.append(canvas);
|
||||
const ctx=canvas.getContext('2d',{alpha:true});if(!ctx)return true;
|
||||
const reduce=window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches||false;
|
||||
let w=0,h=0,dpr=1,mode=String(root.dataset.familyMode||'idle');
|
||||
let phase=0,smoothed=.02,pcm=0,lastPCM=0,voiceFinished=false,then=0,raf=0;
|
||||
const socket=window.alfredSocket;
|
||||
socket?.on('alfred_state',data=>{
|
||||
const next=String(data?.mode||'idle').toLowerCase();
|
||||
if(next==='speaking'&&mode!=='speaking')voiceFinished=false;
|
||||
mode=next;
|
||||
});
|
||||
socket?.on('dona_piper_level',data=>{
|
||||
const value=Number(data?.level);
|
||||
if(!Number.isFinite(value))return;
|
||||
pcm=Math.max(0,Math.min(1,value));
|
||||
lastPCM=performance.now();
|
||||
});
|
||||
socket?.on('alfred_tts_finished',()=>{pcm=0;voiceFinished=true;});
|
||||
const ro=typeof ResizeObserver!=='undefined'?new ResizeObserver(resize):null;
|
||||
ro?.observe(wrap);window.addEventListener('resize',resize,{passive:true});
|
||||
function resize(){
|
||||
const box=wrap.getBoundingClientRect();
|
||||
if(!box.width||!box.height)return;
|
||||
const ratio=Math.min(window.devicePixelRatio||1,1.7);
|
||||
const nw=Math.round(box.width*ratio),nh=Math.round(box.height*ratio);
|
||||
if(nw===canvas.width&&nh===canvas.height)return;
|
||||
w=box.width;h=box.height;dpr=ratio;
|
||||
canvas.width=nw;canvas.height=nh;ctx.setTransform(ratio,0,0,ratio,0,0);
|
||||
}
|
||||
// DONA_SCULPTURE_V11 : membranes de lumière, 2D pur, animées par PCM Piper.
|
||||
function drawSculpture(now){
|
||||
const cx=w*.5, cy=h*.51;
|
||||
const R=Math.min(w*.23,h*.30);
|
||||
const strength=Math.min(1,smoothed);
|
||||
const phi=phase*.74;
|
||||
ctx.save();
|
||||
// Lueur ambiante derrière les rubans, sans rectangle de fond.
|
||||
let halo=ctx.createRadialGradient(cx,cy,R*.12,cx,cy,R*2.25);
|
||||
halo.addColorStop(0,'rgba(255,188,186,.13)');
|
||||
halo.addColorStop(.39,'rgba(120,82,249,.12)');
|
||||
halo.addColorStop(1,'rgba(12,43,138,0)');
|
||||
ctx.fillStyle=halo;ctx.fillRect(0,0,w,h);
|
||||
const shell=(layer,behind)=>{
|
||||
const n=104, z=layer/8;
|
||||
const width=Math.min(w*.40,h*1.16)*(1-z*.34);
|
||||
const rise=h*(.225+.07*Math.sin(layer*.87+phi*.25))*(1-z*.24);
|
||||
const yShift=h*(.015*Math.sin(layer*1.8+phi*.18));
|
||||
const steps=[];
|
||||
for(let i=0;i<=n;i++){
|
||||
const t=i/n, x=cx+(t-.5)*width*2;
|
||||
const env=Math.pow(Math.max(0,Math.sin(Math.PI*t)),.65);
|
||||
const y=cy+yShift+Math.sin(t*Math.PI*(2.7+layer*.16)+phi*.5+layer*.63)*rise*env
|
||||
+Math.cos(t*Math.PI*4.8-phi*.38+layer)*rise*.29*env;
|
||||
steps.push({x,y,t,env});
|
||||
}
|
||||
const thickness=h*(.21+.045*Math.sin(layer*1.24+phi*.1));
|
||||
const g=ctx.createLinearGradient(cx-width,cy,cx+width,cy);
|
||||
g.addColorStop(0,'rgba(26,119,250,.60)');
|
||||
g.addColorStop(.33,'rgba(104,98,253,.58)');
|
||||
g.addColorStop(.59,'rgba(249,167,209,.70)');
|
||||
g.addColorStop(1,'rgba(252,192,123,.62)');
|
||||
ctx.beginPath();ctx.moveTo(steps[0].x,steps[0].y);
|
||||
for(let i=1;i<steps.length;i++)ctx.lineTo(steps[i].x,steps[i].y);
|
||||
for(let i=steps.length-1;i>=0;i--){
|
||||
const p=steps[i];
|
||||
ctx.lineTo(p.x,p.y+thickness*p.env*(.8+strength*.44));
|
||||
}
|
||||
ctx.closePath();ctx.globalAlpha=(behind?.19:.30)+strength*.09;
|
||||
ctx.fillStyle=g;ctx.fill();ctx.globalAlpha=.55+strength*.25;
|
||||
ctx.beginPath();ctx.moveTo(steps[0].x,steps[0].y);
|
||||
for(let i=1;i<steps.length;i++)ctx.lineTo(steps[i].x,steps[i].y);
|
||||
ctx.lineWidth=1.1+(layer%3)*.35+strength;
|
||||
ctx.strokeStyle=g;ctx.shadowBlur=behind?11:21;
|
||||
ctx.shadowColor=layer%2?'#f2a1bc':'#5faaff';ctx.stroke();ctx.shadowBlur=0;
|
||||
// Fines nervures / maillage, effet étoffe lumineuse.
|
||||
if(layer%2===0){
|
||||
ctx.globalAlpha=.13+strength*.08;
|
||||
for(let i=6;i<n;i+=7){
|
||||
const p=steps[i],x=p.x,y=p.y;
|
||||
ctx.beginPath();ctx.moveTo(x,y);
|
||||
ctx.lineTo(x+Math.sin(layer+phi)*5,y+thickness*p.env);
|
||||
ctx.lineWidth=.7;ctx.strokeStyle=layer%4?'#b9adff':'#ffcaad';ctx.stroke();
|
||||
}
|
||||
}
|
||||
ctx.globalAlpha=1;
|
||||
};
|
||||
for(let layer=7;layer>=4;layer--)shell(layer,true);
|
||||
// Noyau irisé : diaphragme vivant, se dilate sur les syllabes.
|
||||
const pulse=1+strength*.20+.035*Math.sin(phi*1.05);
|
||||
const r=R*pulse;
|
||||
const core=ctx.createRadialGradient(cx-r*.19,cy-r*.26,r*.1,cx,cy,r*1.15);
|
||||
core.addColorStop(0,'rgba(255,214,214,.90)');
|
||||
core.addColorStop(.26,'rgba(244,147,194,.78)');
|
||||
core.addColorStop(.53,'rgba(117,113,244,.82)');
|
||||
core.addColorStop(.82,'rgba(41,125,253,.72)');
|
||||
core.addColorStop(1,'rgba(37,135,245,.025)');
|
||||
ctx.fillStyle=core;ctx.beginPath();
|
||||
for(let i=0;i<=180;i++){
|
||||
const a=i/180*Math.PI*2;
|
||||
const rad=r*(1+.12*Math.sin(4*a+phi*.5)+.085*Math.cos(3*a-phi*.3));
|
||||
const x=cx+Math.cos(a)*rad,y=cy+Math.sin(a)*rad*.82;
|
||||
if(!i)ctx.moveTo(x,y);else ctx.lineTo(x,y);
|
||||
}
|
||||
ctx.closePath();ctx.shadowColor='#b696ff';ctx.shadowBlur=32+strength*25;ctx.fill();ctx.shadowBlur=0;
|
||||
for(let layer=3;layer>=0;layer--)shell(layer,false);
|
||||
// Poussière irisée légère dans le volume.
|
||||
for(let i=0;i<70;i++){
|
||||
const t=(i*.61803398875)%1;
|
||||
const x=cx+(t-.5)*w*.70;
|
||||
const env=Math.sin(Math.PI*t);
|
||||
const y=cy+Math.cos(i*1.71+phi*.15)*h*.27*env;
|
||||
ctx.globalAlpha=(.08+strength*.21)*env;
|
||||
ctx.fillStyle=i%3?'#accaff':'#ffccbd';
|
||||
ctx.beginPath();ctx.arc(x,y,.65+(i%4)*.22,0,Math.PI*2);ctx.fill();
|
||||
}
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
function draw(now){
|
||||
raf=requestAnimationFrame(draw);
|
||||
if(choice==='orb'||document.hidden||now-then<30)return;
|
||||
then=now;
|
||||
resize();if(!w||!h)return;
|
||||
const speaking=mode==='speaking'&&!voiceFinished;
|
||||
const current=(now-lastPCM<240&&speaking)?pcm:0;
|
||||
const base=mode==='listening'?.16:mode==='thinking'?.115:speaking?.07:.025;
|
||||
const target=Math.max(base,current*.88);
|
||||
smoothed+=(target-smoothed)*(target>smoothed?.35:.19);
|
||||
if(!reduce)phase+=mode==='listening'?.054:mode==='thinking'?.034:speaking?.047:.018;
|
||||
ctx.clearRect(0,0,w,h);
|
||||
if(choice==='sculpture'){drawSculpture(now);return;}
|
||||
const mid=h*.51, amplitude=h*(.245+smoothed*.35);
|
||||
const palette=[
|
||||
['#1362ff','#11c8fc','#6b56e9'],
|
||||
['#1e92ef','#9274ff','#e47dbd'],
|
||||
['#6c4bd9','#ef86b5','#ffd29b'],
|
||||
['#4a5ad8','#ffb3c2','#ffc282'],
|
||||
['#16b8ed','#8c66f5','#f596b5'],
|
||||
['#7854e5','#d891ed','#fdad8b']
|
||||
];
|
||||
// Contours en membranes translucides, superposés pour former une onde lumineuse.
|
||||
for(let layer=0;layer<palette.length;layer++){
|
||||
const [left,center,right]=palette[layer];
|
||||
const m=layer*1.07;
|
||||
const points=[];
|
||||
for(let x=0;x<=w+5;x+=5){
|
||||
const nx=x/w;
|
||||
const envelope=Math.pow(Math.max(0,Math.sin(Math.PI*nx)),.75);
|
||||
const s1=Math.sin(nx*Math.PI*(2.55+m*.24)+phase*(.70+m*.04)+m*.79);
|
||||
const s2=Math.sin(nx*Math.PI*(5.0-m*.17)-phase*(.42+m*.02)+m*1.18);
|
||||
const y=mid+(s1*.77+s2*.23)*amplitude*envelope
|
||||
+Math.cos(nx*Math.PI*2.6+phase*.28+m)*h*.014;
|
||||
points.push([x,y]);
|
||||
}
|
||||
const gradient=ctx.createLinearGradient(0,0,w,0);
|
||||
gradient.addColorStop(0,left);gradient.addColorStop(.5,center);gradient.addColorStop(1,right);
|
||||
ctx.beginPath();ctx.moveTo(0,mid);
|
||||
for(const [x,y] of points)ctx.lineTo(x,y);
|
||||
const thickness=h*(.11+.018*(layer%3)+.09*smoothed);
|
||||
for(let i=points.length-1;i>=0;i--){const [x,y]=points[i];ctx.lineTo(x,y+thickness);}
|
||||
ctx.closePath();ctx.fillStyle=gradient;ctx.globalAlpha=.095+(layer%3)*.058+smoothed*.1;ctx.fill();
|
||||
ctx.beginPath();points.forEach(([x,y],i)=>i?ctx.lineTo(x,y):ctx.moveTo(x,y));
|
||||
ctx.lineWidth=(layer%2?1.5:1.9)+smoothed*1.35;
|
||||
ctx.strokeStyle=gradient;ctx.globalAlpha=.60+smoothed*.30;
|
||||
ctx.shadowBlur=15+smoothed*25;ctx.shadowColor=center;ctx.stroke();
|
||||
ctx.shadowBlur=0;ctx.globalAlpha=1;
|
||||
}
|
||||
// Lueur centrale très diffuse, avec énergie liée à l'amplitude Piper.
|
||||
const glow=ctx.createRadialGradient(w*.5,mid,0,w*.5,mid,w*.34);
|
||||
glow.addColorStop(0,`rgba(255,194,205,${.06+smoothed*.18})`);
|
||||
glow.addColorStop(.45,`rgba(107,99,255,${.025+smoothed*.045})`);
|
||||
glow.addColorStop(1,'rgba(56,138,244,0)');
|
||||
ctx.fillStyle=glow;ctx.fillRect(0,0,w,h);
|
||||
// Petits points lumineux déterministes, très discrets au repos.
|
||||
for(let i=0;i<22;i++){
|
||||
const nx=(i*0.61803398875)%1,ny=.5+.33*Math.sin(i*2.18+phase*.14);
|
||||
const x=nx*w,y=ny*h;
|
||||
ctx.globalAlpha=(.11+smoothed*.37)*Math.pow(Math.sin(nx*Math.PI),2);
|
||||
ctx.fillStyle=i%3===0?'#ffb5cc':'#83ceff';ctx.beginPath();ctx.arc(x,y,.8+(i%3)*.35,0,Math.PI*2);ctx.fill();
|
||||
}
|
||||
ctx.globalAlpha=1;
|
||||
}
|
||||
resize();raf=requestAnimationFrame(draw);
|
||||
window.addEventListener('pagehide',()=>{cancelAnimationFrame(raf);ro?.disconnect();},{once:true});
|
||||
return true;
|
||||
}
|
||||
let attempts=0;
|
||||
function ready(){
|
||||
if(!init()&&attempts++<50)setTimeout(ready,120);
|
||||
addMenuControls();
|
||||
const menu=document.getElementById('dv92ToolsMenu');
|
||||
if(menu&&!menu.dataset.donaWavesObserved){
|
||||
menu.dataset.donaWavesObserved='1';
|
||||
new MutationObserver(()=>addMenuControls()).observe(menu,{childList:true});
|
||||
}
|
||||
}
|
||||
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',ready,{once:true});else ready();
|
||||
})();
|
||||
Reference in New Issue
Block a user