<div id="wrapper">
<div class="overlay" id="overlay1"><code>smoothOrigin:true</code> <br>element doesn't jump when origin changes.</div>
<div class="overlay" id="overlay2"><code>smoothOrigin:false</code> <br>element jumps when origin changes.</div>
<div class="bottomOverlay"><h2 id="transform"></h2></div>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
	 width="800px" height="300px" viewBox="0 0 800 300" style="enable-background:new 0 0 800 300;" xml:space="preserve">
<style type="text/css">
	.false{fill:#C54741;}
	.true{fill:#8AC640;}
	.originMarker{fill:#ff0000; stroke:rgba(255, 255, 255, 0.8); stroke-width:1px;}
  .ghost{opacity:0.3;}
</style>
<g id="boxFalseGhost" class="box">
	<rect x="420" y="100" class="false ghost" width="50" height="50"/>
	<g>
		<g>
			<path d="M430.669,131.898v-10.464c0-0.512,0.48-0.768,1.44-0.768h0.816c0.96,0,1.44,0.256,1.44,0.768v10.224
				c0,0.848,0.304,1.544,0.912,2.088c0.608,0.544,1.392,0.816,2.352,0.816s1.748-0.271,2.364-0.816
				c0.616-0.543,0.924-1.24,0.924-2.088v-10.224c0-0.512,0.48-0.768,1.44-0.768h0.792c0.96,0,1.44,0.256,1.44,0.768v10.464
				c0,1.84-0.608,3.269-1.824,4.284c-1.216,1.016-2.928,1.524-5.136,1.524s-3.92-0.508-5.136-1.524
				C431.277,135.167,430.669,133.738,430.669,131.898z"/>
			<path d="M447.829,136.794v-15.12c0-0.64,0.32-0.96,0.96-0.96h5.04c1.872,0,3.32,0.464,4.344,1.392
				c0.384,0.369,0.708,0.884,0.972,1.548c0.264,0.664,0.396,1.436,0.396,2.316s-0.152,1.652-0.456,2.316
				c-0.304,0.664-0.668,1.176-1.092,1.536s-0.908,0.652-1.452,0.876c-0.849,0.352-1.672,0.528-2.472,0.528h-2.544v5.568
				c0,0.513-0.48,0.768-1.44,0.768h-0.816C448.309,137.562,447.829,137.307,447.829,136.794z M451.525,128.058h2.136
				c0.576,0,1.068-0.152,1.476-0.456c0.408-0.304,0.612-0.848,0.612-1.632c0-0.784-0.204-1.332-0.612-1.644
				c-0.408-0.312-0.9-0.468-1.476-0.468h-2.136V128.058z"/>
		</g>
		<polygon points="430.459,118.931 444.481,110.931 458.503,118.931 		"/>
	</g>
</g>
<g id="boxTrueGhost" class="box">
	<rect y="100" class="true ghost" width="50" height="50"/>
	<g>
		<g>
			<path d="M10.669,131.898v-10.464c0-0.512,0.48-0.768,1.44-0.768h0.816c0.96,0,1.44,0.256,1.44,0.768v10.224
				c0,0.848,0.304,1.544,0.912,2.088c0.608,0.544,1.392,0.816,2.352,0.816s1.748-0.271,2.364-0.816
				c0.616-0.543,0.924-1.24,0.924-2.088v-10.224c0-0.512,0.48-0.768,1.44-0.768h0.792c0.96,0,1.44,0.256,1.44,0.768v10.464
				c0,1.84-0.608,3.269-1.824,4.284c-1.216,1.016-2.928,1.524-5.136,1.524s-3.92-0.508-5.136-1.524
				C11.277,135.167,10.669,133.738,10.669,131.898z"/>
			<path d="M27.829,136.794v-15.12c0-0.64,0.32-0.96,0.96-0.96h5.04c1.872,0,3.32,0.464,4.344,1.392
				c0.384,0.369,0.708,0.884,0.972,1.548c0.264,0.664,0.396,1.436,0.396,2.316s-0.152,1.652-0.456,2.316
				c-0.304,0.664-0.668,1.176-1.092,1.536s-0.908,0.652-1.452,0.876c-0.849,0.352-1.672,0.528-2.472,0.528h-2.544v5.568
				c0,0.513-0.48,0.768-1.44,0.768h-0.816C28.309,137.562,27.829,137.307,27.829,136.794z M31.525,128.058h2.136
				c0.576,0,1.068-0.152,1.476-0.456c0.408-0.304,0.612-0.848,0.612-1.632c0-0.784-0.204-1.332-0.612-1.644
				c-0.408-0.312-0.9-0.468-1.476-0.468h-2.136V128.058z"/>
		</g>
		<polygon points="10.459,118.931 24.481,110.931 38.503,118.931 		"/>
	</g>
</g>
<g id="boxFalse" class="box">
	<rect x="420" y="100" class="false" width="50" height="50"/>
	<g>
		<g>
			<path d="M430.669,131.898v-10.464c0-0.512,0.48-0.768,1.44-0.768h0.816c0.96,0,1.44,0.256,1.44,0.768v10.224
				c0,0.848,0.304,1.544,0.912,2.088c0.608,0.544,1.392,0.816,2.352,0.816s1.748-0.271,2.364-0.816
				c0.616-0.543,0.924-1.24,0.924-2.088v-10.224c0-0.512,0.48-0.768,1.44-0.768h0.792c0.96,0,1.44,0.256,1.44,0.768v10.464
				c0,1.84-0.608,3.269-1.824,4.284c-1.216,1.016-2.928,1.524-5.136,1.524s-3.92-0.508-5.136-1.524
				C431.277,135.167,430.669,133.738,430.669,131.898z"/>
			<path d="M447.829,136.794v-15.12c0-0.64,0.32-0.96,0.96-0.96h5.04c1.872,0,3.32,0.464,4.344,1.392
				c0.384,0.369,0.708,0.884,0.972,1.548c0.264,0.664,0.396,1.436,0.396,2.316s-0.152,1.652-0.456,2.316
				c-0.304,0.664-0.668,1.176-1.092,1.536s-0.908,0.652-1.452,0.876c-0.849,0.352-1.672,0.528-2.472,0.528h-2.544v5.568
				c0,0.513-0.48,0.768-1.44,0.768h-0.816C448.309,137.562,447.829,137.307,447.829,136.794z M451.525,128.058h2.136
				c0.576,0,1.068-0.152,1.476-0.456c0.408-0.304,0.612-0.848,0.612-1.632c0-0.784-0.204-1.332-0.612-1.644
				c-0.408-0.312-0.9-0.468-1.476-0.468h-2.136V128.058z"/>
		</g>
		<polygon points="430.459,118.931 444.481,110.931 458.503,118.931 		"/>
	</g>
   <circle class="originMarker" cx="422.5" cy="102.5" r="2.5"/>
</g>
<g id="boxTrue" class="box">
	<rect y="100" class="true" width="50" height="50"/>
	<g>
		<g>
			<path d="M10.669,131.898v-10.464c0-0.512,0.48-0.768,1.44-0.768h0.816c0.96,0,1.44,0.256,1.44,0.768v10.224
				c0,0.848,0.304,1.544,0.912,2.088c0.608,0.544,1.392,0.816,2.352,0.816s1.748-0.271,2.364-0.816
				c0.616-0.543,0.924-1.24,0.924-2.088v-10.224c0-0.512,0.48-0.768,1.44-0.768h0.792c0.96,0,1.44,0.256,1.44,0.768v10.464
				c0,1.84-0.608,3.269-1.824,4.284c-1.216,1.016-2.928,1.524-5.136,1.524s-3.92-0.508-5.136-1.524
				C11.277,135.167,10.669,133.738,10.669,131.898z"/>
			<path d="M27.829,136.794v-15.12c0-0.64,0.32-0.96,0.96-0.96h5.04c1.872,0,3.32,0.464,4.344,1.392
				c0.384,0.369,0.708,0.884,0.972,1.548c0.264,0.664,0.396,1.436,0.396,2.316s-0.152,1.652-0.456,2.316
				c-0.304,0.664-0.668,1.176-1.092,1.536s-0.908,0.652-1.452,0.876c-0.849,0.352-1.672,0.528-2.472,0.528h-2.544v5.568
				c0,0.513-0.48,0.768-1.44,0.768h-0.816C28.309,137.562,27.829,137.307,27.829,136.794z M31.525,128.058h2.136
				c0.576,0,1.068-0.152,1.476-0.456c0.408-0.304,0.612-0.848,0.612-1.632c0-0.784-0.204-1.332-0.612-1.644
				c-0.408-0.312-0.9-0.468-1.476-0.468h-2.136V128.058z"/>
		</g>
		<polygon points="10.459,118.931 24.481,110.931 38.503,118.931 		"/>
	</g>
	<circle class="originMarker" cx="2.5" cy="102.5" r="2.5"/>
</g>
</svg>
  <div class="nav">
  <div id="slider"></div>
    <button id="play" class="dark-grey-button club-demo-button">restart</button></div>
  
</div>
</div>
<p>Initial scale of the boxes is <code>scale:2</code> with their transform origin in the upper left corner,
<code>transformOrigin:"left top"</code>. The red circles indicate the transformOrigin position.</p>
<p><code>smoothOrigin:false</code> is actually the "proper" implementation based on the SVG and CSS specs, but <code>smoothOrigin:true</code> looks more natural and smooth.</p>
body {
  background: #2d2d2d;
  color: white;
  font-family: sans-serif;
  font-size: 16px;
  padding: 12px;
}

p {
  color: #999;
  text-align: center;
}

#wrapper {
  position: relative;
  width: 800px;
  margin: auto;
}

svg {
  border: solid 1px black;
  background: #1d1d1d;
  display: block;
}

code {
  color: #ccc;
}

button {
  margin: 20px;
}

.nav {
  width:520px;
  margin:auto;
}
#play {
  float: right;
  margin-top: 20px;
}

p {
  line-height: 24px;
}

.overlay {
  top: 10px;
  left: 10px;
  position: absolute;
}

#overlay2 {
  left: 420px;
}

