Skip to content

SylvaLivingWorldScene: bundled font 404s via CORS in its own sandboxed iframe (sourceUrl/assetBaseUrl not exposed) #39

Description

@jazrs1

Package version: @designcodeio/threeui@1.1.0 (also reproduces on 1.0.0, 0.3.0)

What's happening

SylvaLivingWorldScene renders its content in a sandboxed iframe: sandbox="allow-scripts", with no allow-same-origin. That makes the iframe a null-origin document.

The scene's own inner-green-3d.html declares:

@font-face{
  font-family:'Lexend';
  src:url('inner-green-assets/lexend-latin.woff2') format('woff2');
  ...
}

a root-relative fetch. From a null-origin iframe, that's a cross-origin request no matter what host actually serves it — and Chrome/WebKit require CORS approval specifically for cross-origin @font-face loads (unlike images or scripts, which can load no-cors). Console:

Access to font at 'https://<host>/inner-green-assets/lexend-latin.woff2' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

The documented workaround doesn't apply to this component

The README says:

Components that render full HTML documents expect their runtime files at the same root-relative URLs used by the ThreeUI preview. Copy the needed files from node_modules/@designcodeio/threeui/lib-dist/assets/ into your app's public directory, or override the component's sourceUrl or assetBaseUrl prop where available.

SylvaLivingWorldSceneProps is exactly:

type SylvaLivingWorldSceneProps = {
  variant?: "living-green";
  className?: string;
  style?: CSSProperties;
};

No sourceUrl, no assetBaseUrl. So the "override the prop" half of the documented fix isn't available for this component — only the "copy the file into your public dir" half is, and even that's insufficient on its own (see below).

Copying the file isn't sufficient either

I copied lexend-latin.woff2 to the exact expected path in my app's public/ dir. The font still failed to load with the same CORS error, because the request's Origin header is null (from the sandbox) and my server (a stock Next.js dev/prod server) doesn't send Access-Control-Allow-Origin for static files by default. The actual fix required adding an explicit CORS header for that path in my app's server config:

// next.config.ts
async headers() {
  return [{
    source: "/inner-green-assets/:path*",
    headers: [{ key: "Access-Control-Allow-Origin", value: "*" }],
  }];
}

That's a non-obvious requirement that follows directly from the allow-scripts-only sandbox choice, and it isn't mentioned anywhere in the README's asset-path guidance.

Ask

Either (or both):

  1. Expose sourceUrl/assetBaseUrl on SylvaLivingWorldScene (and any other "full HTML document" component that's missing it), matching what the README already documents as the intended override.
  2. Document the CORS-header requirement explicitly wherever the "copy the file into public/" guidance appears, since it's not enough by itself given the sandbox.

Note: fixing this did not resolve the branch/foliage geometry never appearing (filed separately as #38) — that reproduces identically with or without this font loading successfully. Filing this as its own issue since it's a real, independent gap.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions