GSAP 사례 연구
Simple Animation
배경 · MIT (local companion); GSAP Standard No Charge License (runtime)
갤러리 안에서는 화면을 벗어나거나 움직임을 멈추면 예제도 닫힙니다. 다시 재생할 때는 처음부터 시작해요.
저장한 HTML에서는 갤러리의 재생 설정이 적용되지 않아요.
SOURCE FILES
독립 예제 코드 읽기
사례의 구도나 문서의 원리를 바탕으로 새로 만든 예제입니다. 아래 코드를 복사해 직접 응용할 수 있습니다. 실행 HTML에는 미리보기를 위한 실행 환경이 들어 있습니다.
vendor/gsap-previews/sources/gsap-2298f263a66d/study-brief.json실행 안내·자료
{
"id": "gsap-2298f263a66d",
"sourceId": "gsap",
"title": "Simple Animation",
"sourceUrl": "https://demos.gsap.com/demo/simple-animation",
"demoUrl": "https://codepen.io/GreenSock/pen/myeLGNV",
"sourceStatus": "unresolved",
"sourceReason": "Public page unavailable through web browsing",
"sourceRevision": null,
"sourceLicense": null,
"originalDemoAcquired": false,
"disposition": "ready_for_independent_study",
"evidenceBasis": "catalog_explanation_and_linked_api",
"studyId": "gsap-2298f263a66d",
"sharedStudyCanonicalId": null,
"label": "Independently authored documentation study; original Pen unavailable",
"catalogEvidence": {
"localPath": "artifacts/full-import/gsap/remaining-docs/catalog-evidence.json",
"sha256": "4f2a4f9aa64456b85b905b562b60d7733629b41026787b3057cba29e8b10de69",
"bytes": 30117,
"recordId": "gsap-2298f263a66d"
},
"sourceInputs": [
{
"kind": "authored-study-specification",
"localPath": "artifacts/full-import/gsap/remaining-docs/study-specs.json",
"sha256": "cbb89331eda8783b5cf2f173b326b9195eeabfb223374fb60019161d9f46d4a6",
"bytes": 52279,
"recordId": "gsap-2298f263a66d"
},
{
"kind": "official-catalog-metadata",
"localPath": "artifacts/full-import/gsap/remaining-docs/catalog-evidence.json",
"sha256": "4f2a4f9aa64456b85b905b562b60d7733629b41026787b3057cba29e8b10de69",
"bytes": 30117,
"recordId": "gsap-2298f263a66d"
},
{
"kind": "official-documentation-evidence",
"localPath": "artifacts/full-import/gsap/remaining-docs/official-documentation-evidence.json",
"sha256": "bfa25f561e61c597569cf1bc0b3538e6dce4b9985a932775ceab41e665ca24a2",
"bytes": 11430,
"recordIds": [
"tween"
]
},
{
"kind": "original-library-source",
"localPath": "artifacts/full-import/gsap/library/src/gsap-core.js",
"sha256": "8063816e0e7c3e6c07970fb06feafb06146fd266db5d8346419176b3d496e284",
"gitBlob": "c673b9e2e0ee04832afb13cb892ae75f503e268c",
"revision": "13e2b790546426a1a2e0e9b409f3f8dc6d6611f2",
"sourcePath": "src/gsap-core.js",
"ranges": [
{
"id": "tween-factories",
"startLine": 2637,
"endLine": 2657,
"rangeSha256": "23ae9d51865c9b7966bbc3b6cdbdb560fc790ff19e3b8bb524a3493fbf60c58a"
}
]
}
],
"studiedPrinciple": "Compare how to, from, and fromTo choose their starting and ending values from a declared resting style.",
"namedApis": [
{
"name": "gsap.to(target, vars)",
"purpose": "Animate from the current resting value to the supplied destination.",
"libraryEvidence": [
"tween-factories"
],
"documentationEvidence": [
"tween"
]
},
{
"name": "gsap.from(target, vars)",
"purpose": "Animate from the supplied starting value back to the recorded resting value.",
"libraryEvidence": [
"tween-factories"
],
"documentationEvidence": [
"tween"
]
},
{
"name": "gsap.fromTo(target, fromVars, toVars)",
"purpose": "Supply both endpoints explicitly instead of relying on the resting value.",
"libraryEvidence": [
"tween-factories"
],
"documentationEvidence": [
"tween"
]
}
],
"implementationBrief": {
"scene": "Three labeled horizontal tracks with identical square markers. Mark positions zero, resting, and supplied destination so the method difference is visible without reading source code.",
"controls": [
{
"label": "Play comparison",
"type": "button",
"action": "Create or replay the three method tweens from a known baseline."
},
{
"label": "Progress",
"type": "range",
"action": "Pause all three and set equal normalized progress."
},
{
"label": "Show resting state",
"type": "button",
"action": "Kill existing study tweens and restore the same resting value on all three tracks before any new from/fromTo construction."
}
],
"mechanismSteps": [
"Set all three markers to the same authored resting x value and label that position.",
"For to supply only the destination; for from supply only the start; for fromTo supply both start and destination. Use identical duration/ease and separate target elements.",
"Account for from/fromTo normally applying their start values during construction, even when paused. Label those as method initialization, not an unexpected playback jump.",
"Before rebuilding, kill old tweens and explicitly restore the resting value. Killing a tween alone is not a style reset.",
"At completion display the three expected endpoints: to reaches destination, from reaches resting, and fromTo reaches destination."
]
},
"authoredDefaults": {
"restingX": 80,
"suppliedStartX": 0,
"suppliedDestinationX": 160,
"markerSizePixels": 24,
"durationSeconds": 1,
"ease": "power1.inOut",
"trackMinimumInnerWidthPixels": 184
},
"verificationRequired": [
"to starts at 80 and ends at 160; from starts at 0 and ends at 80; fromTo starts at 0 and ends at 160.",
"Show resting state restores all markers to 80; repeated play produces the same endpoints without capturing stale styles.",
"Progress zero and one match the labeled method endpoints, including immediate-render initialization.",
"The three tracks and labels fit at 320px without horizontal page overflow."
],
"unsupportedClaims": [
"Original composition, assets, timing, breakpoint behavior, and live interaction are not observable in captured frames. This brief does not establish visual fidelity or recover original code.",
"The catalog teaches the three methods but supplies no recovered original values or visual arrangement. These three tracks and all values are newly authored.",
"The embedded article links a second Pen as an illustration; neither linked Pen is being claimed as recovered source here."
],
"dependencies": {
"package": "gsap",
"version": "3.15.0",
"revision": "13e2b790546426a1a2e0e9b409f3f8dc6d6611f2",
"repository": "https://github.com/greensock/GSAP",
"plugins": [],
"registration": "Core includes CSSPlugin; no separate plugin registration required.",
"runtimeCandidates": [
{
"path": "dist/gsap.js",
"localPath": "artifacts/full-import/gsap/library/dist/gsap.js",
"gitBlob": "ec5ffee3f099bc454f2f1c79cee6a55ba97e7400",
"sha256": "01effe0e121c22ba0f885a3f091f3dc6d1f0d445c4fba37dcb298e314eca5cfb",
"bytes": 179557
}
],
"license": {
"name": "GSAP Standard 'No Charge' License (custom, not MIT)",
"localPath": "artifacts/full-import/gsap/licenses/gsap-standard-license.html",
"sha256": "bf8536e67b77db780f7db0c14a645f184f554bb19e938d1e52d58986e2f10528",
"bytes": 6988,
"url": "https://gsap.com/community/standard-license/"
},
"originalDependencyVersionKnown": false
},
"runtimeVerified": false,
"implementationWritten": false
}
vendor/gsap-previews/sources/gsap-2298f263a66d/source-inputs.json실행 안내·자료
[
{
"kind": "authored-study-specification",
"localPath": "artifacts/full-import/gsap/remaining-docs/study-specs.json",
"sha256": "cbb89331eda8783b5cf2f173b326b9195eeabfb223374fb60019161d9f46d4a6",
"bytes": 52279,
"recordId": "gsap-2298f263a66d"
},
{
"kind": "official-catalog-metadata",
"localPath": "artifacts/full-import/gsap/remaining-docs/catalog-evidence.json",
"sha256": "4f2a4f9aa64456b85b905b562b60d7733629b41026787b3057cba29e8b10de69",
"bytes": 30117,
"recordId": "gsap-2298f263a66d"
},
{
"kind": "official-documentation-evidence",
"localPath": "artifacts/full-import/gsap/remaining-docs/official-documentation-evidence.json",
"sha256": "bfa25f561e61c597569cf1bc0b3538e6dce4b9985a932775ceab41e665ca24a2",
"bytes": 11430,
"recordIds": [
"tween"
]
},
{
"kind": "original-library-source",
"localPath": "artifacts/full-import/gsap/library/src/gsap-core.js",
"sha256": "8063816e0e7c3e6c07970fb06feafb06146fd266db5d8346419176b3d496e284",
"gitBlob": "c673b9e2e0ee04832afb13cb892ae75f503e268c",
"revision": "13e2b790546426a1a2e0e9b409f3f8dc6d6611f2",
"sourcePath": "src/gsap-core.js",
"ranges": [
{
"id": "tween-factories",
"startLine": 2637,
"endLine": 2657,
"rangeSha256": "23ae9d51865c9b7966bbc3b6cdbdb560fc790ff19e3b8bb524a3493fbf60c58a"
}
]
}
]
함께 쓰는 파일 4개 보기
vendor/gsap-previews/sources/gsap-2298f263a66d/index.html실행 안내·자료
<main class="study"><p class="study-label">공식 API 기반 · 독립 예제</p><header><h2>출발과 도착을 정하는 세 방법</h2><p>기본 위치는 80px입니다. 입력한 시작은 0px, 입력한 도착은 160px입니다.</p></header><div class="stage method-stage"><div class="method-row"><strong>to</strong><div class="method-track"><span class="axis-label" style="left:0">0</span><span class="axis-label" style="left:80px">80</span><span class="axis-label" style="left:160px">160</span><div class="method-mark" style="background:#95efd2;transform:translateX(80px)"></div></div></div><div class="method-row"><strong>from</strong><div class="method-track"><span class="axis-label" style="left:0">0</span><span class="axis-label" style="left:80px">80</span><span class="axis-label" style="left:160px">160</span><div class="method-mark" style="background:#fbadce;transform:translateX(80px)"></div></div></div><div class="method-row"><strong>fromTo</strong><div class="method-track"><span class="axis-label" style="left:0">0</span><span class="axis-label" style="left:80px">80</span><span class="axis-label" style="left:160px">160</span><div class="method-mark" style="background:#ffd28c;transform:translateX(80px)"></div></div></div></div><div class="controls"><button id="play" type="button">함께 재생</button><button id="rest" type="button">기본 위치로</button><label>진행<input id="progress" type="range" min="0" max="100" value="0" step="1"></label><label><input id="static-mode" type="checkbox">정적 보기</label></div><p class="readout" id="reading" aria-live="off"></p></main>vendor/gsap-previews/sources/gsap-2298f263a66d/style.css실행 안내·자료
*{box-sizing:border-box}body{background:#111522;color:#f5f2eb;font-family:system-ui,sans-serif;margin:0}button{font:inherit}.study{margin:0 auto;max-width:1100px;min-height:100vh;padding:clamp(20px,4vw,42px)}.study-label{color:#95efd2;font-size:12px;letter-spacing:.08em;margin:0 0 24px}header h2{font-size:clamp(24px,4vw,40px);letter-spacing:-.04em;margin:0 0 12px}header p{color:#aeb7c9;line-height:1.6;margin:0 0 24px;max-width:62ch}.controls{display:flex;flex-wrap:wrap;gap:8px;margin:20px 0}button{background:#26314b;border:1px solid #617394;border-radius:9px;color:#f5f2eb;cursor:pointer;padding:9px 14px}button:hover{background:#334261}button:focus-visible{outline:3px solid #95efd2;outline-offset:3px}button:disabled{cursor:default;opacity:.45}.stage{align-items:center;background:radial-gradient(ellipse at top,#243253,#141c2d);border:1px solid #3d4c68;border-radius:20px;display:flex;justify-content:center;min-height:220px;overflow:hidden;position:relative}.note{color:#aeb7c9;font-size:13px;line-height:1.5}.readout{color:#95efd2;font-family:ui-monospace,monospace;font-size:13px;min-height:2em}.stage svg{display:block;max-width:100%}code{font-family:ui-monospace,monospace}button[aria-pressed="true"]{background:#95efd2;color:#111522}
.study{padding:18px;max-width:960px}.study-label{margin-bottom:10px}header h2{font-size:clamp(22px,4vw,32px);margin-bottom:8px}header p{font-size:14px;margin-bottom:16px}.controls{align-items:center;gap:9px;margin:14px 0}.controls label{align-items:center;color:#cbd4e3;display:flex;flex-wrap:wrap;font-size:13px;gap:7px}.controls input[type=range]{accent-color:#95efd2;max-width:145px}.controls select{background:#26314b;border:1px solid #617394;border-radius:7px;color:#f5f2eb;font:inherit;padding:6px}.stage{min-height:180px}.readout{line-height:1.5;margin:8px 0}.small-code{background:#172036;border:1px solid #354258;border-radius:10px;color:#c3d1e7;font-size:12px;line-height:1.5;max-height:180px;overflow:auto;padding:12px;white-space:pre-wrap;word-break:break-word}.pair{display:flex;gap:12px;justify-content:center}.pair figure{flex:1;margin:0;max-width:300px;min-width:0;padding:8px}.pair figcaption{color:#aeb7c9;font-family:ui-monospace,monospace;font-size:12px;margin-bottom:6px;text-align:center}.pair svg{display:block;max-height:210px;width:100%}.tile-art{align-items:center;border-radius:14px;color:#152039;display:flex;justify-content:center}.tile-art svg{height:65%;width:65%}.menu-stage{min-height:196px;padding:18px}.menu-panels{display:flex;gap:10px;max-width:570px;width:100%}.menu-panel{align-items:center;background:linear-gradient(135deg,#95efd2,#75d8ed);border-radius:14px;color:#142137;display:flex;flex:1;flex-direction:column;font-weight:650;gap:10px;justify-content:center;min-height:135px;min-width:0;padding:12px}.menu-panel:nth-child(2){background:linear-gradient(135deg,#fbadce,#897dff)}.menu-panel:nth-child(3){background:linear-gradient(135deg,#ffd28c,#fc7f8e)}.menu-panel svg{height:58px;width:58px}.icon-bars{display:inline-flex;flex-direction:column;gap:5px;margin-right:7px;vertical-align:middle}.icon-bars span{background:currentColor;display:block;height:2px;width:17px}.endpoint-note{color:#aeb7c9;font-size:12px;line-height:1.5}button[hidden],[hidden]{display:none!important}@media(max-width:380px){.study{padding:14px}.controls label{max-width:100%}.menu-panels{gap:6px}.menu-panel{font-size:12px;padding:7px}.pair{gap:0}}
.method-stage{align-items:stretch;flex-direction:column;gap:10px;padding:16px}.method-row{align-items:center;display:grid;gap:12px;grid-template-columns:50px 1fr;width:100%}.method-row strong{font-family:ui-monospace,monospace;font-size:12px}.method-track{border-top:1px dashed #617394;height:58px;min-width:184px;position:relative}.method-mark{border-radius:7px;height:24px;left:0;position:absolute;top:15px;width:24px}.axis-label{color:#aeb7c9;font-family:ui-monospace,monospace;font-size:10px;position:absolute;top:43px}vendor/gsap-previews/sources/gsap-2298f263a66d/script.js실행 안내·자료
gsap.registerPlugin();
const q=selector=>document.querySelector(selector),qa=selector=>Array.from(document.querySelectorAll(selector));
const studyAbort=new AbortController(),studyCleanup=[];
const listen=(target,type,handler)=>target.addEventListener(type,handler,{signal:studyAbort.signal});
const preference=matchMedia('(prefers-reduced-motion: reduce)'),staticControl=q('#static-mode');
staticControl.checked=preference.matches;staticControl.disabled=preference.matches;
const isStatic=()=>staticControl.checked||preference.matches;
let applyMode=()=>{};
listen(staticControl,'change',()=>applyMode());
listen(preference,'change',()=>{staticControl.checked=preference.matches;staticControl.disabled=preference.matches;applyMode();});
listen(window,'pagehide',()=>{studyCleanup.forEach(cleanup=>cleanup());studyAbort.abort();});
const reading=text=>q('#reading').textContent=text;
const methodMarks=qa('.method-mark');let methodTweens=[];
function inspect(){reading(['to','from','fromTo'].map((name,i)=>name+': '+Number(gsap.getProperty(methodMarks[i],'x')).toFixed(0)+'px').join(' / '));if(methodTweens[0])q('#progress').value=Math.round(methodTweens[0].progress()*100);}
function rest(){methodTweens.forEach(t=>t.kill());methodTweens=[];gsap.set(methodMarks,{x:80});q('#progress').value=0;inspect();}
function buildMethods(){rest();const options={duration:1,ease:'power1.inOut',paused:true,onUpdate:inspect};methodTweens=[gsap.to(methodMarks[0],{...options,x:160}),gsap.from(methodMarks[1],{...options,x:0}),gsap.fromTo(methodMarks[2],{x:0},{...options,x:160})];inspect();}
listen(q('#play'),'click',()=>{buildMethods();methodTweens.forEach(t=>isStatic()?t.progress(1,true):t.play());inspect();});listen(q('#rest'),'click',rest);listen(q('#progress'),'input',e=>{const progress=Number(e.target.value)/100;if(!methodTweens.length)buildMethods();methodTweens.forEach(t=>t.pause().progress(progress,true));inspect();});applyMode=rest;studyCleanup.push(()=>methodTweens.forEach(t=>t.kill()));rest();LICENSE실행 안내·자료
Locally authored companion HTML/CSS/control wiring: MIT License.
Copyright (c) 2026 StyleGallery contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
The typed source-inputs.json and study-brief.json preserve official catalog, documentation and original library source pointers. This is independently authored API research, not a recovered CodePen source or documentation snippet. The local MIT notice does not assign new licenses to referenced third-party sources.
GSAP 3.15.0: Copyright 2026, GreenSock. All rights reserved. Subject to https://gsap.com/standard-license. Original library notices are preserved.
BEHIND THE EXAMPLE
이 장면을 만드는 원리
현재 값과 명시한 시작·도착 값
입력이 생략된 끝점은 무엇을 읽는지 명시하고 반복 시 초기 상태를 복원합니다.
- 이 예제에서는
- 세 트랙의 기본 x는 80입니다. 새 효과를 만들기 전 rest가 모두 80으로 복원하고 to는 160으로, from은 지정한 0에서 현재 80으로, fromTo는 명시한 0에서 160으로 향합니다. 초기 렌더링과 트윈 생성 시점을 구분하며 매번 중간값을 새 도착값으로 삼지 않습니다.
코드와 함께 확인하기
코드에서 찾기
function buildMethodsscript.js공통 복원 뒤 서로 다른 끝점 계약의 세 트윈을 만듭니다.
function restscript.js이전 효과를 제거하고 세 대상의 기본값을 명시적으로 복원합니다.
직접 해보기
0%와 100%에서 세 x 값을 비교합니다.
살펴볼 변화to 80→160, from 0→80, fromTo 0→160이라는 입력 계약과 일치해야 합니다.
중간에서 함께 재생을 다시 누르고 기본 위치로 복원합니다.
살펴볼 변화중간값을 새 끝점으로 누적하지 않고 세 대상 모두 80으로 돌아와야 합니다.
