자주 묻는 질문 (FAQ)

VRISM Viewer SDK 사용 중 자주 발생하는 질문들과 해결책을 정리했습니다.

📍 마커/스텝 제어 관련

Q: 마커만 끄고 스텝 기능은 유지하고 싶어요

A: stepAnnotation: false로 설정하면 됩니다.

<VrismViewer
  token="your-token-here"
  contentId="your-content-id"
  ui={{
    step: {
      enabled: true,           // 스텝 기능 활성화
      stepControls: true,      // 이전/다음 버튼 표시
      stepDots: true,          // 도트 네비게이션 표시  
      stepAnnotation: false    // 🎯 마커만 끄기
    }
  }}
/>

Q: 스텝이 몇 개인지 어떻게 알 수 있나요?

A: 스텝의 전체 개수는 step.items에 추가한 아이템 수와 같습니다. 현재 스텝의 정보는 onStepChange 콜백에서 확인하거나, API 응답 데이터에서 확인할 수 있습니다.

function StepCounter() {
  const [totalSteps, setTotalSteps] = useState(0);
  const [currentStep, setCurrentStep] = useState(0);

  return (
    <VrismViewer
      token="your-token-here"
      contentId="your-content-id"
      ui={{ step: { enabled: true } }}
      onStepChange={(options) => {
        setCurrentStep(options.step || 0);
        // 일반적으로 API 응답에서 스텝 개수를 확인
      }}
      onLoadScene={() => {
        // 뷰어 로드 완료 후 스텝 정보 확인 가능
      }}
    />
  );
}

Q: 외부 버튼으로 스텝을 제어하고 싶어요

A: ref를 사용해서 setStep() 메서드를 호출하면 됩니다.

function CustomStepControl() {
  const viewerRef = useRef(null);

  return (
    <div>
      <button onClick={() => viewerRef.current?.setStep(0)}>1단계</button>
      <button onClick={() => viewerRef.current?.setStep(1)}>2단계</button>
      <button onClick={() => viewerRef.current?.setStep(2)}>3단계</button>
      
      <VrismViewer
        ref={viewerRef}
        token="your-token-here"
        contentId="your-content-id"
        ui={{
          step: {
            enabled: true,
            stepControls: false,  // 기본 버튼 숨김
            stepDots: false      // 기본 도트 숨김
          }
        }}
      />
    </div>
  );
}

⚡ 이벤트 처리 관련

Q: 로딩이 완료된 시점을 정확히 알고 싶어요

A: onLoadScene을 사용하세요. onLoadFinish는 로딩 바만 완료된 상태입니다.

<VrismViewer
  token="your-token-here"
  contentId="your-content-id"
  // ❌ 로딩 바 완료 (아직 사용 불가능할 수 있음)
  onLoadFinish={() => {
    console.log('로딩 바 100% 완료');
  }}
  // ✅ 뷰어 완전히 준비 완료 (API 호출 가능)
  onLoadScene={() => {
    console.log('뷰어 사용 준비 완료');
    // 이 시점에서 setStep(), setGestureGuideShow() 등 호출 가능
  }}
/>

Q: 에러가 발생했을 때 어떻게 처리하나요?

A: onError 콜백을 사용해서 에러를 처리하세요.

function ErrorHandlingViewer() {
  const [error, setError] = useState(null);
  
  if (error) {
    return (
      <div className="error-display">
        <h3>뷰어 로딩 실패</h3>
        <p>{error.message}</p>
        <button onClick={() => setError(null)}>다시 시도</button>
      </div>
    );
  }
  
  return (
    <VrismViewer
      token="your-token-here"
      contentId="your-content-id"
      onError={(error) => {
        console.error('뷰어 에러:', error);
        setError(error);
      }}
    />
  );
}

🐛 에러 해결 관련

Q: "Invalid token" 에러가 발생해요

A: 다음 사항들을 확인해보세요:

  1. 토큰 형식 확인: 토큰이 올바른 형식인지 확인
  2. 토큰 만료: 토큰이 만료되지 않았는지 확인
  3. 토큰 권한: 해당 contentId에 대한 권한이 있는지 확인
// 토큰 검증 예시
<VrismViewer
  token="your-valid-token-here"
  contentId="your-content-id"
  onError={(error) => {
    if (error.message.includes('token')) {
      alert('토큰이 유효하지 않습니다. 토큰을 확인해주세요.');
    }
  }}
/>

Q: 뷰어가 검은 화면만 나와요

A: 다음을 확인해보세요:

  1. 컨테이너 크기: 부모 요소에 적절한 width/height 설정
  2. contentId 확인: 올바른 contentId인지 확인
  3. 네트워크 연결: 3D 모델 로딩이 차단되지 않았는지 확인
// 컨테이너 크기 확실히 설정
<div style={{ width: '100%', height: '500px' }}>
  <VrismViewer
    token="your-token-here"
    contentId="your-content-id"
    onLoadScene={() => console.log('로딩 성공')}
    onError={(error) => console.error('로딩 실패:', error)}
  />
</div>

🚀 성능 최적화 팁

Q: 여러 뷰어를 한 페이지에 사용해도 되나요?

A: 권장하지 않습니다. 성능상 페이지당 하나의 뷰어만 사용하세요.

// ❌ 비추천: 여러 뷰어 동시 사용
function MultipleViewers() {
  return (
    <div>
      <VrismViewer token="token1" contentId="content1" />
      <VrismViewer token="token2" contentId="content2" />
    </div>
  );
}

// ✅ 추천: 탭으로 구분하여 하나씩 표시
function TabViewers() {
  const [activeTab, setActiveTab] = useState(0);
  
  return (
    <div>
      <div className="tabs">
        <button onClick={() => setActiveTab(0)}>제품 A</button>
        <button onClick={() => setActiveTab(1)}>제품 B</button>
      </div>
      
      {activeTab === 0 && (
        <VrismViewer token="token1" contentId="content1" />
      )}
      {activeTab === 1 && (
        <VrismViewer token="token2" contentId="content2" />
      )}
    </div>
  );
}

Q: 뷰어를 언마운트할 때 메모리 정리는 어떻게 하나요?

A: React의 컴포넌트 언마운트 시 자동으로 정리되지만, 수동으로도 할 수 있습니다.

function ViewerWithCleanup() {
  const viewerRef = useRef(null);
  
  useEffect(() => {
    return () => {
      // 컴포넌트 언마운트 시 수동 정리
      viewerRef.current?.destroy();
    };
  }, []);
  
  return (
    <VrismViewer
      ref={viewerRef}
      token="your-token-here"
      contentId="your-content-id"
    />
  );
}

🔧 기타

Q: TypeScript 지원이 되나요?

A: 네, 완전히 지원됩니다.

import { VrismViewer, type VrismViewerProps } from '@vrism/viewer-sdk';

const viewerProps: VrismViewerProps = {
  token: "your-token-here",
  contentId: "your-content-id",
  ui: {
    viewerBackgroundColor: '#ffffff',
    gestureGuide: true
  }
};

function TypedViewer() {
  return <VrismViewer {...viewerProps} />;
}

💡 더 도움이 필요하다면

문제가 해결되지 않으면 VRISM에 문의해주세요.