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

@kubohiroya/turbowarp-aframe

v0.11.0

Published

A TurboWarp extension for declarative A-Frame scene graphs.

Readme

TurboWarp-A-Frame

English | 日本語

TurboWarp-A-Frame is an unsandboxed TurboWarp extension for building declarative A-Frame scene graphs from blocks.

It treats TurboWarp sprites and backdrops as places to run 3D scene logic, not as 3D object identities. The 3D world is addressed with A-Frame-style node ids, classes, data attributes, attributes, templates, selectors, and events.

Minimal demo

Open in TurboWarp Editor · SB3

Select “Run extension without sandbox” and Allow for each embedded extension. Green flag creates one cube; Space moves the cube 0.5 to the right. C removes the cube; green flag resets the scene.

Requires a WebGL browser and access to jsDelivr for A-Frame 1.8.0. Stop and C leave the rendering canvas active. Close the tab to end GPU rendering; there is currently no scene shutdown block. Running again replaces the previous scene.

Source and regeneration

What it does

  • Creates an embedded A-Frame scene host from TurboWarp.
  • Builds a parent-child scene graph with primitive, image, text, model, light, camera, and group nodes.
  • Selects nodes with a limited #id, .class, and [data-key=value] selector subset.
  • Mutates local position, rotation, class, data-*, visibility, and arbitrary A-Frame component attributes.
  • Loads JSON templates and instantiates them with explicit instance ids.
  • Mounts the A-Frame host near the detected TurboWarp stage and queues scene-ready, DOM pointer/click, and selector-scoped custom events for hat blocks.
  • Defines and plays Three.js keyframe animation clips with vector and quaternion tracks.
  • Keeps AR and collision APIs documented as next-stage extension points while preserving a small initial implementation.

Requirements and safety

  • Node.js 24 or newer
  • Corepack-managed pnpm
  • TurboWarp unsandboxed extension support
  • Network access to jsDelivr, from which create 3D scene loads A-Frame 1.8.0 pinned by version and subresource integrity; a page that already has A-Frame 1.8.0, such as an offline venue serving its own copy, loads nothing, and any other A-Frame version on the page is refused

Unsandboxed extensions can manipulate the containing page. Load only generated extension bundles that you trust.

Runtime scene capability

Composite unsandboxed extensions can use the same scene operations as the blocks through the versioned runtime capability. Read Scratch.vm.runtime.turbowarpAFrameCapability, call requireVersion(2), and use the object it returns. Version 2 is the only version; version 1 was removed in 0.4.0, and requesting any other version throws.

interface AFrameRuntimeCapabilityV2 {
  readonly version: 2;
  requireVersion(version: number): AFrameRuntimeCapabilityV2;
  createScene(layer: string, mode: string): Promise<void>;
  createNode(type: string, id: string, parent: string): void;
  addClass(className: string, selector: string): void;
  loadTemplate(id: string, source: string): void;
  createFromTemplate(template: string, instance: string, parent: string): void;
  setPosition(selector: string, x: number, y: number, z: number): void;
  setRotation(selector: string, x: number, y: number, z: number): void;
  setAttribute(selector: string, name: string, value: string): void;
  setData(selector: string, key: string, value: string): void;
  emitEvent(type: string, selector: string, data: string): void;
  deleteSelector(selector: string): void;
  countSelector(selector: string): number;
  loadVrm(url: string, selector: string): Promise<void>;
  setVrmBoneRotation(selector: string, bone: string, x: number, y: number, z: number): void;
  vrmBoneNames(selector: string): string[];
  vrmStatus(selector: string): {state: 'none' | 'loading' | 'ready' | 'error'; error: string};
  setVrmExpression(selector: string, name: string, weight: number): void;
  vrmExpressionNames(selector: string): string[];
}

