Static HTML preview

Loads the tokenized HTML from /api/v1/templates/:name/:version/template.html and substitutes {{namespace.field}} tokens, expands <template data-mstly-each="X"> loops, and renders/drops <template data-mstly-if="path"> blocks (truthy check) against a mock payload. The result renders inside an iframe with the variant CSS applied so you can verify the static rendering shape that server-side template engines will produce.

version 1.0.0 profile

User profile with banner, avatar header, stats, bio, badges, links, and recent activity.

Render settings

With formatting on, the page formats counts (12.4k), engagement rates (4.8%), deltas (↑ +5.8%), and dates (Apr 22, 2026) on your behalf — what most consumers will do downstream. Off emits raw values, matching the strict tokenized contract.

Mock data (JSON)

Rendered iframe

Substituted HTML
<div class="mfly-profile" part="card">
  <div class="mfly-profile__banner" part="banner" style="background-image:url(https://mostly-uk.b-cdn.net/myframely/template/profile-cover.png)"></div>
  <div class="mfly-profile__header">
    <div class="mfly-profile__avatarWrap">
      <img class="mfly-profile__avatar" part="avatar" src="https://mostly-uk.b-cdn.net/myframely/template/amelia-chen-avatar-200.png" alt="" loading="lazy">
      <span class="mfly-profile__status" part="status" data-status="online" aria-label="online"></span>
    </div>
    <div class="mfly-profile__identity">
      <h1 class="mfly-profile__name" part="name">Amelia Chen</h1>
      <p class="mfly-profile__handle" part="handle">@ameliachenvfx</p>
      <p class="mfly-profile__role" part="role">Senior FX Artist / TD at DNEG</p>
    </div>
  </div>
  <div class="mfly-profile__body">
    <p class="mfly-profile__bio" part="bio">Senior FX Artist specialising in Houdini procedural FX, volumetrics, and dynamics simulation. 10+ years in high-end VFX for film &amp; TV. Mentor, pipeline tinkerer, sim nerd.</p>
    <div class="mfly-profile__meta" part="meta">
      <span>📍 London, UK</span>
      <span>Joined Sep 14, 2020</span>
    </div>
    <div class="mfly-profile__stats" part="stats">
      <div class="mfly-profile__stat">
        <strong class="mfly-profile__statValue">64</strong>
        <span class="mfly-profile__statLabel">Posts</span>
        <span class="mfly-profile__statDelta" data-dir="up">↑ +12.5%</span>
      </div>
      <div class="mfly-profile__stat">
        <strong class="mfly-profile__statValue">8,420</strong>
        <span class="mfly-profile__statLabel">Followers</span>
        <span class="mfly-profile__statDelta" data-dir="up">↑ +3.2%</span>
      </div>
      <div class="mfly-profile__stat">
        <strong class="mfly-profile__statValue">412</strong>
        <span class="mfly-profile__statLabel">Following</span>
        <span class="mfly-profile__statDelta" data-dir="up">↑ +0.5%</span>
      </div>
    </div>
    <div class="mfly-profile__badges" part="badges">
      
        <span class="mfly-profile__badge" style="color:#2563eb;border-color:#2563eb">Verified</span>
      
        <span class="mfly-profile__badge" style="color:#0d9488;border-color:#0d9488">Senior FX</span>
      
        <span class="mfly-profile__badge" style="color:#d97706;border-color:#d97706">Mentor</span>
      
    </div>
    <ul class="mfly-profile__links" part="links">
      
        <li><a class="mfly-profile__link" part="link" href="https://www.ameliachenvfx.com" target="_blank" rel="noopener nofollow">Portfolio</a></li>
      
        <li><a class="mfly-profile__link" part="link" href="https://imdb.com/name/nm9238745" target="_blank" rel="noopener nofollow">IMDb</a></li>
      
    </ul>
    <div class="mfly-profile__activityTitle">Recent activity</div>
    <ul class="mfly-profile__activity" part="activity">
      
        <li class="mfly-profile__activityItem">
          <a href="https://www.ameliachenvfx.com/breakdowns/peripheral-smoke" target="_blank" rel="noopener nofollow">Posted: Procedural smoke setup for &#39;The Peripheral&#39; — breakdown</a>
          <span class="mfly-profile__activityAt">2026-04-23T14:20:00.000Z</span>
        </li>
      
        <li class="mfly-profile__activityItem">
          <a href="" target="_blank" rel="noopener nofollow">Followed Side Effects Software</a>
          <span class="mfly-profile__activityAt">2026-04-13T09:05:00.000Z</span>
        </li>
      
        <li class="mfly-profile__activityItem">
          <a href="https://github.com/ameliachenvfx/cloth-tear-hda" target="_blank" rel="noopener nofollow">Posted: Cloth-tear HDA — open-sourced on GitHub</a>
          <span class="mfly-profile__activityAt">2026-03-22T16:48:00.000Z</span>
        </li>
      
    </ul>
  </div>
