The following circuit uses closed loop control to linearize the LED brightness. The feedback element is an LDR that measures the light intensity of the LED.
LED1 and LDR1 are assembled using shrinking tube so that the LED shines onto the LDR.
The circuit uses an LM324 quad OPAMP. U1A and U1B form a triangular waveform oscillator to generate the positive and negative slope to dim/fade the LED.
U1C is a voltage controlled current source that converts the triangular voltage into a triangular current. The LDR voltage is fed back to this voltage controlled current source, so the LDR voltage is subtracted from the triangular voltage.
R17 and D3 are added, so the maximum LED intensity can be adjusted. D3 clamps the OPAMP output to the voltage set by R17.
The picture below shows how to assemble an RGB LED (left side) and an LDR (right side) using shrinking tube:
The oscilloscope picture below shows the voltage at the output of OPAMP U1B:
The oscilloscope picture below shows the voltage over R12 (= 22E) which represents the current through the 3 LEDs (2 LEDs for the skull eyes and 1 LED that is assembled together with the LDR):
I used this circuit for LED's that I implanted in a 3D-printed skull.
The pictures below show the PCB and 3D printed skull: