edutap.ai developers

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) (deprecated - videoTarget 권장)

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 | VideoPlayerAdapter

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

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

// VideoPlayerAdapter (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

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

Static Properties

TapKit.version: string (read-only)

현재 SDK 버전을 반환합니다.

console.log(TapKit.version);  // "2.1.0"

TapKit.buildEnv: string (read-only)

현재 빌드 환경을 반환합니다. ("prod", "staging", "dev", "demo")

console.log(TapKit.buildEnv);  // "prod"

Advanced Properties

아래 속성들은 테스트/개발 환경용입니다. 프로덕션에서는 일반적으로 사용하지 않습니다.

apiUrl: string

백엔드 API URL입니다. Staging/Demo 환경 테스트 시 사용합니다.

kit.apiUrl = 'https://tapapistaging.coxwave.link';

tapUrl: string

iframe URL입니다. 내부 테스트용이며 일반적으로 수정하지 마세요.

environment: "dev" | "prod" | "staging" | "demo"

환경 설정입니다. 로깅 레벨 및 기본 URL에 영향을 줍니다.

kit.environment = 'staging';

root: HTMLElement (deprecated)

Deprecated

이 속성은 더 이상 위치 지정에 영향을 주지 않습니다. floating/sidebar 모드에서 컨테이너는 항상 document.body에 렌더링됩니다.

// ❌ 더 이상 사용하지 마세요
kit.root = document.getElementById('chat-container');

Read-only Properties

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);
});

tap-kit:iframe-retry

iframe 로드 실패 후 재시도할 때 발생합니다.

interface IframeRetryEvent {
  attempt: number;      // 현재 재시도 횟수
  error: Error;         // 발생한 에러
  nextDelay: number;    // 다음 재시도까지 대기 시간 (ms)
}
kit.addEventListener('tap-kit:iframe-retry', (e) => {
  console.log(`iframe 재시도 중... (${e.detail.attempt}번째, ${e.detail.nextDelay}ms 후 재시도)`);
  console.error('에러:', e.detail.error.message);
});

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

Deprecated

kit.video.bind() API는 deprecated되었습니다. 대신 videoTarget 속성을 사용하세요. videoTarget은 라이프사이클 변경에도 자동으로 유지되어 더 안정적입니다.

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

왜 video.bind가 중요한가요?

video.bind()를 사용하면:

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

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

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

ParameterTypeRequiredDescription
configHTMLVideoElement | VideoPlayerAdapterO비디오 요소 또는 커스텀 어댑터
clipIdstring생략 시 SDK 설정에서 자동 추적
interface VideoPlayerAdapter {
  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 | VideoPlayerAdapter비디오 플레이어 바인딩
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

Legacy Class API (new TapKit()) 생성자용 타입입니다.

interface TapKitConfig {
  apiKey: string;
}

CreateTapKitOptions

createTapKit()useTapKit() API용 설정 타입입니다.

interface CreateTapKitOptions {
  // Required
  apiKey: string;

  // Course Information
  userId?: string;
  courseId?: string;
  clipId?: string;
  clipPlayHead?: number;

  // Display Options
  language?: 'ko' | 'en';
  mode?: 'inline' | 'floating' | 'sidebar';
  allowLayoutToggle?: boolean;
  videoTarget?: HTMLVideoElement | VideoPlayerAdapter;
  buttonId?: string;
  debug?: boolean;

  // Advanced Options (테스트/개발용)
  apiUrl?: string;
  tapUrl?: string;
  environment?: 'dev' | 'prod' | 'staging' | 'demo';

  // Event Handlers
  onReady?: () => void;
  onError?: (error: Error) => void;
  onTimelineSeek?: (clipPlayHead: number, clipId: string) => void;
  onAlarmFadeIn?: (messageInfo: AlarmMessageInstanceType) => void;
}

TapKitElement

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

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 | VideoPlayerAdapter;
  buttonId?: string;
  debug: boolean;

  // Advanced Properties
  apiUrl?: string;
  tapUrl?: string;
  environment?: 'dev' | 'prod' | 'staging' | 'demo';
  /** @deprecated This property no longer affects positioning */
  root?: HTMLElement;

