Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Normalize line endings.
#
# Prettier writes LF, so LF is canonical in the repository and in the working
# tree. Without this, running `pnpm format` on Windows turns every touched file
# into a whole-file diff that is pure line-ending noise.
* text=auto eol=lf

# Binary assets are never converted.
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.webp binary
*.ico binary
*.ttf binary
*.woff binary
*.woff2 binary
*.glb binary
*.fbx binary
*.zip binary
43 changes: 43 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: CI

on:
pull_request:
branches:
- main
- develop
push:
branches:
- main
- develop

jobs:
quality:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 24

- name: Install Pnpm
run: npm install -g pnpm

- name: Install Dependencies
run: pnpm i

- name: Type Check
run: pnpm typecheck

- name: Lint
run: pnpm lint:ci

- name: Test
run: pnpm test

- name: Build
run: pnpm build
39 changes: 31 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ useEffect(() => {
- Use `onCreated` callback on `<Scene>` to initialize effects (not `useScene()` hook)
- Set camera position in `handleCreated`: `camera.position.set(0, 0, 4)`
- Use `camera.lookAt(0, 0, 0)` to ensure proper orientation
- **Default Scene background color: `bgColor="#1a1a2e"`** — use this for all demo Scenes by default.
- **Default Scene background color: `bgColor="rgb(40, 42, 54)"`** — use this for all demo Scenes by default.
- Set demo container style: `style={{ marginTop: '10px', marginBottom: '16px', width: '100%', height: '300px' }}`
- Add cleanup in `useEffect` return function and set refs to `null`
- Use `// Cleanup on unmount` comment before useEffect
Expand All @@ -158,8 +158,6 @@ export default function App() {

const handleCreated = (scene: THREE.Scene, components: SceneComponents) => {
const { camera } = components
if (!camera) return

camera.position.set(0, 0, 4)
camera.lookAt(0, 0, 0)

Expand All @@ -175,7 +173,7 @@ export default function App() {
}, [])

return (
<Scene bgColor="#1a1a2e" style={{ marginTop: '10px', marginBottom: '16px', width: '100%', height: '300px' }} onCreated={handleCreated} />
<Scene bgColor="rgb(40, 42, 54)" style={{ marginTop: '10px', marginBottom: '16px', width: '100%', height: '300px' }} onCreated={handleCreated} />
)
}
```
Expand Down Expand Up @@ -215,7 +213,7 @@ When creating particle effects like Rain or Snow, follow this workflow:
**5. Create Demo Component**
- Set front-facing camera: `camera.position.set(0, 0, 4)`
- Use `camera.lookAt(0, 0, 0)` to ensure proper orientation
- Default Scene background color: `bgColor="#1a1a2e"` — use it for all demos by default
- Default Scene background color: `bgColor="rgb(40, 42, 54)"` — use it for all demos by default
- Adjust camera distance for visibility
- Set demo container style: `style={{ marginTop: '10px', marginBottom: '16px', width: '100%', height: '300px' }}`

Expand Down Expand Up @@ -244,6 +242,33 @@ pnpm format # Format with Prettier
pnpm build # Build for production
```

### Releasing

Releases are cut from `main`, never directly from `develop`. Follow this order
exactly - the tag is the last step because pushing it triggers the
`Create Release` workflow (GitHub Release, NPM publish, docs deploy):

1. Update `CHANGELOG.md`: rename the `## [Unreleased]` heading to
`## [x.y.z] - YYYY-MM-DD` (keep the accumulated sections; do not use the
placeholder the release script injects).
2. Bump the version: update `package.json` with the target version, or run
`node scripts/release.js x.y.z` - but if the script creates a tag, delete it
(`git tag -d x.y.z`); the script commits `package.json`/`CHANGELOG.md`, which
is fine.
3. Commit the release preparation on `develop`
(`chore: release version x.y.z`).
4. Push `develop` and open a pull request from `develop` to `main`. The `gh`
CLI is not installed in this environment, so never attempt `gh pr create`;
open the pull request in the browser instead:
`https://github.com/sunquakes/react-three-lite/compare/main...develop?expand=1`.
5. After the PR is reviewed and merged into `main`, create the tag on the
`main` merge commit (`git checkout main && git pull && git tag x.y.z`) and
push only then (`git push origin x.y.z`).
6. Verify the `Create Release` GitHub Actions run completes.

Never create or push a release tag before the code is merged to `main`, and
never run `pnpm publish` manually.

## Common Patterns

### Scene Context Usage
Expand Down Expand Up @@ -359,8 +384,6 @@ function <ComponentName>Component({ rendererType }: { rendererType?: 'webgpu' |

const handleCreated = (scene: THREE.Scene, components: SceneComponents) => {
const { camera } = components
if (!camera) return

camera.position.set(0, 0, 4)
camera.lookAt(0, 0, 0)

Expand All @@ -375,7 +398,7 @@ function <ComponentName>Component({ rendererType }: { rendererType?: 'webgpu' |
}, [])

return (
<Scene rendererType={rendererType} bgColor="#1a1a2e" style={{ marginTop: '10px', width: '100%', height: '300px' }} onCreated={handleCreated} />
<Scene rendererType={rendererType} bgColor="rgb(40, 42, 54)" style={{ marginTop: '10px', width: '100%', height: '300px' }} onCreated={handleCreated} />
)
}
```
Expand Down
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,32 @@
## [0.7.0] - 2026-10-21

### Added

- Add the `Water` component: a displaced plane driven by a 14 wave directional spectrum that is shared with a CPU sampler, so the waterline test follows the surface the shader renders. Shading covers Fresnel reflectance, GGX sun glitter, foam ribbons, depth based water colors, planar reflection and refraction, and an eased transition when the camera crosses the surface.
- Capture planar reflections and refractions explicitly on the WebGL backend, while WebGPU resolves both through the `reflector()` and `viewportSharedTexture()` nodes. Captures are sized from the drawing buffer and skipped while the camera is underwater.
- Add the `HeightFog` component: a screen-space exponential fog layer whose density falls off with world height, with flowing noise and directional inscattering towards a configurable light azimuth and elevation.
- Add the `Fireworks` class: one shader-driven shell that launches a streak and bursts into gravity-bent ribbon trails, with options for burst height, scale, color, timing and trail geometry resolution.
- Add WebGPU / WebGL demos and bilingual (English and Chinese) documentation for the three new effects, and extend the public API surface guard test with the new exports.
- Add unit tests for the wave spectrum sampler, the procedural noise map, the water material graph and the WebGL mirror camera projection.

## [0.6.0] - 2026-10-08

### Added

- Add GIS support with a geographic coordinate reference system. Geographic coordinates (`lng`, `lat`, `alt`) are normalized to WGS84, projected onto a local tangent plane and recentered around a configurable origin, preventing the float32 precision jitter that raw Web Mercator coordinates (around 1.3e7 metres) would cause.
- Add datum conversion between WGS84, GCJ02 and BD09 (`toWGS84`, `fromWGS84`, `convertDatum`, `wgs84ToGcj02`, `gcj02ToWgs84`, `gcj02ToBd09`, `bd09ToGcj02`), with a fixed-point GCJ02 inverse.
- Add projection helpers: recentered Web Mercator (`mercatorProject`, `mercatorUnproject`, `mercatorCRS`) and an equirectangular local tangent plane (`createLocalPlane`).
- Add the `GeoReference` class (and the `createGeoReference` factory) for geographic-to-local conversion, with `toLocal`, `toGeo`, `setPosition` and `distance` methods. ENU axes map east to `+X`, north to `-Z` and up to `+Y`.
- Add `origin`, `crs`, `datum`, `axes` and `geo` props to `<Scene>`. The scene always owns a `GeoReference` (the WGS84 default at `0,0` is a no-op), exposed as `components.geo` in `onCreated` and as `geo` on the `useScene()` context. Omitting the new props keeps the previous behavior unchanged.
- Add the `GeoObject` component to declaratively anchor any `THREE.Object3D` at a geographic coordinate, with per-object datum override and in-place position updates when the coordinate changes.
- Add the `GeoJsonLayer` component for rendering GeoJSON `Point`, `LineString`, `Polygon` (including holes), `MultiPoint`, `MultiLineString`, `MultiPolygon`, `Feature` and `FeatureCollection` data, with base and per-feature styles and datum conversion.
- Add unit tests for datum conversion, projections, `GeoReference` and GeoJSON flattening, and extend the public API surface guard test with the new GIS exports.
- Add WebGPU / WebGL demo components and bilingual (English and Chinese) documentation for the GIS features.
- Allow the `gridHelper` prop of `<Scene>` to accept a `GridHelperOptions` config object (`size`, `divisions`, `colorCenterLine`, `colorGrid`, `y`), so callers can customise the built-in grid without constructing a `THREE.GridHelper` themselves. Passing a `THREE.GridHelper` instance remains supported, and the scene owns disposal of the grid in both cases.
- Add the `TileLayer` component to project standard XYZ / slippy-map raster tiles (256 px, Web Mercator) onto the geographic ground plane. The layer fills the bounding rectangle of a set of coverage points, lazy-loads tile images with `{z}`/`{x}`/`{y}`/`{s}` URL templates, fades tiles in as they arrive and disposes every geometry, material and texture on unmount. Tile selection is datum-neutral and each tile corner is placed through the `GeoReference` in the imagery datum, so GCJ02 sources such as AMap stay seamless. A `maxTiles` safety cap prevents accidental mass requests, and `onReady` / `onTileError` report lifecycle events.
- Add slippy-map tile math utilities: `TILE_SIZE`, `lngLatToTile`, `tileToLngLatBounds`, `tileToCorners`, `selectTiles` and `tileUrl`.
- Add WebGPU / WebGL demo and bilingual documentation for `TileLayer`.

## [0.5.0] - 2026-08-27

This release migrates the library from a WebGL-only implementation to a dual-renderer architecture built on Three.js TSL, with `WebGPURenderer` as the new default.
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ Visit [r3l.sunquakes.com](https://r3l.sunquakes.com).
- **Scene** — Core 3D scene container with camera, renderer, lights, and controls
- **Model Loaders** — GLTF / FBX / OBJ loaders with Draco compression support
- **Bloom** — Post-processing glow effect
- **HeightFog** — Screen-space exponential height fog
- **Fireworks** — Shader-driven firework launch with gravity-bent burst trails
- **Rain / Snow** — Particle effects with custom GLSL shaders
- **Water** — Cinematic shallow ocean with planar reflection and refraction
- **SweepLight** — Model sweep light animation
- **LightGradient** — Dynamic lighting gradient effect
- **Callout** — Leader line annotation with auto-anchor camera tracking
Expand Down
3 changes: 3 additions & 0 deletions README_ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@
- **Scene** — 核心 3D 场景容器,集成相机、渲染器、灯光和控制器
- **Model Loaders** — GLTF / FBX / OBJ 模型加载器,支持 Draco 压缩
- **Bloom** — 后处理辉光效果
- **HeightFog** — 屏幕空间指数高度雾
- **Fireworks** — 基于着色器的烟花升空与重力弯曲拖尾
- **Rain / Snow** — 基于 GLSL 着色器的粒子效果
- **Water** — 电影级浅海效果,支持平面反射与折射
- **SweepLight** — 模型扫描光线动画
- **LightGradient** — 动态光照渐变效果
- **Callout** — 引线注释,支持自动锚点跟随相机
Expand Down
4 changes: 2 additions & 2 deletions docs/guide/animation.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Every example below can be viewed with either the **WebGPU** (default) or the **
return (
<Scene
style={{ marginTop: '10px', width: '100%', height: '300px' }}
bgColor="#1a1a2e"
bgColor="rgb(40, 42, 54)"
onCreated={handleCreated}
/>
)
Expand Down Expand Up @@ -66,7 +66,7 @@ Every example below can be viewed with either the **WebGPU** (default) or the **
<Scene
rendererType="webgl"
style={{ marginTop: '10px', width: '100%', height: '300px' }}
bgColor="#1a1a2e"
bgColor="rgb(40, 42, 54)"
onCreated={handleCreated}
/>
)
Expand Down
4 changes: 2 additions & 2 deletions docs/guide/callout.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ Every example below can be viewed with either the **WebGPU** (default) or the **

return (
<Scene
bgColor="#1a1a2e"
bgColor="rgb(40, 42, 54)"
style={{ marginTop: '10px', width: '100%', height: '360px' }}
onCreated={handleCreated}
/>
Expand Down Expand Up @@ -160,7 +160,7 @@ Every example below can be viewed with either the **WebGPU** (default) or the **
return (
<Scene
rendererType="webgl"
bgColor="#1a1a2e"
bgColor="rgb(40, 42, 54)"
style={{ marginTop: '10px', width: '100%', height: '360px' }}
onCreated={handleCreated}
/>
Expand Down
Loading
Loading