Skip to main content

EXAMPLE_HTML

Constant EXAMPLE_HTML 

Source
const EXAMPLE_HTML: &str = r#"<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
    <title>{{title}}</title>
    <style>
      :root {
        /* The gap between the canvas and the window's edge. */
        --margin: 16px;
      }
      html,
      body {
        margin: 0;
        padding: 0;
        /* The address bar retracts on scroll, so the dynamic viewport unit is
           what keeps the canvas filling the visible area on a phone. */
        height: 100dvh;
        overflow: hidden;
        overscroll-behavior: none;
        background: #101014;
      }
      body {
        /* The margin around the canvas. `border-box` keeps the padding inside
           the viewport, so the canvas's own size is the viewport less this
           margin. */
        box-sizing: border-box;
        padding:
          max(var(--margin), env(safe-area-inset-top))
          max(var(--margin), env(safe-area-inset-right))
          max(var(--margin), env(safe-area-inset-bottom))
          max(var(--margin), env(safe-area-inset-left));
      }
      canvas {
        display: block;
        /* Override the inline size winit sets from the window attributes, so
           the canvas follows the viewport — less the margin above — instead of
           staying at the size the example asks for. */
        width: 100% !important;
        height: 100% !important;
        /* Without this the browser claims a drag as its own pan. */
        touch-action: none;
      }
    </style>
  </head>
  <body>
    <script type="module">
      import init from "./{{module}}.js";
      init();
    </script>
  </body>
</html>
"#;
Expand description

The page that starts one example.

The canvas is sized by this page, not by the window attributes the example asks for: winit writes those into the canvas’s inline style, and !important is what lets the page override them so the canvas follows a phone’s viewport instead of staying at the desktop size the example requests. The body’s padding is the margin around the canvas, and box-sizing keeps that margin inside the viewport rather than pushing the page past it; the safe-area maxima keep the canvas clear of a phone’s notch and home indicator.

The canvas therefore follows the viewport and not its own aspect ratio, so the examples’ scenes take their camera aspect from the render target’s size each frame. A window that changes shape re-aims the projection and shows more or less of the scene; nothing is stretched.

The page carries no overlay of its own: whatever the example draws over the canvas — the corner controls, its link to the API docs — is the example’s own, so those sit together by construction rather than by two hand-kept rules that can collide. The landing page at the root is where the site’s navigation lives; an example page reached directly has only the example’s own overlay.

touch-action: none is what makes a finger drag reach the app at all. The Pointer Events specification has preventDefault() on pointerdown not cancel the browser’s own panning, so without it a drag is taken over by the page mid-gesture and the app is sent a pointercancel instead of the moves. The overflow and overscroll rules keep the page itself from scrolling under the canvas.