fox/storage/framework/views/56658335982d2ea0fa56f384a81...

466 lines
15 KiB
PHP
Executable File

<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="<?php echo e(csrf_token()); ?>">
<title>Fox Brain</title>
<?php echo app('Illuminate\Foundation\Vite')(['resources/css/app.css']); ?>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: #04060a;
color: #e2e8f0;
font-family: 'JetBrains Mono', 'Share Tech Mono', monospace;
min-height: 100vh;
overflow: hidden;
}
.brain-root {
display: grid;
grid-template-columns: 260px 1fr;
grid-template-rows: 48px 1fr;
height: 100vh;
}
/* ── Topbar ── */
.brain-topbar {
grid-column: 1 / -1;
display: flex;
align-items: center;
gap: 16px;
padding: 0 20px;
background: rgba(79,70,229,0.06);
border-bottom: 0.5px solid rgba(79,70,229,0.25);
}
.brain-title {
font-size: 11px;
letter-spacing: 3px;
color: rgba(165,180,252,0.9);
text-transform: uppercase;
}
.brain-topbar-nav {
margin-left: auto;
display: flex;
gap: 12px;
}
.brain-nav-link {
font-size: 9px;
letter-spacing: 1.5px;
color: rgba(255,255,255,0.3);
text-decoration: none;
padding: 4px 10px;
border: 0.5px solid rgba(255,255,255,0.1);
border-radius: 3px;
transition: all 0.15s;
}
.brain-nav-link:hover {
color: rgba(165,180,252,0.9);
border-color: rgba(79,70,229,0.4);
}
/* ── Sidebar ── */
.brain-sidebar {
padding: 20px 16px;
border-right: 0.5px solid rgba(79,70,229,0.2);
display: flex;
flex-direction: column;
gap: 12px;
overflow-y: auto;
}
.stat-card {
background: rgba(79,70,229,0.06);
border: 0.5px solid rgba(79,70,229,0.2);
border-radius: 8px;
padding: 14px 16px;
}
.stat-label {
font-size: 8px;
letter-spacing: 2px;
color: rgba(255,255,255,0.3);
text-transform: uppercase;
margin-bottom: 6px;
}
.stat-value {
font-size: 28px;
font-weight: 700;
color: rgba(165,180,252,0.95);
line-height: 1;
}
.stat-card.pending .stat-value {
color: #fbbf24;
}
.sidebar-section {
font-size: 8px;
letter-spacing: 2px;
color: rgba(255,255,255,0.2);
text-transform: uppercase;
padding: 8px 0 4px;
border-top: 0.5px solid rgba(255,255,255,0.05);
}
.legend {
display: flex;
flex-direction: column;
gap: 6px;
}
.legend-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 9px;
color: rgba(255,255,255,0.5);
}
.legend-dot {
width: 8px;
height: 8px;
border-radius: 50%;
flex-shrink: 0;
}
/* ── Graph Canvas ── */
.brain-graph-wrap {
position: relative;
overflow: hidden;
min-height: 0; /* grid fix: allow shrinking */
}
#fox-brain-graph {
position: absolute;
inset: 0;
}
#fox-brain-graph canvas {
display: block;
width: 100% !important;
height: 100% !important;
}
/* Node tooltip */
.brain-tooltip {
position: fixed;
background: #0d0d1a;
border: 0.5px solid rgba(79,70,229,0.4);
border-radius: 6px;
padding: 8px 12px;
font-size: 10px;
pointer-events: none;
z-index: 999;
max-width: 220px;
display: none;
box-shadow: 0 4px 20px rgba(0,0,0,0.6);
}
.brain-tooltip.visible { display: block; }
.tooltip-type {
font-size: 8px;
letter-spacing: 1.5px;
color: rgba(165,180,252,0.6);
text-transform: uppercase;
margin-bottom: 2px;
}
.tooltip-title {
color: #e2e8f0;
font-weight: 600;
margin-bottom: 4px;
}
.tooltip-content {
font-size: 9px;
color: rgba(255,255,255,0.4);
line-height: 1.5;
}
/* Empty state */
.brain-empty {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 10px;
color: rgba(255,255,255,0.15);
font-size: 11px;
letter-spacing: 2px;
pointer-events: none;
}
.brain-empty-icon {
font-size: 40px;
opacity: 0.2;
}
/* Scrollbar */
::-webkit-scrollbar { width: 4px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(79,70,229,0.3); border-radius: 2px; }
</style>
</head>
<body>
<div class="brain-root">
<header class="brain-topbar">
<div class="brain-title">F · O · X &nbsp;/&nbsp; BRAIN</div>
<nav class="brain-topbar-nav">
<a href="<?php echo e(route('hud')); ?>" class="brain-nav-link">HUD</a>
<a href="<?php echo e(route('dashboard')); ?>" class="brain-nav-link">DASHBOARD</a>
</nav>
</header>
<aside class="brain-sidebar">
<div class="stat-card">
<div class="stat-label">Memory Nodes</div>
<div class="stat-value"><?php echo e($nodes_count); ?></div>
</div>
<div class="stat-card">
<div class="stat-label">Connections</div>
<div class="stat-value"><?php echo e($edges_count); ?></div>
</div>
<div class="stat-card pending">
<div class="stat-label">Pending Review</div>
<div class="stat-value"><?php echo e($pending_count); ?></div>
</div>
<div class="sidebar-section">Node Types</div>
<div class="legend" id="brain-legend">
</div>
<div class="sidebar-section">Controls</div>
<div class="legend">
<div class="legend-item">Scroll — zoom</div>
<div class="legend-item">Drag node — move</div>
<div class="legend-item">Hover — details</div>
</div>
</aside>
<div class="brain-graph-wrap">
<div id="fox-brain-graph"></div>
<div class="brain-empty" id="brain-empty" style="display:none">
<div class="brain-empty-icon">◎</div>
<div>NO MEMORY NODES YET</div>
</div>
</div>
</div>
<div class="brain-tooltip" id="brain-tooltip">
<div class="tooltip-type" id="tt-type"></div>
<div class="tooltip-title" id="tt-title"></div>
<div class="tooltip-content" id="tt-content"></div>
</div>
<script>
(function(){
'use strict';
const TYPE_COLORS={user:'#818cf8',device:'#22d3ee',place:'#34d399',project:'#f59e0b',rule:'#f87171',skill:'#a78bfa',fact:'#94a3b8',preference:'#fb7185',person:'#60a5fa'};
function typeColor(t){return TYPE_COLORS[String(t||'').toLowerCase()]||'#94a3b8';}
function fibSphere(n,r){
const g=Math.PI*(3-Math.sqrt(5)),pts=[];
for(let i=0;i<n;i++){
const y=1-(i/(n-1))*2,rad=Math.sqrt(1-y*y),phi=g*i;
pts.push({x:Math.cos(phi)*rad*r,y:y*r,z:Math.sin(phi)*rad*r});
}
return pts;
}
function project(p,cx,cy,fov,ry,rx){
const cy2=Math.cos(ry),sy2=Math.sin(ry);
let x=p.x*cy2-p.z*sy2,z=p.x*sy2+p.z*cy2,y=p.y;
const cx2=Math.cos(rx),sx2=Math.sin(rx);
const y2=y*cx2-z*sx2,z2=y*sx2+z*cx2;
const d=fov/(fov+z2+300);
return{sx:cx+x*d,sy:cy+y2*d,depth:d,z:z2};
}
function buildLegend(nodes){
const el=document.getElementById('brain-legend');
if(!el)return;
const types=[...new Set(nodes.map(n=>n.type))];
el.innerHTML=types.map(t=>`<div class="legend-item"><div class="legend-dot" style="background:${typeColor(t)}"></div><span>${t}</span></div>`).join('');
}
function start(rawNodes,rawEdges){
const container=document.getElementById('fox-brain-graph');
if(!container)return;
const canvas=document.createElement('canvas');
canvas.style.cssText='position:absolute;inset:0;display:block;';
container.appendChild(canvas);
const ctx=canvas.getContext('2d');
let W=0,H=0,RADIUS=0,dpr=1;
function resize(){
const r=container.getBoundingClientRect();
W=r.width||window.innerWidth;
H=r.height||window.innerHeight;
dpr=window.devicePixelRatio||1;
canvas.width=Math.round(W*dpr);
canvas.height=Math.round(H*dpr);
canvas.style.width=W+'px';
canvas.style.height=H+'px';
ctx.setTransform(dpr,0,0,dpr,0,0);
RADIUS=Math.min(W,H)*0.32;
}
resize();
new ResizeObserver(resize).observe(container);
// Mesh points + proximity pairs
const MESH_N=420;
let meshPts=[],pairs=[];
function buildMesh(){
meshPts=fibSphere(MESH_N,RADIUS);
const LDIST=RADIUS*0.28;
pairs=[];
for(let i=0;i<MESH_N;i++){
let c=0;
for(let j=i+1;j<MESH_N&&c<5;j++){
const dx=meshPts[i].x-meshPts[j].x,dy=meshPts[i].y-meshPts[j].y,dz=meshPts[i].z-meshPts[j].z;
if(Math.sqrt(dx*dx+dy*dy+dz*dz)<LDIST){pairs.push([i,j]);c++;}
}
}
}
buildMesh();
// Memory nodes
const maxW=Math.max(...rawNodes.map(n=>n.weight),1);
const nodePts=rawNodes.length?fibSphere(rawNodes.length,RADIUS):[];
const nodeData=rawNodes.map((n,i)=>({...n,pt:nodePts[i],color:typeColor(n.type),r:7+(n.weight/maxW)*11}));
const edgeList=rawEdges.map(e=>{
const si=rawNodes.findIndex(n=>n.id===e.source),ti=rawNodes.findIndex(n=>n.id===e.target);
return(si>=0&&ti>=0)?{si,ti,strength:e.strength??1}:null;
}).filter(Boolean);
let rotY=0.4,rotX=0.12,velY=0,velX=0;
let isDrag=false,lx=0,ly=0,scale=1.0;
let mouseX=-9999,mouseY=-9999,hovered=-1;
const FOV=520;
const tooltip=document.getElementById('brain-tooltip');
const ttType=document.getElementById('tt-type');
const ttTitle=document.getElementById('tt-title');
const ttContent=document.getElementById('tt-content');
canvas.addEventListener('mousedown',e=>{isDrag=true;lx=e.clientX;ly=e.clientY;});
window.addEventListener('mouseup',()=>{isDrag=false;});
canvas.addEventListener('mousemove',e=>{
const rect=canvas.getBoundingClientRect();
mouseX=e.clientX-rect.left;mouseY=e.clientY-rect.top;
if(isDrag){velY+=(e.clientX-lx)*0.006;velX+=(e.clientY-ly)*0.006;lx=e.clientX;ly=e.clientY;}
if(tooltip){tooltip.style.left=Math.min(e.clientX+14,window.innerWidth-240)+'px';tooltip.style.top=(e.clientY-10)+'px';}
});
canvas.addEventListener('mouseleave',()=>{mouseX=-9999;mouseY=-9999;});
canvas.addEventListener('wheel',e=>{scale=Math.max(0.45,Math.min(1.8,scale-e.deltaY*0.001));},{passive:true});
let prevRadius=RADIUS;
function draw(){
requestAnimationFrame(draw);
// Rebuild mesh if radius changed after resize
if(Math.abs(RADIUS-prevRadius)>1){buildMesh();prevRadius=RADIUS;}
rotY+=isDrag?velY:0.0018+velY;
rotX+=velX;
velY*=0.91;velX*=0.91;
const s=scale,cx=W/2,cy=H/2;
ctx.fillStyle='#030508';
ctx.fillRect(0,0,W,H);
const proj=meshPts.map(p=>project({x:p.x*s,y:p.y*s,z:p.z*s},cx,cy,FOV,rotY,rotX));
// Lines
for(const[a,b]of pairs){
const pa=proj[a],pb=proj[b];
const avgZ=(pa.z+pb.z)/2;
const alpha=Math.max(0.03,0.03+((avgZ+RADIUS)/(RADIUS*2))*0.20);
ctx.beginPath();
ctx.moveTo(pa.sx,pa.sy);
ctx.lineTo(pb.sx,pb.sy);
ctx.strokeStyle=`rgba(255,255,255,${alpha})`;
ctx.lineWidth=0.6;
ctx.stroke();
}
// Dots
for(const p of proj){
const front=p.z>-RADIUS*0.05;
ctx.beginPath();
ctx.arc(p.sx,p.sy,front?1.4:0.7,0,Math.PI*2);
ctx.fillStyle=front?'rgba(255,255,255,0.65)':'rgba(255,255,255,0.15)';
ctx.fill();
}
// Node projections
const np=nodeData.map(n=>project({x:n.pt.x*s,y:n.pt.y*s,z:n.pt.z*s},cx,cy,FOV,rotY,rotX));
// Data edges
for(const e of edgeList){
const pa=np[e.si],pb=np[e.ti];
ctx.beginPath();ctx.moveTo(pa.sx,pa.sy);ctx.lineTo(pb.sx,pb.sy);
ctx.strokeStyle=`rgba(255,255,255,${0.30+e.strength*0.22})`;
ctx.lineWidth=1.2+e.strength*0.4;ctx.stroke();
}
// Memory nodes
let newHov=-1;
for(let i=0;i<nodeData.length;i++){
const n=nodeData[i],p=np[i];
const nr=n.r*s;
const dx=mouseX-p.sx,dy=mouseY-p.sy;
if(Math.sqrt(dx*dx+dy*dy)<nr+8)newHov=i;
const isHov=hovered===i,fr=nr*(isHov?1.6:1);
// Glow
const g=ctx.createRadialGradient(p.sx,p.sy,0,p.sx,p.sy,fr*3);
g.addColorStop(0,n.color+(isHov?'bb':'44'));
g.addColorStop(1,n.color+'00');
ctx.beginPath();ctx.arc(p.sx,p.sy,fr*3,0,Math.PI*2);ctx.fillStyle=g;ctx.fill();
// Circle
ctx.beginPath();ctx.arc(p.sx,p.sy,fr,0,Math.PI*2);
ctx.fillStyle=n.color+'cc';ctx.fill();
ctx.strokeStyle=n.color;ctx.lineWidth=1.8;ctx.stroke();
// Label
const fs=Math.max(9,Math.round(11*s));
ctx.font=(isHov?`bold ${fs}px`:`${fs}px`)+' "JetBrains Mono",monospace';
ctx.fillStyle=isHov?'#fff':'rgba(226,232,240,0.8)';
ctx.textAlign='center';ctx.textBaseline='top';
ctx.fillText(n.label,p.sx,p.sy+fr+6);
ctx.textBaseline='alphabetic';
}
if(newHov!==hovered){
hovered=newHov;
if(tooltip){
if(hovered>=0){
const d=nodeData[hovered];
ttType.textContent=String(d.type||'').toUpperCase();
ttTitle.textContent=d.label;
ttContent.textContent=d.content?d.content.slice(0,160)+(d.content.length>160?'…':''):`weight: ${d.weight}`;
tooltip.classList.add('visible');
}else{tooltip.classList.remove('visible');}
}
}
canvas.style.cursor=hovered>=0?'pointer':'default';
}
draw();
buildLegend(rawNodes);
}
// Load data and start
fetch('/fox/brain/graph')
.then(r=>r.json())
.then(d=>start(d.nodes||[],d.edges||[]))
.catch(()=>{const e=document.getElementById('brain-empty');if(e)e.style.display='flex';});
})();
</script>
</body>
</html>
<?php /**PATH /var/www/resources/views/fox/brain/index.blade.php ENDPATH**/ ?>