npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

tellux

v0.1.8

Published

A Three.js GIS viewer for Cesium Ion 3D Tiles, atmosphere, clouds, and post-processing effects.

Readme

Tellux

English | 中文

Tellux 是一个基于 Three.js 的三维地理空间引擎,用 Three.js 构建数字地球、地形、影像与 3D Tiles 场景。

在线预览:https://tellux.cyanfish.site

安装

npm install tellux three 3d-tiles-renderer postprocessing @takram/three-atmosphere @takram/three-clouds @takram/three-geospatial @takram/three-geospatial-effects @mapbox/vector-tile pbf

使用

import tellux from 'tellux'

const viewer = new tellux.Viewer('viewer', {
  terrain: {
    url: 'https://example.com/terrain/'
  },
  layers: [
    {
      source: {
        type: 'xyz',
        url: 'https://example.com/imagery/{z}/{y}/{x}.png'
      }
    }
  ],
  camera: {
    latitude: 35.6812,
    longitude: 139.8,
    height: 500
  }
})

terrain.url 支持 Cesium quantized-mesh 地形根目录,也可以直接传入 layer.json 地址。也可以在初始化或运行时选择 Cesium Ion 地形资源:

const viewer = new tellux.Viewer('viewer', {
  terrain: {
    type: 'cesium-ion',
    assetId: 1,
    apiToken: import.meta.env.VITE_CESIUM_ION_TOKEN
  }
})

运行时可以热切换地形:

viewer.setTerrain({
  url: 'https://example.com/another-terrain/layer.json'
})

viewer.setTerrain({
  type: 'cesium-ion',
  assetId: 1,
  apiToken: import.meta.env.VITE_CESIUM_ION_TOKEN
})

viewer.setTerrain(null)

也可以使用 Cesium Ion 影像数据源:

new tellux.Viewer(container, {
  layers: [
    {
      source: {
        type: 'cesium-ion',
        assetId: 123456,
        apiToken: import.meta.env.VITE_CESIUM_ION_TOKEN
      }
    }
  ]
})

layers 中的 type: 'cesium-ion' 用于 Cesium Ion 影像资源。Google Photorealistic 3D Tiles 这类 3D Tiles 资源应通过 viewer.load3DTileset(...) 加载:

const photorealisticLayer = viewer.load3DTileset({
  type: 'cesium-ion',
  assetId: 2275207,
  apiToken: import.meta.env.VITE_CESIUM_ION_TOKEN
})

// 作为全球三维底图使用时,可隐藏默认基础地球表面,避免与摄影测量网格重叠。
viewer.tileset.group.visible = false

影像图层统一通过 viewer.layers 管理,图层顺序按数组从下到上绘制:

const imageryLayer = viewer.layers.add({
  name: 'World Imagery',
  source: {
    type: 'xyz',
    url: 'https://example.com/imagery/{z}/{y}/{x}.png'
  }
})

imageryLayer.setVisible(false)
imageryLayer.setStyle({ opacity: 0.65 })
imageryLayer.moveTo(0)
imageryLayer.remove()

MVT 矢量瓦片可以作为影像图层接入:

viewer.layers.add({
  name: 'Water and roads',
  source: {
    type: 'mvt',
    url: 'https://example.com/tiles/{z}/{x}/{y}.pbf'
  },
  style: {
    getStyle(layerName) {
      if (layerName.includes('water')) return { fill: '#38bdf8', order: 10 }
      if (layerName.includes('transportation')) return { stroke: '#facc15', strokeWidth: 1.4, order: 30 }
      return null
    }
  }
})

MVT 图层依赖 3d-tiles-renderer 的 MVT overlay 能力,运行时需要安装 @mapbox/vector-tilepbf

GeoJSON 可以作为贴地矢量 overlay 接入:

viewer.layers.add({
  name: 'Area boundary',
  source: {
    type: 'geojson',
    url: '/data/boundary.geojson'
  },
  style: {
    opacity: 0.85,
    fill: 'rgba(20, 184, 166, 0.28)',
    stroke: '#14b8a6',
    strokeWidth: 2,
    getStyle(feature, properties) {
      if (properties?.kind === 'restricted') return { fill: 'rgba(244, 63, 94, 0.32)', stroke: '#f43f5e' }
      return {}
    }
  }
})

