agent-Specialization/static/liquid-glass-kube.html
JOJO 2f75c1c8bb feat: stable version before virtual monitor timing fix
Current status includes:
- Virtual monitor surface and components
- Monitor store for state management
- Tool call animations and transitions
- Liquid glass shader integration

Known issue to fix: Tool status display timing - "正在xx" appears
after tool execution completes instead of when tool call starts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-13 17:12:12 +08:00

165 lines
6.3 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Liquid GlassKube 方案测验)</title>
<style>
* {
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100vh;
font-family: 'SF Pro Display', 'Helvetica Neue', Arial, sans-serif;
background: radial-gradient(circle at top, #06080f, #08040d 65%, #010005);
color: rgba(255, 255, 255, 0.85);
display: flex;
align-items: center;
justify-content: center;
padding: clamp(16px, 5vw, 60px);
}
.stage {
position: relative;
width: min(1100px, 100%);
height: clamp(480px, 65vh, 640px);
border-radius: 32px;
overflow: hidden;
border: 1px solid rgba(255, 255, 255, 0.08);
background: linear-gradient(135deg, rgba(255, 255, 255, 0.04), rgba(255, 255, 255, 0)),
#04030b;
}
.stage img {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
filter: saturate(1.2);
}
.glass {
position: absolute;
width: 260px;
height: 180px;
border-radius: 90px;
cursor: grab;
box-shadow:
0 18px 55px rgba(5, 5, 25, 0.45),
inset 0 1px 0 rgba(255, 255, 255, 0.65),
inset 0 -24px 35px rgba(0, 0, 0, 0.55);
backdrop-filter: url(#magnifying-glass-filter);
-webkit-backdrop-filter: url(#magnifying-glass-filter);
touch-action: none;
}
.info {
position: absolute;
left: clamp(20px, 5vw, 48px);
bottom: clamp(20px, 5vw, 48px);
max-width: 320px;
background: rgba(0, 0, 0, 0.45);
padding: 18px 22px;
border-radius: 18px;
border: 1px solid rgba(255, 255, 255, 0.12);
backdrop-filter: blur(20px);
}
.info h1 {
font-size: 28px;
margin: 0 0 8px;
}
.info p {
margin: 0;
color: rgba(255, 255, 255, 0.7);
line-height: 1.6;
}
</style>
</head>
<body>
<div class="stage" id="stage">
<img src="https://images.unsplash.com/photo-1519681393784-d120267933ba?auto=format&fit=crop&w=1800&q=80" alt="bg" />
<div class="glass" id="glass"></div>
<div class="info">
<h1>SVG Filter as Liquid Glass</h1>
<p>该示例直接引用 kube.io 文章里滤镜链路(两个 displacement map + specular 层),便于验证在我们环境下是否仍有折射与形变。</p>
</div>
</div>
<svg width="0" height="0" style="position:absolute">
<defs>
<filter id="magnifying-glass-filter" filterUnits="objectBoundingBox" primitiveUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feGaussianBlur in="SourceGraphic" stdDeviation="0.2" result="blurred_source"></feGaussianBlur>
<feImage href="./liquid-glass-demo/assets/magnifying-map.png" x="0" y="0" width="260" height="180" result="magnifying_displacement_map"></feImage>
<feDisplacementMap in="blurred_source" in2="magnifying_displacement_map" scale="24" xChannelSelector="R" yChannelSelector="G" result="magnified_source"></feDisplacementMap>
<feGaussianBlur in="magnified_source" stdDeviation="0.5" result="soft_source"></feGaussianBlur>
<feImage href="./liquid-glass-demo/assets/displacement-map.png" x="0" y="0" width="260" height="180" result="displacement_map"></feImage>
<feDisplacementMap in="soft_source" in2="displacement_map" scale="98" xChannelSelector="R" yChannelSelector="G" result="displaced"></feDisplacementMap>
<feColorMatrix in="displaced" type="saturate" values="8" result="displaced_saturated"></feColorMatrix>
<feImage href="./liquid-glass-demo/assets/specular-map.png" x="0" y="0" width="260" height="180" result="specular_layer"></feImage>
<feComposite in="displaced_saturated" in2="specular_layer" operator="in" result="specular_saturated"></feComposite>
<feComponentTransfer in="specular_layer" result="specular_faded">
<feFuncA type="linear" slope="0.35"></feFuncA>
</feComponentTransfer>
<feBlend in="specular_saturated" in2="displaced" mode="screen" result="withSaturation"></feBlend>
<feBlend in="specular_faded" in2="withSaturation" mode="screen"></feBlend>
</filter>
</defs>
</svg>
<script>
const glass = document.getElementById('glass');
const stage = document.getElementById('stage');
let dragging = false;
let offsetX = 0;
let offsetY = 0;
const clamp = (value, min, max) => Math.max(min, Math.min(max, value));
const startDrag = (clientX, clientY) => {
dragging = true;
const rect = glass.getBoundingClientRect();
offsetX = clientX - rect.left;
offsetY = clientY - rect.top;
glass.style.cursor = 'grabbing';
};
const drag = (clientX, clientY) => {
if (!dragging) return;
const stageRect = stage.getBoundingClientRect();
const x = clamp(clientX - offsetX, stageRect.left + 12, stageRect.right - glass.offsetWidth - 12);
const y = clamp(clientY - offsetY, stageRect.top + 12, stageRect.bottom - glass.offsetHeight - 12);
glass.style.left = `${x - stageRect.left}px`;
glass.style.top = `${y - stageRect.top}px`;
};
const stopDrag = () => {
dragging = false;
glass.style.cursor = 'grab';
};
glass.addEventListener('pointerdown', (e) => {
e.preventDefault();
glass.setPointerCapture(e.pointerId);
startDrag(e.clientX, e.clientY);
});
window.addEventListener('pointermove', (e) => {
drag(e.clientX, e.clientY);
});
window.addEventListener('pointerup', (e) => {
if (!dragging) return;
glass.releasePointerCapture(e.pointerId);
stopDrag();
});
// 初始放置在中心
const init = () => {
const stageRect = stage.getBoundingClientRect();
glass.style.left = `${stageRect.width / 2 - glass.offsetWidth / 2}px`;
glass.style.top = `${stageRect.height / 2 - glass.offsetHeight / 2}px`;
};
window.addEventListener('load', init);
window.addEventListener('resize', init);
</script>
</body>
</html>