Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/OpticsLabColors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,35 @@ const OpticsLabColors = {
// ── Carousel icons ──────────────────────────────────────────────────────────
iconRayStrokeProperty: profileColor("iconRayStroke", "#44ee66", "#22cc44"),
pointSourceFillProperty: profileColor("pointSourceFill", "#ff8844", "#ff8844"),

// ── Blocker fill ────────────────────────────────────────────────────────────
blockerFillProperty: profileColor("blockerFill", "rgba(30, 30, 30, 0.5)", "rgba(30, 30, 30, 0.5)"),

// ── Glass border (high-opacity stroke for half-plane boundary line) ─────────
glassBorderStrokeProperty: profileColor("glassBorderStroke", "rgba(60, 130, 210, 0.95)", "rgba(60, 130, 210, 0.95)"),

// ── Measuring tape ──────────────────────────────────────────────────────────
measuringTapeTextColorProperty: profileColor("measuringTapeTextColor", "white", "black"),
measuringTapeBackgroundColorProperty: profileColor(
"measuringTapeBackground",
"rgba(0,0,0,0.65)",
"rgba(255,255,255,0.65)",
),

// ── Wavelength thumb outline ────────────────────────────────────────────────
wavelengthThumbStrokeProperty: profileColor("wavelengthThumbStroke", "rgba(0,0,0,0.55)", "rgba(0,0,0,0.55)"),
};

opticsLab.register("OpticsLabColors", OpticsLabColors);

/**
* Returns the fill color for a half-plane glass element, scaling opacity
* with the refractive index so denser glass appears more opaque.
* n=1 → ~0.05 (barely visible), n=3 → ~0.40
*/
export function halfPlaneGlassFill(refIndex: number): string {
const opacity = 0.05 + ((refIndex - 1.0) / 2.0) * 0.35;
return `rgba(100, 160, 255, ${opacity.toFixed(3)})`;
}

