edutap.ai developers
SDK 연동

API Reference

TapKit의 전체 API 레퍼런스

API Reference

TapKitElement

<tap-kit> Web Component 요소입니다.

API 요약

라이프사이클

API설명
ready초기화 완료 Promise
isInitialized초기화 완료 여부 (boolean)

UI 제어

API설명
show()채팅 컨테이너 표시
hide()채팅 컨테이너 숨김
isOpen채팅 열림 상태 (boolean)

코스 정보

API설명
setCourse({ courseId, clipId, userId?, clipPlayHead? })코스 정보 업데이트

이벤트 (kit.events)

API설명
seekTimeline({ clipPlayHead, clipId })타임라인 이동 요청
onTimelineSeek(callback)타임라인 seek 이벤트 구독, unsubscribe 함수 반환
onAlarmFadeIn(handler)알람 표시 이벤트 구독, unsubscribe 함수 반환

비디오 (kit.video)

API설명
bind(config, clipId?)비디오 플레이어 바인딩 (타임라인 동기화)
unbind()비디오 바인딩 해제

Properties

apiKey: string (write-only)

보안

Property로만 설정 가능합니다. HTML attribute로 설정하지 마세요.

kit.apiKey = 'your-api-key';  // O
// <tap-kit api-key="..."> 사용 금지

userId: string

kit.userId = 'user-123';
// 또는 <tap-kit user-id="user-123">

courseId: string

kit.courseId = 'course-456';

clipId: string

kit.clipId = 'clip-789';

clipPlayHead: number

재생 위치 (초 단위)입니다.

kit.clipPlayHead = 100;

language: "ko" | "en"

언어 설정입니다. 기본값은 "ko"입니다.

kit.language = 'en';
// 또는 <tap-kit language="en">

mode: "inline" | "floating" | "sidebar"

표시 모드입니다. 기본값은 "inline"입니다.

설명
inline페이지 콘텐츠에 임베드 (기본값)
floating화면에 떠있는 컴팩트 위젯
sidebar화면 우측 전체 높이 사이드바
kit.mode = 'floating';
// 또는 <tap-kit mode="sidebar">

allowLayoutToggle: boolean

floatingsidebar 모드 간 전환 버튼 표시 여부입니다. 기본값은 true입니다.

kit.allowLayoutToggle = false;  // 레이아웃 토글 버튼 숨김

videoTarget: HTMLVideoElement | VideoAdapter

비디오 플레이어 동기화를 위한 선언적 바인딩입니다. video.bind() 대신 권장됩니다.

// HTMLVideoElement
kit.videoTarget = document.querySelector('video');

// VideoAdapter (YouTube, Vimeo 등)
kit.videoTarget = {
  getCurrentTime: () => player.getCurrentTime(),
  setCurrentTime: (time, clipId) => player.seekTo(time),  // clipId는 cross-clip seeking용 (optional)
};

videoTarget은 라이프사이클 변경(mode 변경, 재연결)에도 유지됩니다.

buttonId: string

커스텀 버튼 요소 ID입니다.

debug: boolean

디버그 로깅 활성화 여부입니다.

isOpen: boolean (read-only)

채팅이 현재 열려있는지 확인합니다.

isInitialized: boolean (read-only)

SDK 초기화가 완료되었는지 확인합니다.

ready: Promise<void> (read-only)

SDK가 준비될 때까지 대기하는 Promise입니다.

await kit.ready;
kit.show();

Methods

show(): void

채팅 창을 표시합니다.

hide(): void

채팅 창을 숨깁니다.

setCourse(course): void

강의 정보를 업데이트합니다.

interface SetCourseParams {
  userId?: string;
  courseId: string;    // 필수
  clipId: string;      // 필수
  clipPlayHead?: number;
}
kit.setCourse({
  courseId: 'course-999',
  clipId: 'clip-001',
  clipPlayHead: 50
});

Events

tap-kit:ready

SDK 초기화가 완료되면 발생합니다.

kit.addEventListener('tap-kit:ready', () => {
  console.log('TapKit이 준비되었습니다!');
});

tap-kit:error

초기화 중 오류가 발생하면 발생합니다.

