This is by far the best explanation for quaternions in 3d graphics I have found! The justification to abandon Euler angles is also straight forward, no useless talk about gimble lock. Thank you!
By far the best explanation of quaternions Spent a month looking and learning about it on different TH-cam videos, even the 3blue1brown. No history lessons, no gimble lock. straight to the point. Keep up the SIMPLE and BEST video.
I used quaternions for a car wheel. I could separate the expected roll angle for that frame and the steer angle, Then combine them as a single rotation. I would “zero” the rotation by finding its inverse, make the steering angle change, then roll change, then reapply the inverse of the inverse.
Well, you can check out the video about the TVC model rocket. The attitude estimation/correction system was built with quaternions and formulas I have covered. And it's probably can be considered "robotics" :) Same goes for any drone / UAV or for example describing orientation of the robotic arm end effector.
5:07 I don't understand how _theta_ and _-theta_ are the same angle ( or _q_ same as _-q_ ). That doesn't make sense. *Edit:* Oh, because V and -V point in the opposite directions. Okay. So rotating in the opposite direction when the axis vector is inverted, actually results in the same rotation. Now I think I get it.
Hi! Great video, very well explained! Currently on a quest to try and use ODE-solvers to solve 3D rigid body problems, and for that the equation 11:17 is exactly what I'm looking for. Do you have any recommended further reading? I'm curious to see where it comes from to see if I've missed anything in my implementation! All the best!
Check out this answer stackoverflow.com/a/24201879/3950982 Basically to make a proper step we calculate a small "delta" rotation and rotate the quaternion with that. But if the "delta" is very small we can go with first-order approximation to make it slightly less accurate, but get rid of computing trigonometric functions on each step, which makes it much faster (especially useful if we run it on MCU and struggle with resources). But you can go with more precise formula if you want to.
Sorry. I forgot to answer :( I would start with understanding the basic physics of rocket flight. Like rocket stability (for regular aerodynamically stable rockets). Also how rockets are usually constructed, and what materials are commonly used. Then maybe try to build/launch a simple rocket! Also, check out r/rocketry subReddit -- there is a lot of information on that topic and you also can ask your questions and maybe get some help!
Hello do you know how to use it for finding joint angle What is the operation for one quaternion for the lower arm and for the upper arm ? And how to find flexion extension or pronation supination ?
For the first order approximation how small would the step size have to be? I've been looking into this and was wondering if someone could give an answer. I assume there would be some relationship with delta time and the first order taylor series for the integral approximation. So maybe substepping 60 frames would give enough precision?
Yes, basically this formula uses only first order. What is important is that our variable for taylor series is not dt, but dt*omega, where omega is angular velocity. Ofc we have 3 angular velocities and we use q_omega in the formula for that, but we can represent q_omega as a omega * q_n , where q_n is normalized quaternion. So, if we do that we have a small-factor of omega*dt for our first-order approximation. I did not do the exact math, but I made a simple example where we know exact result and compared to the approximation. So in my test if omega*dt < 0.01 then the error is less than 10^-5 which is pretty good imho. Especially given the fact that if Float data type is used (which is typical for graphics AFAIK) it limits the precision at ~10^-7 Long story short, its not only about dt, but about dt*omega where omega is a typical angular velocity measured in rad/s. Keep dt*omega < 0.01 and that will be fine (if you do re-normalization after each step, that REALLY helps to minimize the error) Hope I did not make a stupid mistake somewhere...
Also if you don't care about the precision that much you can go with dt*omega< 0.1 which gives 10^-3 error which is not that bad too. Just stay well away from dt*omega ~ 1. That the point where things starts to get ugly really fast.
There are a lot of words used in these videos that are only known by mathematically literate people. So I feel like I should understand and want to, but I don't. At 2:06 two equations appear and I am told they are "scalar vectors". The information content for me at that moment is zero. What would I need to study for this to have any meaning to me? Do I have to know these things to use quaternions in Blender?
The goal of the video was to give people a full practical knowledge of how to deal with rotations using quaternions. There is enough information to write a 3d engine from scratch. And at that level I don't think it's possible to avoid all the math. If you want to just use quaternions in Blender that's probably way too much than you need. You don't need to know how multiplication works and you probably don't even care about quaternions multiplication at all. I think you don't care about most of these formulas, just try to understand the part 3:30 - 4:50 and understad what is the meaning of 4 values that define each quaternion. Scalar is "just a number". Vector is a pack of 3 numbers that represents some direction. Sorry that it was not very helpful for you. Maybe there is a good video about quaternions specifically used with Blender. I checked one video like this back then, but unfortunately the person's understanding/explanation was completely wrong.
@@Positive_Altitude Thanks for answering my query. I have since been wading through some more vids on quaternions. I found it very helpful to watch one about Hamilton and the history of them. I did do well in math at school but that was a very very long time ago. Now I just have to work out how to use them in Blender instead of Euler.
@11:15 what does 'tmp' stand for? I don't understand the errors that arise without normalization (the rocket getting bigger and bigger).... what causes that to happen and why does that normalization equation fix it? Is this similar to 'renormalization' in physics?
'tmp' stands for 'temporary'. This formula is an approximation and it makes the norm to slightly increase with each step. I mentioned that rotation quaternions should be normalized, but actually, you can use non-normalized quaternions with the same math to transform coordinates. But in this case, you will not only rotate the space, but also you will scale it by the factor equal to the quaternion's norm. That's why if we let the quaternion's norm increase, the object gets bigger. To explain why exactly this happens I will give you a very similar example: Imagine that we are trying to draw a circle, but we can draw only short straight lines. And we use an algorithm: 1) Draw a line from the current point to the center (a radius) 2) Draw a short line perpendicular to this radius 3) The end of this short line is the next point of the circle 4) Go to 1) If we do this with very short lines this kinda works, but actually, every new point will be slightly further away from the center, and the radius will increase with each step. And if we keep doing it we will draw a spiral instead of a circle. If our steps are small it will spiral out slowly. With bigger steps, the problem gets worse. But we can fix that. After each step, we can make a little step toward the center that will make the current radius equal to the desired radius. That is exactly what normalization does. This example is VERY close to what happens with quaternions and this formula. In the case of quaternions, it's just a trajectory (not really a circle) in 4-dimensional space which I personally struggle to imagine. No, this is unrelated to renormalization. This is just us fixing an error caused by using approximation.
@@Positive_Altitude Thank you, I think I'm getting it. The normalization sort of re-orients or self-orients the origin point of the gyroscope, the center of all the angular velocities right? That's why when you turned normalization off, it sort of dilated in-and-out/breathed like a growing spiral?
@@Positive_Altitude Do you need to renormalize all quaternions or only gyroscopic ones with angular velocity? Does angular velocity add more requirements to make it work?
@@erawanpencil I would not say that it "re-orients" it just scales it. Norm is literally a length and all proper rotation quaternions should have the length = 1. We just fix the error caused by this formula that makes quaternion slightly longer than it is supposed to be. Usually, when we just combine rotations there is no need to normalize quaternions. Because if we have two normalized quaternions, their product will be a normalized quaternion too. But also there is no harm in normalization. If you normalize a quaternion that is already normalized it will not change it. The angular velocity formula is just kinda weird. Mathematically it is obtained with the assumption that time step dt is "infinitely small". But there is no such thing as an infinitely small number when we do 3D graphics or iterative simulations. So in real life, this formula produces a small error both in direction (orientation) and length (norm). To deal with that we need 1) use as small dt as we can, to minimize the error in orientation 2) normalize quaternion to always keep norm = 1 as it is supposed to be
This is because we use ZYZ Euler scheme in this example. "ZYZ scheme" means that we make a sequence of 3 rotations around local axes 1) by alpha around Z; 2) by beta around Y 3) by gamma around Z. You might be thinking "why do we rotate twice around Z?" It works because each rotation is done in the local reference frame whose orientation is also changed with each rotation. So the first Z rotation is not the same as the last one, because when we do the last rotation, the reference frame is re-oriented by the first and second rotations. But because the first and third rotations are both rotate around local Z, the formulas are the same. To calculate q_gamma for example, I am using the formula explained at 4:40. In this case vector V = (0, 0, 1) because it is a normalized vector aligned with Z axis and theta = gamma. So just using this formula you will get all formulas shown at 9:37 Hope that helped :)
@@Positive_Altitude q and -q indeed represent the same rotation. However, they do not represent rotations around opposite axes and opposite angles. If you plug -θ and -n into the quaternion formula cos(θ/2) + sin(θ/2) * n, you will find that it is equal to the original quaternion q and not -q: cos(-θ/2) + sin(-θ/2) * (-n) = cos(θ/2) + (-sin(θ/2)) * (-n) = cos(θ/2) + sin(θ/2) * n = q. Instead, they represent the rotation around the same axes but offset by an odd multiple of 2π. So for example, if you rotate 2π or -2π further, you get -q, and if you rotate 4π or -4π further, you get q again. This is because of the half angle in the quaternion formula: cos(θ/2) + sin(θ/2) * n. Imagine you gradually increase the angle θ, once it reaches 2π you are on the opposite side of the hypersphere (cos(2π/2) = cos(π)) and then increasing it further until 4π gets you back to your starting point (cos(4π/2) = cos(2π) = cos(0)). Formally, negating the quaternion q yields (where k is some whole number): -q = -cos(θ/2) - sin(θ/2) * n = cos(θ/2 + (2k + 1) * π) + sin(θ/2 + (2k + 1) * π) * n = cos((θ + (2k + 1) * 2π) / 2) + sin((θ + (2k + 1) * 2π) / 2) * n = cos(θ'/2) + sin(θ'/2) * n where θ' = (θ + (2k + 1) * 2π), so we can see that -q represents the same rotation as q but rotated by another odd multiple of 2π.
Euler angle triples are overcompressing (squeezing) the geometric information into just 3 numbers. Bad for bug-free algorithms. Quaternions spread the info across 4 real numbers, solving that problem. As far as geometric intuition, V and theta are easy to visualize and sketch (good). But the [ cos(theta/2), sin(theta/2)*V ] seems to depart from two quantities we can visualize. Why? Representing 3D rotation using 3x3 Rotator R = [ newXaxis, newYaxis, newZaxis ] is highly geometric, visualizable for the meaning of the numerics. The algorithms are very simple to program. They offer 1:1 representation (rotation proximate to one another have proximate numerics). They are easier to teach. Why not teach this way of representing and computing 3D rotations? Why not even mention it?
Thank you for the critique. Generally I agree with your arguments. Rotation matrix 100% worth to mention, but I just was too focused on quaternions. I also agree that it is easier to learn. But I still think that matrices will never substitute quaternions. If we check any performance optimized solution for 3D graphics or robotics it will be based on quaternions, because quatenions provides best performance in real application. - quaternions require less computations to combine rotations (for any nested reference frames, like 3D character limbs, or robotic arm joints) - quaternions are cheaper to normalize - quaternions offers very easy and fast interpolation (good for animations) So at the end of the day, anyone who seriously works with software applications for 3D rotations will need to learn quaternions. So the goal of this video was to help someone to learn how to deal with quaternians for such applications.
It's just variables, like x y z etc. A placeholder for some value. They don't have a special meaning I could say x, y, z instead. But traditionally angles are denoted with Greek letters like α, β, γ, θ, φ
This is by far the best explanation for quaternions in 3d graphics I have found! The justification to abandon Euler angles is also straight forward, no useless talk about gimble lock. Thank you!
did you found anything else?
@@have_fun1107 What do you mean? Other videos on the topic?
@@drobin9040 yes or anything else that may help building intuition?
Have a look at Freya Holmer’s content, she’s awesome at explaining math with visuals.
By far the best explanation of quaternions Spent a month looking and learning about it on different TH-cam videos, even the 3blue1brown. No history lessons, no gimble lock. straight to the point. Keep up the SIMPLE and BEST video.
Thank you :)
You are the very first to give a clear explanation of why computer graphics tech prefer Quaternions. Thanks. This I finally understand.
The best explanation of quaternions I have seen so far. It really clicked for me. Thank you for the work!
Thank you! I am happy to hear that it helped someone 😊
This is great! Very well explained and beautifully visualized
This might be enough for a first toehold in the subject!
you helped me understand what it is in first minute, after I couldn't really grasp it after watching 3blue1brown video of 30min. tyvm
this is very much over my head in understanding but its awesome to hear you talk about quaternions!
Amazing, finally a video easy to understand about quaternions
I used quaternions for a car wheel. I could separate the expected roll angle for that frame and the steer angle, Then combine them as a single rotation. I would “zero” the rotation by finding its inverse, make the steering angle change, then roll change, then reapply the inverse of the inverse.
Ohh I was thinking I will never understand this. Now...I'm much better. Thank you
Nice video. Do you can make some example application in robotic? Thanks 🙏🏽😊
Well, you can check out the video about the TVC model rocket. The attitude estimation/correction system was built with quaternions and formulas I have covered. And it's probably can be considered "robotics" :) Same goes for any drone / UAV or for example describing orientation of the robotic arm end effector.
I need more! All others videos are copypaste of the sames videos and "papers", no one teach how to use them.
I need it for physics.
'Have a nice day and please don't use Euler angles.' LOL. Awesome. 👍
5:07 I don't understand how _theta_ and _-theta_ are the same angle ( or _q_ same as _-q_ ). That doesn't make sense.
*Edit:* Oh, because V and -V point in the opposite directions. Okay. So rotating in the opposite direction when the axis vector is inverted, actually results in the same rotation. Now I think I get it.
Well explained!
Hi! Great video, very well explained! Currently on a quest to try and use ODE-solvers to solve 3D rigid body problems, and for that the equation 11:17 is exactly what I'm looking for. Do you have any recommended further reading? I'm curious to see where it comes from to see if I've missed anything in my implementation!
All the best!
Check out this answer stackoverflow.com/a/24201879/3950982
Basically to make a proper step we calculate a small "delta" rotation and rotate the quaternion with that. But if the "delta" is very small we can go with first-order approximation to make it slightly less accurate, but get rid of computing trigonometric functions on each step, which makes it much faster (especially useful if we run it on MCU and struggle with resources). But you can go with more precise formula if you want to.
@@Positive_Altitude Thank you very much!
You are welcome :)
Hey Amazing content. Wondering What path do you recommend to a newbie like me trying to getting into this
Thanks
Hey! What exactly are you interested in?
@@Positive_Altitude Rockets
Sorry. I forgot to answer :( I would start with understanding the basic physics of rocket flight. Like rocket stability (for regular aerodynamically stable rockets). Also how rockets are usually constructed, and what materials are commonly used. Then maybe try to build/launch a simple rocket! Also, check out r/rocketry subReddit -- there is a lot of information on that topic and you also can ask your questions and maybe get some help!
@@Positive_Altitude Thank you so much will keep an eye on your content
Hello do you know how to use it for finding joint angle
What is the operation for one quaternion for the lower arm and for the upper arm ?
And how to find flexion extension or pronation supination ?
Hey, I looked up these terms. It does not seem to be related to quaternions directly. So I don't think I can help with that.
Like the bobby broccoli animation style
wow, well done!
For the first order approximation how small would the step size have to be? I've been looking into this and was wondering if someone could give an answer. I assume there would be some relationship with delta time and the first order taylor series for the integral approximation. So maybe substepping 60 frames would give enough precision?
Yes, basically this formula uses only first order. What is important is that our variable for taylor series is not dt, but dt*omega, where omega is angular velocity. Ofc we have 3 angular velocities and we use q_omega in the formula for that, but we can represent q_omega as a omega * q_n , where q_n is normalized quaternion. So, if we do that we have a small-factor of omega*dt for our first-order approximation. I did not do the exact math, but I made a simple example where we know exact result and compared to the approximation.
So in my test if omega*dt < 0.01 then the error is less than 10^-5 which is pretty good imho. Especially given the fact that if Float data type is used (which is typical for graphics AFAIK) it limits the precision at ~10^-7
Long story short, its not only about dt, but about dt*omega where omega is a typical angular velocity measured in rad/s.
Keep dt*omega < 0.01 and that will be fine (if you do re-normalization after each step, that REALLY helps to minimize the error)
Hope I did not make a stupid mistake somewhere...
Also if you don't care about the precision that much you can go with dt*omega< 0.1 which gives 10^-3 error which is not that bad too. Just stay well away from dt*omega ~ 1. That the point where things starts to get ugly really fast.
There are a lot of words used in these videos that are only known by mathematically literate people. So I feel like I should understand and want to, but I don't. At 2:06 two equations appear and I am told they are "scalar vectors". The information content for me at that moment is zero. What would I need to study for this to have any meaning to me? Do I have to know these things to use quaternions in Blender?
The goal of the video was to give people a full practical knowledge of how to deal with rotations using quaternions. There is enough information to write a 3d engine from scratch. And at that level I don't think it's possible to avoid all the math. If you want to just use quaternions in Blender that's probably way too much than you need. You don't need to know how multiplication works and you probably don't even care about quaternions multiplication at all. I think you don't care about most of these formulas, just try to understand the part 3:30 - 4:50 and understad what is the meaning of 4 values that define each quaternion.
Scalar is "just a number". Vector is a pack of 3 numbers that represents some direction.
Sorry that it was not very helpful for you. Maybe there is a good video about quaternions specifically used with Blender. I checked one video like this back then, but unfortunately the person's understanding/explanation was completely wrong.
@@Positive_Altitude Thanks for answering my query. I have since been wading through some more vids on quaternions. I found it very helpful to watch one about Hamilton and the history of them. I did do well in math at school but that was a very very long time ago. Now I just have to work out how to use them in Blender instead of Euler.
This was helpful, I appreciate it.
@11:15 what does 'tmp' stand for? I don't understand the errors that arise without normalization (the rocket getting bigger and bigger).... what causes that to happen and why does that normalization equation fix it? Is this similar to 'renormalization' in physics?
'tmp' stands for 'temporary'. This formula is an approximation and it makes the norm to slightly increase with each step. I mentioned that rotation quaternions should be normalized, but actually, you can use non-normalized quaternions with the same math to transform coordinates. But in this case, you will not only rotate the space, but also you will scale it by the factor equal to the quaternion's norm. That's why if we let the quaternion's norm increase, the object gets bigger.
To explain why exactly this happens I will give you a very similar example:
Imagine that we are trying to draw a circle, but we can draw only short straight lines. And we use an algorithm:
1) Draw a line from the current point to the center (a radius)
2) Draw a short line perpendicular to this radius
3) The end of this short line is the next point of the circle
4) Go to 1)
If we do this with very short lines this kinda works, but actually, every new point will be slightly further away from the center, and the radius will increase with each step. And if we keep doing it we will draw a spiral instead of a circle. If our steps are small it will spiral out slowly. With bigger steps, the problem gets worse.
But we can fix that. After each step, we can make a little step toward the center that will make the current radius equal to the desired radius. That is exactly what normalization does.
This example is VERY close to what happens with quaternions and this formula. In the case of quaternions, it's just a trajectory (not really a circle) in 4-dimensional space which I personally struggle to imagine.
No, this is unrelated to renormalization. This is just us fixing an error caused by using approximation.
@@Positive_Altitude Thank you, I think I'm getting it. The normalization sort of re-orients or self-orients the origin point of the gyroscope, the center of all the angular velocities right? That's why when you turned normalization off, it sort of dilated in-and-out/breathed like a growing spiral?
@@Positive_Altitude Do you need to renormalize all quaternions or only gyroscopic ones with angular velocity? Does angular velocity add more requirements to make it work?
@@erawanpencil I would not say that it "re-orients" it just scales it. Norm is literally a length and all proper rotation quaternions should have the length = 1. We just fix the error caused by this formula that makes quaternion slightly longer than it is supposed to be.
Usually, when we just combine rotations there is no need to normalize quaternions. Because if we have two normalized quaternions, their product will be a normalized quaternion too. But also there is no harm in normalization. If you normalize a quaternion that is already normalized it will not change it.
The angular velocity formula is just kinda weird. Mathematically it is obtained with the assumption that time step dt is "infinitely small". But there is no such thing as an infinitely small number when we do 3D graphics or iterative simulations. So in real life, this formula produces a small error both in direction (orientation) and length (norm). To deal with that we need 1) use as small dt as we can, to minimize the error in orientation 2) normalize quaternion to always keep norm = 1 as it is supposed to be
9:37 Why is the first one (alpha) same formula as last one (gamma)?
This is because we use ZYZ Euler scheme in this example. "ZYZ scheme" means that we make a sequence of 3 rotations around local axes 1) by alpha around Z; 2) by beta around Y 3) by gamma around Z.
You might be thinking "why do we rotate twice around Z?" It works because each rotation is done in the local reference frame whose orientation is also changed with each rotation. So the first Z rotation is not the same as the last one, because when we do the last rotation, the reference frame is re-oriented by the first and second rotations.
But because the first and third rotations are both rotate around local Z, the formulas are the same. To calculate q_gamma for example, I am using the formula explained at 4:40. In this case vector V = (0, 0, 1) because it is a normalized vector aligned with Z axis and theta = gamma. So just using this formula you will get all formulas shown at 9:37
Hope that helped :)
I have no idea how to use quaternions for Maya...
Видео ис зе бест ин кватернион эриа :)
Достойно!
Thanks for this video. I like the troll face lol
:)
um, actually... rotating minus theta around minus n yields the same quaternion q and not -q
Well, there is no difference between q and -q, both represent exactly the same rotation, right?
@@Positive_Altitude q and -q indeed represent the same rotation. However, they do not represent rotations around opposite axes and opposite angles. If you plug -θ and -n into the quaternion formula cos(θ/2) + sin(θ/2) * n, you will find that it is equal to the original quaternion q and not -q:
cos(-θ/2) + sin(-θ/2) * (-n) = cos(θ/2) + (-sin(θ/2)) * (-n) = cos(θ/2) + sin(θ/2) * n = q.
Instead, they represent the rotation around the same axes but offset by an odd multiple of 2π. So for example, if you rotate 2π or -2π further, you get -q, and if you rotate 4π or -4π further, you get q again. This is because of the half angle in the quaternion formula: cos(θ/2) + sin(θ/2) * n. Imagine you gradually increase the angle θ, once it reaches 2π you are on the opposite side of the hypersphere (cos(2π/2) = cos(π)) and then increasing it further until 4π gets you back to your starting point (cos(4π/2) = cos(2π) = cos(0)).
Formally, negating the quaternion q yields (where k is some whole number):
-q = -cos(θ/2) - sin(θ/2) * n = cos(θ/2 + (2k + 1) * π) + sin(θ/2 + (2k + 1) * π) * n = cos((θ + (2k + 1) * 2π) / 2) + sin((θ + (2k + 1) * 2π) / 2) * n = cos(θ'/2) + sin(θ'/2) * n
where θ' = (θ + (2k + 1) * 2π), so we can see that -q represents the same rotation as q but rotated by another odd multiple of 2π.
@@adrianklug4810 hmm... yeah, I agree. Good point and nice catch. Thanks for taking the time to write this 👍 I will try to fix it somehow.
❤
Хард рашен акцент!
Come on, it's not THAT bad ;)
@@Positive_Altitude шутка, все ок, все понятно)
Dimka krasava
fax
👽 not of this world.
Euler angle triples are overcompressing (squeezing) the geometric information into just 3 numbers. Bad for bug-free algorithms. Quaternions spread the info across 4 real numbers, solving that problem. As far as geometric intuition, V and theta are easy to visualize and sketch (good). But the [ cos(theta/2), sin(theta/2)*V ] seems to depart from two quantities we can visualize. Why?
Representing 3D rotation using 3x3 Rotator R = [ newXaxis, newYaxis, newZaxis ] is highly geometric, visualizable for the meaning of the numerics. The algorithms are very simple to program. They offer 1:1 representation (rotation proximate to one another have proximate numerics). They are easier to teach. Why not teach this way of representing and computing 3D rotations? Why not even mention it?
Thank you for the critique. Generally I agree with your arguments. Rotation matrix 100% worth to mention, but I just was too focused on quaternions. I also agree that it is easier to learn. But I still think that matrices will never substitute quaternions. If we check any performance optimized solution for 3D graphics or robotics it will be based on quaternions, because quatenions provides best performance in real application.
- quaternions require less computations to combine rotations (for any nested reference frames, like 3D character limbs, or robotic arm joints)
- quaternions are cheaper to normalize
- quaternions offers very easy and fast interpolation (good for animations)
So at the end of the day, anyone who seriously works with software applications for 3D rotations will need to learn quaternions.
So the goal of this video was to help someone to learn how to deal with quaternians for such applications.
The moment you start using greek letters, the non mathematical person is lost. What do they mean?
It's just variables, like x y z etc. A placeholder for some value. They don't have a special meaning I could say x, y, z instead. But traditionally angles are denoted with Greek letters like α, β, γ, θ, φ
Научись произносить звуки "th". Это значительно улучшит речь.
I dont understand any of this and im usually quite good with both technical and math stuff. 😞
Sorry to hear that :( Is there anything I can help with?
Dafuq is React doing there 😂
lol
jesus christ who came up with this shit 😭