Files
millionco__react-doctor/docs/three-r3f-grading-rubric-coverage.md

44 KiB

Three.js and React Three Fiber grading-rubric coverage

React Doctor statically diagnoses code defects. It does not claim that source inspection can replace the rubric's Playwright probes, temporal evidence, prompt profile, or craft review. This map keeps that boundary explicit so adding rubric coverage does not turn intentional fixed cameras, flat styles, static scenes, or repeated formations into false positives.

The rule pairs below use Three.js import provenance and closed, locally provable object graphs. They abstain when spreads, callbacks, custom components, imported scene members, shader materials, or helper mutations can change the result.

Source-request coverage

The original request included a core Three.js/R3F implementation checklist and four explicit GPU performance directives before the grading rubric. Those requirements are part of this coverage contract rather than implicit background.

Core scene and implementation checklist

Requested pattern Three.js static coverage React Three Fiber static coverage Remaining evidence boundary
Scene, camera, renderer, DOM attachment three-valid-perspective-camera, three-valid-orthographic-camera, three-require-renderer-dom-attachment, and three-require-renderer-size r3f-valid-perspective-camera, r3f-valid-orthographic-camera, and managed Canvas ownership Required central output and successful boot remain runtime probes. Instantiating a Scene is not required when a valid externally owned scene is rendered.
Responsive resize without distortion three-require-camera-aspect-on-resize, three-effect-composer-require-size-on-resize, and three-no-unconditional-renderer-resize-in-animation-loop r3f-no-manual-canvas-resize; Canvas owns renderer sizing and camera updates CSS layout, embedded canvases, and the observed post-resize image require a runtime resize trial.
Geometry, meshes, and attributes three-valid-buffer-attribute-array-length, three-valid-buffer-attribute-item-size, three-no-normalized-float-buffer-attribute, update-flag rules, and cleanup rules Paired buffer validation, update-flag, ownership, and inline-resource rules Whether a custom shape visually matches the brief is craft evidence.
Materials, PBR properties, and textures Opacity, transparency, PBR/physical-property, ignored-property, color-space, wrapping, UV, normal, and environment rules Paired JSX/material contracts with authoritative-prop and spread handling Material attractiveness, variation, texture scale, and shader-specific semantics require pixels or craft review.
Asset loading, loading state, and failure handling three-require-loader-error-handling, three-require-ktx2-detect-support, and worker-loader cleanup r3f-prefer-use-loader and r3f-no-null-loader-input; R3F loader hooks integrate with externally owned React Suspense and error boundaries Network completion, decoder failures, and externally placed loading/error boundaries require runtime exercise or owning-component context.
Effective lighting Light-property validators plus three-require-lighting-for-pbr and three-require-environment-for-metal Paired closed-Canvas lighting and environment rules Form separation, mood, and dynamic/imported lighting remain pixel and craft evidence.
Shadows three-require-shadows-enabled, three-no-shadows-on-unsupported-light, three-valid-shadow-map-size, and three-limit-shadowed-point-lights Paired shadow contracts Visible shadow quality and prompt applicability require rendered evidence.
Animation loop and frame-rate independence three-prefer-set-animation-loop, three-require-render-in-animation-loop, three-require-frame-delta, and animation-loop safety rules useFrame priority, delta, async, dependency-array, recursion, and hot-loop rules Smoothness and equivalent evolution under throttling require temporal probes.
Orbit controls, picking, and pointer interaction three-require-controls-update, three-require-controls-cleanup, three-valid-raycaster-range, and pointer hot-path rules r3f-valid-raycaster-range, pointer-event mutation/capture rules, and pointer hot-path rules Whether controls exist when requested, gesture separation, coordinate locality, and selection correctness require prompt-aware input trials.
Modular structure General React Doctor architecture and component-size rules apply; Three.js resource ownership is separated into focused lifecycle rules The same architecture rules apply to components and hooks File/module decomposition is not a universal Three.js correctness contract and must not be inferred from scene complexity alone.
Performance and disposal Instancing, GPU-animation, allocation, compile, clone, resize, readback, material-recompile, update-flag, and owned-resource cleanup families Paired useFrame, instancing, GPU-animation, managed-resource, loader-cache, root-unmount, and cleanup families Absolute FPS, draw-call budgets, and dynamic GPU memory growth remain runtime measurements.