</div>
Tokenized HTML (as served by the API)
<div class="mfly-profile" part="card">
  <div class="mfly-profile__banner" part="banner" style="background-image:url({{user.bannerUrl}})"></div>
  <div class="mfly-profile__header">
    <div class="mfly-profile__avatarWrap">
      <img class="mfly-profile__avatar" part="avatar" src="{{user.avatarUrl}}" alt="" loading="lazy">
      <span class="mfly-profile__status" part="status" data-status="{{user.status}}" aria-label="{{user.status}}"></span>
    </div>
    <div class="mfly-profile__identity">
      <h1 class="mfly-profile__name" part="name">{{user.displayName}}</h1>
      <p class="mfly-profile__handle" part="handle">@{{user.handle}}</p>
      <p class="mfly-profile__role" part="role">{{user.role}}</p>
    </div>
  </div>
  <div class="mfly-profile__body">
    <p class="mfly-profile__bio" part="bio">{{user.bio}}</p>
    <div class="mfly-profile__meta" part="meta">
      <span>📍 {{user.location}}</span>
      <span>Joined {{user.joinedAt}}</span>
    </div>
    <div class="mfly-profile__stats" part="stats">
      <div class="mfly-profile__stat">
        <strong class="mfly-profile__statValue">{{stats.posts}}</strong>
        <span class="mfly-profile__statLabel">Posts</span>
        <span class="mfly-profile__statDelta" data-dir="{{statsDelta.posts.dir}}">{{statsDelta.posts}}</span>
      </div>
      <div class="mfly-profile__stat">
        <strong class="mfly-profile__statValue">{{stats.followers}}</strong>
        <span class="mfly-profile__statLabel">Followers</span>
        <span class="mfly-profile__statDelta" data-dir="{{statsDelta.followers.dir}}">{{statsDelta.followers}}</span>
      </div>
      <div class="mfly-profile__stat">
        <strong class="mfly-profile__statValue">{{stats.following}}</strong>
        <span class="mfly-profile__statLabel">Following</span>
        <span class="mfly-profile__statDelta" data-dir="{{statsDelta.following.dir}}">{{statsDelta.following}}</span>
      </div>
    </div>
    <div class="mfly-profile__badges" part="badges">
      <template data-mstly-each="badges">
        <span class="mfly-profile__badge" style="color:{{badges.color}};border-color:{{badges.color}}">{{badges.label}}</span>
      </template>
    </div>
    <ul class="mfly-profile__links" part="links">
      <template data-mstly-each="links">
        <li><a class="mfly-profile__link" part="link" href="{{links.href}}" target="_blank" rel="noopener nofollow">{{links.label}}</a></li>
      </template>
    </ul>
    <div class="mfly-profile__activityTitle">Recent activity</div>
    <ul class="mfly-profile__activity" part="activity">
      <template data-mstly-each="activity">
        <li class="mfly-profile__activityItem">
          <a href="{{activity.href}}" target="_blank" rel="noopener nofollow">{{activity.title}}</a>
          <span class="mfly-profile__activityAt">{{activity.at}}</span>
        </li>
      </template>
    </ul>
  </div>
