# dwg-dxf-viewer-sample

DWG/DXF 2D viewer module과 다중 포맷 3D viewer sample을 함께 관리하는
Three.js 기반 npm workspace입니다.

현재 구현은 파일을 브라우저에서 파싱하고 화면에 표시하는 기술 검증용입니다.
좌표, 단위, 원점, 형상 허용오차, topology와 CAD/BIM 의미 정보의 보존을
보장하는 운영용 engineering viewer로는 아직 검증되지 않았습니다.

## 검토 기준

| 항목 | 내용 |
|---|---|
| 기준일 | 2026-07-29 |
| 기준 commit | `3279ac099ec30bb52363710c73fbd4fe174b707b` |
| 기준 tree | 위 commit과 2026-07-29 작업 tree의 미커밋 변경 포함 |
| 대상 | `cyhan/dwg-dxf-viewer-sample` |
| 참조 | 형제 저장소 `hmwebviewer/README.md`의 분석 구조와 3D asset provenance |
| 검토 범위 | workspace 구조, 2D/3D 기능, source·test·build 설정, 입력 경계, npm dependency, WASM·font·decoder·fixture license |
| 기능 판정 | **내부 개발·기능 검증 조건부 GO** |
| 외부 배포 판정 | **NO-GO — license·source 제공·asset provenance blocker 존재** |

외부 배포 판정은 기술적인 compliance 준비 상태를 뜻합니다. 법률 자문이 아니며,
실제 계약·특허·상표와 배포 승인은 조직의 법무·오픈소스 정책으로 확정해야 합니다.

## Workspace 구성

| Workspace | 역할 | 주요 runtime |
|---|---|---|
| `apps/viewer-2d-sample` | DWG/DXF sample UI와 입력 정책 | `@hmwebviewer/viewer2d`, Three.js |
| `packages/viewer2d` | 재사용 가능한 2D parser·renderer module | `dxf-parser`, `opentype.js`, Three.js peer, acadrust WASM |
| `apps/viewer-3d` | 다중 포맷 3D static web application | Three.js, `web-ifc` |

```text
dwg-dxf-viewer-sample/
├─ apps/
│  ├─ viewer-2d-sample/   # 2D sample application
│  └─ viewer-3d/          # 3D sample application과 offline 도구
├─ packages/
│  └─ viewer2d/           # 2D public module
├─ tests/                 # Vitest와 Playwright
├─ LICENSES/              # 현재 MPL-2.0, OFL-1.1 전문
├─ THIRD_PARTY_NOTICES.md
└─ docs/PROVENANCE.md
```

세 workspace는 `"private": true`이며 npm registry 배포용 package가 아닙니다.
`@hmwebviewer/viewer2d`의 export도 현재 TypeScript source를 직접 가리키므로,
독립 배포 package가 아니라 이 workspace 안에서 재사용하는 module입니다.

## 현재 제공 기능

### DWG/DXF 2D viewer

- `.dwg`, `.dxf` URL과 로컬 파일 load
- 파일 선택, Drag & Drop, `?model=<url>` 진입 경로
- DWG는 acadrust WebAssembly parser, DXF는 `dxf-parser`와 adapter 사용
- Three.js orthographic renderer와 pan·zoom
- Zoom Fit, dark/light theme, layer별 표시·숨김
- entity click 선택과 type·layer·handle 표시
- TEXT/MTEXT glyph용 NanumGothic TTF load
- module API의 grid, zoom speed, view-change 구독, entity/block 통계,
  WebP snapshot, 2점 거리 측정, accent color
- page 종료 시 RAF, listener, WebGL resource와 canvas dispose

renderer에는 LINE, CIRCLE, ARC, ELLIPSE, POINT, POLYLINE/LWPOLYLINE,
SPLINE, TEXT/MTEXT/ATTRIB, INSERT, HATCH, DIMENSION, LEADER, XLINE/RAY 등
여러 entity 경로가 있습니다. 모든 DWG/DXF version과 entity 조합의 정확도를
보장한다는 의미는 아닙니다.

2D 입력 경계는 application layer에서 다음과 같이 제한합니다.

- URL은 HTTP(S)와 viewer 동일 origin만 허용
- `Content-Length`와 streaming 누적 크기를 모두 확인
- 로컬·URL 입력 최대 50 MiB
- URL fetch timeout 15초

### 다중 포맷 3D viewer