也可以直接传入 GeoJSON 对象:

viewer.layers.add({
  source: {
    type: 'geojson',
    geojson
  }
})

WMS 服务可以作为影像图层接入:

viewer.layers.add({
  name: 'Province boundary',
  source: {
    type: 'wms',
    url: 'https://example.com/geoserver/wms',
    layer: 'workspace:layer',
    crs: 'EPSG:4326',
    format: 'image/png',
    transparent: true
  },
  style: {
    opacity: 0.7
  }
})

例如 GeoServer WMS 1.1.0 服务:

viewer.layers.add({
  name: '中国省界 WMS',
  source: {
    type: 'wms',
    url: 'https://example.com/geoserver/wms',
    layer: 'workspace:province_boundary',
    version: '1.1.0',
    crs: 'EPSG:4326',
    styles: '',
    format: 'image/png',
    transparent: true,
    contentBoundingBox: [73.501142, 3.397162, 135.088511, 53.560901]
  },
  style: {
    opacity: 0.72
  }
})

WMS 图层应请求图片格式,例如 image/pngformat=application/openlayers 通常是 GeoServer 的预览页格式,不适合作为影像贴图。

glTF / GLB 模型

可以通过 viewer.addModel(...) 加载普通 glTF 或 GLB 模型,并直接按经纬高放置到 Tellux 场景中。coordinates 支持 [经度, 纬度, 高度] 数组,也支持 { longitude, latitude, height } 对象;高度单位为米。

const model = viewer.addModel({
  type: 'gltf',
  id: 'littlest-tokyo',
  url: 'https://threejs.org/examples/models/gltf/LittlestTokyo.glb',
  coordinates: [114, 30, 0],
  scale: 0.45,
  heading: 180,
  alignToGround: true,
  animate: true,
  animationChannel: 0
})

await model.ready

viewer.flyToTarget(model.root, {
  heading: -35,
  pitch: -28,
  distance: 2600
})

model.playAnimation(0)
model.pauseAnimation()
model.stopAnimation()
model.remove()

type 固定为 'gltf',URL 可以指向 .gltf.glb。当 animate: true 时,模型加载完成后默认播放第 0 个动画通道;可以用 animationChannel 指定其他通道。

如果你需要自己放置 Three.js 对象,也可以复用 Tellux 的坐标转换 API:

const position = viewer.cartographicToVector3([114, 30, 100])

const matrix = viewer.cartographicToMatrix4([114, 30, 0], {
  heading: 90,
  pitch: 0,
  roll: 0
})

object.matrixAutoUpdate = false
object.matrix.copy(matrix)
viewer.scene.threeScene.add(object)

cartographicToVector3(...) 返回底层 Three.js 世界坐标;cartographicToMatrix4(...) 返回适合 Three.js 对象的当地坐标矩阵,+Y 指向当地上方,+Z 指向对象前方。

光照模式

Tellux 提供两种大气光照模式,默认使用 light-source

const viewer = new tellux.Viewer(container, {
  scene: {
    atmosphere: {
      lighting: {
        mode: 'light-source'
      }
    }
  }
})

light-source 会在 Three.js 场景中使用 Takram 的太阳方向光和天空光探针。它适合大多数 3D GIS 场景:3D Tiles、地形、overlay 影像、自定义 Three.js 模型和 PBR 材质都可以沿用 Three.js 的常规受光方式。可以通过 scene.atmosphere.lighting 调整光源强度:

viewer.scene.atmosphere.lighting.mode = 'light-source'
viewer.scene.atmosphere.lighting.sunLight = true
viewer.scene.atmosphere.lighting.skyLight = true
viewer.scene.atmosphere.lighting.sunLightIntensity = 1.2
viewer.scene.atmosphere.lighting.skyLightIntensity = 0.8

Tellux 还会自动应用夜间光照:当当前视角所在地的太阳低于地平线时,会根据月亮方向和月相叠加冷色低强度月光,并加少量冷色环境补光,避免夜晚完全变黑。夜间效果会同时作用于天空、月盘/月晕、星空、体积云和地表;light-source 模式下地表会使用 Three.js 月光方向光和环境光,post-process 模式下地表会在 AerialPerspectiveEffect 中基于表面 albedo 补充月光和环境补光。可以通过 scene.atmosphere.night 调整:

const viewer = new tellux.Viewer(container, {
  scene: {
    atmosphere: {
      lighting: {
        mode: 'light-source'
      },
      night: {
        enabled: true,
        color: 0x9bbcff,
        moonLightIntensity: 0.18,
        ambientIntensity: 0.08,
        useMoonPhase: true,
        transitionRange: [-0.08, 0.05]
      }
    }
  }
})

viewer.scene.atmosphere.night.moonLightIntensity = 0.22
viewer.scene.atmosphere.night.ambientIntensity = 0.1

post-process 是 Takram 的原生空气透视后处理光照路径。它会把渲染结果当作表面反照率(albedo),再在 AerialPerspectiveEffect 中应用太阳光、天空光、大气透射和空气散射。这个模式适合想获得更统一的大气后处理效果的高级场景,但输入材质应是不受 Three.js 光源影响的 albedo 材质,例如 MeshBasicMaterial 或 glTF 的 KHR_materials_unlit

加载 3D Tiles 时,如果数据本身不是 unlit 材质,但希望它参与 post-process 光照,可以显式使用 materialMode: 'unlit'

viewer.scene.atmosphere.lighting.mode = 'post-process'
viewer.scene.atmosphere.lighting.sunLight = true
viewer.scene.atmosphere.lighting.skyLight = true
viewer.scene.atmosphere.lighting.albedoScale = 0.6

const layer = viewer.load3DTileset({
  type: 'url',
  url: 'https://example.com/tileset.json',
  materialMode: 'unlit'
})

如果在 post-process 模式下仍使用 PBR 或其他受光材质,场景中的 Three.js 光源会被关闭,瓦片在进入后处理前可能已经变暗甚至变黑。此时要么改用默认的 light-source,要么为需要后处理光照的 3D Tiles 使用 materialMode: 'unlit'

请确保容器具有非零尺寸:

#viewer {
  width: 100vw;
  height: 100vh;
}

Renderer 类型

默认情况下,Viewer 使用 Three.js WebGLRenderer,完整支持大气、体积云、星空和后处理效果。也可以通过 renderer.type 切换到实验性的 WebGPU renderer:

const viewer = await tellux.Viewer.create(container, {
  renderer: {
    type: 'webgpu'
  },
  scene: {
    atmosphere: {
      show: true,
      lighting: {
        mode: 'light-source'
      }
    },
    clouds: {
      show: false
    }
  }
})

WebGPU renderer 需要异步初始化。推荐使用 Viewer.create(...),它会在返回前等待 renderer 初始化完成;如果使用 new Viewer(...) 并接入外部手动渲染循环,建议先 await viewer.ready 再调用 viewer.render()

const viewer = new tellux.Viewer(container, {
  renderer: { type: 'webgpu' },
  useDefaultRenderLoop: false
})

await viewer.ready
viewer.render()

WebGPU 支持目前是实验能力,API 和效果范围后续可能调整。基础地球、3D Tiles、地形、影像、模型、拾取和大气天空 / 空气透视会走 WebGPU 管线;体积云、星空和 WebGL 专属后处理效果(SMAA、镜头光晕、抖动等)在 WebGPU 模式下会降级为不渲染。WebGPU 大气首版使用 Takram 的 node-based 管线,light-source 光照模式支持更完整,部分 WebGL 专属的散射调试参数暂不映射;地球瓦片 LOD 切换目前为直接切换,暂不支持 WebGL 版的丝滑淡入淡出。

WebGPU 模式目前不会在不支持的环境上自动回退 WebGL:在不支持 WebGPU 的浏览器中 renderer.init() 会失败,Viewer.create(...) 会抛错。需要应用层自行检测后决定 renderer.type,或设置 renderer.forceWebGL: trueWebGPURenderer 走 Three.js 的 WebGL2 fallback backend(仍走 WebGPU 代码路径,但底层用 WebGL2)。

Draco 解码器

Tellux 使用 DRACOLoader 加载 glTF tiles 和 glTF / GLB 模型。默认情况下,解码器会从 /draco/gltf/ 加载。

