---
id: web-webtransport-hid-usb
title: WebTransport / WebHID / WebUSB / WebSerial
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [web, transport, hardware, vibe-coding]
tech_stack: { language: "TS", applicable_to: ["Frontend"] }
applied_in: []
aliases: [WebTransport, WebHID, WebUSB, WebSerial, Web Bluetooth, Web NFC, hardware API]
---

# WebTransport / WebHID / WebUSB

> Browser 가 native-like 영역. **WebTransport (HTTP/3 stream), WebHID (game controller, MIDI), WebUSB (firmware flash), WebSerial (Arduino)**.

## 📖 핵심 개념
- WebTransport: WebSocket 보다 빠름 (HTTP/3, UDP).
- WebHID: human interface device.
- WebUSB: 임의 USB.
- WebSerial: serial port.

## 💻 코드 패턴

### WebTransport
```ts
const transport = new WebTransport('https://server.example.com/wt');
await transport.ready;

// Bidirectional stream
const stream = await transport.createBidirectionalStream();
const writer = stream.writable.getWriter();
await writer.write(new TextEncoder().encode('hello'));
await writer.close();

const reader = stream.readable.getReader();
const { value } = await reader.read();
console.log(new TextDecoder().decode(value));
```

→ HTTP/3 + QUIC. Multiple stream 가 1 connection.

### Datagram (unreliable, fast)
```ts
const writer = transport.datagrams.writable.getWriter();
await writer.write(new Uint8Array([1, 2, 3]));

const reader = transport.datagrams.readable.getReader();
const { value } = await reader.read();
```

→ UDP-like. Game / WebRTC alternative.

### WebTransport server (Node)
```ts
// 일부 server library 만 지원
import { Http3Server } from '@fails-components/webtransport';

const server = new Http3Server({ port: 4433, host: '0.0.0.0' });
server.startServer();

const sessions = await server.sessionStream('/wt');
for await (const session of sessions) {
  // ... handle
}
```

→ HTTP/3 stack 필요. Bun / Node 가 부분 지원.

### WebHID (game controller)
```ts
const devices = await navigator.hid.requestDevice({
  filters: [{ vendorId: 0x054c }],  // Sony
});

const device = devices[0];
await device.open();

device.addEventListener('inputreport', (e) => {
  const { data, reportId } = e;
  // Parse report (game controller state)
});
```

### MIDI controller
```ts
const access = await navigator.requestMIDIAccess();

for (const input of access.inputs.values()) {
  input.onmidimessage = (e) => {
    const [status, note, velocity] = e.data;
    // Note on, note off, ...
  };
}
```

### WebUSB (firmware update)
```ts
const device = await navigator.usb.requestDevice({
  filters: [{ vendorId: 0x2341 }],  // Arduino
});

await device.open();
await device.selectConfiguration(1);
await device.claimInterface(0);

// Send
await device.transferOut(1, new TextEncoder().encode('hello'));

// Receive
const r = await device.transferIn(2, 64);
console.log(new Uint8Array(r.data!.buffer));
```

→ Sketch upload, firmware flash.

### WebSerial (Arduino, ESP32)
```ts
const port = await navigator.serial.requestPort();
await port.open({ baudRate: 9600 });

const writer = port.writable!.getWriter();
await writer.write(new TextEncoder().encode('led on\n'));

const reader = port.readable!.getReader();
while (true) {
  const { value, done } = await reader.read();
  if (done) break;
  console.log(new TextDecoder().decode(value));
}
```

### Web Bluetooth
```ts
const device = await navigator.bluetooth.requestDevice({
  filters: [{ services: ['heart_rate'] }],
});

const server = await device.gatt!.connect();
const service = await server.getPrimaryService('heart_rate');
const char = await service.getCharacteristic('heart_rate_measurement');

await char.startNotifications();
char.addEventListener('characteristicvaluechanged', (e) => {
  const value = (e.target as any).value;
  console.log('heart rate:', value.getUint8(1));
});
```

### Web NFC (Android)
```ts
if ('NDEFReader' in window) {
  const ndef = new NDEFReader();
  await ndef.scan();
  
  ndef.onreading = ({ message }) => {
    for (const r of message.records) {
      console.log(r.recordType, r.data);
    }
  };
}
```

→ Android Chrome 만.

### Permission
```
모든 = user gesture (click) 필수.
사용자 가 device picker 에서 grant.
HTTPS 만.
```