createScene, createNode, and addClass build the scene itself, so an extension that turns a scene description into A-Frame nodes can do it through this port rather than only through blocks. createFromTemplate is not a substitute: it prefixes child ids with the instance id and writes template and instance data keys, so a caller that already owns its ids would not get the ids it asked for.

setAttribute and setData write an A-Frame component attribute such as visible, and a data-<key> attribute, on every matching node. They exist so that a companion extension which has to write attributes, such as turbowarp-ar writing target pose and visibility, goes through this port and keeps the extension's scene state in sync, instead of reaching into the DOM behind its back.

Besides the scene operations, version 2 carries VRM avatars. loadVrm loads the model onto the first node matching the selector with three-vrm, running on the Three.js that A-Frame loaded, and resolves when it is ready. setVrmBoneRotation sets Euler degrees on a normalized humanoid bone such as leftUpperArm, relative to the T-pose, so the same rotation means the same thing on every VRM; the scene tick applies it to the model's own bones. Nodes whose VRM is not ready are skipped, and an unknown bone name throws. setVrmExpression sets the weight of a preset expression such as happy, blink, or aa, or of a custom one, clamped to 0 through 1 as three-vrm does, and the scene tick applies it; vrmExpressionNames lists the names the model has, and an unknown name throws.

The capability deliberately exposes declarative templates, selectors, and humanoid bone names, not private DOM nodes, A-Frame objects, Three.js objects, or glTF internals. Unsupported versions fail closed. A retained capability reference also rejects every operation after the extension is disposed.

Install

npm install --global corepack@latest
corepack enable
pnpm install --frozen-lockfile

Quick start

pnpm run build

Load dist/turbowarp-aframe.js as an unsandboxed custom extension in TurboWarp.

For package-based reuse, pin the version:

pnpm add --save-exact @kubohiroya/[email protected]

Block reference

create 3D scene with layer [LAYER] mode [MODE]

Loads A-Frame 1.8.0 from jsDelivr when the page does not have it, initializes the A-Frame scene host, and emits the scene ready event.

| Property | Value | |---|---| | Type | Command | | Opcode | createScene | | LAYER | String, default: above-stage | | MODE | String, default: 3d |

load template [ID] from JSON [SOURCE]

Stores a declarative scene graph template for later instantiation.

| Property | Value | |---|---| | Type | Command | | Opcode | loadTemplate | | ID | String, default: monster | | SOURCE | String, default: {"type":"box","id":"body","attributes":{"color":"#4cffb0"}} |

create [TYPE] node id [ID] under [PARENT]

Creates a primitive, model, text, light, camera, or group node.

| Property | Value | |---|---| | Type | Command | | Opcode | createNode | | TYPE | String, default: box | | ID | String, default: card | | PARENT | String, default: #scene |

create template [TEMPLATE] as [INSTANCE] under [PARENT]

Instantiates a stored template under the first node matching the parent selector.

| Property | Value | |---|---| | Type | Command | | Opcode | createFromTemplate | | TEMPLATE | String, default: monster | | INSTANCE | String, default: monster-1 | | PARENT | String, default: #scene |

set selector [SELECTOR] position x [X] y [Y] z [Z]

Sets local position on every node matching the selector.

| Property | Value | |---|---| | Type | Command | | Opcode | setPosition | | SELECTOR | String, default: #card | | X | Number, default: 0 | | Y | Number, default: 1 | | Z | Number, default: -3 |

move selector [SELECTOR] by x [X] y [Y] z [Z]

Offsets local position on every node matching the selector.

| Property | Value | |---|---| | Type | Command | | Opcode | moveBy | | SELECTOR | String, default: #card | | X | Number, default: 0 | | Y | Number, default: 0 | | Z | Number, default: 1 |

set selector [SELECTOR] rotation x [X] y [Y] z [Z]

Sets local Euler rotation in degrees on every node matching the selector.

| Property | Value | |---|---| | Type | Command | | Opcode | setRotation | | SELECTOR | String, default: #card | | X | Number, default: 0 | | Y | Number, default: 45 | | Z | Number, default: 0 |

