@johnnygadget already described it, but the best way I can think of doing it is by moving the part half the difference in size:
local newSize = Vector3.new(1, 1, 2)
local deltaSize = newSize - part.Size --> (0, 0, 1)
part.Size = newSize
-- moving the part forward half the distance:
part.Position = part.CFrame * deltaSize/2
-- moving the part back half the distance:
part.Position = part.CFrame * -deltaSize/2
The best way to understand why this works is with a graph.
Say you have a square made up of the lines x = 0, x = 1, y = 0, y = 1
:
You can find the center by taking an average of the x’s and y’s:
origin.X = (x0 + x1) / 2 --> (0 + 1) / 2 --> 1/2
origin.Y = (y0 + y1) / 2 --> (0 + 1) / 2 --> 1/2
so, if we increase x1
by 1 to create a rectangle of your shape:
Our new center of the shape would be (1, 1/2)
:
origin.X = (0 + 2) / 2 --> 1
origin.Y = (0 + 1) / 2 --> 1/2
If you haven’t noticed from the picture, x1
moved one unit, while the center moved half that amount. We can apply this to our problem by making the change in the part’s position proportional to how much the size has changed, and in order to make that change in position lock to a surface, we can use the CFrame to apply the size offset in local space, which results in the code from the beginning of this post.
I hope that helps with understanding the math better, if you didn’t already understand it.