- `?model=<url>` server asset load와 로컬 Drag & Drop
- GLB, GLTF, OBJ, FBX, DAE, IFC, PLY load
- OBJ와 함께 드롭한 MTL 및 PNG/JPEG/BMP/GIF/WebP/TGA texture 연결
- 300 MiB 초과 OBJ의 2-pass streaming parser
- 큰 절대 좌표를 가진 OBJ의 float64 source 단계 재중심화
- Draco geometry와 KTX2/Basis texture runtime decode
- IFC single-thread WebAssembly parse와 geometry 변환
- PLY mesh·point cloud 처리 및 Float64 attribute의 Float32 정규화
- OrbitControls, Zoom Fit, 원근·직교 projection, outline 표시
- FPS overlay와 지속적인 저 FPS에서 pixel ratio를 낮추는 adaptive quality
- model URL과 이름이 같은 360° WebP preview를 먼저 표시한 뒤 canvas로 전환
- Vite `BASE_URL`을 따르는 decoder·preview 경로와 subpath 배포
- 교체 model의 geometry·material·texture와 Blob URL 정리

WebP preview는 미리 생성된 정적 파일입니다. Vite가 HTML shell을 제공한 뒤
브라우저에서 preview와 model을 load하므로 server-side 3D rendering 또는 SSR
구현은 없습니다.

## 실행 구조

```mermaid
flowchart TD
    A["2D File / same-origin URL"] --> B["cadInputPolicy"]
    B --> C["parseCad"]
    C --> D["acadrust WASM<br/>DWG"]
    C --> E["dxf-parser + adapter<br/>DXF"]
    D --> F["CadParseResult"]
    E --> F
    F --> G["Viewer2D / Three.js"]

    H["3D File / ?model URL"] --> I["ThreeDViewer"]
    I --> J["modelLoader"]
    J --> K["Three.js format loaders"]
    J --> L["web-ifc JS + WASM"]
    K --> M["THREE.Object3D"]
    L --> M
    M --> N["WebGLRenderer"]
```

2D application은 `packages/viewer2d` 내부 파일을 직접 import하지 않고
`@hmwebviewer/viewer2d` public interface를 사용합니다. 3D `modelLoader`는
확장자로 loader를 선택하고 결과를 `THREE.Object3D`로 정규화합니다.

`npm ci`의 root `postinstall`은 Three.js의 Draco·Basis 파일과 `web-ifc` WASM을
`apps/viewer-3d/public` 아래에 staging합니다. runtime에서는 설치된 Three.js와
동일한 decoder를 사용합니다. `web-ifc-mt.wasm`도 복사되지만 현재 code path는
single-thread `web-ifc.wasm`만 사용합니다.

## 지원 범위와 알려진 제한

### 2D

| 포맷 | URL | 로컬 파일 | 현재 검증과 제한 |
|---|---:|---:|---|
| DWG | 동일 origin 지원 | 지원 | `BasicSample.dwg` 1개 fixture 중심. acadrust WASM wrapper의 재현 build source가 없음 |
| DXF | 동일 origin 지원 | 지원 | `simple.dxf`와 public parser contract 검증. binary DXF 및 전체 entity fidelity 미검증 |

### 3D

| 포맷 | `?model` URL | 로컬 파일 | 알려진 제한 |
|---|---:|---:|---|
| GLB | 지원 | 지원 | Draco/KTX2 지원. 손실 압축 허용오차와 원본 대비 fidelity 기준 없음 |
| GLTF | 지원 | 제한적 | 로컬 `.bin`·texture sidecar를 함께 해석하는 file-set session 없음 |
| OBJ | 지원 | 지원 | URL 경로의 MTL 자동 load 없음. 로컬만 MTL·texture sidecar 지원 |
| OBJ > 300 MiB | 지원 | 지원 | streaming path는 smooth normal과 MTL `Kd` color만 사용하고 texture·hard edge fidelity를 포기 |
| FBX | 지원 | 지원 | 축·단위·animation·외부 texture 보존 계약 없음 |
| DAE | 지원 | 제한적 | 로컬 외부 texture sidecar 미지원 |
| IFC | 지원 | 지원 | geometry와 color만 Three.js object로 변환. property/semantic API와 원점 이동 기록 미보존 |
| PLY | 지원 | 지원 | mesh 또는 point cloud. double attribute는 GPU용 Float32로 변환되어 정밀도 손실 가능 |

여기서 “지원”은 sample을 파싱해 renderable object를 만들 수 있다는 뜻입니다.
CAD/BIM 원본과의 좌표·단위·원점·topology·재질·속성 일치를 의미하지 않습니다.

## 신뢰 경계와 운영 위험

2D 경로는 same-origin, 50 MiB, 15초 제한을 적용하지만 magic bytes, MIME,
압축 해제 후 entity 수와 geometry 복잡도 quota는 없습니다.

3D `?model`은 URL scheme·origin·크기·timeout을 제한하지 않습니다. browser CORS가
허용하면 외부 origin도 요청할 수 있고, GLTF/DAE/FBX/OBJ가 참조하는 URI가 추가
network request를 만들 수 있습니다. 로컬 3D 파일에도 최대 크기와 decode 후
vertex·texture·memory quota가 없습니다.

두 viewer 모두 parser와 상당한 geometry 처리를 browser main thread에서 수행합니다.
운영 배포에는 format별 Worker 격리, URL allowlist, CSP, MIME·signature 검사,
streaming byte limit, decode complexity quota, timeout과 cancellation이 필요합니다.

동시에 여러 load를 시작했을 때 이전 요청을 취소하거나 latest-wins를 보장하는
session 규약도 없습니다. 느린 이전 요청이 나중 요청 뒤에 완료되어 화면을
덮을 수 있습니다.

현재 E2E는 sample render, finite vertex, canvas lifecycle과 subpath decoder URL을
검사합니다. 공식 validator, golden geometry, 좌표·단위 왕복, topology,
material·IFC property contract와 장시간 memory soak는 release gate에 없습니다.

## 외부 의존성·라이선스 감사

> **배포 준비 판정: 외부 demo·고객 전달·public CDN·commercial SaaS `NO-GO`,
> 조직 내부 개발·검증 조건부 `GO`**
>
> dependency 자체는 대부분 상업 사용 가능한 license이지만, 프로젝트 소유 코드의
> license, MPL source 제공, Apache/MIT 고지와 sample provenance가 완결되지 않았습니다.

감사 범위는 `package-lock.json`의 `node_modules/*` entry, 실제 browser bundle,
`public` 정적 파일, bundled WASM·font, sample과 파생 preview, repository가
호출하거나 언급하는 system tool입니다.

lockfile에는 142개 `node_modules/*` entry가 있습니다. 이 중 3개는 이 저장소의
workspace link이고 제3자 package는 139개입니다. 제3자 entry의 license metadata
누락은 0개입니다. runtime entry는 5개, build/dev entry는 134개이며 그중 57개는
platform별 optional package입니다.

### Browser runtime과 직접 배포되는 구성요소

| 구성요소 | 버전·출처 | 역할·배포 위치 | License | 현재 compliance 상태 |
|---|---|---|---|---|
| Three.js | `0.185.1` | 두 viewer의 JS bundle, loader·controls | MIT | package license는 확인. 배포 artifact에 통합 MIT notice 없음 |
| dxf-parser | `1.1.2` | DXF parser JS bundle | MIT | package license는 확인. 통합 notice 없음 |
| loglevel | `1.9.2`, `dxf-parser` transitive | DXF runtime logging | MIT | lockfile·package license 확인 |
| opentype.js | `2.0.0` | TTF glyph 처리 JS bundle | MIT | package license는 확인. 통합 notice 없음 |
| acadrust | WASM 내부 `0.4.1` | `acadrust_dwg_bg.wasm`, DWG parse | MPL-2.0 | MPL 전문과 checksum은 있음. wrapper source·toolchain과 재현 build가 없음 |
| NanumGothic | Google Fonts 원본 checksum 일치 | `NanumGothic-Regular.ttf` | OFL-1.1 | 전문과 checksum은 있음. root license 파일이 app dist에는 자동 포함되지 않음 |
| web-ifc | `0.0.77` | dynamic JS bundle, `/web-ifc/*.wasm` | MPL-2.0 | package 전문은 확인. exact covered source 취득 안내가 배포물에 없음 |
| Draco decoder | Three.js r185 배포본 | `/draco/*.js`, `/draco/*.wasm` | Apache-2.0 | source와 byte-for-byte staging test 있음. Apache 전문·NOTICE가 app dist에 없음 |
| Basis Universal transcoder | Three.js r185 배포본 | `/basis/*.js`, `/basis/*.wasm` | Apache-2.0 | `basis/README.md`에 upstream link만 있음. Apache 전문·NOTICE가 app dist에 없음 |