Explicit GPU and instancing directives

Directive Three.js rule React Three Fiber rule Reporting boundary
Use InstancedMesh for many copies of shared geometry and material three-prefer-instanced-mesh r3f-prefer-instanced-mesh Reports only provably repeated rendered meshes with stable shared resources and no incompatible per-object semantics.
Favor GPU animation for repeated instance transforms three-prefer-gpu-instanced-animation r3f-prefer-gpu-instanced-animation Reports repeated per-instance matrix/color writes in a recognized frame loop; one-time setup and open helpers abstain.
Animate repeated vertex positions in shaders or GPU state instead of rewriting buffers each frame three-prefer-gpu-position-animation r3f-prefer-gpu-position-animation Reports repeated position-buffer entry mutations in a recognized animation loop or useFrame; bulk one-time initialization and unrelated attributes stay quiet.
Compute particle position and transform evolution on the GPU where possible three-prefer-gpu-position-animation and three-prefer-gpu-instanced-animation r3f-prefer-gpu-position-animation and r3f-prefer-gpu-instanced-animation Particle vocabulary alone never reports. The detector requires the harmful CPU-per-frame mutation shape, so static or low-cardinality systems are not penalized.

These boundaries follow the current Three.js guidance for WebGLRenderer.setAnimationLoop, InstancedMesh, and BufferAttribute updates, together with R3F's managed Canvas, useFrame and useLoader, automatic disposal, and instancing guidance.

Added static contracts

Contract Three.js React Three Fiber Static reporting boundary
Normal-mapped custom geometry requires normals three-require-lit-material-normals r3f-require-lit-material-normals A closed BufferGeometry defines position, does not define or compute normal, and is paired with a built-in lit material that applies a non-null normalMap. Unlit, shader, unmapped, and open materials are excluded.
Mapped custom geometry requires UVs three-require-uv-for-texture-map r3f-require-uv-for-texture-map A closed BufferGeometry defines position, has none of uv, uv1, uv2, or uv3, and is paired with a built-in material that has a non-null UV-sampled map.
Strong metal requires an environment three-require-environment-for-metal r3f-require-environment-for-metal A closed rendered scene or inline Canvas contains a standard or physical material with statically known metalness > 0.5, no material environment map, and no scene environment. Direct lights do not satisfy metal reflections.
PBR requires a lighting source three-require-lighting-for-pbr r3f-require-lighting-for-pbr A closed rendered scene or inline Canvas contains a standard or physical material and no direct light, scene environment, material environment map, light map, or intentional emissive source.

These contracts follow the Three.js definitions of BufferGeometry attributes, texture UV channels, and environment lighting for MeshStandardMaterial. Since Three.js r183, renderers fall back to derivative-based flat shading when ordinary lit geometry has no normal attribute, so the normals rules intentionally report only the normal-map case where that fallback does not apply.

Grading-protocol boundary

The rubric also specifies how a grader combines evidence. Those instructions are not application source patterns and therefore do not become lint diagnostics.

Rubric protocol React Doctor responsibility External grader responsibility
Keep the probe floor and craft review separate Report source diagnostics with their normal rule identity, category, severity, and confidence boundary Report Plane 1 and Plane 2 side by side and never convert diagnostic count into craft credit or sum the planes into one rubric score
Set prompt applicability before grading Avoid inferring fixed-camera, flat-style, static-scene, interaction, occupancy, or visual-ambition requirements from implementation vocabulary Declare one prompt profile, eligible probes, eligible craft weight, and evidence modality before inspecting competing outputs
Grade runtime failures on calibrated share Keep each static diagnostic no broader than a locally proven defect and abstain on visibility, share, and intent ambiguity Measure visible/runtime share, calibrate thresholds against a reference, and report not measurable when confidence is insufficient
Exercise multiple poses, time, input, and recovery paths Diagnose statically provable setup, lifecycle, hot-loop, and resource-ownership defects Run boot, grazing, wide, and rotated poses; idle soak; normal and rapid input; cancellation; resize; pause/resume; and privileged-API accept/reject/retry flows
Apply hard and craft gates before scores Do not claim that a clean source scan proves a rendered experience booted, completed, or achieved spatial integrity Apply page/boot hard gates and the eligible experience-completeness and spatial-integrity craft gates before reporting scores
Preserve every passing probe as a regression Keep rule tests, fuzz regressions, open-source eval evidence, pull-request parity, and the complete repository test suite green Re-run the full probe.mjs battery for each build round instead of selecting only probes related to the latest source change
Use probe.mjs through public runtime evidence Do not require app-specific debug APIs or pretend lint can observe pixels, browser diagnostics, GPU counters, or temporal state Serve the built app and run the Playwright battery through __THREE_DEVTOOLS__, pixels, browser diagnostics, and synthetic input, using lite mode when its documented perturbation requires it

