Skip to content

Fix alphaFade and occludeDirect types in the StandardMaterial declarations - #9295

Merged
willeastcott merged 5 commits into
mainfrom
fix-dts-alphafade-occludedirect-types
Sep 4, 2026
Merged

Fix alphaFade and occludeDirect types in the StandardMaterial declarations#9295
willeastcott merged 5 commits into
mainfrom
fix-dts-alphafade-occludedirect-types

Conversation

@willeastcott

@willeastcott willeastcott commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Description

Fixes two wrong types in the generated StandardMaterial TypeScript declarations, and makes the fixup that injects those declarations safe to re-run over a stale file and correct in what it emits.

Addresses the .d.ts half of #9152. The other half of that issue, the opacityShadowDither JSDoc type, was fixed in #9294.

TypeScript cannot see the accessors that StandardMaterial creates with Object.defineProperty, so the types build injects them into standard-material.d.ts from the STANDARD_MAT_PROPS list in utils/plugins/rollup-types-fixup.mjs. Two entries in that list disagreed with the runtime and the JSDoc:

  • alphaFade was declared boolean. It is a float (default 1) that feeds the material_alphaFade uniform.
  • occludeDirect was declared number. It is a boolean flag (default false).

Idempotent injection. The plugin relied on a hard-coded guard string, 'set alphaFade(arg: boolean);', to recognise a declaration file that had already been fixed up. Incremental tsc runs and the watch build depend on that check to avoid injecting the accessors twice, so fixing the list alone would have broken it, and any guard that encodes a type has the same problem the next time a type changes. The transformer is now idempotent instead: tsc indents the class body with four spaces while the injected accessors are tab-indented, so a run of tab-indented lines directly after the reset(): void; anchor can only be an earlier injection, and it is replaced in place. A stale file left behind by an incremental tsc run, including one produced by the old plugin with alphaFade as boolean, is therefore corrected rather than duplicated. The anchor is located with a plain string search, so the anchor string is the single source of truth, and the transformer throws if it is missing instead of silently emitting a class without the accessors.

Correct doc comments. The description lookup passed @property {Type} name to String#match, which reads the type as a regex. Texture|null therefore matched the first @property {Texture tag in the file and sliced from the wrong offset, so 21 texture accessors in the published declarations carried a fragment of diffuseMap's description. For example aoMap:

// before
/** seMap The main (primary) diffuse map of the material (default is null). */
set aoMap(arg: Texture|null);
// after
/** The main (primary) baked ambient occlusion (AO) map (default is null). Modulates ambient color. */
set aoMap(arg: Texture|null);

The lookup is now a plain string search for the tag, and a description ends at the next block tag or the end of the comment rather than running to the end of the file when the tag is the last one in the block.

Public API changes (build/playcanvas.d.ts)

Before:

set alphaFade(arg: boolean);
get alphaFade(): boolean;
set occludeDirect(arg: number);
get occludeDirect(): number;

After:

set alphaFade(arg: number);
get alphaFade(): number;
set occludeDirect(arg: boolean);
get occludeDirect(): boolean;

material.alphaFade = 0.5 and material.occludeDirect = true now type-check. No runtime changes.

Verification

  • Produced a genuinely stale file by fixing up a clean tsc emit with the plugin from main, then ran the new plugin over it: a single accessor block with the corrected types, a second run is a no-op, and the result is byte-identical to a fresh injection on a clean emit.
  • Diffed the bundled .d.ts against the previous transformer's output: exactly 21 lines changed, all of them doc comments on Texture|null accessors; no declaration changed.
  • Synthetic declaration files check that a description ending at @category or at the end of the comment is extracted correctly, and that a missing anchor throws.
  • npm run build:types with incremental tsc reusing the patched file, npm run test:types, a consumer tsc check of the two assignments above, and npm run lint.

Relationship to #9163. The draft PR #9163 fixes the same two types and the same String#match bug as part of a broader rewrite of the plugin, with build-time validation of the list against the JSDoc. This PR is the minimal, independently mergeable subset. If #9163 lands first, this PR can simply be closed. If this lands first, #9163 needs a rebase of its transformer changes; the two list entries are identical hunks.

Checklist

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

🤖 Generated with Claude Code

…clarations

- alphaFade is a number (default 1), not a boolean
- occludeDirect is a boolean flag (default false), not a number
- Derive the fixup guard from the first STANDARD_MAT_PROPS entry instead of
  hard-coding the alphaFade type, so the list and the guard cannot drift apart

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 3, 2026

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 2407.4 KB — 620.0 KB — 481.4 KB —
playcanvas.min.mjs 2404.7 KB — 618.7 KB — 480.4 KB —

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new type-specific guard can cause duplicate accessor injection when upgrading from previously fixed-up incremental outputs, potentially breaking the generated .d.ts.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR updates the TypeScript declaration fixup plugin so the generated StandardMaterial accessors match runtime/JSDoc types, and adjusts the injection guard logic used to keep incremental/watch type builds from re-injecting the accessor block.

Changes:

  • Correct STANDARD_MAT_PROPS entries so alphaFade is emitted as number and occludeDirect as boolean.
  • Replace the hard-coded guard string with one derived from the first STANDARD_MAT_PROPS entry to reduce drift between the guard and the injected accessor list.
File summaries
File Description
utils/plugins/rollup-types-fixup.mjs Fixes two StandardMaterial accessor types and updates the “already fixed up” guard generation for the types injection step.
Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread utils/plugins/rollup-types-fixup.mjs Outdated
willeastcott and others added 2 commits September 4, 2026 00:49
…types fixup

The fixup used to inject the accessors whenever a guard string was missing.
With the alphaFade type corrected, a declaration file left behind by an
incremental tsc run (fixed up by the old plugin, with alphaFade as boolean)
would not match the new guard and would receive a second copy of the block.

The transformer now recognises any earlier injection - tsc indents the class
body with four spaces while the injected lines are tab-indented - and
replaces it in place, so a stale block is corrected rather than duplicated.
It also throws if the anchor is missing, and uses a function replacement so
a '$' in a description cannot be read as a replacement pattern.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The updated transformer still uses String#match with an unescaped pattern derived from STANDARD_MAT_PROPS (e.g. Texture|null), which can mis-match @property tags and inject incorrect JSDoc/accessor blocks.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 2
  • Review effort level: Lite

Comment thread utils/plugins/rollup-types-fixup.mjs Outdated
Comment thread utils/plugins/rollup-types-fixup.mjs Outdated
…ng search

The description lookup passed "@Property {Type} name" to String#match,
which reads the type as a regex. Texture|null therefore matched the first
"@Property {Texture" tag and sliced from the wrong offset, so 21 texture
accessors carried a fragment of diffuseMap's description in the published
declarations. The lookup is now a plain string search for the tag, and a
description ends at the next block tag or the end of the comment.

The injected block is now located from the STANDARD_MAT_ANCHOR string alone,
so the anchor is no longer duplicated inside a regex.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The changes are narrowly scoped to type-generation fixup logic and appear to correctly address the stated type and doc-comment extraction defects without affecting runtime behavior.

Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

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.

2 participants