Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aecd0471fa | ||
|
|
48f0af927a | ||
|
|
b73b057862 | ||
|
|
1b2c8439f0 |
No files matched your search
@@ -1,102 +0,0 @@
|
||||
---
|
||||
name: remotion-video
|
||||
description: Create videos from React code with Remotion. Use when the user asks to make, animate, preview, or render a video, motion graphic, intro, caption, or social clip using code.
|
||||
---
|
||||
|
||||
# Remotion Video
|
||||
|
||||
Remotion makes videos out of React components. Each frame is a web page. Render them in order and you get an MP4.
|
||||
|
||||
## Core ideas
|
||||
- **Composition**: one video. Has `width`, `height`, `fps`, `durationInFrames`.
|
||||
- **Frame**: `useCurrentFrame()` returns the current frame number. All animation is a function of the frame.
|
||||
- **`interpolate`**: maps a frame range to a value range (fade, slide).
|
||||
- **`spring`**: natural bouncy motion.
|
||||
- **`Sequence`**: shows children only during a frame range.
|
||||
- **`AbsoluteFill`**: full-screen layer; stack them for backgrounds.
|
||||
- **`Audio` / `OffthreadVideo` / `Img`**: media. Put files in `public/` and load with `staticFile("name.mp3")`.
|
||||
|
||||
## Workflow
|
||||
1. **Plan first.** Ask or decide: length (seconds), size (1920x1080, or 1080x1920 for vertical), fps (30), and the scenes. Keep scenes to a short list.
|
||||
2. **Set up** (skip if the project exists):
|
||||
```
|
||||
npx create-video@latest
|
||||
cd <project> && npm install
|
||||
```
|
||||
3. **Write** compositions in `src/`, register them in `src/Root.tsx`.
|
||||
4. **Preview**: `npm run dev` (opens Remotion Studio).
|
||||
5. **Render**: `npx remotion render <CompositionId> out/video.mp4`
|
||||
Still frame: `npx remotion still <CompositionId> out/frame.png --frame=30`
|
||||
6. **Verify**: render one still first, check it looks right, then render the full video.
|
||||
|
||||
## Starter example
|
||||
`src/Root.tsx`
|
||||
```tsx
|
||||
import { Composition } from "remotion";
|
||||
import { Hello } from "./Hello";
|
||||
|
||||
export const RemotionRoot = () => (
|
||||
<Composition
|
||||
id="Hello"
|
||||
component={Hello}
|
||||
durationInFrames={150}
|
||||
fps={30}
|
||||
width={1920}
|
||||
height={1080}
|
||||
defaultProps={{ title: "Hello, world" }}
|
||||
/>
|
||||
);
|
||||
```
|
||||
|
||||
`src/Hello.tsx`
|
||||
```tsx
|
||||
import { AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig } from "remotion";
|
||||
|
||||
export const Hello = ({ title }: { title: string }) => {
|
||||
const frame = useCurrentFrame();
|
||||
const { fps } = useVideoConfig();
|
||||
const opacity = interpolate(frame, [0, 30], [0, 1], { extrapolateRight: "clamp" });
|
||||
const scale = spring({ frame, fps, config: { damping: 12 } });
|
||||
|
||||
return (
|
||||
<AbsoluteFill style={{ backgroundColor: "#0b1020", justifyContent: "center", alignItems: "center" }}>
|
||||
<h1 style={{ color: "white", fontSize: 120, opacity, transform: `scale(${scale})` }}>{title}</h1>
|
||||
</AbsoluteFill>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
## Rules of thumb
|
||||
- Never animate with CSS transitions, `setTimeout`, or CSS animations. They don't render per frame. Drive everything from `useCurrentFrame()`.
|
||||
- Always pass `extrapolateRight: "clamp"` to `interpolate` unless you want values to keep growing.
|
||||
- Seconds to frames: `seconds * fps`.
|
||||
- Use `<Sequence from={..} durationInFrames={..}>` to order scenes; `<Series>` to chain them.
|
||||
- Load fonts with `@remotion/google-fonts` so they are ready before rendering.
|
||||
- Keep props in `defaultProps` so the user can edit text in the Studio.
|
||||
- Rendering needs Chromium and ffmpeg (Remotion installs/handles these); first render can be slow.
|
||||
|
||||
## Fonts
|
||||
Google Fonts: `npm i @remotion/google-fonts`, then
|
||||
```tsx
|
||||
import { loadFont } from "@remotion/google-fonts/Inter";
|
||||
const { fontFamily } = loadFont(); // use as style={{ fontFamily }}
|
||||
```
|
||||
It downloads the font while rendering, so the machine needs internet access to fonts.googleapis.com. If the render fails with "Failed to load font", the network is blocking it: use a local font file in `public/` with `@remotion/fonts` (`loadFont({ family, url: staticFile("x.woff2") })`) or a system font. (Not verified in the sandbox where this skill was tested, which had no access to Google.)
|
||||
|
||||
## Common problems
|
||||
- **Can't download the browser (no internet / locked-down machine)**: point Remotion at an installed Chromium:
|
||||
`npx remotion render <Id> out/video.mp4 --browser-executable=/path/to/chromium --chrome-mode=chrome-for-testing`
|
||||
- **Blank/white frames**: an asset path is wrong; use `staticFile()`.
|
||||
- **Flicker**: an image or font not loaded; use `<Img>` and `@remotion/google-fonts`.
|
||||
- **Slow render**: lower resolution/fps while testing, or use `--concurrency`.
|
||||
|
||||
## Templates
|
||||
Copy-paste starting points. Read the one that fits:
|
||||
- `templates/captions.md` - words highlighted in time with speech
|
||||
- `templates/charts.md` - animated bar chart
|
||||
- `templates/intro-outro.md` - title card + chaining scenes with `Series`
|
||||
- `templates/audio-voiceover.md` - background music, voiceover, auto video length
|
||||
- `templates/vertical.md` - 1080x1920 clips for Reels/TikTok/Shorts
|
||||
|
||||
## Docs
|
||||
https://www.remotion.dev/docs
|
||||
@@ -1,62 +0,0 @@
|
||||
# Template: Audio, music and voiceover
|
||||
|
||||
Put sound files in `public/` (mp3 or wav). Load them with `staticFile()`.
|
||||
|
||||
`src/Narrated.tsx`
|
||||
```tsx
|
||||
import { AbsoluteFill, Audio, Sequence, interpolate, staticFile, useVideoConfig } from "remotion";
|
||||
import { getAudioDurationInSeconds } from "@remotion/media-utils";
|
||||
import type { CalculateMetadataFunction } from "remotion";
|
||||
|
||||
type Props = { title: string; voice: string; music: string };
|
||||
|
||||
// Make the video exactly as long as the voiceover (+1 second of padding).
|
||||
export const calcNarratedMetadata: CalculateMetadataFunction<Props> = async ({ props }) => {
|
||||
const seconds = await getAudioDurationInSeconds(staticFile(props.voice));
|
||||
return { durationInFrames: Math.ceil((seconds + 1) * 30) };
|
||||
};
|
||||
|
||||
export const Narrated = ({ title, voice, music }: Props) => {
|
||||
const { fps, durationInFrames } = useVideoConfig();
|
||||
return (
|
||||
<AbsoluteFill style={{ background: "#0b1020", justifyContent: "center", alignItems: "center" }}>
|
||||
<h1 style={{ color: "white", fontSize: 110 }}>{title}</h1>
|
||||
|
||||
{/* Background music: quiet, fades out over the last second. */}
|
||||
<Audio
|
||||
src={staticFile(music)}
|
||||
volume={(f) => interpolate(f, [durationInFrames - fps, durationInFrames], [0.15, 0], { extrapolateLeft: "clamp", extrapolateRight: "clamp" })}
|
||||
/>
|
||||
|
||||
{/* Voiceover starts half a second in, full volume. */}
|
||||
<Sequence from={Math.round(fps * 0.5)}>
|
||||
<Audio src={staticFile(voice)} volume={1} />
|
||||
</Sequence>
|
||||
</AbsoluteFill>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
Register it (note `calculateMetadata`):
|
||||
```tsx
|
||||
<Composition
|
||||
id="Narrated"
|
||||
component={Narrated}
|
||||
calculateMetadata={calcNarratedMetadata}
|
||||
durationInFrames={300} // placeholder, replaced by calculateMetadata
|
||||
fps={30} width={1920} height={1080}
|
||||
defaultProps={{ title: "My story", voice: "voice.mp3", music: "music.mp3" }}
|
||||
/>
|
||||
```
|
||||
|
||||
Install: `npm i @remotion/media-utils`
|
||||
|
||||
Getting a voiceover
|
||||
- Record yourself, or generate speech with a text-to-speech service, and save as `public/voice.mp3`. Never commit API keys; keep them in environment variables.
|
||||
- Pair with `templates/captions.md`: feed it word timings from a transcription of the same file.
|
||||
|
||||
Rules
|
||||
- Music volume 0.1-0.2 so the voice stays clear.
|
||||
- `<Sequence from={...}>` delays when a sound starts.
|
||||
- Audio is only in the final render (mp4). Stills (`remotion still`) have no sound.
|
||||
- Check the sound made it in: `ffprobe out/video.mp4` should list an `Audio:` stream.
|
||||
@@ -1,38 +0,0 @@
|
||||
# Template: Captions
|
||||
|
||||
Words appear in time with speech. Give each word a start time in seconds.
|
||||
|
||||
`src/Captions.tsx`
|
||||
```tsx
|
||||
import { AbsoluteFill, useCurrentFrame, useVideoConfig } from "remotion";
|
||||
|
||||
type Word = { text: string; start: number; end: number }; // seconds
|
||||
|
||||
export const Captions = ({ words, background = "#111" }: { words: Word[]; background?: string }) => {
|
||||
const frame = useCurrentFrame();
|
||||
const { fps } = useVideoConfig();
|
||||
const t = frame / fps;
|
||||
|
||||
// Show a window of up to 5 words around the current one.
|
||||
const current = words.findIndex((w) => t >= w.start && t < w.end);
|
||||
const i = current === -1 ? 0 : current;
|
||||
const visible = words.slice(Math.floor(i / 5) * 5, Math.floor(i / 5) * 5 + 5);
|
||||
|
||||
return (
|
||||
<AbsoluteFill style={{ backgroundColor: background, justifyContent: "flex-end", alignItems: "center", paddingBottom: 200 }}>
|
||||
<div style={{ fontSize: 72, fontWeight: 800, color: "white", textShadow: "0 4px 12px black", textAlign: "center", maxWidth: "80%" }}>
|
||||
{visible.map((w, k) => (
|
||||
<span key={k} style={{ color: t >= w.start && t < w.end ? "#ffd400" : "white", marginRight: 16 }}>
|
||||
{w.text}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
Tips
|
||||
- Get word times from a transcription tool (e.g. `@remotion/captions` or Whisper) and save them as JSON in `public/`.
|
||||
- `background` is the backdrop when there is no video. Pass `"transparent"` when layering over a video.
|
||||
- Layer it over the video: `<AbsoluteFill><OffthreadVideo src={staticFile("clip.mp4")} /><Captions words={words} background="transparent" /></AbsoluteFill>`.
|
||||
@@ -1,37 +0,0 @@
|
||||
# Template: Animated bar chart
|
||||
|
||||
Bars grow one after another.
|
||||
|
||||
`src/BarChart.tsx`
|
||||
```tsx
|
||||
import { AbsoluteFill, spring, useCurrentFrame, useVideoConfig } from "remotion";
|
||||
|
||||
type Bar = { label: string; value: number };
|
||||
|
||||
export const BarChart = ({ data, color = "#4f8cff" }: { data: Bar[]; color?: string }) => {
|
||||
const frame = useCurrentFrame();
|
||||
const { fps } = useVideoConfig();
|
||||
const max = Math.max(...data.map((d) => d.value));
|
||||
|
||||
return (
|
||||
<AbsoluteFill style={{ backgroundColor: "#0b1020", padding: 120, justifyContent: "flex-end" }}>
|
||||
<div style={{ display: "flex", alignItems: "flex-end", gap: 40, height: 700 }}>
|
||||
{data.map((d, i) => {
|
||||
const grow = spring({ frame: frame - i * 6, fps, config: { damping: 15 } });
|
||||
return (
|
||||
<div key={d.label} style={{ flex: 1, textAlign: "center", color: "white", fontSize: 36 }}>
|
||||
<div style={{ height: (d.value / max) * 600 * grow, background: color, borderRadius: 8 }} />
|
||||
<div style={{ marginTop: 16 }}>{d.label}</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
Tips
|
||||
- Delay each bar with `frame - i * 6` (6 frames apart).
|
||||
- For lines, animate `strokeDashoffset` on an SVG path using `interpolate`.
|
||||
- Keep numbers readable: show the value as text, rounded.
|
||||
@@ -1,34 +0,0 @@
|
||||
# Template: Title intro / outro card
|
||||
|
||||
A short card (2-3 seconds) with a title and subtitle. Use at the start or end.
|
||||
|
||||
`src/TitleCard.tsx`
|
||||
```tsx
|
||||
import { AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig } from "remotion";
|
||||
|
||||
export const TitleCard = ({ title, subtitle }: { title: string; subtitle?: string }) => {
|
||||
const frame = useCurrentFrame();
|
||||
const { fps, durationInFrames } = useVideoConfig();
|
||||
const rise = spring({ frame, fps, config: { damping: 14 } });
|
||||
const fadeOut = interpolate(frame, [durationInFrames - 15, durationInFrames], [1, 0], {
|
||||
extrapolateLeft: "clamp",
|
||||
extrapolateRight: "clamp",
|
||||
});
|
||||
|
||||
return (
|
||||
<AbsoluteFill style={{ background: "linear-gradient(135deg,#1b2a6b,#0b1020)", justifyContent: "center", alignItems: "center", opacity: fadeOut }}>
|
||||
<h1 style={{ color: "white", fontSize: 130, margin: 0, transform: `translateY(${(1 - rise) * 60}px)`, opacity: rise }}>{title}</h1>
|
||||
{subtitle && <p style={{ color: "#9fb3ff", fontSize: 48, opacity: rise }}>{subtitle}</p>}
|
||||
</AbsoluteFill>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
Chain with the main video using `<Series>`:
|
||||
```tsx
|
||||
<Series>
|
||||
<Series.Sequence durationInFrames={90}><TitleCard title="My Video" /></Series.Sequence>
|
||||
<Series.Sequence durationInFrames={600}><MainScene /></Series.Sequence>
|
||||
<Series.Sequence durationInFrames={90}><TitleCard title="Thanks for watching" /></Series.Sequence>
|
||||
</Series>
|
||||
```
|
||||
@@ -1,23 +0,0 @@
|
||||
# Template: Vertical clips (Reels / TikTok / Shorts)
|
||||
|
||||
Same code, different size. Register a vertical composition:
|
||||
|
||||
```tsx
|
||||
<Composition
|
||||
id="Vertical"
|
||||
component={MyScene}
|
||||
width={1080}
|
||||
height={1920}
|
||||
fps={30}
|
||||
durationInFrames={30 * 30} // 30 seconds
|
||||
/>
|
||||
```
|
||||
|
||||
Render: `npx remotion render Vertical out/vertical.mp4`
|
||||
|
||||
Rules
|
||||
- Keep text inside the **safe zone**: about 150px from the top, 350px from the bottom (apps cover those parts with buttons and captions), and 60px from the sides.
|
||||
- Use big text (60px+). Phone screens are small.
|
||||
- Keep clips under 60 seconds (Shorts limit); 15-30 seconds does best.
|
||||
- Use `useVideoConfig()` for width/height instead of hard-coding, so the same scene works wide and tall.
|
||||
- Put captions in the lower-middle, above the bottom safe zone (see captions.md).
|
||||
@@ -1 +0,0 @@
|
||||
ff37d1cd
|
||||
@@ -1 +0,0 @@
|
||||
.hallmark/shots/
|
||||
@@ -1,5 +0,0 @@
|
||||
shots/
|
||||
before/
|
||||
before.json
|
||||
before.txt
|
||||
compare.html
|
||||
@@ -1,31 +0,0 @@
|
||||
[
|
||||
{
|
||||
"shape": "Marquee Hero",
|
||||
"theme": "squeeze",
|
||||
"axes": "mid/geometric-sans/warm",
|
||||
"hero": "Banner",
|
||||
"nav": "edge-aligned",
|
||||
"footer": "letter close",
|
||||
"imagery": "photographs, library 1, natural",
|
||||
"photos": [
|
||||
"worm-bay"
|
||||
],
|
||||
"entry": "BeingOne front page",
|
||||
"sections": [
|
||||
"Hero",
|
||||
"Path",
|
||||
"Finder",
|
||||
"Checks",
|
||||
"Privacy",
|
||||
"Talk",
|
||||
"Family+Safety",
|
||||
"Questions+Join",
|
||||
"Footer"
|
||||
],
|
||||
"signature": "match finder with a tappable map of Australia and a moving score",
|
||||
"waived": [],
|
||||
"prompt": "BeingOne marriage site for Australians",
|
||||
"date": "2026-10-23",
|
||||
"mode": "build"
|
||||
}
|
||||
]
|
||||
@@ -1,65 +0,0 @@
|
||||
# BeingOne: plan (PRD)
|
||||
|
||||
Tagline: Real people. Real profiles. Real marriage.
|
||||
For: Australians, and the families of Australians, who want to find a life partner. English only. Australia only.
|
||||
Written for: Keith. Plain words on purpose.
|
||||
|
||||
## The big idea
|
||||
|
||||
BeingOne is a marriage website where every profile is checked to be a real person. People find matches, talk safely, and families can be part of it.
|
||||
|
||||
## The 13 core features (from Keith's plan)
|
||||
|
||||
1. Sign up and log in with email.
|
||||
2. Make a profile: photos, age, city, job, things you love, a short "about me".
|
||||
3. Check the profile is real: phone check, photo check, ID check, and a quick look by a person on the team.
|
||||
4. Search by Australian city, age and shared interests.
|
||||
5. Match score: a number showing how well two people fit.
|
||||
6. Photo privacy: you decide who sees your photos.
|
||||
7. Send an interest. The other person accepts or says no thanks.
|
||||
8. Private chat that opens only when both say yes.
|
||||
9. Family view: a parent or sibling helps look at profiles.
|
||||
10. Safety tools: block, report, hide your profile.
|
||||
11. Free plan and paid plan (payments).
|
||||
12. Admin area for the BeingOne team: review profiles, handle reports, see numbers.
|
||||
13. Emails and phone alerts: new matches, interests, messages.
|
||||
|
||||
## Phase 1 (today): the new look, with working demos
|
||||
|
||||
What you get: one front page in a new design. Everything on it is a demo that runs in your browser, with made-up sample people.
|
||||
|
||||
| Feature | Where it shows up on the page |
|
||||
| --- | --- |
|
||||
| 1 Sign up, log in | The join card at the bottom (Join and Log in tabs). It does not save anything yet. |
|
||||
| 2 Profile | Shown through the sample people and the checks demo. The real profile editor is Phase 3. |
|
||||
| 3 Checks | "Every profile is checked": run the four checks on a sample profile. |
|
||||
| 4 Search | "Find your match across Australia": map of Australia, city, ages, interests. |
|
||||
| 5 Match score | The score and bar on every sample person. |
|
||||
| 6 Photo privacy | "You choose who sees your photos": pick who can see, pick who is looking. |
|
||||
| 7 Interest, accept | "Chat opens when both say yes": accept or say no thanks. |
|
||||
| 8 Private chat | Same section: the chat unlocks after Accept. |
|
||||
| 9 Family view | "Family view" tile: pick who helps you look. |
|
||||
| 10 Safety tools | "Safety tools" tile: block, report, hide. |
|
||||
| 11 Plans | The "What does it cost?" answer. The paid price is left blank until you give it. |
|
||||
| 12 Admin | Mentioned in "Who runs the site?". The real admin area is Phase 7 and is a separate private page. |
|
||||
| 13 Alerts | The "Will I get alerts?" answer. Real alerts are Phase 6. |
|
||||
|
||||
Tests, in this order:
|
||||
1. The page loads with no errors.
|
||||
2. Every button, chip, slider, tab and form reacts.
|
||||
3. Real connections: none yet, so nothing to test.
|
||||
4. Security: no passwords, no keys, no calls to other servers for data. The forms only show a message on screen.
|
||||
|
||||
## Phases 2 to 8 (one at a time, each must work before the next)
|
||||
|
||||
2. Real sign-up and login (needs a host, a domain, a privacy policy and a consent step).
|
||||
3. Real profiles and photos, with private photo storage.
|
||||
4. Real checks (phone code, ID check through a trusted provider, team review screen).
|
||||
5. Real search and matching on real profiles.
|
||||
6. Private chat, block and report, email and phone alerts.
|
||||
7. Payments (test mode first) and the admin area.
|
||||
8. Launch checks: speed, phones, privacy rules, backups, a trial with friends and family.
|
||||
|
||||
## Important
|
||||
|
||||
Marriage sites hold very private details. In Australia some of them are "sensitive information" under the Privacy Act 1988, so people must clearly agree to how they are used. Plan the privacy policy and consent step in Phase 2. Please check with a lawyer before launch. This is not legal advice.
|
||||
@@ -1,42 +0,0 @@
|
||||
# BeingOne
|
||||
|
||||
Real people. Real profiles. Real marriage.
|
||||
|
||||
BeingOne is a marriage website for Australians and their families. Every profile is checked to be a real person. People find matches, talk safely, and families can be part of it.
|
||||
|
||||
This is **Phase 1**: the front page, in its new design, with working demos that run in the browser. The people on it are made up. Nothing is saved and nothing is sent anywhere yet.
|
||||
|
||||
## See it
|
||||
|
||||
There is no build step. Open `index.html` in a browser.
|
||||
|
||||
## What is in this folder
|
||||
|
||||
| File | What it is |
|
||||
| --- | --- |
|
||||
| `index.html` | The page |
|
||||
| `style.css` | How it looks (colours, fonts, spacing, motion) |
|
||||
| `tokens.css`, `base.css` | The colour and font settings, and the basic rules |
|
||||
| `app.js` | What the buttons, map, search, checks, chat and forms do |
|
||||
| `images/hero.jpg` | The photo at the top of the page (swap in the original) |
|
||||
| `PRD.md` | The plan: 13 features and the 8 phases |
|
||||
|
||||
## What the demos do
|
||||
|
||||
- **Search bar and map of Australia:** pick a city, ages and interests. Made-up people appear with a match score.
|
||||
- **Four checks:** run the phone, photo, ID and team checks on a sample profile.
|
||||
- **Photo privacy:** choose who can see a photo, and who is looking.
|
||||
- **Interest and chat:** accept an interest and a private chat opens.
|
||||
- **Family view and safety tools:** pick who helps you look; block, report and hide.
|
||||
- **Join and log in:** forms that do not send anything yet.
|
||||
|
||||
## Before it goes live
|
||||
|
||||
- The fonts load from Google Fonts. The beach photo loads from Wikimedia Commons (CC BY-SA 4.0, credited in the footer). Download both into this folder if you want the page to make no outside calls.
|
||||
- Replace `images/hero.jpg` with the original photo file.
|
||||
- The paid-plan price is a blank box on the page until you decide it.
|
||||
- Marriage sites hold very private details. In Australia some of them count as "sensitive information" under the Privacy Act 1988, so people must clearly agree to how it is used. Plan the privacy policy and consent step in Phase 2, and check with a lawyer before launch. This is not legal advice.
|
||||
|
||||
## Next: Phase 2
|
||||
|
||||
Real sign-up and login. This needs a hosting place (for example Vercel and Supabase) and a domain name.
|
||||
-313
@@ -1,313 +0,0 @@
|
||||
(() => {
|
||||
'use strict';
|
||||
const $ = (s, r = document) => r.querySelector(s);
|
||||
const $$ = (s, r = document) => Array.from(r.querySelectorAll(s));
|
||||
const cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
||||
const reduced = matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
|
||||
/* made-up sample people; nothing here is a real person (g: w = woman, m = man) */
|
||||
const PEOPLE = [
|
||||
{ n: 'Mia', g: 'w', a: 28, c: 'Sydney', l: ['beach', 'coffee', 'travel'], t: 'a' },
|
||||
{ n: 'Arjun', g: 'm', a: 31, c: 'Melbourne', l: ['footy', 'cooking', 'music'], t: 'b' },
|
||||
{ n: 'Hannah', g: 'w', a: 27, c: 'Brisbane', l: ['beach', 'hiking', 'pets'], t: 'c' },
|
||||
{ n: 'Wei', g: 'm', a: 30, c: 'Perth', l: ['coffee', 'travel', 'hiking'], t: 'd' },
|
||||
{ n: 'Sana', g: 'w', a: 29, c: 'Adelaide', l: ['cooking', 'music', 'pets'], t: 'a' },
|
||||
{ n: 'Tom', g: 'm', a: 33, c: 'Hobart', l: ['hiking', 'footy', 'coffee'], t: 'b' },
|
||||
{ n: 'Priya', g: 'w', a: 26, c: 'Sydney', l: ['music', 'cooking', 'beach'], t: 'c' },
|
||||
{ n: 'Jack', g: 'm', a: 35, c: 'Melbourne', l: ['footy', 'beach', 'pets'], t: 'd' },
|
||||
{ n: 'Elena', g: 'w', a: 32, c: 'Brisbane', l: ['travel', 'coffee', 'music'], t: 'a' },
|
||||
{ n: 'Dev', g: 'm', a: 34, c: 'Perth', l: ['footy', 'cooking', 'hiking'], t: 'b' },
|
||||
{ n: 'Grace', g: 'w', a: 30, c: 'Canberra', l: ['hiking', 'coffee', 'pets'], t: 'c' },
|
||||
{ n: 'Sam', g: 'm', a: 28, c: 'Darwin', l: ['beach', 'footy', 'travel'], t: 'd' },
|
||||
{ n: 'Lena', g: 'w', a: 38, c: 'Sydney', l: ['travel', 'music', 'pets'], t: 'a' },
|
||||
{ n: 'Omar', g: 'm', a: 29, c: 'Melbourne', l: ['coffee', 'cooking', 'hiking'], t: 'c' }
|
||||
];
|
||||
|
||||
/* ---------- scroll reveal, once ---------- */
|
||||
const revealEls = $$('[data-reveal]');
|
||||
if ('IntersectionObserver' in window) {
|
||||
const io = new IntersectionObserver((es) => es.forEach((e) => {
|
||||
if (e.isIntersecting) { e.target.classList.add('is-in'); io.unobserve(e.target); }
|
||||
}), { rootMargin: '0px 0px -10% 0px' });
|
||||
revealEls.forEach((el) => io.observe(el));
|
||||
} else {
|
||||
revealEls.forEach((el) => el.classList.add('is-in'));
|
||||
}
|
||||
|
||||
/* ---------- mobile menu ---------- */
|
||||
const menu = $('.nav__menu'), links = $('#nav-links');
|
||||
menu.addEventListener('click', () => {
|
||||
const open = links.classList.toggle('is-open');
|
||||
menu.setAttribute('aria-expanded', String(open));
|
||||
menu.textContent = open ? 'Close' : 'Menu';
|
||||
});
|
||||
links.addEventListener('click', (e) => {
|
||||
if (e.target.closest('a')) { links.classList.remove('is-open'); menu.setAttribute('aria-expanded', 'false'); menu.textContent = 'Menu'; }
|
||||
});
|
||||
|
||||
/* ---------- match finder (the quick search bar drives it too) ---------- */
|
||||
const st = { city: 'Anywhere', gender: 'any', from: 25, to: 40, likes: new Set(), sent: new Set() };
|
||||
const from = $('#f-from'), to = $('#f-to'), oFrom = $('#o-from'), oTo = $('#o-to');
|
||||
const results = $('#results'), status = $('#finder-status'), mapCity = $('#map-city');
|
||||
const qFor = $('#q-for'), qAge = $('#q-age'), qCity = $('#q-city');
|
||||
const pins = $$('.pin');
|
||||
|
||||
function scoreOf(p) {
|
||||
const mid = (st.from + st.to) / 2, half = Math.max((st.to - st.from) / 2, 1);
|
||||
const ageFit = Math.max(0, 1 - Math.abs(p.a - mid) / (half + 4));
|
||||
const shared = p.l.filter((x) => st.likes.has(x)).length;
|
||||
const likeFit = st.likes.size ? Math.min(1, shared / Math.min(st.likes.size, 3)) : 0.5;
|
||||
const cityFit = st.city === 'Anywhere' ? 0.7 : 1;
|
||||
return Math.round(55 + 45 * (0.5 * likeFit + 0.3 * ageFit + 0.2 * cityFit));
|
||||
}
|
||||
|
||||
function tile(r, i) {
|
||||
const p = r.p, sent = st.sent.has(p.n);
|
||||
const tags = p.l.map((x) => '<li' + (st.likes.has(x) ? ' class="is-shared"' : '') + '>' + cap(x) + '</li>').join('');
|
||||
return '<article class="person" style="--i:' + i + '">' +
|
||||
'<div class="person__who"><span class="avatar" style="--tone:var(--tone-' + p.t + ')" aria-hidden="true">' + p.n.charAt(0) + '</span>' +
|
||||
'<div><h3>' + p.n + ', ' + p.a + '</h3><p class="label">' + p.c + '</p></div></div>' +
|
||||
'<div><div class="score"><b data-to="' + r.score + '">' + r.score + '</b><span class="label" title="Counts shared interests, city and age">match</span></div>' +
|
||||
'<div class="bar" role="img" aria-label="Match score ' + r.score + ' out of 100"><i style="--s:' + r.score + '"></i></div></div>' +
|
||||
'<ul class="tags">' + tags + '</ul>' +
|
||||
'<button class="btn btn--sm" type="button" data-interest="' + p.n + '" aria-pressed="' + sent + '">' + (sent ? 'Interest sent' : 'Send interest') + '</button>' +
|
||||
'</article>';
|
||||
}
|
||||
|
||||
/* scores count up from 55 to their value, once per render */
|
||||
function countUp(el) {
|
||||
const to = +el.dataset.to;
|
||||
if (reduced) { el.textContent = to; return; }
|
||||
const t0 = performance.now(), dur = 900, start = 55;
|
||||
el.textContent = start;
|
||||
(function step(now) {
|
||||
const k = Math.min(1, (now - t0) / dur), e = 1 - Math.pow(1 - k, 3);
|
||||
el.textContent = Math.round(start + (to - start) * e);
|
||||
if (k < 1) requestAnimationFrame(step);
|
||||
})(t0);
|
||||
}
|
||||
|
||||
function renderFinder() {
|
||||
const pool = PEOPLE
|
||||
.filter((p) => (st.city === 'Anywhere' || p.c === st.city) && (st.gender === 'any' || p.g === st.gender) && p.a >= st.from && p.a <= st.to)
|
||||
.map((p) => ({ p, score: scoreOf(p) }))
|
||||
.sort((x, y) => y.score - x.score || x.p.n.localeCompare(y.p.n));
|
||||
const top = pool.slice(0, 4);
|
||||
results.innerHTML = top.length
|
||||
? top.map(tile).join('')
|
||||
: '<p class="results__empty">No one fits yet. Widen the ages or try another city.</p>';
|
||||
$$('.score b', results).forEach(countUp);
|
||||
status.textContent = top.length ? top.length + ' of ' + pool.length + ' shown.' : '';
|
||||
mapCity.textContent = st.city === 'Anywhere' ? 'All of Australia' : st.city;
|
||||
qCity.value = st.city;
|
||||
pins.forEach((b) => b.setAttribute('aria-pressed', String(b.dataset.city === st.city)));
|
||||
}
|
||||
|
||||
function setAges(a, b) {
|
||||
st.from = a; st.to = b; from.value = a; to.value = b;
|
||||
oFrom.textContent = a; oTo.textContent = b;
|
||||
}
|
||||
|
||||
pins.forEach((b) => b.addEventListener('click', () => {
|
||||
st.city = st.city === b.dataset.city ? 'Anywhere' : b.dataset.city;
|
||||
if (st.city === b.dataset.city && !reduced) {
|
||||
const ping = document.createElement('span');
|
||||
ping.className = 'ping';
|
||||
ping.addEventListener('animationend', () => ping.remove(), { once: true });
|
||||
b.appendChild(ping);
|
||||
}
|
||||
renderFinder();
|
||||
}));
|
||||
from.addEventListener('input', () => {
|
||||
st.from = +from.value;
|
||||
if (st.from > st.to) { st.to = st.from; to.value = st.to; }
|
||||
oFrom.textContent = st.from; oTo.textContent = st.to; renderFinder();
|
||||
});
|
||||
to.addEventListener('input', () => {
|
||||
st.to = +to.value;
|
||||
if (st.to < st.from) { st.from = st.to; from.value = st.from; }
|
||||
oFrom.textContent = st.from; oTo.textContent = st.to; renderFinder();
|
||||
});
|
||||
$$('#f-likes input').forEach((c) => c.addEventListener('change', () => {
|
||||
c.checked ? st.likes.add(c.value) : st.likes.delete(c.value);
|
||||
renderFinder();
|
||||
}));
|
||||
results.addEventListener('click', (e) => {
|
||||
const b = e.target.closest('[data-interest]');
|
||||
if (!b) return;
|
||||
const name = b.dataset.interest;
|
||||
st.sent.has(name) ? st.sent.delete(name) : st.sent.add(name);
|
||||
const on = st.sent.has(name);
|
||||
b.setAttribute('aria-pressed', String(on));
|
||||
b.textContent = on ? 'Interest sent' : 'Send interest';
|
||||
});
|
||||
|
||||
/* quick search bar: each choice updates the finder, the button also scrolls to the people */
|
||||
function applyQuick() {
|
||||
st.gender = qFor.value;
|
||||
st.city = qCity.value;
|
||||
const [a, b] = qAge.value.split('-').map(Number);
|
||||
setAges(a, b);
|
||||
renderFinder();
|
||||
}
|
||||
[qFor, qAge, qCity].forEach((el) => el.addEventListener('change', applyQuick));
|
||||
$('#quick').addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
applyQuick();
|
||||
results.scrollIntoView({ behavior: reduced ? 'auto' : 'smooth', block: 'center' });
|
||||
});
|
||||
renderFinder();
|
||||
|
||||
/* ---------- the four checks ---------- */
|
||||
const rows = $$('[data-check]'), vStatus = $('#v-status'), vText = $('#v-status-text'), vBar = $('#v-progress');
|
||||
const timers = new Map();
|
||||
function updateChecks() {
|
||||
const n = rows.filter((r) => r.classList.contains('is-done')).length;
|
||||
vStatus.dataset.state = n === rows.length ? 'done' : 'idle';
|
||||
vText.textContent = n === rows.length ? 'Verified' : n ? n + ' of 4 passed' : 'Not verified yet';
|
||||
vBar.style.setProperty('--p', n / rows.length);
|
||||
}
|
||||
function runCheck(row) {
|
||||
if (row.classList.contains('is-done') || timers.has(row)) return;
|
||||
const btn = $('[data-run]', row);
|
||||
btn.setAttribute('aria-busy', 'true'); btn.disabled = true; btn.textContent = 'Checking…';
|
||||
timers.set(row, setTimeout(() => {
|
||||
timers.delete(row);
|
||||
row.classList.add('is-done');
|
||||
btn.hidden = true; btn.removeAttribute('aria-busy');
|
||||
$('.passed', row).hidden = false;
|
||||
updateChecks();
|
||||
}, 800));
|
||||
}
|
||||
rows.forEach((r) => $('[data-run]', r).addEventListener('click', () => runCheck(r)));
|
||||
$('#v-all').addEventListener('click', () => rows.forEach((r, i) => setTimeout(() => runCheck(r), i * 250)));
|
||||
$('#v-reset').addEventListener('click', () => {
|
||||
timers.forEach((t) => clearTimeout(t)); timers.clear();
|
||||
rows.forEach((r) => {
|
||||
r.classList.remove('is-done');
|
||||
const btn = $('[data-run]', r);
|
||||
btn.hidden = false; btn.disabled = false; btn.removeAttribute('aria-busy'); btn.textContent = 'Run';
|
||||
$('.passed', r).hidden = true;
|
||||
});
|
||||
updateChecks();
|
||||
});
|
||||
|
||||
/* ---------- photo privacy ---------- */
|
||||
const photo = $('#photo'), photoState = $('#photo-state');
|
||||
const rank = { stranger: 0, verified: 1, accepted: 2 };
|
||||
function renderPhoto() {
|
||||
const setting = $('input[name="setting"]:checked').value;
|
||||
const viewer = $('input[name="viewer"]:checked').value;
|
||||
const can = setting === 'everyone' ||
|
||||
(setting === 'verified' && rank[viewer] >= 1) ||
|
||||
(setting === 'accepted' && rank[viewer] >= 2);
|
||||
photo.classList.toggle('is-hidden', !can);
|
||||
photoState.textContent = can ? 'Visible to this visitor' : 'Hidden from this visitor';
|
||||
}
|
||||
$$('input[name="setting"], input[name="viewer"]').forEach((r) => r.addEventListener('change', renderPhoto));
|
||||
renderPhoto();
|
||||
|
||||
/* ---------- interest, accept, chat ---------- */
|
||||
const chat = $('#chat'), log = $('#chat-log'), tResult = $('#t-result');
|
||||
const accept = $('#t-accept'), decline = $('#t-decline'), tReset = $('#t-reset');
|
||||
const chatForm = $('#chat-form'), chatInput = $('#chat-input');
|
||||
function addLine(text, cls) {
|
||||
const li = document.createElement('li');
|
||||
if (cls) li.className = cls;
|
||||
li.textContent = text;
|
||||
log.appendChild(li);
|
||||
log.scrollTop = log.scrollHeight;
|
||||
}
|
||||
function decide(yes) {
|
||||
accept.hidden = true; decline.hidden = true; tReset.hidden = false;
|
||||
tResult.textContent = yes ? 'You both said yes. Say hello.' : 'You said no thanks. Nothing opens.';
|
||||
if (yes) {
|
||||
chat.classList.remove('is-locked');
|
||||
addLine('You and Priya both said yes.', 'note');
|
||||
chatInput.focus();
|
||||
}
|
||||
}
|
||||
accept.addEventListener('click', () => decide(true));
|
||||
decline.addEventListener('click', () => decide(false));
|
||||
tReset.addEventListener('click', () => {
|
||||
accept.hidden = false; decline.hidden = false; tReset.hidden = true;
|
||||
tResult.textContent = ''; log.textContent = '';
|
||||
chat.classList.add('is-locked'); chatInput.value = '';
|
||||
});
|
||||
chatForm.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
const v = chatInput.value.trim();
|
||||
if (!v) { chatInput.focus(); return; }
|
||||
addLine(v, 'me'); chatInput.value = ''; chatInput.focus();
|
||||
});
|
||||
|
||||
/* ---------- family view and safety tools ---------- */
|
||||
const famStatus = $('#fam-status');
|
||||
function renderFam() {
|
||||
const on = $$('#fam input:checked').map((c) => c.value);
|
||||
famStatus.textContent = !on.length ? 'Just you for now.'
|
||||
: (on.length === 1 ? on[0] : on.slice(0, -1).join(', ') + ' and ' + on[on.length - 1]) +
|
||||
(on.length === 1 ? ' is' : ' are') + ' looking with you.';
|
||||
}
|
||||
$$('#fam input').forEach((c) => c.addEventListener('change', renderFam));
|
||||
|
||||
const safe = $('#safe-status'), sBlock = $('#s-block'), sHide = $('#s-hide'), sReport = $('#s-report');
|
||||
let blocked = false;
|
||||
sBlock.addEventListener('click', () => {
|
||||
blocked = !blocked;
|
||||
$('span', sBlock).textContent = blocked ? 'Unblock' : 'Block';
|
||||
sBlock.setAttribute('aria-pressed', String(blocked));
|
||||
safe.textContent = blocked ? 'Jack is blocked. He cannot message you.' : 'Jack is unblocked.';
|
||||
});
|
||||
sReport.addEventListener('click', () => { safe.textContent = 'Demo only: nothing was sent to our team.'; });
|
||||
sHide.addEventListener('click', () => {
|
||||
const on = sHide.getAttribute('aria-pressed') !== 'true';
|
||||
sHide.setAttribute('aria-pressed', String(on));
|
||||
$('span', sHide).textContent = on ? 'Show my profile' : 'Hide my profile';
|
||||
safe.textContent = on ? 'Your profile is hidden from search.' : 'Your profile shows in search.';
|
||||
});
|
||||
|
||||
/* ---------- join card: tabs and forms that post nowhere yet ---------- */
|
||||
const tabs = $$('[role="tab"]', $('#join-card'));
|
||||
const panels = { join: $('#panel-join'), login: $('#panel-login') };
|
||||
function openTab(name, focus) {
|
||||
tabs.forEach((t) => {
|
||||
const on = t.id === 'tab-' + name;
|
||||
t.setAttribute('aria-selected', String(on));
|
||||
t.tabIndex = on ? 0 : -1;
|
||||
if (on && focus) t.focus();
|
||||
});
|
||||
Object.keys(panels).forEach((k) => { panels[k].hidden = k !== name; });
|
||||
}
|
||||
tabs.forEach((t, i) => {
|
||||
t.addEventListener('click', () => openTab(t.id.replace('tab-', '')));
|
||||
t.addEventListener('keydown', (e) => {
|
||||
if (e.key !== 'ArrowRight' && e.key !== 'ArrowLeft') return;
|
||||
e.preventDefault();
|
||||
const next = tabs[(i + (e.key === 'ArrowRight' ? 1 : tabs.length - 1)) % tabs.length];
|
||||
openTab(next.id.replace('tab-', ''), true);
|
||||
});
|
||||
});
|
||||
$$('[data-open-tab]').forEach((a) => a.addEventListener('click', () => openTab(a.dataset.openTab)));
|
||||
openTab('join');
|
||||
|
||||
$$('form[data-endpoint]').forEach((form) => {
|
||||
const help = $('.form-help', form);
|
||||
form.addEventListener('input', (e) => { e.target.removeAttribute && e.target.removeAttribute('aria-invalid'); });
|
||||
form.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
help.classList.remove('is-error');
|
||||
const bad = $$('input', form).filter((i) => !i.checkValidity());
|
||||
$$('input', form).forEach((i) => i.toggleAttribute('aria-invalid', bad.includes(i)));
|
||||
if (bad.length) {
|
||||
help.classList.add('is-error');
|
||||
help.textContent = bad[0].type === 'email'
|
||||
? 'That email looks incomplete. Write it as name@example.com.'
|
||||
: 'Please fill in the highlighted field.';
|
||||
bad[0].focus();
|
||||
return;
|
||||
}
|
||||
if (!form.dataset.endpoint) { help.textContent = 'Nothing was sent: this form is not connected yet.'; return; }
|
||||
});
|
||||
});
|
||||
})();
|
||||
@@ -1,23 +0,0 @@
|
||||
*, *::before, *::after { box-sizing: border-box; }
|
||||
html, body { overflow-x: clip; }
|
||||
html { scrollbar-color: var(--color-muted) var(--color-paper); scroll-padding-top: var(--space-3xl); }
|
||||
body { margin: 0; background: var(--color-paper); color: var(--color-ink); font-family: var(--font-body); font-size: var(--text-md); line-height: 1.55; -webkit-font-smoothing: antialiased; caret-color: var(--color-accent); }
|
||||
::selection { background: color-mix(in oklab, var(--color-accent) 22%, transparent); color: var(--color-ink); }
|
||||
:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
|
||||
a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: 0.16em; }
|
||||
h1, h2, h3 { margin: 0; font-family: var(--font-display); font-synthesis: none; overflow-wrap: break-word; min-width: 0; text-wrap: balance; }
|
||||
p { margin: 0; text-wrap: pretty; }
|
||||
p:not([class]) { max-width: 65ch; }
|
||||
img, video { max-width: 100%; height: auto; display: block; }
|
||||
svg { display: block; }
|
||||
[hidden] { display: none !important; }
|
||||
button, input, select, textarea { font: inherit; }
|
||||
.container { width: 100%; max-width: var(--container); margin-inline: auto; padding-inline: var(--gutter); box-sizing: border-box; }
|
||||
.num, .figure, td.num { font-variant-numeric: tabular-nums; }
|
||||
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
|
||||
[data-slot] { position: relative; overflow: hidden; background: linear-gradient(160deg, var(--color-paper-2, var(--color-paper)), var(--color-paper-3, var(--color-paper))); }
|
||||
[data-slot] > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 1; }
|
||||
[data-slot]:has(> img) > :not(img):not([data-keep]) { display: none !important; }
|
||||
@media (max-width: 60rem) { :root { --gutter: 24px; --section-gap-s: 80px; --section-gap: 96px; --section-gap-l: 120px; } }
|
||||
@media (max-width: 40rem) { :root { --gutter: 16px; --section-gap-s: 56px; --section-gap: 72px; --section-gap-l: 96px; --gap-columns: 16px; } }
|
||||
@media (prefers-reduced-motion: reduce) { *:not(.keep-motion), *:not(.keep-motion)::before, *:not(.keep-motion)::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } }
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 80 KiB |
@@ -1,346 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en-AU">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>BeingOne: marriage profiles for Australians, every one checked</title>
|
||||
<meta name="description" content="BeingOne is a marriage website for Australians and their families where every profile is checked to be a real person.">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=DM+Serif+Display:ital@0;1&family=Figtree:wght@500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<script>document.documentElement.classList.add('js');</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<svg width="0" height="0" style="position:absolute" aria-hidden="true" focusable="false">
|
||||
<symbol id="i-check" viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></symbol>
|
||||
<symbol id="i-arrow" viewBox="0 0 24 24"><path d="M5 12h14M13 6l6 6-6 6"/></symbol>
|
||||
<symbol id="i-search" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></symbol>
|
||||
<symbol id="i-lock" viewBox="0 0 24 24"><rect width="18" height="11" x="3" y="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></symbol>
|
||||
<symbol id="i-eye" viewBox="0 0 24 24"><path d="M2.06 12.35a1 1 0 0 1 0-.7 10.75 10.75 0 0 1 19.88 0 1 1 0 0 1 0 .7 10.75 10.75 0 0 1-19.88 0"/><circle cx="12" cy="12" r="3"/></symbol>
|
||||
<symbol id="i-shield" viewBox="0 0 24 24"><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/><path d="m9 12 2 2 4-4"/></symbol>
|
||||
<symbol id="i-phone" viewBox="0 0 24 24"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.13.96.36 1.9.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0 1 22 16.92z"/></symbol>
|
||||
<symbol id="i-camera" viewBox="0 0 24 24"><path d="M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z"/><circle cx="12" cy="13" r="3"/></symbol>
|
||||
<symbol id="i-id" viewBox="0 0 24 24"><rect x="2" y="5" width="20" height="14" rx="2"/><circle cx="9" cy="11" r="2"/><path d="M5.5 16c.5-1.5 2-2.5 3.5-2.5s3 1 3.5 2.5M15 10h4M15 14h3"/></symbol>
|
||||
<symbol id="i-users" viewBox="0 0 24 24"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75"/></symbol>
|
||||
<symbol id="i-ban" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="m4.9 4.9 14.2 14.2"/></symbol>
|
||||
<symbol id="i-flag" viewBox="0 0 24 24"><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/><path d="M4 22v-7"/></symbol>
|
||||
<symbol id="i-send" viewBox="0 0 24 24"><path d="m22 2-7 20-4-9-9-4z"/><path d="M22 2 11 13"/></symbol>
|
||||
</svg>
|
||||
|
||||
<a class="skip" href="#main">Skip to content</a>
|
||||
|
||||
<header class="nav">
|
||||
<div class="container nav__bar">
|
||||
<a class="wordmark" href="#top" aria-label="BeingOne, back to the top">
|
||||
<svg class="mark" viewBox="0 0 32 32" aria-hidden="true"><circle cx="12" cy="16" r="8"/><circle cx="20" cy="16" r="8"/></svg>
|
||||
<span>Being<b>One</b></span>
|
||||
</a>
|
||||
<nav class="nav__links" id="nav-links" aria-label="Main">
|
||||
<a href="#find">Discover</a>
|
||||
<a href="#results">Curated matches</a>
|
||||
<a href="#talk">Messages</a>
|
||||
<a href="#safety">Safety centre</a>
|
||||
<a href="#help">Help</a>
|
||||
<a class="only-sm" href="#join" data-open-tab="login">Sign in</a>
|
||||
</nav>
|
||||
<div class="nav__actions">
|
||||
<a class="nav__signin" href="#join" data-open-tab="login">Sign in</a>
|
||||
<a class="btn btn--sm" href="#join" data-open-tab="join">Join</a>
|
||||
<button class="nav__menu btn btn--sm" type="button" aria-expanded="false" aria-controls="nav-links">Menu</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main id="main">
|
||||
|
||||
<section class="hero" id="top" aria-labelledby="hero-title">
|
||||
<figure class="hero__photo" data-slot="hero" data-alt="A bride and groom holding hands outdoors as guests throw petals">
|
||||
<img src="images/hero.jpg" width="998" height="770" alt="A bride and groom holding hands outdoors as guests throw petals" fetchpriority="high">
|
||||
</figure>
|
||||
<div class="container hero__inner">
|
||||
<div class="hero__text">
|
||||
<h1 id="hero-title">
|
||||
<span class="line" style="--i:0"><span>Real people.</span></span>
|
||||
<span class="line" style="--i:1"><span>Real profiles.</span></span>
|
||||
<span class="line line--it" style="--i:2"><span>Real marriage.</span></span>
|
||||
</h1>
|
||||
<p class="lead hero__lead">Every profile is checked, so you meet real people across Australia.</p>
|
||||
<a class="btn btn--primary hero__cta" href="#join" data-open-tab="join">Create your profile<svg class="icon" aria-hidden="true"><use href="#i-arrow"/></svg></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container quick__wrap">
|
||||
<form class="quick" id="quick" onsubmit="return false" aria-label="Quick search">
|
||||
<div class="quick__field">
|
||||
<label for="q-for">I’m looking for</label>
|
||||
<select id="q-for"><option value="any">Anyone</option><option value="w">A woman</option><option value="m">A man</option></select>
|
||||
</div>
|
||||
<div class="quick__field">
|
||||
<label for="q-age">Age</label>
|
||||
<select id="q-age"><option value="21-60">Any age</option><option value="21-29">21 to 29</option><option value="30-39">30 to 39</option><option value="40-49">40 to 49</option><option value="50-60">50 to 60</option></select>
|
||||
</div>
|
||||
<div class="quick__field">
|
||||
<label for="q-city">Location</label>
|
||||
<select id="q-city"><option>Anywhere</option><option>Adelaide</option><option>Brisbane</option><option>Canberra</option><option>Darwin</option><option>Hobart</option><option>Melbourne</option><option>Perth</option><option>Sydney</option></select>
|
||||
</div>
|
||||
<button class="btn btn--primary quick__go" type="submit"><svg class="icon" aria-hidden="true"><use href="#i-search"/></svg>Search</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="band band--path" id="path" aria-label="How it goes">
|
||||
<div class="container">
|
||||
<ol class="path">
|
||||
<li data-reveal style="--i:0"><a href="#join">Join</a></li>
|
||||
<li data-reveal style="--i:1"><a href="#verified">Get checked</a></li>
|
||||
<li data-reveal style="--i:2"><a href="#find">Find</a></li>
|
||||
<li data-reveal style="--i:3"><a href="#talk">Say yes</a></li>
|
||||
<li data-reveal style="--i:4"><a href="#talk">Chat</a></li>
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sec finder" id="find" aria-labelledby="find-title">
|
||||
<div class="container">
|
||||
<div class="grid finder__top">
|
||||
<h2 id="find-title" data-reveal>Find your match across Australia</h2>
|
||||
<p class="lead" data-reveal style="--i:1">Pick a city, ages and what you love.</p>
|
||||
</div>
|
||||
<div class="grid finder__body">
|
||||
<div class="map" data-reveal role="group" aria-label="Map of Australia. Tap a city to search there.">
|
||||
<svg class="map__svg" viewBox="-40 -20 605 516" role="img" aria-label="Outline of Australia">
|
||||
<path d="M381.3 9.8L393.8 56.0L416.3 70.0L422.5 96.6L435.0 130.2L458.7 144.2L465.0 155.4L485.0 187.6L505.0 208.6L513.7 224.0L512.5 245.0L520.0 260.4L512.5 284.2L506.3 308.0L490.0 334.6L485.0 348.6L476.2 366.8L473.8 385.0L450.0 392.0L430.0 407.4L412.5 397.6L393.8 403.2L362.5 393.4L350.0 385.0L343.8 358.4L326.2 359.1L331.3 347.2L321.2 336.0L300.0 347.2L277.5 322.0L237.5 301.0L212.5 303.8L175.0 312.2L143.8 333.2L123.8 334.6L87.5 348.6L73.8 350.0L38.7 341.6L46.3 326.2L47.5 308.0L32.5 263.2L17.5 224.0L18.8 196.0L26.2 165.2L58.8 149.8L82.5 144.2L118.8 126.0L127.5 112.0L147.5 91.0L168.8 77.0L186.3 54.6L212.5 70.0L221.2 68.6L225.0 46.2L235.0 35.0L256.3 21.0L275.0 28.0L310.0 30.8L306.3 49.0L297.5 72.8L322.5 91.0L343.8 105.0L360.0 103.6L370.0 77.0L368.8 49.0L376.2 30.8ZM408.7 429.8L453.8 432.6L453.8 450.8L441.3 469.0L425.0 470.4L415.0 450.8Z"/>
|
||||
</svg>
|
||||
<button class="pin" type="button" data-city="Perth" aria-pressed="false" aria-label="Perth" title="Perth" style="--x:14.6%;--y:63.4%;--i:0"></button>
|
||||
<button class="pin" type="button" data-city="Adelaide" aria-pressed="false" aria-label="Adelaide" title="Adelaide" style="--x:61.6%;--y:71.5%;--i:1"></button>
|
||||
<button class="pin" type="button" data-city="Darwin" aria-pressed="false" aria-label="Darwin" title="Darwin" style="--x:45.5%;--y:10.5%;--i:2"></button>
|
||||
<button class="pin" type="button" data-city="Brisbane" aria-pressed="false" aria-label="Brisbane" title="Brisbane" style="--x:91.4%;--y:51.3%;--i:3"></button>
|
||||
<button class="pin" type="button" data-city="Sydney" aria-pressed="false" aria-label="Sydney" title="Sydney" style="--x:87.6%;--y:68.6%;--i:4"></button>
|
||||
<button class="pin" type="button" data-city="Canberra" aria-pressed="false" aria-label="Canberra" title="Canberra" style="--x:83.3%;--y:72.5%;--i:5"></button>
|
||||
<button class="pin" type="button" data-city="Melbourne" aria-pressed="false" aria-label="Melbourne" title="Melbourne" style="--x:74.7%;--y:79.3%;--i:6"></button>
|
||||
<button class="pin" type="button" data-city="Hobart" aria-pressed="false" aria-label="Hobart" title="Hobart" style="--x:79.6%;--y:93.1%;--i:7"></button>
|
||||
<p class="map__city" id="map-city">All of Australia</p>
|
||||
</div>
|
||||
|
||||
<form class="controls" id="finder-form" data-reveal style="--i:1" onsubmit="return false" aria-label="Match finder">
|
||||
<div class="controls__ages">
|
||||
<div class="field">
|
||||
<div class="field__row"><label for="f-from">From</label><output id="o-from" for="f-from">25</output></div>
|
||||
<input id="f-from" type="range" min="21" max="60" value="25">
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="field__row"><label for="f-to">To</label><output id="o-to" for="f-to">40</output></div>
|
||||
<input id="f-to" type="range" min="21" max="60" value="40">
|
||||
</div>
|
||||
</div>
|
||||
<fieldset class="choices" id="f-likes">
|
||||
<legend>You love</legend>
|
||||
<input type="checkbox" id="l-beach" value="beach"><label for="l-beach">Beach</label>
|
||||
<input type="checkbox" id="l-footy" value="footy"><label for="l-footy">Footy</label>
|
||||
<input type="checkbox" id="l-coffee" value="coffee"><label for="l-coffee">Coffee</label>
|
||||
<input type="checkbox" id="l-hiking" value="hiking"><label for="l-hiking">Hiking</label>
|
||||
<input type="checkbox" id="l-cooking" value="cooking"><label for="l-cooking">Cooking</label>
|
||||
<input type="checkbox" id="l-travel" value="travel"><label for="l-travel">Travel</label>
|
||||
<input type="checkbox" id="l-music" value="music"><label for="l-music">Music</label>
|
||||
<input type="checkbox" id="l-pets" value="pets"><label for="l-pets">Pets</label>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="results" id="results" aria-live="polite"></div>
|
||||
<p class="visually-hidden" id="finder-status" role="status"></p>
|
||||
<p class="finder__note">Sample people, made up for this demo.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sec band--navy on-dark checks" id="verified" aria-labelledby="verified-title">
|
||||
<div class="container grid">
|
||||
<div class="head">
|
||||
<h2 id="verified-title" data-reveal>Every profile is checked</h2>
|
||||
<p class="lead" data-reveal style="--i:1">Try the four checks.</p>
|
||||
</div>
|
||||
<div class="checks__panel" data-reveal style="--i:2">
|
||||
<div class="checks__who">
|
||||
<span class="avatar" style="--tone:var(--tone-a)" aria-hidden="true">M</span>
|
||||
<div><h3>Mia, 28</h3><p class="label">Sydney</p></div>
|
||||
<span class="status" id="v-status" data-state="idle" role="status"><svg class="icon icon--sm" aria-hidden="true"><use href="#i-shield"/></svg><span id="v-status-text">Not verified yet</span></span>
|
||||
</div>
|
||||
<div class="progress" aria-hidden="true"><i id="v-progress" style="--p:0"></i></div>
|
||||
<ul class="rows" id="v-rows">
|
||||
<li data-check>
|
||||
<svg class="icon idle" aria-hidden="true"><use href="#i-phone"/></svg><svg class="icon tick" aria-hidden="true"><use href="#i-check"/></svg>
|
||||
<div><h3>Phone check</h3><p>A code arrives by text.</p></div>
|
||||
<button class="btn btn--sm" type="button" data-run>Run</button><span class="passed" hidden>Passed</span>
|
||||
</li>
|
||||
<li data-check>
|
||||
<svg class="icon idle" aria-hidden="true"><use href="#i-camera"/></svg><svg class="icon tick" aria-hidden="true"><use href="#i-check"/></svg>
|
||||
<div><h3>Photo check</h3><p>Checked as real.</p></div>
|
||||
<button class="btn btn--sm" type="button" data-run>Run</button><span class="passed" hidden>Passed</span>
|
||||
</li>
|
||||
<li data-check>
|
||||
<svg class="icon idle" aria-hidden="true"><use href="#i-id"/></svg><svg class="icon tick" aria-hidden="true"><use href="#i-check"/></svg>
|
||||
<div><h3>ID check</h3><p>Matched to your photo.</p></div>
|
||||
<button class="btn btn--sm" type="button" data-run>Run</button><span class="passed" hidden>Passed</span>
|
||||
</li>
|
||||
<li data-check>
|
||||
<svg class="icon idle" aria-hidden="true"><use href="#i-users"/></svg><svg class="icon tick" aria-hidden="true"><use href="#i-check"/></svg>
|
||||
<div><h3>Team look</h3><p>A quick look by our team.</p></div>
|
||||
<button class="btn btn--sm" type="button" data-run>Run</button><span class="passed" hidden>Passed</span>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="checks__foot">
|
||||
<button class="btn btn--sm" type="button" id="v-all">Run all four</button>
|
||||
<button class="btn btn--sm" type="button" id="v-reset">Start again</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sec sec--tall" id="privacy" aria-labelledby="privacy-title">
|
||||
<div class="container grid">
|
||||
<figure class="privacy__photo" id="photo" data-reveal>
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e2/Peterborough_%28AU%29%2C_Port_Campbell_National_Park%2C_Worm_Bay_--_2019_--_0863.jpg/1280px-Peterborough_%28AU%29%2C_Port_Campbell_National_Park%2C_Worm_Bay_--_2019_--_0863.jpg" srcset="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e2/Peterborough_%28AU%29%2C_Port_Campbell_National_Park%2C_Worm_Bay_--_2019_--_0863.jpg/960px-Peterborough_%28AU%29%2C_Port_Campbell_National_Park%2C_Worm_Bay_--_2019_--_0863.jpg 960w, https://upload.wikimedia.org/wikipedia/commons/thumb/e/e2/Peterborough_%28AU%29%2C_Port_Campbell_National_Park%2C_Worm_Bay_--_2019_--_0863.jpg/1280px-Peterborough_%28AU%29%2C_Port_Campbell_National_Park%2C_Worm_Bay_--_2019_--_0863.jpg 1280w, https://upload.wikimedia.org/wikipedia/commons/thumb/e/e2/Peterborough_%28AU%29%2C_Port_Campbell_National_Park%2C_Worm_Bay_--_2019_--_0863.jpg/1920px-Peterborough_%28AU%29%2C_Port_Campbell_National_Park%2C_Worm_Bay_--_2019_--_0863.jpg 1920w" sizes="(min-width: 60rem) 58vw, 100vw" width="6718" height="4479" alt="A beach below orange sandstone cliffs, standing in for a profile photo" loading="lazy">
|
||||
<img class="blur" src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/e2/Peterborough_%28AU%29%2C_Port_Campbell_National_Park%2C_Worm_Bay_--_2019_--_0863.jpg/960px-Peterborough_%28AU%29%2C_Port_Campbell_National_Park%2C_Worm_Bay_--_2019_--_0863.jpg" width="6718" height="4479" alt="" aria-hidden="true" loading="lazy">
|
||||
<span class="privacy__lock" aria-hidden="true"><span class="privacy__disc"><svg class="icon"><use href="#i-lock"/></svg></span></span>
|
||||
<span class="privacy__badge" role="status"><svg class="icon icon--sm icon-open" aria-hidden="true"><use href="#i-eye"/></svg><svg class="icon icon--sm icon-shut" aria-hidden="true"><use href="#i-lock"/></svg><span id="photo-state">Hidden from this visitor</span></span>
|
||||
</figure>
|
||||
<form class="privacy__panel" onsubmit="return false" aria-label="Photo privacy">
|
||||
<h2 id="privacy-title" data-reveal>You choose who sees your photos</h2>
|
||||
<fieldset class="choices choices--stack" id="p-setting">
|
||||
<legend>Photos are visible to</legend>
|
||||
<input type="radio" name="setting" id="s-everyone" value="everyone"><label for="s-everyone">Everyone</label>
|
||||
<input type="radio" name="setting" id="s-verified" value="verified" checked><label for="s-verified">Verified members</label>
|
||||
<input type="radio" name="setting" id="s-accepted" value="accepted"><label for="s-accepted">People I accept</label>
|
||||
<input type="radio" name="setting" id="s-me" value="me"><label for="s-me">Only me</label>
|
||||
</fieldset>
|
||||
<fieldset class="choices" id="p-viewer">
|
||||
<legend>Right now, a visitor is</legend>
|
||||
<input type="radio" name="viewer" id="v-stranger" value="stranger" checked><label for="v-stranger">A stranger</label>
|
||||
<input type="radio" name="viewer" id="v-member" value="verified"><label for="v-member">A verified member</label>
|
||||
<input type="radio" name="viewer" id="v-accepted" value="accepted"><label for="v-accepted">Someone I accepted</label>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="band talk" id="talk" aria-labelledby="talk-title">
|
||||
<div class="container">
|
||||
<div class="talk__top"><h2 id="talk-title" data-reveal>Chat opens when both say yes</h2></div>
|
||||
<div class="grid talk__body">
|
||||
<div class="invite" data-reveal>
|
||||
<div class="invite__who">
|
||||
<span class="avatar" style="--tone:var(--tone-c)" aria-hidden="true">P</span>
|
||||
<div><h3>Priya sent you an interest</h3><p class="label">26, Sydney</p></div>
|
||||
</div>
|
||||
<div class="invite__actions" id="invite-actions">
|
||||
<button class="btn" type="button" id="t-accept">Accept</button>
|
||||
<button class="btn" type="button" id="t-decline">No thanks</button>
|
||||
<button class="btn btn--sm" type="button" id="t-reset" hidden>Start again</button>
|
||||
</div>
|
||||
<p class="invite__result" id="t-result" role="status"></p>
|
||||
</div>
|
||||
<div class="chat on-dark is-locked" id="chat" data-reveal style="--i:1">
|
||||
<ul class="chat__log" id="chat-log" role="log" aria-label="Chat with Priya"></ul>
|
||||
<form class="chat__form" id="chat-form" autocomplete="off">
|
||||
<label class="visually-hidden" for="chat-input">Message</label>
|
||||
<input id="chat-input" name="message" type="text" maxlength="300" enterkeyhint="send">
|
||||
<button class="btn btn--sm btn--primary" type="submit"><svg class="icon" aria-hidden="true"><use href="#i-send"/></svg>Send</button>
|
||||
</form>
|
||||
<div class="chat__lock"><svg class="icon" aria-hidden="true"><use href="#i-lock"/></svg><span>Chat opens when you both say yes.</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sec sec--tall" id="family" aria-label="Family view and safety tools">
|
||||
<div class="container grid together">
|
||||
<div class="tile tile--wide" data-reveal>
|
||||
<h2>Family view</h2>
|
||||
<p class="lead">A parent or sibling can look at profiles with you.</p>
|
||||
<fieldset class="choices" id="fam">
|
||||
<legend>Who helps you look</legend>
|
||||
<input type="checkbox" id="h-mum" value="Mum"><label for="h-mum">Mum</label>
|
||||
<input type="checkbox" id="h-dad" value="Dad"><label for="h-dad">Dad</label>
|
||||
<input type="checkbox" id="h-sister" value="Sister"><label for="h-sister">Sister</label>
|
||||
<input type="checkbox" id="h-brother" value="Brother"><label for="h-brother">Brother</label>
|
||||
</fieldset>
|
||||
<p class="live" id="fam-status" role="status">Just you for now.</p>
|
||||
</div>
|
||||
<div class="tile tile--narrow on-dark" id="safety" data-reveal style="--i:1">
|
||||
<h2>Safety tools</h2>
|
||||
<div class="safety__who">
|
||||
<span class="avatar" style="--tone:var(--tone-d)" aria-hidden="true">J</span>
|
||||
<div><h3>Jack, 35</h3><p class="label">Melbourne</p></div>
|
||||
</div>
|
||||
<div class="safety__actions">
|
||||
<button class="btn btn--sm" type="button" id="s-block"><svg class="icon" aria-hidden="true"><use href="#i-ban"/></svg><span>Block</span></button>
|
||||
<button class="btn btn--sm" type="button" id="s-report"><svg class="icon" aria-hidden="true"><use href="#i-flag"/></svg><span>Report</span></button>
|
||||
<button class="btn btn--sm" type="button" id="s-hide" aria-pressed="false"><svg class="icon" aria-hidden="true"><use href="#i-lock"/></svg><span>Hide my profile</span></button>
|
||||
</div>
|
||||
<p class="live" id="safe-status" role="status"></p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="band join" id="join" aria-labelledby="join-title">
|
||||
<div class="container grid">
|
||||
<div class="head">
|
||||
<h2 id="join-title" data-reveal>Make your profile</h2>
|
||||
<dl class="qa" id="help" data-reveal style="--i:1">
|
||||
<div><dt>What does it cost?</dt><dd>A free plan and a paid plan. Paid price: <span class="fill" data-fill="paid-price">to be announced</span></dd></div>
|
||||
<div><dt>Will I get alerts?</dt><dd>Email and phone alerts for matches, interests and messages.</dd></div>
|
||||
<div><dt>Who runs the site?</dt><dd>Our team reviews profiles and reports.</dd></div>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="card" id="join-card" data-reveal style="--i:2">
|
||||
<div class="tabs" role="tablist" aria-label="Join or log in">
|
||||
<button type="button" role="tab" id="tab-join" aria-selected="true" aria-controls="panel-join">Join</button>
|
||||
<button type="button" role="tab" id="tab-login" aria-selected="false" aria-controls="panel-login" tabindex="-1">Log in</button>
|
||||
</div>
|
||||
<div class="panel" role="tabpanel" id="panel-join" aria-labelledby="tab-join">
|
||||
<form data-endpoint="" novalidate class="panel">
|
||||
<div class="field"><label for="j-name">First name</label><input id="j-name" name="name" type="text" autocomplete="given-name" required></div>
|
||||
<div class="field"><label for="j-email">Email address</label><input id="j-email" name="email" type="email" autocomplete="email" inputmode="email" required></div>
|
||||
<div class="field"><label for="j-for">Joining for</label>
|
||||
<select id="j-for" name="for"><option>Myself</option><option>My son</option><option>My daughter</option><option>My brother or sister</option></select>
|
||||
</div>
|
||||
<button class="btn btn--primary" type="submit">Create your profile<svg class="icon" aria-hidden="true"><use href="#i-arrow"/></svg></button>
|
||||
<p class="form-help" aria-live="polite"></p>
|
||||
</form>
|
||||
</div>
|
||||
<div class="panel" role="tabpanel" id="panel-login" aria-labelledby="tab-login">
|
||||
<form data-endpoint="" novalidate class="panel">
|
||||
<div class="field"><label for="l-email">Email address</label><input id="l-email" name="email" type="email" autocomplete="email" inputmode="email" required></div>
|
||||
<button class="btn btn--primary" type="submit">Log in<svg class="icon" aria-hidden="true"><use href="#i-arrow"/></svg></button>
|
||||
<p class="form-help" aria-live="polite"></p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</main>
|
||||
|
||||
<footer class="foot on-dark">
|
||||
<div class="container">
|
||||
<p class="foot__sign">Warmly, the BeingOne team.</p>
|
||||
<div class="foot__row">
|
||||
<p>For Australians and their families. <time datetime="2026-10">October 2026</time></p>
|
||||
<ul class="foot__links">
|
||||
<li><a href="#find">Discover</a></li>
|
||||
<li><a href="#verified">Checks</a></li>
|
||||
<li><a href="#privacy">Photos</a></li>
|
||||
<li><a href="#talk">Messages</a></li>
|
||||
<li><a href="#join">Join</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<p data-credits>Photographs: beach by <a href="https://commons.wikimedia.org/wiki/File:Peterborough_(AU),_Port_Campbell_National_Park,_Worm_Bay_--_2019_--_0863.jpg">Dietmar Rabich</a> (CC BY-SA 4.0, Wikimedia Commons)</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>document.querySelectorAll('[data-slot] img').forEach((i) => { if (i.complete && !i.naturalWidth) i.remove(); else i.addEventListener('error', () => i.remove(), { once: true }); });</script>
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,309 +0,0 @@
|
||||
/* Hallmark · shape: Split Hero With Floating Search · genre: editorial · theme: custom (by request: the user's own reference screenshot) · job: sign up · idea: "a marriage site that opens like a wedding morning: warm paper, a serif that speaks plainly, and every demo a visitor can touch" · vibe: "warm cream, navy ink, quietly lively"
|
||||
* paper: oklch(98.4% 0.012 85) · accent: oklch(56% 0.15 38) · display: DM Serif Display · body: Figtree · hero: text left, the couple's photo bleeding off the right edge, a search bar floating across its foot · nav: edge-aligned · footer: letter close · imagery: photographs, user's own 1, library 1, natural · signature: the floating search bar that drives the Australia map and the scored matches
|
||||
* axes: light/roman-serif/warm · posture: restrained · contrast: pass · fold: pass · v2.0.0 */
|
||||
/* Hallmark · pre-emit critique: P4 H4 E4 S4 R3 V3 · weakest: R, the page now holds a lot of motion; cut every loop and kept only one-time entrances, hover lifts and state changes */
|
||||
/* Hallmark · waive 65 · the user's own reference screenshot pins cream paper, a high-contrast serif and a terracotta accent for BeingOne · the look is the client's brief, not a model default */
|
||||
/* Hallmark · waive 38ii · guard: true italic of the display face is loaded, font-synthesis none, one line of one h1 only · the closing line of the hero head mirrors the BeingOne reference the user supplied */
|
||||
/* Hallmark · waive 38iii · one italic closing line of the hero head, once on the page · it mirrors the BeingOne reference the user supplied */
|
||||
/* Hallmark · dismissed 59 · the path strip under the search bar is one row of five links that shows how the visitor moves through BeingOne, so it is wayfinding and not a content section */
|
||||
/* Hallmark · dismissed F7 · the pill radius sits on controls only: nav links, choice chips, map pins and their ping ring are all pressed to act */
|
||||
@import url("./tokens.css");
|
||||
@import url("./base.css");
|
||||
|
||||
:root {
|
||||
--color-navy-3: oklch(20% 0.06 255);
|
||||
--color-accent-on-dark: oklch(70% 0.14 38);
|
||||
--nav-h: 76px;
|
||||
--color-rule-on-navy: oklch(44% 0.05 255);
|
||||
}
|
||||
|
||||
/* type */
|
||||
h1, h2 { font-weight: 400; letter-spacing: var(--tracking-display); }
|
||||
h1 { max-width: none; font-size: clamp(3.25rem, 6.4vw, 6rem); line-height: 1; }
|
||||
h2 { max-width: 22ch; font-size: clamp(2.25rem, 3.6vw, 3.5rem); line-height: 1.04; }
|
||||
h3 { max-width: 40ch; font-weight: 400; font-size: var(--text-title); line-height: 1.2; letter-spacing: -0.01em; }
|
||||
.lead { font-size: var(--text-lead); line-height: 1.45; max-width: 46ch; color: var(--color-ink-2); }
|
||||
.label { font-size: var(--text-sm); font-weight: 700; color: var(--color-muted); }
|
||||
.muted { color: var(--color-muted); }
|
||||
body { font-weight: 500; }
|
||||
|
||||
/* local dark surfaces: components keep using the same tokens */
|
||||
.on-dark { --color-ink: var(--color-on-navy); --color-ink-2: var(--color-on-navy); --color-muted: var(--color-on-navy-muted); --color-paper-2: var(--color-navy-2); --color-paper-3: var(--color-navy-3); --color-rule: var(--color-rule-on-navy); --color-card: var(--color-navy-2); --color-card-ink: var(--color-on-navy); background: var(--color-navy); color: var(--color-on-navy); }
|
||||
|
||||
/* frame */
|
||||
.skip { position: absolute; left: var(--space-md); top: calc(-1 * var(--space-3xl)); z-index: var(--z-toast); padding: var(--space-xs) var(--space-md); background: var(--color-card); color: var(--color-card-ink); border-radius: var(--radius-control); font-weight: 700; }
|
||||
.skip:focus-visible { top: var(--space-md); }
|
||||
.grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gap-columns); }
|
||||
.sec { padding-block: var(--space-3xl); }
|
||||
.sec--tall { padding-block: var(--space-4xl); }
|
||||
.band { background: var(--color-paper-2); padding-block: var(--section-gap-s); }
|
||||
.band--navy { background: var(--color-navy); color: var(--color-on-navy); padding-block: var(--section-gap-s); }
|
||||
.head { display: grid; gap: var(--space-md); align-content: start; }
|
||||
.icon { width: 24px; height: 24px; flex-shrink: 0; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
|
||||
.icon--sm { width: 20px; height: 20px; }
|
||||
.fill { padding: 0 0.25em; border: 1px dashed color-mix(in oklch, var(--color-muted) 70%, transparent); border-radius: 3px; color: var(--color-muted); -webkit-box-decoration-break: clone; box-decoration-break: clone; }
|
||||
|
||||
/* nav: edge-aligned */
|
||||
.nav { position: sticky; top: 0; z-index: var(--z-sticky-nav); height: var(--nav-h); background: var(--color-paper); border-bottom: var(--rule-hair) solid var(--color-rule); }
|
||||
.nav__bar { height: 100%; display: flex; align-items: center; justify-content: space-between; gap: var(--space-lg); }
|
||||
.wordmark { display: inline-flex; align-items: center; gap: var(--space-xs); font: 400 var(--text-2xl)/1 var(--font-display); letter-spacing: -0.01em; text-decoration: none; color: var(--color-ink); }
|
||||
.wordmark b { font-weight: 400; color: var(--color-accent); }
|
||||
.mark { width: 34px; height: 34px; fill: none; stroke: var(--color-accent); stroke-width: 2.5; transition: transform var(--dur-long) var(--ease-out); }
|
||||
.wordmark:hover .mark { transform: rotate(-18deg); }
|
||||
.nav__links { display: flex; align-items: center; gap: var(--space-xs); }
|
||||
.nav__links a { padding: var(--space-xs) var(--space-md); border-radius: var(--radius-pill); text-decoration: none; font-weight: 700; white-space: nowrap; transition: background-color var(--dur-short) var(--ease-out); }
|
||||
.nav__links a:hover { background: var(--color-paper-2); }
|
||||
.nav__actions { display: flex; align-items: center; gap: var(--space-md); }
|
||||
.nav__signin { white-space: nowrap; font-weight: 700; color: var(--color-accent); text-decoration: none; padding: var(--space-xs); }
|
||||
.nav__signin:hover { text-decoration: underline; text-decoration-thickness: 2px; }
|
||||
.nav__actions .nav__menu { display: none; }
|
||||
.nav__links .only-sm { display: none; }
|
||||
@media (max-width: 68rem) {
|
||||
.nav__actions .nav__menu { display: inline-flex; }
|
||||
.nav__links { position: absolute; top: var(--nav-h); left: 0; right: 0; flex-direction: column; align-items: stretch; gap: 0; padding: var(--space-md) var(--gutter); background: var(--color-paper); border-bottom: var(--rule-hair) solid var(--color-rule); display: none; }
|
||||
.nav__links.is-open { display: flex; }
|
||||
.nav__links a { padding: var(--space-md) 0; border-radius: 0; border-top: var(--rule-hair) solid var(--color-rule); }
|
||||
.nav__links a:first-child { border-top: 0; }
|
||||
}
|
||||
@media (max-width: 40rem) { .nav__signin { display: none; } .nav__links .only-sm { display: block; } .nav__actions { gap: var(--space-xs); } }
|
||||
|
||||
/* controls */
|
||||
.btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--space-xs); min-height: 52px; padding: 0 var(--space-lg); border: var(--rule-bar) solid var(--color-ink); border-radius: var(--radius-control); background: transparent; color: var(--color-ink); font: 700 var(--text-md)/1.25 var(--font-body); text-decoration: none; white-space: nowrap; cursor: pointer; transition: transform var(--dur-short) var(--ease-out), background-color var(--dur-short) var(--ease-out), color var(--dur-short) var(--ease-out), border-color var(--dur-short) var(--ease-out), box-shadow var(--dur-short) var(--ease-out); }
|
||||
.btn:hover { background: var(--color-paper-3); }
|
||||
.btn:active { transform: translateY(1px); }
|
||||
.btn--sm { min-height: 44px; padding: 0 var(--space-md); font-size: var(--text-sm); }
|
||||
.btn--primary { background: var(--color-accent); border-color: var(--color-accent); color: var(--color-accent-ink); box-shadow: 0 14px 24px -14px color-mix(in oklab, var(--color-accent) 80%, transparent); }
|
||||
.btn--primary:hover { background: var(--color-accent-2); border-color: var(--color-accent-2); transform: translateY(-2px); }
|
||||
.btn--primary:active { transform: translateY(1px); }
|
||||
.btn .icon { width: 20px; height: 20px; transition: transform var(--dur-short) var(--ease-out); }
|
||||
.btn:hover .icon { transform: translateX(4px); }
|
||||
.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.55; cursor: not-allowed; transform: none; }
|
||||
.btn[aria-busy="true"] { cursor: progress; }
|
||||
.btn[aria-pressed="true"] { background: var(--color-paper-3); box-shadow: inset 0 0 0 2px var(--color-ink); }
|
||||
.on-dark .btn--primary { color: var(--color-accent-ink); }
|
||||
.on-dark .btn--primary:hover { background: var(--color-accent-2); }
|
||||
|
||||
.choices { position: relative; display: flex; flex-wrap: wrap; gap: var(--space-xs); border: 0; margin: 0; padding: 0; min-width: 0; }
|
||||
.choices legend { padding: 0; margin-bottom: var(--space-sm); font-size: var(--text-sm); font-weight: 700; color: var(--color-muted); }
|
||||
.choices input { position: absolute; opacity: 0; width: 1px; height: 1px; }
|
||||
.choices label { display: inline-flex; align-items: center; min-height: 44px; padding: 0 var(--space-md); border: var(--rule-bar) solid var(--color-rule); border-radius: var(--radius-pill); background: var(--color-card); font-weight: 700; font-size: var(--text-sm); cursor: pointer; transition: transform var(--dur-short) var(--ease-out), background-color var(--dur-short) var(--ease-out), color var(--dur-short) var(--ease-out), border-color var(--dur-short) var(--ease-out); }
|
||||
.choices label:hover { border-color: var(--color-ink); }
|
||||
.choices label:active { transform: translateY(1px); }
|
||||
.choices input:checked + label { background: var(--color-ink); border-color: var(--color-ink); color: var(--color-paper); }
|
||||
.on-dark .choices input:checked + label { color: var(--color-navy); }
|
||||
.choices input:focus-visible + label { outline: 2px solid var(--color-focus); outline-offset: 3px; }
|
||||
.choices--stack { flex-direction: column; flex-wrap: nowrap; }
|
||||
.choices--stack label { border-radius: var(--radius-control); width: 100%; }
|
||||
|
||||
.field { display: grid; gap: var(--space-xs); }
|
||||
.field label { font-size: var(--text-sm); font-weight: 700; }
|
||||
.field input:not([type="range"]), .field select, .chat__form input { width: 100%; min-height: 52px; padding: 0 var(--space-md); border: var(--rule-bar) solid var(--color-muted); border-radius: var(--radius-control); background: var(--color-card); color: var(--color-card-ink); outline: 2px solid transparent; outline-offset: -3px; transition: border-color var(--dur-short) var(--ease-out); }
|
||||
.field input:not([type="range"]):hover, .field select:hover { border-color: var(--color-ink); }
|
||||
.field input:not([type="range"]):focus-visible, .field select:focus-visible, .chat__form input:focus-visible { outline-color: var(--color-focus); border-color: var(--color-focus); }
|
||||
.field input[aria-invalid] { border-color: var(--color-error); }
|
||||
.field input[type="range"] { width: 100%; accent-color: var(--color-accent); min-height: 32px; cursor: pointer; }
|
||||
.field output { font: 400 var(--text-xl)/1 var(--font-display); font-variant-numeric: tabular-nums; }
|
||||
.field__row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-md); }
|
||||
|
||||
/* hero: photo bleeds off the right edge, head on the left */
|
||||
.hero { position: relative; background: var(--color-paper); }
|
||||
.hero__inner { position: relative; z-index: 2; padding-block: var(--space-2xl) var(--space-xl); }
|
||||
.hero__text { display: grid; gap: var(--space-lg); justify-items: start; max-width: 46%; }
|
||||
.hero h1 .line { display: block; overflow: hidden; padding: 0 0.12em 0.12em 0; margin-bottom: -0.12em; }
|
||||
.hero h1 .line > span { display: block; animation: line-up 1000ms var(--ease-out) backwards; animation-delay: calc(var(--i) * 120ms + 120ms); }
|
||||
.hero h1 .line--it > span { font-style: italic; }
|
||||
.hero__lead { animation: rise 800ms var(--ease-out) 650ms backwards; }
|
||||
.hero__cta { animation: rise 800ms var(--ease-out) 780ms backwards; }
|
||||
.hero__photo { position: absolute; z-index: 1; top: 0; right: 0; bottom: var(--space-2xl); width: 50%; margin: 0; border-radius: var(--radius-card) 0 0 var(--radius-card); animation: curtain 1300ms var(--ease-in-out) 200ms backwards; }
|
||||
.hero__photo > img { object-position: 60% 40%; animation: settle 2200ms var(--ease-out) 200ms backwards; }
|
||||
@keyframes line-up { from { transform: translateY(110%); } }
|
||||
@keyframes rise { from { opacity: 0; transform: translateY(16px); } }
|
||||
@keyframes curtain { from { clip-path: inset(0 0 0 100% round var(--radius-card)); } to { clip-path: inset(0 0 0 0 round var(--radius-card)); } }
|
||||
@keyframes settle { from { transform: scale(1.16); } }
|
||||
@media (max-width: 60rem) {
|
||||
.hero__inner { padding-block: var(--space-2xl) var(--space-xl); }
|
||||
.hero__text { max-width: none; }
|
||||
.hero__photo { position: relative; width: 100%; aspect-ratio: 4 / 3; border-radius: 0; }
|
||||
.hero { display: flex; flex-direction: column; }
|
||||
.hero__inner { order: 1; }
|
||||
.hero__photo { order: 2; }
|
||||
.quick__wrap { order: 3; }
|
||||
}
|
||||
|
||||
/* floating search bar */
|
||||
.quick__wrap { position: relative; z-index: 5; margin-bottom: calc(-1 * var(--space-2xl)); }
|
||||
.quick { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)) auto; gap: var(--space-md); align-items: end; max-width: 1120px; margin-inline: auto; padding: var(--space-lg); background: var(--color-card); border-radius: var(--radius-card); box-shadow: var(--shadow-card); animation: rise-lg 900ms var(--ease-out) 900ms backwards; }
|
||||
.quick__field { display: grid; gap: var(--space-2xs); }
|
||||
.quick__field label { font-size: var(--text-sm); font-weight: 700; color: var(--color-muted); }
|
||||
.quick select { width: 100%; min-height: 52px; padding: 0 var(--space-md); border: var(--rule-bar) solid var(--color-muted); border-radius: var(--radius-control); background: var(--color-card); color: var(--color-card-ink); font-weight: 700; transition: border-color var(--dur-short) var(--ease-out); }
|
||||
.quick select:hover { border-color: var(--color-ink); }
|
||||
.quick select:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
|
||||
.quick__go { min-width: 160px; }
|
||||
@keyframes rise-lg { from { opacity: 0; transform: translateY(40px); } }
|
||||
@media (max-width: 60rem) { .quick__wrap { margin-bottom: 0; padding-block: var(--space-lg); } .quick { grid-template-columns: minmax(0, 1fr); } }
|
||||
|
||||
/* path: a real ol */
|
||||
.band--path { padding-block: calc(var(--space-2xl) + var(--space-md)) var(--space-2xl); }
|
||||
.path { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: var(--gap-columns); counter-reset: step; }
|
||||
.path li { counter-increment: step; position: relative; display: grid; gap: var(--space-2xs); align-content: start; padding-top: var(--space-lg); }
|
||||
.path li::after { content: ""; position: absolute; inset: 0 0 auto 0; height: 3px; background: var(--color-ink); transform-origin: left; transition: transform 1000ms var(--ease-out); transition-delay: calc(var(--i, 0) * 120ms + 150ms); }
|
||||
.js .path li:not(.is-in)::after { transform: scaleX(0); }
|
||||
.path li::before { content: counter(step); font: 400 clamp(3.5rem, 6vw, 5.25rem)/0.95 var(--font-display); color: var(--color-accent); font-variant-numeric: lining-nums tabular-nums; }
|
||||
.path a { font: 700 var(--text-lg)/1.15 var(--font-body); text-decoration: none; }
|
||||
.path a:hover { text-decoration: underline; text-decoration-color: var(--color-accent); text-decoration-thickness: 3px; text-underline-offset: 0.25em; }
|
||||
@media (max-width: 60rem) { .path { grid-template-columns: minmax(0, 1fr); gap: var(--space-md); } .path li { grid-template-columns: 72px minmax(0, 1fr); align-items: center; } .path li::before { font-size: var(--text-3xl); } }
|
||||
|
||||
/* finder */
|
||||
.finder__top { align-items: end; margin-bottom: var(--space-2xl); }
|
||||
.finder__top h2 { grid-column: 1 / 8; }
|
||||
.finder__top .lead { grid-column: 8 / 13; }
|
||||
.finder__body { align-items: stretch; }
|
||||
.map { grid-column: 1 / 6; position: relative; aspect-ratio: 605 / 516; background: var(--color-paper-2); border-radius: var(--radius-card); }
|
||||
.map svg { position: absolute; inset: 0; width: 100%; height: 100%; }
|
||||
.map path { fill: var(--color-land); stroke: var(--color-card); stroke-width: 3; stroke-linejoin: round; }
|
||||
.pin { position: absolute; left: var(--x); top: var(--y); width: 36px; height: 36px; transform: translate(-50%, -50%); padding: 0; border: 0; background: transparent; cursor: pointer; border-radius: var(--radius-pill); }
|
||||
.pin::before { content: ""; position: absolute; inset: 10px; border-radius: var(--radius-pill); background: var(--color-ink); box-shadow: 0 0 0 3px var(--color-card); transition: transform var(--dur-short) var(--ease-out), background-color var(--dur-short) var(--ease-out); }
|
||||
.js .map.is-in .pin::before { animation: pop 600ms var(--ease-out) backwards; animation-delay: calc(var(--i) * 90ms + 250ms); }
|
||||
.pin:hover::before { transform: scale(1.4); }
|
||||
.pin[aria-pressed="true"]::before { background: var(--color-accent); transform: scale(1.9); }
|
||||
.pin:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 0; }
|
||||
.ping { position: absolute; inset: 8px; border-radius: var(--radius-pill); border: 2px solid var(--color-accent); pointer-events: none; animation: ping 800ms var(--ease-out) both; }
|
||||
.map__city { position: absolute; left: var(--space-md); bottom: var(--space-md); padding: var(--space-xs) var(--space-md); border-radius: var(--radius-control); background: var(--color-card); box-shadow: var(--shadow-card); font-size: var(--text-sm); font-weight: 700; }
|
||||
@keyframes pop { from { transform: scale(0); } }
|
||||
@keyframes ping { from { opacity: 0.9; transform: scale(0.6); } to { opacity: 0; transform: scale(2.8); } }
|
||||
.controls { grid-column: 6 / 13; display: grid; gap: var(--space-xl); align-content: center; padding: var(--space-xl); background: var(--color-paper-2); border-radius: var(--radius-card); }
|
||||
.controls__ages { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--gap-columns); }
|
||||
.results { margin-top: var(--space-xl); display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--gap-columns); min-height: 300px; scroll-margin-top: var(--space-3xl); }
|
||||
.person { display: grid; gap: var(--space-md); align-content: space-between; padding: var(--space-lg); background: var(--color-card); border-radius: var(--radius-card); box-shadow: var(--shadow-card); animation: rise var(--dur-long) var(--ease-out) backwards; animation-delay: calc(var(--i, 0) * 80ms); transition: transform var(--dur-short) var(--ease-out), box-shadow var(--dur-short) var(--ease-out); }
|
||||
.person:hover { transform: translateY(-5px); box-shadow: var(--shadow-lift); }
|
||||
.person__who { display: flex; align-items: center; gap: var(--space-md); }
|
||||
.person h3 { font-size: var(--text-xl); }
|
||||
.avatar { width: 56px; height: 56px; flex-shrink: 0; display: grid; place-items: center; border-radius: var(--radius-pill); background: var(--tone, var(--tone-a)); color: var(--color-navy); font: 400 var(--text-xl)/1 var(--font-display); }
|
||||
.score { display: flex; align-items: baseline; gap: var(--space-xs); }
|
||||
.score b { font: 400 var(--text-3xl)/1 var(--font-display); font-variant-numeric: lining-nums tabular-nums; }
|
||||
.bar { height: 8px; margin-top: var(--space-xs); border-radius: var(--radius-pill); background: var(--color-paper-3); overflow: hidden; }
|
||||
.bar i { display: block; height: 100%; background: var(--color-accent); transform-origin: left; transform: scaleX(calc(var(--s, 0) / 100)); animation: grow 1100ms var(--ease-out) backwards; animation-delay: calc(var(--i, 0) * 80ms + 200ms); }
|
||||
.tags { display: flex; flex-wrap: wrap; gap: var(--space-xs); padding: 0; margin: 0; list-style: none; }
|
||||
.tags li { padding: var(--space-3xs) var(--space-sm); border-radius: var(--radius-pill); border: var(--rule-bar) solid var(--color-rule); font-size: var(--text-sm); font-weight: 700; transition: background-color var(--dur-short) var(--ease-out); }
|
||||
.tags li.is-shared { background: var(--color-paper-3); border-color: var(--color-paper-3); }
|
||||
.results__empty { grid-column: 1 / -1; align-self: center; font: 400 var(--text-2xl)/1.2 var(--font-display); max-width: 30ch; animation: rise var(--dur-long) var(--ease-out) backwards; }
|
||||
.finder__note { margin-top: var(--space-md); font-size: var(--text-sm); color: var(--color-muted); }
|
||||
@keyframes grow { from { transform: scaleX(0); } }
|
||||
@media (max-width: 60rem) {
|
||||
.finder__top h2, .finder__top .lead, .map, .controls { grid-column: 1 / -1; }
|
||||
.finder__top .lead { margin-top: var(--space-md); }
|
||||
.controls { margin-top: var(--space-lg); padding: var(--space-lg); }
|
||||
.results { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
}
|
||||
@media (max-width: 40rem) { .results { grid-template-columns: minmax(0, 1fr); } .controls__ages { grid-template-columns: minmax(0, 1fr); } }
|
||||
|
||||
/* checks */
|
||||
.checks .head { grid-column: 1 / 6; }
|
||||
.checks__panel { grid-column: 7 / 13; background: var(--color-paper-2); border-radius: var(--radius-card); padding: var(--space-lg); display: grid; gap: var(--space-md); }
|
||||
.checks__who { display: flex; align-items: center; gap: var(--space-md); }
|
||||
.checks__who h3 { font-size: var(--text-xl); }
|
||||
.status { margin-left: auto; display: inline-flex; align-items: center; gap: var(--space-xs); padding: var(--space-xs) var(--space-md); border-radius: var(--radius-pill); background: var(--color-paper-3); font-size: var(--text-sm); font-weight: 700; }
|
||||
.status .icon { display: none; }
|
||||
.status[data-state="done"] { background: var(--color-on-navy); color: var(--color-navy); animation: settle-in 600ms var(--ease-out) both; }
|
||||
.status[data-state="done"] .icon { display: block; }
|
||||
@keyframes settle-in { from { transform: scale(0.9); opacity: 0.4; } }
|
||||
.progress { height: 6px; border-radius: var(--radius-pill); background: var(--color-paper-3); overflow: hidden; }
|
||||
.progress i { display: block; height: 100%; background: var(--color-accent-on-dark); transform-origin: left; transform: scaleX(var(--p, 0)); transition: transform 700ms var(--ease-out); }
|
||||
.rows { list-style: none; margin: 0; padding: 0; }
|
||||
.rows > li { display: grid; grid-template-columns: 24px minmax(0, 1fr) auto; gap: var(--space-md); align-items: center; padding-block: var(--space-md); border-top: var(--rule-hair) solid var(--color-rule); }
|
||||
.rows h3 { font: 700 var(--text-md)/1.3 var(--font-body); letter-spacing: 0; }
|
||||
.rows p { font-size: var(--text-sm); color: var(--color-muted); }
|
||||
.rows .tick { display: none; color: var(--color-accent-on-dark); }
|
||||
.rows .is-done .tick { display: block; animation: pop 500ms var(--ease-out) backwards; }
|
||||
.rows .is-done .idle { display: none; }
|
||||
.rows .passed { font-weight: 700; font-size: var(--text-sm); }
|
||||
.checks__foot { display: flex; justify-content: space-between; align-items: center; gap: var(--space-md); border-top: var(--rule-hair) solid var(--color-rule); padding-top: var(--space-md); }
|
||||
@media (max-width: 60rem) { .checks .head, .checks__panel { grid-column: 1 / -1; } .checks__panel { margin-top: var(--space-xl); } }
|
||||
@media (max-width: 40rem) { .rows > li { grid-template-columns: 24px minmax(0, 1fr); } .rows .btn, .rows .passed { grid-column: 2; justify-self: start; } .checks__who { flex-wrap: wrap; } }
|
||||
|
||||
/* photo privacy */
|
||||
.privacy__photo { grid-column: 1 / 8; position: relative; aspect-ratio: 4 / 3; border-radius: var(--radius-card); overflow: hidden; background: var(--color-paper-3); box-shadow: var(--shadow-card); margin: 0; }
|
||||
.privacy__photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 35% 40%; filter: saturate(1.06) contrast(1.04); }
|
||||
.privacy__photo .blur { filter: blur(28px) saturate(1.06); transform: scale(1.15); transition: opacity var(--dur-long) var(--ease-in-out); }
|
||||
.js .privacy__photo:not(.is-hidden) .blur { opacity: 0; }
|
||||
.privacy__badge { position: absolute; left: var(--space-lg); bottom: var(--space-lg); display: inline-flex; align-items: center; gap: var(--space-xs); padding: var(--space-xs) var(--space-md); border-radius: var(--radius-pill); background: var(--color-card); font-size: var(--text-sm); font-weight: 700; z-index: 2; box-shadow: var(--shadow-card); }
|
||||
.privacy__lock { position: absolute; inset: 0; display: grid; place-items: center; z-index: 2; transition: opacity var(--dur-long) var(--ease-in-out); }
|
||||
.privacy__disc { display: grid; place-items: center; width: 112px; height: 112px; border-radius: var(--radius-pill); background: var(--color-card); box-shadow: var(--shadow-card); transition: transform var(--dur-long) var(--ease-out); }
|
||||
.privacy__disc .icon { width: 44px; height: 44px; }
|
||||
.js .privacy__photo:not(.is-hidden) .privacy__lock { opacity: 0; }
|
||||
.js .privacy__photo:not(.is-hidden) .privacy__disc { transform: scale(0.7); }
|
||||
.privacy__badge .icon-open, .privacy__badge .icon-shut { display: none; }
|
||||
.privacy__photo:not(.is-hidden) .icon-open { display: block; }
|
||||
.privacy__photo.is-hidden .icon-shut { display: block; }
|
||||
.privacy__panel { grid-column: 9 / 13; display: grid; gap: var(--space-lg); align-content: center; }
|
||||
@media (max-width: 60rem) { .privacy__photo, .privacy__panel { grid-column: 1 / -1; } .privacy__panel { margin-top: var(--space-xl); } }
|
||||
|
||||
/* talk */
|
||||
.talk__top { margin-bottom: var(--space-2xl); }
|
||||
.talk__body { align-items: stretch; }
|
||||
.invite { grid-column: 1 / 6; display: grid; gap: var(--space-lg); align-content: space-between; padding: var(--space-xl); background: var(--color-card); border-radius: var(--radius-card); box-shadow: var(--shadow-card); }
|
||||
.invite__who { display: flex; align-items: center; gap: var(--space-md); }
|
||||
.invite h3 { font-size: var(--text-xl); }
|
||||
.invite__actions { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
|
||||
.invite__result { min-height: 1lh; font-weight: 700; }
|
||||
.chat { grid-column: 6 / 13; position: relative; display: grid; grid-template-rows: minmax(0, 1fr) auto; min-height: 380px; padding: var(--space-lg); border-radius: var(--radius-card); }
|
||||
.chat__log { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; justify-content: flex-end; gap: var(--space-xs); overflow-y: auto; }
|
||||
.chat__log li { max-width: 80%; padding: var(--space-xs) var(--space-md); border-radius: var(--radius-control); background: var(--color-paper-2); animation: rise var(--dur-short) var(--ease-out) backwards; overflow-wrap: break-word; }
|
||||
.chat__log li.me { align-self: flex-end; background: var(--color-accent); color: var(--color-accent-ink); }
|
||||
.chat__log li.note { align-self: center; max-width: 100%; background: transparent; color: var(--color-muted); font-size: var(--text-sm); font-weight: 700; }
|
||||
.chat__form { display: flex; gap: var(--space-sm); margin-top: var(--space-md); }
|
||||
.chat__form input { flex: 1; min-width: 0; }
|
||||
.chat.is-locked .chat__log, .chat.is-locked .chat__form { visibility: hidden; }
|
||||
.chat__lock { position: absolute; inset: 0; display: none; place-items: center; align-content: center; gap: var(--space-sm); text-align: center; padding: var(--space-lg); font: 400 var(--text-2xl)/1.2 var(--font-display); }
|
||||
.chat__lock .icon { width: 48px; height: 48px; margin-inline: auto; }
|
||||
.chat.is-locked .chat__lock { display: grid; }
|
||||
@media (max-width: 60rem) { .invite, .chat { grid-column: 1 / -1; } .chat { margin-top: var(--space-lg); } }
|
||||
|
||||
/* family and safety */
|
||||
.together { align-items: stretch; row-gap: var(--gap-columns); }
|
||||
.tile { display: grid; gap: var(--space-lg); align-content: start; padding: var(--space-xl); background: var(--color-paper-2); border-radius: var(--radius-card); }
|
||||
.tile--wide { grid-column: 1 / 8; }
|
||||
.tile--narrow { grid-column: 8 / 13; }
|
||||
.tile h2 { font-size: clamp(2rem, 3vw, 3rem); }
|
||||
.tile .lead { color: var(--color-ink-2); }
|
||||
.safety__who { display: flex; align-items: center; gap: var(--space-md); }
|
||||
.safety__who h3 { font-size: var(--text-xl); }
|
||||
.safety__actions { display: flex; flex-wrap: wrap; gap: var(--space-sm); }
|
||||
.live { min-height: 1lh; font-weight: 700; }
|
||||
@media (max-width: 60rem) { .tile--wide, .tile--narrow { grid-column: 1 / -1; } .tile { padding: var(--space-lg); } }
|
||||
|
||||
/* questions and join */
|
||||
.join .head { grid-column: 1 / 7; align-content: start; gap: var(--space-xl); }
|
||||
.qa { margin: 0; display: grid; }
|
||||
.qa > div { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: var(--space-md); padding-block: var(--space-md); border-top: var(--rule-hair) solid var(--color-rule); }
|
||||
.qa dt { font: 700 var(--text-md)/1.3 var(--font-body); }
|
||||
.qa dd { margin: 0; color: var(--color-ink-2); }
|
||||
.card { grid-column: 8 / 13; background: var(--color-card); color: var(--color-card-ink); border-radius: var(--radius-card); box-shadow: var(--shadow-card); padding: var(--space-xl); display: grid; gap: var(--space-lg); align-content: start; }
|
||||
.tabs { display: flex; gap: var(--space-xs); border-bottom: var(--rule-bar) solid var(--color-rule); }
|
||||
.tabs button { min-height: 44px; padding: 0 var(--space-md); border: 0; border-bottom: 4px solid transparent; margin-bottom: calc(-1 * var(--space-3xs)); background: transparent; color: inherit; font-weight: 700; cursor: pointer; transition: border-color var(--dur-short) var(--ease-out); }
|
||||
.tabs button:hover { border-bottom-color: var(--color-rule); }
|
||||
.tabs button[aria-selected="true"] { border-bottom-color: var(--color-accent); }
|
||||
.form-help { min-height: 1lh; font-size: var(--text-sm); }
|
||||
.form-help.is-error { color: var(--color-error); font-weight: 700; }
|
||||
.panel { display: grid; gap: var(--space-md); }
|
||||
@media (max-width: 60rem) { .join .head, .card { grid-column: 1 / -1; } .card { margin-top: var(--space-xl); padding: var(--space-lg); } .qa > div { grid-template-columns: minmax(0, 1fr); gap: var(--space-2xs); } }
|
||||
|
||||
/* footer: letter close */
|
||||
.foot { padding-block: var(--space-3xl) var(--space-xl); }
|
||||
.foot__sign { font: 400 var(--text-display-s)/1.05 var(--font-display); letter-spacing: var(--tracking-display); max-width: 18ch; text-wrap: balance; }
|
||||
.foot__row { margin-top: var(--space-2xl); display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--space-lg); font-size: var(--text-sm); }
|
||||
.foot__links { display: flex; flex-wrap: wrap; gap: var(--space-lg); list-style: none; margin: 0; padding: 0; }
|
||||
.foot__links a { font-weight: 700; }
|
||||
.foot__links a:hover { text-decoration-color: var(--color-accent-on-dark); text-decoration-thickness: 3px; }
|
||||
.foot [data-credits] { margin-top: var(--space-lg); color: var(--color-muted); font-size: var(--text-xs); max-width: 80ch; }
|
||||
|
||||
/* one scroll reveal, visible without script */
|
||||
.js [data-reveal] { opacity: 0; transform: translateY(18px); transition: opacity 800ms var(--ease-out), transform 800ms var(--ease-out); transition-delay: calc(var(--i, 0) * 110ms); }
|
||||
.js [data-reveal].is-in { opacity: 1; transform: none; }
|
||||
.js .person[data-reveal], .js li[data-reveal] { transition-property: opacity, transform; }
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.js [data-reveal] { opacity: 1; transform: none; transition: none; }
|
||||
.hero h1 .line > span, .hero__lead, .hero__cta, .hero__photo, .hero__photo > img, .quick, .person, .bar i, .chat__log li, .ping, .status, .rows .is-done .tick, .js .map.is-in .pin::before { animation: none; }
|
||||
.bar i { transform: scaleX(calc(var(--s, 0) / 100)); }
|
||||
.js .path li:not(.is-in)::after { transform: none; }
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
:root {
|
||||
--space-3xs: 2px; --space-2xs: 4px; --space-xs: 8px; --space-sm: 12px; --space-md: 16px; --space-lg: 24px; --space-xl: 40px; --space-2xl: 64px; --space-3xl: 96px; --space-4xl: 144px;
|
||||
--text-xs: 0.8125rem; --text-sm: 0.875rem; --text-md: 1rem; --text-lg: 1.25rem; --text-xl: 1.5625rem; --text-2xl: 1.953rem; --text-3xl: 2.441rem;
|
||||
--text-display-s: clamp(2.25rem, 4vw + 0.5rem, 3.75rem); --text-display: clamp(2.75rem, 5vw + 1rem, 5.25rem);
|
||||
--text-section: clamp(2rem, 2.5vw + 1rem, 3.5rem); --text-title: clamp(1.25rem, 0.75vw + 0.875rem, 1.625rem); --text-lead: clamp(1.125rem, 0.35vw + 1rem, 1.375rem);
|
||||
--ease-out: cubic-bezier(0.16, 1, 0.3, 1); --ease-in: cubic-bezier(0.7, 0, 0.84, 0); --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
|
||||
--dur-micro: 120ms; --dur-short: 220ms; --dur-long: 420ms;
|
||||
--color-error: oklch(52% 0.19 27); --color-success: oklch(50% 0.12 150);
|
||||
--container: 1440px; --gutter: 64px; --gap-columns: 32px; --section-gap-s: 120px; --section-gap: 144px; --section-gap-l: 176px;
|
||||
--z-base: 1; --z-raised: 10; --z-dropdown: 100; --z-sticky: 200; --z-sticky-nav: 300; --z-modal: 400; --z-toast: 500; --z-tooltip: 600;
|
||||
--color-paper: oklch(98.4% 0.012 85); --color-paper-2: oklch(95.6% 0.02 80); --color-paper-3: oklch(91.5% 0.03 75);
|
||||
--color-ink: oklch(25% 0.07 255); --color-ink-2: oklch(36% 0.065 255); --color-muted: oklch(46% 0.045 255);
|
||||
--color-rule: oklch(87% 0.025 80);
|
||||
--color-accent: oklch(56% 0.15 38); --color-accent-2: oklch(49% 0.15 38); --color-accent-ink: oklch(99% 0.008 85); --color-focus: oklch(58% 0.19 38);
|
||||
--color-card: oklch(99.6% 0.006 85); --color-card-ink: oklch(25% 0.07 255);
|
||||
--color-navy: oklch(25% 0.07 255); --color-navy-2: oklch(31% 0.07 255); --color-on-navy: oklch(97% 0.015 85); --color-on-navy-muted: oklch(82% 0.03 255);
|
||||
--color-land: oklch(88% 0.04 250);
|
||||
--font-display: "DM Serif Display", ui-serif, Georgia, serif; --font-body: "Figtree", ui-sans-serif, system-ui, sans-serif; --font-outlier: var(--font-display);
|
||||
--radius-card: 24px; --radius-control: 14px; --radius-pill: 999px; --rule-hair: 1px; --rule-bar: 2px;
|
||||
--shadow-card: 0 18px 40px -22px oklch(25% 0.07 255 / 0.35), 0 2px 6px oklch(25% 0.07 255 / 0.06);
|
||||
--shadow-lift: 0 26px 48px -24px oklch(25% 0.07 255 / 0.45), 0 3px 8px oklch(25% 0.07 255 / 0.08);
|
||||
--tracking-display: -0.025em;
|
||||
--tone-a: oklch(86% 0.08 20); --tone-b: oklch(92% 0.09 95); --tone-c: oklch(88% 0.07 150); --tone-d: oklch(86% 0.06 235);
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
.hyperframes/artifacts/
|
||||
node_modules/
|
||||
@@ -0,0 +1,233 @@
|
||||
<!--
|
||||
Daisy Days — caption skin (preset-local source).
|
||||
|
||||
This is the preset's own lower-third karaoke caption look. product-launch-video's
|
||||
Step 2 copies it into the project as caption-skin.html; captions.mjs then fills the
|
||||
three reserved holes, wraps the fragment in a <template>, and writes
|
||||
compositions/captions.html:
|
||||
· the empty GROUPS array → the engine's scene-aware word groups
|
||||
· the 0 duration + 0 width/height → real total + canvas size
|
||||
· the empty data-brand-tokens style → :root tokens derived from the project's frame.md
|
||||
|
||||
Token contract — reference ONLY this fixed vocab (captions.mjs injects it from
|
||||
frame.md, so the Step-2 brand overlay flows through; each var has a daisy-days literal
|
||||
fallback for standalone preview):
|
||||
--cap-ink · --cap-canvas · --cap-accent · --cap-accent-2 · --font-display ·
|
||||
--font-body · --cap-band-top · --cap-band-height
|
||||
Hooks (do not rename): .caption-group / .caption-word + states .is-active / .is-spoken,
|
||||
root data-composition-id="captions", timeline at window.__timelines["captions"].
|
||||
State changes use gsap.set({className}) (applied on the engine's frame-by-frame seek);
|
||||
never tl.call() callbacks (seek does not fire them → wrong state on render).
|
||||
|
||||
Visual: a cheerful picture-book card — a cream surface inside a 3px charcoal outline
|
||||
with a hard 6px charcoal offset shadow (no blur) and a generous 24px radius, the
|
||||
sticker-on-paper signature. Fredoka One glyphs, sentence case, charcoal ink. Upcoming
|
||||
words sit in muted charcoal; the current word pops into a rounded sunny-pastel candy
|
||||
block (coral fill, 3px charcoal outline, hard 3px offset shadow, 12px radius) with a
|
||||
bouncy scale pop; spoken words settle to solid charcoal, the candy block cleared.
|
||||
-->
|
||||
<script src="assets/vendor/gsap.min.js"></script>
|
||||
|
||||
<!-- captions.mjs injects the project's :root tokens here -->
|
||||
<style data-brand-tokens></style>
|
||||
|
||||
<style>
|
||||
@font-face { font-family: "Fredoka"; src: url("assets/fonts/fredoka-600.woff2") format("woff2"); font-weight: 600; font-style: normal; }
|
||||
@font-face { font-family: "Fredoka One"; src: url("assets/fonts/fredoka-600.woff2") format("woff2"); font-weight: 600; font-style: normal; }
|
||||
@font-face { font-family: "Quicksand"; src: url("assets/fonts/quicksand-var.woff2") format("woff2"); font-weight: 500 700; font-style: normal; }
|
||||
#captions-root {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.caption-layer {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 20;
|
||||
pointer-events: none;
|
||||
}
|
||||
/* the keep-out band, from captionBand(H) — frame content stays above it */
|
||||
.caption-stage {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: var(--cap-band-top, 900px);
|
||||
height: var(--cap-band-height, 180px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.caption-group {
|
||||
/* every group is absolutely stacked over the SAME band — exactly one shown at a
|
||||
time via opacity. Must be absolute: in-flow groups would lay out side-by-side. */
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* THE picture-book card — cream surface, 3px charcoal outline, generous 24px radius,
|
||||
a hard 6px charcoal offset shadow (no blur): the sticker-on-paper signature */
|
||||
.caption-pill {
|
||||
max-width: 80%;
|
||||
padding: 18px 40px 22px;
|
||||
background: var(--cap-canvas, #f5f0e6);
|
||||
border: 3px solid var(--cap-ink, #2d2d2d);
|
||||
border-radius: 24px;
|
||||
box-shadow: 6px 6px 0 var(--cap-ink, #2d2d2d);
|
||||
}
|
||||
.caption-line {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 0.18em 0.32em;
|
||||
font-family: var(--font-display, "Fredoka"), sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: clamp(38px, 4.2vw, 56px);
|
||||
line-height: 1.22;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
/* upcoming — muted charcoal, no candy block */
|
||||
.caption-word {
|
||||
display: inline-block;
|
||||
padding: 0.02em 0.16em;
|
||||
border-radius: 12px;
|
||||
color: color-mix(in srgb, var(--cap-ink, #2d2d2d) 52%, var(--cap-canvas, #f5f0e6));
|
||||
}
|
||||
/* current word — THE sunny-pastel candy block: a rounded coral chip with a 3px
|
||||
charcoal outline + a hard 3px charcoal offset shadow (no blur), charcoal on top */
|
||||
.caption-word.is-active {
|
||||
color: var(--cap-ink, #2d2d2d);
|
||||
background: var(--cap-accent, #f8635f);
|
||||
border-radius: 12px;
|
||||
box-shadow:
|
||||
0 0 0 3px var(--cap-ink, #2d2d2d),
|
||||
3px 5px 0 0 var(--cap-ink, #2d2d2d);
|
||||
}
|
||||
/* already spoken — solid charcoal, candy block cleared */
|
||||
.caption-word.is-spoken {
|
||||
color: var(--cap-ink, #2d2d2d);
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* optional per-word accents (dormant until a word-classer tags them) */
|
||||
/* brand / key term — a butter candy chip, the cheerful second pastel */
|
||||
.caption-word.cap-brand {
|
||||
color: var(--cap-ink, #2d2d2d);
|
||||
background: var(--cap-accent-2, #fde68a);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 0 0 3px var(--cap-ink, #2d2d2d);
|
||||
}
|
||||
/* numerals / data — Quicksand, slightly recessed */
|
||||
.caption-word.cap-num {
|
||||
font-family: var(--font-body, "Quicksand"), system-ui, sans-serif;
|
||||
font-weight: 700;
|
||||
color: color-mix(in srgb, var(--cap-ink, #2d2d2d) 78%, var(--cap-canvas, #f5f0e6));
|
||||
}
|
||||
/* emphasis — a butter underline rule (the second sunny pastel) */
|
||||
.caption-word.cap-cta {
|
||||
text-decoration: underline;
|
||||
text-decoration-thickness: 3px;
|
||||
text-decoration-color: var(--cap-accent-2, #fde68a);
|
||||
text-underline-offset: 0.12em;
|
||||
}
|
||||
|
||||
@media (max-aspect-ratio: 9/16) {
|
||||
.caption-pill {
|
||||
max-width: 92%;
|
||||
}
|
||||
.caption-line {
|
||||
font-size: clamp(32px, 5.2vw, 46px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div
|
||||
id="captions-root"
|
||||
data-composition-id="captions"
|
||||
data-timeline-locked
|
||||
data-start="0"
|
||||
data-duration="0"
|
||||
data-fps="30"
|
||||
data-width="0"
|
||||
data-height="0"
|
||||
>
|
||||
<div class="caption-layer" aria-hidden="true">
|
||||
<div id="caption-stage" class="caption-stage"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// captions.mjs injects the engine's scene-aware groups + real duration here.
|
||||
var GROUPS = [];
|
||||
var DURATION = 0;
|
||||
|
||||
(function () {
|
||||
var stage = document.getElementById("caption-stage");
|
||||
|
||||
// build DOM: one .caption-group per group, .caption-word per word
|
||||
GROUPS.forEach(function (group, g) {
|
||||
var groupEl = document.createElement("div");
|
||||
groupEl.className = "caption-group";
|
||||
groupEl.id = "caption-group-" + g;
|
||||
var pill = document.createElement("div");
|
||||
pill.className = "caption-pill";
|
||||
var line = document.createElement("div");
|
||||
line.className = "caption-line";
|
||||
(group.words || []).forEach(function (w, i) {
|
||||
var span = document.createElement("span");
|
||||
span.className = "caption-word";
|
||||
span.id = "caption-word-" + g + "-" + i;
|
||||
span.textContent = String(w.text);
|
||||
line.appendChild(span);
|
||||
});
|
||||
pill.appendChild(line);
|
||||
groupEl.appendChild(pill);
|
||||
stage.appendChild(groupEl);
|
||||
});
|
||||
|
||||
window.__timelines = window.__timelines || {};
|
||||
var tl = gsap.timeline({ paused: true });
|
||||
|
||||
GROUPS.forEach(function (group, g) {
|
||||
var groupEl = document.getElementById("caption-group-" + g);
|
||||
var words = group.words || [];
|
||||
var next = GROUPS[g + 1];
|
||||
var isLast = g === GROUPS.length - 1;
|
||||
var start = Math.max(0, Number(group.start));
|
||||
var end = isLast ? DURATION : Math.min(Number(next.start), Number(group.end) + 0.3);
|
||||
if (end <= start) end = start + 0.01;
|
||||
|
||||
// group on/off — exactly one group visible at a time
|
||||
tl.set(groupEl, { opacity: 1 }, start);
|
||||
tl.set(groupEl, { opacity: 0 }, end);
|
||||
|
||||
// 3-state karaoke via className SETS — seek-safe (gsap.set applies on the
|
||||
// engine's frame-by-frame seek; .call callbacks would NOT fire).
|
||||
words.forEach(function (w, i) {
|
||||
var el = document.getElementById("caption-word-" + g + "-" + i);
|
||||
var at = Math.max(start, Number(w.start));
|
||||
tl.set(el, { className: "caption-word" }, start); // upcoming (also resets on reverse-seek)
|
||||
tl.set(el, { className: "caption-word is-active" }, at); // current
|
||||
tl.fromTo(el, { scale: 0.82 }, { scale: 1, duration: 0.2, ease: "back.out(2.6)" }, at);
|
||||
if (i + 1 < words.length) {
|
||||
var nextAt = Math.max(start, Number(words[i + 1].start));
|
||||
tl.set(el, { className: "caption-word is-spoken" }, nextAt); // demote when next activates
|
||||
}
|
||||
});
|
||||
if (words.length) {
|
||||
var lastEl = document.getElementById("caption-word-" + g + "-" + (words.length - 1));
|
||||
var lastSpoken = Math.min(end, Number(words[words.length - 1].end) + 0.1);
|
||||
tl.set(lastEl, { className: "caption-word is-spoken" }, lastSpoken);
|
||||
}
|
||||
});
|
||||
|
||||
// full-span anchor so the sub-comp timeline spans the whole video
|
||||
tl.to({}, { duration: DURATION }, 0);
|
||||
window.__timelines["captions"] = tl;
|
||||
})();
|
||||
</script>
|
||||
@@ -0,0 +1 @@
|
||||
635d4927-f2e8-44dd-9cbf-1b5d4f285f53
|
||||
@@ -0,0 +1 @@
|
||||
{"version":1,"paths":["renders/video.mp4"]}
|
||||
@@ -0,0 +1,939 @@
|
||||
{
|
||||
"version": 1,
|
||||
"historyId": "635d4927-f2e8-44dd-9cbf-1b5d4f285f53",
|
||||
"currentRevision": "6999d82e-2d3b-4026-b89c-d3107735bf7e",
|
||||
"pendingChanges": false,
|
||||
"files": {
|
||||
".media/manifest.jsonl": {
|
||||
"hash": "0619ff69adc91e800fdbfe4cd508b67d21791a1ef4eb8b043518158c0ce3483e",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/06/0619ff69adc91e800fdbfe4cd508b67d21791a1ef4eb8b043518158c0ce3483e"
|
||||
},
|
||||
"AGENTS.md": {
|
||||
"hash": "1d4f0c8ca2507b94fd7c9df709fff01416adbd51a0f922b9d6ed2f40129147d5",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/1d/1d4f0c8ca2507b94fd7c9df709fff01416adbd51a0f922b9d6ed2f40129147d5"
|
||||
},
|
||||
"BRIEF.md": {
|
||||
"hash": "14d649b0556246e716324f80fc2b65b27aaa4a25d5f508c9e6fceb702f29ebb4",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/14/14d649b0556246e716324f80fc2b65b27aaa4a25d5f508c9e6fceb702f29ebb4"
|
||||
},
|
||||
"CLAUDE.md": {
|
||||
"hash": "1d4f0c8ca2507b94fd7c9df709fff01416adbd51a0f922b9d6ed2f40129147d5",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/1d/1d4f0c8ca2507b94fd7c9df709fff01416adbd51a0f922b9d6ed2f40129147d5"
|
||||
},
|
||||
"SCRIPT.md": {
|
||||
"hash": "5fbae06748238e1717948353b077a8776b7f88221790923652363834c49fad9a",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/5f/5fbae06748238e1717948353b077a8776b7f88221790923652363834c49fad9a"
|
||||
},
|
||||
"STORYBOARD.md": {
|
||||
"hash": "34f5c1242e964e76cf330da278bb80d9174ba52197439863a9c32f6a2bf23383",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/34/34f5c1242e964e76cf330da278bb80d9174ba52197439863a9c32f6a2bf23383"
|
||||
},
|
||||
"assets/fonts/fredoka-600.woff2": {
|
||||
"hash": "b62f2898de150f019961f4884a49f83dcd2ce74375be5e0992c594ebb8f30294",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/b6/b62f2898de150f019961f4884a49f83dcd2ce74375be5e0992c594ebb8f30294"
|
||||
},
|
||||
"assets/fonts/quicksand-var.woff2": {
|
||||
"hash": "2add7d60b1cd2ab84c9967e23d5ec08eb3fc9635c46855b17d59404dec6b410e",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/2a/2add7d60b1cd2ab84c9967e23d5ec08eb3fc9635c46855b17d59404dec6b410e"
|
||||
},
|
||||
"assets/voice/01.wav": {
|
||||
"hash": "ef67616aef5fe0312c5a5a833eaba38438d7a1248057dcdd00b4d7053b064e98",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/ef/ef67616aef5fe0312c5a5a833eaba38438d7a1248057dcdd00b4d7053b064e98"
|
||||
},
|
||||
"assets/voice/02.wav": {
|
||||
"hash": "c4b74e279af592152edbe412bc477e2fe8da05cb5add99bdbd55ed536d80cc1b",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/c4/c4b74e279af592152edbe412bc477e2fe8da05cb5add99bdbd55ed536d80cc1b"
|
||||
},
|
||||
"assets/voice/03.wav": {
|
||||
"hash": "e8537998055079e160467161206dcc3c51d8cc98411f89f42e478f3672fe9630",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/e8/e8537998055079e160467161206dcc3c51d8cc98411f89f42e478f3672fe9630"
|
||||
},
|
||||
"assets/voice/04.wav": {
|
||||
"hash": "e9e118731fb136fab2751e5392c47a1b89598acac4bee763962ba0e6f3ede377",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/e9/e9e118731fb136fab2751e5392c47a1b89598acac4bee763962ba0e6f3ede377"
|
||||
},
|
||||
"assets/voice/05.wav": {
|
||||
"hash": "70c9e8aad9f6f0167e2d9e31d830a27e0aa313e1307085b73e858c8108dc83e8",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/70/70c9e8aad9f6f0167e2d9e31d830a27e0aa313e1307085b73e858c8108dc83e8"
|
||||
},
|
||||
"assets/voice/06.wav": {
|
||||
"hash": "9441a5b1472967c809efb6ff246e25800e74fd9e6372a748c73568e4450108c3",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/94/9441a5b1472967c809efb6ff246e25800e74fd9e6372a748c73568e4450108c3"
|
||||
},
|
||||
"assets/voice/07.wav": {
|
||||
"hash": "4fbc575c406ead86d77a06c79dcd680303c7a935147208936c83969d0b4121b3",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/4f/4fbc575c406ead86d77a06c79dcd680303c7a935147208936c83969d0b4121b3"
|
||||
},
|
||||
"assets/voice/08.wav": {
|
||||
"hash": "7859a7ded9d7d2fe821b93162b97790c70b6929ff07211f230f9cc0f75764e95",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/78/7859a7ded9d7d2fe821b93162b97790c70b6929ff07211f230f9cc0f75764e95"
|
||||
},
|
||||
"assets/voice/09.wav": {
|
||||
"hash": "0864df842c3d65cfb43aafd936de8bc963cd91aca56248475a8eb2c968fd4a55",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/08/0864df842c3d65cfb43aafd936de8bc963cd91aca56248475a8eb2c968fd4a55"
|
||||
},
|
||||
"audio_engine_meta.json": {
|
||||
"hash": "4f2da6bf20a3982fb9ed326e7a457cac7e7128ef7e5e08d585f58bbf47a8c397",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/4f/4f2da6bf20a3982fb9ed326e7a457cac7e7128ef7e5e08d585f58bbf47a8c397"
|
||||
},
|
||||
"audio_meta.json": {
|
||||
"hash": "ecc4980e89d34d9873cdc8a92f954b38dcf094112a5bab89fde7fe98a321b624",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/ec/ecc4980e89d34d9873cdc8a92f954b38dcf094112a5bab89fde7fe98a321b624"
|
||||
},
|
||||
"audio_request.json": {
|
||||
"hash": "76765154cffa684843af5b4bc6492f4e22d7a6aa9d2b6a716351eceab241a464",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/76/76765154cffa684843af5b4bc6492f4e22d7a6aa9d2b6a716351eceab241a464"
|
||||
},
|
||||
"caption-overrides.json": {
|
||||
"hash": "37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/37/37517e5f3dc66819f61f5a7bb8ace1921282415f10551d2defa5c3eb0985b570"
|
||||
},
|
||||
"caption_groups.json": {
|
||||
"hash": "8b53722d14f329a000bcd109192eaedf8f098e16f4e553381c1a139843f8fb94",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/8b/8b53722d14f329a000bcd109192eaedf8f098e16f4e553381c1a139843f8fb94"
|
||||
},
|
||||
"capture/extracted/asset-descriptions.md": {
|
||||
"hash": "92c2cfe647902a93e595e21cebab23e9af1a2fefbec14cf22d0a5af437dc6964",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/92/92c2cfe647902a93e595e21cebab23e9af1a2fefbec14cf22d0a5af437dc6964"
|
||||
},
|
||||
"capture/extracted/tokens.json": {
|
||||
"hash": "2f533a1d991bdf84ad653ceb0061fbefd42a19f7b4dc22fe9b37f7156ce79c32",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/2f/2f533a1d991bdf84ad653ceb0061fbefd42a19f7b4dc22fe9b37f7156ce79c32"
|
||||
},
|
||||
"capture/extracted/visible-text.txt": {
|
||||
"hash": "39c044a9ee527c4a857cb65b5f0dc3f855fca4a7d17beb8ffb2cf24089f5d54f",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/39/39c044a9ee527c4a857cb65b5f0dc3f855fca4a7d17beb8ffb2cf24089f5d54f"
|
||||
},
|
||||
"compositions/captions.html": {
|
||||
"hash": "c7a724d68db626674aa77f2e4b9967b63cb606d3dd1156796d0a319e23f1e0e8",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/c7/c7a724d68db626674aa77f2e4b9967b63cb606d3dd1156796d0a319e23f1e0e8"
|
||||
},
|
||||
"compositions/frames/01-hook.html": {
|
||||
"hash": "48852887a870cc3daa0c98e65504ee207475b7add2b4eecb79fe304b0539441b",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/48/48852887a870cc3daa0c98e65504ee207475b7add2b4eecb79fe304b0539441b"
|
||||
},
|
||||
"compositions/frames/02-worry.html": {
|
||||
"hash": "36c53f5f5bdcbf9ebb6a7c73dc22017e80dfc64bd98470d78af8ef7846bb1d94",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/36/36c53f5f5bdcbf9ebb6a7c73dc22017e80dfc64bd98470d78af8ef7846bb1d94"
|
||||
},
|
||||
"compositions/frames/03-meet.html": {
|
||||
"hash": "33f5f3cc5d827610300ff1198268b19f675d3adc26898e76ed11f7a89be5ef67",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/33/33f5f3cc5d827610300ff1198268b19f675d3adc26898e76ed11f7a89be5ef67"
|
||||
},
|
||||
"compositions/frames/04-limits.html": {
|
||||
"hash": "fd4173fd65eff6f6ca43680ba4824545ae6bb57eb8710780a035c9dd120ebc37",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/fd/fd4173fd65eff6f6ca43680ba4824545ae6bb57eb8710780a035c9dd120ebc37"
|
||||
},
|
||||
"compositions/frames/05-apps.html": {
|
||||
"hash": "5da142d1be64b6d51d5c707ac913fdf819a0419288696974c2775b1f35e3654e",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/5d/5da142d1be64b6d51d5c707ac913fdf819a0419288696974c2775b1f35e3654e"
|
||||
},
|
||||
"compositions/frames/06-location.html": {
|
||||
"hash": "199c8b0642ea141b105b1eb7f62ff545b4b3f77dcbf1767f6581cdceac9ac019",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/19/199c8b0642ea141b105b1eb7f62ff545b4b3f77dcbf1767f6581cdceac9ac019"
|
||||
},
|
||||
"compositions/frames/07-balance.html": {
|
||||
"hash": "6ed5fc2fb15ca1573c5ff92fc4d6c73aa89808776f0236d1934f0537b3e42a8e",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/6e/6ed5fc2fb15ca1573c5ff92fc4d6c73aa89808776f0236d1934f0537b3e42a8e"
|
||||
},
|
||||
"compositions/frames/08-platforms.html": {
|
||||
"hash": "b0a5b3c9b1d4bd94c0b3f9f7b71e7137632d8e400add3f5e93958acb7036d99a",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/b0/b0a5b3c9b1d4bd94c0b3f9f7b71e7137632d8e400add3f5e93958acb7036d99a"
|
||||
},
|
||||
"compositions/frames/09-cta.html": {
|
||||
"hash": "d9e539932cec2431c43f6125a26bb452abc66a2f7c616b1d1e26da5911e80e07",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/d9/d9e539932cec2431c43f6125a26bb452abc66a2f7c616b1d1e26da5911e80e07"
|
||||
},
|
||||
"frame.md": {
|
||||
"hash": "42d827dbd279990052e171d04380b5e6bbc111ae391dc283deb7a452e70b9b97",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/42/42d827dbd279990052e171d04380b5e6bbc111ae391dc283deb7a452e70b9b97"
|
||||
},
|
||||
"hyperframes.json": {
|
||||
"hash": "44d4e8dcefebce0a13f5afa82aa270b0b19a1d3f82e434f92616010cee775dc4",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/44/44d4e8dcefebce0a13f5afa82aa270b0b19a1d3f82e434f92616010cee775dc4"
|
||||
},
|
||||
"index.html": {
|
||||
"hash": "7f9f086ba7fb700d1308e5f9efee068c11034983a04dfc6baed7b8096034ea32",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/7f/7f9f086ba7fb700d1308e5f9efee068c11034983a04dfc6baed7b8096034ea32"
|
||||
},
|
||||
"meta.json": {
|
||||
"hash": "1497903acd6ced7f19d4cf6c76f104f5656593c484427d89aea883c8246ad541",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/14/1497903acd6ced7f19d4cf6c76f104f5656593c484427d89aea883c8246ad541"
|
||||
},
|
||||
"package.json": {
|
||||
"hash": "6873ac1737fc27fd1046b92a493604be2ebc328b232d134f04f3b65c07200b4f",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/68/6873ac1737fc27fd1046b92a493604be2ebc328b232d134f04f3b65c07200b4f"
|
||||
},
|
||||
"assets/vendor/gsap.min.js": {
|
||||
"hash": "c174bfce53a729418d57a8ad8625e7247c793a22fef8e2851e3cfa3de9cd8280",
|
||||
"content": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/c1/c174bfce53a729418d57a8ad8625e7247c793a22fef8e2851e3cfa3de9cd8280"
|
||||
}
|
||||
},
|
||||
"revisions": {
|
||||
"ad80a38d-f38a-4cc1-9042-d179e2b0e6f3": {
|
||||
"actor": {
|
||||
"kind": "outside",
|
||||
"name": "Outside"
|
||||
},
|
||||
"label": "Changed outside the app",
|
||||
"startedAt": 1792016103184,
|
||||
"endedAt": 1792016103225,
|
||||
"files": {
|
||||
"compositions/frames/03-meet.html": {
|
||||
"before": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/96/96f8c3849528fd883b0c70f66c0fd291aa3030adaaa346a8ebdf3c95aeb38d7e",
|
||||
"after": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/33/33f5f3cc5d827610300ff1198268b19f675d3adc26898e76ed11f7a89be5ef67"
|
||||
},
|
||||
"compositions/frames/09-cta.html": {
|
||||
"before": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/a9/a924e8f0e68f92423d70d4d8e086d81f0596cec3d6ad1120d1c7e930fd086fad",
|
||||
"after": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/35/3566b01fb9bb64e4d22e86877179c7b7cbee0a98f4bb3c354c97db2b85b13b15"
|
||||
}
|
||||
}
|
||||
},
|
||||
"2748be21-fde2-40ba-a2c0-fddfb7e47431": {
|
||||
"actor": {
|
||||
"kind": "outside",
|
||||
"name": "Outside"
|
||||
},
|
||||
"label": "Changed outside the app",
|
||||
"startedAt": 1792016129829,
|
||||
"endedAt": 1792016129859,
|
||||
"files": {
|
||||
"assets/vendor/gsap.min.js": {
|
||||
"before": null,
|
||||
"after": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/c1/c174bfce53a729418d57a8ad8625e7247c793a22fef8e2851e3cfa3de9cd8280"
|
||||
},
|
||||
"index.html": {
|
||||
"before": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/cb/cb8df64b81d4e2ad46e13002a5697224c5e21c3c04e925d3302f8c4ceb0a58c3",
|
||||
"after": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/7f/7f9f086ba7fb700d1308e5f9efee068c11034983a04dfc6baed7b8096034ea32"
|
||||
}
|
||||
}
|
||||
},
|
||||
"f155d8de-7fb6-4e12-9291-60b3874a47cc": {
|
||||
"actor": {
|
||||
"kind": "outside",
|
||||
"name": "Outside"
|
||||
},
|
||||
"label": "Changed outside the app",
|
||||
"startedAt": 1792016156924,
|
||||
"endedAt": 1792016156944,
|
||||
"files": {
|
||||
"compositions/captions.html": {
|
||||
"before": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/d9/d9ed837d5d7a9893cf38400b360adc8d5636489ede0eaffb3f4e341faab51c04",
|
||||
"after": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/c7/c7a724d68db626674aa77f2e4b9967b63cb606d3dd1156796d0a319e23f1e0e8"
|
||||
},
|
||||
"compositions/frames/01-hook.html": {
|
||||
"before": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/1f/1f8e5283549f95e82cfa7324067517b68a5c852ee0400e39a4b8eeadb8d2afdb",
|
||||
"after": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/f4/f4e6a9d0f2414e3f78e0b7ec499f3adf397e480ad3e3cbfc13110bd9ee6553f3"
|
||||
}
|
||||
}
|
||||
},
|
||||
"6999d82e-2d3b-4026-b89c-d3107735bf7e": {
|
||||
"actor": {
|
||||
"kind": "outside",
|
||||
"name": "Outside"
|
||||
},
|
||||
"label": "Changed outside the app",
|
||||
"startedAt": 1792016208793,
|
||||
"endedAt": 1792016208815,
|
||||
"files": {
|
||||
"compositions/frames/01-hook.html": {
|
||||
"before": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/f4/f4e6a9d0f2414e3f78e0b7ec499f3adf397e480ad3e3cbfc13110bd9ee6553f3",
|
||||
"after": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/48/48852887a870cc3daa0c98e65504ee207475b7add2b4eecb79fe304b0539441b"
|
||||
},
|
||||
"compositions/frames/02-worry.html": {
|
||||
"before": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/4d/4df905219fb45cf58401646096425b66025ec56d32b12fca340e88e5a07ac264",
|
||||
"after": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/36/36c53f5f5bdcbf9ebb6a7c73dc22017e80dfc64bd98470d78af8ef7846bb1d94"
|
||||
},
|
||||
"compositions/frames/04-limits.html": {
|
||||
"before": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/0b/0b852cb30390684e6002b762165405fabb56cad4955fc8287e84d595bd1891d3",
|
||||
"after": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/fd/fd4173fd65eff6f6ca43680ba4824545ae6bb57eb8710780a035c9dd120ebc37"
|
||||
},
|
||||
"compositions/frames/09-cta.html": {
|
||||
"before": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/35/3566b01fb9bb64e4d22e86877179c7b7cbee0a98f4bb3c354c97db2b85b13b15",
|
||||
"after": "/root/.cache/hyperframes/history/635d4927-f2e8-44dd-9cbf-1b5d4f285f53/blobs/d9/d9e539932cec2431c43f6125a26bb452abc66a2f7c616b1d1e26da5911e80e07"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"checks": {
|
||||
"latest": {
|
||||
"revision": "6999d82e-2d3b-4026-b89c-d3107735bf7e",
|
||||
"id": "31e798e4-ad68-444f-b4c3-170cece3aeb1"
|
||||
},
|
||||
"revisions": {
|
||||
"ad80a38d-f38a-4cc1-9042-d179e2b0e6f3": [
|
||||
{
|
||||
"id": "bdef997d-ad31-4453-8fb8-c432364aadaf",
|
||||
"scope": "project",
|
||||
"metadata": {
|
||||
"ok": false,
|
||||
"browserSkipped": false,
|
||||
"options": {
|
||||
"samples": 9,
|
||||
"atTransitions": false,
|
||||
"maxIssues": 80,
|
||||
"collapseStatic": true,
|
||||
"tolerance": 2,
|
||||
"timeout": 3000,
|
||||
"contrast": true,
|
||||
"strict": false,
|
||||
"snapshots": false,
|
||||
"browserGpuMode": "auto"
|
||||
}
|
||||
},
|
||||
"createdAt": 1792016113510,
|
||||
"contentHash": "cbaddad6d2047ae01a30682fc6f678b633adb8e61cc6d7b2cd135829f2f6a67d",
|
||||
"revision": "ad80a38d-f38a-4cc1-9042-d179e2b0e6f3",
|
||||
"inputFingerprint": "69a931e0c93bee3efd6531a54ac48f71e88a2fc05106c9891ccb8713064b92ee",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
}
|
||||
],
|
||||
"2748be21-fde2-40ba-a2c0-fddfb7e47431": [
|
||||
{
|
||||
"id": "0e229a06-9c97-4ec5-badd-59e38d09bb91",
|
||||
"scope": "project",
|
||||
"metadata": {
|
||||
"ok": false,
|
||||
"browserSkipped": false,
|
||||
"options": {
|
||||
"samples": 9,
|
||||
"atTransitions": false,
|
||||
"maxIssues": 80,
|
||||
"collapseStatic": true,
|
||||
"tolerance": 2,
|
||||
"timeout": 3000,
|
||||
"contrast": true,
|
||||
"strict": false,
|
||||
"snapshots": false,
|
||||
"browserGpuMode": "auto"
|
||||
}
|
||||
},
|
||||
"createdAt": 1792016142676,
|
||||
"contentHash": "cd9b82c350369ca166d5210b7192e5c1f0394570ec246f30f0a3134ed89d3e9a",
|
||||
"revision": "2748be21-fde2-40ba-a2c0-fddfb7e47431",
|
||||
"inputFingerprint": "86db889a4aed182e0d1dc77ef05552d96c77a15f49c3c15e3fb33051e7f719e6",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
}
|
||||
],
|
||||
"f155d8de-7fb6-4e12-9291-60b3874a47cc": [
|
||||
{
|
||||
"id": "2e9e2e50-ea4c-4ce0-ae6d-feb42f2db77c",
|
||||
"scope": "project",
|
||||
"metadata": {
|
||||
"ok": true,
|
||||
"browserSkipped": false,
|
||||
"options": {
|
||||
"samples": 9,
|
||||
"atTransitions": false,
|
||||
"maxIssues": 80,
|
||||
"collapseStatic": true,
|
||||
"tolerance": 2,
|
||||
"timeout": 3000,
|
||||
"contrast": true,
|
||||
"strict": false,
|
||||
"snapshots": false,
|
||||
"browserGpuMode": "auto"
|
||||
}
|
||||
},
|
||||
"createdAt": 1792016169247,
|
||||
"contentHash": "3c336e043480b32bbb2ecf2a89aa5ad157bf0b6a1243806c47aeb6fba4bb5858",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
}
|
||||
],
|
||||
"6999d82e-2d3b-4026-b89c-d3107735bf7e": [
|
||||
{
|
||||
"id": "31e798e4-ad68-444f-b4c3-170cece3aeb1",
|
||||
"scope": "project",
|
||||
"report": "/home/user/cycle-atlas/videos/lookatu-promo/.hyperframes/artifacts/checks/31e798e4-ad68-444f-b4c3-170cece3aeb1.json",
|
||||
"metadata": {
|
||||
"ok": true,
|
||||
"browserSkipped": false,
|
||||
"options": {
|
||||
"samples": 9,
|
||||
"atTransitions": false,
|
||||
"maxIssues": 80,
|
||||
"collapseStatic": true,
|
||||
"tolerance": 2,
|
||||
"timeout": 3000,
|
||||
"contrast": true,
|
||||
"strict": false,
|
||||
"snapshots": false,
|
||||
"browserGpuMode": "auto"
|
||||
}
|
||||
},
|
||||
"createdAt": 1792016221309,
|
||||
"contentHash": "e4b290d5513ee41c22f25665bfab73ab61f26f0c137a9fddd861279b15f805d4",
|
||||
"revision": "6999d82e-2d3b-4026-b89c-d3107735bf7e",
|
||||
"inputFingerprint": "4f091d26af72cc80221f64652e53f7b6154f8b8d94c2c43bddbdaa7e7bacc2a8",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision"
|
||||
}
|
||||
]
|
||||
},
|
||||
"unversioned": [
|
||||
{
|
||||
"id": "b81768cb-66dc-4b7d-8159-85d988ebc321",
|
||||
"scope": "project",
|
||||
"report": "/home/user/cycle-atlas/videos/lookatu-promo/.hyperframes/artifacts/checks/b81768cb-66dc-4b7d-8159-85d988ebc321.json",
|
||||
"metadata": {
|
||||
"ok": false,
|
||||
"browserSkipped": false,
|
||||
"options": {
|
||||
"samples": 9,
|
||||
"atTransitions": false,
|
||||
"maxIssues": 80,
|
||||
"collapseStatic": true,
|
||||
"tolerance": 2,
|
||||
"timeout": 3000,
|
||||
"contrast": true,
|
||||
"strict": false,
|
||||
"snapshots": false,
|
||||
"browserGpuMode": "auto"
|
||||
}
|
||||
},
|
||||
"createdAt": 1792016095244,
|
||||
"contentHash": "aab572c254c1e2e2a0d41cb3e69f19c969c52ea74d52d8a7b70fa33ca1a3d2e6",
|
||||
"revision": null,
|
||||
"inputFingerprint": "3b3a22e794c378dd99ccd728175edebfae98c1e343c6ca06027a0679d088604a",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "unversioned"
|
||||
}
|
||||
]
|
||||
},
|
||||
"snapshots": {
|
||||
"latest": {
|
||||
"revision": "6999d82e-2d3b-4026-b89c-d3107735bf7e",
|
||||
"id": "a82e082b-e292-496f-a873-daced29d123f-4"
|
||||
},
|
||||
"revisions": {
|
||||
"f155d8de-7fb6-4e12-9291-60b3874a47cc": [
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-0",
|
||||
"time": 1.5,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182293,
|
||||
"contentHash": "b9d7d37046d37a8418b0e35047fa3c528818b9f28f321fd8c163b7d821b7b2f8",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-1",
|
||||
"time": 4.8,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182293,
|
||||
"contentHash": "8bfcfe4356e344034a588fb8eaa48d8c6a17fd1f00921172ac0452a80b1b71e4",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-2",
|
||||
"time": 9,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182293,
|
||||
"contentHash": "d7c0b4142c09d36f84c8a5b82705bd6cf46522dc372d88cef51f43192b37e42d",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-3",
|
||||
"time": 12.3,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182293,
|
||||
"contentHash": "90ca4efc8f9645e29abd5e9c1c6900404f7a53ac80294f7c6069b847fa1bccdd",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-4",
|
||||
"time": 16,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182293,
|
||||
"contentHash": "bc7a6a0347049f51793185e2867b34f9200ff93d40a06f0bffa6965696338d8c",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-5",
|
||||
"time": 20.2,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182293,
|
||||
"contentHash": "c86c03f4c948e4b51a67e7012bf1eb5898e381c173080a13261b212b5c8ce25a",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-6",
|
||||
"time": 24,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182293,
|
||||
"contentHash": "e2b216d57db98ddf973fd0134008417ff00f646888ace8fc5d3e7ce2ddef9bd0",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-7",
|
||||
"time": 27.3,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182293,
|
||||
"contentHash": "48b1ae5f592678b077b5b5ea2c166090dfc9e84c6baaabb2b1bba5f41642a735",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-8",
|
||||
"time": 31,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182293,
|
||||
"contentHash": "6b3edca25c8d8c0e7be74e31690404694ecb679d0d4348a05823c96bf891e492",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-9",
|
||||
"time": 33,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182293,
|
||||
"contentHash": "228695183d4db7398381a0d6d7f502ad5755dfe8601c9c68d7c73b45b44a210c",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-10",
|
||||
"time": 36,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182294,
|
||||
"contentHash": "d8a1ec155678c44ce8e68cde3085859a1ff031b78febf7ea5b6f4d5e45c4d0d6",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-11",
|
||||
"time": 39.5,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182294,
|
||||
"contentHash": "d814f09e5d907213260a03a8b6b0129ed31848abbd29de93417b6deaa5ff8871",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-12",
|
||||
"time": 42,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182294,
|
||||
"contentHash": "acb9108624fc79f1dcc4ecb6ddf74ee6f2c46be2c53604d8a8243b886779f9e7",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-13",
|
||||
"time": 45.3,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182294,
|
||||
"contentHash": "73edeff4a0be0e45c4d82b20caafd7eb154d496c5252af5c351d9349871a2dcd",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-14",
|
||||
"time": 47.5,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182294,
|
||||
"contentHash": "5f425b67e37447223fb533746a74d4994827e00945958068d3c6b6213f7a4938",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-15",
|
||||
"time": 49,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182294,
|
||||
"contentHash": "73b125a618712fb0d3e5daecffb66f3704e0b160f5844e4759971551a98c1c76",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-16",
|
||||
"time": 51,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182294,
|
||||
"contentHash": "83be74004821d6907afaaa93dd798169144c976855840ebaa8082069d1d7ce34",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-17",
|
||||
"time": 54.2,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182294,
|
||||
"contentHash": "a4293fac697e7669476d2d8668abf92a9c4aec2ed6f11672ad53f15074b43cf6",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "f15403c5-4592-4d35-ace8-a22740b42e6f-18",
|
||||
"time": 53.091,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016182294,
|
||||
"contentHash": "882bf50bb17bf4324156c5719de60e94835d1af72402f7af984a845c7684fd3a",
|
||||
"revision": "f155d8de-7fb6-4e12-9291-60b3874a47cc",
|
||||
"inputFingerprint": "9bc516d75c695a9fbcd85911f32ded85e7af79a7c0e6ef3b740f22c5908e924b",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision",
|
||||
"status": "cleaned",
|
||||
"cleanedAfterRender": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3"
|
||||
}
|
||||
],
|
||||
"6999d82e-2d3b-4026-b89c-d3107735bf7e": [
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "a82e082b-e292-496f-a873-daced29d123f-0",
|
||||
"image": "/home/user/cycle-atlas/videos/lookatu-promo/.hyperframes/artifacts/snapshots/f0662448-af98-40ff-b6fd-626156d4a694/frame-00-at-1.5s.png",
|
||||
"time": 1.5,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016226995,
|
||||
"contentHash": "79be7032c63e7a191b47eaceb152a02bf809936a7e76071b68c388a49038f28a",
|
||||
"revision": "6999d82e-2d3b-4026-b89c-d3107735bf7e",
|
||||
"inputFingerprint": "4f091d26af72cc80221f64652e53f7b6154f8b8d94c2c43bddbdaa7e7bacc2a8",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "a82e082b-e292-496f-a873-daced29d123f-1",
|
||||
"image": "/home/user/cycle-atlas/videos/lookatu-promo/.hyperframes/artifacts/snapshots/f0662448-af98-40ff-b6fd-626156d4a694/frame-01-at-9s.png",
|
||||
"time": 9,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016226996,
|
||||
"contentHash": "1a9105cec34e2127ce91c60aab69a567895822f45267710285d03b2b99a1bf84",
|
||||
"revision": "6999d82e-2d3b-4026-b89c-d3107735bf7e",
|
||||
"inputFingerprint": "4f091d26af72cc80221f64652e53f7b6154f8b8d94c2c43bddbdaa7e7bacc2a8",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "a82e082b-e292-496f-a873-daced29d123f-2",
|
||||
"image": "/home/user/cycle-atlas/videos/lookatu-promo/.hyperframes/artifacts/snapshots/f0662448-af98-40ff-b6fd-626156d4a694/frame-02-at-26.5s.png",
|
||||
"time": 26.5,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016226996,
|
||||
"contentHash": "9132f797582916f355f507d87da8843d0fdd23f1b9c5d7f6473eb859b3fd3392",
|
||||
"revision": "6999d82e-2d3b-4026-b89c-d3107735bf7e",
|
||||
"inputFingerprint": "4f091d26af72cc80221f64652e53f7b6154f8b8d94c2c43bddbdaa7e7bacc2a8",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "a82e082b-e292-496f-a873-daced29d123f-3",
|
||||
"image": "/home/user/cycle-atlas/videos/lookatu-promo/.hyperframes/artifacts/snapshots/f0662448-af98-40ff-b6fd-626156d4a694/frame-03-at-53s.png",
|
||||
"time": 53,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016226996,
|
||||
"contentHash": "c8714c376f4e7f375d0c2c11766a2717127224c0927372e4ff67ee41c4d52a72",
|
||||
"revision": "6999d82e-2d3b-4026-b89c-d3107735bf7e",
|
||||
"inputFingerprint": "4f091d26af72cc80221f64652e53f7b6154f8b8d94c2c43bddbdaa7e7bacc2a8",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision"
|
||||
},
|
||||
{
|
||||
"scope": "full",
|
||||
"id": "a82e082b-e292-496f-a873-daced29d123f-4",
|
||||
"image": "/home/user/cycle-atlas/videos/lookatu-promo/.hyperframes/artifacts/snapshots/f0662448-af98-40ff-b6fd-626156d4a694/frame-04-at-53.091s.png",
|
||||
"time": 53.091,
|
||||
"metadata": {
|
||||
"width": 1080,
|
||||
"height": 1920,
|
||||
"zoomScale": 1,
|
||||
"browserGpuMode": "auto",
|
||||
"warnings": [],
|
||||
"partial": false
|
||||
},
|
||||
"createdAt": 1792016226996,
|
||||
"contentHash": "5605b5c311601f318545227a90787eb6f2950613dea019cf8e0daf81353d7946",
|
||||
"revision": "6999d82e-2d3b-4026-b89c-d3107735bf7e",
|
||||
"inputFingerprint": "4f091d26af72cc80221f64652e53f7b6154f8b8d94c2c43bddbdaa7e7bacc2a8",
|
||||
"inputScope": "local-project-files",
|
||||
"attribution": "recorded-revision"
|
||||
}
|
||||
]
|
||||
},
|
||||
"unversioned": []
|
||||
},
|
||||
"renders": {
|
||||
"latest": {
|
||||
"id": "690e4ff7-bd4a-49ec-94b8-f18083c79bc3",
|
||||
"completedAt": 1792016445275,
|
||||
"output": "/home/user/cycle-atlas/videos/lookatu-promo/renders/video.mp4",
|
||||
"status": "completed",
|
||||
"revision": "6999d82e-2d3b-4026-b89c-d3107735bf7e"
|
||||
},
|
||||
"retainedRevisions": [
|
||||
"6999d82e-2d3b-4026-b89c-d3107735bf7e"
|
||||
]
|
||||
},
|
||||
"pendingArtifactCleanup": []
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# .media · 9 assets
|
||||
|
||||
id type dur dims path description
|
||||
voice_010 voice 3.8s — assets/voice/01.wav Where are they right now? And what are they really doing on that phone?
|
||||
voice_011 voice 5.6s — assets/voice/02.wav Endless scrolling. Arguments at dinner. And that quiet worry you never say out loud.
|
||||
voice_012 voice 6.1s — assets/voice/03.wav There has to be a better way. Meet lookatu. The child safety app that gives you peace of mind.
|
||||
voice_013 voice 5.1s — assets/voice/04.wav Set screen time limits that actually stick. When the time is up, the phone knows.
|
||||
voice_014 voice 4.2s — assets/voice/05.wav Choose which apps are okay. Allow the good ones. Block the rest.
|
||||
voice_015 voice 5s — assets/voice/06.wav And when it really matters, see where they are. Location, only when you need it.
|
||||
voice_016 voice 4s — assets/voice/07.wav Because kids deserve some freedom, and parents deserve some calm.
|
||||
voice_017 voice 2.3s — assets/voice/08.wav Works on Android and on iPhone.
|
||||
voice_018 voice 3.1s — assets/voice/09.wav lookatu. Look out for them. Download it today.
|
||||
@@ -0,0 +1,18 @@
|
||||
{"id":"voice_001","type":"voice","path":"assets/voice/01.wav","source":"generated","description":"Where are they right now? And what are they really doing on that phone?","duration":3.3,"provenance":{"provider":"kokoro","prompt":"Where are they right now? And what are they really doing on that phone?"}}
|
||||
{"id":"voice_002","type":"voice","path":"assets/voice/02.wav","source":"generated","description":"Endless scrolling. Arguments at dinner. And that quiet worry you never say out loud.","duration":4.9,"provenance":{"provider":"kokoro","prompt":"Endless scrolling. Arguments at dinner. And that quiet worry you never say out loud."}}
|
||||
{"id":"voice_003","type":"voice","path":"assets/voice/03.wav","source":"generated","description":"There has to be a better way. Meet lookatu. The child safety app that gives you peace of mind.","duration":5.4,"provenance":{"provider":"kokoro","prompt":"There has to be a better way. Meet lookatu. The child safety app that gives you peace of mind."}}
|
||||
{"id":"voice_004","type":"voice","path":"assets/voice/04.wav","source":"generated","description":"Set screen time limits that actually stick. When the time is up, the phone knows.","duration":4.5,"provenance":{"provider":"kokoro","prompt":"Set screen time limits that actually stick. When the time is up, the phone knows."}}
|
||||
{"id":"voice_005","type":"voice","path":"assets/voice/05.wav","source":"generated","description":"Choose which apps are okay. Allow the good ones. Block the rest.","duration":3.7,"provenance":{"provider":"kokoro","prompt":"Choose which apps are okay. Allow the good ones. Block the rest."}}
|
||||
{"id":"voice_006","type":"voice","path":"assets/voice/06.wav","source":"generated","description":"And when it really matters, see where they are. Location, only when you need it.","duration":4.4,"provenance":{"provider":"kokoro","prompt":"And when it really matters, see where they are. Location, only when you need it."}}
|
||||
{"id":"voice_007","type":"voice","path":"assets/voice/07.wav","source":"generated","description":"Because kids deserve some freedom, and parents deserve some calm.","duration":3.6,"provenance":{"provider":"kokoro","prompt":"Because kids deserve some freedom, and parents deserve some calm."}}
|
||||
{"id":"voice_008","type":"voice","path":"assets/voice/08.wav","source":"generated","description":"Works on Android and on iPhone.","duration":2,"provenance":{"provider":"kokoro","prompt":"Works on Android and on iPhone."}}
|
||||
{"id":"voice_009","type":"voice","path":"assets/voice/09.wav","source":"generated","description":"lookatu. Look out for them. Download it today.","duration":2.7,"provenance":{"provider":"kokoro","prompt":"lookatu. Look out for them. Download it today."}}
|
||||
{"id":"voice_010","type":"voice","path":"assets/voice/01.wav","source":"generated","description":"Where are they right now? And what are they really doing on that phone?","duration":3.8,"provenance":{"provider":"kokoro","prompt":"Where are they right now? And what are they really doing on that phone?"}}
|
||||
{"id":"voice_011","type":"voice","path":"assets/voice/02.wav","source":"generated","description":"Endless scrolling. Arguments at dinner. And that quiet worry you never say out loud.","duration":5.6,"provenance":{"provider":"kokoro","prompt":"Endless scrolling. Arguments at dinner. And that quiet worry you never say out loud."}}
|
||||
{"id":"voice_012","type":"voice","path":"assets/voice/03.wav","source":"generated","description":"There has to be a better way. Meet lookatu. The child safety app that gives you peace of mind.","duration":6.1,"provenance":{"provider":"kokoro","prompt":"There has to be a better way. Meet lookatu. The child safety app that gives you peace of mind."}}
|
||||
{"id":"voice_013","type":"voice","path":"assets/voice/04.wav","source":"generated","description":"Set screen time limits that actually stick. When the time is up, the phone knows.","duration":5.1,"provenance":{"provider":"kokoro","prompt":"Set screen time limits that actually stick. When the time is up, the phone knows."}}
|
||||
{"id":"voice_014","type":"voice","path":"assets/voice/05.wav","source":"generated","description":"Choose which apps are okay. Allow the good ones. Block the rest.","duration":4.2,"provenance":{"provider":"kokoro","prompt":"Choose which apps are okay. Allow the good ones. Block the rest."}}
|
||||
{"id":"voice_015","type":"voice","path":"assets/voice/06.wav","source":"generated","description":"And when it really matters, see where they are. Location, only when you need it.","duration":5,"provenance":{"provider":"kokoro","prompt":"And when it really matters, see where they are. Location, only when you need it."}}
|
||||
{"id":"voice_016","type":"voice","path":"assets/voice/07.wav","source":"generated","description":"Because kids deserve some freedom, and parents deserve some calm.","duration":4,"provenance":{"provider":"kokoro","prompt":"Because kids deserve some freedom, and parents deserve some calm."}}
|
||||
{"id":"voice_017","type":"voice","path":"assets/voice/08.wav","source":"generated","description":"Works on Android and on iPhone.","duration":2.3,"provenance":{"provider":"kokoro","prompt":"Works on Android and on iPhone."}}
|
||||
{"id":"voice_018","type":"voice","path":"assets/voice/09.wav","source":"generated","description":"lookatu. Look out for them. Download it today.","duration":3.1,"provenance":{"provider":"kokoro","prompt":"lookatu. Look out for them. Download it today."}}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": 1,
|
||||
"preferences": {
|
||||
"style_preset.product-launch-video": {
|
||||
"value": "daisy-days",
|
||||
"confirmed_in": [
|
||||
"lookatu-promo"
|
||||
],
|
||||
"updated_at": "2026-10-14T22:05:31.928Z"
|
||||
}
|
||||
},
|
||||
"sightings": {}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
# HyperFrames Composition Project
|
||||
|
||||
## Skills — USE THESE FIRST
|
||||
|
||||
**Always invoke the relevant skill before writing or modifying compositions.** Skills encode framework-specific patterns (e.g., `window.__timelines` registration, `data-*` attribute semantics, shader-compatible CSS rules) that are NOT in generic web docs. Skipping them produces broken compositions.
|
||||
|
||||
**Doing anything with HyperFrames?** Start at `/hyperframes` — it tells you what HyperFrames can do and which skill or workflow handles your intent (make a video, TTS / BGM, prep footage, author / animate, render, install blocks), confirms your brief up front (the intent layer), and routes every "make me a…" request (a video, a deck, a composition port) to the right workflow. Read it first, especially when there's no project context to orient you. The workflows it routes to:
|
||||
|
||||
- `/product-launch-video` — any **website** URL or brief / script → a product launch / SaaS / promo video, or a site tour / showcase featuring the site's own captured visuals.
|
||||
- `/faceless-explainer` — arbitrary text (topic / article / notes), **no URL, no website capture** → 60-90s faceless explainer.
|
||||
- `/embedded-captions` — an existing talking-head video (MP4) → the same footage with captions / subtitles added (rail + embed, or pure-cinematic embed); the footage itself is untouched.
|
||||
- `/talking-head-recut` — an existing talking-head / interview / podcast video (MP4) → the same footage **packaged with designed graphic overlays** (kinetic titles, lower-thirds, data callouts, pull-quotes, side panels, pip) synced to the transcript; the clip plays unchanged underneath. (Plain captions/subtitles → `/embedded-captions`.)
|
||||
- `/pr-to-video` — a GitHub PR (URL / `owner/repo#N` / "this PR") → 30-90s code-change explainer (changelog / feature reveal / fix / refactor).
|
||||
- `/motion-graphics` — a short (typically under 10s) design-led **motion graphic**, motion-is-the-message, no narration: kinetic type, a stat / number count-up, a chart, a logo sting, a lower-third / overlay, or an animated tweet / headline / captured-page highlight; rendered to MP4 or a transparent overlay. Longer / narrated / custom → `/general-video`.
|
||||
- `/music-to-video` — a **music track** (audio file, video to pull audio from, or one generated from a mood brief) → beat-synced video (lyric / slideshow / kinetic promo). Music drives pacing; user-supplied images / videos are cut onto the same beat grid.
|
||||
- `/slideshow` — a **presentation / pitch deck / interactive deck** — discrete slides, fragment reveals, branching, hotspot navigation, presenter mode. Output is a navigable deck, not a rendered video.
|
||||
- `/general-video` — fallback for any other video (title card, longer brand / sizzle reel, multi-scene montage, static loop, custom composition) and the home of **companion mode** — co-create with the full HyperFrames toolbox; the original hyperframes authoring flow, any length.
|
||||
|
||||
**Porting an existing composition?** `/remotion-to-hyperframes` translates a Remotion (React) composition into HyperFrames HTML — a source migration, separate from the creation workflows above.
|
||||
|
||||
The domain skills (`/hyperframes-core`, `/hyperframes-animation`, `/hyperframes-keyframes`, `/hyperframes-creative`, `/hyperframes-cli`, `/media-use`, `/hyperframes-audio`, `/hyperframes-registry`, `/figma`) and the full capability map live inside `/hyperframes` — it is the single source of truth for which skill handles which intent.
|
||||
|
||||
**Changing how real footage or images look or reveal?** Load `/media-use` and read its `references/media-treatments.md` before editing, even when the request only says dark, flat, boring, retro, private, or “make the reveal cooler.” It governs how footage is treated, never whether media may be used. Use canonical media treatments and seek-safe motion; do not improvise equivalent CSS/SVG filters or overlays.
|
||||
|
||||
> **Tailwind v4 projects** (`hyperframes init --tailwind`): see `/hyperframes-core` → `references/tailwind.md`.
|
||||
|
||||
> **Using a HyperFrames plugin?** Load skills from that installed bundle and follow
|
||||
> its `hyperframes/references/plugin-installation.md` execution rules. Update via
|
||||
> the plugin manager, not the standalone commands below.
|
||||
>
|
||||
> **Standalone skill missing or stale?** Run `npx hyperframes skills update <name>` to install/refresh
|
||||
> the specific skill you need (the `/hyperframes` router does this automatically before
|
||||
> entering a workflow), or bare `npx hyperframes skills update` to refresh the core set plus
|
||||
> everything already installed — neither pulls the full set. Restart the agent session so
|
||||
> newly installed skills load.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
npm run dev # human-operated foreground preview (blocks until stopped)
|
||||
npx hyperframes preview --background # agent-safe persistent Studio preview
|
||||
npx hyperframes preview --status # verify the persistent preview is listening
|
||||
npx hyperframes preview --stop # stop it when review is finished
|
||||
npm run check # lint + runtime + layout + motion + contrast (one command)
|
||||
npm run render # render to MP4
|
||||
npm run publish # publish and get a shareable link
|
||||
npx hyperframes lint --verbose # include info-level findings
|
||||
npx hyperframes lint --json # machine-readable output for CI
|
||||
npx hyperframes docs <topic> # reference docs in terminal
|
||||
```
|
||||
|
||||
> **Agents must use `npx hyperframes preview --background` for Studio handoff.** Do not rely
|
||||
> on a shell/tool `run_in_background` wrapper around `npm run dev`: that foreground process
|
||||
> remains owned by the invoking session and can disappear while the browser stays open,
|
||||
> leaving refreshes at `ERR_CONNECTION_TIMED_OUT`. Verify with `preview --status`, keep it
|
||||
> alive through review, and stop it explicitly with `preview --stop` afterward.
|
||||
|
||||
> **Back from the desktop app.** Once this project was opened in the HyperFrames desktop app, run `npx hyperframes catch-up` before your next change here: it lists what the person asked Framey in the app and which files changed since.
|
||||
|
||||
> **Pinned CLI version.** These scripts pin an exact `hyperframes@X.Y.Z` so this project re-renders identically over time. Weeks later that pin lags fixes shipped since. To move up: `npx hyperframes@latest upgrade --project . --check` (shows the delta), then `npx hyperframes@latest upgrade --project .` to rewrite the pins. Always unpinned — the pinned script re-runs the old version against itself.
|
||||
|
||||
## Documentation
|
||||
|
||||
**For quick reference**, use the local CLI docs command (no network required):
|
||||
|
||||
```bash
|
||||
npx hyperframes docs <topic>
|
||||
```
|
||||
|
||||
Topics: `data-attributes`, `gsap`, `compositions`, `rendering`, `examples`, `troubleshooting`
|
||||
|
||||
**For full documentation**, discover pages via the machine-readable index — do NOT guess URLs:
|
||||
|
||||
```
|
||||
https://hyperframes.heygen.com/llms.txt
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
|
||||
- `index.html` — main composition (root timeline)
|
||||
- `compositions/` — sub-compositions referenced via `data-composition-src`
|
||||
- `meta.json` — project metadata (id, name)
|
||||
- `transcript.json` — whisper word-level transcript (if generated)
|
||||
|
||||
## Linting — ALWAYS RUN AFTER CHANGES
|
||||
|
||||
After creating or editing any `.html` composition, **always** run the full check before considering the task complete:
|
||||
|
||||
```bash
|
||||
npm run check
|
||||
```
|
||||
|
||||
Fix all errors before presenting the result. Warnings should be reviewed before rendering.
|
||||
|
||||
## Key Rules
|
||||
|
||||
1. Every timed element needs `data-start` and a duration. `data-start` is what marks it as timed; `data-track-index` is an optional Studio display lane the render never reads
|
||||
2. Give timed visual elements `class="clip"`. The framework keys visibility off `data-start`, not the class, but the shared `.clip` CSS is what gives a scene its full-frame box, and `lint` warns without it
|
||||
3. Register one paused root timeline per composition on `window.__timelines`:
|
||||
```js
|
||||
window.__timelines = window.__timelines || {};
|
||||
window.__timelines["composition-id"] = gsap.timeline({ paused: true });
|
||||
```
|
||||
Scene timelines manually added to this root must not be paused. A paused
|
||||
child does not advance when the root is seeked. The runtime activates
|
||||
registered composition siblings, not arbitrary nested scene timelines.
|
||||
4. A video with sound keeps it on the `<video>` (`data-has-audio="true"`, no `muted`). Use a separate `<audio>` for music, voiceover, replacement audio, J/L cuts, or audio detached in Studio. Silent footage and b-roll: `muted`.
|
||||
5. Sub-compositions use `data-composition-src="compositions/file.html"` to reference other HTML files
|
||||
6. Only deterministic logic — no `Date.now()`, no `Math.random()`, no network fetches
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
workflow: product-launch-video
|
||||
flow: automation
|
||||
storyboard: no
|
||||
message: "Keep your kids safe on their phones, with peace of mind for parents"
|
||||
destination: tiktok-reels-shorts
|
||||
aspect: 1080x1920
|
||||
language: en
|
||||
audience: parents of children with smartphones
|
||||
length: 60s
|
||||
angle: parent peace of mind
|
||||
---
|
||||
|
||||
## Intent
|
||||
|
||||
Promo for "lookatu", an Android and iOS child-safety app. Parents control how
|
||||
much their kids use the phone (time limits, app control) and can track location
|
||||
only when needed. Story shape: start with a worried parent, then lookatu brings
|
||||
calm and safety. Warm, reassuring, trustworthy. Not scary, not spying.
|
||||
|
||||
## Assets
|
||||
|
||||
- None supplied. No website, logo, or screenshots yet. Use invented phone UI
|
||||
mock-ups and a typographic "lookatu" wordmark. Real screens come in Phase 2.
|
||||
|
||||
## Customizations
|
||||
|
||||
- No-capture mode (nothing to scrape). A shipped preset supplies the design.
|
||||
|
||||
## Notes
|
||||
|
||||
- User is not a coder: explain steps in plain language.
|
||||
- Only claim features the user described: usage control, location tracking
|
||||
when needed, Android and iOS. No invented stats, awards, or user counts.
|
||||
- Frame tracking as parent-led and transparent (no secret spying language).
|
||||
- Phase 2: swap in real logo and screenshots, add real voice. Phase 3: other sizes.
|
||||
@@ -0,0 +1,109 @@
|
||||
# HyperFrames Composition Project
|
||||
|
||||
## Skills — USE THESE FIRST
|
||||
|
||||
**Always invoke the relevant skill before writing or modifying compositions.** Skills encode framework-specific patterns (e.g., `window.__timelines` registration, `data-*` attribute semantics, shader-compatible CSS rules) that are NOT in generic web docs. Skipping them produces broken compositions.
|
||||
|
||||
**Doing anything with HyperFrames?** Start at `/hyperframes` — it tells you what HyperFrames can do and which skill or workflow handles your intent (make a video, TTS / BGM, prep footage, author / animate, render, install blocks), confirms your brief up front (the intent layer), and routes every "make me a…" request (a video, a deck, a composition port) to the right workflow. Read it first, especially when there's no project context to orient you. The workflows it routes to:
|
||||
|
||||
- `/product-launch-video` — any **website** URL or brief / script → a product launch / SaaS / promo video, or a site tour / showcase featuring the site's own captured visuals.
|
||||
- `/faceless-explainer` — arbitrary text (topic / article / notes), **no URL, no website capture** → 60-90s faceless explainer.
|
||||
- `/embedded-captions` — an existing talking-head video (MP4) → the same footage with captions / subtitles added (rail + embed, or pure-cinematic embed); the footage itself is untouched.
|
||||
- `/talking-head-recut` — an existing talking-head / interview / podcast video (MP4) → the same footage **packaged with designed graphic overlays** (kinetic titles, lower-thirds, data callouts, pull-quotes, side panels, pip) synced to the transcript; the clip plays unchanged underneath. (Plain captions/subtitles → `/embedded-captions`.)
|
||||
- `/pr-to-video` — a GitHub PR (URL / `owner/repo#N` / "this PR") → 30-90s code-change explainer (changelog / feature reveal / fix / refactor).
|
||||
- `/motion-graphics` — a short (typically under 10s) design-led **motion graphic**, motion-is-the-message, no narration: kinetic type, a stat / number count-up, a chart, a logo sting, a lower-third / overlay, or an animated tweet / headline / captured-page highlight; rendered to MP4 or a transparent overlay. Longer / narrated / custom → `/general-video`.
|
||||
- `/music-to-video` — a **music track** (audio file, video to pull audio from, or one generated from a mood brief) → beat-synced video (lyric / slideshow / kinetic promo). Music drives pacing; user-supplied images / videos are cut onto the same beat grid.
|
||||
- `/slideshow` — a **presentation / pitch deck / interactive deck** — discrete slides, fragment reveals, branching, hotspot navigation, presenter mode. Output is a navigable deck, not a rendered video.
|
||||
- `/general-video` — fallback for any other video (title card, longer brand / sizzle reel, multi-scene montage, static loop, custom composition) and the home of **companion mode** — co-create with the full HyperFrames toolbox; the original hyperframes authoring flow, any length.
|
||||
|
||||
**Porting an existing composition?** `/remotion-to-hyperframes` translates a Remotion (React) composition into HyperFrames HTML — a source migration, separate from the creation workflows above.
|
||||
|
||||
The domain skills (`/hyperframes-core`, `/hyperframes-animation`, `/hyperframes-keyframes`, `/hyperframes-creative`, `/hyperframes-cli`, `/media-use`, `/hyperframes-audio`, `/hyperframes-registry`, `/figma`) and the full capability map live inside `/hyperframes` — it is the single source of truth for which skill handles which intent.
|
||||
|
||||
**Changing how real footage or images look or reveal?** Load `/media-use` and read its `references/media-treatments.md` before editing, even when the request only says dark, flat, boring, retro, private, or “make the reveal cooler.” It governs how footage is treated, never whether media may be used. Use canonical media treatments and seek-safe motion; do not improvise equivalent CSS/SVG filters or overlays.
|
||||
|
||||
> **Tailwind v4 projects** (`hyperframes init --tailwind`): see `/hyperframes-core` → `references/tailwind.md`.
|
||||
|
||||
> **Using a HyperFrames plugin?** Load skills from that installed bundle and follow
|
||||
> its `hyperframes/references/plugin-installation.md` execution rules. Update via
|
||||
> the plugin manager, not the standalone commands below.
|
||||
>
|
||||
> **Standalone skill missing or stale?** Run `npx hyperframes skills update <name>` to install/refresh
|
||||
> the specific skill you need (the `/hyperframes` router does this automatically before
|
||||
> entering a workflow), or bare `npx hyperframes skills update` to refresh the core set plus
|
||||
> everything already installed — neither pulls the full set. Restart the agent session so
|
||||
> newly installed skills load.
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
npm run dev # human-operated foreground preview (blocks until stopped)
|
||||
npx hyperframes preview --background # agent-safe persistent Studio preview
|
||||
npx hyperframes preview --status # verify the persistent preview is listening
|
||||
npx hyperframes preview --stop # stop it when review is finished
|
||||
npm run check # lint + runtime + layout + motion + contrast (one command)
|
||||
npm run render # render to MP4
|
||||
npm run publish # publish and get a shareable link
|
||||
npx hyperframes lint --verbose # include info-level findings
|
||||
npx hyperframes lint --json # machine-readable output for CI
|
||||
npx hyperframes docs <topic> # reference docs in terminal
|
||||
```
|
||||
|
||||
> **Agents must use `npx hyperframes preview --background` for Studio handoff.** Do not rely
|
||||
> on a shell/tool `run_in_background` wrapper around `npm run dev`: that foreground process
|
||||
> remains owned by the invoking session and can disappear while the browser stays open,
|
||||
> leaving refreshes at `ERR_CONNECTION_TIMED_OUT`. Verify with `preview --status`, keep it
|
||||
> alive through review, and stop it explicitly with `preview --stop` afterward.
|
||||
|
||||
> **Back from the desktop app.** Once this project was opened in the HyperFrames desktop app, run `npx hyperframes catch-up` before your next change here: it lists what the person asked Framey in the app and which files changed since.
|
||||
|
||||
> **Pinned CLI version.** These scripts pin an exact `hyperframes@X.Y.Z` so this project re-renders identically over time. Weeks later that pin lags fixes shipped since. To move up: `npx hyperframes@latest upgrade --project . --check` (shows the delta), then `npx hyperframes@latest upgrade --project .` to rewrite the pins. Always unpinned — the pinned script re-runs the old version against itself.
|
||||
|
||||
## Documentation
|
||||
|
||||
**For quick reference**, use the local CLI docs command (no network required):
|
||||
|
||||
```bash
|
||||
npx hyperframes docs <topic>
|
||||
```
|
||||
|
||||
Topics: `data-attributes`, `gsap`, `compositions`, `rendering`, `examples`, `troubleshooting`
|
||||
|
||||
**For full documentation**, discover pages via the machine-readable index — do NOT guess URLs:
|
||||
|
||||
```
|
||||
https://hyperframes.heygen.com/llms.txt
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
|
||||
- `index.html` — main composition (root timeline)
|
||||
- `compositions/` — sub-compositions referenced via `data-composition-src`
|
||||
- `meta.json` — project metadata (id, name)
|
||||
- `transcript.json` — whisper word-level transcript (if generated)
|
||||
|
||||
## Linting — ALWAYS RUN AFTER CHANGES
|
||||
|
||||
After creating or editing any `.html` composition, **always** run the full check before considering the task complete:
|
||||
|
||||
```bash
|
||||
npm run check
|
||||
```
|
||||
|
||||
Fix all errors before presenting the result. Warnings should be reviewed before rendering.
|
||||
|
||||
## Key Rules
|
||||
|
||||
1. Every timed element needs `data-start` and a duration. `data-start` is what marks it as timed; `data-track-index` is an optional Studio display lane the render never reads
|
||||
2. Give timed visual elements `class="clip"`. The framework keys visibility off `data-start`, not the class, but the shared `.clip` CSS is what gives a scene its full-frame box, and `lint` warns without it
|
||||
3. Register one paused root timeline per composition on `window.__timelines`:
|
||||
```js
|
||||
window.__timelines = window.__timelines || {};
|
||||
window.__timelines["composition-id"] = gsap.timeline({ paused: true });
|
||||
```
|
||||
Scene timelines manually added to this root must not be paused. A paused
|
||||
child does not advance when the root is seeked. The runtime activates
|
||||
registered composition siblings, not arbitrary nested scene timelines.
|
||||
4. A video with sound keeps it on the `<video>` (`data-has-audio="true"`, no `muted`). Use a separate `<audio>` for music, voiceover, replacement audio, J/L cuts, or audio detached in Studio. Silent footage and b-roll: `muted`.
|
||||
5. Sub-compositions use `data-composition-src="compositions/file.html"` to reference other HTML files
|
||||
6. Only deterministic logic — no `Date.now()`, no `Math.random()`, no network fetches
|
||||
@@ -0,0 +1,70 @@
|
||||
# SCRIPT — lookatu-promo
|
||||
|
||||
**Voice:** af_heart (Kokoro, offline)
|
||||
**Voice settings:** default
|
||||
**Voice direction:** Warm, calm, reassuring. Like a friend who is also a parent.
|
||||
|
||||
---
|
||||
|
||||
## Line 1 — Where are they (Frame 1)
|
||||
|
||||
**Time:** 0.0 – 6.0s
|
||||
**Delivery:** Gentle worry, then curious.
|
||||
|
||||
Where are they right now? And what are they really doing on that phone?
|
||||
|
||||
## Line 2 — The quiet worry (Frame 2)
|
||||
|
||||
**Time:** 6.0 – 13.0s
|
||||
**Delivery:** Slow, a little tired, honest.
|
||||
|
||||
Endless scrolling. Arguments at dinner. And that quiet worry you never say out loud.
|
||||
|
||||
## Line 3 — Meet lookatu (Frame 3)
|
||||
|
||||
**Time:** 13.0 – 22.0s
|
||||
**Delivery:** A breath, then relief and warmth on the name.
|
||||
|
||||
There has to be a better way. Meet lookatu. The child safety app that gives you peace of mind.
|
||||
|
||||
## Line 4 — Screen time limits (Frame 4)
|
||||
|
||||
**Time:** 22.0 – 30.0s
|
||||
**Delivery:** Confident and clear.
|
||||
|
||||
Set screen time limits that actually stick. When the time is up, the phone knows.
|
||||
|
||||
## Line 5 — App control (Frame 5)
|
||||
|
||||
**Time:** 30.0 – 37.0s
|
||||
**Delivery:** Crisp, three short beats.
|
||||
|
||||
Choose which apps are okay. Allow the good ones. Block the rest.
|
||||
|
||||
## Line 6 — Location when needed (Frame 6)
|
||||
|
||||
**Time:** 37.0 – 45.0s
|
||||
**Delivery:** Soft and reassuring.
|
||||
|
||||
And when it really matters, see where they are. Location, only when you need it.
|
||||
|
||||
## Line 7 — Freedom and calm (Frame 7)
|
||||
|
||||
**Time:** 45.0 – 51.0s
|
||||
**Delivery:** Warm, almost a smile.
|
||||
|
||||
Because kids deserve some freedom, and parents deserve some calm.
|
||||
|
||||
## Line 8 — Android and iPhone (Frame 8)
|
||||
|
||||
**Time:** 51.0 – 55.0s
|
||||
**Delivery:** Simple and friendly.
|
||||
|
||||
Works on Android and on iPhone.
|
||||
|
||||
## Line 9 — Look out for them (Frame 9)
|
||||
|
||||
**Time:** 55.0 – 61.0s
|
||||
**Delivery:** Warm sign-off, land on the name.
|
||||
|
||||
lookatu. Look out for them. Download it today.
|
||||
@@ -0,0 +1,169 @@
|
||||
---
|
||||
format: 1080x1920
|
||||
duration: 60s
|
||||
message: "Keep your kids safe on their phones, with peace of mind for parents"
|
||||
arc: Hook → Pain → Product → Time limits → App control → Location → Balance → Platforms → CTA
|
||||
audience: parents of children with smartphones
|
||||
mode: autonomous
|
||||
music: none
|
||||
---
|
||||
|
||||
## Video direction
|
||||
|
||||
Daisy Days picture-book look: cream and pastel grounds, 3px charcoal outlines, hard offset shadows,
|
||||
hand-drawn ornaments (daisy, star, sun, cloud) filling the corners. Warm, reassuring, never scary.
|
||||
Motion is soft and bouncy (back.out, power3.out), each piece lands when the voice names it. Phone
|
||||
mock-ups are invented generic screens with no real brand logos. Captions sit in the bottom band.
|
||||
|
||||
## Frame 1 — Where are they
|
||||
|
||||
- scene: Two big question bubbles pop in over a sky-blue ground, a small phone silhouette wobbles
|
||||
- voiceover: "Where are they right now? And what are they really doing on that phone?"
|
||||
- duration: 5.64s
|
||||
- transition_in: crossfade
|
||||
- status: animated
|
||||
- src: compositions/frames/01-hook.html
|
||||
- type: hook
|
||||
- persuasion: Pain validation
|
||||
- beat: worry
|
||||
- blueprint: compose
|
||||
- asset_candidates:
|
||||
|
||||
narrativeRole: Opens on the parent's silent question in outcome language.
|
||||
keyMessage: Parents worry about where their kids are and what the phone is doing.
|
||||
|
||||
## Frame 2 — The quiet worry
|
||||
|
||||
- scene: Three sticker words stack in one by one: SCROLLING, ARGUING, WORRYING
|
||||
- voiceover: "Endless scrolling. Arguments at dinner. And that quiet worry you never say out loud."
|
||||
- duration: 7.111s
|
||||
- transition_in: crossfade
|
||||
- status: animated
|
||||
- src: compositions/frames/02-worry.html
|
||||
- type: pain_point
|
||||
- persuasion: Pain agitation
|
||||
- beat: tension
|
||||
- blueprint: compose
|
||||
- asset_candidates:
|
||||
|
||||
narrativeRole: Names the everyday pain so the product feels like relief.
|
||||
keyMessage: The phone brings daily friction and worry.
|
||||
|
||||
## Frame 3 — Meet lookatu
|
||||
|
||||
- scene: The lookatu wordmark builds on a turquoise ground with a shield badge and a calm sun
|
||||
- voiceover: "There has to be a better way. Meet lookatu. The child safety app that gives you peace of mind."
|
||||
- duration: 8.144s
|
||||
- transition_in: zoom-through
|
||||
- status: animated
|
||||
- src: compositions/frames/03-meet.html
|
||||
- type: product_intro
|
||||
- persuasion: Future pacing
|
||||
- beat: relief
|
||||
- blueprint: compose
|
||||
- asset_candidates:
|
||||
|
||||
narrativeRole: Lands the promise (the message) by beat 3 and names the product.
|
||||
keyMessage: lookatu gives parents peace of mind.
|
||||
|
||||
## Frame 4 — Screen time limits
|
||||
|
||||
- scene: A phone mock-up with a timer ring that counts down and locks with a gentle lock icon
|
||||
- voiceover: "Set screen time limits that actually stick. When the time is up, the phone knows."
|
||||
- duration: 6.599s
|
||||
- transition_in: push-slide LEFT
|
||||
- status: animated
|
||||
- src: compositions/frames/04-limits.html
|
||||
- type: feature_showcase
|
||||
- persuasion: Feature-to-benefit translation
|
||||
- beat: control
|
||||
- blueprint: compose
|
||||
- asset_candidates:
|
||||
|
||||
narrativeRole: Feature 1 shown working, with the benefit of limits that hold.
|
||||
keyMessage: Parents set the phone usage limits.
|
||||
|
||||
## Frame 5 — App control
|
||||
|
||||
- scene: A phone mock-up with a list of generic app tiles and toggles; good apps switch on, others switch off
|
||||
- voiceover: "Choose which apps are okay. Allow the good ones. Block the rest."
|
||||
- duration: 5.703s
|
||||
- transition_in: push-slide LEFT
|
||||
- status: animated
|
||||
- src: compositions/frames/05-apps.html
|
||||
- type: feature_showcase
|
||||
- persuasion: Show-don't-tell proof
|
||||
- beat: control
|
||||
- blueprint: compose
|
||||
- asset_candidates:
|
||||
|
||||
narrativeRole: Feature 2, parents decide which apps are allowed.
|
||||
keyMessage: Parents allow or block apps.
|
||||
|
||||
## Frame 6 — Location when needed
|
||||
|
||||
- scene: A soft map card with a pin that drops and pulses once, sitting inside a phone mock-up
|
||||
- voiceover: "And when it really matters, see where they are. Location, only when you need it."
|
||||
- duration: 6.513s
|
||||
- transition_in: push-slide LEFT
|
||||
- status: animated
|
||||
- src: compositions/frames/06-location.html
|
||||
- type: feature_showcase
|
||||
- persuasion: Risk reversal
|
||||
- beat: reassurance
|
||||
- blueprint: compose
|
||||
- asset_candidates:
|
||||
|
||||
narrativeRole: Feature 3, location tracking available when needed.
|
||||
keyMessage: Parents can check location when needed.
|
||||
|
||||
## Frame 7 — Freedom and calm
|
||||
|
||||
- scene: Two big words on a pink ground, FREEDOM and CALM, each in a sticker card joined by a heart
|
||||
- voiceover: "Because kids deserve some freedom, and parents deserve some calm."
|
||||
- duration: 5.468s
|
||||
- transition_in: crossfade
|
||||
- status: animated
|
||||
- src: compositions/frames/07-balance.html
|
||||
- type: benefit_highlight
|
||||
- persuasion: Rule of two
|
||||
- beat: peace of mind
|
||||
- blueprint: compose
|
||||
- asset_candidates:
|
||||
|
||||
narrativeRole: The emotional payoff that ties the features together.
|
||||
keyMessage: Safety without a fight.
|
||||
|
||||
## Frame 8 — Android and iPhone
|
||||
|
||||
- scene: Two pill badges, ANDROID and iOS, pop in side by side on a butter ground
|
||||
- voiceover: "Works on Android and on iPhone."
|
||||
- duration: 3.783s
|
||||
- transition_in: crossfade
|
||||
- status: animated
|
||||
- src: compositions/frames/08-platforms.html
|
||||
- type: benefit_highlight
|
||||
- persuasion: Friction reduction
|
||||
- beat: ease
|
||||
- blueprint: compose
|
||||
- asset_candidates:
|
||||
|
||||
narrativeRole: Removes the "will it work on my phone" question.
|
||||
keyMessage: Available for both Android and iOS.
|
||||
|
||||
## Frame 9 — Look out for them
|
||||
|
||||
- scene: Lavender ground, lookatu wordmark with the tagline, ornament wreath, gentle settle
|
||||
- voiceover: "lookatu. Look out for them. Download it today."
|
||||
- duration: 5.772s
|
||||
- transition_in: zoom-through
|
||||
- status: animated
|
||||
- src: compositions/frames/09-cta.html
|
||||
- type: cta
|
||||
- persuasion: Clear call to action
|
||||
- beat: confidence
|
||||
- blueprint: compose
|
||||
- asset_candidates:
|
||||
|
||||
narrativeRole: Closing lockup and call to action.
|
||||
keyMessage: Download lookatu.
|
||||
Binary file not shown.
Binary file not shown.
+11
@@ -0,0 +1,11 @@
|
||||
/*!
|
||||
* GSAP 3.14.2
|
||||
* https://gsap.com
|
||||
*
|
||||
* @license Copyright 2025, GreenSock. All rights reserved.
|
||||
* Subject to the terms at https://gsap.com/standard-license.
|
||||
* @author: Jack Doyle, jack@greensock.com
|
||||
*/
|
||||
|
||||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).window=t.window||{})}(this,function(e){"use strict";function _inheritsLoose(t,e){t.prototype=Object.create(e.prototype),(t.prototype.constructor=t).__proto__=e}function _assertThisInitialized(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function r(t){return"string"==typeof t}function s(t){return"function"==typeof t}function t(t){return"number"==typeof t}function u(t){return void 0===t}function v(t){return"object"==typeof t}function w(t){return!1!==t}function x(){return"undefined"!=typeof window}function y(t){return s(t)||r(t)}function R(t){return(i=bt(t,ht))&&Fe}function S(t,e){return console.warn("Invalid property",t,"set to",e,"Missing plugin? gsap.registerPlugin()")}function T(t,e){return!e&&console.warn(t)}function U(t,e){return t&&(ht[t]=e)&&i&&(i[t]=e)||ht}function V(){return 0}function ga(t){var e,r,i=t[0];if(v(i)||s(i)||(t=[t]),!(e=(i._gsap||{}).harness)){for(r=yt.length;r--&&!yt[r].targetTest(i););e=yt[r]}for(r=t.length;r--;)t[r]&&(t[r]._gsap||(t[r]._gsap=new Xt(t[r],e)))||t.splice(r,1);return t}function ha(t){return t._gsap||ga(Pt(t))[0]._gsap}function ia(t,e,r){return(r=t[e])&&s(r)?t[e]():u(r)&&t.getAttribute&&t.getAttribute(e)||r}function ja(t,e){return(t=t.split(",")).forEach(e)||t}function ka(t){return Math.round(1e5*t)/1e5||0}function la(t){return Math.round(1e7*t)/1e7||0}function ma(t,e){var r=e.charAt(0),i=parseFloat(e.substr(2));return t=parseFloat(t),"+"===r?t+i:"-"===r?t-i:"*"===r?t*i:t/i}function na(t,e){for(var r=e.length,i=0;t.indexOf(e[i])<0&&++i<r;);return i<r}function oa(){var t,e,r=pt.length,i=pt.slice(0);for(_t={},t=pt.length=0;t<r;t++)(e=i[t])&&e._lazy&&(e.render(e._lazy[0],e._lazy[1],!0)._lazy=0)}function pa(t){return!!(t._initted||t._startAt||t.add)}function qa(t,e,r,i){pt.length&&!I&&oa(),t.render(e,r,i||!!(I&&e<0&&pa(t))),pt.length&&!I&&oa()}function ra(t){var e=parseFloat(t);return(e||0===e)&&(t+"").match(ot).length<2?e:r(t)?t.trim():t}function sa(t){return t}function ta(t,e){for(var r in e)r in t||(t[r]=e[r]);return t}function wa(t,e){for(var r in e)"__proto__"!==r&&"constructor"!==r&&"prototype"!==r&&(t[r]=v(e[r])?wa(t[r]||(t[r]={}),e[r]):e[r]);return t}function xa(t,e){var r,i={};for(r in t)r in e||(i[r]=t[r]);return i}function ya(t){var e=t.parent||L,r=t.keyframes?function _setKeyframeDefaults(i){return function(t,e){for(var r in e)r in t||"duration"===r&&i||"ease"===r||(t[r]=e[r])}}($(t.keyframes)):ta;if(w(t.inherit))for(;e;)r(t,e.vars.defaults),e=e.parent||e._dp;return t}function Aa(t,e,r,i,n){void 0===r&&(r="_first"),void 0===i&&(i="_last");var a,s=t[i];if(n)for(a=e[n];s&&s[n]>a;)s=s._prev;return s?(e._next=s._next,s._next=e):(e._next=t[r],t[r]=e),e._next?e._next._prev=e:t[i]=e,e._prev=s,e.parent=e._dp=t,e}function Ba(t,e,r,i){void 0===r&&(r="_first"),void 0===i&&(i="_last");var n=e._prev,a=e._next;n?n._next=a:t[r]===e&&(t[r]=a),a?a._prev=n:t[i]===e&&(t[i]=n),e._next=e._prev=e.parent=null}function Ca(t,e){t.parent&&(!e||t.parent.autoRemoveChildren)&&t.parent.remove&&t.parent.remove(t),t._act=0}function Da(t,e){if(t&&(!e||e._end>t._dur||e._start<0))for(var r=t;r;)r._dirty=1,r=r.parent;return t}function Fa(t,e,r,i){return t._startAt&&(I?t._startAt.revert(ft):t.vars.immediateRender&&!t.vars.autoRevert||t._startAt.render(e,!0,i))}function Ha(t){return t._repeat?wt(t._tTime,t=t.duration()+t._rDelay)*t:0}function Ja(t,e){return(t-e._start)*e._ts+(0<=e._ts?0:e._dirty?e.totalDuration():e._tDur)}function Ka(t){return t._end=la(t._start+(t._tDur/Math.abs(t._ts||t._rts||q)||0))}function La(t,e){var r=t._dp;return r&&r.smoothChildTiming&&t._ts&&(t._start=la(r._time-(0<t._ts?e/t._ts:((t._dirty?t.totalDuration():t._tDur)-e)/-t._ts)),Ka(t),r._dirty||Da(r,t)),t}function Ma(t,e){var r;if((e._time||!e._dur&&e._initted||e._start<t._time&&(e._dur||!e.add))&&(r=Ja(t.rawTime(),e),(!e._dur||Mt(0,e.totalDuration(),r)-e._tTime>q)&&e.render(r,!0)),Da(t,e)._dp&&t._initted&&t._time>=t._dur&&t._ts){if(t._dur<t.duration())for(r=t;r._dp;)0<=r.rawTime()&&r.totalTime(r._tTime),r=r._dp;t._zTime=-q}}function Na(e,r,i,n){return r.parent&&Ca(r),r._start=la((t(i)?i:i||e!==L?Ot(e,i,r):e._time)+r._delay),r._end=la(r._start+(r.totalDuration()/Math.abs(r.timeScale())||0)),Aa(e,r,"_first","_last",e._sort?"_start":0),xt(r)||(e._recent=r),n||Ma(e,r),e._ts<0&&La(e,e._tTime),e}function Oa(t,e){return(ht.ScrollTrigger||S("scrollTrigger",e))&&ht.ScrollTrigger.create(e,t)}function Pa(t,e,r,i,n){return Qt(t,e,n),t._initted?!r&&t._pt&&!I&&(t._dur&&!1!==t.vars.lazy||!t._dur&&t.vars.lazy)&&f!==It.frame?(pt.push(t),t._lazy=[n,i],1):void 0:1}function Ua(t,e,r,i){var n=t._repeat,a=la(e)||0,s=t._tTime/t._tDur;return s&&!i&&(t._time*=a/t._dur),t._dur=a,t._tDur=n?n<0?1e10:la(a*(n+1)+t._rDelay*n):a,0<s&&!i&&La(t,t._tTime=t._tDur*s),t.parent&&Ka(t),r||Da(t.parent,t),t}function Va(t){return t instanceof Zt?Da(t)Line truncated
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"tts_provider": "kokoro",
|
||||
"voice_id": "af_heart",
|
||||
"bgm": null,
|
||||
"bgm_pending": false,
|
||||
"bgm_provider": null,
|
||||
"bgm_pid": null,
|
||||
"bgm_log": null,
|
||||
"bgm_mode": null,
|
||||
"bgm_target_duration_s": null,
|
||||
"bgm_seed_duration_s": null,
|
||||
"bgm_loop_count": null,
|
||||
"voices": [
|
||||
{
|
||||
"id": "01",
|
||||
"path": "assets/voice/01.wav",
|
||||
"duration_s": 3.84,
|
||||
"words": []
|
||||
},
|
||||
{
|
||||
"id": "02",
|
||||
"path": "assets/voice/02.wav",
|
||||
"duration_s": 5.611,
|
||||
"words": []
|
||||
},
|
||||
{
|
||||
"id": "03",
|
||||
"path": "assets/voice/03.wav",
|
||||
"duration_s": 6.144,
|
||||
"words": []
|
||||
},
|
||||
{
|
||||
"id": "04",
|
||||
"path": "assets/voice/04.wav",
|
||||
"duration_s": 5.099,
|
||||
"words": []
|
||||
},
|
||||
{
|
||||
"id": "05",
|
||||
"path": "assets/voice/05.wav",
|
||||
"duration_s": 4.203,
|
||||
"words": []
|
||||
},
|
||||
{
|
||||
"id": "06",
|
||||
"path": "assets/voice/06.wav",
|
||||
"duration_s": 5.013,
|
||||
"words": []
|
||||
},
|
||||
{
|
||||
"id": "07",
|
||||
"path": "assets/voice/07.wav",
|
||||
"duration_s": 3.968,
|
||||
"words": []
|
||||
},
|
||||
{
|
||||
"id": "08",
|
||||
"path": "assets/voice/08.wav",
|
||||
"duration_s": 2.283,
|
||||
"words": []
|
||||
},
|
||||
{
|
||||
"id": "09",
|
||||
"path": "assets/voice/09.wav",
|
||||
"duration_s": 3.072,
|
||||
"words": []
|
||||
}
|
||||
],
|
||||
"sfx": [],
|
||||
"total_duration_s": 39.233
|
||||
}
|
||||
@@ -0,0 +1,635 @@
|
||||
{
|
||||
"bgm": null,
|
||||
"bgm_pending": false,
|
||||
"voices": [
|
||||
{
|
||||
"frame": 1,
|
||||
"path": "assets/voice/01.wav",
|
||||
"duration_s": 5.64,
|
||||
"words": [
|
||||
{
|
||||
"text": "Where",
|
||||
"start": 0.8,
|
||||
"end": 1.058
|
||||
},
|
||||
{
|
||||
"text": "are",
|
||||
"start": 1.08,
|
||||
"end": 1.264
|
||||
},
|
||||
{
|
||||
"text": "they",
|
||||
"start": 1.28,
|
||||
"end": 1.501
|
||||
},
|
||||
{
|
||||
"text": "right",
|
||||
"start": 1.52,
|
||||
"end": 1.778
|
||||
},
|
||||
{
|
||||
"text": "now",
|
||||
"start": 1.8,
|
||||
"end": 2.205
|
||||
},
|
||||
{
|
||||
"text": "And",
|
||||
"start": 2.24,
|
||||
"end": 2.424
|
||||
},
|
||||
{
|
||||
"text": "what",
|
||||
"start": 2.44,
|
||||
"end": 2.661
|
||||
},
|
||||
{
|
||||
"text": "are",
|
||||
"start": 2.68,
|
||||
"end": 2.864
|
||||
},
|
||||
{
|
||||
"text": "they",
|
||||
"start": 2.88,
|
||||
"end": 3.101
|
||||
},
|
||||
{
|
||||
"text": "really",
|
||||
"start": 3.12,
|
||||
"end": 3.414
|
||||
},
|
||||
{
|
||||
"text": "doing",
|
||||
"start": 3.44,
|
||||
"end": 3.698
|
||||
},
|
||||
{
|
||||
"text": "on",
|
||||
"start": 3.72,
|
||||
"end": 3.867
|
||||
},
|
||||
{
|
||||
"text": "that",
|
||||
"start": 3.88,
|
||||
"end": 4.101
|
||||
},
|
||||
{
|
||||
"text": "phone",
|
||||
"start": 4.12,
|
||||
"end": 4.598
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"frame": 2,
|
||||
"path": "assets/voice/02.wav",
|
||||
"duration_s": 7.111,
|
||||
"words": [
|
||||
{
|
||||
"text": "Endless",
|
||||
"start": 0.5,
|
||||
"end": 0.908
|
||||
},
|
||||
{
|
||||
"text": "scrolling",
|
||||
"start": 0.943,
|
||||
"end": 1.713
|
||||
},
|
||||
{
|
||||
"text": "Arguments",
|
||||
"start": 1.78,
|
||||
"end": 2.278
|
||||
},
|
||||
{
|
||||
"text": "at",
|
||||
"start": 2.321,
|
||||
"end": 2.502
|
||||
},
|
||||
{
|
||||
"text": "dinner",
|
||||
"start": 2.518,
|
||||
"end": 3.152
|
||||
},
|
||||
{
|
||||
"text": "And",
|
||||
"start": 3.207,
|
||||
"end": 3.433
|
||||
},
|
||||
{
|
||||
"text": "that",
|
||||
"start": 3.453,
|
||||
"end": 3.725
|
||||
},
|
||||
{
|
||||
"text": "quiet",
|
||||
"start": 3.748,
|
||||
"end": 4.065
|
||||
},
|
||||
{
|
||||
"text": "worry",
|
||||
"start": 4.093,
|
||||
"end": 4.41
|
||||
},
|
||||
{
|
||||
"text": "you",
|
||||
"start": 4.438,
|
||||
"end": 4.664
|
||||
},
|
||||
{
|
||||
"text": "never",
|
||||
"start": 4.684,
|
||||
"end": 5.001
|
||||
},
|
||||
{
|
||||
"text": "say",
|
||||
"start": 5.028,
|
||||
"end": 5.255
|
||||
},
|
||||
{
|
||||
"text": "out",
|
||||
"start": 5.274,
|
||||
"end": 5.501
|
||||
},
|
||||
{
|
||||
"text": "loud",
|
||||
"start": 5.52,
|
||||
"end": 6.064
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"frame": 3,
|
||||
"path": "assets/voice/03.wav",
|
||||
"duration_s": 8.144,
|
||||
"words": [
|
||||
{
|
||||
"text": "There",
|
||||
"start": 0.5,
|
||||
"end": 0.807
|
||||
},
|
||||
{
|
||||
"text": "has",
|
||||
"start": 0.833,
|
||||
"end": 1.052
|
||||
},
|
||||
{
|
||||
"text": "to",
|
||||
"start": 1.072,
|
||||
"end": 1.247
|
||||
},
|
||||
{
|
||||
"text": "be",
|
||||
"start": 1.262,
|
||||
"end": 1.437
|
||||
},
|
||||
{
|
||||
"text": "a",
|
||||
"start": 1.453,
|
||||
"end": 1.584
|
||||
},
|
||||
{
|
||||
"text": "better",
|
||||
"start": 1.595,
|
||||
"end": 1.946
|
||||
},
|
||||
{
|
||||
"text": "way",
|
||||
"start": 1.976,
|
||||
"end": 2.458
|
||||
},
|
||||
{
|
||||
"text": "Meet",
|
||||
"start": 2.5,
|
||||
"end": 2.763
|
||||
},
|
||||
{
|
||||
"text": "lookatu",
|
||||
"start": 2.786,
|
||||
"end": 3.443
|
||||
},
|
||||
{
|
||||
"text": "The",
|
||||
"start": 3.501,
|
||||
"end": 3.72
|
||||
},
|
||||
{
|
||||
"text": "child",
|
||||
"start": 3.739,
|
||||
"end": 4.045
|
||||
},
|
||||
{
|
||||
"text": "safety",
|
||||
"start": 4.072,
|
||||
"end": 4.423
|
||||
},
|
||||
{
|
||||
"text": "app",
|
||||
"start": 4.453,
|
||||
"end": 4.672
|
||||
},
|
||||
{
|
||||
"text": "that",
|
||||
"start": 4.691,
|
||||
"end": 4.954
|
||||
},
|
||||
{
|
||||
"text": "gives",
|
||||
"start": 4.977,
|
||||
"end": 5.284
|
||||
},
|
||||
{
|
||||
"text": "you",
|
||||
"start": 5.31,
|
||||
"end": 5.53
|
||||
},
|
||||
{
|
||||
"text": "peace",
|
||||
"start": 5.549,
|
||||
"end": 5.855
|
||||
},
|
||||
{
|
||||
"text": "of",
|
||||
"start": 5.882,
|
||||
"end": 6.057
|
||||
},
|
||||
{
|
||||
"text": "mind",
|
||||
"start": 6.072,
|
||||
"end": 6.598
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"frame": 4,
|
||||
"path": "assets/voice/04.wav",
|
||||
"duration_s": 6.599,
|
||||
"words": [
|
||||
{
|
||||
"text": "Set",
|
||||
"start": 0.5,
|
||||
"end": 0.715
|
||||
},
|
||||
{
|
||||
"text": "screen",
|
||||
"start": 0.734,
|
||||
"end": 1.078
|
||||
},
|
||||
{
|
||||
"text": "time",
|
||||
"start": 1.108,
|
||||
"end": 1.366
|
||||
},
|
||||
{
|
||||
"text": "limits",
|
||||
"start": 1.389,
|
||||
"end": 1.733
|
||||
},
|
||||
{
|
||||
"text": "that",
|
||||
"start": 1.763,
|
||||
"end": 2.021
|
||||
},
|
||||
{
|
||||
"text": "actually",
|
||||
"start": 2.044,
|
||||
"end": 2.474
|
||||
},
|
||||
{
|
||||
"text": "stick",
|
||||
"start": 2.512,
|
||||
"end": 3.071
|
||||
},
|
||||
{
|
||||
"text": "When",
|
||||
"start": 3.12,
|
||||
"end": 3.378
|
||||
},
|
||||
{
|
||||
"text": "the",
|
||||
"start": 3.4,
|
||||
"end": 3.616
|
||||
},
|
||||
{
|
||||
"text": "time",
|
||||
"start": 3.634,
|
||||
"end": 3.892
|
||||
},
|
||||
{
|
||||
"text": "is",
|
||||
"start": 3.915,
|
||||
"end": 4.087
|
||||
},
|
||||
{
|
||||
"text": "up",
|
||||
"start": 4.102,
|
||||
"end": 4.403
|
||||
},
|
||||
{
|
||||
"text": "the",
|
||||
"start": 4.43,
|
||||
"end": 4.645
|
||||
},
|
||||
{
|
||||
"text": "phone",
|
||||
"start": 4.663,
|
||||
"end": 4.965
|
||||
},
|
||||
{
|
||||
"text": "knows",
|
||||
"start": 4.991,
|
||||
"end": 5.55
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"frame": 5,
|
||||
"path": "assets/voice/05.wav",
|
||||
"duration_s": 5.703,
|
||||
"words": [
|
||||
{
|
||||
"text": "Choose",
|
||||
"start": 0.5,
|
||||
"end": 0.836
|
||||
},
|
||||
{
|
||||
"text": "which",
|
||||
"start": 0.865,
|
||||
"end": 1.16
|
||||
},
|
||||
{
|
||||
"text": "apps",
|
||||
"start": 1.185,
|
||||
"end": 1.437
|
||||
},
|
||||
{
|
||||
"text": "are",
|
||||
"start": 1.459,
|
||||
"end": 1.67
|
||||
},
|
||||
{
|
||||
"text": "okay",
|
||||
"start": 1.688,
|
||||
"end": 2.192
|
||||
},
|
||||
{
|
||||
"text": "Allow",
|
||||
"start": 2.236,
|
||||
"end": 2.53
|
||||
},
|
||||
{
|
||||
"text": "the",
|
||||
"start": 2.556,
|
||||
"end": 2.766
|
||||
},
|
||||
{
|
||||
"text": "good",
|
||||
"start": 2.784,
|
||||
"end": 3.036
|
||||
},
|
||||
{
|
||||
"text": "ones",
|
||||
"start": 3.058,
|
||||
"end": 3.563
|
||||
},
|
||||
{
|
||||
"text": "Block",
|
||||
"start": 3.607,
|
||||
"end": 3.901
|
||||
},
|
||||
{
|
||||
"text": "the",
|
||||
"start": 3.926,
|
||||
"end": 4.137
|
||||
},
|
||||
{
|
||||
"text": "rest",
|
||||
"start": 4.155,
|
||||
"end": 4.659
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"frame": 6,
|
||||
"path": "assets/voice/06.wav",
|
||||
"duration_s": 6.513,
|
||||
"words": [
|
||||
{
|
||||
"text": "And",
|
||||
"start": 0.5,
|
||||
"end": 0.71
|
||||
},
|
||||
{
|
||||
"text": "when",
|
||||
"start": 0.728,
|
||||
"end": 0.979
|
||||
},
|
||||
{
|
||||
"text": "it",
|
||||
"start": 1.001,
|
||||
"end": 1.169
|
||||
},
|
||||
{
|
||||
"text": "really",
|
||||
"start": 1.184,
|
||||
"end": 1.519
|
||||
},
|
||||
{
|
||||
"text": "matters",
|
||||
"start": 1.548,
|
||||
"end": 2.051
|
||||
},
|
||||
{
|
||||
"text": "see",
|
||||
"start": 2.095,
|
||||
"end": 2.305
|
||||
},
|
||||
{
|
||||
"text": "where",
|
||||
"start": 2.323,
|
||||
"end": 2.616
|
||||
},
|
||||
{
|
||||
"text": "they",
|
||||
"start": 2.642,
|
||||
"end": 2.893
|
||||
},
|
||||
{
|
||||
"text": "are",
|
||||
"start": 2.915,
|
||||
"end": 3.377
|
||||
},
|
||||
{
|
||||
"text": "Location",
|
||||
"start": 3.417,
|
||||
"end": 3.962
|
||||
},
|
||||
{
|
||||
"text": "only",
|
||||
"start": 4.009,
|
||||
"end": 4.261
|
||||
},
|
||||
{
|
||||
"text": "when",
|
||||
"start": 4.283,
|
||||
"end": 4.534
|
||||
},
|
||||
{
|
||||
"text": "you",
|
||||
"start": 4.556,
|
||||
"end": 4.766
|
||||
},
|
||||
{
|
||||
"text": "need",
|
||||
"start": 4.784,
|
||||
"end": 5.035
|
||||
},
|
||||
{
|
||||
"text": "it",
|
||||
"start": 5.057,
|
||||
"end": 5.477
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"frame": 7,
|
||||
"path": "assets/voice/07.wav",
|
||||
"duration_s": 5.468,
|
||||
"words": [
|
||||
{
|
||||
"text": "Because",
|
||||
"start": 0.5,
|
||||
"end": 0.896
|
||||
},
|
||||
{
|
||||
"text": "kids",
|
||||
"start": 0.93,
|
||||
"end": 1.194
|
||||
},
|
||||
{
|
||||
"text": "deserve",
|
||||
"start": 1.217,
|
||||
"end": 1.613
|
||||
},
|
||||
{
|
||||
"text": "some",
|
||||
"start": 1.647,
|
||||
"end": 1.911
|
||||
},
|
||||
{
|
||||
"text": "freedom",
|
||||
"start": 1.934,
|
||||
"end": 2.462
|
||||
},
|
||||
{
|
||||
"text": "and",
|
||||
"start": 2.508,
|
||||
"end": 2.728
|
||||
},
|
||||
{
|
||||
"text": "parents",
|
||||
"start": 2.747,
|
||||
"end": 3.143
|
||||
},
|
||||
{
|
||||
"text": "deserve",
|
||||
"start": 3.177,
|
||||
"end": 3.573
|
||||
},
|
||||
{
|
||||
"text": "some",
|
||||
"start": 3.607,
|
||||
"end": 3.871
|
||||
},
|
||||
{
|
||||
"text": "calm",
|
||||
"start": 3.894,
|
||||
"end": 4.422
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"frame": 8,
|
||||
"path": "assets/voice/08.wav",
|
||||
"duration_s": 3.783,
|
||||
"words": [
|
||||
{
|
||||
"text": "Works",
|
||||
"start": 0.5,
|
||||
"end": 0.842
|
||||
},
|
||||
{
|
||||
"text": "on",
|
||||
"start": 0.872,
|
||||
"end": 1.067
|
||||
},
|
||||
{
|
||||
"text": "Android",
|
||||
"start": 1.084,
|
||||
"end": 1.524
|
||||
},
|
||||
{
|
||||
"text": "and",
|
||||
"start": 1.562,
|
||||
"end": 1.806
|
||||
},
|
||||
{
|
||||
"text": "on",
|
||||
"start": 1.827,
|
||||
"end": 2.023
|
||||
},
|
||||
{
|
||||
"text": "iPhone",
|
||||
"start": 2.04,
|
||||
"end": 2.724
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"frame": 9,
|
||||
"path": "assets/voice/09.wav",
|
||||
"duration_s": 5.772,
|
||||
"words": [
|
||||
{
|
||||
"text": "lookatu",
|
||||
"start": 0.5,
|
||||
"end": 1.106
|
||||
},
|
||||
{
|
||||
"text": "Look",
|
||||
"start": 1.158,
|
||||
"end": 1.401
|
||||
},
|
||||
{
|
||||
"text": "out",
|
||||
"start": 1.422,
|
||||
"end": 1.623
|
||||
},
|
||||
{
|
||||
"text": "for",
|
||||
"start": 1.641,
|
||||
"end": 1.843
|
||||
},
|
||||
{
|
||||
"text": "them",
|
||||
"start": 1.86,
|
||||
"end": 2.345
|
||||
},
|
||||
{
|
||||
"text": "Download",
|
||||
"start": 2.387,
|
||||
"end": 2.791
|
||||
},
|
||||
{
|
||||
"text": "it",
|
||||
"start": 2.826,
|
||||
"end": 2.987
|
||||
},
|
||||
{
|
||||
"text": "today",
|
||||
"start": 3.001,
|
||||
"end": 3.526
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"sfx": []
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"provider": "kokoro",
|
||||
"speed": "0.85",
|
||||
"lines": [
|
||||
{
|
||||
"id": "01",
|
||||
"text": "Where are they right now? And what are they really doing on that phone?"
|
||||
},
|
||||
{
|
||||
"id": "02",
|
||||
"text": "Endless scrolling. Arguments at dinner. And that quiet worry you never say out loud."
|
||||
},
|
||||
{
|
||||
"id": "03",
|
||||
"text": "There has to be a better way. Meet lookatu. The child safety app that gives you peace of mind."
|
||||
},
|
||||
{
|
||||
"id": "04",
|
||||
"text": "Set screen time limits that actually stick. When the time is up, the phone knows."
|
||||
},
|
||||
{
|
||||
"id": "05",
|
||||
"text": "Choose which apps are okay. Allow the good ones. Block the rest."
|
||||
},
|
||||
{
|
||||
"id": "06",
|
||||
"text": "And when it really matters, see where they are. Location, only when you need it."
|
||||
},
|
||||
{
|
||||
"id": "07",
|
||||
"text": "Because kids deserve some freedom, and parents deserve some calm."
|
||||
},
|
||||
{
|
||||
"id": "08",
|
||||
"text": "Works on Android and on iPhone."
|
||||
},
|
||||
{
|
||||
"id": "09",
|
||||
"text": "lookatu. Look out for them. Download it today."
|
||||
}
|
||||
],
|
||||
"bgm": {
|
||||
"mode": "none"
|
||||
},
|
||||
"voice": "af_heart"
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
[]
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1 @@
|
||||
No assets were captured. No website, logo or screenshots supplied. Use invented phone UI mock-ups and a typographic lookatu wordmark.
|
||||
@@ -0,0 +1 @@
|
||||
{ "title": "lookatu", "description": "Child-safety app (Android and iOS) that lets parents control kids' phone usage and track location when needed.", "colors": [], "fonts": [] }
|
||||
@@ -0,0 +1,4 @@
|
||||
lookatu - child safety app for Android and iOS.
|
||||
Parents control how their kids use the phone (time limits, app control).
|
||||
Parents can track location when needed.
|
||||
Message: keep your kids safe on their phones, with peace of mind for parents.
|
||||
@@ -0,0 +1,235 @@
|
||||
<template id="captions-template" data-composition-id="captions" data-width="1080" data-height="1920">
|
||||
<script src="assets/vendor/gsap.min.js"></script>
|
||||
|
||||
|
||||
<style data-brand-tokens>
|
||||
@font-face { font-family: 'Quicksand'; src: url('assets/fonts/quicksand-var.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: block; }
|
||||
:root {
|
||||
--cream: #F5F0E6;
|
||||
--turquoise: #7ECDC0;
|
||||
--soft-pink: #F7C8D4;
|
||||
--butter: #FDE68A;
|
||||
--mint: #A8E6CF;
|
||||
--lavender: #D4A5E8;
|
||||
--peach: #FFCBA4;
|
||||
--sky: #A8D8F0;
|
||||
--coral: #F8635F;
|
||||
--text-dark: #2D2D2D;
|
||||
--text-muted: #6B6B6B;
|
||||
--white: #FFFFFF;
|
||||
--cap-ink: #2D2D2D;
|
||||
--cap-canvas: #F5F0E6;
|
||||
--cap-accent: #F8635F;
|
||||
--cap-accent-2: #FDE68A;
|
||||
--font-display: "Fredoka One", system-ui, serif;
|
||||
--font-body: "Quicksand", system-ui, sans-serif;
|
||||
--cap-band-top: 1600px;
|
||||
--cap-band-height: 320px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
@font-face { font-family: "Fredoka"; src: url("assets/fonts/fredoka-600.woff2") format("woff2"); font-weight: 600; font-style: normal; }
|
||||
@font-face { font-family: "Fredoka One"; src: url("assets/fonts/fredoka-600.woff2") format("woff2"); font-weight: 600; font-style: normal; }
|
||||
@font-face { font-family: "Quicksand"; src: url("assets/fonts/quicksand-var.woff2") format("woff2"); font-weight: 500 700; font-style: normal; }
|
||||
#captions-root {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
.caption-layer {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 20;
|
||||
pointer-events: none;
|
||||
}
|
||||
/* the keep-out band, from captionBand(H) — frame content stays above it */
|
||||
.caption-stage {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: var(--cap-band-top, 900px);
|
||||
height: var(--cap-band-height, 180px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.caption-group {
|
||||
/* every group is absolutely stacked over the SAME band — exactly one shown at a
|
||||
time via opacity. Must be absolute: in-flow groups would lay out side-by-side. */
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* THE picture-book card — cream surface, 3px charcoal outline, generous 24px radius,
|
||||
a hard 6px charcoal offset shadow (no blur): the sticker-on-paper signature */
|
||||
.caption-pill {
|
||||
max-width: 80%;
|
||||
padding: 18px 40px 22px;
|
||||
background: var(--cap-canvas, #f5f0e6);
|
||||
border: 3px solid var(--cap-ink, #2d2d2d);
|
||||
border-radius: 24px;
|
||||
box-shadow: 6px 6px 0 var(--cap-ink, #2d2d2d);
|
||||
}
|
||||
.caption-line {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 0.18em 0.32em;
|
||||
font-family: "Fredoka One", sans-serif;
|
||||
font-weight: 600;
|
||||
font-size: clamp(38px, 4.2vw, 56px);
|
||||
line-height: 1.22;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
/* upcoming — muted charcoal, no candy block */
|
||||
.caption-word {
|
||||
display: inline-block;
|
||||
padding: 0.02em 0.16em;
|
||||
border-radius: 12px;
|
||||
color: color-mix(in srgb, var(--cap-ink, #2d2d2d) 52%, var(--cap-canvas, #f5f0e6));
|
||||
}
|
||||
/* current word — THE sunny-pastel candy block: a rounded coral chip with a 3px
|
||||
charcoal outline + a hard 3px charcoal offset shadow (no blur), charcoal on top */
|
||||
.caption-word.is-active {
|
||||
color: var(--cap-ink, #2d2d2d);
|
||||
background: var(--cap-accent, #f8635f);
|
||||
border-radius: 12px;
|
||||
box-shadow:
|
||||
0 0 0 3px var(--cap-ink, #2d2d2d),
|
||||
3px 5px 0 0 var(--cap-ink, #2d2d2d);
|
||||
}
|
||||
/* already spoken — solid charcoal, candy block cleared */
|
||||
.caption-word.is-spoken {
|
||||
color: var(--cap-ink, #2d2d2d);
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* optional per-word accents (dormant until a word-classer tags them) */
|
||||
/* brand / key term — a butter candy chip, the cheerful second pastel */
|
||||
.caption-word.cap-brand {
|
||||
color: var(--cap-ink, #2d2d2d);
|
||||
background: var(--cap-accent-2, #fde68a);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 0 0 3px var(--cap-ink, #2d2d2d);
|
||||
}
|
||||
/* numerals / data — Quicksand, slightly recessed */
|
||||
.caption-word.cap-num {
|
||||
font-family: "Quicksand", system-ui, sans-serif;
|
||||
font-weight: 700;
|
||||
color: color-mix(in srgb, var(--cap-ink, #2d2d2d) 78%, var(--cap-canvas, #f5f0e6));
|
||||
}
|
||||
/* emphasis — a butter underline rule (the second sunny pastel) */
|
||||
.caption-word.cap-cta {
|
||||
text-decoration: underline;
|
||||
text-decoration-thickness: 3px;
|
||||
text-decoration-color: var(--cap-accent-2, #fde68a);
|
||||
text-underline-offset: 0.12em;
|
||||
}
|
||||
|
||||
@media (max-aspect-ratio: 9/16) {
|
||||
.caption-pill {
|
||||
max-width: 92%;
|
||||
}
|
||||
.caption-line {
|
||||
font-size: clamp(32px, 5.2vw, 46px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div
|
||||
id="captions-root"
|
||||
data-composition-id="captions"
|
||||
data-timeline-locked
|
||||
data-start="0"
|
||||
data-duration="54.733"
|
||||
data-fps="30"
|
||||
data-width="1080"
|
||||
data-height="1920"
|
||||
>
|
||||
<div class="caption-layer" aria-hidden="true">
|
||||
<div id="caption-stage" class="caption-stage"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// captions.mjs injects the engine's scene-aware groups + real duration here.
|
||||
var GROUPS = [{"id":"caption-group-0","frame":1,"start":0.8,"end":1.28,"text":"Where are","words":[{"id":"caption-word-0-0","text":"Where","start":0.8,"end":1.058},{"id":"caption-word-0-1","text":"are","start":1.08,"end":1.264}]},{"id":"caption-group-1","frame":1,"start":1.28,"end":1.8,"text":"they right","words":[{"id":"caption-word-1-0","text":"they","start":1.28,"end":1.501},{"id":"caption-word-1-1","text":"right","start":1.52,"end":1.778}]},{"id":"caption-group-2","frame":1,"start":1.8,"end":2.44,"text":"now And","words":[{"id":"caption-word-2-0","text":"now","start":1.8,"end":2.205},{"id":"caption-word-2-1","text":"And","start":2.24,"end":2.424}]},{"id":"caption-group-3","frame":1,"start":2.44,"end":2.88,"text":"what are","words":[{"id":"caption-word-3-0","text":"what","start":2.44,"end":2.661},{"id":"caption-word-3-1","text":"are","start":2.68,"end":2.864}]},{"id":"caption-group-4","frame":1,"start":2.88,"end":3.44,"text":"they really","words":[{"id":"caption-word-4-0","text":"they","start":2.88,"end":3.101},{"id":"caption-word-4-1","text":"really","start":3.12,"end":3.414}]},{"id":"caption-group-5","frame":1,"start":3.44,"end":3.88,"text":"doing on","words":[{"id":"caption-word-5-0","text":"doing","start":3.44,"end":3.698},{"id":"caption-word-5-1","text":"on","start":3.72,"end":3.867}]},{"id":"caption-group-6","frame":1,"start":3.88,"end":4.718,"text":"that phone","words":[{"id":"caption-word-6-0","text":"that","start":3.88,"end":4.101},{"id":"caption-word-6-1","text":"phone","start":4.12,"end":4.598}]},{"id":"caption-group-7","frame":2,"start":6.14,"end":8.158,"text":"Endless scrolling Arguments at","words":[{"id":"caption-word-7-0","text":"Endless","start":6.14,"end":6.548},{"id":"caption-word-7-1","text":"scrolling","start":6.583,"end":7.353},{"id":"caption-word-7-2","text":"Arguments","start":7.42,"end":7.918},{"id":"caption-word-7-3","text":"at","start":7.961,"end":8.142}]},{"id":"caption-group-8","frame":2,"start":8.158,"end":9.388,"text":"dinner And that","words":[{"id":"caption-word-8-0","text":"dinner","start":8.158,"end":8.792},{"id":"caption-word-8-1","text":"And","start":8.847,"end":9.073},{"id":"caption-word-8-2","text":"that","start":9.093,"end":9.365}]},{"id":"caption-group-9","frame":2,"start":9.388,"end":10.078,"text":"quiet worry","words":[{"id":"caption-word-9-0","text":"quiet","start":9.388,"end":9.705},{"id":"caption-word-9-1","text":"worry","start":9.733,"end":10.05}]},{"id":"caption-group-10","frame":2,"start":10.078,"end":10.668,"text":"you never","words":[{"id":"caption-word-10-0","text":"you","start":10.078,"end":10.304},{"id":"caption-word-10-1","text":"never","start":10.324,"end":10.641}]},{"id":"caption-group-11","frame":2,"start":10.668,"end":11.824,"text":"say out loud","words":[{"id":"caption-word-11-0","text":"say","start":10.668,"end":10.895},{"id":"caption-word-11-1","text":"out","start":10.914,"end":11.141},{"id":"caption-word-11-2","text":"loud","start":11.16,"end":11.704}]},{"id":"caption-group-12","frame":3,"start":13.251,"end":13.823,"text":"There has","words":[{"id":"caption-word-12-0","text":"There","start":13.251,"end":13.558},{"id":"caption-word-12-1","text":"has","start":13.584,"end":13.803}]},{"id":"caption-group-13","frame":3,"start":13.823,"end":14.204,"text":"to be","words":[{"id":"caption-word-13-0","text":"to","start":13.823,"end":13.998},{"id":"caption-word-13-1","text":"be","start":14.013,"end":14.188}]},{"id":"caption-group-14","frame":3,"start":14.204,"end":15.251,"text":"a better way","words":[{"id":"caption-word-14-0","text":"a","start":14.204,"end":14.335},{"id":"caption-word-14-1","text":"better","start":14.346,"end":14.697},{"id":"caption-word-14-2","text":"way","start":14.727,"end":15.209}]},{"id":"caption-group-15","frame":3,"start":15.251,"end":16.823,"text":"Meet lookatu The child","words":[{"id":"caption-word-15-0","text":"Meet","start":15.251,"end":15.514},{"id":"caption-word-15-1","text":"lookatu","start":15.537,"end":16.194},{"id":"caption-word-15-2","text":"The","start":16.252,"end":16.471},{"id":"caption-word-15-3","text":"child","start":16.49,"end":16.796}]},{"id":"caption-group-16","frame":3,"start":16.823,"end":17.442,"text":"safety app","words":[{"id":"caption-word-16-0","text":"safety","start":16.823,"end":17.174},{"id":"caption-word-16-1","text":"app","start":17.204,"end":17.423}]},{"id":"caption-group-17","frame":3,"start":17.442,"end":18.061,"text":"that gives","words":[{"id":"caption-word-17-0","text":"that","start":17.442,"end":17.705},{"id":"caption-word-17-1","text":"gives","start":17.728,"end":18.035}]},{"id":"caption-group-18","frame":3,"start":18.061,"end":18.633,"text":"you peace","words":[{"id":"caption-word-18-0","text":"you","start":18.061,"end":18.281},{"id":"caption-word-18-1","text":"peace","start":18.3,"end":18.606}]},{"id":"caption-group-19","frame":3,"start":18.633,"end":19.469,"text":"of mind","words":[{"id":"caption-word-19-0","text":"of","start":18.633,"end":18.808},{"id":"caption-word-19-1","text":"mLine truncated
|
||||
var DURATION = 54.733;
|
||||
|
||||
(function () {
|
||||
var stage = document.getElementById("caption-stage");
|
||||
|
||||
// build DOM: one .caption-group per group, .caption-word per word
|
||||
GROUPS.forEach(function (group, g) {
|
||||
var groupEl = document.createElement("div");
|
||||
groupEl.className = "caption-group";
|
||||
groupEl.id = "caption-group-" + g;
|
||||
var pill = document.createElement("div");
|
||||
pill.className = "caption-pill";
|
||||
var line = document.createElement("div");
|
||||
line.className = "caption-line";
|
||||
(group.words || []).forEach(function (w, i) {
|
||||
var span = document.createElement("span");
|
||||
span.className = "caption-word";
|
||||
span.id = "caption-word-" + g + "-" + i;
|
||||
span.textContent = String(w.text);
|
||||
line.appendChild(span);
|
||||
});
|
||||
pill.appendChild(line);
|
||||
groupEl.appendChild(pill);
|
||||
stage.appendChild(groupEl);
|
||||
});
|
||||
|
||||
window.__timelines = window.__timelines || {};
|
||||
var tl = gsap.timeline({ paused: true });
|
||||
|
||||
GROUPS.forEach(function (group, g) {
|
||||
var groupEl = document.getElementById("caption-group-" + g);
|
||||
var words = group.words || [];
|
||||
var next = GROUPS[g + 1];
|
||||
var isLast = g === GROUPS.length - 1;
|
||||
var start = Math.max(0, Number(group.start));
|
||||
var end = isLast ? DURATION : Math.min(Number(next.start), Number(group.end) + 0.3);
|
||||
if (end <= start) end = start + 0.01;
|
||||
|
||||
// group on/off — exactly one group visible at a time
|
||||
tl.set(groupEl, { opacity: 1 }, start);
|
||||
tl.set(groupEl, { opacity: 0 }, end);
|
||||
|
||||
// 3-state karaoke via className SETS — seek-safe (gsap.set applies on the
|
||||
// engine's frame-by-frame seek; .call callbacks would NOT fire).
|
||||
words.forEach(function (w, i) {
|
||||
var el = document.getElementById("caption-word-" + g + "-" + i);
|
||||
var at = Math.max(start, Number(w.start));
|
||||
tl.set(el, { className: "caption-word" }, start); // upcoming (also resets on reverse-seek)
|
||||
tl.set(el, { className: "caption-word is-active" }, at); // current
|
||||
tl.fromTo(el, { scale: 0.82 }, { scale: 1, duration: 0.2, ease: "back.out(2.6)" }, at);
|
||||
if (i + 1 < words.length) {
|
||||
var nextAt = Math.max(start, Number(words[i + 1].start));
|
||||
tl.set(el, { className: "caption-word is-spoken" }, nextAt); // demote when next activates
|
||||
}
|
||||
});
|
||||
if (words.length) {
|
||||
var lastEl = document.getElementById("caption-word-" + g + "-" + (words.length - 1));
|
||||
var lastSpoken = Math.min(end, Number(words[words.length - 1].end) + 0.1);
|
||||
tl.set(lastEl, { className: "caption-word is-spoken" }, lastSpoken);
|
||||
}
|
||||
});
|
||||
|
||||
// full-span anchor so the sub-comp timeline spans the whole video
|
||||
tl.to({}, { duration: DURATION }, 0);
|
||||
window.__timelines["captions"] = tl;
|
||||
})();
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.caption-line { line-height: 1.1 !important; }
|
||||
</style>
|
||||
</template>
|
||||
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<style>
|
||||
@font-face { font-family: "Fredoka"; src: url("assets/fonts/fredoka-600.woff2") format("woff2"); font-weight: 600; font-style: normal; }
|
||||
@font-face { font-family: "Quicksand"; src: url("assets/fonts/quicksand-var.woff2") format("woff2"); font-weight: 500 700; font-style: normal; }
|
||||
#root { position: absolute; inset: 0; overflow: hidden; color: #2D2D2D; font-family: "Quicksand", sans-serif; font-weight: 600; }
|
||||
.f1-bg { position: absolute; inset: 0; }
|
||||
.f1-orn { position: absolute; z-index: 1; }
|
||||
.f1-orn svg { width: 100%; height: 100%; display: block; overflow: visible; }
|
||||
.f1-z { position: absolute; z-index: 2; }
|
||||
.f1-d { font-family: "Fredoka", sans-serif; font-weight: 600; letter-spacing: 0.02em; line-height: 1.05; }
|
||||
.f1-card { background: #FFFFFF; border: 5px solid #2D2D2D; border-radius: 40px; box-shadow: 12px 12px 0 #2D2D2D; }
|
||||
.f1-pill { display: inline-flex; align-items: center; gap: 18px; border: 5px solid #2D2D2D; border-radius: 80px; box-shadow: 8px 8px 0 #2D2D2D; padding: 20px 46px; white-space: nowrap; }
|
||||
.f1-phone { position: absolute; z-index: 2; left: 260px; top: 230px; width: 560px; height: 1120px; background: #FFFFFF; border: 6px solid #2D2D2D; border-radius: 80px; box-shadow: 16px 16px 0 #2D2D2D; overflow: hidden; }
|
||||
.f1-notch { position: absolute; left: 50%; top: 22px; margin-left: -70px; width: 140px; height: 28px; border-radius: 20px; background: #2D2D2D; }
|
||||
|
||||
.f1-bub { position: absolute; z-index: 2; display: flex; align-items: center; justify-content: center; border-radius: 70px; }
|
||||
.f1-bub span { font-size: 168px; color: #2D2D2D; }
|
||||
.f1-b1 { left: 80px; top: 250px; width: 760px; height: 360px; }
|
||||
.f1-b2 { left: 240px; top: 700px; width: 760px; height: 360px; background: #FDE68A; }
|
||||
.f1-tail1 { position: absolute; z-index: 3; left: 190px; top: 584px; width: 70px; height: 70px; background: #FFFFFF; border-right: 5px solid #2D2D2D; border-bottom: 5px solid #2D2D2D; transform: rotate(45deg); }
|
||||
.f1-tail2 { position: absolute; z-index: 3; left: 820px; top: 1034px; width: 70px; height: 70px; background: #FDE68A; border-right: 5px solid #2D2D2D; border-bottom: 5px solid #2D2D2D; transform: rotate(45deg); }
|
||||
.f1-ph { left: 390px; top: 1160px; width: 300px; height: 420px; background: #2D2D2D; border: 6px solid #2D2D2D; border-radius: 56px; box-shadow: 12px 12px 0 rgba(45,45,45,0.25); display: flex; align-items: center; justify-content: center; }
|
||||
.f1-ph b { font-family: "Fredoka", sans-serif; font-weight: 600; font-size: 170px; color: #FDE68A; }
|
||||
</style>
|
||||
<div id="root" data-composition-id="01-hook" data-width="1080" data-height="1920" data-duration="6.14">
|
||||
<div id="scene1-bg" class="clip f1-bg" data-start="0" data-duration="6.14" data-track-index="0" style="background:#A8D8F0"></div>
|
||||
<div class="f1-orn" style="left:-70px;top:90px;width:300px;height:300px"><svg viewBox="0 0 100 100" style="transform:rotate(-4deg)" xmlns="http://www.w3.org/2000/svg"><path d="M24 72 a17 17 0 0 1 3-33 a22 22 0 0 1 43-3 a17 17 0 0 1 6 36 z" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f1-orn" style="left:800px;top:40px;width:260px;height:260px"><svg viewBox="0 0 100 100" style="transform:rotate(10deg)" xmlns="http://www.w3.org/2000/svg"><line x1="50" y1="9" x2="50" y2="22" transform="rotate(0 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(30 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(60 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(90 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(120 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(150 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(180 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(210 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(240 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(270 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(300 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(330 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><circle cx="50" cy="50" r="24" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f1-orn" style="left:900px;top:1150px;width:150px;height:150px"><svg viewBox="0 0 100 100" style="transform:rotate(14deg)" xmlns="http://www.w3.org/2000/svg"><polygon points="50,6 61,38 95,38 67,58 78,92 50,71 22,92 33,58 5,38 39,38" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f1-orn" style="left:-50px;top:1330px;width:230px;height:230px"><svg viewBox="0 0 100 100" style="transform:rotate(8deg)" xmlns="http://www.w3.org/2000/svg"><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(0 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(45 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(90 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(135 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(180 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(225 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(270 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(315 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><circle cx="50" cy="50" r="14" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f1-orn" style="left:760px;top:1380px;width:260px;height:260px"><svg viewBox="0 0 100 100" style="transform:rotate(5deg)" xmlns="http://www.w3.org/2000/svg"><path d="M24 72 a17 17 0 0 1 3-33 a22 22 0 0 1 43-3 a17 17 0 0 1 6 36 z" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
|
||||
<div class="f1-bub f1-card f1-b1"><span class="f1-d">WHERE?</span></div>
|
||||
<div class="f1-tail1"></div>
|
||||
<div class="f1-bub f1-card f1-b2"><span class="f1-d">WHAT?</span></div>
|
||||
<div class="f1-tail2"></div>
|
||||
<div class="f1-z f1-ph"><b>?</b></div>
|
||||
</div>
|
||||
<script>
|
||||
(function () {
|
||||
const DUR = 5.64;
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
|
||||
const orns = document.querySelectorAll(".f1-orn");
|
||||
tl.fromTo(orns, { scale: 0, opacity: 0 }, { scale: 1, opacity: 1, duration: 0.55, ease: "back.out(1.8)", stagger: 0.07 }, 0.05);
|
||||
orns.forEach((el, i) => {
|
||||
const t0 = 0.9 + i * 0.12, half = Math.max(1.2, (DUR - 1.6) / 2), amp = i % 2 ? -14 : 14;
|
||||
tl.to(el, { y: amp, duration: half, ease: "sine.inOut" }, t0).to(el, { y: 0, duration: half, ease: "sine.inOut" }, t0 + half);
|
||||
});
|
||||
|
||||
tl.fromTo(".f1-b1", { scale: 0.2, opacity: 0, rotation: -8 }, { scale: 1, opacity: 1, rotation: -2, duration: 0.55, ease: "back.out(1.9)" }, 0.3);
|
||||
tl.fromTo(".f1-tail1", { opacity: 0 }, { opacity: 1, duration: 0.2 }, 0.6499999999999999);
|
||||
tl.fromTo(".f1-b2", { scale: 0.2, opacity: 0, rotation: 8 }, { scale: 1, opacity: 1, rotation: 2, duration: 0.55, ease: "back.out(1.9)" }, 2.12);
|
||||
tl.fromTo(".f1-tail2", { opacity: 0 }, { opacity: 1, duration: 0.2 }, 2.47);
|
||||
tl.fromTo(".f1-ph", { scale: 0, rotation: 12 }, { scale: 1, rotation: 0, duration: 0.6, ease: "back.out(1.7)" }, 3);
|
||||
tl.to(".f1-ph", { rotation: -5, duration: 0.18, ease: "sine.inOut" }, 3.6)
|
||||
.to(".f1-ph", { rotation: 5, duration: 0.3, ease: "sine.inOut" }, ">")
|
||||
.to(".f1-ph", { rotation: -3, duration: 0.3, ease: "sine.inOut" }, ">")
|
||||
.to(".f1-ph", { rotation: 0, duration: 0.25, ease: "sine.inOut" }, ">");
|
||||
window.__timelines["01-hook"] = tl;
|
||||
})();
|
||||
</script>
|
||||
</template>
|
||||
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<style>
|
||||
@font-face { font-family: "Fredoka"; src: url("assets/fonts/fredoka-600.woff2") format("woff2"); font-weight: 600; font-style: normal; }
|
||||
@font-face { font-family: "Quicksand"; src: url("assets/fonts/quicksand-var.woff2") format("woff2"); font-weight: 500 700; font-style: normal; }
|
||||
#root { position: absolute; inset: 0; overflow: hidden; color: #2D2D2D; font-family: "Quicksand", sans-serif; font-weight: 600; }
|
||||
.f2-bg { position: absolute; inset: 0; }
|
||||
.f2-orn { position: absolute; z-index: 1; }
|
||||
.f2-orn svg { width: 100%; height: 100%; display: block; overflow: visible; }
|
||||
.f2-z { position: absolute; z-index: 2; }
|
||||
.f2-d { font-family: "Fredoka", sans-serif; font-weight: 600; letter-spacing: 0.02em; line-height: 1.05; }
|
||||
.f2-card { background: #FFFFFF; border: 5px solid #2D2D2D; border-radius: 40px; box-shadow: 12px 12px 0 #2D2D2D; }
|
||||
.f2-pill { display: inline-flex; align-items: center; gap: 18px; border: 5px solid #2D2D2D; border-radius: 80px; box-shadow: 8px 8px 0 #2D2D2D; padding: 20px 46px; white-space: nowrap; }
|
||||
.f2-phone { position: absolute; z-index: 2; left: 260px; top: 230px; width: 560px; height: 1120px; background: #FFFFFF; border: 6px solid #2D2D2D; border-radius: 80px; box-shadow: 16px 16px 0 #2D2D2D; overflow: hidden; }
|
||||
.f2-notch { position: absolute; left: 50%; top: 22px; margin-left: -70px; width: 140px; height: 28px; border-radius: 20px; background: #2D2D2D; }
|
||||
|
||||
.f2-row { position: absolute; z-index: 2; left: 100px; width: 880px; height: 320px; display: flex; align-items: center; padding: 0 44px; gap: 34px; }
|
||||
.f2-row svg { width: 130px; height: 130px; flex: none; background: #FFFFFF; border: 5px solid #2D2D2D; border-radius: 50%; padding: 22px; box-sizing: border-box; }
|
||||
.f2-row span { font-size: 92px; color: #2D2D2D; }
|
||||
</style>
|
||||
<div id="root" data-composition-id="02-worry" data-width="1080" data-height="1920" data-duration="7.511">
|
||||
<div id="scene2-bg" class="clip f2-bg" data-start="0" data-duration="7.511" data-track-index="0" style="background:#F5F0E6"></div>
|
||||
<div class="f2-orn" style="left:880px;top:90px;width:170px;height:170px"><svg viewBox="0 0 100 100" style="transform:rotate(12deg)" xmlns="http://www.w3.org/2000/svg"><polygon points="50,6 61,38 95,38 67,58 78,92 50,71 22,92 33,58 5,38 39,38" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f2-orn" style="left:-60px;top:150px;width:220px;height:220px"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(0 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(45 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(90 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(135 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(180 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(225 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(270 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(315 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><circle cx="50" cy="50" r="14" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f2-orn" style="left:780px;top:1360px;width:300px;height:300px"><svg viewBox="0 0 100 100" style="transform:rotate(-6deg)" xmlns="http://www.w3.org/2000/svg"><path d="M24 72 a17 17 0 0 1 3-33 a22 22 0 0 1 43-3 a17 17 0 0 1 6 36 z" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f2-orn" style="left:50px;top:1420px;width:130px;height:130px"><svg viewBox="0 0 100 100" style="transform:rotate(-14deg)" xmlns="http://www.w3.org/2000/svg"><polygon points="50,6 61,38 95,38 67,58 78,92 50,71 22,92 33,58 5,38 39,38" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f2-orn" style="left:900px;top:700px;width:170px;height:170px"><svg viewBox="0 0 100 100" style="transform:rotate(20deg)" xmlns="http://www.w3.org/2000/svg"><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(0 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(45 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(90 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(135 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(180 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(225 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(270 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(315 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><circle cx="50" cy="50" r="14" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
|
||||
<div class="f2-row f2-card f2-r0" style="top:250px;background:#FDE68A"><svg viewBox="0 0 100 100"><path d="M20 34 L50 62 L80 34" fill="none" stroke="#2D2D2D" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/><path d="M20 12 L50 40 L80 12" fill="none" stroke="#2D2D2D" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/></svg><span class="f2-d">SCROLLING</span></div>
|
||||
<div class="f2-row f2-card f2-r1" style="top:650px;background:#F7C8D4"><svg viewBox="0 0 100 100"><polygon points="58,6 24,54 48,54 40,94 76,42 52,42" fill="#F8635F" stroke="#2D2D2D" stroke-width="5" stroke-linejoin="round"/></svg><span class="f2-d">ARGUING</span></div>
|
||||
<div class="f2-row f2-card f2-r2" style="top:1050px;background:#D4A5E8"><svg viewBox="0 0 100 100"><path d="M24 72 a17 17 0 0 1 3-33 a22 22 0 0 1 43-3 a17 17 0 0 1 6 36 z" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="5" stroke-linejoin="round"/></svg><span class="f2-d">WORRYING</span></div>
|
||||
</div>
|
||||
<script>
|
||||
(function () {
|
||||
const DUR = 7.111;
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
|
||||
const orns = document.querySelectorAll(".f2-orn");
|
||||
tl.fromTo(orns, { scale: 0, opacity: 0 }, { scale: 1, opacity: 1, duration: 0.55, ease: "back.out(1.8)", stagger: 0.07 }, 0.05);
|
||||
orns.forEach((el, i) => {
|
||||
const t0 = 0.9 + i * 0.12, half = Math.max(1.2, (DUR - 1.6) / 2), amp = i % 2 ? -14 : 14;
|
||||
tl.to(el, { y: amp, duration: half, ease: "sine.inOut" }, t0).to(el, { y: 0, duration: half, ease: "sine.inOut" }, t0 + half);
|
||||
});
|
||||
tl.fromTo(".f2-r0", { x: -260, opacity: 0, rotation: -12 }, { x: 0, opacity: 1, rotation: -3, duration: 0.6, ease: "back.out(1.5)" }, 0.38);
|
||||
tl.fromTo(".f2-r1", { x: 260, opacity: 0, rotation: 10 }, { x: 0, opacity: 1, rotation: 2.5, duration: 0.6, ease: "back.out(1.5)" }, 1.66);
|
||||
tl.fromTo(".f2-r2", { x: -260, opacity: 0, rotation: -8 }, { x: 0, opacity: 1, rotation: -2, duration: 0.6, ease: "back.out(1.5)" }, 3.09);
|
||||
window.__timelines["02-worry"] = tl;
|
||||
})();
|
||||
</script>
|
||||
</template>
|
||||
@@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<style>
|
||||
@font-face { font-family: "Fredoka"; src: url("assets/fonts/fredoka-600.woff2") format("woff2"); font-weight: 600; font-style: normal; }
|
||||
@font-face { font-family: "Quicksand"; src: url("assets/fonts/quicksand-var.woff2") format("woff2"); font-weight: 500 700; font-style: normal; }
|
||||
#root { position: absolute; inset: 0; overflow: hidden; color: #2D2D2D; font-family: "Quicksand", sans-serif; font-weight: 600; }
|
||||
.f3-bg { position: absolute; inset: 0; }
|
||||
.f3-orn { position: absolute; z-index: 1; }
|
||||
.f3-orn svg { width: 100%; height: 100%; display: block; overflow: visible; }
|
||||
.f3-z { position: absolute; z-index: 2; }
|
||||
.f3-d { font-family: "Fredoka", sans-serif; font-weight: 600; letter-spacing: 0.02em; line-height: 1.05; }
|
||||
.f3-card { background: #FFFFFF; border: 5px solid #2D2D2D; border-radius: 40px; box-shadow: 12px 12px 0 #2D2D2D; }
|
||||
.f3-pill { display: inline-flex; align-items: center; gap: 18px; border: 5px solid #2D2D2D; border-radius: 80px; box-shadow: 8px 8px 0 #2D2D2D; padding: 20px 46px; white-space: nowrap; }
|
||||
.f3-phone { position: absolute; z-index: 2; left: 260px; top: 230px; width: 560px; height: 1120px; background: #FFFFFF; border: 6px solid #2D2D2D; border-radius: 80px; box-shadow: 16px 16px 0 #2D2D2D; overflow: hidden; }
|
||||
.f3-notch { position: absolute; left: 50%; top: 22px; margin-left: -70px; width: 140px; height: 28px; border-radius: 20px; background: #2D2D2D; }
|
||||
|
||||
.f3-eye { display: block; position: relative; width: 128.8px; height: 128.8px; border-radius: 50%; background: #FFFFFF; border: 6.8999999999999995px solid #2D2D2D; box-sizing: border-box; text-shadow: none; }
|
||||
.f3-pup { position: absolute; left: 50%; top: 50%; width: 50.6px; height: 50.6px; margin: -25.3px 0 0 -25.3px; border-radius: 50%; background: #2D2D2D; }
|
||||
.f3-badge { left: 50%; top: 250px; margin-left: -330px; width: 660px; justify-content: center; background: #FDE68A; }
|
||||
.f3-badge span { font-size: 62px; }
|
||||
.f3-wmwrap { left: 0; right: 0; top: 700px; }
|
||||
.f3-shield { left: 50%; top: 380px; margin-left: -115px; width: 230px; height: 260px; }
|
||||
.f3-peace { left: 50%; top: 1130px; margin-left: -400px; width: 800px; height: 200px; display: flex; align-items: center; justify-content: center; gap: 36px; }
|
||||
.f3-peace span { font-size: 78px; }
|
||||
.f3-peace svg { width: 100px; height: 100px; }
|
||||
</style>
|
||||
<div id="root" data-composition-id="03-meet" data-width="1080" data-height="1920" data-duration="8.644">
|
||||
<div id="scene3-bg" class="clip f3-bg" data-start="0" data-duration="8.644" data-track-index="0" style="background:#7ECDC0"></div>
|
||||
<div class="f3-orn" style="left:790px;top:60px;width:280px;height:280px"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><line x1="50" y1="9" x2="50" y2="22" transform="rotate(0 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(30 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(60 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(90 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(120 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(150 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(180 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(210 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(240 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(270 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(300 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(330 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><circle cx="50" cy="50" r="24" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f3-orn" style="left:-80px;top:200px;width:330px;height:330px"><svg viewBox="0 0 100 100" style="transform:rotate(-3deg)" xmlns="http://www.w3.org/2000/svg"><path d="M24 72 a17 17 0 0 1 3-33 a22 22 0 0 1 43-3 a17 17 0 0 1 6 36 z" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f3-orn" style="left:-40px;top:1250px;width:260px;height:260px"><svg viewBox="0 0 100 100" style="transform:rotate(10deg)" xmlns="http://www.w3.org/2000/svg"><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(0 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(45 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(90 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(135 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(180 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(225 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(270 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(315 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><circle cx="50" cy="50" r="14" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f3-orn" style="left:820px;top:1330px;width:230px;height:230px"><svg viewBox="0 0 100 100" style="transform:rotate(-12deg)" xmlns="http://www.w3.org/2000/svg"><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(0 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(45 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(90 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(135 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(180 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(225 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(270 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(315 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><circle cx="50" cy="50" r="14" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f3-orn" style="left:130px;top:1010px;width:120px;height:120px"><svg viewBox="0 0 100 100" style="transform:rotate(8deg)" xmlns="http://www.w3.org/2000/svg"><polygon points="50,6 61,38 95,38 67,58 78,92 50,71 22,92 33,58 5,38 39,38" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f3-orn" style="left:830px;top:1020px;width:140px;height:140px"><svg viewBox="0 0 100 100" style="transform:rotate(-10deg)" xmlns="http://www.w3.org/2000/svg"><polygon points="50,6 61,38 95,38 67,58 78,92 50,71 22,92 33,58 5,38 39,38" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
|
||||
<div class="f3-z f3-pill f3-badge"><span class="f3-d">A BETTER WAY</span></div>
|
||||
<svg class="f3-z f3-shield" viewBox="0 0 100 112"><path d="M50 4 L92 18 V54 C92 82 70 100 50 108 C30 100 8 82 8 54 V18 Z" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="4.5" stroke-linejoin="round"/><path d="M30 56 L45 71 L72 40" fill="none" stroke="#F8635F" stroke-width="10" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
<div class="f3-z f3-wmwrap">
|
||||
<div class="f3-wm f3-d" style="display:flex;align-items:flex-end;justify-content:center;font-size:230px;color:#2D2D2D;text-shadow:8px 8px 0 #FFFFFF;line-height:1">
|
||||
<span>l</span>
|
||||
<span class="f3-eye" style="margin:0 6.8999999999999995px 13.799999999999999px 11.5px"><i class="f3-pup"></i></span>
|
||||
<span class="f3-eye" style="margin:0 11.5px 13.799999999999999px 6.8999999999999995px"><i class="f3-pup"></i></span>
|
||||
<span>katu</span>
|
||||
</div></div>
|
||||
<div class="f3-z f3-card f3-peace"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><path d="M50 86 C8 56 10 18 32 18 C42 18 48 25 50 32 C52 25 58 18 68 18 C90 18 92 56 50 86 Z" fill="#F8635F" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg><span class="f3-d">PEACE OF MIND</span></div>
|
||||
</div>
|
||||
<script>
|
||||
(function () {
|
||||
const DUR = 8.144;
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
|
||||
const orns = document.querySelectorAll(".f3-orn");
|
||||
tl.fromTo(orns, { scale: 0, opacity: 0 }, { scale: 1, opacity: 1, duration: 0.55, ease: "back.out(1.8)", stagger: 0.07 }, 0.05);
|
||||
orns.forEach((el, i) => {
|
||||
const t0 = 0.9 + i * 0.12, half = Math.max(1.2, (DUR - 1.6) / 2), amp = i % 2 ? -14 : 14;
|
||||
tl.to(el, { y: amp, duration: half, ease: "sine.inOut" }, t0).to(el, { y: 0, duration: half, ease: "sine.inOut" }, t0 + half);
|
||||
});
|
||||
|
||||
tl.fromTo(".f3-badge", { y: -80, opacity: 0, scale: 0.7 }, { y: 0, opacity: 1, scale: 1, duration: 0.55, ease: "back.out(1.8)" }, 0.38);
|
||||
tl.fromTo(".f3-shield", { scale: 0, rotation: -20, opacity: 0 }, { scale: 1, rotation: 0, opacity: 1, duration: 0.65, ease: "back.out(1.9)" }, 1.48);
|
||||
tl.fromTo(".f3-wm", { scale: 0.3, opacity: 0, y: 60 }, { scale: 1, opacity: 1, y: 0, duration: 0.75, ease: "back.out(1.6)" }, 2.38);
|
||||
|
||||
const pups = document.querySelectorAll(".f3-pup"), r = 23;
|
||||
tl.fromTo(pups, { x: 0, y: 0 }, { x: -r, y: -r * 0.4, duration: 0.35, ease: "power2.out" }, 2.9699999999999998)
|
||||
.to(pups, { x: r, y: r * 0.3, duration: 0.5, ease: "power2.inOut" }, 3.57)
|
||||
.to(pups, { x: 0, y: 0, duration: 0.35, ease: "power2.out" }, 4.32);
|
||||
tl.fromTo(".f3-peace", { y: 100, opacity: 0, rotation: -3 }, { y: 0, opacity: 1, rotation: 0, duration: 0.6, ease: "back.out(1.6)" }, 5.43);
|
||||
tl.to(".f3-peace svg", { scale: 1.2, duration: 0.3, ease: "sine.inOut" }, 6.13).to(".f3-peace svg", { scale: 1, duration: 0.3, ease: "sine.inOut" }, ">");
|
||||
window.__timelines["03-meet"] = tl;
|
||||
})();
|
||||
</script>
|
||||
</template>
|
||||
@@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<style>
|
||||
@font-face { font-family: "Fredoka"; src: url("assets/fonts/fredoka-600.woff2") format("woff2"); font-weight: 600; font-style: normal; }
|
||||
@font-face { font-family: "Quicksand"; src: url("assets/fonts/quicksand-var.woff2") format("woff2"); font-weight: 500 700; font-style: normal; }
|
||||
#root { position: absolute; inset: 0; overflow: hidden; color: #2D2D2D; font-family: "Quicksand", sans-serif; font-weight: 600; }
|
||||
.f4-bg { position: absolute; inset: 0; }
|
||||
.f4-orn { position: absolute; z-index: 1; }
|
||||
.f4-orn svg { width: 100%; height: 100%; display: block; overflow: visible; }
|
||||
.f4-z { position: absolute; z-index: 2; }
|
||||
.f4-d { font-family: "Fredoka", sans-serif; font-weight: 600; letter-spacing: 0.02em; line-height: 1.05; }
|
||||
.f4-card { background: #FFFFFF; border: 5px solid #2D2D2D; border-radius: 40px; box-shadow: 12px 12px 0 #2D2D2D; }
|
||||
.f4-pill { display: inline-flex; align-items: center; gap: 18px; border: 5px solid #2D2D2D; border-radius: 80px; box-shadow: 8px 8px 0 #2D2D2D; padding: 20px 46px; white-space: nowrap; }
|
||||
.f4-phone { position: absolute; z-index: 2; left: 260px; top: 230px; width: 560px; height: 1120px; background: #FFFFFF; border: 6px solid #2D2D2D; border-radius: 80px; box-shadow: 16px 16px 0 #2D2D2D; overflow: hidden; }
|
||||
.f4-notch { position: absolute; left: 50%; top: 22px; margin-left: -70px; width: 140px; height: 28px; border-radius: 20px; background: #2D2D2D; }
|
||||
|
||||
.f4-label { position: absolute; left: 0; right: 0; top: 130px; text-align: center; }
|
||||
.f4-label .f4-pill { background: #FDE68A; padding: 14px 44px; } .f4-label span { font-size: 56px; }
|
||||
.f4-ringbox { position: absolute; left: 90px; top: 250px; width: 380px; height: 380px; }
|
||||
.f4-ringbox svg { position: absolute; inset: 0; width: 100%; height: 100%; }
|
||||
.f4-time { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 104px; }
|
||||
.f4-lock { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; }
|
||||
.f4-lock svg { position: static; width: 170px; height: 170px; }
|
||||
.f4-state { position: absolute; left: 50px; top: 740px; width: 460px; text-align: center; }
|
||||
.f4-state .f4-pill { padding: 14px 0; width: 100%; justify-content: center; box-shadow: 6px 6px 0 #2D2D2D; } .f4-state span { font-size: 56px; }
|
||||
.f4-s2 { position: absolute; left: 0; top: 0; background: #F8635F; color: #FFFFFF; opacity: 0; }
|
||||
.f4-bar { position: absolute; left: 70px; top: 930px; width: 420px; height: 26px; border: 4px solid #2D2D2D; border-radius: 20px; background: #F5F0E6; overflow: hidden; }
|
||||
.f4-bar i { display: block; height: 100%; width: 100%; background: #A8E6CF; transform-origin: left center; }
|
||||
</style>
|
||||
<div id="root" data-composition-id="04-limits" data-width="1080" data-height="1920" data-duration="7.099">
|
||||
<div id="scene4-bg" class="clip f4-bg" data-start="0" data-duration="7.099" data-track-index="0" style="background:#F5F0E6"></div>
|
||||
<div class="f4-orn" style="left:-70px;top:120px;width:240px;height:240px"><svg viewBox="0 0 100 100" style="transform:rotate(5deg)" xmlns="http://www.w3.org/2000/svg"><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(0 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(45 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(90 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(135 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(180 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(225 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(270 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(315 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><circle cx="50" cy="50" r="14" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f4-orn" style="left:840px;top:90px;width:230px;height:230px"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><line x1="50" y1="9" x2="50" y2="22" transform="rotate(0 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(30 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(60 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(90 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(120 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(150 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(180 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(210 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(240 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(270 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(300 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(330 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><circle cx="50" cy="50" r="24" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f4-orn" style="left:30px;top:1050px;width:140px;height:140px"><svg viewBox="0 0 100 100" style="transform:rotate(-8deg)" xmlns="http://www.w3.org/2000/svg"><polygon points="50,6 61,38 95,38 67,58 78,92 50,71 22,92 33,58 5,38 39,38" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f4-orn" style="left:770px;top:1180px;width:300px;height:300px"><svg viewBox="0 0 100 100" style="transform:rotate(4deg)" xmlns="http://www.w3.org/2000/svg"><path d="M24 72 a17 17 0 0 1 3-33 a22 22 0 0 1 43-3 a17 17 0 0 1 6 36 z" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f4-orn" style="left:40px;top:1400px;width:190px;height:190px"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(0 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(45 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(90 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(135 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(180 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(225 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(270 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(315 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><circle cx="50" cy="50" r="14" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
|
||||
<div class="f4-label f4-z"><span class="f4-pill"><span class="f4-d">SCREEN TIME</span></span></div>
|
||||
<div class="f4-phone">
|
||||
<div class="f4-notch"></div>
|
||||
<div class="f4-ringbox">
|
||||
<svg viewBox="0 0 380 380"><circle cx="190" cy="190" r="150" fill="none" stroke="#E8E0D4" stroke-width="40"/><circle class="f4-arc" cx="190" cy="190" r="150" fill="none" stroke="#7ECDC0" stroke-width="40" stroke-linecap="round" stroke-dasharray="942.5" stroke-dashoffset="0" transform="rotate(-90 190 190)"/></svg>
|
||||
<div class="f4-time f4-d">1:00</div>
|
||||
<div class="f4-lock"><svg viewBox="0 0 100 100"><rect x="20" y="42" width="60" height="46" rx="10" fill="#F8635F" stroke="#2D2D2D" stroke-width="5"/><path d="M33 42 V30 a17 17 0 0 1 34 0 V42" fill="none" stroke="#2D2D2D" stroke-width="6" stroke-linecap="round"/><circle cx="50" cy="65" r="6" fill="#2D2D2D"/></svg></div>
|
||||
</div>
|
||||
<div class="f4-state"><div class="f4-pill f4-s1" style="background:#A8E6CF"><span class="f4-d">LIMIT SET</span></div><div class="f4-pill f4-s2"><span class="f4-d">TIME'S UP</span></div></div>
|
||||
<div class="f4-bar"><i></i></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
(function () {
|
||||
const DUR = 6.599;
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
|
||||
const orns = document.querySelectorAll(".f4-orn");
|
||||
tl.fromTo(orns, { scale: 0, opacity: 0 }, { scale: 1, opacity: 1, duration: 0.55, ease: "back.out(1.8)", stagger: 0.07 }, 0.05);
|
||||
orns.forEach((el, i) => {
|
||||
const t0 = 0.9 + i * 0.12, half = Math.max(1.2, (DUR - 1.6) / 2), amp = i % 2 ? -14 : 14;
|
||||
tl.to(el, { y: amp, duration: half, ease: "sine.inOut" }, t0).to(el, { y: 0, duration: half, ease: "sine.inOut" }, t0 + half);
|
||||
});
|
||||
|
||||
const t0 = 0.38, tEnd = 3.79;
|
||||
tl.fromTo(".f4-label", { y: -60, opacity: 0 }, { y: 0, opacity: 1, duration: 0.5, ease: "back.out(1.6)" }, t0);
|
||||
tl.fromTo(".f4-phone", { y: 160, opacity: 0, rotation: 4 }, { y: 0, opacity: 1, rotation: 0, duration: 0.7, ease: "power3.out" }, t0);
|
||||
tl.set(".f4-lock", { opacity: 0 }, 0);
|
||||
tl.fromTo(".f4-state", { scale: 0.6, opacity: 0 }, { scale: 1, opacity: 1, duration: 0.45, ease: "back.out(1.8)" }, 0.61);
|
||||
tl.to(".f4-arc", { strokeDashoffset: 942.5, duration: tEnd - 0.99, ease: "none" }, 0.99);
|
||||
tl.to(".f4-bar i", { scaleX: 0, duration: tEnd - 0.99, ease: "none" }, 0.99);
|
||||
const cd = { v: 60 }, tm = document.querySelector(".f4-time");
|
||||
tl.to(cd, { v: 0, duration: tEnd - 0.99, ease: "none", onUpdate: () => { const s = Math.ceil(cd.v); tm.textContent = Math.floor(s / 60) + ":" + String(s % 60).padStart(2, "0"); } }, 0.99);
|
||||
tl.to(".f4-time", { opacity: 0, duration: 0.2 }, tEnd);
|
||||
tl.to(".f4-arc", { opacity: 0, duration: 0.1 }, tEnd - 0.05);
|
||||
tl.fromTo(".f4-lock", { opacity: 0, scale: 0.3, rotation: -25 }, { opacity: 1, scale: 1, rotation: 0, duration: 0.55, ease: "back.out(2)" }, tEnd);
|
||||
tl.to(".f4-s1", { opacity: 0, duration: 0.15 }, tEnd).to(".f4-s2", { opacity: 1, duration: 0.2 }, tEnd);
|
||||
tl.to(".f4-phone", { rotation: -2, duration: 0.12, ease: "sine.inOut" }, tEnd + 0.1).to(".f4-phone", { rotation: 2, duration: 0.16, ease: "sine.inOut" }, ">").to(".f4-phone", { rotation: 0, duration: 0.14, ease: "sine.inOut" }, ">");
|
||||
window.__timelines["04-limits"] = tl;
|
||||
})();
|
||||
</script>
|
||||
</template>
|
||||
@@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<style>
|
||||
@font-face { font-family: "Fredoka"; src: url("assets/fonts/fredoka-600.woff2") format("woff2"); font-weight: 600; font-style: normal; }
|
||||
@font-face { font-family: "Quicksand"; src: url("assets/fonts/quicksand-var.woff2") format("woff2"); font-weight: 500 700; font-style: normal; }
|
||||
#root { position: absolute; inset: 0; overflow: hidden; color: #2D2D2D; font-family: "Quicksand", sans-serif; font-weight: 600; }
|
||||
.f5-bg { position: absolute; inset: 0; }
|
||||
.f5-orn { position: absolute; z-index: 1; }
|
||||
.f5-orn svg { width: 100%; height: 100%; display: block; overflow: visible; }
|
||||
.f5-z { position: absolute; z-index: 2; }
|
||||
.f5-d { font-family: "Fredoka", sans-serif; font-weight: 600; letter-spacing: 0.02em; line-height: 1.05; }
|
||||
.f5-card { background: #FFFFFF; border: 5px solid #2D2D2D; border-radius: 40px; box-shadow: 12px 12px 0 #2D2D2D; }
|
||||
.f5-pill { display: inline-flex; align-items: center; gap: 18px; border: 5px solid #2D2D2D; border-radius: 80px; box-shadow: 8px 8px 0 #2D2D2D; padding: 20px 46px; white-space: nowrap; }
|
||||
.f5-phone { position: absolute; z-index: 2; left: 260px; top: 230px; width: 560px; height: 1120px; background: #FFFFFF; border: 6px solid #2D2D2D; border-radius: 80px; box-shadow: 16px 16px 0 #2D2D2D; overflow: hidden; }
|
||||
.f5-notch { position: absolute; left: 50%; top: 22px; margin-left: -70px; width: 140px; height: 28px; border-radius: 20px; background: #2D2D2D; }
|
||||
|
||||
.f5-row { position: absolute; left: 36px; width: 488px; height: 170px; display: flex; align-items: center; gap: 22px; padding: 0 24px; background: #FFFFFF; border: 4px solid #2D2D2D; border-radius: 34px; box-shadow: 6px 6px 0 #2D2D2D; }
|
||||
.f5-ic { flex: none; width: 92px; height: 92px; border-radius: 50%; border: 4px solid #2D2D2D; display: flex; align-items: center; justify-content: center; font-size: 52px; }
|
||||
.f5-nm { font-size: 46px; flex: 1; }
|
||||
.f5-tg { flex: none; position: relative; width: 120px; height: 66px; border-radius: 40px; border: 4px solid #2D2D2D; background: #D9D4C7; }
|
||||
.f5-kn { position: absolute; left: 4px; top: 4px; width: 50px; height: 50px; border-radius: 50%; background: #FFFFFF; border: 4px solid #2D2D2D; box-sizing: border-box; width: 50px; }
|
||||
.f5-blk { position: absolute; right: -12px; top: -22px; background: #F8635F; color: #FFFFFF; border: 4px solid #2D2D2D; border-radius: 30px; padding: 4px 16px; font-size: 30px; opacity: 0; }
|
||||
.f5-head { position: absolute; left: 0; right: 0; top: 80px; text-align: center; font-size: 56px; }
|
||||
</style>
|
||||
<div id="root" data-composition-id="05-apps" data-width="1080" data-height="1920" data-duration="6.203">
|
||||
<div id="scene5-bg" class="clip f5-bg" data-start="0" data-duration="6.203" data-track-index="0" style="background:#A8D8F0"></div>
|
||||
<div class="f5-orn" style="left:-90px;top:90px;width:320px;height:320px"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><path d="M24 72 a17 17 0 0 1 3-33 a22 22 0 0 1 43-3 a17 17 0 0 1 6 36 z" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f5-orn" style="left:880px;top:150px;width:170px;height:170px"><svg viewBox="0 0 100 100" style="transform:rotate(14deg)" xmlns="http://www.w3.org/2000/svg"><polygon points="50,6 61,38 95,38 67,58 78,92 50,71 22,92 33,58 5,38 39,38" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f5-orn" style="left:-50px;top:1180px;width:250px;height:250px"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(0 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(45 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(90 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(135 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(180 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(225 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(270 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(315 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><circle cx="50" cy="50" r="14" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f5-orn" style="left:800px;top:1250px;width:260px;height:260px"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><line x1="50" y1="9" x2="50" y2="22" transform="rotate(0 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(30 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(60 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(90 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(120 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(150 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(180 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(210 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(240 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(270 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(300 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(330 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><circle cx="50" cy="50" r="24" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f5-orn" style="left:900px;top:760px;width:110px;height:110px"><svg viewBox="0 0 100 100" style="transform:rotate(-12deg)" xmlns="http://www.w3.org/2000/svg"><polygon points="50,6 61,38 95,38 67,58 78,92 50,71 22,92 33,58 5,38 39,38" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
|
||||
<div class="f5-phone">
|
||||
<div class="f5-notch"></div>
|
||||
<div class="f5-head f5-d">APPS</div>
|
||||
<div class="f5-row f5-r0" style="top:190px"><div class="f5-ic f5-d" style="background:#A8E6CF">L</div><div class="f5-nm f5-d">Learn</div><div class="f5-tg f5-t0"><div class="f5-kn f5-k0"></div></div></div>
|
||||
<div class="f5-row f5-r1" style="top:400px"><div class="f5-ic f5-d" style="background:#A8D8F0">D</div><div class="f5-nm f5-d">Draw</div><div class="f5-tg f5-t1"><div class="f5-kn f5-k1"></div></div></div>
|
||||
<div class="f5-row f5-r2" style="top:610px"><div class="f5-ic f5-d" style="background:#FFCBA4">G</div><div class="f5-nm f5-d">Games</div><div class="f5-tg f5-t2"><div class="f5-kn f5-k2"></div></div><div class="f5-blk f5-d f5-bl2">BLOCKED</div></div>
|
||||
<div class="f5-row f5-r3" style="top:820px"><div class="f5-ic f5-d" style="background:#D4A5E8">V</div><div class="f5-nm f5-d">Videos</div><div class="f5-tg f5-t3"><div class="f5-kn f5-k3"></div></div><div class="f5-blk f5-d f5-bl3">BLOCKED</div></div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
(function () {
|
||||
const DUR = 5.703;
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
|
||||
const orns = document.querySelectorAll(".f5-orn");
|
||||
tl.fromTo(orns, { scale: 0, opacity: 0 }, { scale: 1, opacity: 1, duration: 0.55, ease: "back.out(1.8)", stagger: 0.07 }, 0.05);
|
||||
orns.forEach((el, i) => {
|
||||
const t0 = 0.9 + i * 0.12, half = Math.max(1.2, (DUR - 1.6) / 2), amp = i % 2 ? -14 : 14;
|
||||
tl.to(el, { y: amp, duration: half, ease: "sine.inOut" }, t0).to(el, { y: 0, duration: half, ease: "sine.inOut" }, t0 + half);
|
||||
});
|
||||
|
||||
tl.fromTo(".f5-phone", { y: 160, opacity: 0, rotation: -4 }, { y: 0, opacity: 1, rotation: 0, duration: 0.7, ease: "power3.out" }, 0.38);
|
||||
tl.fromTo(".f5-r0", { x: 90, opacity: 0 }, { x: 0, opacity: 1, duration: 0.45, ease: "power3.out" }, 0.88);
|
||||
tl.fromTo(".f5-r1", { x: 90, opacity: 0 }, { x: 0, opacity: 1, duration: 0.45, ease: "power3.out" }, 1.16);
|
||||
tl.fromTo(".f5-r2", { x: 90, opacity: 0 }, { x: 0, opacity: 1, duration: 0.45, ease: "power3.out" }, 1.44);
|
||||
tl.fromTo(".f5-r3", { x: 90, opacity: 0 }, { x: 0, opacity: 1, duration: 0.45, ease: "power3.out" }, 1.72);
|
||||
tl.to(".f5-k0", { x: 54, duration: 0.3, ease: "back.out(1.7)" }, 2.12).to(".f5-t0", { backgroundColor: "#A8E6CF", duration: 0.3 }, 2.12);
|
||||
tl.to(".f5-k1", { x: 54, duration: 0.3, ease: "back.out(1.7)" }, 2.57).to(".f5-t1", { backgroundColor: "#A8E6CF", duration: 0.3 }, 2.57);
|
||||
tl.to(".f5-r2", { opacity: 0.55, duration: 0.3 }, 3.49).fromTo(".f5-bl2", { opacity: 0, scale: 0.3, rotation: -10 }, { opacity: 1, scale: 1, rotation: -4, duration: 0.4, ease: "back.out(2)" }, 3.49);
|
||||
tl.to(".f5-r3", { opacity: 0.55, duration: 0.3 }, 3.79).fromTo(".f5-bl3", { opacity: 0, scale: 0.3, rotation: -10 }, { opacity: 1, scale: 1, rotation: -4, duration: 0.4, ease: "back.out(2)" }, 3.79);
|
||||
window.__timelines["05-apps"] = tl;
|
||||
})();
|
||||
</script>
|
||||
</template>
|
||||
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<style>
|
||||
@font-face { font-family: "Fredoka"; src: url("assets/fonts/fredoka-600.woff2") format("woff2"); font-weight: 600; font-style: normal; }
|
||||
@font-face { font-family: "Quicksand"; src: url("assets/fonts/quicksand-var.woff2") format("woff2"); font-weight: 500 700; font-style: normal; }
|
||||
#root { position: absolute; inset: 0; overflow: hidden; color: #2D2D2D; font-family: "Quicksand", sans-serif; font-weight: 600; }
|
||||
.f6-bg { position: absolute; inset: 0; }
|
||||
.f6-orn { position: absolute; z-index: 1; }
|
||||
.f6-orn svg { width: 100%; height: 100%; display: block; overflow: visible; }
|
||||
.f6-z { position: absolute; z-index: 2; }
|
||||
.f6-d { font-family: "Fredoka", sans-serif; font-weight: 600; letter-spacing: 0.02em; line-height: 1.05; }
|
||||
.f6-card { background: #FFFFFF; border: 5px solid #2D2D2D; border-radius: 40px; box-shadow: 12px 12px 0 #2D2D2D; }
|
||||
.f6-pill { display: inline-flex; align-items: center; gap: 18px; border: 5px solid #2D2D2D; border-radius: 80px; box-shadow: 8px 8px 0 #2D2D2D; padding: 20px 46px; white-space: nowrap; }
|
||||
.f6-phone { position: absolute; z-index: 2; left: 260px; top: 230px; width: 560px; height: 1120px; background: #FFFFFF; border: 6px solid #2D2D2D; border-radius: 80px; box-shadow: 16px 16px 0 #2D2D2D; overflow: hidden; }
|
||||
.f6-notch { position: absolute; left: 50%; top: 22px; margin-left: -70px; width: 140px; height: 28px; border-radius: 20px; background: #2D2D2D; }
|
||||
|
||||
.f6-btn { position: absolute; left: 70px; top: 100px; width: 420px; justify-content: center; padding: 18px 0; background: #7ECDC0; box-shadow: 6px 6px 0 #2D2D2D; }
|
||||
.f6-btn span { font-size: 50px; }
|
||||
.f6-map { position: absolute; left: 36px; top: 260px; width: 488px; height: 780px; border: 5px solid #2D2D2D; border-radius: 40px; background: #A8E6CF; overflow: hidden; }
|
||||
.f6-map svg { position: absolute; inset: 0; width: 100%; height: 100%; }
|
||||
.f6-pin { position: absolute; left: 244px; top: 360px; width: 120px; margin-left: -60px; height: 150px; margin-top: -150px; }
|
||||
.f6-pin svg { width: 100%; height: 100%; }
|
||||
.f6-pulse { position: absolute; left: 244px; top: 360px; width: 200px; height: 200px; margin: -100px 0 0 -100px; border: 6px solid #F8635F; border-radius: 50%; opacity: 0; }
|
||||
.f6-note { left: 0; right: 0; top: 1430px; text-align: center; }
|
||||
.f6-note .f6-pill { background: #FDE68A; } .f6-note span { font-size: 62px; }
|
||||
</style>
|
||||
<div id="root" data-composition-id="06-location" data-width="1080" data-height="1920" data-duration="7.013">
|
||||
<div id="scene6-bg" class="clip f6-bg" data-start="0" data-duration="7.013" data-track-index="0" style="background:#FFCBA4"></div>
|
||||
<div class="f6-orn" style="left:-80px;top:90px;width:280px;height:280px"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><line x1="50" y1="9" x2="50" y2="22" transform="rotate(0 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(30 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(60 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(90 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(120 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(150 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(180 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(210 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(240 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(270 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(300 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(330 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><circle cx="50" cy="50" r="24" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f6-orn" style="left:890px;top:120px;width:150px;height:150px"><svg viewBox="0 0 100 100" style="transform:rotate(10deg)" xmlns="http://www.w3.org/2000/svg"><polygon points="50,6 61,38 95,38 67,58 78,92 50,71 22,92 33,58 5,38 39,38" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f6-orn" style="left:880px;top:1230px;width:220px;height:220px"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(0 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(45 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(90 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(135 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(180 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(225 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(270 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(315 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><circle cx="50" cy="50" r="14" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f6-orn" style="left:-90px;top:1180px;width:300px;height:300px"><svg viewBox="0 0 100 100" style="transform:rotate(4deg)" xmlns="http://www.w3.org/2000/svg"><path d="M24 72 a17 17 0 0 1 3-33 a22 22 0 0 1 43-3 a17 17 0 0 1 6 36 z" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f6-orn" style="left:40px;top:700px;width:100px;height:100px"><svg viewBox="0 0 100 100" style="transform:rotate(-12deg)" xmlns="http://www.w3.org/2000/svg"><polygon points="50,6 61,38 95,38 67,58 78,92 50,71 22,92 33,58 5,38 39,38" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
|
||||
<div class="f6-phone">
|
||||
<div class="f6-notch"></div>
|
||||
<div class="f6-pill f6-d f6-btn"><span class="f6-d">CHECK NOW</span></div>
|
||||
<div class="f6-map">
|
||||
<svg viewBox="0 0 488 780">
|
||||
<rect x="300" y="0" width="188" height="780" fill="#A8D8F0"/>
|
||||
<rect x="30" y="40" width="190" height="150" rx="26" fill="#8ADBB6" stroke="#2D2D2D" stroke-width="3"/>
|
||||
<rect x="30" y="520" width="230" height="200" rx="26" fill="#8ADBB6" stroke="#2D2D2D" stroke-width="3"/>
|
||||
<path d="M0 250 H488 M150 0 V780 M0 470 H300 M360 60 L120 780" fill="none" stroke="#FFFFFF" stroke-width="22" stroke-linecap="round"/>
|
||||
<path d="M0 250 H488 M150 0 V780 M0 470 H300 M360 60 L120 780" fill="none" stroke="#E8E0D4" stroke-width="3" stroke-dasharray="14 18"/>
|
||||
</svg>
|
||||
<div class="f6-pulse f6-pu1"></div><div class="f6-pulse f6-pu2"></div>
|
||||
<div class="f6-pin"><svg viewBox="0 0 100 125"><path d="M50 118 C14 74 12 54 12 42 a38 38 0 0 1 76 0 C88 54 86 74 50 118 Z" fill="#F8635F" stroke="#2D2D2D" stroke-width="5" stroke-linejoin="round"/><circle cx="50" cy="42" r="14" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="5"/></svg></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="f6-z f6-note"><span class="f6-pill"><span class="f6-d">ONLY WHEN NEEDED</span></span></div>
|
||||
</div>
|
||||
<script>
|
||||
(function () {
|
||||
const DUR = 6.513;
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
|
||||
const orns = document.querySelectorAll(".f6-orn");
|
||||
tl.fromTo(orns, { scale: 0, opacity: 0 }, { scale: 1, opacity: 1, duration: 0.55, ease: "back.out(1.8)", stagger: 0.07 }, 0.05);
|
||||
orns.forEach((el, i) => {
|
||||
const t0 = 0.9 + i * 0.12, half = Math.max(1.2, (DUR - 1.6) / 2), amp = i % 2 ? -14 : 14;
|
||||
tl.to(el, { y: amp, duration: half, ease: "sine.inOut" }, t0).to(el, { y: 0, duration: half, ease: "sine.inOut" }, t0 + half);
|
||||
});
|
||||
|
||||
tl.fromTo(".f6-phone", { y: 160, opacity: 0, rotation: 4 }, { y: 0, opacity: 1, rotation: 0, duration: 0.7, ease: "power3.out" }, 0.38);
|
||||
tl.fromTo(".f6-map", { opacity: 0, scale: 0.9 }, { opacity: 1, scale: 1, duration: 0.5, ease: "power3.out" }, 0.61);
|
||||
tl.set(".f6-pin", { opacity: 0 }, 0);
|
||||
tl.to(".f6-btn", { scale: 0.9, duration: 0.12, ease: "power2.in" }, 1.8).to(".f6-btn", { scale: 1, duration: 0.25, ease: "back.out(2.5)" }, ">");
|
||||
tl.fromTo(".f6-pin", { y: -520, opacity: 1, scaleY: 1.1 }, { y: 0, opacity: 1, scaleY: 1, duration: 0.7, ease: "bounce.out" }, 2.2);
|
||||
tl.fromTo(".f6-pu1", { scale: 0.3, opacity: 0.9 }, { scale: 2.6, opacity: 0, duration: 1.1, ease: "power2.out" }, 2.95);
|
||||
tl.fromTo(".f6-pu2", { scale: 0.3, opacity: 0.9 }, { scale: 2.6, opacity: 0, duration: 1.1, ease: "power2.out" }, 3.45);
|
||||
tl.fromTo(".f6-note", { y: 80, opacity: 0, scale: 0.8 }, { y: 0, opacity: 1, scale: 1, duration: 0.55, ease: "back.out(1.8)" }, 3.89);
|
||||
window.__timelines["06-location"] = tl;
|
||||
})();
|
||||
</script>
|
||||
</template>
|
||||
@@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<style>
|
||||
@font-face { font-family: "Fredoka"; src: url("assets/fonts/fredoka-600.woff2") format("woff2"); font-weight: 600; font-style: normal; }
|
||||
@font-face { font-family: "Quicksand"; src: url("assets/fonts/quicksand-var.woff2") format("woff2"); font-weight: 500 700; font-style: normal; }
|
||||
#root { position: absolute; inset: 0; overflow: hidden; color: #2D2D2D; font-family: "Quicksand", sans-serif; font-weight: 600; }
|
||||
.f7-bg { position: absolute; inset: 0; }
|
||||
.f7-orn { position: absolute; z-index: 1; }
|
||||
.f7-orn svg { width: 100%; height: 100%; display: block; overflow: visible; }
|
||||
.f7-z { position: absolute; z-index: 2; }
|
||||
.f7-d { font-family: "Fredoka", sans-serif; font-weight: 600; letter-spacing: 0.02em; line-height: 1.05; }
|
||||
.f7-card { background: #FFFFFF; border: 5px solid #2D2D2D; border-radius: 40px; box-shadow: 12px 12px 0 #2D2D2D; }
|
||||
.f7-pill { display: inline-flex; align-items: center; gap: 18px; border: 5px solid #2D2D2D; border-radius: 80px; box-shadow: 8px 8px 0 #2D2D2D; padding: 20px 46px; white-space: nowrap; }
|
||||
.f7-phone { position: absolute; z-index: 2; left: 260px; top: 230px; width: 560px; height: 1120px; background: #FFFFFF; border: 6px solid #2D2D2D; border-radius: 80px; box-shadow: 16px 16px 0 #2D2D2D; overflow: hidden; }
|
||||
.f7-notch { position: absolute; left: 50%; top: 22px; margin-left: -70px; width: 140px; height: 28px; border-radius: 20px; background: #2D2D2D; }
|
||||
|
||||
.f7-big { position: absolute; z-index: 2; left: 110px; width: 860px; height: 400px; display: flex; align-items: center; justify-content: center; gap: 30px; }
|
||||
.f7-big span { font-size: 138px; }
|
||||
.f7-big svg { width: 120px; height: 120px; flex: none; }
|
||||
.f7-heart { position: absolute; z-index: 3; left: 50%; top: 720px; margin-left: -110px; width: 220px; height: 220px; }
|
||||
.f7-heart svg { width: 100%; height: 100%; }
|
||||
</style>
|
||||
<div id="root" data-composition-id="07-balance" data-width="1080" data-height="1920" data-duration="5.968">
|
||||
<div id="scene7-bg" class="clip f7-bg" data-start="0" data-duration="5.968" data-track-index="0" style="background:#F7C8D4"></div>
|
||||
<div class="f7-orn" style="left:-60px;top:100px;width:240px;height:240px"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(0 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(45 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(90 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(135 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(180 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(225 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(270 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(315 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><circle cx="50" cy="50" r="14" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f7-orn" style="left:880px;top:120px;width:160px;height:160px"><svg viewBox="0 0 100 100" style="transform:rotate(12deg)" xmlns="http://www.w3.org/2000/svg"><polygon points="50,6 61,38 95,38 67,58 78,92 50,71 22,92 33,58 5,38 39,38" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f7-orn" style="left:800px;top:1230px;width:280px;height:280px"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><path d="M24 72 a17 17 0 0 1 3-33 a22 22 0 0 1 43-3 a17 17 0 0 1 6 36 z" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f7-orn" style="left:-80px;top:1210px;width:260px;height:260px"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><line x1="50" y1="9" x2="50" y2="22" transform="rotate(0 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(30 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(60 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(90 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(120 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(150 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(180 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(210 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(240 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(270 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(300 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(330 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><circle cx="50" cy="50" r="24" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f7-orn" style="left:60px;top:760px;width:110px;height:110px"><svg viewBox="0 0 100 100" style="transform:rotate(-10deg)" xmlns="http://www.w3.org/2000/svg"><polygon points="50,6 61,38 95,38 67,58 78,92 50,71 22,92 33,58 5,38 39,38" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
|
||||
<div class="f7-big f7-card f7-c1" style="top:240px;background:#A8D8F0"><svg viewBox="0 0 100 100" style="transform:rotate(8deg)" xmlns="http://www.w3.org/2000/svg"><polygon points="50,6 61,38 95,38 67,58 78,92 50,71 22,92 33,58 5,38 39,38" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg><span class="f7-d">FREEDOM</span></div>
|
||||
<div class="f7-heart f7-h"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><path d="M50 86 C8 56 10 18 32 18 C42 18 48 25 50 32 C52 25 58 18 68 18 C90 18 92 56 50 86 Z" fill="#F8635F" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f7-big f7-card f7-c2" style="top:1000px;background:#A8E6CF"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><line x1="50" y1="9" x2="50" y2="22" transform="rotate(0 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(30 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(60 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(90 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(120 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(150 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(180 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(210 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(240 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(270 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(300 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(330 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><circle cx="50" cy="50" r="24" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg><span class="f7-d">CALM</span></div>
|
||||
</div>
|
||||
<script>
|
||||
(function () {
|
||||
const DUR = 5.468;
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
|
||||
const orns = document.querySelectorAll(".f7-orn");
|
||||
tl.fromTo(orns, { scale: 0, opacity: 0 }, { scale: 1, opacity: 1, duration: 0.55, ease: "back.out(1.8)", stagger: 0.07 }, 0.05);
|
||||
orns.forEach((el, i) => {
|
||||
const t0 = 0.9 + i * 0.12, half = Math.max(1.2, (DUR - 1.6) / 2), amp = i % 2 ? -14 : 14;
|
||||
tl.to(el, { y: amp, duration: half, ease: "sine.inOut" }, t0).to(el, { y: 0, duration: half, ease: "sine.inOut" }, t0 + half);
|
||||
});
|
||||
|
||||
tl.fromTo(".f7-c1", { x: -300, opacity: 0, rotation: -10 }, { x: 0, opacity: 1, rotation: -2, duration: 0.65, ease: "back.out(1.5)" }, 0.81);
|
||||
tl.fromTo(".f7-c2", { x: 300, opacity: 0, rotation: 10 }, { x: 0, opacity: 1, rotation: 2, duration: 0.65, ease: "back.out(1.5)" }, 2.63);
|
||||
tl.fromTo(".f7-h", { scale: 0, opacity: 0, rotation: -30 }, { scale: 1, opacity: 1, rotation: 0, duration: 0.7, ease: "back.out(2.2)" }, 3.49);
|
||||
tl.to(".f7-h", { scale: 1.18, duration: 0.3, ease: "sine.inOut" }, 4.29).to(".f7-h", { scale: 1, duration: 0.3, ease: "sine.inOut" }, ">");
|
||||
window.__timelines["07-balance"] = tl;
|
||||
})();
|
||||
</script>
|
||||
</template>
|
||||
@@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<style>
|
||||
@font-face { font-family: "Fredoka"; src: url("assets/fonts/fredoka-600.woff2") format("woff2"); font-weight: 600; font-style: normal; }
|
||||
@font-face { font-family: "Quicksand"; src: url("assets/fonts/quicksand-var.woff2") format("woff2"); font-weight: 500 700; font-style: normal; }
|
||||
#root { position: absolute; inset: 0; overflow: hidden; color: #2D2D2D; font-family: "Quicksand", sans-serif; font-weight: 600; }
|
||||
.f8-bg { position: absolute; inset: 0; }
|
||||
.f8-orn { position: absolute; z-index: 1; }
|
||||
.f8-orn svg { width: 100%; height: 100%; display: block; overflow: visible; }
|
||||
.f8-z { position: absolute; z-index: 2; }
|
||||
.f8-d { font-family: "Fredoka", sans-serif; font-weight: 600; letter-spacing: 0.02em; line-height: 1.05; }
|
||||
.f8-card { background: #FFFFFF; border: 5px solid #2D2D2D; border-radius: 40px; box-shadow: 12px 12px 0 #2D2D2D; }
|
||||
.f8-pill { display: inline-flex; align-items: center; gap: 18px; border: 5px solid #2D2D2D; border-radius: 80px; box-shadow: 8px 8px 0 #2D2D2D; padding: 20px 46px; white-space: nowrap; }
|
||||
.f8-phone { position: absolute; z-index: 2; left: 260px; top: 230px; width: 560px; height: 1120px; background: #FFFFFF; border: 6px solid #2D2D2D; border-radius: 80px; box-shadow: 16px 16px 0 #2D2D2D; overflow: hidden; }
|
||||
.f8-notch { position: absolute; left: 50%; top: 22px; margin-left: -70px; width: 140px; height: 28px; border-radius: 20px; background: #2D2D2D; }
|
||||
|
||||
.f8-big { position: absolute; z-index: 2; left: 110px; width: 860px; height: 400px; display: flex; align-items: center; justify-content: center; gap: 36px; }
|
||||
.f8-big span { font-size: 124px; }
|
||||
</style>
|
||||
<div id="root" data-composition-id="08-platforms" data-width="1080" data-height="1920" data-duration="4.183">
|
||||
<div id="scene8-bg" class="clip f8-bg" data-start="0" data-duration="4.183" data-track-index="0" style="background:#FDE68A"></div>
|
||||
<div class="f8-orn" style="left:800px;top:90px;width:250px;height:250px"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><line x1="50" y1="9" x2="50" y2="22" transform="rotate(0 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(30 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(60 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(90 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(120 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(150 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(180 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(210 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(240 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(270 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(300 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(330 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><circle cx="50" cy="50" r="24" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f8-orn" style="left:-60px;top:130px;width:230px;height:230px"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(0 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(45 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(90 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(135 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(180 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(225 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(270 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(315 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><circle cx="50" cy="50" r="14" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f8-orn" style="left:-70px;top:1230px;width:290px;height:290px"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><path d="M24 72 a17 17 0 0 1 3-33 a22 22 0 0 1 43-3 a17 17 0 0 1 6 36 z" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f8-orn" style="left:880px;top:1300px;width:150px;height:150px"><svg viewBox="0 0 100 100" style="transform:rotate(12deg)" xmlns="http://www.w3.org/2000/svg"><polygon points="50,6 61,38 95,38 67,58 78,92 50,71 22,92 33,58 5,38 39,38" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f8-orn" style="left:520px;top:1440px;width:100px;height:100px"><svg viewBox="0 0 100 100" style="transform:rotate(-8deg)" xmlns="http://www.w3.org/2000/svg"><polygon points="50,6 61,38 95,38 67,58 78,92 50,71 22,92 33,58 5,38 39,38" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
|
||||
<div class="f8-big f8-card f8-c1" style="top:290px;background:#A8E6CF"><svg viewBox="0 0 100 100" style="width:150px;height:150px;flex:none"><rect x="26" y="6" width="48" height="88" rx="12" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="5"/><rect x="34" y="18" width="32" height="56" rx="4" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3"/><circle cx="50" cy="83" r="4" fill="#2D2D2D"/></svg><span class="f8-d">ANDROID</span></div>
|
||||
<div class="f8-big f8-card f8-c2" style="top:790px;background:#A8D8F0"><svg viewBox="0 0 100 100" style="width:150px;height:150px;flex:none"><rect x="26" y="6" width="48" height="88" rx="12" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="5"/><rect x="34" y="18" width="32" height="56" rx="4" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3"/><circle cx="50" cy="83" r="4" fill="#2D2D2D"/></svg><span class="f8-d">iOS</span></div>
|
||||
</div>
|
||||
<script>
|
||||
(function () {
|
||||
const DUR = 3.783;
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
|
||||
const orns = document.querySelectorAll(".f8-orn");
|
||||
tl.fromTo(orns, { scale: 0, opacity: 0 }, { scale: 1, opacity: 1, duration: 0.55, ease: "back.out(1.8)", stagger: 0.07 }, 0.05);
|
||||
orns.forEach((el, i) => {
|
||||
const t0 = 0.9 + i * 0.12, half = Math.max(1.2, (DUR - 1.6) / 2), amp = i % 2 ? -14 : 14;
|
||||
tl.to(el, { y: amp, duration: half, ease: "sine.inOut" }, t0).to(el, { y: 0, duration: half, ease: "sine.inOut" }, t0 + half);
|
||||
});
|
||||
|
||||
tl.fromTo(".f8-c1", { y: 160, opacity: 0, rotation: -6, scale: 0.8 }, { y: 0, opacity: 1, rotation: -2, scale: 1, duration: 0.6, ease: "back.out(1.6)" }, 0.96);
|
||||
tl.fromTo(".f8-c2", { y: 160, opacity: 0, rotation: 6, scale: 0.8 }, { y: 0, opacity: 1, rotation: 2, scale: 1, duration: 0.6, ease: "back.out(1.6)" }, 1.92);
|
||||
window.__timelines["08-platforms"] = tl;
|
||||
})();
|
||||
</script>
|
||||
</template>
|
||||
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<style>
|
||||
@font-face { font-family: "Fredoka"; src: url("assets/fonts/fredoka-600.woff2") format("woff2"); font-weight: 600; font-style: normal; }
|
||||
@font-face { font-family: "Quicksand"; src: url("assets/fonts/quicksand-var.woff2") format("woff2"); font-weight: 500 700; font-style: normal; }
|
||||
#root { position: absolute; inset: 0; overflow: hidden; color: #2D2D2D; font-family: "Quicksand", sans-serif; font-weight: 600; }
|
||||
.f9-bg { position: absolute; inset: 0; }
|
||||
.f9-orn { position: absolute; z-index: 1; }
|
||||
.f9-orn svg { width: 100%; height: 100%; display: block; overflow: visible; }
|
||||
.f9-z { position: absolute; z-index: 2; }
|
||||
.f9-d { font-family: "Fredoka", sans-serif; font-weight: 600; letter-spacing: 0.02em; line-height: 1.05; }
|
||||
.f9-card { background: #FFFFFF; border: 5px solid #2D2D2D; border-radius: 40px; box-shadow: 12px 12px 0 #2D2D2D; }
|
||||
.f9-pill { display: inline-flex; align-items: center; gap: 18px; border: 5px solid #2D2D2D; border-radius: 80px; box-shadow: 8px 8px 0 #2D2D2D; padding: 20px 46px; white-space: nowrap; }
|
||||
.f9-phone { position: absolute; z-index: 2; left: 260px; top: 230px; width: 560px; height: 1120px; background: #FFFFFF; border: 6px solid #2D2D2D; border-radius: 80px; box-shadow: 16px 16px 0 #2D2D2D; overflow: hidden; }
|
||||
.f9-notch { position: absolute; left: 50%; top: 22px; margin-left: -70px; width: 140px; height: 28px; border-radius: 20px; background: #2D2D2D; }
|
||||
|
||||
.f9-eye { display: block; position: relative; width: 140px; height: 140px; border-radius: 50%; background: #FFFFFF; border: 7.5px solid #2D2D2D; box-sizing: border-box; text-shadow: none; }
|
||||
.f9-pup { position: absolute; left: 50%; top: 50%; width: 55px; height: 55px; margin: -27.5px 0 0 -27.5px; border-radius: 50%; background: #2D2D2D; }
|
||||
.f9-wmwrap { left: 0; right: 0; top: 400px; }
|
||||
.f9-tag { left: 50%; top: 840px; margin-left: -400px; width: 800px; height: 190px; display: flex; align-items: center; justify-content: center; background: #FFFFFF; }
|
||||
.f9-tag span { font-size: 64px; }
|
||||
.f9-chips { left: 0; right: 0; top: 1130px; display: flex; justify-content: center; gap: 40px; }
|
||||
.f9-chips .f9-pill { padding: 16px 40px; } .f9-chips span { font-size: 56px; }
|
||||
</style>
|
||||
<div id="root" data-composition-id="09-cta" data-width="1080" data-height="1920">
|
||||
<div id="scene9-bg" class="clip f9-bg" data-start="0" data-duration="5.772" data-track-index="0" style="background:#D4A5E8"></div>
|
||||
<div class="f9-orn" style="left:780px;top:70px;width:300px;height:300px"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><line x1="50" y1="9" x2="50" y2="22" transform="rotate(0 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(30 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(60 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(90 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(120 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(150 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(180 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(210 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(240 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(270 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(300 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><line x1="50" y1="9" x2="50" y2="22" transform="rotate(330 50 50)" stroke="#2D2D2D" stroke-width="3.2" stroke-linecap="round"/><circle cx="50" cy="50" r="24" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f9-orn" style="left:-80px;top:160px;width:260px;height:260px"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(0 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(45 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(90 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(135 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(180 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(225 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(270 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(315 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><circle cx="50" cy="50" r="14" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f9-orn" style="left:850px;top:1250px;width:250px;height:250px"><svg viewBox="0 0 100 100" style="transform:rotate(0deg)" xmlns="http://www.w3.org/2000/svg"><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(0 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(45 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(90 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(135 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(180 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(225 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(270 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><ellipse cx="50" cy="21" rx="11" ry="19" transform="rotate(315 50 50)" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2"/><circle cx="50" cy="50" r="14" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2"/></svg></div>
|
||||
<div class="f9-orn" style="left:-90px;top:1220px;width:330px;height:330px"><svg viewBox="0 0 100 100" style="transform:rotate(3deg)" xmlns="http://www.w3.org/2000/svg"><path d="M24 72 a17 17 0 0 1 3-33 a22 22 0 0 1 43-3 a17 17 0 0 1 6 36 z" fill="#FFFFFF" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f9-orn" style="left:140px;top:1010px;width:130px;height:130px"><svg viewBox="0 0 100 100" style="transform:rotate(-10deg)" xmlns="http://www.w3.org/2000/svg"><polygon points="50,6 61,38 95,38 67,58 78,92 50,71 22,92 33,58 5,38 39,38" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
<div class="f9-orn" style="left:810px;top:1000px;width:120px;height:120px"><svg viewBox="0 0 100 100" style="transform:rotate(12deg)" xmlns="http://www.w3.org/2000/svg"><polygon points="50,6 61,38 95,38 67,58 78,92 50,71 22,92 33,58 5,38 39,38" fill="#FDE68A" stroke="#2D2D2D" stroke-width="3.2" stroke-linejoin="round"/></svg></div>
|
||||
|
||||
<div class="f9-z f9-wmwrap">
|
||||
<div class="f9-wm f9-d" style="display:flex;align-items:flex-end;justify-content:center;font-size:250px;color:#2D2D2D;text-shadow:9px 9px 0 #FFFFFF;line-height:1">
|
||||
<span>l</span>
|
||||
<span class="f9-eye" style="margin:0 7.5px 15px 12.5px"><i class="f9-pup"></i></span>
|
||||
<span class="f9-eye" style="margin:0 12.5px 15px 7.5px"><i class="f9-pup"></i></span>
|
||||
<span>katu</span>
|
||||
</div></div>
|
||||
<div class="f9-z f9-card f9-tag"><span class="f9-d">LOOK OUT FOR THEM</span></div>
|
||||
<div class="f9-z f9-chips"><span class="f9-pill f9-ch1" style="background:#A8E6CF"><span class="f9-d">ANDROID</span></span><span class="f9-pill f9-ch2" style="background:#A8D8F0"><span class="f9-d">iOS</span></span></div>
|
||||
</div>
|
||||
<script>
|
||||
(function () {
|
||||
const DUR = 5.772;
|
||||
const tl = gsap.timeline({ paused: true });
|
||||
|
||||
const orns = document.querySelectorAll(".f9-orn");
|
||||
tl.fromTo(orns, { scale: 0, opacity: 0 }, { scale: 1, opacity: 1, duration: 0.55, ease: "back.out(1.8)", stagger: 0.07 }, 0.05);
|
||||
orns.forEach((el, i) => {
|
||||
const t0 = 0.9 + i * 0.12, half = Math.max(1.2, (DUR - 1.6) / 2), amp = i % 2 ? -14 : 14;
|
||||
tl.to(el, { y: amp, duration: half, ease: "sine.inOut" }, t0).to(el, { y: 0, duration: half, ease: "sine.inOut" }, t0 + half);
|
||||
});
|
||||
|
||||
tl.fromTo(".f9-wm", { scale: 0.4, opacity: 0, y: 70 }, { scale: 1, opacity: 1, y: 0, duration: 0.75, ease: "back.out(1.6)" }, 0.12);
|
||||
|
||||
const pups = document.querySelectorAll(".f9-pup"), r = 25;
|
||||
tl.fromTo(pups, { x: 0, y: 0 }, { x: -r, y: -r * 0.4, duration: 0.35, ease: "power2.out" }, 0.7)
|
||||
.to(pups, { x: r, y: r * 0.3, duration: 0.5, ease: "power2.inOut" }, 1.2999999999999998)
|
||||
.to(pups, { x: 0, y: 0, duration: 0.35, ease: "power2.out" }, 2.05);
|
||||
tl.fromTo(".f9-tag", { y: 90, opacity: 0, rotation: -4 }, { y: 0, opacity: 1, rotation: 0, duration: 0.6, ease: "back.out(1.6)" }, 1.04);
|
||||
tl.fromTo(".f9-ch1", { y: 70, opacity: 0, scale: 0.7 }, { y: 0, opacity: 1, scale: 1, duration: 0.5, ease: "back.out(1.8)" }, 2.27);
|
||||
tl.fromTo(".f9-ch2", { y: 70, opacity: 0, scale: 0.7 }, { y: 0, opacity: 1, scale: 1, duration: 0.5, ease: "back.out(1.8)" }, 2.45);
|
||||
tl.to(".f9-wm", { scale: 1.04, duration: 0.5, ease: "sine.inOut" }, 3.28).to(".f9-wm", { scale: 1, duration: 0.5, ease: "sine.inOut" }, ">");
|
||||
window.__timelines["09-cta"] = tl;
|
||||
})();
|
||||
</script>
|
||||
</template>
|
||||
@@ -0,0 +1,274 @@
|
||||
---
|
||||
version: alpha
|
||||
name: Daisy Days — Frame (video / frame layer)
|
||||
description: >
|
||||
Video-first companion to Daisy Days' design.md. The unit is the frame (1920×1080). Atoms are
|
||||
identical and sacred — the sunny-garden pastel palette (cream + turquoise/pink/butter/mint/
|
||||
lavender/peach/sky + coral accent), charcoal 3px outlines, hard offset shadows (6/4px, no blur),
|
||||
the Fredoka + Quicksand pairing, generous radii, headline text-shadow on color, dot bullets, and
|
||||
the hand-drawn SVG ornament layer. Composition + frame scale rewritten. Motion out of scope.
|
||||
unit: the frame — 1920×1080 primary; 9:16 and 1:1 documented
|
||||
principle: atoms are sacred · composition is free · numbers come from the script
|
||||
|
||||
colors:
|
||||
cream: "#F5F0E6"
|
||||
turquoise: "#7ECDC0"
|
||||
soft-pink: "#F7C8D4"
|
||||
butter: "#FDE68A"
|
||||
mint: "#A8E6CF"
|
||||
lavender: "#D4A5E8"
|
||||
peach: "#FFCBA4"
|
||||
sky: "#A8D8F0"
|
||||
coral: "#F8635F"
|
||||
text-dark: "#2D2D2D"
|
||||
text-muted: "#6B6B6B"
|
||||
white: "#FFFFFF"
|
||||
|
||||
borders: { primary: "3px solid text-dark", thin: "2px solid text-dark" }
|
||||
shadows: { default: "6px 6px 0 text-dark", small: "4px 4px 0 text-dark", text-headline: "3px 3px 0 text-dark", text-headline-soft: "3px 3px 0 rgba(0,0,0,0.2)" }
|
||||
|
||||
typography:
|
||||
# — reading ramp (Quicksand) —
|
||||
body: { fontFamily: "Quicksand", cqw: 0.95, weight: 500, lineHeight: 1.6 }
|
||||
body-strong:{ fontFamily: "Quicksand", cqw: 0.95, weight: 600, lineHeight: 1.5 }
|
||||
meta: { fontFamily: "Quicksand", cqw: 0.78, weight: 600, lineHeight: 1.45 }
|
||||
# — display ramp (Fredoka One / Fredoka 600 — single weight, never italic) —
|
||||
badge: { fontFamily: "Fredoka One", cqw: 0.9, tracking: "0.02em" }
|
||||
label-display:{ fontFamily: "Fredoka One", cqw: 1.3, lineHeight: 1.3, tracking: "0.02em" }
|
||||
subtitle:{ fontFamily: "Fredoka One", cqw: 1.8, lineHeight: 1.2, tracking: "0.02em" }
|
||||
quote: { fontFamily: "Fredoka One", cqw: 2.6, lineHeight: 1.35 }
|
||||
title: { fontFamily: "Fredoka One", cqw: 3.0, lineHeight: 1.15, tracking: "0.02em" }
|
||||
headline:{ fontFamily: "Fredoka One", cqw: 4.5, lineHeight: 1.1, tracking: "0.02em" }
|
||||
display: { fontFamily: "Fredoka One", cqw: 6.5, lineHeight: 1.1, tracking: "0.02em" }
|
||||
|
||||
spacing:
|
||||
pad-slide: "3cqw"
|
||||
radius: "20px"
|
||||
radius-lg: "28px"
|
||||
radius-pill: "50px"
|
||||
radius-round: "50%"
|
||||
|
||||
components:
|
||||
card:
|
||||
backgroundColor: "{colors.white}"
|
||||
border: "3px solid {colors.text-dark}"
|
||||
rounded: "{spacing.radius} (28px featured)"
|
||||
shadow: "6px 6px 0 {colors.text-dark}"
|
||||
description: "The universal container; white-on-pastel is standard."
|
||||
framed-header:
|
||||
backgroundColor: "pastel cap + {colors.white} body"
|
||||
border: "3px solid {colors.text-dark} (one continuous)"
|
||||
rounded: "{spacing.radius-lg}"
|
||||
shadow: "6px 6px 0 {colors.text-dark}"
|
||||
description: "Pastel header strip flush above a white body — one unit, one shadow."
|
||||
badge-pill:
|
||||
backgroundColor: "{colors.butter}"
|
||||
border: "3px solid {colors.text-dark}"
|
||||
rounded: "{spacing.radius-pill}"
|
||||
typography: "{typography.badge}"
|
||||
shadow: "4px 4px 0 {colors.text-dark}"
|
||||
description: "Section tag. white-space:nowrap."
|
||||
circle-marker:
|
||||
backgroundColor: "any pastel"
|
||||
textColor: "{colors.white} (dark on butter)"
|
||||
border: "3px solid {colors.text-dark}"
|
||||
rounded: "50%"
|
||||
size: "bullet 20 / icon 44 / dot 48 / step 90"
|
||||
typography: "Fredoka numeral"
|
||||
description: "Steps carry a small shadow."
|
||||
bullet-dot:
|
||||
backgroundColor: "{colors.butter}"
|
||||
border: "2px solid {colors.text-dark}"
|
||||
rounded: "50%"
|
||||
size: "20px (::before, 4px from line top)"
|
||||
description: "Lists never use glyph bullets."
|
||||
ornament:
|
||||
type: "hand-drawn SVG (daisy, star, sun, cloud, rainbow)"
|
||||
stroke: "2.1px {colors.text-dark}"
|
||||
placement: "z-index:1 behind content (z-index:2), cropping past the frame edge"
|
||||
description: "3–7 per frame, clustered at corners/edges."
|
||||
quote-mark:
|
||||
typography: "oversized Fredoka quote glyph"
|
||||
color: "{colors.soft-pink} (charcoal stroke)"
|
||||
description: "Above a quote body."
|
||||
text-headline-shadow:
|
||||
shadow: "3px 3px 0 {colors.text-dark} (soft 20% variant on pink/mint)"
|
||||
appliesTo: "Fredoka headlines on saturated surfaces (cream headlines sit flat)"
|
||||
description: "Makes the headline read 'outlined' like the shapes."
|
||||
---
|
||||
|
||||
# Daisy Days — Frame (video / frame layer)
|
||||
|
||||
## Overview
|
||||
|
||||
Daisy Days at frame scale is a **cheerful, childlike system** — picture-book illustration meets
|
||||
sticker-sheet kawaii. Every shape carries a **3px charcoal outline**, every elevated element a
|
||||
**solid hard offset shadow** (no blur), every surface a sunny-garden pastel. The voice is one
|
||||
pairing: **Fredoka One** (chunky rounded, single weight) for every headline, **Quicksand** for
|
||||
every body and meta line. The signature is the **hand-drawn SVG ornament layer** — daisies, stars,
|
||||
suns, clouds, rainbows clustering at corners and cropping past the edge.
|
||||
|
||||
The palette is **multi-pastel with one warm pop**: cream canvas, seven pastel surfaces, and
|
||||
`{colors.coral}` reserved for small high-attention markers only. Headlines on a saturated surface
|
||||
get a 3px charcoal text-shadow (so they read "outlined" like the shapes) and switch to white;
|
||||
headlines on cream sit flat in charcoal. Depth is 2D and graphic — thick outline + hard offset =
|
||||
sticker-on-paper.
|
||||
|
||||
**Key characteristics at frame scale:**
|
||||
|
||||
- **Cream default + rotating pastel surfaces**; `{colors.coral}` is a marker accent, never a surface.
|
||||
- **Fredoka One** headlines + **Quicksand 500/600** body — strict by role, never crossed.
|
||||
- **3px charcoal outline + hard offset shadow** (6/4px, zero blur) on every elevated shape.
|
||||
- **Generous radii** — 20px cards, 28px featured, pill badges, full-circle markers; no square corners.
|
||||
- **Headline text-shadow on saturated surfaces** (white text); flat charcoal on cream.
|
||||
- **Dot bullets** (outlined butter discs, never glyphs) + a **3–7 ornament wreath** per frame.
|
||||
|
||||
## The Frame
|
||||
|
||||
### Frame Craft Bar
|
||||
|
||||
Three eyeball tests gate every frame before any structural check:
|
||||
|
||||
- **Squint** — one Fredoka headline or content card dominates at 3–6× its neighbor.
|
||||
- **Silence** — **one content container per frame** surrounded by an ornament wreath; the **info-card grid is the one dense exception**. Empty corners read as broken.
|
||||
- **Restraint** — cream or **one** pastel surface; coral is a small-marker accent (never a surface); charcoal borders + hard offset shadows only; no ninth color.
|
||||
- **Reference** — aim at a **children's picture-book / sticker-sheet kawaii zine**; failure looks like a **flat, square-cornered, blurred-shadow corporate slide**.
|
||||
|
||||
- **Primary:** 1920×1080 (16:9). Display authored in **`cqw`** (`px ÷ 1920 × 100 = cqw`).
|
||||
- **Vertical:** 1080×1920 (9:16). **Square:** 1080×1080 (1:1).
|
||||
- **Safe area:** `pad-slide` ~3cqw; ornaments deliberately bleed past the edge.
|
||||
|
||||
**The container law (load-bearing).** Every frame ground sets `container-type: size`; ALL
|
||||
frame-relative units are `cqw`/`cqh` against it — never `vw`. Borders stay 3px/2px; radii stay
|
||||
20/28/50px; shadow offsets scale in `cqw` so the sticker offset holds proportionally.
|
||||
|
||||
## Colors
|
||||
|
||||
Tokens identical to the source. Default ground `{colors.cream}`; rotate saturated pastels
|
||||
(turquoise / soft-pink / butter / mint / lavender / peach / sky) for tonal mood. **Cards are white**
|
||||
on any surface. **Borders + shadows are always `{colors.text-dark}` charcoal** — never colored,
|
||||
never blurred, never `rgba` (save the soft text-shadow variant). `{colors.coral}` is the lone
|
||||
high-saturation accent — small markers (step circles, dots, headers) **only**, never a surface.
|
||||
Body is charcoal/muted; pastels carry **no semantic meaning**. No ninth color.
|
||||
|
||||
## Typography
|
||||
|
||||
Two ramps. The **reading ramp** (Quicksand 500 body 0.95cqw, 600 emphasis, meta) carries copy; the
|
||||
**display ramp** (Fredoka One `label-display` 1.3cqw → `display` 6.5cqw, single weight) carries
|
||||
every headline, title, quote, and marker numeral.
|
||||
|
||||
- **Legibility floor:** any load-bearing line ≥ **1.4cqw**; meta is chrome only.
|
||||
- **Fit-to-measure:** size the headline to its length. Cap the block at **≤ 78cqw**; ≤3 words → `display`; 4–6 → `headline`; 7+ → `title`.
|
||||
- **Fredoka One for all display, Quicksand for all body — never crossed.** Fredoka is single-weight (no italic, no underline, no alt weights); Quicksand stays 500/600/700. Fredoka tracking 0.02em; Quicksand body never uppercase.
|
||||
|
||||
## Depth & Surface
|
||||
|
||||
2D graphic depth — hard offset shadow, solid charcoal, zero blur, bottom-right:
|
||||
|
||||
- **`shadows.default` 6px** cards, frames, badges, chart containers.
|
||||
- **`shadows.small` 4px** small cards, step circles, avatars.
|
||||
- **Text-headline shadow** — 3px charcoal on Fredoka headlines over saturated surfaces (20% soft variant on pink/mint); cream headlines flat.
|
||||
- **Outline + offset** together are the sticker-on-paper signature.
|
||||
|
||||
**Ceiling:** no blurred shadow, no `rgba` (except the soft text-shadow), no gradient, no glow; an element either casts a hard charcoal offset or none.
|
||||
|
||||
## Shapes
|
||||
|
||||
- **20px** cards, **28px** featured, **50px** pill (badges, counter), **50%** all circles, **4px** legend swatch. Zero square corners — every region is rounded.
|
||||
|
||||
## Components
|
||||
|
||||
- **card / framed-header** — the white-fill bordered containers (one shadow). **badge-pill** — butter section tag.
|
||||
- **circle-marker** family (bullet 20 / icon 44 / dot 48 / step 90) + **bullet-dot** — outlined pastel discs, Fredoka numerals.
|
||||
- **ornament** — the hand-drawn SVG sticker layer (3–7 per frame). **quote-mark** — soft-pink Fredoka anchor. **text-headline-shadow** — the on-color headline treatment.
|
||||
|
||||
## Frame Treatments
|
||||
|
||||
> Recipe: ground · container · composes · focal · chrome · accent · silence · Fixed/Free · density.
|
||||
> One content container per frame + a 3–7 ornament wreath; empty corners read as broken.
|
||||
|
||||
### 1 · Cover (identity · move: ornament wreath · saturated · centered)
|
||||
|
||||
**Ground** a saturated pastel (e.g. `{colors.turquoise}`). **Composes** badge-pill, display, body sub, 3–7 ornaments, counter. **Focal** a 1–2 line Fredoka `display` in **white with the 3px charcoal text-shadow**, centered, under a butter badge-pill. **Chrome** counter pill. **Accent** the ornament wreath (daisies + stars at corners, cropping past edges). **Silence** content centered; ornaments fill the edges. **Fixed** text-shadow on color, 3px outlines, charcoal shadows. **Free** surface color, ornament mix/positions, copy. **Density** full-but-not-crowded.
|
||||
|
||||
### 2 · Info Cards (catalog · move: 3-up white cards · cream · the dense frame)
|
||||
|
||||
**Ground** `{colors.cream}`, `pad-slide`. **Composes** headline (flat charcoal), 3× card (circle-icon + Fredoka title + Quicksand body), a couple ornaments. **Focal** three white 3px-bordered cards with 6px shadows. **Chrome** flat headline. **Accent** the pastel circle-icons (rotate turquoise/coral/lavender). **Silence** tight — the density exception (fewer ornaments here). **Fixed** white cards, 3px + 6px, 20px radius. **Free** card content, icon hues. **Density** dense-exception.
|
||||
|
||||
### 3 · Process Steps (sequence · move: rotating circle markers · peach · centered)
|
||||
|
||||
**Ground** `{colors.peach}` (or another pastel). **Composes** headline (white + text-shadow), 3–4 step circles + `→` arrows, ornaments. **Focal** a row of 90px outlined step circles, fills **rotating coral → mint → sky → lavender**, Fredoka white numerals, linked by Fredoka arrows. **Chrome** white headline with text-shadow. **Accent** the rotating circle fills. **Silence** moderate. **Fixed** 3px circles + small shadow, rotating fills, arrow glyphs. **Free** step count, labels. **Density** standard.
|
||||
|
||||
### 4 · Quote (quote · move: quote-mark anchor · soft-pink · centered)
|
||||
|
||||
**Ground** `{colors.soft-pink}`. **Composes** a white quote card (28px radius, 6px shadow), quote-mark, Fredoka quote, Quicksand attribution, ornaments. **Focal** a Fredoka `quote` in charcoal inside the white card, under an oversized soft-pink quote-mark. **Chrome** Quicksand 700 attribution. **Accent** the quote-mark + a star or two. **Silence** card centered, ornaments at corners. **Fixed** quote-mark anchor, white card. **Free** quote, attribution. **Density** moderate.
|
||||
|
||||
### 5 · Framed Section (feature · move: cap+body card · cream)
|
||||
|
||||
**Ground** `{colors.cream}`. **Composes** framed-header (pastel cap + white body), bullet-dot list, ornaments. **Focal** a framed-header — a pastel cap strip (Fredoka title, optional text-shadow) above a white body with a butter-dot bullet list. **Accent** the cap color + bullet dots. **Silence** moderate. **Fixed** one continuous 3px border + one shadow, butter dot bullets. **Free** cap color, list. **Density** standard.
|
||||
|
||||
### 6 · Closing (closer · move: ornament wreath · saturated · centered)
|
||||
|
||||
**Ground** a saturated pastel (e.g. `{colors.lavender}`). **Composes** badge-pill, display (white + text-shadow), 3–7 ornaments. **Focal** a Fredoka `display` sign-off in white with the charcoal text-shadow, centered. **Accent** the ornament wreath. **Silence** content centered. **Fixed** text-shadow on color, ornaments fill corners. **Free** sign-off, surface, ornaments. **Density** full.
|
||||
|
||||
## Composition Rules
|
||||
|
||||
### Do
|
||||
|
||||
- Pair **Fredoka One headlines + Quicksand body** strictly by role.
|
||||
- Outline every shape **3px charcoal + a hard offset shadow** (6/4px, no blur); white card fills on any surface.
|
||||
- Give Fredoka headlines on **saturated surfaces a 3px charcoal text-shadow + white text**; flat charcoal on cream.
|
||||
- Use **outlined butter-disc bullets** (never glyphs); cluster **3–7 hand-drawn ornaments** per frame (corners, cropping past edges).
|
||||
- Keep **one content container per frame**; rotate marker colors (coral → mint → sky → lavender → butter); reserve coral for small markers.
|
||||
- Center most frames; lean cream for content-dense frames, saturated for cover/closer/quote.
|
||||
|
||||
### Don't
|
||||
|
||||
- No square corners; no blurred or `rgba` shadows (save the soft text-shadow).
|
||||
- No colored borders (charcoal only); no coral surface; no ninth color.
|
||||
- No third font; no Quicksand headline or Fredoka body; no italic/underline Fredoka; no uppercase Quicksand body.
|
||||
- No glyph bullets; no empty corners (ornaments fill them); no two competing content panels.
|
||||
- Don't blow a headline edge-to-edge — fit to measure.
|
||||
|
||||
## Aspect-Ratio Behavior
|
||||
|
||||
| Treatment | 16:9 | 9:16 | 1:1 |
|
||||
| -------------- | -------------------------- | -------------------------------- | ---------- |
|
||||
| Cover | centered, corner ornaments | centered, taller, more ornaments | centered |
|
||||
| Info Cards | 3 across | stacked | 2+1 |
|
||||
| Process Steps | horizontal + arrows | vertical, arrows rotate down | 2×2 |
|
||||
| Quote | centered card | centered, taller | centered |
|
||||
| Framed Section | cap + body | cap + body taller | cap + body |
|
||||
| Closing | centered, wreath | centered, wreath | centered |
|
||||
|
||||
`pad-slide` holds on the short edge; re-step display above the 1.4cqw floor. On tighter ratios keep
|
||||
the ornament count toward the upper end (5–7) so corners never read empty.
|
||||
|
||||
## Approved Real Entities
|
||||
|
||||
No real customers, logos, or vendors are defined in the source — render any such mark as a
|
||||
placeholder. Ornaments and pastels are content-agnostic; counters/badges carry per-deck text.
|
||||
|
||||
## Numerals & Claims (hard rule)
|
||||
|
||||
Never invent figures, dates, or counts at frame scale. Render slots as `— figure —`, `{metric}`,
|
||||
`N`. Step numbers and any chart values carry placeholders until the script supplies them; the slide
|
||||
counter is decorative chrome.
|
||||
|
||||
## Pre-Render Self-Audit
|
||||
|
||||
- **Squint** — one Fredoka headline or content card dominates per frame.
|
||||
- **Silence** — one container per frame surrounded by an ornament wreath; only the info-card grid runs dense.
|
||||
- **Color** — cream or one pastel surface; coral markers only; charcoal borders/shadows; no ninth hue.
|
||||
- **Type** — Fredoka headlines (text-shadow + white on saturated, flat charcoal on cream), Quicksand body; ≥1.4cqw floor.
|
||||
- **Depth** — 3px outline + hard offset (no blur, no rgba save soft text-shadow); rounded corners only.
|
||||
- **Ornaments** — 3–7 per frame, cropping past edges; no empty corners. **Bullets** — outlined discs, never glyphs.
|
||||
- **Fabrication** — every numeral traces to the script, else placeholder.
|
||||
|
||||
## Known Gaps
|
||||
|
||||
- **Motion intentionally out of scope.** frame.md specifies composition only; the source uses scroll-snap nav, no transition spec.
|
||||
- **Fonts:** the source names _Fredoka One_; Google now serves the **Fredoka** variable family — request `Fredoka:wght@500;600;700` and set display weight 600 (visually equal to Fredoka One), with `Fredoka One` kept first in the stack for environments that still serve it. Quicksand loads normally. CJK: ZCOOL XiaoWei (display) / Yozai (body).
|
||||
- **9:16 / 1:1 are guidance**; keep ornament count high so corners stay filled per ratio.
|
||||
- Ornaments (daisy/star/sun/cloud/rainbow), markers, and framed headers are CSS/SVG-only; recoloring SVG ornaments requires editing their stroke values.
|
||||
- **Contrast:** keep `{colors.text-muted}` off pastel surfaces (cream/white cards only); small text on saturated grounds should be charcoal or white.
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "https://hyperframes.heygen.com/schema/hyperframes.json",
|
||||
"registry": "https://raw.githubusercontent.com/heygen-com/hyperframes/main/registry",
|
||||
"paths": {
|
||||
"blocks": "compositions",
|
||||
"components": "compositions/components",
|
||||
"assets": "assets"
|
||||
},
|
||||
"media": {
|
||||
"autoProxy": true
|
||||
},
|
||||
"authoringSkill": "product-launch-video"
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=1080, height=1920" />
|
||||
<script src="assets/vendor/gsap.min.js"></script>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
width: 1080px;
|
||||
height: 1920px;
|
||||
overflow: hidden;
|
||||
background: #000;
|
||||
}
|
||||
#root {
|
||||
position: relative;
|
||||
width: 1080px;
|
||||
height: 1920px;
|
||||
overflow: hidden;
|
||||
background: #F5F0E6;
|
||||
}
|
||||
.scene {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div
|
||||
id="root"
|
||||
data-composition-id="main"
|
||||
data-start="0"
|
||||
data-duration="54.733"
|
||||
data-width="1080"
|
||||
data-height="1920"
|
||||
>
|
||||
<div
|
||||
id="el-01-hook"
|
||||
class="scene"
|
||||
data-composition-id="01-hook"
|
||||
data-composition-src="compositions/frames/01-hook.html"
|
||||
data-start="0"
|
||||
data-duration="6.14"
|
||||
data-track-index="0"
|
||||
></div>
|
||||
<audio
|
||||
id="el-01-hook-voice"
|
||||
src="assets/voice/01.wav"
|
||||
data-start="0"
|
||||
data-duration="5.64"
|
||||
data-track-index="10"
|
||||
data-volume="1"
|
||||
></audio>
|
||||
|
||||
<div
|
||||
id="el-02-worry"
|
||||
class="scene"
|
||||
data-composition-id="02-worry"
|
||||
data-composition-src="compositions/frames/02-worry.html"
|
||||
data-start="5.64"
|
||||
data-duration="7.511"
|
||||
data-track-index="1"
|
||||
></div>
|
||||
<audio
|
||||
id="el-02-worry-voice"
|
||||
src="assets/voice/02.wav"
|
||||
data-start="5.64"
|
||||
data-duration="7.111"
|
||||
data-track-index="10"
|
||||
data-volume="1"
|
||||
></audio>
|
||||
|
||||
<div
|
||||
id="el-03-meet"
|
||||
class="scene"
|
||||
data-composition-id="03-meet"
|
||||
data-composition-src="compositions/frames/03-meet.html"
|
||||
data-start="12.751"
|
||||
data-duration="8.644"
|
||||
data-track-index="0"
|
||||
></div>
|
||||
<audio
|
||||
id="el-03-meet-voice"
|
||||
src="assets/voice/03.wav"
|
||||
data-start="12.751"
|
||||
data-duration="8.144"
|
||||
data-track-index="10"
|
||||
data-volume="1"
|
||||
></audio>
|
||||
|
||||
<div
|
||||
id="el-04-limits"
|
||||
class="scene"
|
||||
data-composition-id="04-limits"
|
||||
data-composition-src="compositions/frames/04-limits.html"
|
||||
data-start="20.895"
|
||||
data-duration="7.099"
|
||||
data-track-index="1"
|
||||
></div>
|
||||
<audio
|
||||
id="el-04-limits-voice"
|
||||
src="assets/voice/04.wav"
|
||||
data-start="20.895"
|
||||
data-duration="6.599"
|
||||
data-track-index="10"
|
||||
data-volume="1"
|
||||
></audio>
|
||||
|
||||
<div
|
||||
id="el-05-apps"
|
||||
class="scene"
|
||||
data-composition-id="05-apps"
|
||||
data-composition-src="compositions/frames/05-apps.html"
|
||||
data-start="27.494"
|
||||
data-duration="6.203"
|
||||
data-track-index="0"
|
||||
></div>
|
||||
<audio
|
||||
id="el-05-apps-voice"
|
||||
src="assets/voice/05.wav"
|
||||
data-start="27.494"
|
||||
data-duration="5.703"
|
||||
data-track-index="10"
|
||||
data-volume="1"
|
||||
></audio>
|
||||
|
||||
<div
|
||||
id="el-06-location"
|
||||
class="scene"
|
||||
data-composition-id="06-location"
|
||||
data-composition-src="compositions/frames/06-location.html"
|
||||
data-start="33.197"
|
||||
data-duration="7.013"
|
||||
data-track-index="1"
|
||||
></div>
|
||||
<audio
|
||||
id="el-06-location-voice"
|
||||
src="assets/voice/06.wav"
|
||||
data-start="33.197"
|
||||
data-duration="6.513"
|
||||
data-track-index="10"
|
||||
data-volume="1"
|
||||
></audio>
|
||||
|
||||
<div
|
||||
id="el-07-balance"
|
||||
class="scene"
|
||||
data-composition-id="07-balance"
|
||||
data-composition-src="compositions/frames/07-balance.html"
|
||||
data-start="39.71"
|
||||
data-duration="5.968"
|
||||
data-track-index="0"
|
||||
></div>
|
||||
<audio
|
||||
id="el-07-balance-voice"
|
||||
src="assets/voice/07.wav"
|
||||
data-start="39.71"
|
||||
data-duration="5.468"
|
||||
data-track-index="10"
|
||||
data-volume="1"
|
||||
></audio>
|
||||
|
||||
<div
|
||||
id="el-08-platforms"
|
||||
class="scene"
|
||||
data-composition-id="08-platforms"
|
||||
data-composition-src="compositions/frames/08-platforms.html"
|
||||
data-start="45.178"
|
||||
data-duration="4.183"
|
||||
data-track-index="1"
|
||||
></div>
|
||||
<audio
|
||||
id="el-08-platforms-voice"
|
||||
src="assets/voice/08.wav"
|
||||
data-start="45.178"
|
||||
data-duration="3.783"
|
||||
data-track-index="10"
|
||||
data-volume="1"
|
||||
></audio>
|
||||
|
||||
<div
|
||||
id="el-09-cta"
|
||||
class="scene"
|
||||
data-composition-id="09-cta"
|
||||
data-composition-src="compositions/frames/09-cta.html"
|
||||
data-start="48.961"
|
||||
data-duration="5.772"
|
||||
data-track-index="0"
|
||||
></div>
|
||||
<audio
|
||||
id="el-09-cta-voice"
|
||||
src="assets/voice/09.wav"
|
||||
data-start="48.961"
|
||||
data-duration="5.772"
|
||||
data-track-index="10"
|
||||
data-volume="1"
|
||||
></audio>
|
||||
|
||||
<!-- captions -->
|
||||
<div
|
||||
id="el-captions"
|
||||
data-track-kind="captions"
|
||||
class="scene"
|
||||
data-composition-id="captions"
|
||||
data-composition-src="compositions/captions.html"
|
||||
data-start="0"
|
||||
data-duration="54.733"
|
||||
data-track-index="2"
|
||||
></div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.__timelines = window.__timelines || {};
|
||||
window.__timelines["main"] = gsap.timeline({ paused: true });
|
||||
// ── frame transitions (injected by transitions.mjs) ──
|
||||
(function () { var tl = window.__timelines["main"];
|
||||
tl.to("#el-01-hook", { opacity: 0, duration: 0.5, ease: "power2.inOut" }, 5.64);
|
||||
tl.fromTo("#el-02-worry", { opacity: 0 }, { opacity: 1, duration: 0.5, ease: "power2.inOut" }, 5.64);
|
||||
tl.to("#el-02-worry", { scale: 2.5, opacity: 0, filter: "blur(8px)", duration: 0.4, ease: "power3.in" }, 12.751);
|
||||
tl.fromTo("#el-03-meet", { scale: 0.5, opacity: 0, filter: "blur(8px)" }, { scale: 1, opacity: 1, filter: "blur(0px)", duration: 0.4, ease: "power3.out" }, 12.751);
|
||||
tl.to("#el-03-meet", { x: -1080, duration: 0.5, ease: "power3.inOut" }, 20.895);
|
||||
tl.fromTo("#el-04-limits", { x: 1080, opacity: 1 }, { x: 0, opacity: 1, duration: 0.5, ease: "power3.inOut" }, 20.895);
|
||||
tl.to("#el-04-limits", { x: -1080, duration: 0.5, ease: "power3.inOut" }, 27.494);
|
||||
tl.fromTo("#el-05-apps", { x: 1080, opacity: 1 }, { x: 0, opacity: 1, duration: 0.5, ease: "power3.inOut" }, 27.494);
|
||||
tl.to("#el-05-apps", { x: -1080, duration: 0.5, ease: "power3.inOut" }, 33.197);
|
||||
tl.fromTo("#el-06-location", { x: 1080, opacity: 1 }, { x: 0, opacity: 1, duration: 0.5, ease: "power3.inOut" }, 33.197);
|
||||
tl.to("#el-06-location", { opacity: 0, duration: 0.5, ease: "power2.inOut" }, 39.71);
|
||||
tl.fromTo("#el-07-balance", { opacity: 0 }, { opacity: 1, duration: 0.5, ease: "power2.inOut" }, 39.71);
|
||||
tl.to("#el-07-balance", { opacity: 0, duration: 0.5, ease: "power2.inOut" }, 45.178);
|
||||
tl.fromTo("#el-08-platforms", { opacity: 0 }, { opacity: 1, duration: 0.5, ease: "power2.inOut" }, 45.178);
|
||||
tl.to("#el-08-platforms", { scale: 2.5, opacity: 0, filter: "blur(8px)", duration: 0.4, ease: "power3.in" }, 48.961);
|
||||
tl.fromTo("#el-09-cta", { scale: 0.5, opacity: 0, filter: "blur(8px)" }, { scale: 1, opacity: 1, filter: "blur(0px)", duration: 0.4, ease: "power3.out" }, 48.961);
|
||||
tl.to({}, { duration: 54.733 }, 0); // full-span anchor — main.duration() == composition total (Studio master duration)
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"id": "lookatu-promo",
|
||||
"name": "lookatu-promo",
|
||||
"createdAt": "2026-10-14T22:04:45.006Z"
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "lookatu-promo",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "npx --yes hyperframes@0.8.158 preview",
|
||||
"check": "npx --yes hyperframes@0.8.158 check",
|
||||
"render": "npx --yes hyperframes@0.8.158 render",
|
||||
"publish": "npx --yes hyperframes@0.8.158 publish"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Reference in new issue
Block a user