Plane 1A: core discriminators

Rubric probe Static coverage Disposition
Page errors None Runtime-only hard gate. Source cannot establish whether a page throws over the complete exercise path.
Console diagnostics Shader validation, WebGPU compatibility, render-target, texture, and material rules catch provable precursors Runtime console capture remains authoritative for driver, framebuffer, texture-unit, and deprecation diagnostics.
Boot and render three-require-render-in-animation-loop, three-require-renderer-dom-attachment, three-require-renderer-size, and R3F Canvas rules Framebuffer activity and required central output remain runtime-only.
Unprompted-interaction gate None Requires synthetic input before and after a documented entry flow.
Privileged-input acquisition and recovery None Accept, rejection, retry, and browser permission state require runtime exercise.
Input to response locality three-valid-raycaster-range and r3f-valid-raycaster-range cover invalid ray intervals only Pointer/response centroids and coordinate transforms require rendered input trials.
Input cross-contamination None Requires causal comparison of distinct gestures.
Input lifecycle Controls and root cleanup rules cover owned resources, not held-state cancellation Blur, pointercancel, visibility, and lock-loss behavior require runtime state observation.
Saturation bound Numeric material, fog, camera, light, and buffer validators cover local invalid values Simulation amplitude, NaN pixels, and freeze signatures require stressed runtime input.
Time-step independence three-require-frame-delta and r3f-require-frame-delta Static rules catch frame-step mutation that ignores the supplied delta; replay at multiple frame rates remains the behavioral oracle.
Metal without environment three-require-environment-for-metal and r3f-require-environment-for-metal Static coverage is limited to closed scenes and known metalness. Runtime share grading covers dynamic and imported scenes.
Interaction jank Allocation, clone, compile, readback, resize, state-update, and material-recompile loop rules catch high-confidence causes Long Animation Frame duration and the calibrated 200 ms threshold are runtime-only.

Plane 1B: scoped graded checks