</div>
Variant CSS
:host {
  --mfly-font-family: inherit;
  --mfly-font-size: 14px;
  --mfly-text-color: #111827;
  --mfly-muted-color: #6b7280;
  --mfly-bg: #ffffff;
  --mfly-surface: #ffffff;
  --mfly-border: 1px solid #e5e7eb;
  --mfly-accent: #2563eb;
  --mfly-radius: 10px;
  --mfly-profile-banner-height: 180px;
  --mfly-profile-avatar-size: 96px;

  display: block;
  max-width: var(--mfly-max-width, 720px);
  font-family: var(--mfly-font-family);
  font-size: var(--mfly-font-size);
  color: var(--mfly-text-color);
}
:host([theme="dark"]) {
  --mfly-text-color: #f3f4f6;
  --mfly-muted-color: #9ca3af;
  --mfly-bg: #111827;
  --mfly-surface: #1f2937;
  --mfly-border: 1px solid #374151;
  --mfly-accent: #60a5fa;
}
@media (prefers-color-scheme: dark) {
  :host([theme="auto"]) {
    --mfly-text-color: #f3f4f6;
    --mfly-muted-color: #9ca3af;
    --mfly-bg: #111827;
    --mfly-surface: #1f2937;
    --mfly-border: 1px solid #374151;
    --mfly-accent: #60a5fa;
  }
}

.mfly-profile {
  display: block;
  background: var(--mfly-bg);
  border: var(--mfly-border);
  border-radius: var(--mfly-radius);
  overflow: hidden;
  box-sizing: border-box;
}
.mfly-profile *, .mfly-profile *::before, .mfly-profile *::after { box-sizing: border-box; }

