From ls-clad
Search the Google Fonts catalog by style/mood and import/apply font assets to Text/Text3D components in a Lens Studio project. Use when adding typography to a UI panel, theming text to match a mood, or applying a specific font family by name.
How this skill is triggered — by the user, by Claude, or both
Slash command
/ls-clad:font-selector a description of the font feel (e.g., "modern clean sans-serif for game HUD", "playful handwriting for kids Lens") or an exact family name (e.g., "Roboto", "Playfair Display")a description of the font feel (e.g., "modern clean sans-serif for game HUD", "playful handwriting for kids Lens") or an exact family name (e.g., "Roboto", "Playfair Display")The summary Claude sees in its skill listing — used to decide when to auto-load this skill
<!--
Search the Google Fonts database for a font matching the user's description, then import the family into the active Lens Studio project as a Font asset and (optionally) apply it to Text / Text3D components on a target SceneObject.
Backed by the FontSelector MCP tool — it handles network fetch, asset import, .meta generation, and live application to text components inside Lens Studio. Tool naming, deferred schemas, and ask/spawn semantics: see lens-studio-field-notes Hard Rule 2 / Cross-runtime orchestration.
Not auto-invoked by any orchestrator. Typography is a discretionary asset — if you want a themed font in an experience built by specs-experience-builder, run /font-selector yourself (before or after the build), then re-invoke /specs-build-ui with the imported path as theme_font_path so the generated UI module bakes the requireAsset(...) as Font reference.
When the next step is regenerating a UI module via
/specs-build-ui, use Step 2 in import-only mode (omitsceneObjectId) and pass the imported path to/specs-build-uiastheme_font_path. The script'srequireAsset(...) as Fontbecomes the source of truth and the runtimet.font = THEME_FONTassignment wins. Inspector apply (sceneObjectIdpassed in) is for ad-hoc swaps in an already-generated UI; if you Inspector-apply a font that doesn't match what<Name>UI.tsrequireAssets, the font reverts on the next reload.
When the user gives a description (not an exact family name), search the catalog. Search returns up to 10 fonts per page with a visual preview image showing each font rendering a pangram — use this to compare candidates by eye, not just by name.
FontSelector({ query: "modern clean sans-serif", category: "sans-serif" })
| Parameter | Notes |
|---|---|
query | Free-text search across name, style descriptors, and mood (e.g., "elegant serif", "playful handwriting", "tech monospace"). Required for search mode. |
category | Optional. One of: sans-serif, serif, display, handwriting, monospace. Use when the user signaled a category — e.g., "monospace for the score" → category: "monospace". Omit when the description is general ("modern, clean"). |
page | Optional, 1-indexed. Use when the first 10 results don't include a fit and the response indicates more pages. |
Pick by visual fit, not vibes alone. The pangram preview is the source of truth — letter shapes, weight, x-height, geometric vs humanist character. If the user said "futuristic" and the top result is a humanist sans, scroll the preview list before applying.
If the user gave an exact family name (e.g., "Roboto", "Playfair Display", "JetBrains Mono"), skip search — jump straight to Step 2.
Call with family to download the font, import it as a Lens Studio Font asset, and apply it to text components.
FontSelector({ family: "Inter" })
| Parameter | Notes |
|---|---|
family | Exact family name as returned by search (or as named in Google Fonts). Case-sensitive — "Open Sans", not "open sans". |
sceneObjectId | Optional UUID. The font is applied to every Text / Text3D component found inside that SceneObject's subtree. If omitted, applies to the currently selected text components. |
category | Optional, used to disambiguate when multiple families share a name. Rarely needed. |
Three apply modes:
sceneObjectId of a UI root or HUD container. Best when the orchestrator already knows the UUID (Phase 3 bootstrap returns it). Recursive: every nested Component.Text / Component.Text3D under that root gets the new font.sceneObjectId; the user pre-selects the target text components in the Scene Hierarchy panel. Best for ad-hoc tweaks during interactive sessions.sceneObjectId and ensure no text components are selected. The font asset is downloaded and imported but nothing is rewired. Useful when a script will reference the font via requireAsset(...) and you just need the file on disk.After Step 2, confirm the asset landed and reflect the actual filename in any downstream requireAsset calls. The MCP tool typically writes to Assets/Fonts/<Family>.ttf (spaces become underscores or are preserved — check the tool response). The tool response includes the imported asset path; verify the filename matches before using it in requireAsset calls.
If verification fails:
errors field. Most commonly the family name was misspelled (case mismatch, missing space, e.g., "OpenSans" instead of "Open Sans"). Re-search to confirm the exact name.LFS gotcha (consumer repo): if the target Lens Studio project's .gitattributes sends Assets/** through git-lfs, a fresh clone without git lfs pull resolves font assets to pointer text and Lens Studio fails to load them. Add Assets/Fonts/*.ttf !filter !diff !merge (and *.otf if used) to the consumer repo's .gitattributes so font files are stored inline.
Once imported, reference the font in TypeScript via requireAsset and assign it to Component.Text / Component.Text3D:
const HUD_FONT = requireAsset("../Fonts/Inter.ttf") as Font;
const label = obj.createComponent("Component.Text") as Text;
label.font = HUD_FONT;
Rules:
"Inter.ttf" if the actual file is "Inter-Regular.ttf" or "Inter Variable.ttf". Read the tool response.as Font cast is required — requireAsset returns the base asset type.HUD_FONT once at module scope and assign by reference. No need to re-requireAsset per component.When the caller provides a theme (style, mood, palette) — for example the Specs orchestrator's theme block — derive the search query from mood + style + intended surface (e.g., mood: tense, gritty sci-fi → "industrial wide condensed, mechanical futuristic", category: display). For quick surface-to-family picks, see references/font-catalog.md → Specs-specific picks by surface.
Score/timer HUDs in particular want a monospace family — non-monospace digits change width as the value updates (9 → 10 → 99), causing the label to jitter or reflow. Even if theme.style is humanist, override to monospace for purely-numeric HUDs.
curl / wget and dropping a .ttf into Assets/Fonts/ manually. The Lens Studio asset pipeline needs the .meta file the MCP tool generates — a hand-placed file is invisible to the project and requireAsset fails with InternalError: Cannot find asset. Always go through the MCP tool.family: with a hallucinated name. Google Fonts has ~1500 families; "Modern Sans" and "Tech Mono" sound plausible but don't exist. Search first when in doubt — the visual preview both confirms the family exists and shows what it looks like.sceneObjectId per region) — don't blast one family across the whole UI subtree.npx claudepluginhub lens-studio-devs/ls-extensions --plugin ls-cladGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.