Rubric probe Static coverage Disposition
Transparency sorting risk three-require-transparent-for-opacity and r3f-require-transparent-for-opacity validate opacity/transparent consistency Visibility, world-space classification, cutout intent, ordering, and problematic share require runtime evidence. A per-material sorting warning would violate the rubric's scope.
Color-texture semantics three-valid-texture-color-space and r3f-valid-texture-color-space Reports only statically classified color and data map roles; procedural or unknown semantics abstain.
Mipmap filters None HUD exemption, world-space use, sampled visibility, and the bad-share threshold require runtime texture/material association.
Shading normals three-require-lit-material-normals and r3f-require-lit-material-normals Current Three.js supplies a flat-shading fallback for ordinary lit geometry. The static rules report only normal-mapped geometry where normals remain required; shader, unlit, open, and externally mutated geometry abstains.
Z-fighting None Dolly flips must be measured against idle framebuffer churn from multiple poses.
Light rotation or lights-out cue Lighting configuration rules validate provable setup errors Pixel response relative to idle noise requires runtime rotation or light toggling.
Input release None Eligibility requires a causal motion pretest, followed by held, released, and ambient speed measurements.
Exposure and clipping Numeric light/material validators catch impossible local parameters Global and grid luminance/clipping shares require framebuffer pixels.
Return to rest None Transient intent and the idle-noise envelope require prompt applicability and temporal evidence.
Motion continuity Frame-delta and GPU-animation rules cover implementation hazards Entity tracking, declared teleports, cuts, wraps, respawns, and velocity discontinuities require runtime state.
Bounds containment Camera and raycaster range validators cover invalid numeric ranges only Intended containing volume and visible transitions require scene semantics and tracked transforms.
Idle motion churn None Static-by-design applicability and framebuffer churn require prompt and temporal evidence.
Camera temporal stability Camera validators, projection-update rules, and controls-update rules cover setup defects Primary-camera selection, intentional shake/cuts, and transform frequencies require runtime evidence.
Control-gain envelope None Useful macro range and smallest intended interaction scale depend on FOV, target size, playable range, and input trials.
Repeated-entity occupancy Instancing preference, instance-buffer update, and GPU-instanced-animation rules cover implementation quality Formations, stacks, transforms, visible overlap, and interpenetration require prompt scope and runtime instance matrices.
Resize and aspect three-require-renderer-size, three-require-camera-aspect-on-resize, three-effect-composer-require-size-on-resize, three-no-unconditional-renderer-resize-in-animation-loop, and r3f-no-manual-canvas-resize Runtime resize remains useful for CSS/layout and embedded-canvas behavior that source cannot prove.
Texture-load completion three-require-loader-error-handling, r3f-prefer-use-loader, r3f-no-null-loader-input, and KTX2 support checks Network completion, decoding, and visible use still require runtime observation.
Resource leak Renderer, root, controls, geometry, material, texture, render-target, animation-mixer, postprocessing, GPU-computation, and worker-loader cleanup rules Static rules cover locally owned resources; soak testing remains authoritative for dynamic ownership and GPU memory.
Wrap versus repeat three-texture-repeat-requires-wrapping, r3f-texture-repeat-requires-wrapping, and three-require-texture-update-after-wrapping-change Explicit, local wrapping contracts are fully static; visual tiling quality is not graded.
Normal-map sanity Normal, UV, color-space, and PBR-property rules cover provable prerequisites Tangent orientation, handedness, strength, and visible inversion require pixels or model semantics.
UV under map three-require-uv-for-texture-map and r3f-require-uv-for-texture-map Modern uv through uv3 channels are accepted; shaders and open geometry abstain.
Lights for PBR three-require-lighting-for-pbr and r3f-require-lighting-for-pbr Closed graphs only; dynamic/imported lighting is left to the runtime probe.

Plane 1C: report-only context

Rubric measurement Related static diagnostics Why it remains report-only
Frame budget, draw calls, and triangles Instancing and hot-loop allocation/compile/readback rules suggest structural improvements Absolute counts combine ambition, scene scale, hardware, and host contention.
Render calls per requestAnimationFrame Render-loop presence, render-target reset, and composer ordering rules validate correctness Shadows, minimaps, postprocessing, and simulation passes may legitimately render more than once.
Untextured surface share Basic-material ignored-property rules catch configuration mistakes Flat, procedural, and stylized surfaces may be intentional.
Shadow contrast ratio Shadow enablement, supported-light, map-size, and shadowed-point-light rules cover configuration Art direction and lighting conditions determine desirable contrast.
Depth range Perspective and orthographic camera validators catch invalid clipping planes A broad far / near ratio may be required by world scale.
Chromatic or tonal variance Texture color-space and exposure-related parameter checks cover technical misuse Monochrome and high-variance palettes can both be deliberate.
Spatial spawn entropy Instancing rules make repeated entities cheaper but do not grade arrangement Formations may be intentional; promote only through a prompt-conditioned runtime assertion.
aoMap or uv1 presence UV-under-map rules accept uv, uv1, uv2, and uv3 Three.js texture.channel selects the channel, so one named attribute is not universally required.
Output color space Texture semantics and three-effect-composer-output-pass-last cover common pipeline errors Linear renderer output followed by an sRGB output pass can be correct.

Plane 1D: prompt-conditioned checks

All checks in this tier remain prompt-profiled runtime assertions. Static rules must not infer the intended mapping, direction, amplitude, distribution, palette, or timing from implementation vocabulary alone.

