tapwithus/tap-web-sdk/tap-build-an-app

Claude Code and agent skill by tapwithus/tap-web-sdk

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Build a complete browser app or interactive experience controlled by a Tap - games, pages, presentations, or creative tools. Use when the user asks to build, make, or create something with their Tap, especially if they are not a developer.

Install

npx vskill@latest install tapwithus/tap-web-sdk/tap-build-an-app

SKILL.md

Build an app with a Tap

The user may not be a developer. Keep the project small, explain how to run it in plain words, and test with the real device.

Workflow

  1. Ask (only what is missing): device (Tap Strap / Tap Strap 2 / TapXR) and what the app should do. TapBand uses the same BLE API and is coming soon (waitlist). Never call it unsupported or buyable.
  2. Connect first. Use the tap-getting-started quickstart and confirm taps arrive before you build anything else.
  3. Pick the input (load the matching skill):
  • finger taps and combos: tap-tapping
  • raw swipes, pinches, fist: tap-vision-models
  • pointer, tilt, rotation: tap-imu-motion
  • twist-to-adjust value: tap-knob (TapSDKWeb2 app recipe)
  • directions + select + drag/rotate: tap-dpad (TapSDKWeb2 app recipe)
  • data recording: tap-raw-sensors
  1. Put the output on the same page.
  2. Build one interaction, test it with the user, then add the next.
  3. Give feedback: haptics (sendVibrationSequence) and on-screen state, so the user knows the gesture was seen.
  4. Deliver: one folder, a package.json that depends on @tapwithus/tapsdk, one HTML page, and one run command (npx serve or npx vite, on localhost).

Core pattern

Call connect() from a button click. It starts notifications. There is no start(). Register callbacks next, then enable input. Keep callback work short. Update state, then draw.

typescript
import {
connect,
isTapSDKWeb2,
DeviceFeatures,
InputModeController,
ModelTypes,
VisionSensorOpModes,
} from '@tapwithus/tapsdk';
document.querySelector('#connect')!.addEventListener('click', async () => {
const sdk = await connect();
if (isTapSDKWeb2(sdk)) {
sdk.registerTapEvents((_id, tapcode) => handle('tap', tapcode[0]));
sdk.registerAirGestureEvents((_id, gesture) => handle('air', gesture[0]));
await sdk.setFeature(DeviceFeatures.MODEL_DETECTION, true);
await sdk.setVisionSensorModel(ModelTypes.TAPPING);
await sdk.setVisionSensorOpMode(VisionSensorOpModes.TRIGGER);
} else {
sdk.registerTapEvents((_id, tapcode) => handle('tap', tapcode));
sdk.registerAirGestureEvents((_id, gesture) => handle('air', gesture));
await sdk.setInputMode(new InputModeController());
}
});

If a callback must not draw, push the event onto an array and read that array from requestAnimationFrame.

Output on the page

OutputHow
Status and textUpdate the DOM. Show "Click Connect", "Connected", or "Disconnected".
Game or visualCanvas or HTML elements in this page.
SoundWeb Audio in this page.
Keyboard fallbackkeydown on this page (arrow keys, space) calls the same functions as taps.

The browser cannot press keys in other applications and cannot change the OS volume. Keep the interaction inside the page.

Connect button and reconnect

Use this pattern when the app has its own buttons. It is the reconnect flow the SDK expects: the same page reuses the last Tap without the picker, and "Choose device" always shows the picker.

typescript
import { connect, getPermittedDevices, isTapSDKWeb2, type ConnectedTapSDK } from '@tapwithus/tapsdk';
const connectBtn = document.querySelector<HTMLButtonElement>('#connect')!;
const chooseBtn = document.querySelector<HTMLButtonElement>('#choose')!;
const statusEl = document.querySelector<HTMLElement>('#status')!;
let sdk: ConnectedTapSDK | null = null;
function setBusy(busy: boolean): void {
connectBtn.disabled = busy;
chooseBtn.disabled = busy;
}
async function attach(pending: Promise<ConnectedTapSDK>): Promise<void> {
setBusy(true); // one connection at a time; a second click would start a second connect()
try {
sdk = await pending;
// Register callbacks, then enable input (see the required order above).
statusEl.textContent = isTapSDKWeb2(sdk) ? 'Connected (framed firmware)' : 'Connected (classic firmware)';
} catch (err) {
statusEl.textContent = `Connection failed: ${(err as Error).message}`;
setBusy(false);
}
}
// Connect: reuses the Tap connected earlier in this page (about 3 s), else opens the picker.
connectBtn.addEventListener('click', () => void attach(connect()));
// Choose device: always opens the picker, for adding or switching Taps.
chooseBtn.addEventListener('click', () => void attach(connect({ reuseKnownDevice: false })));
// Optional: list devices the page was granted. Empty unless getDevices() is enabled (see flags).
const granted = await getPermittedDevices();

Notes:

  • connect() does not tell you whether it reused the Tap or opened the picker. If the picker opens after Connect, that is expected: the last Tap did not answer.
  • After a page reload, do not show a Reconnect button for granted Taps. Connecting fails with "no longer in range" while the Tap is still held by the OS. Tell the user to disconnect the Tap in system Bluetooth settings, then click Choose device.
  • Call setBusy(false) again on disconnect, as well as on error.

Rules

  • Do not add dependencies to the SDK. Add them to the app's package.json.
  • Import @tapwithus/tapsdk. Do not copy SDK source into the app.
  • Add a keyboard fallback so the user can test the page without the Tap.
  • Show connection status on screen.
  • Use Chrome or Edge. Serve the page on localhost or HTTPS.
  • Call connect() from a button click.
  • Offer Connect (connect(), which reuses the last Tap of the session) and Choose device… (connect({ reuseKnownDevice: false }), always the picker). After a page reload a Tap still held by the OS cannot be reconnected from the page, so do not build a reload-time Reconnect button. Tell the user to disconnect the Tap in system Bluetooth settings, then use the picker.
  • If you list getPermittedDevices(), feature-detect it. getDevices() needs a flag: Chrome chrome://flags/#enable-experimental-web-platform-features, Edge edge://flags/#enable-experimental-web-platform-features. Without it only this session's Taps are listed.
  • If the device does not connect, use the troubleshooting table in tap-getting-started.

Security

  • Security scanPassed, 95 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

7-day trend score
0

Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/tapwithus/tap-web-sdk/tap-build-an-app/badge)](https://verified-skill.com/skills/tapwithus/tap-web-sdk/tap-build-an-app)

Something wrong with this skill or its page? Tell us.