kit.addEventListener('tap-kit:error', (e) => {
  console.error('TapKit 오류:', e.detail.error);
});

kit.events

이벤트 관련 API입니다.

kit.events.seekTimeline(params): void

타임라인을 특정 위치로 이동합니다.

interface SeekTimelineParams {
  clipPlayHead: number;  // 이동할 위치 (초 단위)
  clipId: string;
}
kit.events.seekTimeline({ clipPlayHead: 100, clipId: 'clip-789' });

kit.events.onTimelineSeek(handler): () => void

타임라인 이동 이벤트를 리스닝합니다. Unsubscribe 함수를 반환합니다.

const unsubscribe = kit.events.onTimelineSeek((playHead, clipId) => {
  console.log(`${playHead}초로 이동: ${clipId}`);
  videoElement.currentTime = playHead;
});

// 구독 해제
unsubscribe();

kit.events.onAlarmFadeIn(handler): () => void

알림이 도착할 때 발생하는 이벤트를 리스닝합니다.

const unsubscribe = kit.events.onAlarmFadeIn((alarm) => {
  console.log('새 알림:', alarm.message);
});

kit.video

비디오 플레이어 동기화 API입니다.

왜 video.bind가 중요한가요?

video.bind()를 사용하면:

  • AI 튜터가 현재 재생 시점을 인식하여 정확한 답변 제공
  • 채팅에서 특정 구간 클릭 시 비디오 자동 이동
  • setCourse() 호출 시 자동으로 새 clipId 추적

kit.video.bind(config, clipId?): void

비디오 플레이어를 TapKit과 동기화합니다.

ParameterTypeRequiredDescription
configHTMLVideoElement | VideoAdapterO비디오 요소 또는 커스텀 어댑터
clipIdstring생략 시 SDK 설정에서 자동 추적
interface VideoAdapter {
  getCurrentTime: () => number;
  setCurrentTime: (time: number, clipId?: string) => void;  // clipId는 cross-clip seeking용
}

자동 추적 (권장):

kit.video.bind(videoElement);

// 나중에 강의 변경 시 자동으로 새 clipId 사용
kit.setCourse({ courseId: 'new-course', clipId: 'new-clip' });

커스텀 어댑터 (YouTube 등):

kit.video.bind({
  getCurrentTime: () => player.getCurrentTime(),
  // clipId는 optional - cross-clip seeking 시 활용
  setCurrentTime: (time, clipId) => player.seekTo(time, true),
});

kit.video.unbind(): void

비디오 플레이어 동기화를 해제합니다.

kit.video.unbind();

createTapKit()

<tap-kit> Web Component 요소를 프로그래밍 방식으로 생성하고 제어할 수 있는 Factory API입니다.

npm 패키지와 CDN 모두에서 사용 가능합니다.

  • npm: import { createTapKit } from '@coxwave/tap-kit'
  • CDN: window.createTapKit(...)

React 프로젝트에서는 useTapKit Hook을 권장합니다.

Syntax

// npm 패키지
import { createTapKit } from '@coxwave/tap-kit';

const tapkit = createTapKit(options);
tapkit.mount();        // DOM에 추가 (필수)
await tapkit.ready;    // 초기화 완료 대기
tapkit.show();         // 채팅 창 표시

Parameters

PropertyTypeRequiredDescription
apiKeystringOTapKit API 키
userIdstring사용자 ID
courseIdstring강의 ID
clipIdstring클립 ID
clipPlayHeadnumber초기 재생 위치 (초 단위)
language'ko' | 'en'언어 설정
mode'inline' | 'floating' | 'sidebar'표시 모드 (기본값: 'floating')
allowLayoutTogglebooleanfloating↔sidebar 토글 허용 (기본값: true)
videoTargetHTMLVideoElement | VideoAdapter비디오 플레이어 바인딩
buttonIdstring커스텀 버튼 요소 ID
debugboolean디버그 로깅 활성화

Advanced Options (테스트/개발용):

PropertyTypeDescription
apiUrlstring백엔드 API URL (예: 'https://tapapistaging.coxwave.link')
tapUrlstringiframe URL (내부 테스트용)
environment'dev' | 'prod' | 'staging' | 'demo'환경 설정