저장소의 [`THIRD_PARTY_NOTICES.md`](./THIRD_PARTY_NOTICES.md)는 acadrust,
NanumGothic과 주요 runtime library를 기록하고, [`LICENSES/`](./LICENSES/)에는
MPL-2.0과 OFL-1.1 전문이 있습니다. 그러나 이 파일들은 두 Vite application의
`public` 아래에 있지 않아 현재 `npm run build` 결과에는 포함되지 않습니다.

### 전체 npm license 집계

| License | 제3자 package entry 수 | 주 사용 범위 | 상업 사용 | source 공개 영향 |
|---|---:|---|---:|---|
| MIT | 86 | runtime 4개와 build/dev | 가능 | 프로젝트 source 공개 의무 없음. copyright·license notice 보존 |
| Apache-2.0 | 31 | TypeScript, Playwright, Puppeteer와 platform package | 가능 | 프로젝트 source 공개 의무 없음. license·변경·NOTICE·patent 조건 적용 |
| MPL-2.0 | 13 | `web-ifc` runtime 1개, Lightning CSS 계열 dev 12개 | 가능 | 외부 executable 배포 시 covered source와 취득 안내 필요 |
| ISC | 6 | build/dev | 가능 | copyright·permission notice 보존 |
| BSD-3-Clause | 2 | build/dev | 가능 | notice·면책 보존, 이름을 홍보에 사용하지 않음 |
| 0BSD | 1 | optional build/dev | 가능 | source 공개와 attribution 의무 없음 |

위 집계에는 npm 밖의 acadrust WASM, NanumGothic, Draco, Basis와 sample asset
license가 포함되지 않습니다. `UNKNOWN` 3개처럼 보이는 lockfile entry는
`@hmwebviewer/*` first-party workspace link이며 제3자 license 누락이 아닙니다.

### Build·test·offline 도구

| 구성요소 | lockfile 기준 | 역할 | License·배포 판단 |
|---|---:|---|---|
| Vite | `8.1.5` | dev server와 production build | MIT. build output에는 runtime third-party notice를 별도로 넣어야 함 |
| TypeScript | `7.0.2` | typecheck | Apache-2.0. compiler를 고객에게 함께 전달하지 않으면 제품 source 공개 영향 없음 |
| Vitest | `4.1.10` | unit test | MIT, 제품 runtime 아님 |
| Playwright | `1.62.0` | browser E2E | Apache-2.0, 제품 runtime 아님 |
| Puppeteer Core | `25.4.0` resolved | 3D smoke·preview capture | Apache-2.0. Chrome binary를 포함하지 않음 |
| Lightning CSS | `1.33.0` 계열 12 entry | Vite build transitive | MPL-2.0. build host에서만 사용하며 browser runtime에는 포함되지 않음 |
| Node.js·npm | Node >=24, npm >=11 요구 | install, build, tool runtime | 함께 재배포하면 각 runtime과 bundled dependency license를 별도 감사 |
| Chrome | system executable | Playwright/Puppeteer 실행 | repository가 bundle하지 않음. CI image·설치형 배포에 포함하면 vendor 조건 별도 검토 |
| ffmpeg | optional, lockfile 밖 | PNG frame을 animated WebP로 결합 | binary를 bundle할 때 실제 build option의 LGPL/GPL/nonfree 조건 확인 |
| KTX-Software `toktx` | 도입 안내만 존재 | 선택적 KTX2 encoding | 현재 dependency가 아님. 도입 시 exact binary BOM과 license 재검토 |

`apps/viewer-3d/tools/preprocess.mjs`는 `@gltf-transform/core`,
`@gltf-transform/functions`, `@gltf-transform/extensions`, `draco3d`를 import하지만
현재 `package.json`과 lockfile에는 이 package들이 없습니다. 따라서 clean install의
정식 toolchain으로 재현되지 않습니다.

현재 script가 구현한 texture output은 WebP/JPEG/PNG이며 KTX2 encoding은 하지
않습니다. KTX2는 별도 glTF Transform CLI와 `toktx`가 필요합니다.
하위 `tools/README.md`의 “KTX2 default” 설명은 현재 code와 일치하지 않습니다.

### MPL·Apache·OFL 적용 범위

MPL-2.0은 file-level copyleft입니다. 별도 파일로 결합한 이 application 전체를
MPL로 공개할 필요는 없지만, 조직 밖으로 browser JS/WASM executable을 전달하면
수령자가 해당 MPL covered source와 수정분을 합리적인 방법으로 얻을 수 있게
알려야 합니다. browser로 전송되는 client code도 배포에 해당합니다.

