From b8dd023a97bf6e960601258db154ca3ab1fc7437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miguel=20=C3=81ngel?= Date: Thu, 24 Sep 2026 21:13:27 -0400 Subject: [PATCH] feat(core): a composition's script can load its own files with __hyperframes.assetUrl (#4434) * feat(core): a composition's script can load its own files with __hyperframes.assetUrl * test(core): a template composition inside a mounted file resolves assets from that file * docs: assetUrl is for paths beside the composition, not project-root paths * docs: say assetUrl misses a project-root path --- docs/concepts/compositions.mdx | 29 ++++++++++++ .../src/compiler/compositionScoping.test.ts | 33 ++++++++++++++ .../core/src/compiler/compositionScoping.ts | 6 +++ .../core/src/compiler/htmlBundler.test.ts | 45 +++++++++++++++++++ .../src/compiler/inlineSubCompositions.ts | 1 + packages/core/src/runtime/assetUrl.ts | 8 ++++ .../src/runtime/compositionLoader.test.ts | 18 ++++++++ .../core/src/runtime/compositionLoader.ts | 1 + packages/core/src/runtime/entry.ts | 3 ++ packages/core/src/runtime/window.d.ts | 2 + skills-manifest.json | 2 +- .../references/contributing.md | 6 +++ 12 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 packages/core/src/runtime/assetUrl.ts diff --git a/docs/concepts/compositions.mdx b/docs/concepts/compositions.mdx index 768e3bd534..fd6c754c82 100644 --- a/docs/concepts/compositions.mdx +++ b/docs/concepts/compositions.mdx @@ -242,6 +242,35 @@ script, CLI overrides, and which value wins. If you are building tooling on `@hyperframes/core`, `extractCompositionMetadata()` reads the same `data-composition-variables` array — that is how Studio builds its editing UI. +## Load a composition's own files from its script + +When a composition is mounted, a `src` or `href` attribute that points at a +file next to it is rewritten to where that file lives, so +`` keeps working. A path your script builds is a +plain string and is never rewritten, so resolve it with +`window.__hyperframes.assetUrl()`. It takes a path written relative to the +composition's own file and returns a URL the page can load, whether the file is +mounted, previewed or opened on its own. + +A path meant from the project root, such as `assets/logo.png` in a composition +at `compositions/intro.html` whose image sits in the project's own `assets/` +folder, already resolves from the page. Leave it as a plain string: +`assetUrl()` would look for it beside the composition and miss. + +```html compositions/globe/globe.html +
+ +
+``` + +A separate script file (` +`, + }); + + const bundled = await bundleToSingleHtml(dir); + + expect(bundled).toContain('var __hfCompositionSrc = "compositions/blk/blk.html";'); + }); + + it("binds a