Event Handlers:

PropertyTypeDescription
onReady() => voidSDK 초기화 완료 시 호출
onError(error: Error) => void오류 발생 시 호출
onTimelineSeek(time: number, clipId: string) => void타임라인 이동 이벤트
onAlarmFadeIn(info: unknown) => void알람 표시 이벤트

Return Value: TapKitFactoryControl

Property/MethodTypeDescription
readyPromise<void>초기화 완료 Promise
isReadyboolean초기화 완료 여부
isOpenboolean채팅 열림 상태
isMountedbooleanDOM에 마운트 여부
mount(container?)voidDOM에 추가 (필수)
unmount()voidDOM에서 제거
show()void채팅 창 표시
hide()void채팅 창 숨김
setCourse(course)void코스 정보 업데이트
eventsEventManager이벤트 API
videoVideoController비디오 API
elementTapKitElement | null내부 요소 접근
destroy()void인스턴스 정리

Example (npm 패키지)

import { createTapKit } from '@coxwave/tap-kit';

const tapkit = createTapKit({
  apiKey: 'your-api-key',
  userId: 'user-123',
  courseId: 'course-456',
  clipId: 'clip-789',

  // 환경 설정 (테스트용)
  apiUrl: 'https://tapapistaging.coxwave.link',
  environment: 'staging',

  // 이벤트 핸들러
  onReady: () => console.log('Ready!'),
  onTimelineSeek: (time, clipId) => {
    videoElement.currentTime = time;
  },
});

// DOM에 추가 (필수)
tapkit.mount();

// 또는 특정 컨테이너에 추가
tapkit.mount(document.getElementById('chat-container'));

// 초기화 완료 대기
await tapkit.ready;

// 채팅 창 표시
tapkit.show();

// 정리
tapkit.destroy();

Example (CDN)

<script src="https://files.edutap.ai/tap-sdk/loader.js"></script>
<script>
  const kit = window.createTapKit({
    apiKey: 'your-api-key',
    userId: 'user-123',
    courseId: 'course-456',
    clipId: 'clip-789'
  });

  document.body.appendChild(kit);
  kit.ready.then(() => kit.show());
</script>

CSS Variables

UI 스타일링을 위한 CSS 변수는 스타일링 가이드를 참조하세요.


TypeScript Types

TapKitConfig

interface TapKitConfig {
  apiKey: string;
  userId?: string;
  courseId?: string;
  clipId?: string;
  clipPlayHead?: number;
  language?: 'ko' | 'en';
  mode?: 'inline' | 'floating' | 'sidebar';
  allowLayoutToggle?: boolean;
  videoTarget?: HTMLVideoElement | VideoAdapter;
  buttonId?: string;
  debug?: boolean;
}

TapKitElement

interface TapKitElement extends HTMLElement {
  // Properties
  apiKey: string;
  userId?: string;
  courseId?: string;
  clipId?: string;
  clipPlayHead?: number;
  language?: 'ko' | 'en';
  mode?: 'inline' | 'floating' | 'sidebar';
  allowLayoutToggle: boolean;
  videoTarget?: HTMLVideoElement | VideoAdapter;
  buttonId?: string;
  debug: boolean;

  // Read-only
  readonly isOpen: boolean;
  readonly isInitialized: boolean;
  readonly ready: Promise<void>;

  // Methods
  show(): void;
  hide(): void;
  setCourse(params: SetCourseParams): void;

  // Sub-APIs
  readonly events: {
    seekTimeline(params: { clipPlayHead: number; clipId: string }): void;
    onTimelineSeek(handler: (playHead: number, clipId: string) => void): () => void;
    onAlarmFadeIn(handler: (messageInfo: AlarmMessageInfo) => void): () => void;
  };

  readonly video: {
    bind(config: HTMLVideoElement | VideoAdapter, clipId?: string): void;
    unbind(): void;
  };
}

VideoAdapter

interface VideoAdapter {
  getCurrentTime: () => number;
  /**
   * @param time - 이동할 시간 (초)
   * @param clipId - cross-clip seeking 시 대상 클립 ID (optional)
   */
  setCurrentTime: (time: number, clipId?: string) => void;
}

다음 단계