7ed2ccc414
The reference-round workflow, run end to end for a real template: Taste system (how we learn the user's taste, persisted): - references/TASTE_PROFILE.md (living design contract) + references/README.md (the daily loop) + a "reference round" stage in docs/TEMPLATE_BRIEF.md (provide refs or I suggest+mock directions). Design-quality before/after: - HeroDemo — the fix recipe vs the faint default: layered-depth background, a proper big video type scale, and a bold composed focal object. (Backgrounds were naked, text too small, scenes had no objects.) - YaldaSofreh3D + IGPromoDirections + IGProfileMock — reference-match proofs (low-poly 3D, 3 IG-promo style directions, the realistic IG-light page). Instagram channel-promo template (the deliverable — a flexible 5-scene FlexStory): - igkit + 5 blocks: IGIntro, IGProfile (realistic IG-light profile, scales to all aspects), IGFeed (post grid), IGStats (animated count-up), IGFollowCTA (Follow taps to "Following"). - FlexStory gains a `finish` toggle so the IG-light scenes render clean (no brand grade). INSTAGRAM_PROMO preset + 3 aspect comps in Root. Verified: a still of every scene at 9:16 renders clean; full preview MP4 rendering. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
118 lines
8.3 KiB
TypeScript
118 lines
8.3 KiB
TypeScript
import React from "react";
|
||
import { AbsoluteFill } from "remotion";
|
||
import { FONT } from "../lib/fonts";
|
||
import { hexToRgba } from "../lib/anim";
|
||
|
||
/**
|
||
* IGProfileMock — an authentic Instagram profile page (LIGHT theme) inside a phone,
|
||
* as the centrepiece of a "follow our page" promo. Real IG chrome: status bar, the
|
||
* username header, avatar + stats, bio, Follow/Message buttons, story highlights,
|
||
* the grid tabs and the posts grid. Everything here is an editable field later.
|
||
*/
|
||
const IGLOGO = "linear-gradient(45deg,#f09433,#e6683c,#dc2743,#cc2366,#bc1888)";
|
||
const BLUE = "#0095f6";
|
||
const HANDLE = "flat.studio";
|
||
const NAME = "استودیو فلت";
|
||
const CAT = "هنر و طراحی";
|
||
const BIO = ["هر روز یک طرح تازه ✨", "آموزش، قالب و الهام برای طراحان", "سفارش و دانلود 👇"];
|
||
const LINK = "flat.studio/shop";
|
||
const HILITES = ["جدید", "قالبها", "آموزش", "نمونهکار"];
|
||
const POSTS = ["#ff5a3c", "#7c5cff", "#16b5a0", "#ffb23c", "#ef5da8", "#3aa0ff", "#ff7a59", "#4cd4b0", "#a06bff", "#ff5a3c", "#3aa0ff", "#ffb23c"];
|
||
|
||
const IgCamera: React.FC<{ s: number }> = ({ s }) => (
|
||
<svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="url(#ig)" strokeWidth="2">
|
||
<defs><linearGradient id="ig" x1="0" y1="1" x2="1" y2="0"><stop offset="0" stopColor="#f09433" /><stop offset="0.5" stopColor="#dc2743" /><stop offset="1" stopColor="#bc1888" /></linearGradient></defs>
|
||
<rect x="2" y="2" width="20" height="20" rx="6" /><circle cx="12" cy="12" r="5" /><circle cx="17.5" cy="6.5" r="1.2" fill="url(#ig)" stroke="none" />
|
||
</svg>
|
||
);
|
||
|
||
const Stat: React.FC<{ n: string; l: string }> = ({ n, l }) => (
|
||
<div style={{ textAlign: "center" }}>
|
||
<div style={{ fontWeight: 800, fontSize: 38, color: "#000" }}>{n}</div>
|
||
<div style={{ fontWeight: 400, fontSize: 27, color: "#262626" }}>{l}</div>
|
||
</div>
|
||
);
|
||
|
||
export const IGProfileMock: React.FC = () => {
|
||
const S = 770; // phone screen inner width
|
||
const cell = (S - 12) / 3;
|
||
return (
|
||
<AbsoluteFill style={{ fontFamily: FONT, background: "linear-gradient(165deg,#fdfcfb,#f3edf5)" }}>
|
||
<div style={{ position: "absolute", left: "-12%", top: "-6%", width: "55%", height: "34%", borderRadius: "50%", background: hexToRgba("#dc2743", 0.16), filter: "blur(150px)" }} />
|
||
<div style={{ position: "absolute", right: "-14%", bottom: "2%", width: "58%", height: "36%", borderRadius: "50%", background: hexToRgba("#7c5cff", 0.16), filter: "blur(160px)" }} />
|
||
|
||
{/* promo header: IG logo + headline */}
|
||
<div style={{ position: "absolute", top: 96, left: 0, right: 0, display: "flex", flexDirection: "column", alignItems: "center", gap: 18 }}>
|
||
<div style={{ display: "flex", alignItems: "center", gap: 16 }}>
|
||
<IgCamera s={64} />
|
||
<div style={{ fontWeight: 800, fontSize: 52, background: IGLOGO, WebkitBackgroundClip: "text", backgroundClip: "text", color: "transparent" }}>Instagram</div>
|
||
</div>
|
||
<div style={{ direction: "rtl", fontWeight: 900, fontSize: 64, color: "#15151a" }}>صفحهٔ ما را دنبال کنید</div>
|
||
</div>
|
||
|
||
{/* phone */}
|
||
<div style={{ position: "absolute", left: "50%", top: 300, transform: "translateX(-50%)", width: S + 36, borderRadius: 64, background: "#0c0c0f", padding: 18, boxShadow: "0 50px 100px rgba(20,12,30,0.4)" }}>
|
||
<div style={{ width: S, borderRadius: 48, background: "#fff", overflow: "hidden" }}>
|
||
{/* status bar */}
|
||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "16px 34px 6px", fontSize: 26, fontWeight: 700, color: "#000" }}>
|
||
<span>۹:۴۱</span><span style={{ display: "flex", gap: 10, alignItems: "center", fontSize: 24 }}>▮▮▮ <span style={{ fontSize: 22 }}>WiFi</span> <span style={{ border: "2px solid #000", borderRadius: 5, padding: "2px 6px", fontSize: 18 }}>۸۴٪</span></span>
|
||
</div>
|
||
{/* username header */}
|
||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "12px 28px" }}>
|
||
<div style={{ display: "flex", alignItems: "center", gap: 10, direction: "ltr" }}>
|
||
<span style={{ fontSize: 26 }}>🔒</span><span style={{ fontWeight: 800, fontSize: 36, color: "#000" }}>{HANDLE}</span><span style={{ fontSize: 24, color: "#000" }}>▾</span>
|
||
</div>
|
||
<div style={{ display: "flex", gap: 26, fontSize: 42, color: "#000" }}><span>+</span><span>☰</span></div>
|
||
</div>
|
||
{/* profile: avatar + stats */}
|
||
<div style={{ display: "flex", alignItems: "center", gap: 30, padding: "12px 34px" }}>
|
||
<div style={{ width: 176, height: 176, borderRadius: "50%", background: IGLOGO, padding: 6 }}>
|
||
<div style={{ width: "100%", height: "100%", borderRadius: "50%", background: "#eee", border: "5px solid #fff", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 78 }}>🎨</div>
|
||
</div>
|
||
<div style={{ flex: 1, display: "flex", justifyContent: "space-around" }}>
|
||
<Stat n="۳۲۰" l="پست" /><Stat n="۲۴٫۸ هزار" l="دنبالکننده" /><Stat n="۱۸۰" l="دنبالشده" />
|
||
</div>
|
||
</div>
|
||
{/* name + bio */}
|
||
<div style={{ direction: "rtl", padding: "6px 34px 0", color: "#000" }}>
|
||
<div style={{ fontWeight: 800, fontSize: 32 }}>{NAME}</div>
|
||
<div style={{ fontSize: 27, color: "#737373", marginTop: 2 }}>{CAT}</div>
|
||
{BIO.map((b, i) => <div key={i} style={{ fontSize: 28, marginTop: 4 }}>{b}</div>)}
|
||
<div style={{ fontSize: 28, color: "#00376b", fontWeight: 600, marginTop: 4, direction: "ltr", textAlign: "right" }}>{LINK}</div>
|
||
</div>
|
||
{/* buttons */}
|
||
<div style={{ display: "flex", gap: 12, padding: "20px 34px 8px" }}>
|
||
<div style={{ flex: 1, height: 76, borderRadius: 12, background: BLUE, color: "#fff", fontWeight: 800, fontSize: 30, display: "flex", alignItems: "center", justifyContent: "center" }}>دنبال کردن</div>
|
||
<div style={{ flex: 1, height: 76, borderRadius: 12, background: "#efefef", color: "#000", fontWeight: 700, fontSize: 30, display: "flex", alignItems: "center", justifyContent: "center" }}>پیام</div>
|
||
<div style={{ width: 76, height: 76, borderRadius: 12, background: "#efefef", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 34 }}>👤</div>
|
||
</div>
|
||
{/* highlights */}
|
||
<div style={{ display: "flex", gap: 28, padding: "16px 34px", direction: "rtl" }}>
|
||
{HILITES.map((h, i) => (
|
||
<div key={i} style={{ textAlign: "center" }}>
|
||
<div style={{ width: 120, height: 120, borderRadius: "50%", border: "2px solid #dbdbdb", background: i % 2 ? "#f3e9df" : "#e9eef5", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 46 }}>{["✨", "🗂️", "🎓", "🖼️"][i]}</div>
|
||
<div style={{ fontSize: 24, color: "#000", marginTop: 8 }}>{h}</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
{/* tabs */}
|
||
<div style={{ display: "flex", borderTop: "1px solid #dbdbdb", marginTop: 6 }}>
|
||
{["▦", "▶", "𓏬"].map((t, i) => (
|
||
<div key={i} style={{ flex: 1, textAlign: "center", padding: "18px 0", fontSize: 38, color: i === 0 ? "#000" : "#b3b3b3", borderTop: i === 0 ? "2px solid #000" : "none", marginTop: -1 }}>{t}</div>
|
||
))}
|
||
</div>
|
||
{/* posts grid */}
|
||
<div style={{ display: "grid", gridTemplateColumns: `repeat(3, ${cell}px)`, gap: 6 }}>
|
||
{POSTS.map((c, i) => (
|
||
<div key={i} style={{ width: cell, height: cell, background: c, display: "flex", alignItems: "center", justifyContent: "center", position: "relative" }}>
|
||
<div style={{ width: cell * 0.36, height: cell * 0.36, borderRadius: 12, background: hexToRgba("#fff", 0.4) }} />
|
||
{i % 4 === 0 ? <span style={{ position: "absolute", top: 10, right: 12, color: "#fff", fontSize: 30 }}>▶</span> : i % 4 === 1 ? <span style={{ position: "absolute", top: 10, right: 12, color: "#fff", fontSize: 26 }}>⧉</span> : null}
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</AbsoluteFill>
|
||
);
|
||
};
|