oikos: the home directory, a room of screens wired to one VCR - #2
Merged
Merged
Conversation
/oikos (and /~): every part of æthera, and a few places past it, as a CRT in a dark room in the Wired, every cable running into a VCR on a plinth in the middle. A Windows XP (Luna) desktop sits over the room. Two ways in. The VCR, or the start button, opens ~: every site is a tape, in Tiles view. Clicking a screen works too. Either way the tape goes into the VCR, the display reads PLAY and the channel, and that screen's cable surges. The site's pane then opens, showing the same canvas its screen is painted on. Open dives through the glass to the site. The screens are live wherever it costs the site nothing: - transmissions shows the latest real titles. - dreams shows the chronicle's last keyframe plus the monitoring status. It never opens /ws/dreams, since a viewer socket wakes the GPU. - chronicle shows its real strata and eras. - irc is the live broadcast. - apeiron composes real prompts from its own grammar. - syrinx shows the visitor's own creature from localStorage. parlor, dream_gen and loom draw from their own boards, READMEs and fixtures. heimdall is a labelled replica. Built like syrinx: a Vite + three.js module whose iife bundle is committed into aethera/static/oikos. Without WebGL the desktop runs alone; without JS the template's <nav> lists every site. /oikos?contact shows every screen on one sheet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UkALiUc3TzCNEMkPECnaDS
A site's pane can now "Watch it here". The camera squares up to the site's screen and holds still. The real page is laid over the glass: an iframe under a CSS CRT layer (scanlines, vignette, reflection, roll bar, power-on line). It is fully alive while the room renders around it: links navigate, keys and sound work, and syrinx wakes on a click. Eject, or Esc, steps back out. Any other camera move also steps out first. It is a projected 2D rectangle (Room.glassRect), not CSS3D. An iframe inside a preserve-3d context paints on the glass, but Chrome won't hit-test into it, so clicks fell through to the canvas. Framing: every page used to answer X-Frame-Options: DENY. Pages other than /preview/ now answer frame-ancestors 'self' plus SAMEORIGIN, so æthera may frame æthera and other origins still can't clickjack it. The tune flag in oikos.py marks what can be tuned in: æthera's own pages, with irc in its embed mode. parlor is left out because it answers DENY. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UkALiUc3TzCNEMkPECnaDS
A new harness walks the page through everything a visitor does and steps the room frame by frame. ?drive stops the room's own loop and exposes step(n, dt) with a paint/render timing split, so the harness runs at a true 30 fps on a machine with no GPU. `npm run drive` covers desktop, `--phone` covers touch, and `--browser firefox|webkit` runs another engine. Each run writes stills plus tour.webm. What driving it found: - A played tape went in behind two windows. The directory and the new pane covered the whole room, so the tape entering the VCR, the cable surge and the channel change were never seen. Now the directory folds to the taskbar while the camera swoops. It stops by the VCR as the cassette goes through the door, then follows the lit cable to the screen. The screen changes channel, then the pane opens beside it. The directory comes back when the pane closes. The choreography runs on the room's clock rather than wall-clock timeouts. - Windows were sized for 1440px wide. They now size to the page, and a narrow window folds its task pane away with a container query. - Orbit was too loose: a small drag swung the view round the side. It is slower now and held nearer the front of the arc. - The tooltip outlived the click that opened the VCR. - Each screen's light sat so close that its tape label blew out. - Once you clicked into a tuned-in page, Esc no longer ejected. It now listens inside the page (same origin), unless the page used the key or a text field has focus. - On a phone the room was a speck, and a tuned-in page laid out at 1024 wide was unreadable. The room is framed closer, and the tube's page lays out near the glass's own size. - WebKit showed a black room for seconds while it compiled shaders. The programs now compile, and one frame renders, behind the boot screen. Checked in Chromium on desktop and phone (full tours, no page errors), in WebKit (renders, no errors), and in Firefox without WebGL (the desktop fallback, no errors). Screens paint in 2.3 ms and the render issues in 4-6 ms per frame; real GPU time is not measured here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UkALiUc3TzCNEMkPECnaDS
Room / play sequence - play() now resolves true on arrival or false when cancelled (a click, Esc, a tile select). Cancelled plays eject the tape, restore the folded directory and clear the hash instead of stranding everything. - Floor clicks and arrow keys are ignored while a tape is going in. - Only primary-button clicks pick; right/middle click no longer plays. - tuneOut() hands the camera back (limits + controls); a tune-in called off mid-flight lands as a plain focus instead of locking picks. - pageshow (bfcache) resets leaving/off state and stands the camera up from the glass after Back. - resize() only re-homes the camera when the aspect changes; quality steps resize the buffers directly and no longer yank the view. - quality threshold 1/27s so 30fps-capped browsers aren't downgraded. - Room construction failure disposes the renderer and removes the canvas; the WebGL probe releases its context. Lifecycle - Boot doesn't start feeds or the loop in a hidden tab. - Hiding the tab tunes out, so a framed /dreams can't hold /ws/dreams. - /api/dreams/status polls no longer cancel the pending GPU shutdown or refresh the API-activity timer (presence.py; regression tests added). Misc - Esc closes the Turn Off dialog instead of the window behind it. - Open navigates once; hash writes keep the query string; malformed hashes don't abort boot; a stale error dialog is replaced. - No-JS and failed-bundle fallbacks lift the boot screen off the <nav>; boot() failure falls back to the plain directory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both go from the registry, the painters, the layout and RELATED. heimdall was the only site without an href, so the private-network paths it alone exercised go too: the error box, the Restricted zone, the lock icon and the href-None branches in pane/explorer/shell/template. Site.href is now always a string, and a test holds the registry to that. The hanging row is rebalanced for two: dream_gen at -20°, parlor at +20°, channels renumbered 8 and 9 so the remote has no gaps, and the power-line drops moved over the two screens that remain. Tests: /preview/ keeps its admin framing policy, /oikos and /irc/admin get frame-ancestors 'self', and a </script> post title can't break out of the embedded JSON. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Menus - One shared Luna popup menu (xp/menu.ts): checkmarks, greyed items, shortcuts, cascades, arrow-key navigation, closes on pick/outside/Esc. - Working menu bars (File/Edit/View/Favorites/Tools/Help) on every window; moving across the bar while one is open swaps menus. View has Toolbars ▸, Status Bar, Tiles/Icons/List, Go To ▸ and Refresh. Help ▸ About æthera opens an About box. - Right-click menus on tiles, screens, the VCR, the empty room (desktop), the folder's blank space and the taskbar; the system menu opens from the title-bar icon or a right-click on the title bar. Window chrome - Inactive windows fade the whole frame; their selection goes grey. - No drop shadow, no scale-in animation (Luna had neither). - Maximised drops the frame and the button becomes Restore. - Double-clicking the title icon closes; the drag handler no longer captures the pointer away from the icon. Start menu - Pinned tapes bold with subtitles, the rest plain; "All Programs ▸" cascades every tape; "My Tapes" / "My Recent Transmissions ▸" bold, everything else normal weight; larger framed picture; the orange rule fades at its ends. - Footer is Log Off + Turn Off Computer. Log Off gets XP's dialog (Switch User greyed) and clears the desk. Interaction - Esc only dismisses menus and dialogs, then steps the camera back; it no longer closes ordinary windows. Turn Off / Log Off are modal. - A click in the room deactivates every window. - Back/Forward (toolbar, Go To, Alt+←/→) walk a real history of ~ and the tapes played. - Blank space in the folder deselects; back/forward icons stay inside their circles. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Screens outside the camera frustum are neither painted nor uploaded. The focused screen and the one whose pane is open (keepAlive: the pane shows its canvas) always are. - With a screen focused, the others tick at half rate. - Quality steps back up after three quick windows in a row, so one slow moment no longer costs the whole visit its pixel ratio and bloom. - ?drive reports texture uploads alongside paint/render time. Measured with ?drive (software GL, 1280×800), focused on one screen: screen painting 1.97 → 0.93 ms/frame, texture uploads ~120 → 57 per second. The home view is unchanged: every screen really is on camera. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Ordinary windows resize from any edge or corner, with the right cursors and XP's dotted size grip in the status bar corner; minimum 300×180. Dialogs, maximised windows and phone sheets don't resize. - Windows are clamped back on screen when the viewport shrinks (a rotated phone could strand one offscreen). - Tile text shrinks to its column, so a long tagline ends in an ellipsis instead of running into the next tile. - Rebuilt bundle (includes the previous commit's changes). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
/oikos(and/~): every part of æthera, and a few places past it, as a CRT in a dark Lain-style room. Every cable runs into one VCR on a plinth in the middle, and a hand-built Windows XP (Luna) desktop sits over it all.What's in it
The room (
oikos/src/world/)12:00, a tape door, and a real cassette.The screens are live, not recorded (
oikos/src/screens/). Every source costs the site nothing to watch:oikos.py)/api/dreams/status/api/dreams/statusJSONtemplates.json/components.json/ws/ircbroadcast, formatted likeirc.jsThe room never opens
/ws/dreams. A viewer socket is what wakes the dreamer's GPU, and a hub left open in a tab would keep it awake all night. Every poll and socket stops while the tab is hidden. Tuning in to dreams frames the real/dreamspage, which does open it; hiding the tab tunes out, so a background tab can't hold it.The XP layer (
oikos/src/xp/) is Luna by hand:~explorer with every site as a VHS tape.Tune in ("▣ Watch it here"): the camera squares up to a screen and the real page is laid over the glass. It sits in an iframe under a CSS CRT layer and stays fully interactive. Eject or Esc steps back out.
Fallbacks
<nav>lists every site. It's also what crawlers read.Files outside
oikos/aethera/api/oikos.py: the route and the site registry. This is the single source for the<nav>and the scene, and the place to add a site.aethera/templates/oikos/viewer.html, plus the router registered inaethera/main.py.aethera/utils/security.pyis a security-relevant change. Every page used to answerX-Frame-Options: DENY. Everything except/preview/now answersContent-Security-Policy: frame-ancestors 'self'+X-Frame-Options: SAMEORIGIN. æthera may frame æthera; other origins still can't clickjack it. Tune-in needs this./preview/keeps its admin-panel policy.aethera/static/oikos/: the committed build, as with syrinx and apeiron.stage.jpgis a 512px crop ofdreams_bg.png, andmark.pngis the moon mark cropped from the logo.aethera/dreams/presence.py:/api/dreams/statuspolls are now lifecycle-neutral. Before, a poll cancelled the pending GPU shutdown, so any poller (this room, an admin panel) could keep the dreamer awake indefinitely. Tests intests/test_presence.py.tests/test_oikos.py: 9 tests./~redirects./preview/keeping its admin policy).</script>post title can't break out of the embedded JSON.Decisions for the owner
X-Frame-Options: DENY. Production currently sends it twice. Modern browsers let the app'sframe-ancestorsoverride it, but that proxy line should go (or becomeSAMEORIGIN) so tune-in doesn't lean on that precedence rule. It isn't in this repo.X-Frame-Options: DENY, so it isn't tunable. It would needframe-ancestors https://aetherawi.redfirst.oikos(οἶκος, household) is easy to change.Review round
A review pass (correctness, the room and window logic, XP authenticity) and the fixes it led to, as separate commits:
43d3ba6correctness.<nav>.ee65f3dloom and heimdall removed. The private-network code only heimdall used goes with them. The hanging row is rebalanced to dream_gen −20° and parlor +20°, on channels 8 and 9.08b72c0the XP layer behaves like XP.5336b3dperformance.e6b10e4window resizing from any edge or corner, with XP's size grip. Windows are clamped back on screen when the viewport shrinks.Testing
uv run pytest -q: 45 passed.npm run typecheck/npm run buildinoikos/: clean.npm run drivewalks through everything a visitor does. It steps the room at a true 30 fps via?drivebecause CI has no GPU, and writes stills and a video./syrinx. No page errors.--phone): tap a screen, tune in, tap the VCR, tap-tap to play, start menu. No page errors./oikos?contactshows every screen side by side, for reviewing the painters.🤖 Generated with Claude Code
https://claude.ai/code/session_01UkALiUc3TzCNEMkPECnaDS
Generated by Claude Code