Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions layouts/_partials/home.html
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,7 @@
}
</style>
<link rel="stylesheet" href="/assets/homepage-demo/lenis.css">
<link rel="stylesheet" href="/assets/homepage-demo/homepage-demo.css">
<link rel="stylesheet" href="/assets/homepage-demo/homepage-demo.css?v={{ printf "%.12s" (crypto.SHA256 (os.ReadFile "static/assets/homepage-demo/homepage-demo.css")) }}">
</head>
<body>

Expand Down Expand Up @@ -803,6 +803,6 @@
</script>
<script src="/assets/homepage-demo/lenis.min.js"></script>
<script src="/assets/homepage-demo/scroll-motion.js"></script>
<script src="/assets/homepage-demo/homepage-demo.js"></script>
<script src="/assets/homepage-demo/homepage-demo.js?v={{ printf "%.12s" (crypto.SHA256 (os.ReadFile "static/assets/homepage-demo/homepage-demo.js")) }}"></script>
</body>
</html>
2 changes: 1 addition & 1 deletion layouts/_partials/homepage-demo.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<section class="section telar-demo-section" id="demo" aria-labelledby="demo-title" data-telar-demo>
<section class="section telar-demo-section" aria-labelledby="demo-title" data-telar-demo>
<div class="telar-demo-layout">
<h2 id="demo-title" class="visually-hidden">Telar</h2>
<figure class="telar-demo-media">
Expand Down
18 changes: 11 additions & 7 deletions layouts/_partials/landing-body.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,20 @@ <h1 class="hero__title">Telar</h1>
</a>
</section>

<section class="section telar-about-section" id="about" aria-labelledby="about-title">
<div class="about telar-about-copy">
<h2 id="about-title"><span data-lang="en" lang="en">What is Telar?</span><span data-lang="es" lang="es">¿Qué es Telar?</span></h2>
<p data-lang="en" lang="en">Telar (Spanish for "loom") weaves together images, video, audio, narrative text, and layered contextual information into interactive visual narrative exhibitions. It follows minimal computing principles: plain text authoring, static generation, and sustainable hosting.</p>
<p data-lang="es" lang="es">Telar entreteje imágenes, video, audio, texto narrativo e información contextual en exhibiciones narrativas visuales e interactivas. Sigue los principios de computación mínima: autoría en texto plano, generación estática y alojamiento sostenible.</p>
<section class="section telar-about-section" id="about" aria-labelledby="about-title" data-telar-intro>
<div class="telar-intro-stage">
<div class="telar-intro-copy" data-intro-copy>
<div class="about telar-about-copy">
<h2 id="about-title"><span data-lang="en" lang="en">What is Telar?</span><span data-lang="es" lang="es">¿Qué es Telar?</span></h2>
<p data-lang="en" lang="en">Telar (Spanish for "loom") weaves together images, video, audio, narrative text, and layered contextual information into interactive visual narrative exhibitions. It follows minimal computing principles: plain text authoring, static generation, and sustainable hosting.</p>
<p data-lang="es" lang="es">Telar entreteje imágenes, video, audio, texto narrativo e información contextual en exhibiciones narrativas visuales e interactivas. Sigue los principios de computación mínima: autoría en texto plano, generación estática y alojamiento sostenible.</p>
</div>
</div>
{{ partial "homepage-demo.html" . }}
</div>
<span id="demo" class="telar-intro-demo-stop" aria-hidden="true"></span>
</section>

{{ partial "homepage-demo.html" . }}

<!-- Features Section -->
<section class="section features fade-in" id="features">
<div class="section__content">
Expand Down
5 changes: 4 additions & 1 deletion static/assets/homepage-demo/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Telar homepage video
The homepage uses normal document flow and the supplied Spanish/English Vimeo
embeds. The definition and viewport-fitted film occupy separate scroll steps. There is no native scroll-film renderer or local MP4 fetch.
embeds. The definition and viewport-fitted film share a sticky stage: the next scroll
step fades out the definition and reveals the video in place; the previous step
restores the definition. Hidden layers are inert and hidden from assistive
technology, and the video pauses while the definition is showing. There is no native scroll-film renderer or local MP4 fetch.