你可以将 three/examples/jsm/libs/draco/gltf/ 中的解码器文件复制到应用的 public 目录,或传入自定义路径:

new Viewer(container, {
  dracoDecoderPath: '/assets/draco/gltf/'
})

静态资源目录

Tellux 随 npm 包内置云、STBN 和星空资源。使用 Vite、Webpack、Rollup 等现代打包器时,直接 new tellux.Viewer(...) 即可,打包器会把这些资源复制到应用构建产物中。

如果你的项目需要从 CDN、内网静态目录或非打包环境加载资源,可以把 local_weather.pngturbulence.pngshape.binshape_detail.binstbn.binstars.bin 放到自己的静态目录,并在创建 Viewer 前设置 tellux.baseUrl 覆盖默认资源地址:

import tellux from 'tellux'

tellux.baseUrl = '/assets/tellux/'

new tellux.Viewer(container)

也可以按需读取 Tellux 默认资源 URL:

import { telluxAssetUrls } from 'tellux/assets'

console.log(telluxAssetUrls.stbn)

API

viewer.camera.setView({
  latitude: 31.2304,
  longitude: 121.4737,
  height: 1000,
  heading: -90,
  pitch: -15
})

viewer.flyToTarget({
  latitude: 31.2304,
  longitude: 121.4737,
  height: 0
}, {
  heading: -90,
  pitch: -30,
  distance: 1200
})

const layer = viewer.load3DTileset({
  type: 'url',
  url: 'https://example.com/tileset.json'
})

viewer.flyToTarget(layer.tileset, {
  heading: 0,
  pitch: -30
})

const model = viewer.addModel({
  type: 'gltf',
  url: '/models/site.glb',
  coordinates: [121.4737, 31.2304, 0],
  animate: true
})

await model.ready
viewer.flyToTarget(model.root)

viewer.scene.clouds.show = false
viewer.scene.atmosphere.show = true
viewer.scene.postProcess.smaa.enabled = true
viewer.toneMappingExposure = 8
viewer.resolutionScale = 1.5

viewer.destroy()

项目架构

Tellux 采用 Viewer 门面加多个内部 manager 协作的结构。用户侧只需要面对 ViewerCameraSceneClock 和资源配置对象;复杂的瓦片、地形、影像、大气、云和后处理逻辑由内部模块分工管理。

flowchart TB
  User["用户代码<br/>new tellux.Viewer"] --> Entry["src/index.ts<br/>tellux 入口"]
  Entry --> Viewer["Viewer<br/>主门面 / 生命周期 / 事件 / render loop"]

  Viewer --> Camera["Camera<br/>Cesium 风格相机 API"]
  Viewer --> Scene["Scene<br/>云 / 大气 / 后处理开关"]
  Viewer --> Clock["Clock<br/>太阳时间"]
  Viewer --> Controls["GlobeControls<br/>地球交互控制"]
  Viewer --> Renderer["Three.WebGLRenderer<br/>canvas / render"]

  Viewer --> TilesetManager["TilesetManager<br/>surface / terrain / imagery / overlays"]
  Viewer --> Models["ModelLayer<br/>glTF / GLB / AnimationMixer"]
  Viewer --> AtmosphereManager["AtmosphereManager<br/>大气 / 云 / 太阳光 / 贴图"]
  Viewer --> PostProcessingManager["PostProcessingManager<br/>NormalPass / 大气云组合 / SMAA 等"]

  TilesetManager --> Sources["layers[].source<br/>xyz / cesium-ion / mvt / wms / geojson"]
  TilesetManager --> TilesRenderer["3d-tiles-renderer<br/>TilesRenderer / plugins"]
  TilesetManager --> TilePlugins["本地插件<br/>TerrainFetchPlugin<br/>图层级 TileCreasedNormalsPlugin"]

  AtmosphereManager --> Takram["@takram<br/>atmosphere / clouds / geospatial"]
  PostProcessingManager --> Postprocessing["postprocessing<br/>EffectPass / NormalPass"]

  Scene --> PostProcessingManager
  Clock --> AtmosphereManager
  Camera --> TilesRenderer
  Controls --> Camera
  Renderer --> Scene

