Skip to content

Fix StandardMaterial property types in the generated .d.ts - #9163

Draft
willeastcott wants to merge 1 commit into
mainfrom
fix-standard-material-dts-types
Draft

Fix StandardMaterial property types in the generated .d.ts#9163
willeastcott wants to merge 1 commit into
mainfrom
fix-standard-material-dts-types

Conversation

@willeastcott

Copy link
Copy Markdown
Contributor

Description

StandardMaterial defines its accessors dynamically, so tsc emits none of them — they are declared by hand from STANDARD_MAT_PROPS in utils/plugins/rollup-types-fixup.mjs. Each doc comment was looked up with contents.match(`@property {${type}} ${name}`), passing the type through as a regex. That one line caused three distinct defects.

1. Type disagreements silently dropped the doc comment and emitted the wrong type. When the type in the list disagreed with the class JSDoc, the lookup found nothing, so the accessor was emitted with an empty doc comment and the (wrong) type from the list:

Property Emitted .d.ts Runtime default Correct type
occludeDirect number false boolean
alphaFade boolean 1 (_defineFloat) number

Both broke the correct assignment from TypeScript:

material.occludeDirect = true;  // TS2322: Type 'boolean' is not assignable to type 'number'.
material.alphaFade = 0.5;       // TS2322: Type 'number' is not assignable to type 'boolean'.

occludeDirect is the one reported in #9152; alphaFade is the same defect found by generalizing it.

2. Texture|null was treated as a regex alternation. It matched @property {Texture at its first occurrence in the file and then sliced from the wrong offset, so every texture property inherited a mangled fragment of diffuseMap's description:

/** e main (primary) diffuse map of the material (default is null). */
set anisotropyMap(arg: Texture|null);

/** seMap The main (primary) diffuse map of the material (default is null). */
set aoMap(arg: Texture|null);

3. @property {number} anisotropy prefix-matched anisotropyIntensity, so the deprecated alias inherited its neighbour's documentation.

Changes

  • occludeDirectboolean, alphaFadenumber, matching their runtime defaults.
  • opacityShadowDither's JSDoc said boolean for what is a dither mode string (DITHER_NONE/DITHER_BAYER8/…). The emitted declaration was already correct, so the JSDoc is corrected to string — its sibling opacityDither was already documented correctly.
  • The doc lookup now parses the @property block into a map keyed by property name instead of building a regex out of the type. This restores the correct description on ~30 texture properties and on anisotropy.
  • The build now throws on a type disagreement or a missing @property tag, so this cannot silently regress into a dropped doc comment again:
    StandardMaterial types disagree with its JSDoc - fix the @property tag in
    src/scene/materials/standard-material.js or the type in STANDARD_MAT_PROPS:
      occludeDirect: declared as 'number' but documented as 'boolean'
    
  • Added the missing @property tag for sheenVertexColorChannel (verified 'rgb' at runtime) and an explicit @deprecated doc for the anisotropy alias.

Every StandardMaterial accessor now emits with its own correct doc comment — previously occludeDirect, opacityShadowDither, alphaFade and sheenVertexColorChannel had none at all.

Fixes #9152

Notes for reviewers

  • The guard no longer encodes a type (set alphaFade(arg: boolean);set alphaFade(arg:), so it won't need updating the next time a type changes. Re-running build:types is idempotent — verified.
  • The new check firing was verified by re-introducing both failure modes against a temp copy of the plugin.
  • Out of scope, worth a follow-up: checking the reverse direction turned up 49 documented properties with no declaration in the .d.ts at all (thickness, attenuation, sheenGloss, alphaDither, and all the iridescence/refraction ones) — the hand-maintained list holds 184 entries against 233 @property tags. That's missing declarations rather than wrong ones, and adding 49 entries would swamp this change, so it is deliberately left out.

Testing

  • npm run build:typesnpm run test:types clean.
  • The issue's repro type-checks under --strict, with occludeDirect = 1 and alphaFade = true still correctly rejected (asserted via @ts-expect-error).
  • npm run lint clean.
  • npm test: 2044 passing / 11 failing — identical with the changes stashed. The 11 are pre-existing asset-loading timeouts in the font/sprite handler tests, unrelated to this change.

Checklist

  • I have read the contributing guidelines
  • My code follows the project's coding standards
  • This PR focuses on a single change

StandardMaterial defines its accessors dynamically, so tsc emits none of
them. They are declared by hand from STANDARD_MAT_PROPS in the types fixup
plugin, and each doc comment was looked up with
contents.match(`@property {${type}} ${name}`) - passing the type through as
a regex. That one line caused three distinct defects:

- When the type in the list disagreed with the type in the class JSDoc, the
  lookup silently found nothing, so the accessor was emitted with no doc
  comment and with the (wrong) type from the list. occludeDirect was typed
  `number` despite defaulting to `false`, so `material.occludeDirect = true`
  needed a @ts-ignore from TypeScript. alphaFade had the same problem in
  reverse, typed `boolean` despite being _defineFloat('alphaFade', 1).

- `Texture|null` was treated as a regex alternation, matching "@Property
  {Texture" at its first occurrence in the file and then slicing from the
  wrong offset. Every texture property inherited a mangled fragment of
  diffuseMap's description, e.g. anisotropyMap documented as "e main
  (primary) diffuse map of the material (default is null)."

- "@Property {number} anisotropy" prefix-matched anisotropyIntensity, so the
  deprecated alias inherited its neighbour's documentation.

Fixes:

- occludeDirect is now `boolean` and alphaFade `number`, matching their
  runtime defaults.
- opacityShadowDither's JSDoc said `boolean` for what is a dither mode
  string (DITHER_NONE etc.); the emitted declaration was already correct, so
  the JSDoc is corrected to `string`.
- The doc lookup now parses the @Property block into a map keyed by property
  name, rather than building a regex out of the type.
- The build throws on a type disagreement or a missing @Property tag, so
  this cannot silently regress into a dropped doc comment again.
- Added the missing @Property tag for sheenVertexColorChannel, and an
  explicit @deprecated doc for the anisotropy alias.

Every StandardMaterial accessor now emits with its own correct doc comment.

Fixes #9152

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Build size report

This PR does not change the size of the minified bundles.

Bundle Minified Gzip Brotli
playcanvas.min.js 2358.1 KB — 605.3 KB — 470.2 KB —
playcanvas.min.mjs 2355.5 KB — 604.4 KB — 469.5 KB —

@github-actions

Copy link
Copy Markdown

Public API report

This PR changes the public API surface (+2 / −1), per the docs' rules (@ignore / @Private / undocumented are excluded).

Show API diff
-StandardMaterial.opacityShadowDither: boolean
+StandardMaterial.opacityShadowDither: string
+StandardMaterial.sheenVertexColorChannel: string

Informational only — this never fails the build.

@willeastcott
willeastcott marked this pull request as draft August 12, 2026 20:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

StandardMaterial: occludeDirect is typed as number in the generated .d.ts, and opacityShadowDither's JSDoc says boolean

1 participant