add class [CLASS] to selector [SELECTOR]

Adds a CSS-style class to every node matching the selector.

| Property | Value | |---|---| | Type | Command | | Opcode | addClass | | CLASS | String, default: monster | | SELECTOR | String, default: #card |

set selector [SELECTOR] data [KEY] to [VALUE]

Sets a data-* value on every node matching the selector.

| Property | Value | |---|---| | Type | Command | | Opcode | setData | | SELECTOR | String, default: #card | | KEY | String, default: zone | | VALUE | String, default: field |

set selector [SELECTOR] attribute [NAME] to [VALUE]

Sets an A-Frame component or HTML attribute on every node matching the selector.

| Property | Value | |---|---| | Type | Command | | Opcode | setAttribute | | SELECTOR | String, default: #card | | NAME | String, default: visible | | VALUE | String, default: true |

delete selector [SELECTOR]

Deletes every non-root node matching the selector and its descendants.

| Property | Value | |---|---| | Type | Command | | Opcode | deleteSelector | | SELECTOR | String, default: #card |

count selector [SELECTOR]

Returns the number of nodes matching a limited selector.

| Property | Value | |---|---| | Type | Reporter | | Opcode | countSelector | | SELECTOR | String, default: .monster |

event target id

Returns the id of the most recently handled 3D event target.

| Property | Value | |---|---| | Type | Reporter | | Opcode | eventTargetId |

emit 3D event [TYPE] from selector [SELECTOR] with data [DATA]

Queues and dispatches a 3D event from the first node matching the selector.

| Property | Value | |---|---| | Type | Command | | Opcode | emitEvent | | TYPE | String, default: attack | | SELECTOR | String, default: #card | | DATA | String, default: {} |

when 3D scene ready

Fires once after create 3D scene initializes the scene host.

| Property | Value | |---|---| | Type | Hat | | Opcode | whenSceneReady |

when event [TYPE] on selector [SELECTOR]

Fires when a queued 3D event of the given type targets a node matching the selector.

| Property | Value | |---|---| | Type | Hat | | Opcode | whenEventOnSelector | | TYPE | String, default: attack | | SELECTOR | String, default: .monster |

create 3D animation clip [NAME] duration [DURATION]

Creates or replaces a Three.js AnimationClip definition.

| Property | Value | |---|---| | Type | Command | | Opcode | createAnimationClip | | NAME | String, default: wave | | DURATION | Number, default: -1 |

delete 3D animation clip [NAME]

Deletes a stored 3D animation clip definition and stops its active actions.

| Property | Value | |---|---| | Type | Command | | Opcode | deleteAnimationClip | | NAME | String, default: wave |

add vector keyframe track to clip [CLIP] path [PATH] times [TIMES] values [VALUES]

Adds a Three.js VectorKeyframeTrack definition with x y z values.

| Property | Value | |---|---| | Type | Command | | Opcode | addVectorKeyframeTrack | | CLIP | String, default: move-up | | PATH | String, default: .position | | TIMES | String, default: 0,0.5,1 | | VALUES | String, default: 0,1,-3, 0,1.5,-3, 0,1,-3 |

add quaternion keyframe track to clip [CLIP] path [PATH] times [TIMES] values [VALUES]

Adds a Three.js QuaternionKeyframeTrack definition with x y z w values.

| Property | Value | |---|---| | Type | Command | | Opcode | addQuaternionKeyframeTrack | | CLIP | String, default: wave | | PATH | String, default: .quaternion | | TIMES | String, default: 0,0.5,1 | | VALUES | String, default: 0,0,0,1, 0,0,0.389,0.921, 0,0,0,1 |

add euler rotation keyframe track to clip [CLIP] path [PATH] times [TIMES] values [VALUES] unit [UNIT]