.mfly-profile__banner {
  width: 100%;
  height: var(--mfly-profile-banner-height);
  background: #e5e7eb;
  background-size: cover;
  background-position: center;
  display: block;
}
:host([theme="dark"]) .mfly-profile__banner { background-color: #374151; }

.mfly-profile__header {
  position: relative;
  padding: 0 20px;
  margin-top: calc(-1 * (var(--mfly-profile-avatar-size) / 2));
  display: flex;
  align-items: flex-end;
  gap: 16px;
}
.mfly-profile__avatarWrap {
  position: relative;
  flex: 0 0 var(--mfly-profile-avatar-size);
  width: var(--mfly-profile-avatar-size);
  height: var(--mfly-profile-avatar-size);
}
.mfly-profile__avatar {
  width: var(--mfly-profile-avatar-size);
  height: var(--mfly-profile-avatar-size);
  border-radius: 50%;
  border: 4px solid var(--mfly-bg);
  object-fit: cover;
  background: #d1d5db;
  display: block;
}
/* Status dot — hidden by default; templates that want it (inline) opt in. */
.mfly-profile__status {
  display: none;
  position: absolute;
  right: 2px;
  bottom: 2px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  border: 2px solid var(--mfly-bg);
  background: #9ca3af;
}
.mfly-profile__status[data-status="online"] { background: #10b981; }
.mfly-profile__status[data-status="offline"] { background: #9ca3af; }
.mfly-profile__status[data-status="away"] { background: #f59e0b; }
.mfly-profile__status[data-status="busy"] { background: #ef4444; }
/* Role line — hidden by default (inline + dashboard opt in). */
.mfly-profile__role {
  display: none;
  margin: 2px 0 0;
  font-size: 0.9em;
  color: var(--mfly-muted-color);
}
/* Stat delta — hidden by default (dashboard opts in). */
.mfly-profile__statDelta {
  display: none;
  font-size: 0.8em;
  font-weight: 600;
}
.mfly-profile__statDelta[data-dir="up"] { color: #059669; }
.mfly-profile__statDelta[data-dir="down"] { color: #dc2626; }
:host([theme="dark"]) .mfly-profile__statDelta[data-dir="up"] { color: #34d399; }
:host([theme="dark"]) .mfly-profile__statDelta[data-dir="down"] { color: #f87171; }
.mfly-profile__identity {
  flex: 1 1 auto;
  min-width: 0;
  padding-bottom: 12px;
}
.mfly-profile__name {
  margin: 0;
  font-size: 1.25em;
  font-weight: 700;
  line-height: 1.2;
  color: var(--mfly-text-color);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mfly-profile__handle {
  margin: 2px 0 0;
  font-size: 0.95em;
  color: var(--mfly-muted-color);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mfly-profile__body { padding: 12px 20px 20px; }

.mfly-profile__bio {
  margin: 0 0 12px;
  font-size: 1em;
  line-height: 1.5;
  color: var(--mfly-text-color);
  white-space: pre-wrap;
}
.mfly-profile__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 16px;
  margin-bottom: 14px;
  font-size: 0.9em;
  color: var(--mfly-muted-color);
}
.mfly-profile__meta > span {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.mfly-profile__stats {
  display: flex;
  gap: 20px;
  padding: 12px 0;
  border-top: var(--mfly-border);
  border-bottom: var(--mfly-border);
  margin: 0 0 14px;
}
.mfly-profile__stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.mfly-profile__stat > strong {
  font-size: 1.1em;
  font-weight: 700;
  color: var(--mfly-text-color);
}
.mfly-profile__stat > span {
  font-size: 0.85em;
  color: var(--mfly-muted-color);
}

.mfly-profile__badges {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 14px;
}
.mfly-profile__badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 0.8em;
  font-weight: 600;
  background: var(--mfly-surface);
  border: var(--mfly-border);
  color: var(--mfly-muted-color);
}

.mfly-profile__links {
  list-style: none;
  padding: 0;
  margin: 0 0 14px;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 12px;
}
.mfly-profile__link {
  color: var(--mfly-accent);
  text-decoration: none;
  font-size: 0.95em;
}
.mfly-profile__link:hover { text-decoration: underline; }

.mfly-profile__activityTitle {
  margin: 0 0 8px;
  font-size: 0.85em;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--mfly-muted-color);
}
.mfly-profile__activity {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.mfly-profile__activityItem {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 12px;
  background: var(--mfly-surface);
  border: var(--mfly-border);
  border-radius: calc(var(--mfly-radius) - 4px);
}
.mfly-profile__activityItem a {
  color: var(--mfly-text-color);
  text-decoration: none;
  font-weight: 500;
}
.mfly-profile__activityItem a:hover { text-decoration: underline; }
.mfly-profile__activityAt {
  font-size: 0.8em;
  color: var(--mfly-muted-color);
}

/* Skeleton */
.mfly-profile__skeleton .mfly-profile__banner,
.mfly-profile__skeleton .mfly-profile__avatar,
.mfly-profile__skeleton .mfly-profile__skelLine,
.mfly-profile__skeleton .mfly-profile__skelStat {
  background-color: #e5e7eb;
  background-image: linear-gradient(90deg, #e5e7eb 0%, #f3f4f6 50%, #e5e7eb 100%);
  background-size: 200% 100%;
  animation: mflyShimmer 1.4s linear infinite;
}
:host([theme="dark"]) .mfly-profile__skeleton .mfly-profile__banner,
:host([theme="dark"]) .mfly-profile__skeleton .mfly-profile__avatar,
:host([theme="dark"]) .mfly-profile__skeleton .mfly-profile__skelLine,
:host([theme="dark"]) .mfly-profile__skeleton .mfly-profile__skelStat {
  background-color: #374151;
  background-image: linear-gradient(90deg, #374151 0%, #4b5563 50%, #374151 100%);
}
.mfly-profile__skelLine {
  height: 12px;
  border-radius: 6px;
  margin-bottom: 8px;
}
.mfly-profile__skelLine--name { width: 40%; height: 18px; }
.mfly-profile__skelLine--handle { width: 25%; }
.mfly-profile__skelLine--bio { width: 90%; }
.mfly-profile__skelLine--bio2 { width: 70%; }
.mfly-profile__skelStats {
  display: flex; gap: 20px; padding: 12px 0;
  border-top: var(--mfly-border); border-bottom: var(--mfly-border);
  margin: 8px 0 14px;
}
.mfly-profile__skelStat { width: 60px; height: 36px; border-radius: 6px; }
@keyframes mflyShimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* Error overlay. debug="1" gets a red monospace block; otherwise a muted
   error line so a consumer with a broken adapter sees something. */
.mfly-profile__error {
  padding: 12px 16px;
  border-radius: calc(var(--mfly-radius) - 2px);
  background: var(--mfly-surface);
  border: var(--mfly-border);
  color: var(--mfly-muted-color);
  font-size: 0.9em;
  line-height: 1.4;
}
:host([debug="1"]) .mfly-profile__error {
  color: #b91c1c;
  background: #fef2f2;
  border-color: #fecaca;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  font-size: 0.85em;
  white-space: pre-wrap;
  word-break: break-word;
}
@media (prefers-color-scheme: dark) {
  :host([theme="auto"][debug="1"]) .mfly-profile__error,
  :host([theme="dark"][debug="1"]) .mfly-profile__error {
    color: #fecaca;
    background: #7f1d1d;
    border-color: #991b1b;
  }
}