.bottomOverlay {
  width: 800px;
  text-align: center;
  position: absolute;
  top: 250px;
}


#slider {
  width:400px;
  margin:30px auto;
  background-color: #222;
  display: inline-block;
}

#slider, #slider a {
  background-image: none;
  border: 1px solid #555;
}
#slider a {
  background-color: #444;
}
gsap.registerPlugin(TextPlugin);

//CSSPlugin.defaultSmoothOrigin = false;
var boxTrue = document.getElementById("boxTrue"); 
var boxFalse = document.getElementById("boxFalse");
var boxTrueGhost = document.getElementById("boxTrueGhost");
var text = document.getElementById("transform");
var originMarkers = document.querySelectorAll(".originMarker");

var tl = gsap.timeline({onUpdate:updateSlider, paused:true, defaults:{duration: 0.5}});

tl.add("scaleUp1")
  .set(text, {text:'transformOrigin:"left top"'})
  .to(boxTrue, {scale:2}, "scaleUp1")
  .to(boxFalse, {scale:2}, "scaleUp1")
  .set(originMarkers, {x:"-50%", y:"-50%"}, "scaleUp1+=-0.01")
  
  .add("rotate1")
  .set(originMarkers, {x:25, y:25}, "rotate1") //move them inside box so they don't alter bounds / transformOrigin of boxes
  .set(text, {text:'transformOrigin:"right bottom"'}, "rotate1")
  .to(boxTrue, {rotation:"+=90", transformOrigin:"right bottom"}, "rotate1")
  .to(boxFalse, {rotation:"+=90", transformOrigin:"right bottom", smoothOrigin:false}, "rotate1")
  .set(originMarkers, {x:50, y:50}, "rotate1")

  .add("rotate2")
  .set(originMarkers, {x:25, y:25}, "rotate2")
  .set(text, {text:'transformOrigin:"right top"'}, "rotate2")
  .to(boxTrue, {rotation:"+=90", transformOrigin:"right top"}, "rotate2")
  .to(boxFalse, {rotation:"+=90", transformOrigin:"right top", smoothOrigin:false}, "rotate2")
  .set(originMarkers, {x:50, y:0}, "rotate2")
 
  