  // 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: AlarmMessageInstanceType) => void): () => void;
  };

  /** @deprecated Use videoTarget property instead */
  readonly video: {
    bind(config: HTMLVideoElement | VideoPlayerAdapter, clipId?: string): void;
    unbind(): void;
  };
}

AlarmMessageInstanceType

알람 메시지 정보 타입입니다.

interface AlarmMessageInstanceType {
  type: 'basic:welcome' | 'basic:default' | 'feat:quiz' | 'feat:guide' | 'feat:progress' | 'custom:cheer';
  content: AlarmElement;
}

interface AlarmElement {
  tag: string;
  props?: Record<string, unknown>;
  children?: (AlarmElement | string)[];
  payload?: {
    type: 'startChat';
    message: string;
    pingMessageId?: string;
  };
}

VideoPlayerAdapter

커스텀 비디오 플레이어 (YouTube, Vimeo, Video.js 등) 연동용 인터페이스입니다.

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

/** HTMLVideoElement 또는 커스텀 어댑터 */
type VideoPlayerConfig = HTMLVideoElement | VideoPlayerAdapter;

TapButtonElement

<tap-button> Web Component는 AI 튜터 채팅을 열기 위한 플로팅 버튼입니다.

기본 사용법

<!-- TapKit과 함께 사용 (자동 토글) -->
<tap-kit user-id="user-123" course-id="course-456" clip-id="clip-789"></tap-kit>
<tap-button position="bottom-right" size="large"></tap-button>

<script>
  const kit = document.querySelector('tap-kit');
  kit.apiKey = 'your-api-key';
</script>

<tap-button><tap-kit>과 같은 페이지에 있으면 자동으로 연결되어 클릭 시 채팅창이 토글됩니다.

Attributes

position: string

버튼의 화면 위치를 지정합니다. 기본값은 "bottom-right"입니다.

설명
bottom-right화면 우측 하단 (기본값)
bottom-left화면 좌측 하단
top-right화면 우측 상단
top-left화면 좌측 상단
custom사용자 정의 위치 (inline style로 지정)
<tap-button position="bottom-left"></tap-button>

<!-- custom 위치 예시 -->
<tap-button position="custom" style="top: 100px; right: 50px;"></tap-button>

size: string

버튼 크기를 지정합니다. 기본값은 "large"입니다.

크기
small48px
medium56px
large64px (기본값)
<tap-button size="small"></tap-button>

floating: string

포지셔닝 모드를 설정합니다. 기본값은 플로팅(fixed) 모드입니다.

설명
(생략)플로팅 모드 (position: fixed)
"false"정적 모드 (일반 문서 흐름)
<!-- 플로팅 모드 (기본) -->
<tap-button></tap-button>

<!-- 정적 모드: 일반 요소처럼 배치 -->
<tap-button floating="false"></tap-button>

language: string

툴팁 언어를 설정합니다. 기본값은 "ko"입니다.

<tap-button language="en"></tap-button>

tutor-name: string

툴팁에 표시할 튜터 이름입니다. 설정하지 않으면 기본 문구가 표시됩니다.

<tap-button tutor-name="에듀탭 선생님"></tap-button>

커스텀 아이콘

슬롯을 사용하여 버튼 내용을 커스터마이징할 수 있습니다.

<tap-button position="bottom-right">
  <img src="/my-tutor-icon.svg" alt="AI 튜터" />
</tap-button>

CSS Shadow Parts

외부 스타일링을 위한 CSS Shadow Parts를 제공합니다.

tap-button::part(button) {
  background: linear-gradient(135deg, #6366f1, #8b5cf6);
  border-radius: 50%;
}

tap-button::part(tooltip) {
  background: #1f2937;
  color: white;
}

Events

tap-button:click

버튼 클릭 시 발생합니다. <tap-kit>이 있으면 자동으로 채팅이 토글됩니다.

const button = document.querySelector('tap-button');
button.addEventListener('tap-button:click', (e) => {
  console.log('버튼 클릭됨', e.detail);
});

다음 단계