Adds a quaternion track converted from Euler x y z rotation values.

| Property | Value | |---|---| | Type | Command | | Opcode | addEulerRotationKeyframeTrack | | CLIP | String, default: wave | | PATH | String, default: .quaternion | | TIMES | String, default: 0,0.25,0.5,0.75,1 | | VALUES | String, default: 0,0,0, 0,0,0.8, 0,0,0, 0,0,-0.8, 0,0,0 | | UNIT | String, default: radians |

add position keyframe to clip [CLIP] at [TIME] x [X] y [Y] z [Z]

Adds or replaces one position keyframe on the clip.

| Property | Value | |---|---| | Type | Command | | Opcode | addPositionKeyframe | | CLIP | String, default: move-up | | TIME | Number, default: 0 | | X | Number, default: 0 | | Y | Number, default: 1 | | Z | Number, default: -3 |

add scale keyframe to clip [CLIP] at [TIME] x [X] y [Y] z [Z]

Adds or replaces one scale keyframe on the clip.

| Property | Value | |---|---| | Type | Command | | Opcode | addScaleKeyframe | | CLIP | String, default: pulse | | TIME | Number, default: 0 | | X | Number, default: 1 | | Y | Number, default: 1 | | Z | Number, default: 1 |

add euler rotation keyframe to clip [CLIP] at [TIME] x [X] y [Y] z [Z] unit [UNIT]

Adds or replaces one Euler rotation keyframe converted to quaternion values.

| Property | Value | |---|---| | Type | Command | | Opcode | addEulerRotationKeyframe | | CLIP | String, default: wave | | TIME | Number, default: 0 | | X | Number, default: 0 | | Y | Number, default: 0 | | Z | Number, default: 0.8 | | UNIT | String, default: radians |

play 3D animation clip [CLIP] on selector [SELECTOR] loop [LOOP]

Plays a stored 3D animation clip on every matching node.

| Property | Value | |---|---| | Type | Command | | Opcode | playAnimationClip | | CLIP | String, default: wave | | SELECTOR | String, default: #leftArm | | LOOP | Boolean, default: true |

stop 3D animation clip [CLIP] on selector [SELECTOR]

Stops a stored 3D animation clip on every matching node.

| Property | Value | |---|---| | Type | Command | | Opcode | stopAnimationClip | | CLIP | String, default: wave | | SELECTOR | String, default: #leftArm |

pause 3D animation clip [CLIP] on selector [SELECTOR]

Pauses a stored 3D animation clip on every matching node.

| Property | Value | |---|---| | Type | Command | | Opcode | pauseAnimationClip | | CLIP | String, default: wave | | SELECTOR | String, default: #leftArm |

resume 3D animation clip [CLIP] on selector [SELECTOR]

Resumes a paused 3D animation clip on every matching node.

| Property | Value | |---|---| | Type | Command | | Opcode | resumeAnimationClip | | CLIP | String, default: wave | | SELECTOR | String, default: #leftArm |

set 3D animation clip [CLIP] on selector [SELECTOR] time scale [SCALE]

Sets the playback speed for a stored 3D animation clip on every matching node.

| Property | Value | |---|---| | Type | Command | | Opcode | setAnimationTimeScale | | CLIP | String, default: wave | | SELECTOR | String, default: #leftArm | | SCALE | Number, default: 1 |

is 3D animation clip [CLIP] playing on selector [SELECTOR]?

Reports whether any matching node has the stored 3D animation clip playing.

| Property | Value | |---|---| | Type | Boolean | | Opcode | isAnimationClipPlaying | | CLIP | String, default: wave | | SELECTOR | String, default: #leftArm |

load VRM [URL] onto [SELECTOR]

Loads a VRM avatar with three-vrm on the A-Frame Three.js and attaches it to the first matching node. The block waits until the model is ready.

| Property | Value | |---|---| | Type | Command | | Opcode | loadVrm | | URL | String, default: avatar.vrm | | SELECTOR | String, default: #avatar |

