Skip to content

LogoAtom

Animation

Studying the details and the parameters using GeoGebra

Inspiration and Origin

LogoAtom is an animation based on the classic atomic logo, with electrons orbiting around the nucleus. The inspiration for this animation came from the work of Keishiro Ueki (keishiroueki.net), who shared a similar idea on social media.

In an initial study, I explored the motion in GeoGebra, analyzing the trajectories and orbital behavior of the electrons. Later, I transferred these principles to p5.js, where I developed the final animation.

Animation Dynamics

The animation follows a cyclical structure in which:

  • A central nucleus remains static.
  • Electrons orbit around it, following trajectories that combine circles and rotating triangles.
  • Variations in speed and rotation angles create a dynamic effect.
  • Orbit intersections generate a woven visual effect.
  • The system loops continuously to reinforce the sensation of constant motion.

Technical Implementation

The animation in p5.js is based on geometry concepts and coordinate transformations:

  • Trajectory construction: Trigonometric equations define the orbits and electron displacements.
  • Motion vectors: p5.Vector is used to calculate dynamic positions.
  • Position history: Electron trajectories are stored in arrays to visualize motion traces.
  • Color interpolation: Variations in opacity and electron colors simulate a persistence effect.

Classroom Application

I have used this animation in class to teach students about:

  • Graphic programming concepts in p5.js.
  • Using GeoGebra to analyze movements before coding them.
  • The relationship between mathematical models and their computational implementation.
  • Using vectors in animations to efficiently calculate dynamic positions.

This experience has served as an excellent example of how programming can be used to visualize and understand scientific and mathematical phenomena interactively.

Code (p5.js)

Text Only
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
var radio=150;
var radio2=210;
var diff=40;
var speed=2;
var rojo=100, verde=10, azul=30;
var modAng=0;

var n=3;
var ncircles=1;
var posX=0;
var posY=0;
var angle=0;

var rojosX=new Array(360*speed);
var rojosY=new Array(360*speed);

for(var t=0; t<=360*speed;t++){
rojosX[t]=new Array(ncircles);
rojosY[t]=new Array(ncircles);
for(var j=0; j<=ncircles;j++){
    rojosX[t][j]=new Array(n);
    rojosY[t][j]=new Array(n);
}

}



var t1X=new Array(ncircles);
var t1Y=new Array(ncircles);
var t2X=new Array(ncircles);
var t2Y=new Array(ncircles);



for(var j=0; j<=ncircles;j++){
t1X[j]=new Array(n);
t1Y[j]=new Array(n);
t2X[j]=new Array(n);
t2Y[j]=new Array(n);

}
let v1;
let v2;
let v3;
var sentido=1;




function setup(){
    createCanvas(1800, 1000);
    background(255);
    rojo=0;
    verde=250;
    azul=130;
    angleMode(DEGREES);
}


function draw(){

background(256);

    if(angle>360) modAng=angle%360;
    else modAng=angle;

    angle=angle+speed;
    textSize(32);
    text(angle, 10, 30);
    text(modAng, 10, 70);

    fill(0);
    stroke(0);
    strokeWeight(2);
    posX=width/2;
    posY=height/2;
    ellipse(posX,posY, 30, 30);

    for(var j=0; j<=ncircles;j++){
    for(var i=0; i<=n;i++){
        //triángulo 1
        t1X[j][i]=posX+(radio+diff*j)*cos(angle+i*360/n);
        t1Y[j][i]=posY+(radio+diff*j)*sin(angle+i*360/n);
        //triángulo 2
        t2X[j][i]=posX+(radio2+diff*j)*cos(i*360/n-angle);
        t2Y[j][i]=posY+(radio2+diff*j)*sin(i*360/n-angle);

    }
}
for(var j=0; j<ncircles;j++){
    for(var i=0; i<n;i++){
    v3=createVector(posX, posY);
    v1 = createVector(t2X[j][i]-posX, t2Y[j][i]-posY);
    v2 = createVector(t1X[j][i+1]-posX, t1Y[j][i+1]-posY);
    v3.add(v1);
    v3.add(v2);

    //ellipse(v3.x, v3.y, 10, 10);

    //rojosX
    rojosX[modAng][j][i]=v3.x;
    rojosY[modAng][j][i]=v3.y;

    fill(60);
    strokeWeight(1);
    line(t2X[j][i],t2Y[j][i],v3.x,v3.y);
    line(t1X[j][i],t1Y[j][i],v3.x,v3.y);

    fill(0);
    strokeWeight(3.5);
    //triángulo 1
    ellipse(t1X[j][i],t1Y[j][i], 10, 10);
    line(t1X[j][i],t1Y[j][i], t1X[j][i+1],t1Y[j][i+1]);
    strokeWeight(2.7);
    //triángulo 2
    ellipse(t2X[j][i],t2Y[j][i], 10, 10);
    //line(t2X[j][i],t2Y[j][i], t2X[j][i+1],t2Y[j][i+1]);
    //líneas del centro a cada punto
    line(posX,posY, t1X[j][i],t1Y[j][i]);
    //líneas del centro a cada punto
    line(posX,posY, t2X[j][i],t2Y[j][i]);
    //lineas entre triángulos
    line(t2X[j][i],t2Y[j][i], t1X[j][i+1],t1Y[j][i+1]);
    line(t2X[j][i+1],t2Y[j][i+1], t1X[j][i],t1Y[j][i]);
    }

}
var alcance=300;
var prop;
//dibujar los rojos

if(modAng>alcance){
for(var t=0; t<=modAng;t=t+speed){
    for(var j=0; j<ncircles;j++){
    for(var i=0; i<n;i++){
        strokeWeight(0);
        prop=(1-(modAng-t)/alcance)*255;
        fill(255, 0,0,prop);
        if(t==modAng) strokeWeight(1);
        if(modAng-t<alcance) ellipse(rojosX[t][j][i], rojosY[t][j][i], 10, 10);
        strokeWeight(0);
    }
    }
}
}else{

for(var t=360-(alcance-modAng); t<=360;t=t+speed){
    for(var j=0; j<ncircles;j++){
    for(var i=0; i<n;i++){
        strokeWeight(0);
        prop=(1-(modAng+360-t)/alcance)*255;
        fill(255, 0,0,prop);
        if(modAng-t<alcance) ellipse(rojosX[t][j][i], rojosY[t][j][i], 10, 10);

    }
    }
}

for(var t=0; t<=modAng;t=t+speed){
    for(var j=0; j<ncircles;j++){
    for(var i=0; i<n;i++){
        strokeWeight(0);
        //prop=(1-(modAng-t)/alcance)*255;
            prop=(1-(modAng-t)/alcance)*255;
        fill(255, 0,0,prop);
        if(t==modAng) strokeWeight(1);

        if(modAng-t<alcance) ellipse(rojosX[t][j][i], rojosY[t][j][i], 10, 10);
        strokeWeight(0);
    }
    }
}


}

}