返回 Skill 列表
extension
分类: 开发与工程无需 API Key

glb-compressor-server

通过REST API和SSE流压缩GLB/glTF 3D模型的HTTP服务器。在构建Web集成、设置压缩微服务或向前端添加实时压缩进度时使用。

person作者: jakexiaohubgithub

glb-compressor Server

HTTP compression server built on Bun.serve(). Provides synchronous and streaming (SSE) compression endpoints with full CORS support.

Starting the Server

# Production (from installed package)
glb-server

# Development (hot reload)
bun run dev

# Custom port
PORT=3000 bun run start

Default port: 8080 (override via PORT env var).

Endpoints

GET /healthz

Health check. Returns 200 ok.

POST /compress

Synchronous compression. Returns compressed GLB binary.

Accepts: multipart/form-data (field: file) or raw application/octet-stream.

Query params / form fields:

  • preset - Compression preset: default, balanced, aggressive, max
  • simplify - Mesh simplification ratio (0, 1), e.g. 0.5

Form fields override query params when both are provided.

Response headers:

| Header | Description | | ---------------------- | ---------------------------------- | | X-Request-ID | UUID tracking this request | | X-Original-Size | Input file size in bytes | | X-Compressed-Size | Output file size in bytes | | X-Compression-Method | gltfpack or meshopt | | X-Compression-Ratio | Percentage reduction (e.g. 84.1) | | Content-Disposition | Suggested download filename |

Example:

# Multipart upload
curl -X POST -F "file=@model.glb" \
  "http://localhost:8080/compress?preset=aggressive" \
  -o compressed.glb

# Raw binary upload
curl -X POST --data-binary @model.glb \
  -H "Content-Type: application/octet-stream" \
  "http://localhost:8080/compress?preset=balanced" \
  -o compressed.glb

POST /compress-stream

SSE streaming compression with real-time progress. Multipart only.

Content-Type: text/event-stream

SSE events:

| Event | Data shape | | -------- | ------------------------------------------------------------------------------------- | | log | { message: string } | | result | { requestId, filename, data (base64), originalSize, compressedSize, ratio, method } | | error | { message, requestId, code } |

Stream closes after result or error event.

Example (JavaScript):

const form = new FormData();
form.append('file', glbFile);

const response = await fetch(
	'http://localhost:8080/compress-stream?preset=aggressive',
	{ method: 'POST', body: form },
);

const reader = response.body.getReader();
const decoder = new TextDecoder();

// Parse SSE events from the stream
while (true) {
	const { done, value } = await reader.read();
	if (done) break;
	const text = decoder.decode(value);
	// Parse "event: <type>\ndata: <json>\n\n" format
	console.log(text);
}

Error Responses

All errors return structured JSON:

{
	"error": { "code": "ERROR_CODE", "message": "Human-readable message" },
	"requestId": "uuid"
}

Error codes:

| Code | HTTP | Description | | ---------------------- | ---- | ----------------------------------- | | NO_FILE_PROVIDED | 400 | No file in form data | | INVALID_GLB | 400 | Failed GLB magic byte validation | | FILE_TOO_LARGE | 413 | Exceeds 100 MB limit | | INVALID_CONTENT_TYPE | 415 | Non-multipart on streaming endpoint | | COMPRESSION_FAILED | 500 | Pipeline error during compression |

CORS

Full CORS enabled on all endpoints. Exposed headers: X-Request-ID, X-Original-Size, X-Compressed-Size, X-Compression-Method, X-Compression-Ratio.

Limits

  • Max file size: 100 MB
  • gltfpack timeout: 60 seconds per file

Architecture Notes

  • import.meta.main guard: safe to import server/main.ts as a library without starting the server.
  • Request ID (X-Request-ID) is generated per request and logged server-side.
  • The /compress-stream endpoint sends the compressed GLB as base64 in the result SSE event (~33% larger than binary). For large files near the 100 MB limit, prefer /compress.