.add("rotate3")
  .set(originMarkers, {x:25, y:25}, "rotate3")
  .set(text, {text:'transformOrigin:"left top"'}, "rotate3")
  .to(boxTrue, {rotation:"+=90", transformOrigin:"left top"}, "rotate43")
  .to(boxFalse, {rotation:"+=90", transformOrigin:"left top", smoothOrigin:false}, "rotate3")
  .set(originMarkers, {x:0, y:0}, "rotate3")




  

tl.timeScale(0.3);
gsap.set(".box", {y:45});
gsap.set([boxTrue, boxTrueGhost], {x:10});

document.getElementById("play").addEventListener("click", function() {
  tl.restart();
});
  
//--- SLIDER ---
var $slider = $("#slider");
$slider.slider({
  range: false,
  min: 0,
  max: 100,
  step: 0.02,
  value:0,
  slide: function ( event, ui ) {
    tl.progress( ui.value / 100 ).pause();
  }
});
function updateSlider() {
	$slider.slider("value", tl.progress() * 100);
}

External CSS

  1. https://codepen.io/GreenSock/pen/ee8ac247ddeb87e229d660127c6fe73d.css
  2. //ajax.googleapis.com/ajax/libs/jqueryui/1.11.2/themes/smoothness/jquery-ui.css

External JavaScript

  1. //cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js
  2. //cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.2/jquery-ui.min.js
  3. https://unpkg.co/gsap@3/dist/gsap.min.js
  4. https://unpkg.com/gsap@3/dist/TextPlugin.min.js