@plasius/gpu-renderer 0.2.47 → 0.2.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -11,6 +11,42 @@ All notable changes to this project will be documented in this file.
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ - **Added**
15
+ - (placeholder)
16
+
17
+ - **Changed**
18
+ - (placeholder)
19
+
20
+ - **Fixed**
21
+ - (placeholder)
22
+
23
+ - **Security**
24
+ - (placeholder)
25
+
26
+ ## [0.2.48] - 2026-10-11
27
+
28
+ - Expose native material preflight validation and transfer the reviewed demo adapters plus their tests to the shared material-study runtime for production reuse (#230).
29
+
30
+ - Correct vertical grab direction in the material-review camera for mouse, touch and keyboard orbit; preserve horizontal, pan and zoom directions (#230).
31
+
32
+ - Replace the material review camera toolbar with a five-second focus gesture guide; keep direct mouse/touch movement independent of keyboard modes, with replay and dismissal (#230).
33
+
34
+ - Update the existing brace-expansion development override to 5.0.12 for patched denial-of-service advisories (#230).
35
+
36
+ - Fix native normal maps losing detail at close range; add a source-demo camera adapter using shared orbit, truck, pan, dolly and zoom controls with keyboard/touch support (#230).
37
+
38
+ - Fix full varnish wear to exactly match the uncoated endpoint; replace random rope strands with shorter, finer guide-aligned tufts and bounded denser nap (#230).
39
+
40
+ - Add a versioned material-ageing profile and crate adapter with independent 30% rope fraying / 90% varnish-wear review defaults; preserve fibre roots across wear edits and retain coating islands within heavily scuffed wood (#230).
41
+
42
+ - Add bounded, deterministic curved rope fibres to the chest review fixture, with matte exposed-fibre materials and comparison/detail views (#230).
43
+
44
+ - Support spatial clearcoat coverage and roughness maps; keep the crate fixture's rope and hardware uncoated and vary its wood varnish with a deterministic wear preset (#230).
45
+
46
+ - Separate optional neutral varnish/clearcoat reflection from the coloured native surface, with independent roughness and Fresnel attenuation (#230).
47
+
48
+ - Add bounded, mip-filtered authored colour, normal and ORM materials to native surfaces, with optional UVs and draw ranges shared by the main and reflection passes (#230).
49
+
14
50
  - **Added**
15
51
  - (placeholder)
16
52
 
@@ -1165,3 +1201,4 @@ All notable changes to this project will be documented in this file.
1165
1201
  [0.2.45]: https://github.com/Plasius-LTD/gpu-renderer/releases/tag/v0.2.45
1166
1202
  [0.2.46]: https://github.com/Plasius-LTD/gpu-renderer/releases/tag/v0.2.46
1167
1203
  [0.2.47]: https://github.com/Plasius-LTD/gpu-renderer/releases/tag/v0.2.47
1204
+ [0.2.48]: https://github.com/Plasius-LTD/gpu-renderer/releases/tag/v0.2.48
package/README.md CHANGED
@@ -786,3 +786,198 @@ there is no npm write-token fallback. CD remains disabled until the npm trusted
786
786
  publisher binding and protected-branch-only production environment are
787
787
  independently verified.
788
788
  <!-- END PLASIUS RELEASE INTEGRITY -->
789
+
790
+ ### Authored materials in native surfaces
791
+
792
+ `createNativeSceneRenderer({ canvas, materials })` accepts up to 16 opaque
793
+ materials containing decoded RGBA8 `baseColor`, `normal`, and/or `orm` maps.
794
+ This matches images returned by the `@plasius/gpu-shared` glTF loader. Colour maps
795
+ are sRGB; normals and ORM (occlusion/roughness/metalness) are linear. Optional
796
+ `normalScale` defaults to 1. Maps must be power-of-two, up to 2048 pixels per axis,
797
+ with a 64 MiB combined decoded-source budget. Textures are uploaded once and mip
798
+ filtered; the renderer owns GPU disposal, while callers own image loading.
799
+
800
+ For textured frames, supply `texcoords` (two floats per vertex) and `surfaces`
801
+ containing `{ firstVertex, vertexCount, materialIndex }`. Ranges must cover the
802
+ whole triangle list in order, refer to the initialization-time materials, and
803
+ contain whole triangles. At most 256 ranges are accepted. Linear vertex colour
804
+ and roughness/metalness factors multiply the maps. Omit both new frame fields to
805
+ retain the existing procedural/untextured path. Main and reflection passes use
806
+ the same authored material; alpha/transmission/skinning are not added here.
807
+
808
+ See [material design](docs/design/native-textured-surfaces.md) and
809
+ [ADR-0031](docs/adrs/adr-0031-native-authored-materials.md). Rollout inherits
810
+ `gpu-demo.scene-fidelity.enabled`; access remains governed by the site's capability.
811
+
812
+ For varnished wood, set optional `clearcoat` and `clearcoatRoughness` (both 0–1).
813
+ The coating reflects neutral light using its own smooth geometric normal above
814
+ the coloured, normal-mapped wood; Fresnel layering attenuates the underlying
815
+ material instead of simply adding shine. Strength defaults to zero, preserving
816
+ uncoated callers. Coating roughness defaults to zero and is independent of the
817
+ base roughness map. Optional `clearcoatMap` uses linear RGBA8: red multiplies
818
+ `clearcoat` coverage and green multiplies `clearcoatRoughness`; blue and alpha
819
+ are ignored. Omission uses white, preserving the scalar-only finish. Use a
820
+ nonzero roughness factor (for example 1) to author roughness directly in green.
821
+ The map shares the surface UVs, mip filtering, memory budget and GPU lifetime of
822
+ other maps. Clearcoat normal maps remain unsupported.
823
+
824
+ For mixed objects, give uncoated parts their own surface ranges with
825
+ `clearcoat: 0`. This keeps rope and hardware uncoated even when they share the
826
+ wood's atlas. The source example [native-crate-finish.js](https://github.com/Plasius-LTD/gpu-shared/tree/main/src/material-study-helpers/native-crate-finish.js)
827
+ provides reviewed crate ranges and a deterministic wear preset combining existing
828
+ roughness/scuff detail with broad UV patches. Its 0–1 wear control changes coat
829
+ coverage and roughness without modifying the underlying colour or source asset.
830
+ See [spatial coating decision](docs/adrs/adr-0032-spatial-native-clearcoat.md) and
831
+ the [fixture/provenance record](docs/design/cc0-demo-asset-review.md). The example
832
+ helper is source-only; the published API is the generic material map.
833
+
834
+ For subtle rope fraying, the source-demo helper
835
+ [native-rope-fibres.js](https://github.com/Plasius-LTD/gpu-shared/tree/main/src/material-study-helpers/native-rope-fibres.js) exports `createRopeFibres`.
836
+ Pass the expanded native `vertices`, `texcoords` and explicit rope-only
837
+ `{ firstVertex, vertexCount }` ranges. It returns separate triangles/UVs and a
838
+ `fibreCount`; append them once with their own draw range. Generate in metre-scale
839
+ world coordinates after transforms. Sampling is deterministic and area-weighted,
840
+ with short tapered curves in small aligned tufts. `density` controls roots per
841
+ square metre; `maxFibres` caps them at 4,000 (default 1,600). `length` and `radius`
842
+ are in metres. The 21 triangles per strand use ordinary native multisampling,
843
+ depth and lighting; no animated fur or dedicated hair scattering is claimed.
844
+
845
+ Optional `fray` (0–1, default 0.08) promotes exactly
846
+ `round(fibreCount * fray)` strands to longer curled loose ends, reported as
847
+ `looseEndCount`. Selection is seeded and nested: raising the level keeps earlier
848
+ loose ends, roots and UVs in place. At 0, short fuzz remains. This is a visual
849
+ proportion of generated fibres, not lost rope strength.
850
+
851
+ Use `createRopeFibreMaterial(ropeMaterial)` for the added range: it keeps the
852
+ rope's colour map and zero clearcoat while omitting the core's baked occlusion
853
+ and normal creases from exposed fibres. Vertex roughness is 1 and metallic is 0.
854
+ The review fixture offers fibre on/off and both rope-detail views. See
855
+ [ADR-0033](docs/adrs/adr-0033-demo-rope-fibres.md). These helpers remain source-only
856
+ and do not add a renderer API, dependency or network request.
857
+
858
+ ### Material ageing review wrapper
859
+
860
+ [material-ageing.js](https://github.com/Plasius-LTD/gpu-shared/tree/main/src/material-study-helpers/material-ageing.js) validates and freezes a serializable
861
+ version-1 profile. [native-crate-ageing.js](https://github.com/Plasius-LTD/gpu-shared/tree/main/src/material-study-helpers/native-crate-ageing.js) applies it
862
+ through the existing coating/fibre helpers:
863
+
864
+ ```js
865
+ import { createCrateAgeing } from '@plasius/gpu-shared/material-study';
866
+
867
+ const ageing = createCrateAgeing({ ropeFray: 0.30, varnishWear: 0.90, seed: 7349 });
868
+ const { wood, rope, metal, fibres: fibreMaterial } = ageing.createMaterials(sourceMaps);
869
+ const fibreGeometry = ageing.createFibres({ vertices, texcoords, ranges: ropeRanges, heightOffset: -minY });
870
+ // Append fibreGeometry with fibreMaterial using the existing native draw contract.
871
+ ```
872
+
873
+ Those values are also the review defaults. `varnishWear` is independent visual
874
+ intensity, not coating area removed or elapsed years. Broad scuff patches expose
875
+ wood while sheltered areas retain coating at intermediate wear. Above 70%, the
876
+ remaining islands smoothly erode; at 100%, every coverage texel and the scalar
877
+ coat strength are zero, matching varnish disabled. The original wood maps remain
878
+ unchanged, including their ordinary substrate light response. `seed` controls fibre placement and
879
+ loose-end selection; varnish uses its existing stable UV pattern. The crate adapter
880
+ uses a 4.5 mm fibre length scale and 0.16 mm root radius, with a 4,000-fibre budget;
881
+ loose ends are 1.3–2 times the length scale and taper to a point. Source images and
882
+ geometry remain unchanged; rope, added fibres and metal never acquire clearcoat.
883
+
884
+ Generate/copy geometry only when the fray channel changes; rebuild finish maps
885
+ only when coating settings change. Camera movement reuses both. The caller still
886
+ owns verified asset ranges, GPU resources and disposal. The local review includes
887
+ fresh/aged presets, fibre/coat toggles and both handle-detail views.
888
+
889
+ This is a tested source-demo wrapper, not a newly published package or a complete
890
+ damage simulator. [ADR-0034](docs/adrs/adr-0034-material-ageing-profile.md) records
891
+ the proposed `@plasius/material-ageing` boundary after a second asset establishes
892
+ the shared contract. Production adoption retains `gpu-demo.scene-fidelity.enabled`
893
+ and the existing GPU route capability; disabling the feature selects the existing
894
+ site fallback. No package publication or site deployment is implied by this study.
895
+
896
+
897
+ For structured nap, `createRopeFibres` accepts optional `guides`: at most eight
898
+ polylines of 2–65 finite 3D points, in the same metre-scale coordinates as the
899
+ input geometry. The nearest guide is projected onto the surface and given a
900
+ consistent helical lay. Without a usable projected guide, a finite tangent
901
+ fallback is used. Four nearby roots form a tuft within 1 mm of its anchor, with
902
+ small angular variation, shallow lift and tapered tips. Sampling remains stable
903
+ when fray changes; changing guides reauthors the groom.
904
+
905
+ [native-crate-groom.js](https://github.com/Plasius-LTD/gpu-shared/tree/main/src/material-study-helpers/native-crate-groom.js) supplies the hash-verified
906
+ fixture's loop/knot paths. Pass the same `heightOffset` used to ground its vertices
907
+ (default 0 means unmodified asset coordinates); other transforms require matching
908
+ transformed guide coordinates. The crate adapter adds 84,000 triangles: 90,578
909
+ triangles / 271,734 vertices total, within the native default budget. Its final
910
+ fibre arrays occupy 14,112,000 bytes. This deliberate denser nap replaces the
911
+ previous 1,600-strand loose-end study. See [ADR-0035](docs/adrs/adr-0035-groomed-rope-and-bare-coat-endpoint.md).
912
+
913
+
914
+ ### In-scene material inspection camera
915
+
916
+ The shared [native-demo-camera.js](https://github.com/Plasius-LTD/gpu-shared/tree/main/src/material-study-helpers/native-demo-camera.js) adapter uses
917
+ released `@plasius/gpu-camera` state/control/projection APIs and the separate
918
+ `@plasius/gpu-camera-controls` pointer gesture runtime/browser normalizer. It maps DOM input to
919
+ orbit, camera-plane truck/pedestal, pan/tilt, dolly and optical zoom; camera math
920
+ is not duplicated in the renderer. The camera and fixture adapters now belong to the isolated gpu-shared material-study
921
+ entry; the renderer root does not load them.
922
+
923
+ ```js
924
+ import { createNativeDemoCamera } from '@plasius/gpu-shared/material-study';
925
+
926
+ // Supply a focusable canvas with an accessible name and persistent
927
+ // aria-describedby instructions. The visual example is initially hidden,
928
+ // aria-hidden, pointer-events:none and contains no interactive controls.
929
+ const cameraControls = createNativeDemoCamera({
930
+ canvas,
931
+ camera: { eye: [-0.7, 0.5, 0.8], target: [0, 0.16, 0], fov: 42 },
932
+ onChange: () => draw(),
933
+ onHintChange: visible => { gestureExample.hidden = !visible; },
934
+ });
935
+ // Each draw uses camera: cameraControls.read(). Keep the controls alive across
936
+ // renderer/material rebuilds; defer drawing while the renderer is unavailable.
937
+ // At teardown (also cancels the hint timer):
938
+ cameraControls.destroy();
939
+ ```
940
+
941
+ The material review uses direct manipulation with no persistent camera toolbar.
942
+ The optional `onHintChange` callback shows a brief example on canvas focus and
943
+ hides it after five seconds, on blur, Escape or disposal. Refocus or `?` replays
944
+ it; replay replaces the prior timer. The host owns visual presentation: show
945
+ mouse/touch or keyboard examples, preserve a screen-reader description without a
946
+ time limit, and respect reduced motion. Do not move the camera to demonstrate a
947
+ gesture or let the example intercept input. Keep material controls below the scene.
948
+
949
+ | Input | Camera action |
950
+ | --- | --- |
951
+ | Left-drag / one finger | Orbit, with the grabbed surface following the drag on both axes |
952
+ | Right/middle/Shift-drag | Truck / pedestal across the current view |
953
+ | Alt-drag | Pan / tilt in place |
954
+ | Scroll / touch pinch | Move closer or farther (dolly) |
955
+ | Shift-scroll | Change the lens (optical zoom) |
956
+ | Two fingers moving together | Truck / pedestal |
957
+ | Arrows / Shift-arrows | Selected keyboard mode / truck |
958
+ | 1–5 | Select orbit, truck, pan, dolly or lens zoom for keyboard arrows |
959
+ | +/− | Dolly (lens zoom in keyboard zoom mode) |
960
+ | Home | Reset view |
961
+ | ? / Escape | Replay / dismiss the brief guide |
962
+
963
+ Vertical orbit follows the grab direction for mouse, one-finger touch and keyboard
964
+ arrows. The adapter maps single-pointer orbit through gpu-camera; the shared
965
+ gesture runtime retains original pointer coordinates for multi-pointer truck/pinch
966
+ and stable transitions. Keyboard mode selection does not change mouse or touch gestures. The source-only
967
+ `setMode`, `getMode`, `move` and `reset` methods remain available to host code.
968
+ Browser Ctrl/Meta/Alt key shortcuts and keys outside the canvas are left alone.
969
+ Wheel input only belongs to a focused canvas; the surrounding page remains
970
+ scrollable. No inertia or animation loop is introduced. Distances, lens and travel
971
+ are bounded; pointer cancellation/blur/disposal release captures and listeners.
972
+ This is an inspection camera without scene collision detection or object picking.
973
+
974
+ Native material normal-map degeneracy checks now use normalized screen-space
975
+ position/UV gradients. Valid tiny derivatives in rope macro views no longer disable
976
+ normal maps. Mirrored UV handedness and geometric-normal fallback for degenerate
977
+ UVs are retained in the common direct/reflection shader. The shader contract tests
978
+ require browser rendering evidence as well; Node mocks do not execute WGSL.
979
+ See [ADR-0036](docs/adrs/adr-0036-in-scene-material-inspection.md).
980
+
981
+ ### Shared material-study runtime
982
+
983
+ Production demo helpers and their regression tests now live in `@plasius/gpu-shared/material-study`. The renderer exposes `validateNativeSurfaceMaterials(materials)` so authoring and GPU creation use identical validation without allocation. See [ADR-0037](docs/adrs/adr-0037-shared-material-study-runtime.md).