Codrops 사례 연구
From far away to within.
데이터 · MIT
갤러리 안에서는 화면을 벗어나거나 움직임을 멈추면 예제도 닫힙니다. 다시 재생할 때는 처음부터 시작해요.
저장한 HTML에서는 갤러리의 재생 설정이 적용되지 않아요.
SOURCE FILES
독립 예제 코드 읽기
사례의 구도나 문서의 원리를 바탕으로 새로 만든 예제입니다. 아래 코드를 복사해 직접 응용할 수 있습니다. 실행 HTML에는 미리보기를 위한 실행 환경이 들어 있습니다.
index.html독립 구현
<!doctype html>
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data:; media-src data:; font-src data:; connect-src 'none'; base-uri 'none'; form-action 'none'"><title>From far away to within. · Independent article study</title><style>/* Generated by scripts/build-codrops-article-studies.mjs.
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.
Scope: independently authored study HTML, CSS, JavaScript, shaders and SVG only. Original articles, source projects, brands, artwork and screenshots are excluded. Their licenses and acquisition dispositions are unchanged.
*/
*{box-sizing:border-box}html{color-scheme:dark}html,body{margin:0;min-height:100%}body{background:var(--paper,#0c1321);color:var(--ink,#f4f3e9);font-family:Arial,Helvetica,sans-serif}button,input,select{font:inherit}button,select,input{min-width:0}button{background:transparent;border:1px solid #ffffff40;border-radius:999px;color:inherit;cursor:pointer;min-height:40px;padding:10px 16px}button:hover{background:#ffffff15}button[aria-pressed=true]{background:var(--accent,#dbff78);border-color:transparent;color:#122014}button:disabled{cursor:default;opacity:.6}button:focus-visible,input:focus-visible,select:focus-visible,summary:focus-visible,a:focus-visible{outline:3px solid var(--accent,#dbff78);outline-offset:4px}input,select{accent-color:var(--accent,#dbff78)}select,input[type=text],input[type=number]{background:#132235;border:1px solid #ffffff50;border-radius:7px;color:#fff;min-height:38px;padding:8px;width:100%}input[type=range]{display:block;min-height:30px;width:100%}a{color:inherit}svg{display:block;max-width:100%}h1,h2,p,figure{margin:0}h1{font-size:clamp(36px,6.5vw,78px);font-weight:500;letter-spacing:-.06em;line-height:.99}h2{font-size:24px;font-weight:500;letter-spacing:-.025em}p{line-height:1.55}.study{isolation:isolate;min-height:100vh;padding:clamp(18px,3.8vw,48px)}.masthead{align-items:center;display:flex;flex-wrap:wrap;font:10px/1.5 ui-monospace,monospace;gap:16px;justify-content:space-between;letter-spacing:.11em;margin-bottom:35px;text-transform:uppercase}.masthead strong{font-size:12px;letter-spacing:-.02em}.intro{display:grid;gap:18px;grid-template-columns:minmax(0,1.5fr) minmax(0,1fr);margin-bottom:30px;align-items:end}.intro p{color:var(--muted,#b7c7d4);font-size:13px;max-width:38em}.eyebrow{color:var(--accent,#dbff78);font:10px/1.4 ui-monospace,monospace;letter-spacing:.14em;margin-bottom:12px;text-transform:uppercase}.workbench{display:grid;gap:20px;grid-template-columns:minmax(0,1fr) 230px}.visual{background:var(--surface,#101d2b);border:1px solid #ffffff20;border-radius:20px;min-width:0;overflow:hidden;position:relative}.drawing{height:auto;width:100%}.art-canvas{aspect-ratio:1.55;display:block;height:auto;width:100%}.panel{align-content:start;display:grid;gap:17px}.control{display:grid;font-size:11px;gap:7px;min-width:0}.control>span{display:flex;gap:10px;justify-content:space-between}.control output{color:var(--accent,#dbff78);font-family:ui-monospace,monospace}.controls{display:flex;flex-wrap:wrap;gap:8px}.readout{background:#ffffff09;border:1px solid #ffffff18;border-radius:12px;font:11px/1.7 ui-monospace,monospace;overflow-wrap:anywhere;padding:14px;white-space:pre-line}.legend{align-items:center;display:flex;flex-wrap:wrap;font:10px/1.6 ui-monospace,monospace;gap:16px;padding:16px 20px}.legend i{background:var(--accent,#dbff78);border-radius:50%;display:inline-block;height:6px;margin-right:6px;width:6px}.contract{border-top:1px solid #ffffff20;color:var(--muted,#b7c7d4);font-size:11px;margin-top:28px;padding-top:18px}.contract summary{color:var(--ink,#f4f3e9);cursor:pointer;font-size:12px}.contract p{margin-top:10px;max-width:90ch}.motion-bar{align-items:center;border-top:1px solid #ffffff20;display:flex;flex-wrap:wrap;font-size:11px;gap:12px;justify-content:space-between;margin-top:26px;padding-top:18px}.motion-bar label{align-items:center;display:flex;gap:8px}.feedback{color:var(--muted,#b7c7d4);font:11px/1.5 ui-monospace,monospace;min-height:18px}.visually-hidden{clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;width:1px}[hidden]{display:none!important}.stage-note{background:#07111ac9;bottom:18px;color:#dfe8f0;font:11px/1.5 ui-monospace,monospace;left:18px;max-width:calc(100% - 36px);padding:8px 12px;position:absolute;z-index:2}.big-number{font-size:clamp(70px,14vw,180px);letter-spacing:-.08em;line-height:1}.plain-list{display:grid;gap:12px;list-style:none;margin:0;padding:0}.plain-list li{border-bottom:1px solid #ffffff20;padding:12px 0}.tabs{display:flex;flex-wrap:wrap;gap:7px}.tabs button{font-size:11px}.two{display:grid;gap:20px;grid-template-columns:1fr 1fr}.code-sample{color:#c9ecbe;font:11px/1.7 ui-monospace,monospace;overflow:auto;white-space:pre-wrap}.fallback{padding:30px}.fallback p{max-width:38ch}.static-gallery{display:none}.study[data-reduced=true] .static-gallery{display:grid}.study[data-reduced=true] .animated-story{display:none}.study[data-reduced=true] *{animation:none!important;transition:none!important}body[data-preview-status=error] .feedback{color:#ffbba3}@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;scroll-behavior:auto!important;transition:none!important}}@media(max-width:700px){.intro{grid-template-columns:1fr}.workbench{grid-template-columns:1fr}.panel{grid-template-columns:repeat(2,minmax(0,1fr))}.panel>.readout,.panel>.controls{grid-column:1/-1}.masthead{margin-bottom:26px}.two{grid-template-columns:1fr}}@media(max-width:380px){.panel{gap:12px}.control{font-size:10px}.panel button{font-size:11px;padding:9px 12px}.legend{gap:8px;padding:12px}.visual{border-radius:13px}}
.story-controls{align-items:center;background:var(--paper,#0c1321);border-block:1px solid #ffffff20;display:grid;gap:14px;grid-template-columns:repeat(3,minmax(0,1fr));padding:15px 0;position:sticky;top:0;z-index:8}.story-controls>.controls{grid-column:1/-1}.story-track{display:none;height:1650px;position:relative}.story-pin{position:sticky;top:126px}.story-pin>.visual{min-height:450px}.story-copy{bottom:25px;left:30px;max-width:330px;pointer-events:none;position:absolute;z-index:4}.story-chapter>span{color:#eff0be;font:10px ui-monospace,monospace;letter-spacing:.12em}.story-chapter h2{font:43px/.98 Georgia,serif;margin:12px 0}.story-chapter p{color:#eff5e4;font-size:12px;max-width:30em;text-shadow:0 1px 5px #081320}.story-reading{display:grid;gap:24px;margin-top:28px}.reading-chapter{align-items:center;background:#ffffff06;border:1px solid #ffffff20;border-radius:15px;display:grid;gap:24px;grid-template-columns:1fr 1fr;overflow:hidden;padding:20px}.reading-chapter p{color:#bfd0ce;font-size:13px;margin-top:13px}.reading-chapter svg{border-radius:8px;width:100%}.study[data-story-enhanced=true][data-reduced=false] .story-track{display:block}.study[data-story-enhanced=true][data-reduced=false] .story-reading{display:none}.study[data-reduced=true] .story-track{display:none}.story-diagnostics{margin-top:15px}.story-skip{color:#c4d3ca;display:inline-block;font:11px ui-monospace,monospace;margin-bottom:15px}.story-end{height:1px}@media(max-width:700px){.story-controls{grid-template-columns:repeat(2,minmax(0,1fr))}.story-pin{top:170px}.story-pin>.visual{min-height:380px}.story-copy{bottom:22px;left:22px;max-width:calc(100% - 44px)}.story-chapter h2{font-size:34px}.story-chapter p{font-size:11px}.reading-chapter{grid-template-columns:1fr}.story-track{height:1450px}}@media(max-height:650px){.story-controls{position:relative}.story-pin{top:10px}}.moon-lab{inline-size:100%;max-inline-size:100%;aspect-ratio:1.45;background:radial-gradient(ellipse at 50% 30%,#305266,#0c2334 55%,#0d1b2a);isolation:isolate;min-height:500px}.moon-stars{background-image:radial-gradient(circle,#b5d5d4 1px,transparent 1.5px),radial-gradient(circle,#e3d6ae 1px,transparent 1.5px);background-position:0 0,29px 43px;background-size:83px 101px,127px 151px;inset:0;opacity:.55;position:absolute}.world-orb{height:100%;left:15%;position:absolute;top:-4%;transform-origin:50% 50%;width:75%;will-change:transform,opacity}.world-orb svg{height:100%;width:100%}.observatory-interior{inset:0;opacity:0;position:absolute}.observatory-interior svg{height:100%;object-fit:cover;width:100%}.moon-lab::after{background:linear-gradient(transparent 45%,#0c1d2ddd);content:'';inset:0;pointer-events:none;position:absolute}.moon-progress{color:#d6dfc9;font:12px ui-monospace,monospace;position:absolute;right:25px;top:25px;z-index:3}@media(max-width:600px){.moon-lab{aspect-ratio:.85;min-height:430px}.world-orb{left:0;top:-13%;width:100%}}
@media(max-height:550px) and (min-width:500px){
.study{padding:18px}.masthead{font-size:8px;gap:10px;margin-bottom:16px}.masthead strong{font-size:10px}.intro{gap:18px;grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);margin-bottom:18px}.intro h1{font-size:34px}.intro p{font-size:10px;line-height:1.5}.intro .eyebrow{font-size:8px;margin-bottom:8px}.workbench{gap:16px;grid-template-columns:minmax(0,1fr) 174px}.panel{gap:10px;grid-template-columns:1fr}.panel .control{font-size:9px;gap:3px}.panel .control input[type=range]{min-height:22px}.panel select,.panel input[type=text],.panel input[type=number]{font-size:10px;min-height:31px;padding:6px}.panel .controls{gap:5px}.panel button{font-size:9px;min-height:30px;padding:7px 10px}.panel .readout{font-size:8px;padding:10px}.art-canvas{aspect-ratio:auto!important;height:250px;object-fit:contain}.legend{font-size:8px;gap:8px;padding:10px 13px}.stage-note{bottom:12px;font-size:8px;left:12px;padding:5px 8px}.type-lab{min-height:280px;padding:23px}.type-heading{font-size:36px}.particle-rack{height:80px}.type-rule{font-size:7px}.bounce-lab>.drawing{height:230px;object-fit:contain}.track-graph{padding:9px 16px}.track-graph svg{height:43px}.member-lab{min-height:300px;padding:18px}.member-heading h2{font-size:24px}.member-collage{height:180px}.member-total .counter{font-size:52px}.member-total>span{font-size:7px}.member-card span{font-size:6px;padding:4px}.composer-surface{padding:20px}.composer-label{font-size:8px;margin-bottom:20px}.form-set{gap:10px}.form-set h2{font-size:20px;margin-top:12px}.form-set p{font-size:9px}.timeline-rows{padding:12px 17px}.mascot-lab>.drawing{height:250px;object-fit:contain}.pose-strip{padding:10px 14px}.pose-marker{font-size:8px;padding:6px 0}.fit-stage{min-height:270px;padding:20px}.fit-stage canvas{max-height:235px}.tree-columns{grid-template-columns:125px minmax(0,1fr);min-height:320px}.tree-inspector{padding:17px 12px}.tree-inspector pre{font-size:8px;margin-top:18px}.tree-rules{display:none}.tree-preview{min-height:0;padding:14px}.tree-width-label,.tree-caption{font-size:7px}.fixture-copy h2{font-size:1.6em}.fixture-copy p{font-size:.65em}.fixture-output{gap:10px;padding:12px}.fixture-art{max-height:90px}.semantic-lab{grid-template-columns:110px minmax(0,1fr);min-height:320px}.node-list{flex-direction:column;padding:12px 7px}.node-list button{font-size:8px;gap:5px;padding:9px 7px}.node-list button small{font-size:7px}.semantic-preview{padding:14px}.semantic-fixture{padding:8px}.semantic-fixture h2{font-size:27px}.semantic-fixture p{font-size:10px}.semantic-art{height:75px}.markup-panel{padding:15px}.markup-panel pre{font-size:8px}.plant-lab{padding:18px}.plant-heading h2{font-size:28px}.plant-heading span{font-size:8px}.plant-illustration{margin:-60px 0 -8px}.plant-illustration svg{height:250px}.plant-callouts{gap:5px}.plant-callouts button{font-size:7px;min-height:28px;padding:7px}.plant-feature,.care-plan{font-size:10px}.orbit-lab{min-height:300px}.orbit-camera{height:270px}.orbit-ring{height:170px;width:110px}.orbit-card{height:170px;width:110px}.orbit-foot{font-size:8px;padding:10px 14px}.botanical-window{aspect-ratio:1.5}.window-label h2{font-size:29px}.window-label span{font-size:8px}.gold-lab{padding:18px}.gold-heading h2{font-size:28px;margin-top:9px}.gold-heading>span,.gold-total>span{font-size:7px}.gold-lab>svg{height:175px;margin:-27px 0 -6px}.gold-total{padding-top:9px}.gold-total output{font-size:43px}.gold-disclaimer{font-size:9px}.story-controls{gap:10px;grid-template-columns:repeat(4,minmax(0,1fr));padding:10px 0;position:relative}.story-controls .control{font-size:8px}.story-controls input[type=range]{min-height:20px}.story-controls>.controls{grid-column:auto}.story-controls button{font-size:8px;min-height:27px;padding:6px 8px}.story-pin{top:10px}.story-pin>.visual{min-height:270px}.story-pin .art-canvas{height:270px}.story-copy{bottom:20px;left:20px;max-width:255px}.story-chapter h2{font-size:29px;margin:8px 0}.story-chapter p{font-size:10px}.story-chapter>span{font-size:8px}.moon-lab{aspect-ratio:auto;min-height:270px}.moon-progress,.cylinder-energy,.terrain-coordinates{font-size:8px}.story-skip{font-size:9px;margin-bottom:10px}.reading-chapter{grid-template-columns:1fr 1fr}.motion-bar{margin-top:18px}
}
</style></head><body><main id="root" class="study"><header class="masthead"><strong>STYLEGALLERY / STUDIES</strong><span>CODE + CURIOSITY / 16</span><span>INDEPENDENT EXAMPLE</span></header><div class="intro"><div><p class="eyebrow">16 / Layered three-scene story</p><h1>From far away to within.</h1></div><p>Approach an original pale world, move around its light, then enter an observatory. The same three chapters also work as a stationary reading sequence.</p></div><a class="story-skip" href="#moon-after">Skip the long scroll track ↓</a><div class="story-controls"><label class="control"><span>Story progress<output data-value="story">0</output></span><input aria-label="Story progress" data-control="story" type="range" min="0" max="100" value="0" step="1"></label><label class="control"><span>View horizontal<output data-value="viewX">0</output></span><input aria-label="View horizontal" data-control="viewX" type="range" min="-100" max="100" value="0" step="1"></label><label class="control"><span>View vertical<output data-value="viewY">0</output></span><input aria-label="View vertical" data-control="viewY" type="range" min="-100" max="100" value="0" step="1"></label><div class="controls"><button type="button" data-action="chapter-0" >01</button><button type="button" data-action="chapter-1" >02</button><button type="button" data-action="chapter-2" >03</button><button type="button" data-action="reading" aria-pressed="false">Reading view</button></div></div><div class="story-track" data-story-track><div class="story-pin" data-story-pin><div class="visual moon-lab" data-moon-surface><div class="moon-stars" aria-hidden="true"></div><div class="world-orb" data-world-orb><svg class="drawing" viewBox="0 0 600 600" role="img" aria-label="Original pale world with generated crater positions"><defs><radialGradient id="moonSphere" cx=".28" cy=".25"><stop stop-color="#e2dec0"/><stop offset=".5" stop-color="#b7bda7"/><stop offset=".8" stop-color="#71887f"/><stop offset="1" stop-color="#1e4348"/></radialGradient><clipPath id="moonCircle"><circle cx="300" cy="300" r="240"/></clipPath></defs><circle cx="300" cy="300" r="248" fill="#aecfca" opacity=".1"/><circle cx="300" cy="300" r="240" fill="url(#moonSphere)"/><g clip-path="url(#moonCircle)" fill="#738c8050"><ellipse cx="90" cy="80" rx="8" ry="9" transform="rotate(0 90 80)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="229" cy="163" rx="16" ry="18" transform="rotate(13 229 163)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="368" cy="246" rx="24" ry="27" transform="rotate(26 368 246)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="507" cy="329" rx="32" ry="36" transform="rotate(39 507 329)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="216" cy="412" rx="40" ry="9" transform="rotate(52 216 412)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="355" cy="495" rx="48" ry="18" transform="rotate(65 355 495)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="494" cy="128" rx="8" ry="27" transform="rotate(78 494 128)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="203" cy="211" rx="16" ry="36" transform="rotate(91 203 211)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="342" cy="294" rx="24" ry="9" transform="rotate(104 342 294)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="481" cy="377" rx="32" ry="18" transform="rotate(117 481 377)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="190" cy="460" rx="40" ry="27" transform="rotate(130 190 460)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="329" cy="93" rx="48" ry="36" transform="rotate(143 329 93)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="468" cy="176" rx="8" ry="9" transform="rotate(156 468 176)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="177" cy="259" rx="16" ry="18" transform="rotate(169 177 259)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="316" cy="342" rx="24" ry="27" transform="rotate(182 316 342)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="455" cy="425" rx="32" ry="36" transform="rotate(195 455 425)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="164" cy="508" rx="40" ry="9" transform="rotate(208 164 508)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="303" cy="141" rx="48" ry="18" transform="rotate(221 303 141)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="442" cy="224" rx="8" ry="27" transform="rotate(234 442 224)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="151" cy="307" rx="16" ry="36" transform="rotate(247 151 307)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="290" cy="390" rx="24" ry="9" transform="rotate(260 290 390)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="429" cy="473" rx="32" ry="18" transform="rotate(273 429 473)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="138" cy="106" rx="40" ry="27" transform="rotate(286 138 106)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="277" cy="189" rx="48" ry="36" transform="rotate(299 277 189)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="416" cy="272" rx="8" ry="9" transform="rotate(312 416 272)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="125" cy="355" rx="16" ry="18" transform="rotate(325 125 355)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="264" cy="438" rx="24" ry="27" transform="rotate(338 264 438)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="403" cy="521" rx="32" ry="36" transform="rotate(351 403 521)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="112" cy="154" rx="40" ry="9" transform="rotate(364 112 154)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="251" cy="237" rx="48" ry="18" transform="rotate(377 251 237)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="390" cy="320" rx="8" ry="27" transform="rotate(390 390 320)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="99" cy="403" rx="16" ry="36" transform="rotate(403 99 403)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="238" cy="486" rx="24" ry="9" transform="rotate(416 238 486)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="377" cy="119" rx="32" ry="18" transform="rotate(429 377 119)" stroke="#e4dfb040" stroke-width="3"/><ellipse cx="516" cy="202" rx="40" ry="27" transform="rotate(442 516 202)" stroke="#e4dfb040" stroke-width="3"/></g></svg></div><div class="observatory-interior" data-interior><svg class="drawing" viewBox="0 0 900 620" role="img" aria-label="Original observatory interior with archways and viewing pedestal"><defs><linearGradient id="hallDepth" x2="0" y2="1"><stop stop-color="#3b5c67"/><stop offset="1" stop-color="#142d3b"/></linearGradient></defs><rect width="900" height="620" fill="url(#hallDepth)"/><path d="M0 620V160Q150-90 300 160V620M300 620V160Q450-90 600 160V620M600 620V160Q750-90 900 160V620" fill="#0e2937" stroke="#79918b" stroke-width="27"/><circle cx="450" cy="233" r="87" fill="#d8cfaa"/><path d="M0 493H900V620H0Z" fill="#23414a"/><path d="M0 540H900M0 590H900M100 620L345 493M300 620L405 493M600 620L495 493M800 620L555 493" stroke="#82938b" stroke-opacity=".45" stroke-width="2"/><path d="M330 493V355H570V493" fill="#486b70"/><ellipse cx="450" cy="355" rx="120" ry="23" fill="#75908b"/><path d="M424 355L441 282H462L480 355" fill="#c8b889"/></svg></div><div class="story-copy"><section class="story-chapter" data-chapter="0"><span>CHAPTER 01</span><h2>A signal in the dark.</h2><p>Begin with distance: a quiet sphere, a far horizon and a small point of light.</p></section><section class="story-chapter" data-chapter="1" hidden><span>CHAPTER 02</span><h2>Around the pale world.</h2><p>Approach changes scale and light. A bounded pointer input adds depth without moving the chapter text.</p></section><section class="story-chapter" data-chapter="2" hidden><span>CHAPTER 03</span><h2>Inside the observatory.</h2><p>A new environment replaces the outside view. Reading mode exposes every chapter without the camera move.</p></section></div><div class="moon-progress"><span data-moon-value>00</span><span> / 100</span></div></div></div></div><div class="story-reading"><section class="reading-chapter"><svg class="drawing" viewBox="0 0 600 300" role="img" aria-label="Original lunar sphere summary"><rect width="600" height="300" fill="#102231"/><circle cx="300" cy="150" r="110" fill="#c8c7a5"/><g fill="#8c9d91"><circle cx="260" cy="117" r="26"/><circle cx="338" cy="195" r="39"/><circle cx="330" cy="89" r="16"/></g><path d="M303 42Q477 146 303 258Q410 150 303 42" fill="#344f51" opacity=".7"/></svg><div><span class="eyebrow">CHAPTER 1 / READING VIEW</span><h2>A signal in the dark.</h2><p>Begin with distance: a quiet sphere, a far horizon and a small point of light.</p></div></section><section class="reading-chapter"><svg class="drawing" viewBox="0 0 600 300" role="img" aria-label="Original lunar sphere summary"><rect width="600" height="300" fill="#102231"/><circle cx="300" cy="150" r="110" fill="#c8c7a5"/><g fill="#8c9d91"><circle cx="260" cy="117" r="26"/><circle cx="338" cy="195" r="39"/><circle cx="330" cy="89" r="16"/></g><path d="M303 42Q477 146 303 258Q410 150 303 42" fill="#344f51" opacity=".7"/></svg><div><span class="eyebrow">CHAPTER 2 / READING VIEW</span><h2>Around the pale world.</h2><p>Approach changes scale and light. A bounded pointer input adds depth without moving the chapter text.</p></div></section><section class="reading-chapter"><svg class="drawing" viewBox="0 0 600 300" role="img" aria-label="Original observatory interior"><rect width="600" height="300" fill="#223b4b"/><path d="M35 300V105Q160-20 285 105V300M315 300V105Q440-20 565 105V300" fill="#102938" stroke="#617e84" stroke-width="20"/><path d="M0 260H600M100 300L230 180M500 300L370 180" stroke="#ddca9380" stroke-width="3"/><circle cx="440" cy="120" r="42" fill="#d6c898"/></svg><div><span class="eyebrow">CHAPTER 3 / READING VIEW</span><h2>Inside the observatory.</h2><p>A new environment replaces the outside view. Reading mode exposes every chapter without the camera move.</p></div></section></div><output class="readout story-diagnostics" data-story-diagnostics></output><div class="story-end" id="moon-after"></div><div class="motion-bar"><label><input type="checkbox" data-static> Static view · less motion</label><p class="feedback" data-feedback aria-live="polite">Motion starts only when requested. All inputs are local.</p></div><details class="contract"><summary>What this study teaches</summary><p>A single progress evaluator blends an original SVG globe, atmospheric depth layers and an observatory interior. Document-owned scroll maps to bounded scale, translation and opacity; chapter availability changes immediately at explicit boundaries. Native view inputs replace pointer parallax and the static path exposes every chapter in ordinary flow.</p><p>Independent implementation informed by “Interactive Storytelling for the Web: Building Immersive Stories with Timelines, 3D, and Layered Scenes”, Bjørn Fjellstad, Codrops. This is newly authored code and artwork, not a recovered original project. Original SVG scene art and a browser progress controller replace the source project, generated panorama and authoring tool. No Instorier export, membership, paid image generator or 3D-provider connection is required.</p></details><noscript><div class="fallback"><p>This study’s explanation and initial HTML illustration remain available. Interactive rendering needs JavaScript.</p></div></noscript></main><script>/* Generated by scripts/build-codrops-article-studies.mjs.
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.
Scope: independently authored study HTML, CSS, JavaScript, shaders and SVG only. Original articles, source projects, brands, artwork and screenshots are excluded. Their licenses and acquisition dispositions are unchanged.
*/
(() => {
'use strict';
const id="codrops-eecfba24b649",stage=document.querySelector('.study');
const preview=window.__STYLEGALLERY_PREVIEW__={id,status:'loading',errors:[]};
const report=error=>{const message=error instanceof Error?error.message:String(error);if(!preview.errors.includes(message))preview.errors.push(message);preview.status='error';document.body.dataset.previewStatus='error';parent.postMessage({type:'sg-preview-error',id,message},'*');const feedback=document.querySelector('[data-feedback]');if(feedback)feedback.textContent=message;};
addEventListener('error',event=>report(event.error||event.message));addEventListener('unhandledrejection',event=>report(event.reason));
const $=selector=>stage.querySelector(selector),$$=selector=>[...stage.querySelectorAll(selector)];
const value=key=>$('[data-control="'+key+'"]').value,number=key=>Number(value(key));
const clamp=(x,a=0,b=1)=>Math.max(a,Math.min(b,x)),lerp=(a,b,t)=>a+(b-a)*t;
const setText=(selector,text)=>{const node=$(selector);if(node)node.textContent=text;};
const media=matchMedia('(prefers-reduced-motion: reduce)');
let isReduced=media.matches,playing=false,time=0,draw=()=>{},raf=0,last=0,disposed=false;
const cleanups=[],on=(target,type,fn,options)=>{target.addEventListener(type,fn,options);cleanups.push(()=>target.removeEventListener(type,fn,options));};
const listen=(key,fn)=>on($('[data-action="'+key+'"]'),'click',fn);
const repaint=()=>{if(!disposed){try{draw(0);}catch(error){report(error);}}};
const loop=now=>{raf=0;if(disposed||!playing||isReduced)return;const dt=Math.min((now-last)/1000,.05);last=now;time+=dt;try{draw(dt);}catch(error){report(error);stop();return;}raf=requestAnimationFrame(loop);};
function stop(){playing=false;cancelAnimationFrame(raf);raf=0;$$('[data-play]').forEach(button=>{button.setAttribute('aria-pressed','false');button.textContent=isReduced?'Static view active':'Play motion';});}
function start(){if(isReduced)return;playing=true;last=performance.now();$$('[data-play]').forEach(button=>{button.setAttribute('aria-pressed','true');button.textContent='Pause motion';});if(!raf)raf=requestAnimationFrame(loop);}
function applyMotionPreference(){isReduced=media.matches||$('[data-static]').checked;stage.dataset.reduced=String(isReduced);if(isReduced)stop();$$('[data-play]').forEach(button=>{button.disabled=isReduced;button.textContent=playing?'Pause motion':isReduced?'Static view active':'Play motion';});repaint();}
function install(render){draw=render;applyMotionPreference();}
const observe=()=>{const root=document.getElementById('root'),elements=[...root.querySelectorAll('*')],rect=root.getBoundingClientRect();parent.postMessage({type:'sg-preview-observation',id,diagnostics:{textLength:root.textContent.trim().length,elementCount:elements.length,visibleElementCount:elements.filter(element=>{const r=element.getBoundingClientRect(),s=getComputedStyle(element);return r.width>0&&r.height>0&&s.display!=='none'&&s.visibility!=='hidden'&&Number(s.opacity)!==0;}).length,images:[],canvases:$$('canvas').map(c=>({width:c.width,height:c.height})),rootRect:{width:rect.width,height:rect.height},documentWidth:document.documentElement.scrollWidth,viewportWidth:innerWidth}},'*');};
on(media,'change',applyMotionPreference);on($('[data-static]'),'change',applyMotionPreference);
$$('[data-play]').forEach(button=>on(button,'click',()=>playing?stop():start()));
$$('[data-control]').forEach(input=>on(input,'input',()=>{const output=$('[data-value="'+input.dataset.control+'"]');if(output)output.textContent=input.value;if(input.dataset.control!=='story')repaint();}));
on(document,'visibilitychange',()=>{if(document.hidden)stop();});
on(window,'pagehide',()=>{disposed=true;stop();cleanups.forEach(fn=>fn());});
function canvas2D(selector,width=900,height=580){const canvas=$(selector);canvas.width=width;canvas.height=height;const context=canvas.getContext('2d');if(!context)throw Error('A 2D drawing surface is unavailable.');return {canvas,ctx:context,width,height};}
function createGL(canvas,fragment,vertex){const gl=canvas.getContext('webgl',{alpha:false,antialias:true,preserveDrawingBuffer:true});if(!gl){canvas.hidden=true;const fallback=$('[data-gl-fallback]');if(fallback)fallback.hidden=false;throw Error('WebGL is unavailable. The study explanation and controls remain readable.');}
const shader=(type,source)=>{const s=gl.createShader(type);gl.shaderSource(s,source);gl.compileShader(s);if(!gl.getShaderParameter(s,gl.COMPILE_STATUS))throw Error(gl.getShaderInfoLog(s));return s;};
const vs=shader(gl.VERTEX_SHADER,vertex||'attribute vec2 aPosition;varying vec2 vUv;void main(){vUv=aPosition*.5+.5;gl_Position=vec4(aPosition,0.,1.);}'),fs=shader(gl.FRAGMENT_SHADER,fragment),program=gl.createProgram();gl.attachShader(program,vs);gl.attachShader(program,fs);gl.linkProgram(program);if(!gl.getProgramParameter(program,gl.LINK_STATUS))throw Error(gl.getProgramInfoLog(program));gl.useProgram(program);
const buffer=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,buffer);if(!vertex){gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]),gl.STATIC_DRAW);const location=gl.getAttribLocation(program,'aPosition');gl.enableVertexAttribArray(location);gl.vertexAttribPointer(location,2,gl.FLOAT,false,0,0);}
const uniforms=new Map(),uniform=(name,...args)=>{if(!uniforms.has(name))uniforms.set(name,gl.getUniformLocation(program,name));const location=uniforms.get(name);if(location===null)return;if(args[0] instanceof Float32Array)gl.uniform3fv(location,args[0]);else gl['uniform'+args.length+'f'](location,...args);};
function resize(){const r=canvas.getBoundingClientRect();canvas.width=Math.max(1,Math.round(Math.min(r.width,850)));canvas.height=Math.max(1,Math.round(canvas.width/(r.width/Math.max(1,r.height))));gl.viewport(0,0,canvas.width,canvas.height);uniform('uResolution',canvas.width,canvas.height);repaint();}
const observer=new ResizeObserver(resize);observer.observe(canvas);cleanups.push(()=>{observer.disconnect();gl.deleteBuffer(buffer);gl.deleteProgram(program);gl.deleteShader(vs);gl.deleteShader(fs);});resize();return {gl,program,buffer,uniform,resize};}
try{
function renderMoonStory(progress){const approach=clamp(progress/.65),entry=clamp((progress-.6)/.4),x=number('viewX')/100,y=number('viewY')/100,scale=.7+approach*.65+entry*3.6;$('[data-world-orb]').style.transform='translate('+(x*14+progress*10)+'px,'+(y*12-progress*30)+'px) scale('+scale+') rotate('+(progress*28+x*3)+'deg)';$('[data-world-orb]').style.opacity=String(1-clamp((entry-.15)/.55));$('[data-interior]').style.opacity=String(clamp(entry*1.5));$('[data-interior]').style.transform='scale('+(1.16-entry*.16)+') translate('+(x*entry*8)+'px,'+(y*entry*5)+'px)';setText('[data-moon-value]',String(Math.round(progress*100)).padStart(2,'0'));}
let storyGeometry={start:0,distance:1},storyProgress=0,storyQueued=0,wasReduced=null;
function storyMeasure(){const track=$('[data-story-track]'),pin=$('[data-story-pin]');if(isReduced||!track.offsetHeight)return;const top=parseFloat(getComputedStyle(pin).top)||0;storyGeometry={start:track.getBoundingClientRect().top+scrollY-top,distance:Math.max(1,track.offsetHeight-pin.offsetHeight)};}
function seekStory(progress){if(isReduced){setText('[data-feedback]','Reading view exposes all three chapters in order.');return;}storyMeasure();scrollTo({top:Math.max(0,storyGeometry.start+clamp(progress)*storyGeometry.distance),behavior:'instant'});storyProgress=clamp(progress);repaint();}
function mountStory(renderer){stage.dataset.storyEnhanced='true';function renderStory(){if(wasReduced!==isReduced){wasReduced=isReduced;storyMeasure();$('[data-action="reading"]').setAttribute('aria-pressed',String(isReduced));$('[data-action="reading"]').textContent=media.matches?'System static view':isReduced?'Return to story':'Reading view';$('[data-action="reading"]').disabled=media.matches;}if(!isReduced){storyMeasure();storyProgress=clamp((scrollY-storyGeometry.start)/storyGeometry.distance);renderer(storyProgress);const chapter=Math.min(2,Math.round(storyProgress*2));$$('[data-chapter]').forEach((node,i)=>node.hidden=i!==chapter);$('[data-control="story"]').value=String(storyProgress*100);setText('[data-value="story"]',Math.round(storyProgress*100));}setText('[data-story-diagnostics]','DOCUMENT PROGRESS / '+storyProgress.toFixed(3)+' · START / '+Math.round(storyGeometry.start)+'px · DISTANCE / '+Math.round(storyGeometry.distance)+'px · MODE / '+(isReduced?'READING':'STICKY SCRUB'));}
on(window,'scroll',()=>{if(storyQueued)return;storyQueued=requestAnimationFrame(()=>{storyQueued=0;repaint();});},{passive:true});on(window,'resize',()=>{storyMeasure();repaint();});on(window,'pageshow',()=>{storyMeasure();repaint();});on($('[data-control="story"]'),'input',()=>seekStory(number('story')/100));for(let i=0;i<3;i++)listen('chapter-'+i,()=>seekStory(i/2));listen('reading',()=>{$('[data-static]').checked=!isReduced;applyMotionPreference();if(isReduced)$('.story-reading').scrollIntoView({block:'start',behavior:'instant'});});cleanups.push(()=>cancelAnimationFrame(storyQueued));install(renderStory);}
on($('[data-moon-surface]'),'pointermove',event=>{if(isReduced)return;const r=event.currentTarget.getBoundingClientRect();$('[data-control="viewX"]').value=String(clamp((event.clientX-r.left)/r.width*200-100,-100,100));$('[data-control="viewY"]').value=String(clamp((event.clientY-r.top)/r.height*200-100,-100,100));repaint();});mountStory(renderMoonStory);
}catch(error){report(error);}
requestAnimationFrame(()=>requestAnimationFrame(()=>{if(preview.status!=='error'){preview.status='mounted';document.body.dataset.previewStatus='mounted';parent.postMessage({type:'sg-preview-ready',id},'*');observe();setTimeout(observe,700);}}));
})();</script></body></html>
styles.css독립 구현
/* Generated by scripts/build-codrops-article-studies.mjs.
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.
Scope: independently authored study HTML, CSS, JavaScript, shaders and SVG only. Original articles, source projects, brands, artwork and screenshots are excluded. Their licenses and acquisition dispositions are unchanged.
*/
*{box-sizing:border-box}html{color-scheme:dark}html,body{margin:0;min-height:100%}body{background:var(--paper,#0c1321);color:var(--ink,#f4f3e9);font-family:Arial,Helvetica,sans-serif}button,input,select{font:inherit}button,select,input{min-width:0}button{background:transparent;border:1px solid #ffffff40;border-radius:999px;color:inherit;cursor:pointer;min-height:40px;padding:10px 16px}button:hover{background:#ffffff15}button[aria-pressed=true]{background:var(--accent,#dbff78);border-color:transparent;color:#122014}button:disabled{cursor:default;opacity:.6}button:focus-visible,input:focus-visible,select:focus-visible,summary:focus-visible,a:focus-visible{outline:3px solid var(--accent,#dbff78);outline-offset:4px}input,select{accent-color:var(--accent,#dbff78)}select,input[type=text],input[type=number]{background:#132235;border:1px solid #ffffff50;border-radius:7px;color:#fff;min-height:38px;padding:8px;width:100%}input[type=range]{display:block;min-height:30px;width:100%}a{color:inherit}svg{display:block;max-width:100%}h1,h2,p,figure{margin:0}h1{font-size:clamp(36px,6.5vw,78px);font-weight:500;letter-spacing:-.06em;line-height:.99}h2{font-size:24px;font-weight:500;letter-spacing:-.025em}p{line-height:1.55}.study{isolation:isolate;min-height:100vh;padding:clamp(18px,3.8vw,48px)}.masthead{align-items:center;display:flex;flex-wrap:wrap;font:10px/1.5 ui-monospace,monospace;gap:16px;justify-content:space-between;letter-spacing:.11em;margin-bottom:35px;text-transform:uppercase}.masthead strong{font-size:12px;letter-spacing:-.02em}.intro{display:grid;gap:18px;grid-template-columns:minmax(0,1.5fr) minmax(0,1fr);margin-bottom:30px;align-items:end}.intro p{color:var(--muted,#b7c7d4);font-size:13px;max-width:38em}.eyebrow{color:var(--accent,#dbff78);font:10px/1.4 ui-monospace,monospace;letter-spacing:.14em;margin-bottom:12px;text-transform:uppercase}.workbench{display:grid;gap:20px;grid-template-columns:minmax(0,1fr) 230px}.visual{background:var(--surface,#101d2b);border:1px solid #ffffff20;border-radius:20px;min-width:0;overflow:hidden;position:relative}.drawing{height:auto;width:100%}.art-canvas{aspect-ratio:1.55;display:block;height:auto;width:100%}.panel{align-content:start;display:grid;gap:17px}.control{display:grid;font-size:11px;gap:7px;min-width:0}.control>span{display:flex;gap:10px;justify-content:space-between}.control output{color:var(--accent,#dbff78);font-family:ui-monospace,monospace}.controls{display:flex;flex-wrap:wrap;gap:8px}.readout{background:#ffffff09;border:1px solid #ffffff18;border-radius:12px;font:11px/1.7 ui-monospace,monospace;overflow-wrap:anywhere;padding:14px;white-space:pre-line}.legend{align-items:center;display:flex;flex-wrap:wrap;font:10px/1.6 ui-monospace,monospace;gap:16px;padding:16px 20px}.legend i{background:var(--accent,#dbff78);border-radius:50%;display:inline-block;height:6px;margin-right:6px;width:6px}.contract{border-top:1px solid #ffffff20;color:var(--muted,#b7c7d4);font-size:11px;margin-top:28px;padding-top:18px}.contract summary{color:var(--ink,#f4f3e9);cursor:pointer;font-size:12px}.contract p{margin-top:10px;max-width:90ch}.motion-bar{align-items:center;border-top:1px solid #ffffff20;display:flex;flex-wrap:wrap;font-size:11px;gap:12px;justify-content:space-between;margin-top:26px;padding-top:18px}.motion-bar label{align-items:center;display:flex;gap:8px}.feedback{color:var(--muted,#b7c7d4);font:11px/1.5 ui-monospace,monospace;min-height:18px}.visually-hidden{clip-path:inset(50%);height:1px;overflow:hidden;position:absolute;width:1px}[hidden]{display:none!important}.stage-note{background:#07111ac9;bottom:18px;color:#dfe8f0;font:11px/1.5 ui-monospace,monospace;left:18px;max-width:calc(100% - 36px);padding:8px 12px;position:absolute;z-index:2}.big-number{font-size:clamp(70px,14vw,180px);letter-spacing:-.08em;line-height:1}.plain-list{display:grid;gap:12px;list-style:none;margin:0;padding:0}.plain-list li{border-bottom:1px solid #ffffff20;padding:12px 0}.tabs{display:flex;flex-wrap:wrap;gap:7px}.tabs button{font-size:11px}.two{display:grid;gap:20px;grid-template-columns:1fr 1fr}.code-sample{color:#c9ecbe;font:11px/1.7 ui-monospace,monospace;overflow:auto;white-space:pre-wrap}.fallback{padding:30px}.fallback p{max-width:38ch}.static-gallery{display:none}.study[data-reduced=true] .static-gallery{display:grid}.study[data-reduced=true] .animated-story{display:none}.study[data-reduced=true] *{animation:none!important;transition:none!important}body[data-preview-status=error] .feedback{color:#ffbba3}@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;scroll-behavior:auto!important;transition:none!important}}@media(max-width:700px){.intro{grid-template-columns:1fr}.workbench{grid-template-columns:1fr}.panel{grid-template-columns:repeat(2,minmax(0,1fr))}.panel>.readout,.panel>.controls{grid-column:1/-1}.masthead{margin-bottom:26px}.two{grid-template-columns:1fr}}@media(max-width:380px){.panel{gap:12px}.control{font-size:10px}.panel button{font-size:11px;padding:9px 12px}.legend{gap:8px;padding:12px}.visual{border-radius:13px}}
.story-controls{align-items:center;background:var(--paper,#0c1321);border-block:1px solid #ffffff20;display:grid;gap:14px;grid-template-columns:repeat(3,minmax(0,1fr));padding:15px 0;position:sticky;top:0;z-index:8}.story-controls>.controls{grid-column:1/-1}.story-track{display:none;height:1650px;position:relative}.story-pin{position:sticky;top:126px}.story-pin>.visual{min-height:450px}.story-copy{bottom:25px;left:30px;max-width:330px;pointer-events:none;position:absolute;z-index:4}.story-chapter>span{color:#eff0be;font:10px ui-monospace,monospace;letter-spacing:.12em}.story-chapter h2{font:43px/.98 Georgia,serif;margin:12px 0}.story-chapter p{color:#eff5e4;font-size:12px;max-width:30em;text-shadow:0 1px 5px #081320}.story-reading{display:grid;gap:24px;margin-top:28px}.reading-chapter{align-items:center;background:#ffffff06;border:1px solid #ffffff20;border-radius:15px;display:grid;gap:24px;grid-template-columns:1fr 1fr;overflow:hidden;padding:20px}.reading-chapter p{color:#bfd0ce;font-size:13px;margin-top:13px}.reading-chapter svg{border-radius:8px;width:100%}.study[data-story-enhanced=true][data-reduced=false] .story-track{display:block}.study[data-story-enhanced=true][data-reduced=false] .story-reading{display:none}.study[data-reduced=true] .story-track{display:none}.story-diagnostics{margin-top:15px}.story-skip{color:#c4d3ca;display:inline-block;font:11px ui-monospace,monospace;margin-bottom:15px}.story-end{height:1px}@media(max-width:700px){.story-controls{grid-template-columns:repeat(2,minmax(0,1fr))}.story-pin{top:170px}.story-pin>.visual{min-height:380px}.story-copy{bottom:22px;left:22px;max-width:calc(100% - 44px)}.story-chapter h2{font-size:34px}.story-chapter p{font-size:11px}.reading-chapter{grid-template-columns:1fr}.story-track{height:1450px}}@media(max-height:650px){.story-controls{position:relative}.story-pin{top:10px}}.moon-lab{inline-size:100%;max-inline-size:100%;aspect-ratio:1.45;background:radial-gradient(ellipse at 50% 30%,#305266,#0c2334 55%,#0d1b2a);isolation:isolate;min-height:500px}.moon-stars{background-image:radial-gradient(circle,#b5d5d4 1px,transparent 1.5px),radial-gradient(circle,#e3d6ae 1px,transparent 1.5px);background-position:0 0,29px 43px;background-size:83px 101px,127px 151px;inset:0;opacity:.55;position:absolute}.world-orb{height:100%;left:15%;position:absolute;top:-4%;transform-origin:50% 50%;width:75%;will-change:transform,opacity}.world-orb svg{height:100%;width:100%}.observatory-interior{inset:0;opacity:0;position:absolute}.observatory-interior svg{height:100%;object-fit:cover;width:100%}.moon-lab::after{background:linear-gradient(transparent 45%,#0c1d2ddd);content:'';inset:0;pointer-events:none;position:absolute}.moon-progress{color:#d6dfc9;font:12px ui-monospace,monospace;position:absolute;right:25px;top:25px;z-index:3}@media(max-width:600px){.moon-lab{aspect-ratio:.85;min-height:430px}.world-orb{left:0;top:-13%;width:100%}}
@media(max-height:550px) and (min-width:500px){
.study{padding:18px}.masthead{font-size:8px;gap:10px;margin-bottom:16px}.masthead strong{font-size:10px}.intro{gap:18px;grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);margin-bottom:18px}.intro h1{font-size:34px}.intro p{font-size:10px;line-height:1.5}.intro .eyebrow{font-size:8px;margin-bottom:8px}.workbench{gap:16px;grid-template-columns:minmax(0,1fr) 174px}.panel{gap:10px;grid-template-columns:1fr}.panel .control{font-size:9px;gap:3px}.panel .control input[type=range]{min-height:22px}.panel select,.panel input[type=text],.panel input[type=number]{font-size:10px;min-height:31px;padding:6px}.panel .controls{gap:5px}.panel button{font-size:9px;min-height:30px;padding:7px 10px}.panel .readout{font-size:8px;padding:10px}.art-canvas{aspect-ratio:auto!important;height:250px;object-fit:contain}.legend{font-size:8px;gap:8px;padding:10px 13px}.stage-note{bottom:12px;font-size:8px;left:12px;padding:5px 8px}.type-lab{min-height:280px;padding:23px}.type-heading{font-size:36px}.particle-rack{height:80px}.type-rule{font-size:7px}.bounce-lab>.drawing{height:230px;object-fit:contain}.track-graph{padding:9px 16px}.track-graph svg{height:43px}.member-lab{min-height:300px;padding:18px}.member-heading h2{font-size:24px}.member-collage{height:180px}.member-total .counter{font-size:52px}.member-total>span{font-size:7px}.member-card span{font-size:6px;padding:4px}.composer-surface{padding:20px}.composer-label{font-size:8px;margin-bottom:20px}.form-set{gap:10px}.form-set h2{font-size:20px;margin-top:12px}.form-set p{font-size:9px}.timeline-rows{padding:12px 17px}.mascot-lab>.drawing{height:250px;object-fit:contain}.pose-strip{padding:10px 14px}.pose-marker{font-size:8px;padding:6px 0}.fit-stage{min-height:270px;padding:20px}.fit-stage canvas{max-height:235px}.tree-columns{grid-template-columns:125px minmax(0,1fr);min-height:320px}.tree-inspector{padding:17px 12px}.tree-inspector pre{font-size:8px;margin-top:18px}.tree-rules{display:none}.tree-preview{min-height:0;padding:14px}.tree-width-label,.tree-caption{font-size:7px}.fixture-copy h2{font-size:1.6em}.fixture-copy p{font-size:.65em}.fixture-output{gap:10px;padding:12px}.fixture-art{max-height:90px}.semantic-lab{grid-template-columns:110px minmax(0,1fr);min-height:320px}.node-list{flex-direction:column;padding:12px 7px}.node-list button{font-size:8px;gap:5px;padding:9px 7px}.node-list button small{font-size:7px}.semantic-preview{padding:14px}.semantic-fixture{padding:8px}.semantic-fixture h2{font-size:27px}.semantic-fixture p{font-size:10px}.semantic-art{height:75px}.markup-panel{padding:15px}.markup-panel pre{font-size:8px}.plant-lab{padding:18px}.plant-heading h2{font-size:28px}.plant-heading span{font-size:8px}.plant-illustration{margin:-60px 0 -8px}.plant-illustration svg{height:250px}.plant-callouts{gap:5px}.plant-callouts button{font-size:7px;min-height:28px;padding:7px}.plant-feature,.care-plan{font-size:10px}.orbit-lab{min-height:300px}.orbit-camera{height:270px}.orbit-ring{height:170px;width:110px}.orbit-card{height:170px;width:110px}.orbit-foot{font-size:8px;padding:10px 14px}.botanical-window{aspect-ratio:1.5}.window-label h2{font-size:29px}.window-label span{font-size:8px}.gold-lab{padding:18px}.gold-heading h2{font-size:28px;margin-top:9px}.gold-heading>span,.gold-total>span{font-size:7px}.gold-lab>svg{height:175px;margin:-27px 0 -6px}.gold-total{padding-top:9px}.gold-total output{font-size:43px}.gold-disclaimer{font-size:9px}.story-controls{gap:10px;grid-template-columns:repeat(4,minmax(0,1fr));padding:10px 0;position:relative}.story-controls .control{font-size:8px}.story-controls input[type=range]{min-height:20px}.story-controls>.controls{grid-column:auto}.story-controls button{font-size:8px;min-height:27px;padding:6px 8px}.story-pin{top:10px}.story-pin>.visual{min-height:270px}.story-pin .art-canvas{height:270px}.story-copy{bottom:20px;left:20px;max-width:255px}.story-chapter h2{font-size:29px;margin:8px 0}.story-chapter p{font-size:10px}.story-chapter>span{font-size:8px}.moon-lab{aspect-ratio:auto;min-height:270px}.moon-progress,.cylinder-energy,.terrain-coordinates{font-size:8px}.story-skip{font-size:9px;margin-bottom:10px}.reading-chapter{grid-template-columns:1fr 1fr}.motion-bar{margin-top:18px}
}
함께 쓰는 파일 5개 보기
script.js독립 구현
/* Generated by scripts/build-codrops-article-studies.mjs.
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.
Scope: independently authored study HTML, CSS, JavaScript, shaders and SVG only. Original articles, source projects, brands, artwork and screenshots are excluded. Their licenses and acquisition dispositions are unchanged.
*/
(() => {
'use strict';
const id="codrops-eecfba24b649",stage=document.querySelector('.study');
const preview=window.__STYLEGALLERY_PREVIEW__={id,status:'loading',errors:[]};
const report=error=>{const message=error instanceof Error?error.message:String(error);if(!preview.errors.includes(message))preview.errors.push(message);preview.status='error';document.body.dataset.previewStatus='error';parent.postMessage({type:'sg-preview-error',id,message},'*');const feedback=document.querySelector('[data-feedback]');if(feedback)feedback.textContent=message;};
addEventListener('error',event=>report(event.error||event.message));addEventListener('unhandledrejection',event=>report(event.reason));
const $=selector=>stage.querySelector(selector),$$=selector=>[...stage.querySelectorAll(selector)];
const value=key=>$('[data-control="'+key+'"]').value,number=key=>Number(value(key));
const clamp=(x,a=0,b=1)=>Math.max(a,Math.min(b,x)),lerp=(a,b,t)=>a+(b-a)*t;
const setText=(selector,text)=>{const node=$(selector);if(node)node.textContent=text;};
const media=matchMedia('(prefers-reduced-motion: reduce)');
let isReduced=media.matches,playing=false,time=0,draw=()=>{},raf=0,last=0,disposed=false;
const cleanups=[],on=(target,type,fn,options)=>{target.addEventListener(type,fn,options);cleanups.push(()=>target.removeEventListener(type,fn,options));};
const listen=(key,fn)=>on($('[data-action="'+key+'"]'),'click',fn);
const repaint=()=>{if(!disposed){try{draw(0);}catch(error){report(error);}}};
const loop=now=>{raf=0;if(disposed||!playing||isReduced)return;const dt=Math.min((now-last)/1000,.05);last=now;time+=dt;try{draw(dt);}catch(error){report(error);stop();return;}raf=requestAnimationFrame(loop);};
function stop(){playing=false;cancelAnimationFrame(raf);raf=0;$$('[data-play]').forEach(button=>{button.setAttribute('aria-pressed','false');button.textContent=isReduced?'Static view active':'Play motion';});}
function start(){if(isReduced)return;playing=true;last=performance.now();$$('[data-play]').forEach(button=>{button.setAttribute('aria-pressed','true');button.textContent='Pause motion';});if(!raf)raf=requestAnimationFrame(loop);}
function applyMotionPreference(){isReduced=media.matches||$('[data-static]').checked;stage.dataset.reduced=String(isReduced);if(isReduced)stop();$$('[data-play]').forEach(button=>{button.disabled=isReduced;button.textContent=playing?'Pause motion':isReduced?'Static view active':'Play motion';});repaint();}
function install(render){draw=render;applyMotionPreference();}
const observe=()=>{const root=document.getElementById('root'),elements=[...root.querySelectorAll('*')],rect=root.getBoundingClientRect();parent.postMessage({type:'sg-preview-observation',id,diagnostics:{textLength:root.textContent.trim().length,elementCount:elements.length,visibleElementCount:elements.filter(element=>{const r=element.getBoundingClientRect(),s=getComputedStyle(element);return r.width>0&&r.height>0&&s.display!=='none'&&s.visibility!=='hidden'&&Number(s.opacity)!==0;}).length,images:[],canvases:$$('canvas').map(c=>({width:c.width,height:c.height})),rootRect:{width:rect.width,height:rect.height},documentWidth:document.documentElement.scrollWidth,viewportWidth:innerWidth}},'*');};
on(media,'change',applyMotionPreference);on($('[data-static]'),'change',applyMotionPreference);
$$('[data-play]').forEach(button=>on(button,'click',()=>playing?stop():start()));
$$('[data-control]').forEach(input=>on(input,'input',()=>{const output=$('[data-value="'+input.dataset.control+'"]');if(output)output.textContent=input.value;if(input.dataset.control!=='story')repaint();}));
on(document,'visibilitychange',()=>{if(document.hidden)stop();});
on(window,'pagehide',()=>{disposed=true;stop();cleanups.forEach(fn=>fn());});
function canvas2D(selector,width=900,height=580){const canvas=$(selector);canvas.width=width;canvas.height=height;const context=canvas.getContext('2d');if(!context)throw Error('A 2D drawing surface is unavailable.');return {canvas,ctx:context,width,height};}
function createGL(canvas,fragment,vertex){const gl=canvas.getContext('webgl',{alpha:false,antialias:true,preserveDrawingBuffer:true});if(!gl){canvas.hidden=true;const fallback=$('[data-gl-fallback]');if(fallback)fallback.hidden=false;throw Error('WebGL is unavailable. The study explanation and controls remain readable.');}
const shader=(type,source)=>{const s=gl.createShader(type);gl.shaderSource(s,source);gl.compileShader(s);if(!gl.getShaderParameter(s,gl.COMPILE_STATUS))throw Error(gl.getShaderInfoLog(s));return s;};
const vs=shader(gl.VERTEX_SHADER,vertex||'attribute vec2 aPosition;varying vec2 vUv;void main(){vUv=aPosition*.5+.5;gl_Position=vec4(aPosition,0.,1.);}'),fs=shader(gl.FRAGMENT_SHADER,fragment),program=gl.createProgram();gl.attachShader(program,vs);gl.attachShader(program,fs);gl.linkProgram(program);if(!gl.getProgramParameter(program,gl.LINK_STATUS))throw Error(gl.getProgramInfoLog(program));gl.useProgram(program);
const buffer=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,buffer);if(!vertex){gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]),gl.STATIC_DRAW);const location=gl.getAttribLocation(program,'aPosition');gl.enableVertexAttribArray(location);gl.vertexAttribPointer(location,2,gl.FLOAT,false,0,0);}
const uniforms=new Map(),uniform=(name,...args)=>{if(!uniforms.has(name))uniforms.set(name,gl.getUniformLocation(program,name));const location=uniforms.get(name);if(location===null)return;if(args[0] instanceof Float32Array)gl.uniform3fv(location,args[0]);else gl['uniform'+args.length+'f'](location,...args);};
function resize(){const r=canvas.getBoundingClientRect();canvas.width=Math.max(1,Math.round(Math.min(r.width,850)));canvas.height=Math.max(1,Math.round(canvas.width/(r.width/Math.max(1,r.height))));gl.viewport(0,0,canvas.width,canvas.height);uniform('uResolution',canvas.width,canvas.height);repaint();}
const observer=new ResizeObserver(resize);observer.observe(canvas);cleanups.push(()=>{observer.disconnect();gl.deleteBuffer(buffer);gl.deleteProgram(program);gl.deleteShader(vs);gl.deleteShader(fs);});resize();return {gl,program,buffer,uniform,resize};}
try{
function renderMoonStory(progress){const approach=clamp(progress/.65),entry=clamp((progress-.6)/.4),x=number('viewX')/100,y=number('viewY')/100,scale=.7+approach*.65+entry*3.6;$('[data-world-orb]').style.transform='translate('+(x*14+progress*10)+'px,'+(y*12-progress*30)+'px) scale('+scale+') rotate('+(progress*28+x*3)+'deg)';$('[data-world-orb]').style.opacity=String(1-clamp((entry-.15)/.55));$('[data-interior]').style.opacity=String(clamp(entry*1.5));$('[data-interior]').style.transform='scale('+(1.16-entry*.16)+') translate('+(x*entry*8)+'px,'+(y*entry*5)+'px)';setText('[data-moon-value]',String(Math.round(progress*100)).padStart(2,'0'));}
let storyGeometry={start:0,distance:1},storyProgress=0,storyQueued=0,wasReduced=null;
function storyMeasure(){const track=$('[data-story-track]'),pin=$('[data-story-pin]');if(isReduced||!track.offsetHeight)return;const top=parseFloat(getComputedStyle(pin).top)||0;storyGeometry={start:track.getBoundingClientRect().top+scrollY-top,distance:Math.max(1,track.offsetHeight-pin.offsetHeight)};}
function seekStory(progress){if(isReduced){setText('[data-feedback]','Reading view exposes all three chapters in order.');return;}storyMeasure();scrollTo({top:Math.max(0,storyGeometry.start+clamp(progress)*storyGeometry.distance),behavior:'instant'});storyProgress=clamp(progress);repaint();}
function mountStory(renderer){stage.dataset.storyEnhanced='true';function renderStory(){if(wasReduced!==isReduced){wasReduced=isReduced;storyMeasure();$('[data-action="reading"]').setAttribute('aria-pressed',String(isReduced));$('[data-action="reading"]').textContent=media.matches?'System static view':isReduced?'Return to story':'Reading view';$('[data-action="reading"]').disabled=media.matches;}if(!isReduced){storyMeasure();storyProgress=clamp((scrollY-storyGeometry.start)/storyGeometry.distance);renderer(storyProgress);const chapter=Math.min(2,Math.round(storyProgress*2));$$('[data-chapter]').forEach((node,i)=>node.hidden=i!==chapter);$('[data-control="story"]').value=String(storyProgress*100);setText('[data-value="story"]',Math.round(storyProgress*100));}setText('[data-story-diagnostics]','DOCUMENT PROGRESS / '+storyProgress.toFixed(3)+' · START / '+Math.round(storyGeometry.start)+'px · DISTANCE / '+Math.round(storyGeometry.distance)+'px · MODE / '+(isReduced?'READING':'STICKY SCRUB'));}
on(window,'scroll',()=>{if(storyQueued)return;storyQueued=requestAnimationFrame(()=>{storyQueued=0;repaint();});},{passive:true});on(window,'resize',()=>{storyMeasure();repaint();});on(window,'pageshow',()=>{storyMeasure();repaint();});on($('[data-control="story"]'),'input',()=>seekStory(number('story')/100));for(let i=0;i<3;i++)listen('chapter-'+i,()=>seekStory(i/2));listen('reading',()=>{$('[data-static]').checked=!isReduced;applyMotionPreference();if(isReduced)$('.story-reading').scrollIntoView({block:'start',behavior:'instant'});});cleanups.push(()=>cancelAnimationFrame(storyQueued));install(renderStory);}
on($('[data-moon-surface]'),'pointermove',event=>{if(isReduced)return;const r=event.currentTarget.getBoundingClientRect();$('[data-control="viewX"]').value=String(clamp((event.clientX-r.left)/r.width*200-100,-100,100));$('[data-control="viewY"]').value=String(clamp((event.clientY-r.top)/r.height*200-100,-100,100));repaint();});mountStory(renderMoonStory);
}catch(error){report(error);}
requestAnimationFrame(()=>requestAnimationFrame(()=>{if(preview.status!=='error'){preview.status='mounted';document.body.dataset.previewStatus='mounted';parent.postMessage({type:'sg-preview-ready',id},'*');observe();setTimeout(observe,700);}}));
})();LICENSE독립 구현
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.
Scope: independently authored study HTML, CSS, JavaScript, shaders and SVG only. Original articles, source projects, brands, artwork and screenshots are excluded. Their licenses and acquisition dispositions are unchanged.
NOTES.md독립 구현
# From far away to within.
Independent article case study. Domain: website consumer / Design Engineering presentation.
A single progress evaluator blends an original SVG globe, atmospheric depth layers and an observatory interior. Document-owned scroll maps to bounded scale, translation and opacity; chapter availability changes immediately at explicit boundaries. Native view inputs replace pointer parallax and the static path exposes every chapter in ordinary flow.
## Attribution and evidence
Studied: [Interactive Storytelling for the Web: Building Immersive Stories with Timelines, 3D, and Layered Scenes](https://tympanus.net/codrops/2026/04/20/interactive-storytelling-for-the-web-building-immersive-stories-with-timelines-3d-and-layered-scenes/), Bjørn Fjellstad. Article SHA-256: 807b2a2644a63d7b037a67e04afc0a284f92687c543c127c4dd24e108ae48514. Analysis SHA-256: 95c24110cb1e3c384418c22a0b01b7f4906729cb36ce3ee3d42fe9cb8a23ab6b. Source revision: f30d439dd7f6cba8455eba7867c44eaef09a2f213daed7a501bf3e718515b31e. The revision hashes the article/analysis hashes, the analyst principle and code-block evidence references; it identifies studied evidence, not a claim that the original demo executes.
Original acquisition: unresolved. Original license: unverified. originalSourceAcquired: false. The product Visit request failed with HTTP403. The article separately links its story and states a free three-story scope, but no original story project or source export was acquired. This is not a paid exclusion.
No original article prose, code, artwork, source project or screenshot is distributed here. The authored-code MIT notice applies only to the independent implementation. Original SVG scene art and a browser progress controller replace the source project, generated panorama and authoring tool. No Instorier export, membership, paid image generator or 3D-provider connection is required.
## Initial state and controls
Approach an original pale world, move around its light, then enter an observatory. The same three chapters also work as a stationary reading sequence.
The page starts stationary. Play motion, where present, advances this study’s presentation until paused; text, bounce, portrait, orbit, strand and mascot motion loops, while the event composer stops at its endpoint. Scroll studies advance through ordinary document scroll or their chapter buttons. Static view stops time-based motion; manual controls still inspect values. The three scroll studies instead show every chapter in ordinary reading flow. Pointer parallax centers its decorative layers.
Initial control values:
| Control key | Value |
| --- | --- |
| story | 0 |
| viewX | 0 |
| viewY | 0 |
## Running and editing
Open index.html directly. It contains all runtime code and visuals and needs no package install, account, network, remote asset or browser-origin storage. Edit its inline style and script to change the downloaded page. styles.css and script.js are reference copies of the inline source; changing those copies alone does not change the running page. Repository regeneration overwrites index.html and all generated copies, including any manual edits. Keep a separate copy when editing a download. The repository authoring modules in vendor/codrops-article-studies/scenes-*.mjs and runtime.mjs regenerate these copies through node scripts/build-codrops-article-studies.mjs. Repository regeneration also needs the private source evidence; downloaded-page execution does not.
## Verification boundary
This generation passed the captured article/analysis hash checks, exact ID membership, local canonical Markdown anchor/hash checks, implementation-symbol checks, JavaScript parsing, semantic main/title counts, duplicate-ID checks and runtime URL/storage exclusion. The manifest codeFiles entries identify every emitted file by SHA-256. Each code symbol is a searchable named function, not a claimed executed call trace. Proposed checks are in KNOWLEDGE.json. runtime_verified: false. SG artifact capture proves only a recorded initial render; no interactive runtime, keyboard, accessibility, comfort or performance result is claimed.
Manual Chrome interaction is blocked by extension UI in this session. No alternate browser-control route was used. Preview sizing is native responsive width. Initial-render captures are tracked separately at site/artifacts/full-import/preview-posters/index.json and site/artifacts/full-import/preview-posters/visual-review.json in the repository. No capture receipt is bundled with this download. The bounded initial-render matrix requests all 21 studies at 320 pixels and three representative studies at 1280 pixels; the separate poster surface is 640 × 420. The authored CSS also adapts at 375 and 768 pixels, without claiming those widths were captured. A width request does not mean that capture exists or passed. Motion starts on explicit playback; system reduced motion and the Static view switch stop it.
consumer_reference: consumer-reference/agent-native/registry.json
KNOWLEDGE.json독립 구현
[
{
"id": "codrops-eecfba24b649-article-0",
"source": "motion/interaction-recipes.md",
"anchor": "scene-composition-contract",
"sourceSha256": "9f065be929f4ad34b867ae7666943aafb99c70ce7022787e935a0f869798f7b2",
"title": "16 / Layered three-scene story · renderMoonStory",
"principle": "One normalized document progress value drives layer opacity, camera-like scale and chapter selection, without hiding essential controls inside fading panels.",
"application": "A single progress evaluator blends an original SVG globe, atmospheric depth layers and an observatory interior. Document-owned scroll maps to bounded scale, translation and opacity; chapter availability changes immediately at explicit boundaries. Native view inputs replace pointer parallax and the static path exposes every chapter in ordinary flow. This binding describes the authored study and does not verify the original project.",
"code": [
{
"file": "vendor/codrops-article-studies/records/codrops-eecfba24b649/script.js",
"symbol": "renderMoonStory",
"explanation": "The named local function implements this mechanism in the downloadable standalone page; its source hash is listed in codeFiles."
}
],
"checks": [
{
"id": "codrops-eecfba24b649-renderMoonStory",
"action": "Visit all three chapter buttons, reverse, then use Reading view.",
"expected": "The same progress reconstructs the same composition; Reading view exposes every chapter in order without the scroll track."
}
],
"runtime_verified": false
},
{
"id": "codrops-eecfba24b649-article-1",
"source": "motion/accessible-motion.md",
"anchor": "classify-before-replacing",
"sourceSha256": "db0ad692d5bb3103a3cbe13ec08dbe5cf12552aed7ecf2c93b1d7cc0b8a34b8b",
"title": "16 / Layered three-scene story · mountStory",
"principle": "The reduced-motion path replaces the zooming scene with three ordinary sections and independent illustrations.",
"application": "A single progress evaluator blends an original SVG globe, atmospheric depth layers and an observatory interior. Document-owned scroll maps to bounded scale, translation and opacity; chapter availability changes immediately at explicit boundaries. Native view inputs replace pointer parallax and the static path exposes every chapter in ordinary flow. This binding describes the authored study and does not verify the original project.",
"code": [
{
"file": "vendor/codrops-article-studies/records/codrops-eecfba24b649/script.js",
"symbol": "mountStory",
"explanation": "The named local function implements this mechanism in the downloadable standalone page; its source hash is listed in codeFiles."
}
],
"checks": [
{
"id": "codrops-eecfba24b649-mountStory",
"action": "Load with reduced motion or enable Static view halfway through the story.",
"expected": "All chapter text and static illustrations appear in document flow, with no need to reach an intermediate zoom frame."
}
],
"runtime_verified": false
},
{
"id": "codrops-eecfba24b649-article-2",
"source": "motion/accessible-motion.md",
"anchor": "preference-changes-during-work",
"sourceSha256": "db0ad692d5bb3103a3cbe13ec08dbe5cf12552aed7ecf2c93b1d7cc0b8a34b8b",
"title": "16 / Layered three-scene story · applyMotionPreference",
"principle": "One effective preference owns CSS and script playback. The initial view is stationary, and manual controls retain the study values.",
"application": "A single progress evaluator blends an original SVG globe, atmospheric depth layers and an observatory interior. Document-owned scroll maps to bounded scale, translation and opacity; chapter availability changes immediately at explicit boundaries. Native view inputs replace pointer parallax and the static path exposes every chapter in ordinary flow. This binding describes the authored study and does not verify the original project.",
"code": [
{
"file": "vendor/codrops-article-studies/records/codrops-eecfba24b649/script.js",
"symbol": "applyMotionPreference",
"explanation": "The named local function implements this mechanism in the downloadable standalone page; its source hash is listed in codeFiles."
}
],
"checks": [
{
"id": "codrops-eecfba24b649-applyMotionPreference",
"action": "Enable Static view during playback, then adjust the visible native controls.",
"expected": "Playback stops, its button is disabled while the preference applies, and the current values remain inspectable without continuous motion."
}
],
"runtime_verified": false
}
]
RETRIEVAL-LOG.md독립 구현
# Retrieval log
Understood as: preserve all 21 original catalog IDs and acquisition dispositions while independently implementing each article’s technical principle as a consumer-owned case study.
SG discover and workflow read from site-compiler revision 6deb1970c80ed113b90be8d6ca617616bbe336c4; workflow SHA-256 0318a99707293af423e52b99b40cf1d87d9c7725e3ab06c5a231e3946f2bebb9. Stage 3 handoff is the primary implementation brief. No original scene assets or source files are reused.
Read-only canonical traversal:
1. AGENTS.md
2. README.md
3. DOMAINS.md
4. GOVERNANCE.md
5. design-engineering/index.md
6. motion/index.md
7. design-engineering/component-contract.md
8. design-engineering/state-management/patterns/derived-state.md
9. design-engineering/native-interaction-contracts.md
10. motion/accessible-motion.md
11. motion/rendering-and-performance.md
12. motion/interruption-and-retargeting.md
13. motion/interaction-recipes.md
Applied canonical sections and current-authoring hashes are recorded in KNOWLEDGE.json. No design-terminology records are relied on. External references within canonical guidance were not independently rechecked by this implementation lane; only the local sections and article capture identities were checked. Root Layout corpus, Game UI, provider integrations and publisher export claims were rejected as outside this lane.
BEHIND THE EXAMPLE
이 장면을 만드는 원리
16 / Layered three-scene story · renderMoonStory
One normalized document progress value drives layer opacity, camera-like scale and chapter selection, without hiding essential controls inside fading panels.
- 이 예제에서는
- A single progress evaluator blends an original SVG globe, atmospheric depth layers and an observatory interior. Document-owned scroll maps to bounded scale, translation and opacity; chapter availability changes immediately at explicit boundaries. Native view inputs replace pointer parallax and the static path exposes every chapter in ordinary flow. This binding describes the authored study and does not verify the original project.
코드와 함께 확인하기
코드에서 찾기
renderMoonStoryscript.jsThe named local function implements this mechanism in the downloadable standalone page; its source hash is listed in codeFiles.
직접 해보기
Visit all three chapter buttons, reverse, then use Reading view.
살펴볼 변화The same progress reconstructs the same composition; Reading view exposes every chapter in order without the scroll track.
16 / Layered three-scene story · mountStory
The reduced-motion path replaces the zooming scene with three ordinary sections and independent illustrations.
- 이 예제에서는
- A single progress evaluator blends an original SVG globe, atmospheric depth layers and an observatory interior. Document-owned scroll maps to bounded scale, translation and opacity; chapter availability changes immediately at explicit boundaries. Native view inputs replace pointer parallax and the static path exposes every chapter in ordinary flow. This binding describes the authored study and does not verify the original project.
코드와 함께 확인하기
코드에서 찾기
mountStoryscript.jsThe named local function implements this mechanism in the downloadable standalone page; its source hash is listed in codeFiles.
직접 해보기
Load with reduced motion or enable Static view halfway through the story.
살펴볼 변화All chapter text and static illustrations appear in document flow, with no need to reach an intermediate zoom frame.
16 / Layered three-scene story · applyMotionPreference
One effective preference owns CSS and script playback. The initial view is stationary, and manual controls retain the study values.
- 이 예제에서는
- A single progress evaluator blends an original SVG globe, atmospheric depth layers and an observatory interior. Document-owned scroll maps to bounded scale, translation and opacity; chapter availability changes immediately at explicit boundaries. Native view inputs replace pointer parallax and the static path exposes every chapter in ordinary flow. This binding describes the authored study and does not verify the original project.
코드와 함께 확인하기
코드에서 찾기
applyMotionPreferencescript.jsThe named local function implements this mechanism in the downloadable standalone page; its source hash is listed in codeFiles.
직접 해보기
Enable Static view during playback, then adjust the visible native controls.
살펴볼 변화Playback stops, its button is disabled while the preference applies, and the current values remain inspectable without continuous motion.