export default OpticsLabColors;
10 changes: 7 additions & 3 deletions src/common/view/SimScreenView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,12 +237,16 @@ export class RayTracingCommonView extends ScreenView {
const protractorVisibleProperty = new BooleanProperty(false);

// Measuring tape – uses model coordinates (metres)
const measuringTapeUnitsProperty = new Property({ name: "m", multiplier: 1 });
const uiStringsForTape = StringManager.getInstance().getUIStrings();
const measuringTapeUnitsProperty = new Property({
name: uiStringsForTape.metersUnitStringProperty.value,
multiplier: 1,
});
const measuringTapeNode = new MeasuringTapeNode(measuringTapeUnitsProperty, {
modelViewTransform: modelViewTransform,
significantFigures: 2,
textColor: "white",
textBackgroundColor: "rgba(0,0,0,0.65)",
textColor: OpticsLabColors.measuringTapeTextColorProperty,
textBackgroundColor: OpticsLabColors.measuringTapeBackgroundColorProperty,
basePositionProperty: new Property(new Vector2(2, 1)),
tipPositionProperty: new Property(new Vector2(3, 1)),
baseDragStarted: () => {
Expand Down
3 changes: 2 additions & 1 deletion src/common/view/SymmetricWavelengthThumb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { Shape } from "scenerystack/kite";
import { Node, Path } from "scenerystack/scenery";
import { VisibleColor } from "scenerystack/scenery-phet";
import { Tandem } from "scenerystack/tandem";
import OpticsLabColors from "../../OpticsLabColors.js";
import {
SLIDER_THUMB_HEIGHT,
SLIDER_THUMB_WIDTH,
Expand Down Expand Up @@ -59,7 +60,7 @@ export class SymmetricWavelengthThumb extends Node {
super({ tandem: Tandem.OPT_OUT });

const body = new Path(buildBowtiePath(), {
stroke: "rgba(0,0,0,0.55)",
stroke: OpticsLabColors.wavelengthThumbStrokeProperty,
lineWidth: WAVELENGTH_THUMB_OUTLINE_WIDTH,
});

Expand Down
7 changes: 3 additions & 4 deletions src/common/view/blockers/CircleBlockerView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@
import { Shape } from "scenerystack/kite";
import type { ModelViewTransform2 } from "scenerystack/phetcommon";
import { type Circle, Path, type RichDragListener } from "scenerystack/scenery";
import OpticsLabColors from "../../../OpticsLabColors.js";
import { GLASS_STROKE_WIDTH } from "../../../OpticsLabConstants.js";
import opticsLab from "../../../OpticsLabNamespace.js";
import type { CircleBlocker } from "../../model/blockers/CircleBlocker.js";
import { BaseOpticalElementView } from "../BaseOpticalElementView.js";
import { attachEndpointDrag, attachTranslationDrag, createHandle } from "../ViewHelpers.js";

const BLOCKER_FILL = "rgba(30, 30, 30, 0.5)";
const BLOCKER_STROKE = "#555";
const BLOCKER_STROKE_WIDTH = GLASS_STROKE_WIDTH;

export class CircleBlockerView extends BaseOpticalElementView {
Expand All @@ -31,8 +30,8 @@ export class CircleBlockerView extends BaseOpticalElementView {
super();

this.circlePath = new Path(null, {
fill: BLOCKER_FILL,
stroke: BLOCKER_STROKE,
fill: OpticsLabColors.blockerFillProperty,
stroke: OpticsLabColors.blockerBackStrokeProperty,
lineWidth: BLOCKER_STROKE_WIDTH,
});
this.handleCenter = createHandle(blocker.p1, modelViewTransform);
Expand Down
15 changes: 8 additions & 7 deletions src/common/view/edit-controls/EditControlHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Dimension2, Range } from "scenerystack/dot";
import type { Node } from "scenerystack/scenery";
import { NumberControl, SpectrumSliderTrack, VisibleColor } from "scenerystack/scenery-phet";
import { Tandem } from "scenerystack/tandem";
import { StringManager } from "../../../i18n/StringManager.js";
import OpticsLabColors from "../../../OpticsLabColors.js";
import {
SEGMENT_LENGTH_MAX,
Expand Down Expand Up @@ -79,8 +80,8 @@ export function makeControl(
numberDisplayOptions: {
decimalPlaces: decimalPlacesForDelta(delta),
textOptions: { fill: OpticsLabColors.overlayValueFillProperty, font: LABEL_FONT },
backgroundFill: "rgba(0,0,0,0.35)",
backgroundStroke: "rgba(100,100,120,0.6)",
backgroundFill: OpticsLabColors.overlayInputBackgroundProperty,
backgroundStroke: OpticsLabColors.overlayInputBorderProperty,
},
sliderOptions: {
trackSize: SLIDER_TRACK_SIZE,
Expand Down Expand Up @@ -116,7 +117,7 @@ export function makeWavelengthControl(

const thumbNode = new SymmetricWavelengthThumb(prop);

return new NumberControl("λ", prop, range, {
return new NumberControl(StringManager.getInstance().getControlStrings().wavelengthStringProperty, prop, range, {
delta: WAVELENGTH_CONTROL_DELTA,
includeArrowButtons: true,
soundGenerator: null,
Expand All @@ -129,8 +130,8 @@ export function makeWavelengthControl(
decimalPlaces: 0,
valuePattern: "{0} nm",
textOptions: { fill: OpticsLabColors.overlayValueFillProperty, font: LABEL_FONT },
backgroundFill: "rgba(0,0,0,0.35)",
backgroundStroke: "rgba(100,100,120,0.6)",
backgroundFill: OpticsLabColors.overlayInputBackgroundProperty,
backgroundStroke: OpticsLabColors.overlayInputBorderProperty,
},
sliderOptions: {
trackNode,
Expand All @@ -154,8 +155,8 @@ export function numberControlOptions(delta: number, decimalPlaces: number) {
numberDisplayOptions: {
decimalPlaces,
textOptions: { fill: OpticsLabColors.overlayValueFillProperty, font: LABEL_FONT },
backgroundFill: "rgba(0,0,0,0.35)",
backgroundStroke: "rgba(100,100,120,0.6)",
backgroundFill: OpticsLabColors.overlayInputBackgroundProperty,
backgroundStroke: OpticsLabColors.overlayInputBorderProperty,
},
sliderOptions: {
trackSize: SLIDER_TRACK_SIZE,
Expand Down
9 changes: 3 additions & 6 deletions src/common/view/glass/CircleGlassView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,13 @@
import { Shape } from "scenerystack/kite";
import type { ModelViewTransform2 } from "scenerystack/phetcommon";
import { type Circle, Path, type RichDragListener } from "scenerystack/scenery";
import OpticsLabColors from "../../../OpticsLabColors.js";
import { GLASS_STROKE_WIDTH } from "../../../OpticsLabConstants.js";
import opticsLab from "../../../OpticsLabNamespace.js";
import type { CircleGlass } from "../../model/glass/CircleGlass.js";
import { BaseOpticalElementView } from "../BaseOpticalElementView.js";
import { attachEndpointDrag, attachTranslationDrag, createHandle } from "../ViewHelpers.js";

// ── Styling constants ─────────────────────────────────────────────────────────
const GLASS_FILL = "rgba(100, 180, 255, 0.22)";
const GLASS_STROKE = "rgba(60, 130, 210, 0.8)";

export class CircleGlassView extends BaseOpticalElementView {
public readonly bodyDragListener: RichDragListener;
private readonly circlePath: Path;
Expand All @@ -32,8 +29,8 @@ export class CircleGlassView extends BaseOpticalElementView {
super();

this.circlePath = new Path(null, {
fill: GLASS_FILL,
stroke: GLASS_STROKE,
fill: OpticsLabColors.glassFillProperty,
stroke: OpticsLabColors.glassStrokeProperty,
lineWidth: GLASS_STROKE_WIDTH,
});
this.handleCenter = createHandle(glass.p1, modelViewTransform);
Expand Down
20 changes: 4 additions & 16 deletions src/common/view/glass/HalfPlaneGlassView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import { Shape } from "scenerystack/kite";
import type { ModelViewTransform2 } from "scenerystack/phetcommon";
import { type Circle, Path, type RichDragListener } from "scenerystack/scenery";
import OpticsLabColors, { halfPlaneGlassFill } from "../../../OpticsLabColors.js";
import {
HALF_PLANE_BORDER_WIDTH,
HALF_PLANE_GLASS_DEPTH_PX,
Expand All @@ -28,19 +29,6 @@ import {
createLineBodyHitPath,
} from "../ViewHelpers.js";

// ── Styling constants ─────────────────────────────────────────────────────────
const BORDER_STROKE = "rgba(60, 130, 210, 0.95)";

/** Map refractive index to a fill opacity so denser glass looks more opaque. */
function glassOpacity(refIndex: number): number {
// n=1 → ~0.05 (barely visible), n=3 → ~0.40
return 0.05 + ((refIndex - 1.0) / 2.0) * 0.35;
}

function glassFill(refIndex: number): string {
return `rgba(100, 160, 255, ${glassOpacity(refIndex).toFixed(3)})`;
}

export class HalfPlaneGlassView extends BaseOpticalElementView {
public readonly bodyDragListener: RichDragListener;
private readonly glassPath: Path;
Expand All @@ -56,11 +44,11 @@ export class HalfPlaneGlassView extends BaseOpticalElementView {
super();

this.glassPath = new Path(null, {
fill: glassFill(glass.refIndex),
fill: halfPlaneGlassFill(glass.refIndex),
pickable: false,
});
this.borderPath = new Path(null, {
stroke: BORDER_STROKE,
stroke: OpticsLabColors.glassBorderStrokeProperty,
lineWidth: HALF_PLANE_BORDER_WIDTH,
lineCap: "butt",
pickable: false,
Expand Down Expand Up @@ -125,7 +113,7 @@ export class HalfPlaneGlassView extends BaseOpticalElementView {

public override rebuild(): void {
// Update fill opacity to reflect current refractive index
this.glassPath.fill = glassFill(this.glass.refIndex);
this.glassPath.fill = halfPlaneGlassFill(this.glass.refIndex);

const { p1, p2 } = this.glass;
const dx = p2.x - p1.x;
Expand Down
4 changes: 4 additions & 0 deletions src/i18n/StringManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export class StringManager {
measuringTapeStringProperty: ReadOnlyProperty<string>;
protractorStringProperty: ReadOnlyProperty<string>;
extendedRaysStringProperty: ReadOnlyProperty<string>;
metersUnitStringProperty: ReadOnlyProperty<string>;
} {
return {
gridStringProperty: this.stringProperties.ui.gridStringProperty,
Expand All @@ -69,10 +70,12 @@ export class StringManager {
measuringTapeStringProperty: this.stringProperties.ui.measuringTapeStringProperty,
protractorStringProperty: this.stringProperties.ui.protractorStringProperty,
extendedRaysStringProperty: this.stringProperties.ui.extendedRaysStringProperty,
metersUnitStringProperty: this.stringProperties.ui.metersUnitStringProperty,
};
}

public getControlStrings(): {
wavelengthStringProperty: ReadOnlyProperty<string>;
brightnessStringProperty: ReadOnlyProperty<string>;
emissionAngleStringProperty: ReadOnlyProperty<string>;
divergenceStringProperty: ReadOnlyProperty<string>;
Expand All @@ -94,6 +97,7 @@ export class StringManager {
} {
const ctrl = this.stringProperties.controls;
return {
wavelengthStringProperty: ctrl.wavelengthStringProperty,
brightnessStringProperty: ctrl.brightnessStringProperty,
emissionAngleStringProperty: ctrl.emissionAngleStringProperty,
divergenceStringProperty: ctrl.divergenceStringProperty,
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/strings_en.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@
"rayDensity": "Ray Density",
"measuringTape": "Measuring Tape",
"protractor": "Protractor",
"extendedRays": "Extended Rays"
"extendedRays": "Extended Rays",
"metersUnit": "m"
},
"controls": {
"brightness": "Brightness",
"wavelength": "λ",
"emissionAngle": "Emission Angle (°)",
"divergence": "Divergence (°)",
"height": "Height (m)",
Expand Down
4 changes: 3 additions & 1 deletion src/i18n/strings_fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,12 @@
"rayDensity": "Densité des rayons",
"measuringTape": "Ruban à mesurer",
"protractor": "Rapporteur",
"extendedRays": "Rayons prolongés"
"extendedRays": "Rayons prolongés",
"metersUnit": "m"
},
"controls": {
"brightness": "Luminosité",
"wavelength": "λ",
"emissionAngle": "Angle d'émission (°)",
"divergence": "Divergence (°)",
"height": "Hauteur (m)",
Expand Down
Loading