cynarAI 6c7eed7580 Initial clean evOo-local from f00577b
Fresh history cut from cynarAI/evoo antigravity-handoff/project-timeline
(Voice First + project timeline). Brand docs/titles as evOo; keep @rakazo/*
packages as tech debt. Excludes node_modules, caches, secrets, voice blobs.
2026-09-20 17:15:16 +02:00

152 lines
4.8 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Rakazo computer</title>
<style>
html,
body,
#screen {
margin: 0;
height: 100%;
width: 100%;
background: #0e0e10;
overflow: hidden;
}
#mobile-controls {
position: fixed;
right: max(12px, env(safe-area-inset-right));
top: calc(
var(--mobile-visual-top, 0px) + var(--mobile-visual-height, 100dvh) - 60px -
env(safe-area-inset-bottom)
);
z-index: 2;
display: flex;
gap: 8px;
}
#mobile-keyboard,
#mobile-trackpad {
box-sizing: border-box;
width: 48px;
height: 48px;
padding: 11px;
border: 1px solid color-mix(in srgb, currentColor 35%, transparent);
border-radius: 12px;
background: Canvas;
color: CanvasText;
box-shadow: 0 2px 10px color-mix(in srgb, CanvasText 25%, transparent);
}
#mobile-keyboard.active,
#mobile-trackpad.active {
outline: 3px solid Highlight;
outline-offset: 1px;
}
#mobile-keyboard svg,
#mobile-trackpad svg {
width: 100%;
height: 100%;
}
#screen.trackpad-active {
touch-action: none;
}
#mobile-keyboard-input {
position: fixed;
left: -40px;
width: 1px;
height: 1px;
border: 0;
opacity: 0;
}
.mobile-keyboard-open #screen {
position: fixed;
top: var(--mobile-visual-top, 0px);
left: 0;
height: var(--mobile-visual-height, 100dvh);
}
</style>
<script type="module">
import { attachHostClipboardPaste } from "./clipboard-bridge.js";
import Keyboard from "./core/input/keyboard.js";
import KeyTable from "./core/input/keysym.js";
import keysyms from "./core/input/keysymdef.js";
import RFB from "./core/rfb.js";
import { attachMobileKeyboard, attachMobileTrackpad, isTouchBrowser } from "./mobile-keyboard.js";
function query(name, fallback) {
const match = `${document.location.href}${window.location.hash}`.match(
new RegExp(`.*[?&]${name}=([^&#]*)`),
);
return match ? decodeURIComponent(match[1]) : fallback;
}
function flag(name) {
const value = String(query(name, "false")).toLowerCase();
return value === "1" || value === "true" || value === "yes";
}
const path = String(query("path", "websockify")).replace(/^\//, "");
const prefix = window.location.pathname.replace(/[^/]+$/, "");
const protocol = window.location.protocol === "https:" ? "wss" : "ws";
const url = `${protocol}://${window.location.host}${prefix}${path}`;
const rfb = new RFB(document.getElementById("screen"), url);
rfb.viewOnly = flag("view_only");
rfb.scaleViewport = true;
rfb.clipViewport = false;
if (!rfb.viewOnly) attachHostClipboardPaste(rfb);
if (!rfb.viewOnly && isTouchBrowser()) {
attachMobileKeyboard(rfb, {
button: document.getElementById("mobile-keyboard"),
input: document.getElementById("mobile-keyboard-input"),
Keyboard,
backspaceKeysym: KeyTable.XK_BackSpace,
lookupKeysym: keysyms.lookup,
});
attachMobileTrackpad(rfb, {
button: document.getElementById("mobile-trackpad"),
surface: document.getElementById("screen"),
});
}
</script>
</head>
<body>
<div id="screen"></div>
<div id="mobile-controls">
<button
id="mobile-keyboard"
type="button"
aria-label="Show keyboard"
aria-pressed="false"
title="Show keyboard"
hidden
>
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="2" y="4" width="20" height="16" rx="2" />
<path d="M6 8h.01M10 8h.01M14 8h.01M18 8h.01M6 12h.01M10 12h.01M14 12h.01M18 12h.01M6 16h12" />
</svg>
</button>
<button
id="mobile-trackpad"
type="button"
aria-label="Use trackpad"
aria-pressed="false"
title="Use trackpad"
hidden
>
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M9 11V5a2 2 0 0 1 4 0v5" />
<path d="M13 10V4a2 2 0 0 1 4 0v7" />
<path d="M17 10V6a2 2 0 0 1 4 0v7c0 5-3 8-8 8h-1c-3 0-5-1-7-4l-2-3a2 2 0 0 1 3-2l3 2" />
</svg>
</button>
</div>
<textarea
id="mobile-keyboard-input"
aria-label="Remote computer keyboard input"
autocapitalize="off"
autocomplete="off"
spellcheck="false"
tabindex="-1"
></textarea>
</body>
</html>