Elonn Docs Platform Documentation

cardboard

elonn-world-cardboard is the Elonn runtime for Google Cardboard headsets. It runs on an Android phone placed inside a Cardboard viewer and renders the Elonn field and carry layers in stereoscopic VR using the phone gyroscope and magnetometer for head tracking.

Cardboard implements the World contract independently following the Runtime Contract, as every Elonn runtime does. Its presentation and interaction layers are VR-specific and separate from the Android AR runtime.

The Runtime Contract is the normative runtime contract. This page describes the current Cardboard implementation and platform constraints.

Conformance checklist →


Local setup

  • Package: com.elonn.worldcardboard
  • Runtime ID: cardboard (sent in X-Elonn-Runtime)
  • Runtime version: 0.1.0
  • VR SDK: com.google.cardboard:cardboard-xr (Maven)
  • Min SDK: API 24
  • Required permissions: CAMERA (passthrough), ACCESS_FINE_LOCATION (field), BLUETOOTH_CONNECT API 31+ (peripheral detection)
  • No ARCore dependency.
  • World base URL and login URL must be configurable without code changes. Store in local.properties:
WORLD_BASE_URL=https://world.elonn.com
LOGIN_URL=https://elonn.com/account/login

What it renders

Field layer — Live CameraX feed split into left/right eye viewports, forming a stereoscopic passthrough view of the real world. Field objects from field_runtime.objects[] are rendered as markers overlaid on each eye's viewport at the correct bearing. Objects with presentation.marker=false are not rendered as markers. Required provider attribution from field_runtime.objects[].attribution is displayed without provider-specific branching. The Runtime Contract heading-relative projection formula applies directly:

relativeBearing = (bearing − deviceHeading + 360) % 360, folded to [−180, 180]
cull if |relativeBearing| > hFOV / 2
projectedX = (relativeBearing / hFOV + 0.5) × viewportWidth

deviceHeading comes from the gyroscope/magnetometer. viewportWidth is half the physical screen width (one eye). The renderer derives a separate per-eye projection shift from the Cardboard viewer profile.

Carry layer — Cardboard currently renders compact head-locked shell surfaces over the passthrough view: center stack, left rail, right rail, and lower dock. This is a partial carry implementation. Full conformance requires preserving every supported World-supplied stack, including finding_overlay, deriving focus from each stack's focused_surface_id, and keeping transient panel payloads separate from durable surface identity.

Runtime v2 dataset — Cardboard parses much of the World runtime dataset: top-level service, contract, runtime session, capabilities, status, shell dock, field runtime, surface runtime, commands, viewports, service descriptors, semantic action ids/labels, object presentation, object actions, and attribution. It is not fully conforming until it consumes the shared contract fixtures as first-class tests and preserves the authoritative surface_runtime shape without local filtering.


Input model

Cardboard paired with a Bluetooth peripheral is an Android computer with a head-tracked display. Input is not constrained to the single Cardboard trigger.

Head — Primary aiming device. The heading vector is the cursor. Looking at a field marker or carry surface selects the target; a peripheral input confirms.

Bluetooth mouse — Implemented as a runtime pointer. Android's platform cursor is hidden and Cardboard draws a small stereo GL pointer. Mouse motion enables pointer_input and refreshes the World session once. Left click dispatches dock, panel navigation, or Field control actions. Right click returns to carry. Scroll wheel flips the focused surface in carry_primary.

Bluetooth keyboard — Planned. Text input for Find queries and panel forms. Tab = next surface. Esc = back / close. Space or Enter = select.

Bluetooth controller — Planned. Left stick = navigate. Right stick or d-pad = rotate cursor. A = select. B = back. X = action. Y = field controls.

Head-gaze fallback — Planned. Without a peripheral, look at an object for one second to select. Used for pure Cardboard with only the magnetic trigger.

The Runtime Contract action model maps cleanly to all input modes — a mouse click, controller trigger, screen tap, hand pinch, or gaze confirmation are all the same confirm action. The input device changes; the contract does not.


Declared capabilities

Cardboard sends this capability declaration in X-Elonn-Runtime on every session request:

{
  "runtime": "cardboard",
  "version": "0.1.0",
  "capabilities": {
    "stereo_rendering": true,
    "headset_mode": true,
    "camera_background": true,
    "field_markers": true
  }
}

camera_background: true is always declared — passthrough is not optional. pointer_input: true is added dynamically after a Bluetooth mouse or equivalent pointing device is detected or used.


Runtime data path

Identical to Android. Cardboard talks only to World:

  • GET /world/identity/me — authenticated member identity (bearer token)
  • GET /world/session — full runtime contract with field objects, surfaces, stacks, commands
  • GET /world/panels/{service} — panel payloads for focused surfaces
  • POST /world/find/query — Find queries; returns updated surface_runtime
  • POST /world/surface/surfaces/{surface_id}/focus — focus writes
  • POST /world/surface/surfaces/{surface_id}/placement — placement writes

Cardboard does not call API, Social, Messages, Maps, Time, Surface, or Find directly.

Partial World responses do not remove recovery UI. Cardboard preserves the existing shell dock, services, commands, and canonical carry/context stacks when a response omits them, so the lower dock remains available after Find, Field, or focused panel updates.


Relation to Android

Cardboard is a standalone app, not a mode or fork of the Android runtime. Both implement the same World contract independently from the Runtime Contract — that is the architecture. The Android runtime's World client is a reference for how the the runtime contract was applied on a similar platform, not a library Cardboard inherits.

The capability declaration is a per-session contract: a runtime declares what it is on load, and World tailors the response to those capabilities. An app that switches between AR and VR mid-session would need to re-fetch the session on mode change, which is not how the model is designed. One runtime, one capability set, one session.


Canonical terms

  • runtime — the execution environment
  • carry — user-following layer rendered as floating VR panels
  • field — spatial layer rendered as stereoscopic VR environment
  • panel — service-owned content loaded inside a surface
  • surface — contextual presentation layer within a stack