### Use case
```
WebTransport: WebSocket 의 modern, low-latency game / streaming.
WebHID: Game controller, MIDI, custom HID.
WebUSB: Hardware programmer, firmware tool.
WebSerial: Arduino IDE in browser, debugging.
Web Bluetooth: IoT, fitness tracker.
Web NFC: Tag reader, payment (Android).
```

### Browser support
```
WebTransport: Chrome 97+, FF / Safari 가 부분.
WebHID: Chrome 89+, Edge.
WebUSB: Chrome 61+. FF / Safari 가 안 (security 우려).
WebSerial: Chrome 89+.
Web Bluetooth: Chrome 56+.
Web NFC: Chrome Android 81+.
```

→ 대부분 Chrome / Edge / Opera 만.

### Permission Policy
```html
<!-- iframe 가 사용 -->
<iframe allow="hid; usb; serial; bluetooth"></iframe>
```

### Reconnect
```ts
// USB
navigator.usb.addEventListener('connect', (e) => {
  // device 가 다시 connected
});
navigator.usb.addEventListener('disconnect', (e) => {});

// 같은 device 가 자동 reconnect 안 됨 — 사용자 picker 다시.
```

### Persistent permission
```ts
// 이전 grant 된 device list
const devices = await navigator.hid.getDevices();
for (const d of devices) {
  if (!d.opened) await d.open();
}
```

→ User 가 picker 안 다시 — handle 가 영구.

### 함정
```
- Chrome 만 = userbase 한계.
- HID parsing 어려움 (binary).
- Connection drop 자주.
- Sandbox 안에서만 (system file system 안 됨).
- HTTPS only.
```

### Native vs Web
```
Web:
- Distribution easy
- 자동 update
- 작은 surface (특정 device 만)

Native:
- 큰 권한
- Performance
- 모든 device

→ 작은 use case = Web. 큰 = Native.
```

### WebGPU (powerful)
```ts
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter!.requestDevice();
// ... shader, pipeline, render
```

→ GPU 사용. ML / 3D.

→ [[Frontend_WebGPU_Patterns]].

### File over USB (e.g. ADB)
```ts
// Chrome OS 의 Android device debug
const device = await navigator.usb.requestDevice({
  filters: [{ classCode: 0xff, subclassCode: 0x42 }],  // ADB
});
```

→ Chrome OS 의 Android Studio web 같은 것.

### Audio / video device
```ts
// MediaDevices API (다름)
const stream = await navigator.mediaDevices.getUserMedia({
  audio: { deviceId: '...' },
  video: { deviceId: '...' },
});
```

→ Camera, microphone, screen share.

### WebRTC vs WebTransport
```
WebRTC:
- Peer-to-peer
- DTLS + SRTP
- 복잡 setup (signaling, ICE)

WebTransport:
- Client-server
- HTTP/3 + QUIC
- Simple

→ Game / streaming = WebTransport. Conferencing = WebRTC.
```

### Browser WASM 가 native-like
```
+ 위 device API
+ WebGPU (GPU)
+ WASM (CPU)
+ File System Access (file)
+ Service Worker (background)
+ Push API (notification)
+ Periodic Sync

→ "Web 가 Win32 / macOS API 와 비슷" 가 modern.
```

### Production 사용
- StackBlitz / WebContainer — Node in browser
- Figma — file, hardware (palette device)
- Photopea — Photoshop in browser
- VS Code Web — File system + ext
- Adafruit — Arduino in browser (WebSerial + WebUSB)

## 🤔 의사결정 기준
| 작업 | 추천 |
|---|---|
| Low-latency game/stream | WebTransport |
| Game controller / MIDI | WebHID |
| Firmware flash | WebUSB |
| Arduino REPL | WebSerial |
| IoT 통신 | Web Bluetooth |
| NFC tag | Web NFC (Android) |
| Cross-browser 필요 | WebSocket / Bluetooth fallback X |
| GPU compute | WebGPU |

## ❌ 안티패턴
- **모든 browser 가정**: Chrome 만 흔함.
- **User gesture 없이**: error.
- **HTTPS 안**: blocked.
- **HID report parse 무기준**: binary 잘못.
- **Disconnect handling 없음**: hang.
- **Persistent permission 무시**: 매번 picker.
- **WebTransport server 없이**: fail.

## 🤖 LLM 활용 힌트
- WebTransport = HTTP/3 stream + datagram (WebSocket 의 모던).
- WebHID / WebUSB / WebSerial = Chrome 만.
- User gesture + HTTPS 의무.
- Native vs Web — 작은 use case.

## 🔗 관련 문서
- [[Web_WebRTC_Realtime]]
- [[Web_WebSocket_Reconnect]]
- [[Frontend_WebGPU_Patterns]]
