Brand Mark (Lantern Flame) Audit โ
Last updated: 2026-06-22
This doc tracks the Lantern flame across the codebase. As of this change there are zero lucide-react Flame icons left: every flame is the custom Lantern silhouette, and a lint rule blocks the lucide Flame from coming back.
The decision โ
We replaced the stock lucide-react Flame icon (a generic open, stroked flame thousands of apps use) with a custom solid-silhouette flame everywhere the flame appears: brand logos, app icons, splash, the beacon, the nav hub, hero badges, AND the small inline glyphs (offer badges, map markers, count pills, step icons, the venue-category lantern icon).
- Shape only. The sacred brand amber
#f59e0bis unchanged. We swapped the silhouette, not the color. Small glyphs still take their color from their context (a Tailwindtext-*class). - One flame everywhere. Earlier we kept lucide for small glyphs; that was reversed in favor of a single consistent mark at every size, enforced by lint.
What to use (single source of truth) โ
The flame geometry lives in one place. Never hand-draw the flame or import the lucide Flame.
| Need | Use | Notes |
|---|---|---|
| The amber brand logo (auth, loading, headers, app-icon tiles) | <LanternLogo size glow /> (@lantern/ui/LanternLogo) | Amber fill + optional glow, role="img". |
An inline flame glyph in UI (badges, markers, buttons, list icons, icon={...} props) | <FlameMark size className /> (@lantern/ui/FlameMark) | Color comes from currentColor (set a text-* class). Drop-in for the old <Flame>; works as icon={FlameMark}. Accepts a fill override. |
| A custom treatment (gradient, specific color, nested in another SVG) | LANTERN_FLAME_PATH + LANTERN_FLAME_VIEWBOX (@lantern/ui/lanternFlame) | The raw path + viewBox. Used by LanternLogo, FlameMark, the beacon, the hub, email/SVG assets. |
| A static asset (favicon, splash, HTML email) | inline copy of the path | Cannot import; each carries the path with a comment pointing to lanternFlame.js. Keep in sync. |
Enforcement (the proactive guardrail) โ
.eslintrc.json bans the lucide Flame via no-restricted-imports:
import { Flame } from 'lucide-react' // ESLint errorThe error message points to LanternLogo / FlameMark / lanternFlame. This is what keeps future integrations from quietly reintroducing the stock flame; it runs as part of npm run lint (and therefore npm run validate / pre-push). Adding a new flame to the UI means reaching for FlameMark or LanternLogo.
Where the mark appears โ
Grouped for orientation; all of these now render the silhouette.
| Group | Locations |
|---|---|
| Brand logo component | packages/ui/LanternLogo.jsx (auth, loading, headers, app-icon tiles app-wide) |
| Inline glyph component | packages/ui/FlameMark.jsx (the drop-in used by the swaps below) |
| Canonical geometry | packages/ui/lanternFlame.js (LANTERN_FLAME_PATH, LANTERN_FLAME_VIEWBOX) |
| Favicons / PWA / splash | apps/web/public/icons/*, apps/admin/public/icons/*, docs/public/icons/*, apps/site/public/lantern-flame.svg, apps/web/index.html (splash) |
| App chrome | HomeView header, DashboardNavigation hub (resting/armed/lit), LanternBeacon, AccessGate (loading/sign-in/maintenance via LanternLogo; denied dimmed gray), LightLanternModal, LandingPage masthead + steps, InfoSupport hero + steps |
| Inline glyphs (FlameMark) | venue map markers (VenuesMap), lantern-count badges (VenuePicker, HomeView, VenueView, offer cards), "Meet"/wave (Chat, WaveManager), light/schedule forms, profile name labels, frens tab/banners, admin metric + tab icons (SystemHealth, Billing, BillingReports, VenueActivityDashboard, merchant Overview), RecentActivityView event icon |
| Offer-card flames | packages/ui/offers/FlamePulse.jsx, LivingFlame.jsx, BurningHotCard.jsx, StorefrontShell.jsx, ClassicHeroCard.jsx, OfferCards.jsx |
| Icon vocabulary (SSOT) | packages/ui/icons.js (lantern mood category, unknown-category fallback). The GCP provider uses CloudCog, not the flame. |
| Composite illustration | apps/admin/src/admin/chat/LanternChat.jsx (flame fitted inside the old-lantern frame) |
services/api/auth/src/lib/email.js, services/functions/firebase/lib/email.js, email-preview.html | |
| Marketing site | apps/site/index.html, apps/site/src/shared/chrome.js |
| Storybook specimens | CallToAction.stories.jsx, StickyBottomCTA.stories.jsx, Primitives.stories.jsx, FlameMark.stories.jsx, Brand.stories.jsx |
Known follow-ups / oddities โ
- LivingFlame / LanternChat: the animated "dying" flame and the flame-in-a-lantern illustration were tuned around the old 24-unit viewBox; the silhouette is fitted via its own viewBox, so ember/shimmer offsets may want a small visual touch-up if they look off.
How to audit again โ
Run from the repo root. Match <Flame without a trailing-character class (to catch multi-line tags), and filter out the <FlamePulse> component:
# Any lucide flame left as a component or icon value (should be empty):
grep -rn "<Flame" --include="*.jsx" . | grep -v node_modules | grep -v "FlamePulse"
grep -rnE "from ['\"]lucide-react['\"]" --include="*.jsx" --include="*.js" . | grep -v node_modules | grep "\bFlame\b"
# Inline path literal (old lucide flame), should be empty:
grep -rn "M8.5 14.5" --include="*.jsx" --include="*.js" --include="*.svg" --include="*.html" . | grep -v node_modules
# Files carrying the silhouette path:
grep -rn "233.2,58.8" --include="*.svg" --include="*.html" --include="*.jsx" --include="*.js" . | grep -v node_modules