npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@we-box/box-components

v0.1.0

Published

Official resource-aware image, audio, video and 3D components for Webox Boxes

Downloads

98

Readme

@we-box/box-components

Official resource-aware Custom Elements for Webox Boxes. Version 0.1.0 is a release candidate in this repository; online use requires npm publication and Package Graph admission in the target environment.

Each Box declares the dependency and imports its required entries; registration happens inside that Box's iframe. The Host injects the SDK, not this component library. Online drafts and uploaded Box Projects use the same package and resource contracts. Development seed snapshots inline workspace code and do not prove registry delivery. See the activation runbook for the release, admission and real Box acceptance requirements.

The published CLI/Builder 0.5.0 cannot build HTML entries containing only component registration imports. Toolchain 0.6.0 contains the required registration-entry fix; workspace tarball validation does not establish compatibility with published 0.5.0. The supported component contract requires renderer 25 or later, including independent native volume under Host mute. Create a new Box version to upgrade an older renderer.

<script type="module">
  import '@we-box/box-components/image';
  import '@we-box/box-components/audio';
  import '@we-box/box-components/video';
  import '@we-box/box-components/model';
</script>
<webox-image resource="images/cover.png" alt="Cover"></webox-image>
<webox-audio resource="audio/voice.m4a" controls aria-label="Voice"></webox-audio>
<webox-video resource="videos/demo.mp4" controls aria-label="Demo"></webox-video>
<webox-model resource="models/product.glb" aria-label="Product"></webox-model>

Declare "@we-box/box-components": "0.1.0" in runtime dependencies, import only the entries used, bind the corresponding resources, and declare resources.box.read. The SDK is injected by the Host; do not install a second SDK runtime. Framework wrappers are unnecessary: these are standard Custom Elements.

| Element | Attributes and methods | | --- | --- | | webox-image | alt (required, empty for decorative images), fit="contain\|cover", loading="lazy\|eager", width, height | | webox-audio | boolean controls, muted, loop, autoplay; preload="none\|metadata\|auto"; mediaElement, play(), pause(), paused, currentTime | | webox-video | boolean controls, muted, loop, autoplay; preload="none\|metadata\|auto"; optional poster bound image path; mediaElement, play(), pause(), paused, currentTime | | webox-model | accessible name; self-contained GLB v2, max 50 MiB; resetView(); pointer orbit, wheel zoom, arrows, +/−, Home |

All accept resource (logical path) or mutually exclusive handle (a viewer resource handle already obtained with the SDK). handle requires resources.user.select; mounting never opens a picker or releases your handle. Audio, video and model require aria-label or aria-labelledby. Boolean attributes use HTML presence semantics: remove muted to disable it, never muted="false". poster requires its own image binding and resources.box.read.

All expose retry(), state, data-state (idle, loading, ready, error), webox-load and webox-error events. Errors contain only {code, retryable}; resource leases are never event payloads. Empty dynamic elements remain idle until their resource/handle is assigned. Presentation attributes are reactive and reload the element; use media methods for playback control.

Images defer opening their lease until visible by default (loading="eager" opens immediately). Audio and video use optional native controls in light DOM so Host mute still applies; autoplay follows browser policy. Expired media leases reopen once on playback, seeking or error and restore position, playback intent and media settings. Permission failure stops playback. Retry is explicit after an error. preload="none" stays loading until metadata becomes available through playback.

Model rendering pauses outside the viewport or when the Host/document is hidden. Removal cancels observation/animation and frees model/GPU resources. External textures and online decoders are unsupported. Image/audio/video entries never import Three.js. Set size on the custom element; --webox-media-fit controls default image/video fitting. Controls/errors support English and Chinese from Host locale or element lang.

/catalog is the machine-readable contract; /authoring validates declarative HTML, imports, capabilities, resource kinds and accessible names. Dynamic JS inputs are validated at runtime. Native media/custom rendering remain allowed.

Styling

Media surfaces are transparent by default: no card background, border, shadow or padding. Transparent pixels in PNG/WebP images and around models show the surrounding Box. Backgrounds, frames and spacing belong to the calling page and are optional; the gallery example adds no media backdrop. Size and crop with ordinary CSS on the custom element, for example style="width:32px;height:32px" for an image in a toolbar. Native video controls and letterboxing follow the browser. Add controls to show the native audio/video UI. Omit it to hide native controls and attach an external player to mediaElement after the webox-load event; the element stays in light DOM so players such as Plyr, Media Chrome or a custom controller can use the standard HTMLAudioElement or HTMLVideoElement. The caller owns the player's lifecycle: destroy it before replacing the resource or unmounting the framework view, and bind the new mediaElement after each webox-load. When destruction is asynchronous (such as Plyr's callback), wait for it before reloading. Keep third-party styles and icon sprites local to the Project (see the toolchain compatibility notes).

Loading uses a small animated ring on a transparent surface, inherits the element's text color and fits within its dimensions, including small inline images. Localized loading text remains available to screen readers. Reduced-motion preferences stop the animation. Loading overlays do not intercept controls; headless audio stays out of the layout, and preload="none" shows the available player without a waiting animation. Ready/idle states hide the indicator. Errors use a fine-line icon, compact message and outlined retry button on the same transparent surface. Narrow elements reduce decoration; very small images show only the retry icon while keeping accessible text. Buttons inherit the Box text color, support keyboard focus and respect reduced-motion preferences.

const video = document.querySelector("webox-video");
video?.addEventListener("webox-load", () => {
  const media = video.mediaElement;
  if (media) attachExternalPlayer(media);
});

Local example and checks

The Form & Motion example uses real repository-owned image, audio, video and GLB fixtures. It is nested here so an unpublished npm dependency does not enter workspace installation. Run from the repository root:

pnpm build:box-toolchain
node apps/box-cli/dist/cli.js build packages/box-components/example --json
node apps/box-cli/dist/cli.js preview packages/box-components/example --json
pnpm --filter @we-box/box-components test

Local preview resolves the workspace package. To use the example outside this repository before publication, pack this package and install that tarball in the example with npm install --no-save /absolute/path/to/we-box-box-components-0.1.0.tgz. Keep the manifest's runtime version as 0.1.0; file/workspace dependency requests are not valid Box upload intent.

Architecture and release prerequisites: Built-in media components.

For audio, import @we-box/box-components/audio and bind an existing MP3/OGG/WAV/M4A resource. The component uses the resource lease returned by the SDK; it does not transcode or fetch waveform derivatives. mediaElement is an HTMLAudioElement (available while metadata loads), so a custom control can also call play() when preload="none". Without controls, audio occupies no player UI space. Host mute remains authoritative: enable Box sound before listening; changing volume does not override it. Renderer 25 routes CORS media with native controls through the Host output gain after volume interaction or playback: native volume and local mute remain adjustable while global sound is off. Hover and focus do not claim a media source. Audio/video components set anonymous CORS before loading their resource lease. Custom players without native controls can attach their Web Audio graph before or after playback. When combining native controls and a custom graph, connect the author source before playback or volume changes; a media element can only bind one source node. Reading mediaElement.muted returns local mute intent, so renewal during Host mute preserves the player's own setting. Saved older Boxes need a new version to receive the runtime change.