Build: restore A2UI scaffold assets (#2455) (thanks @0oAstro)
Co-authored-by: 0oAstro <0oAstro@users.noreply.github.com>
This commit is contained in:
@@ -9,6 +9,7 @@ trap on_error ERR
|
|||||||
|
|
||||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
HASH_FILE="$ROOT_DIR/src/canvas-host/a2ui/.bundle.hash"
|
HASH_FILE="$ROOT_DIR/src/canvas-host/a2ui/.bundle.hash"
|
||||||
|
OUTPUT_FILE="$ROOT_DIR/src/canvas-host/a2ui/a2ui.bundle.js"
|
||||||
|
|
||||||
INPUT_PATHS=(
|
INPUT_PATHS=(
|
||||||
"$ROOT_DIR/package.json"
|
"$ROOT_DIR/package.json"
|
||||||
@@ -39,7 +40,7 @@ compute_hash() {
|
|||||||
current_hash="$(compute_hash)"
|
current_hash="$(compute_hash)"
|
||||||
if [[ -f "$HASH_FILE" ]]; then
|
if [[ -f "$HASH_FILE" ]]; then
|
||||||
previous_hash="$(cat "$HASH_FILE")"
|
previous_hash="$(cat "$HASH_FILE")"
|
||||||
if [[ "$previous_hash" == "$current_hash" ]]; then
|
if [[ "$previous_hash" == "$current_hash" && -f "$OUTPUT_FILE" ]]; then
|
||||||
echo "A2UI bundle up to date; skipping."
|
echo "A2UI bundle up to date; skipping."
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|||||||
307
src/canvas-host/a2ui/index.html
Normal file
307
src/canvas-host/a2ui/index.html
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Clawdbot Canvas</title>
|
||||||
|
<script>
|
||||||
|
(() => {
|
||||||
|
try {
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
const platform = (params.get("platform") || "").trim().toLowerCase();
|
||||||
|
if (platform) {
|
||||||
|
document.documentElement.dataset.platform = platform;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (/android/i.test(navigator.userAgent || "")) {
|
||||||
|
document.documentElement.dataset.platform = "android";
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
color-scheme: dark;
|
||||||
|
}
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
body::before,
|
||||||
|
body::after {
|
||||||
|
animation: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
font:
|
||||||
|
14px system-ui,
|
||||||
|
-apple-system,
|
||||||
|
BlinkMacSystemFont,
|
||||||
|
"Roboto",
|
||||||
|
sans-serif;
|
||||||
|
background:
|
||||||
|
radial-gradient(1200px 900px at 15% 20%, rgba(42, 113, 255, 0.18), rgba(0, 0, 0, 0) 55%),
|
||||||
|
radial-gradient(900px 700px at 85% 30%, rgba(255, 0, 138, 0.14), rgba(0, 0, 0, 0) 60%),
|
||||||
|
radial-gradient(1000px 900px at 60% 90%, rgba(0, 209, 255, 0.1), rgba(0, 0, 0, 0) 60%),
|
||||||
|
#000;
|
||||||
|
color: #e5e7eb;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
:root[data-platform="android"] body {
|
||||||
|
background:
|
||||||
|
radial-gradient(1200px 900px at 15% 20%, rgba(42, 113, 255, 0.62), rgba(0, 0, 0, 0) 55%),
|
||||||
|
radial-gradient(900px 700px at 85% 30%, rgba(255, 0, 138, 0.52), rgba(0, 0, 0, 0) 60%),
|
||||||
|
radial-gradient(1000px 900px at 60% 90%, rgba(0, 209, 255, 0.48), rgba(0, 0, 0, 0) 60%),
|
||||||
|
#0b1328;
|
||||||
|
}
|
||||||
|
body::before {
|
||||||
|
content: "";
|
||||||
|
position: fixed;
|
||||||
|
inset: -20%;
|
||||||
|
background:
|
||||||
|
repeating-linear-gradient(
|
||||||
|
0deg,
|
||||||
|
rgba(255, 255, 255, 0.03) 0,
|
||||||
|
rgba(255, 255, 255, 0.03) 1px,
|
||||||
|
transparent 1px,
|
||||||
|
transparent 48px
|
||||||
|
),
|
||||||
|
repeating-linear-gradient(
|
||||||
|
90deg,
|
||||||
|
rgba(255, 255, 255, 0.03) 0,
|
||||||
|
rgba(255, 255, 255, 0.03) 1px,
|
||||||
|
transparent 1px,
|
||||||
|
transparent 48px
|
||||||
|
);
|
||||||
|
transform: translate3d(0, 0, 0) rotate(-7deg);
|
||||||
|
will-change: transform, opacity;
|
||||||
|
-webkit-backface-visibility: hidden;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
opacity: 0.45;
|
||||||
|
pointer-events: none;
|
||||||
|
animation: clawdbot-grid-drift 140s ease-in-out infinite alternate;
|
||||||
|
}
|
||||||
|
:root[data-platform="android"] body::before {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
body::after {
|
||||||
|
content: "";
|
||||||
|
position: fixed;
|
||||||
|
inset: -35%;
|
||||||
|
background:
|
||||||
|
radial-gradient(900px 700px at 30% 30%, rgba(42, 113, 255, 0.16), rgba(0, 0, 0, 0) 60%),
|
||||||
|
radial-gradient(800px 650px at 70% 35%, rgba(255, 0, 138, 0.12), rgba(0, 0, 0, 0) 62%),
|
||||||
|
radial-gradient(900px 800px at 55% 75%, rgba(0, 209, 255, 0.1), rgba(0, 0, 0, 0) 62%);
|
||||||
|
filter: blur(28px);
|
||||||
|
opacity: 0.52;
|
||||||
|
will-change: transform, opacity;
|
||||||
|
-webkit-backface-visibility: hidden;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
transform: translate3d(0, 0, 0);
|
||||||
|
pointer-events: none;
|
||||||
|
animation: clawdbot-glow-drift 110s ease-in-out infinite alternate;
|
||||||
|
}
|
||||||
|
:root[data-platform="android"] body::after {
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
@supports (mix-blend-mode: screen) {
|
||||||
|
body::after {
|
||||||
|
mix-blend-mode: screen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@supports not (mix-blend-mode: screen) {
|
||||||
|
body::after {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes clawdbot-grid-drift {
|
||||||
|
0% {
|
||||||
|
transform: translate3d(-12px, 8px, 0) rotate(-7deg);
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translate3d(10px, -7px, 0) rotate(-6.6deg);
|
||||||
|
opacity: 0.56;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translate3d(-8px, 6px, 0) rotate(-7.2deg);
|
||||||
|
opacity: 0.42;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes clawdbot-glow-drift {
|
||||||
|
0% {
|
||||||
|
transform: translate3d(-18px, 12px, 0) scale(1.02);
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translate3d(14px, -10px, 0) scale(1.05);
|
||||||
|
opacity: 0.52;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translate3d(-10px, 8px, 0) scale(1.03);
|
||||||
|
opacity: 0.43;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
canvas {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
display: block;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
touch-action: none;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
:root[data-platform="android"] #clawdbot-canvas {
|
||||||
|
background:
|
||||||
|
radial-gradient(1100px 800px at 20% 15%, rgba(42, 113, 255, 0.78), rgba(0, 0, 0, 0) 58%),
|
||||||
|
radial-gradient(900px 650px at 82% 28%, rgba(255, 0, 138, 0.66), rgba(0, 0, 0, 0) 62%),
|
||||||
|
radial-gradient(1000px 900px at 60% 88%, rgba(0, 209, 255, 0.58), rgba(0, 0, 0, 0) 62%),
|
||||||
|
#141c33;
|
||||||
|
}
|
||||||
|
#clawdbot-status {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
display: none;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 24px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
#clawdbot-status .card {
|
||||||
|
width: min(560px, 88vw);
|
||||||
|
text-align: left;
|
||||||
|
padding: 14px 16px 12px;
|
||||||
|
border-radius: 16px;
|
||||||
|
background: linear-gradient(140deg, rgba(23, 24, 35, 0.78), rgba(18, 19, 28, 0.55));
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.12);
|
||||||
|
box-shadow:
|
||||||
|
0 16px 46px rgba(0, 0, 0, 0.52),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.06);
|
||||||
|
-webkit-backdrop-filter: blur(18px) saturate(140%);
|
||||||
|
backdrop-filter: blur(18px) saturate(140%);
|
||||||
|
}
|
||||||
|
#clawdbot-status .title {
|
||||||
|
font:
|
||||||
|
600 12px/1.2 -apple-system,
|
||||||
|
BlinkMacSystemFont,
|
||||||
|
"SF Pro Text",
|
||||||
|
system-ui,
|
||||||
|
sans-serif;
|
||||||
|
letter-spacing: 0.45px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
#clawdbot-status .subtitle {
|
||||||
|
margin-top: 8px;
|
||||||
|
font:
|
||||||
|
500 13px/1.45 -apple-system,
|
||||||
|
BlinkMacSystemFont,
|
||||||
|
"SF Pro Text",
|
||||||
|
system-ui,
|
||||||
|
sans-serif;
|
||||||
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
white-space: pre-wrap;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
}
|
||||||
|
clawdbot-a2ui-host {
|
||||||
|
display: block;
|
||||||
|
height: 100%;
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 4;
|
||||||
|
--clawdbot-a2ui-inset-top: 28px;
|
||||||
|
--clawdbot-a2ui-inset-right: 0px;
|
||||||
|
--clawdbot-a2ui-inset-bottom: 0px;
|
||||||
|
--clawdbot-a2ui-inset-left: 0px;
|
||||||
|
--clawdbot-a2ui-scroll-pad-bottom: 0px;
|
||||||
|
--clawdbot-a2ui-status-top: calc(50% - 18px);
|
||||||
|
--clawdbot-a2ui-empty-top: 18px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas id="clawdbot-canvas"></canvas>
|
||||||
|
<div id="clawdbot-status">
|
||||||
|
<div class="card">
|
||||||
|
<div class="title" id="clawdbot-status-title">Ready</div>
|
||||||
|
<div class="subtitle" id="clawdbot-status-subtitle">Waiting for agent</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<clawdbot-a2ui-host></clawdbot-a2ui-host>
|
||||||
|
<script src="a2ui.bundle.js"></script>
|
||||||
|
<script>
|
||||||
|
(() => {
|
||||||
|
const canvas = document.getElementById("clawdbot-canvas");
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
const statusEl = document.getElementById("clawdbot-status");
|
||||||
|
const titleEl = document.getElementById("clawdbot-status-title");
|
||||||
|
const subtitleEl = document.getElementById("clawdbot-status-subtitle");
|
||||||
|
const debugStatusEnabledByQuery = (() => {
|
||||||
|
try {
|
||||||
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
const raw = params.get("debugStatus") ?? params.get("debug");
|
||||||
|
if (!raw) return false;
|
||||||
|
const normalized = String(raw).trim().toLowerCase();
|
||||||
|
return normalized === "1" || normalized === "true" || normalized === "yes";
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
let debugStatusEnabled = debugStatusEnabledByQuery;
|
||||||
|
|
||||||
|
function resize() {
|
||||||
|
const dpr = window.devicePixelRatio || 1;
|
||||||
|
const w = Math.max(1, Math.floor(window.innerWidth * dpr));
|
||||||
|
const h = Math.max(1, Math.floor(window.innerHeight * dpr));
|
||||||
|
canvas.width = w;
|
||||||
|
canvas.height = h;
|
||||||
|
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("resize", resize);
|
||||||
|
resize();
|
||||||
|
|
||||||
|
const setDebugStatusEnabled = (enabled) => {
|
||||||
|
debugStatusEnabled = !!enabled;
|
||||||
|
if (!statusEl) return;
|
||||||
|
if (!debugStatusEnabled) {
|
||||||
|
statusEl.style.display = "none";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (statusEl && !debugStatusEnabled) {
|
||||||
|
statusEl.style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
window.__clawdbot = {
|
||||||
|
canvas,
|
||||||
|
ctx,
|
||||||
|
setDebugStatusEnabled,
|
||||||
|
setStatus: (title, subtitle) => {
|
||||||
|
if (!statusEl || !debugStatusEnabled) return;
|
||||||
|
if (!title && !subtitle) {
|
||||||
|
statusEl.style.display = "none";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
statusEl.style.display = "flex";
|
||||||
|
if (titleEl && typeof title === "string") titleEl.textContent = title;
|
||||||
|
if (subtitleEl && typeof subtitle === "string") subtitleEl.textContent = subtitle;
|
||||||
|
if (!debugStatusEnabled) {
|
||||||
|
clearTimeout(window.__statusTimeout);
|
||||||
|
window.__statusTimeout = setTimeout(() => {
|
||||||
|
statusEl.style.display = "none";
|
||||||
|
}, 3000);
|
||||||
|
} else {
|
||||||
|
clearTimeout(window.__statusTimeout);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user