主要模块职责:

  • Viewer:主入口和门面类,负责创建 renderer、scene、camera、clock、controls,提供 glTF / GLB 模型加载入口,并协调各 manager 的生命周期。
  • Camera:封装 Cesium 风格的 setViewflyTo 和当前视角读取。
  • Scene:保存云、大气、后处理等场景状态,并在状态变化时触发后处理重组。
  • TilesetManager:创建和热切换基础地球表面、quantized-mesh 地形、影像底图和影像叠加层。
  • ModelLayer:由 viewer.addModel(...) 创建,管理 glTF / GLB 模型、动画通道、显隐和资源释放。
  • AtmosphereManager:创建大气、云、太阳光、天空光,并加载云纹理和 STBN 资源。
  • PostProcessingManager:根据 Scene 状态组合 normal pass、大气云 pass、SMAA、dithering 和 lens flare。

渲染流程

new tellux.Viewer(container, options) 到画面渲染出来,大致会经历以下流程:

sequenceDiagram
  participant U as 用户
  participant V as Viewer
  participant R as WebGLRenderer
  participant S as Scene
  participant A as AtmosphereManager
  participant T as TilesetManager
  participant P as PostProcessingManager
  participant C as Camera/GlobeControls

  U->>V: new Viewer(container, options)
  V->>R: 创建 WebGLRenderer 并挂载 canvas
  V->>S: 创建 Scene 状态对象
  V->>A: 创建大气 / 云 / 光源
  A->>S: 添加 sunLight / skyLight
  V->>T: 创建 surface / terrain tileset
  T->>S: 将 tileset.group 加入 threeScene
  T->>T: 注册 3d-tiles-renderer 插件
  V->>C: 设置初始视角并创建 GlobeControls
  V->>P: 创建后处理 pass
  P->>R: renderer.setEffects(...)
  V->>A: 异步加载大气和云贴图
  V->>V: 注册 resize / click / mousemove
  V->>R: setAnimationLoop(render)

  loop 每帧
    R->>V: render(time)
    V->>V: resize()
    V->>C: controls.update()
    V->>T: tilesets.update()
    T->>T: 根据相机加载和更新可见瓦片
    V->>V: updateModelLayers(deltaTime)
    V->>R: renderer.render(scene, camera)
  end

运行时,Viewer 只负责串联流程:先同步容器尺寸,再更新地球控制器,然后让 TilesetManager 推进瓦片加载与 LOD 更新,接着更新已加载模型的动画,最后交给 Three.js renderer 渲染当前场景。影像、地形和叠加层切换时,Viewer 会转发给 TilesetManager;云、大气和后处理开关变化时,Scene 会触发 PostProcessingManager 重新组合渲染效果。

贡献

提交规范

本项目使用 Conventional Commits 规范,通过 commitlint + husky 在提交时强制校验。提交信息格式:

<type>(<scope>): <subject>

type(必填):

| type | 说明 | 写入 CHANGELOG | |---|---|---| | feat | 新功能 | ✓ | | fix | bug 修复 | ✓ | | refactor | 重构(非新增功能、非修复) | ✓ | | perf | 性能优化 | ✓ | | revert | 回滚提交 | ✓ | | docs | 文档变更 | ✗ | | style | 代码格式(不影响功能) | ✗ | | test | 测试相关 | ✗ | | chore | 构建 / 工具 / 依赖等杂项 | ✗ | | build | 构建系统或外部依赖变更 | ✗ | | ci | CI 配置变更 | ✗ |

scope 可选,表示影响范围,如 feat(viewer): ...subject 为简短描述,中英文均可。

示例:

feat: 实现 SymbolEntity 基本渲染
fix(viewer): 修复 flyToTarget 事件监听未卸载的 bug
refactor: 拆分 TilesetManager 职责
docs: 更新光照模式文档
chore: 升级 three 依赖

破坏性变更在 type 后加 !,或在正文写 BREAKING CHANGE: ...

feat!: 重构相机系统,配置字段变更

提交时 husky 会自动校验,不符合规范的提交会被拒绝。CHANGELOG 在发版时由脚本根据 commit 自动生成,详见 CHANGELOG.md