Prompt-conditioned claim Static support Required evidence
Camera-relative W-angle and per-key travel directions Frame-delta rules catch frame-coupled movement Synthetic key trials and tracked camera/actor transforms.
Diagonal normalization None Compare cardinal and diagonal displacement under the declared control scheme.
Pointer versus keyboard expectations Pointer hot-path and mutation rules catch unsafe implementations Exercise both modalities according to the prompt profile.
Aim, reticle, selection, and hit-volume congruence Raycaster range rules catch invalid intervals Compare visible target, pointer/reticle, hit point, and response.
Texture coverage or surface-depth demands Texture/UV/material rules validate technical prerequisites Pixel, depth, or geometry evidence tied to the requested regions.
Behavior causality None A/B input intervention and response delta.
Locality claims None Trigger at distributed locations and track the effect over time.
Named decay and settling windows None Temporal variance or state measurements over the requested window.
Camera shake, recoil, follow, or stabilization amplitude Camera setup and frame-delta rules catch local defects Camera-transform trials calibrated to the task.
Encounter distribution, separation, cooldown, and progression Instancing/update rules cover implementation hazards Tracked spatial and temporal event samples.
Adaptive-system causality None Controlled player-performance intervention and directional response.
Relational color, contrast, and composition Color-space rules validate texture interpretation Region-to-region pixel comparisons derived from the brief.

Plane 2: craft review

Craft criterion Static contribution Why craft evidence remains necessary
Experience completeness Renderer, loader, animation, and lifecycle rules catch missing technical wiring Requested outcomes, reachability, depth, and end-to-end confirmation require exercising the experience.
Spatial and interaction integrity Raycaster, geometry, camera, and buffer rules catch local invalid contracts Collision, hit volumes, occlusion, tunneling, and impact agreement require runtime geometry and interaction evidence.
Encounter diversity and pacing Instancing and update rules cover repeated-entity implementation Enjoyment, escalation, separation, repeat control, and stage identity are prompt- and time-dependent.
Perceptual calibration and readability Material, texture, light, fog, camera, and opacity rules catch invalid values Subject separation, compositing, affordance clarity, and effect amplitude require representative pixels.
Animation and temporal craft Delta, mixer-update, GPU-animation, and buffer-update rules catch implementation defects Articulation, personality, continuity, secondary motion, and settling quality require video or interaction.
Camera and control feel Camera, projection, controls-update, and frame-delta rules catch setup defects Comfort, smoothing, collision response, recoil, gain, and precision require hands-on or temporal evidence.
Input conventions and tuning Pointer hot-path rules catch jank-prone state and allocation work Direction, discoverability, remapping, gain, and lifecycle require prompt-aware input trials.
Model fidelity Geometry attribute validators prevent malformed buffers Silhouette, proportion, defining parts, style, and viewing-distance detail are visual judgments.
Material treatment PBR ranges, physical properties, texture semantics, UVs, normals, opacity, lighting, and environment rules cover technical contracts Differentiation, variation, scale, attractiveness, and stylistic coherence remain visual judgments.
World composition Camera/fog ranges catch invalid numeric setup Hierarchy, depth, landmarks, negative space, and dressing require scene-level visual review.
Lighting and atmosphere Light validity, PBR lighting, metal environment, shadows, and exposure-related parameter rules catch technical defects Mood, form separation, palette, atmosphere, and reactive-light taste require pixels and prompt intent.
Scene hygiene Cleanup, z-adjacent depth configuration, resource, and motion implementation rules reduce common defects Floating, clipping, flicker, popping, overlap, grounding, and rare paths require full sweeps and soak.
HUD and UI craft General React accessibility and interaction rules still apply to DOM UI Required readouts, hierarchy, styling, feedback, pause, and recovery flows require prompt-aware review.
Frame stability Hot-loop allocation, compile, readback, resize, state, clone, instancing, and GPU-animation rules target high-confidence causes Representative and worst-case frame pacing must be measured on the running build.

Intentionally rejected universal lint rules

  • Transparency sorting, mipmap choice, z-fighting, exposure, motion continuity, containment, occupancy, idle churn, camera stability, and absolute performance depend on visibility, share, time, pixels, or prompt intent.
  • Texture repetition, untextured share, spawn entropy, output color space, scene complexity, and fixed-camera or static-scene choices are not defects without a task-specific contract.
  • Runtime and craft rows must be reported as not observed or not measurable when the required evidence is unavailable. Absence of a static diagnostic is never a passing craft score.