import sys, os src = os.path.join(os.path.dirname(__file__), '../../frontend/js/labs/opticsbench.js') with open(src, 'r', encoding='utf-8') as f: content = f.read() # ───────────────────────────────────────────────────────────────────────────── # PATCH: In MirrorSim.draw(), after _drawFanRays, add aberration fan for _useR mode # ───────────────────────────────────────────────────────────────────────────── OLD = (' this._drawFanRays(ctx, mx, ay, f, dPrime, hPrime, showRay, showFill);\n' ' /* spherical aberration overlay (Agent OB-A3) */\n' ' if (this._showSpherical && this.type !== \'flat\' && isFinite(f))\n' ' this._drawMirrorSphericalAberration(ctx, mx, ay, f);\n' ' this._drawMirror(ctx, mx, ay);') NEW = (' this._drawFanRays(ctx, mx, ay, f, dPrime, hPrime, showRay, showFill);\n' ' /* spherical aberration overlay (Agent OB-A3) */\n' ' if (this._showSpherical && this.type !== \'flat\' && isFinite(f))\n' ' this._drawMirrorSphericalAberration(ctx, mx, ay, f);\n' ' /* Feature 2: parabolic/spherical aberration fan */\n' ' if (this._useR && this.type !== \'flat\' && isFinite(f))\n' ' this._drawAberrationFan(ctx, mx, ay, f);\n' ' this._drawMirror(ctx, mx, ay);\n' ' /* Feature 2: R and f labels on mirror */\n' ' if (this._useR && this.type !== \'flat\' && isFinite(f)) {\n' ' ctx.save();\n' ' ctx.font = \'bold 11px Manrope, system-ui, sans-serif\';\n' ' ctx.fillStyle = \'rgba(6,214,224,0.9)\';\n' ' ctx.textAlign = \'right\'; ctx.textBaseline = \'bottom\';\n' ' ctx.fillText(\'R=\' + this._R.toFixed(0) + \' f=\' + f.toFixed(0), mx - 4, ay - 6);\n' ' ctx.restore();\n' ' }') if OLD not in content: print('ERROR: draw fan/mirror block not found'); sys.exit(1) content = content.replace(OLD, NEW, 1) with open(src, 'w', encoding='utf-8') as f: f.write(content) print('OK lines:', content.count('\n'))