Only the active-language poster is loaded initially. IntersectionObserver creates
the iframe and loads Vimeo's SDK as the film enters view. Playback is muted and
Expand Down
18 changes: 15 additions & 3 deletions static/assets/homepage-demo/homepage-demo.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,18 @@ a:focus-visible,button:focus-visible,iframe:focus-visible{outline:3px solid var(
.hero__utility a{color:var(--cream);font-size:15px;text-decoration:underline;text-underline-offset:4px;opacity:.9}
.hero__utility a:hover{opacity:1}
.hero__scroll{bottom:20px}
.telar-about-section{background:var(--demo-background);min-height:100svh;padding:60px 24px}
.telar-about-section{display:block;background:var(--demo-background);padding:0}
.telar-intro-copy{padding:60px 24px}
.telar-about-section.is-enhanced{height:200svh;min-height:200svh;padding:0}
.is-enhanced .telar-intro-stage{position:sticky;top:0;height:100svh}
.is-enhanced .telar-intro-copy,.is-enhanced .telar-demo-section{position:absolute;inset:0;transition:opacity 250ms ease;}
.is-enhanced:not(.intro-ready) .telar-intro-copy,.is-enhanced:not(.intro-ready) .telar-demo-section{transition:none}
.is-enhanced .telar-intro-copy{display:flex;align-items:center;z-index:2}
.is-enhanced .telar-demo-section{min-height:0;opacity:0;pointer-events:none;z-index:1}
.is-enhanced.is-video .telar-intro-copy{opacity:0;pointer-events:none;z-index:1}
.is-enhanced.is-video .telar-demo-section{opacity:1;pointer-events:auto;z-index:2}
.telar-intro-demo-stop{position:absolute;width:1px;height:1px;pointer-events:none}
.is-enhanced .telar-intro-demo-stop{top:50%;left:0}
.telar-demo-section{background:var(--demo-background);min-height:100svh;padding:24px}
/* Fit the complete film inside one viewport, including on short desktop windows. */
.telar-demo-layout{width:100%;max-width:min(1600px,calc((100svh - 48px) * 16 / 9));margin:auto}
Expand Down Expand Up @@ -55,19 +66,20 @@ a:focus-visible,button:focus-visible,iframe:focus-visible{outline:3px solid var(
.landing-footer a:hover{color:var(--gold)}
@media(max-width:900px){
.telar-demo-section{min-height:auto}
.telar-about-section{min-height:auto;padding:64px 24px}
.telar-intro-copy{padding:64px 24px}
.telar-demo-media{width:100%}
}
@media(max-width:600px){
.hero{padding:24px 20px 68px}
.hero__lang-toggle button{min-height:44px}
.hero__utility{gap:4px 18px}
.telar-demo-section{padding:24px 16px}
.telar-about-section{padding:48px 20px}
.telar-intro-copy{padding:48px 20px}
.cta-section{padding:56px 20px}
.features__grid{gap:16px}
}
@media(prefers-reduced-motion:reduce){
.hero__scroll{animation:none}
.is-enhanced .telar-intro-copy,.is-enhanced .telar-demo-section{transition:none}
.fade-in{opacity:1;transform:none;transition:none}
}
35 changes: 32 additions & 3 deletions static/assets/homepage-demo/homepage-demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,15 @@
window.addEventListener('resize',manualInput);window.addEventListener('resize',()=>lenis.resize());
motion.addEventListener('change',preference);small.addEventListener('change',preference);

const intro=document.querySelector('[data-telar-intro]');
const introStage=intro?.querySelector('.telar-intro-stage'),introCopy=intro?.querySelector('[data-intro-copy]');
intro?.classList.add('is-enhanced');
const root=document.querySelector('[data-telar-demo]'),frame=root.querySelector('[data-demo-frame]');
const embed=root.querySelector('[data-demo-embed]'),poster=root.querySelector('[data-demo-poster]');
const error=root.querySelector('[data-demo-error]'),errorText=root.querySelector('[data-demo-error-text]'),errorLink=root.querySelector('[data-demo-error-link]');
const transcript=root.querySelector('[data-demo-transcript]');
window.addEventListener('scroll',()=>{
updateIntro();
// Cross-origin iframe wheel events do not bubble. Observe their native movement
// and hand the gesture to the same step controller, keeping Vimeo clickable.
if(!embed.querySelector('iframe')?.matches(':hover')){
Expand All @@ -133,6 +137,18 @@
},{passive:true});
const languages=JSON.parse(document.getElementById('telar-demo-config').textContent);
let sdkPromise=null,player=null,iframe=null,ready=false,playing=false,inView=false,userPaused=false,pauseExpected=false,generation=0,timeout=0,data;
function updateIntro(){
if(!intro)return;
const showVideo=(scrollY-layoutTop(intro))/Math.max(1,introStage.offsetHeight)>=.15;
const mode=showVideo?'video':'copy';if(intro.dataset.introState===mode)return;
intro.dataset.introState=mode;intro.classList.toggle('is-video',showVideo);
introCopy.inert=showVideo;introCopy.setAttribute('aria-hidden',String(showVideo));
root.inert=!showVideo;root.setAttribute('aria-hidden',String(!showVideo));
if(showVideo&&introCopy.contains(document.activeElement))focusTarget(root.querySelector('h2'));
else if(!showVideo&&root.contains(document.activeElement))focusTarget(introCopy.querySelector('h2'));
syncPlayback();
}
function videoRevealed(){return !intro||intro.dataset.introState==='video'}
function sdk(){
if(window.Vimeo?.Player)return Promise.resolve(window.Vimeo);
if(sdkPromise)return sdkPromise;
Expand All @@ -152,7 +168,7 @@
}
function syncPlayback(){
if(!ready||!player)return;
if(!inView||document.hidden){suspend();return}
if(!inView||!videoRevealed()||document.hidden){suspend();return}
if(!motion.matches&&!userPaused)player.play().catch(()=>{root.dataset.videoState='paused'});
}
function loadPlayer(){
Expand All @@ -170,7 +186,7 @@
current.on('play',()=>{
if(token!==generation)return;
playing=true;userPaused=false;root.dataset.videoState='playing';
if(!inView||document.hidden)suspend();
if(!inView||!videoRevealed()||document.hidden)suspend();
});
current.on('pause',()=>{
if(token!==generation)return;
Expand Down Expand Up @@ -209,7 +225,20 @@
syncPlayback();
},{threshold:[0,.1]});
document.addEventListener('visibilitychange',syncPlayback);
document.addEventListener('telar:languagechange',language);language();visible.observe(frame);
document.addEventListener('telar:languagechange',language);language();updateIntro();visible.observe(frame);
function restoreIntroLink(){
if(!intro||!['#about','#demo'].includes(location.hash))return;
stops();const position=layoutTop(document.querySelector(location.hash));
document.documentElement.classList.add('is-stepping');
lenis.scrollTo(position,{immediate:true});travel.reset(position);pendingTarget=null;
document.documentElement.classList.remove('is-stepping');updateIntro();
}
let introInput=false;
for(const type of ['wheel','keydown','touchstart','pointerdown'])window.addEventListener(type,()=>{introInput=true},{once:true,passive:true});
requestAnimationFrame(()=>{intro?.classList.add('intro-ready');restoreIntroLink()});
window.addEventListener('hashchange',restoreIntroLink);
window.addEventListener('load',()=>{if(!introInput)restoreIntroLink()});
window.addEventListener('resize',updateIntro);
window.addEventListener('pagehide',event=>{
suspend();if(event.persisted)return;
clearTimeout(timeout);visible.disconnect();cancelAnimationFrame(raf);
Expand Down
Loading