set VRM [SELECTOR] bone [BONE] rotation x [X] y [Y] z [Z]

Sets the Euler rotation in degrees of a normalized VRM humanoid bone, relative to the T-pose, on every matching node whose VRM is ready.

| Property | Value | |---|---| | Type | Command | | Opcode | setVrmBoneRotation | | SELECTOR | String, default: #avatar | | BONE | String, default: leftUpperArm | | X | Number, default: 0 | | Y | Number, default: 0 | | Z | Number, default: -60 |

VRM [SELECTOR] humanoid bones

Returns the humanoid bone names of the first matching node's VRM as a JSON array.

| Property | Value | |---|---| | Type | Reporter | | Opcode | vrmBoneNames | | SELECTOR | String, default: #avatar |

set VRM [SELECTOR] expression [NAME] to [WEIGHT]

Sets the weight, clamped to 0 through 1, of a preset or custom VRM expression such as happy or blink on every matching node whose VRM is ready.

| Property | Value | |---|---| | Type | Command | | Opcode | setVrmExpression | | SELECTOR | String, default: #avatar | | NAME | String, default: happy | | WEIGHT | Number, default: 1 |

VRM [SELECTOR] expressions

Returns the preset and custom expression names of the first matching node's VRM as a JSON array.

| Property | Value | |---|---| | Type | Reporter | | Opcode | vrmExpressionNames | | SELECTOR | String, default: #avatar |

VRM [SELECTOR] state

Returns none, loading, ready, or error with its reason for the first matching node.

| Property | Value | |---|---| | Type | Reporter | | Opcode | vrmState | | SELECTOR | String, default: #avatar |

Scene model

#scene is the root node. Every block operates on this extension-owned 3D graph; Scratch sprites, backdrops, clones, and the current sprite target are not imported into the node identity model.

Selectors intentionally support a small subset first:

  • #card
  • .monster
  • [data-zone=field]
  • *
  • @event or event target after an event hat runs

When a selector matches multiple nodes, command blocks apply to all matches. Blocks that require one node, such as template instantiation parents or event emitters, use the first match in graph insertion order.

Keyframe animations

Animation blocks create stored clip definitions and play them on matching node root object3D instances through AFRAME.THREE.AnimationMixer when A-Frame and Three.js are available. VectorKeyframeTrack supports .position and .scale; QuaternionKeyframeTrack supports .quaternion. glTF internals such as bones, child objects, and material properties are outside the initial scope. VRM humanoid bones are turned by the VRM blocks rather than by animation clips.

The CSV track blocks are low-level APIs that stay close to Three.js. Classroom and ordinary block projects should prefer the single-keyframe blocks: add position keyframe..., add scale keyframe..., and add euler rotation keyframe.... A keyframe with the same clip, path, and time replaces the earlier value.

Existing set selector [SELECTOR] rotation x [X] y [Y] z [Z] uses A-Frame rotation attributes in degrees. Quaternion tracks operate on Three.js object state, so Euler helper input must declare degrees or radians and is converted to quaternion values before playback.

Architecture

src/index.ts + src/extension.ts
  -> vite-plugin-turbowarp-extension
  -> dist/turbowarp-aframe.js

src/config.ts + src/block-definitions.json
  -> extension-api-manifest Vite plugin
  -> dist/extension-manifest.json

See docs/architecture.md for the issue #1 architecture, initial scope, rollback path, and AR fallback notes.

Development

pnpm run typecheck
pnpm run lint
pnpm run test
pnpm run build

The full repository check is:

pnpm run check

License

SPDX-License-Identifier: MPL-2.0

The bundle includes @pixiv/three-vrm under the MIT License; see THIRD_PARTY_NOTICES.md.

固定入力の編集

既定OFFの固定入力フォームと既存データの保持規則は固定入力エディターの契約を参照してください。