- `web-ifc@0.0.77`: exact source archive 또는 고정 commit/tag URL과 수정 여부,
  build 가능한 covered source 취득 안내가 필요
- acadrust DWG WASM: crate source만으로는 현재 binary wrapper를 재현할 수 없으므로
  wrapper source·Cargo/wasm-bindgen 설정·toolchain을 복구하기 전 외부 배포 보류
- Lightning CSS: `node_modules`나 build container를 외부에 전달하지 않고 build
  host에서만 실행하면 application source 공개 범위를 만들지 않음

Apache-2.0의 Draco와 Basis는 source 공개 의무는 없지만 license 사본, 기존
attribution과 upstream NOTICE, 수정 시 변경 고지를 보존해야 합니다. OFL font는
software와 bundle할 수 있지만 copyright와 OFL 전문을 함께 제공해야 하며,
Reserved Font Name 조건을 지켜야 합니다.

참조:

- [Mozilla MPL 2.0 FAQ](https://www.mozilla.org/en-US/MPL/2.0/FAQ/)
- [acadrust upstream](https://github.com/hakanaktt/acadrust)
- [web-ifc upstream](https://github.com/ThatOpen/engine_web-ifc)
- [Three.js r185 MIT license](https://github.com/mrdoob/three.js/blob/r185/LICENSE)
- [Google Draco Apache-2.0 license](https://github.com/google/draco/blob/main/LICENSE)
- [Basis Universal](https://github.com/BinomialLLC/basis_universal)
- [NanumGothic OFL](https://github.com/google/fonts/blob/main/ofl/nanumgothic/OFL.txt)

### Sample asset과 파생 preview

Sample과 preview는 software dependency license와 별개의 저작물입니다.
optimized model과 회전 preview도 원본 asset의 license·attribution·변경 표시를
계승해야 합니다.

| 자산 | 확인된 출처·license | 현재 판단 |
|---|---|---|
| `BasicSample.dwg` | 2D standalone initial commit에서 이관, 원출처 불명 | 내부 회귀 test 전용. 외부 demo 배포 보류 |
| `simple.dxf` | 2D standalone initial commit의 최소 fixture | 권리자·license 명시가 없어 외부 재배포 승인 필요 |
| `Box.glb` | Khronos sample, Cesium 제공, CC BY 4.0 | 상업 사용 가능하나 Cesium attribution, license link와 변경 여부 고지가 현재 배포물에 없음 |
| `Duck.glb` | Copyright 2006 Sony Computer Entertainment Inc., SCEA Shared Source License 1.0 | 비표준 license. 내부 법무 승인 전 외부 배포 보류 |
| `Duck.optimized.glb`, `Duck.webp` | Duck의 Draco/WebP·preview 파생물 | 원본 SCEA 승인과 derivative 변경 표시에 종속 |
| `Cube.obj`, `Cube.dae`, `Cube.ifc`, `DoublePrecision.ply` | 파일·commit에 hand-authored/project fixture 정황 | 프로젝트 권리자와 first-party license가 선언되지 않아 외부 배포 보류 |
| `Cube.fbx`, `sample.mtl` | history에는 Three.js `morph_test`와 Blender 정황만 있고 exact 원본 URL·asset license 없음 | provenance 복구 또는 제거 전 외부 배포 보류 |
| `Cube.*.webp` | 각 Cube model에서 생성한 24-frame preview | 원본 model의 권리·license와 변경 표시에 종속 |

Box와 Duck의 upstream license:

- [Khronos Box — CC BY 4.0](https://github.com/KhronosGroup/glTF-Sample-Models/blob/main/2.0/Box/README.md)
- [Khronos Duck — SCEA Shared Source License 1.0](https://github.com/KhronosGroup/glTF-Sample-Models/blob/main/2.0/Duck/README.md)

fixture checksum과 source history는 [`docs/PROVENANCE.md`](./docs/PROVENANCE.md),
acadrust·font checksum은 [`THIRD_PARTY_NOTICES.md`](./THIRD_PARTY_NOTICES.md)를
기준으로 관리합니다. 현재 provenance 문서는 2D fixture 중심이며 3D asset과
preview derivative chain은 아직 통합되지 않았습니다.

### 프로젝트 license와 외부 release gate

루트에는 프로젝트 소유 코드에 적용되는 `LICENSE`와 copyright holder 선언이
없습니다. `package.json`의 `"private": true`는 npm publish 방지 설정일 뿐
외부 이용·수정·재배포 권한을 부여하지 않습니다. 하위 과거 README의
“Viewer2D 포트·샘플 글루 MIT” 문구도 현재 repository의 license grant로 볼 수
없습니다.

다음 조건을 완료하기 전에는 외부 demo, 고객 전달, 설치형 package, public CDN과
commercial SaaS 배포를 승인하지 않습니다.

- 프로젝트 소유 코드의 권리자와 proprietary/open-source license 결정
- 2D·3D build artifact에 runtime `THIRD_PARTY_NOTICES`와 필요한 license 전문 포함
- acadrust wrapper source·toolchain 복구와 exact WASM 재현 build
- acadrust 및 `web-ifc@0.0.77` covered source의 고정 archive/URL과 취득 안내 제공
- Draco·Basis Apache license와 upstream NOTICE 보존
- Box attribution과 sample별 원본 URL·권리자·license·checksum·derivative chain 기록
- Duck의 내부 법무 승인 또는 승인된 CC0/CC BY asset으로 교체
- `BasicSample.dwg`, `Cube.fbx`, `sample.mtl` 등 출처 미완료 fixture의 승인 또는 제거
- 미사용 `web-ifc-mt.wasm`과 중복 decoder artifact의 배포 필요성 결정
- runtime/build/sample을 구분한 SBOM과 CI의 unknown-license/provenance gate

## 설치와 실행

요구 환경은 Node.js 24 이상, npm 11 이상과 WebGL을 지원하는 browser입니다.

```bash
npm ci
```

`npm ci`는 workspace dependency를 설치한 뒤 3D decoder와 WASM을 staging합니다.

```bash
npm run dev:2d
# http://127.0.0.1:5173

npm run dev:3d
# http://127.0.0.1:3333
```

URL load 예시:

```text
http://127.0.0.1:5173/?model=/samples/simple.dxf
http://127.0.0.1:3333/?model=/samples/Box.glb
```

Production build와 preview:

```bash
npm run build
npm --workspace @hmwebviewer/viewer-2d-sample run preview
npm --workspace @hmwebviewer/viewer-3d run preview
```

## 검증

```bash
npm run typecheck
npm run test:unit
npm run build
npm run test:e2e
```

전체 순차 검증:

```bash
npm run verify
```

현재 test가 확인하는 범위:

- 2D public package interface의 DXF parse
- 2D same-origin·50 MiB 입력 정책
- canonical module map 문서 drift
- decoder WASM의 installed dependency 대비 checksum과 실행 권한
- Vite subpath의 public asset URL
- 2D DWG/DXF sample과 local file load
- 3D GLB, Draco GLB, OBJ, FBX, DAE, IFC, PLY sample render
- 2D/3D canvas dispose와 반복 page transition
- production subpath의 Draco·IFC decoder request

이 검증은 sample이 화면에 나타나고 runtime error가 없다는 smoke/contract 수준입니다.
engineering 정확도와 외부 배포 compliance를 승인하는 test는 아닙니다.

## 문서

- [Third-party notices](./THIRD_PARTY_NOTICES.md)
- [Source와 fixture provenance](./docs/PROVENANCE.md)
- [DWG/DXF module map](./docs/modules-dwg-dxf.html)
- [2D sample 안내](./apps/viewer-2d-sample/README.md)
- [3D architecture](./apps/viewer-3d/docs/architecture.html)
- [3D 구현 계획](./apps/viewer-3d/PLAN.md)
- [3D 검증 기록](./apps/viewer-3d/PROGRESS.md)
- [3D asset 도구](./apps/viewer-3d/tools/README.md)
- [초기 3D 설계서](./apps/viewer-3d/3d_viewer_architecture_spec.pdf)

하위 2D README에는 통합 전 standalone layout이, 3D tools README에는 과거 KTX2
계획이 남아 있습니다. 현재 workspace의 canonical 개요와 배포 판단은 이 문서를
기준으로 하며, 하위 문서는 후속 정합성 정리가 필요합니다.

## 현재 판정

2D와 3D sample의 주요 load path, lifecycle, decoder staging과 subpath 배포를
검증하는 자동화가 있습니다. 내부 기능 검증용 workspace로는 사용할 수 있습니다.

운영 release에는 format별 정확도 contract, 3D 입력 제한·cancellation·Worker 격리,
프로젝트 license, MPL source 제공, third-party 고지와 sample provenance blocker가
남아 있습니다. 특히 “상업 사용 가능한 dependency”와 “현재 artifact를 조건 없이
상업 배포할 수 있음”은 같은 뜻이 아닙니다.
