{
  "id": "studio-portfolio-hero",
  "kind": "template",
  "title": "Studio portfolio hero",
  "summary": "A bold intro for a design studio or freelancer: popping title, running ticker and an indexed work list.",
  "url": "https://enrichr.dev/templates/studio-portfolio-hero.html",
  "section": "page",
  "techniques": [
    "text-animation",
    "pointer-interaction"
  ],
  "stack": [
    "Vanilla JS",
    "CSS"
  ],
  "frameworks": [
    "React",
    "Next.js",
    "Vanilla"
  ],
  "mood": [
    "bold",
    "editorial"
  ],
  "intents": [
    "portfolio hero",
    "designer portfolio",
    "agency intro",
    "studio landing"
  ],
  "status": "preview",
  "params": [
    {
      "key": "headline",
      "label": "Headline",
      "type": "text",
      "value": "Studio North"
    }
  ],
  "license": "Free to use in personal and client projects during the preview. Final licence terms will be published here before any paid tier starts; ask before reselling the code as a collection.",
  "contract": "composition of elements, each mounted with mount(root, opts)",
  "exports": {
    "claude": "Add the \"Studio portfolio hero\" template (first screen) to this project.\n\nThis is the \"Studio portfolio hero\" template (first screen) from the Enrichr Library: A bold intro for a design studio or freelancer: popping title, running ticker and an indexed work list.\nPage: https://enrichr.dev/templates/studio-portfolio-hero.html\nMachine-readable spec: https://enrichr.dev/templates/studio-portfolio-hero.json\n\nTemplate contract: this is a composition of Enrichr elements. Each element follows mount(root, opts):\n- root is an empty container; set root.innerHTML to the element's markup, then call mount(root, opts). It returns { update(partialOpts), destroy() }.\n- The slots below say which container gets which element. Colour tokens: --lt-bg (background), --lt-fg (text), --lt-ac (accent), set on the stage from the palette.\n- slot \"hero\": Letter pop intro (https://enrichr.dev/elements/letter-pop-intro.json)\n- slot \"band\": Marquee ticker (https://enrichr.dev/elements/marquee-ticker.json)\n- slot \"body\": Rule sweep list (https://enrichr.dev/elements/rule-sweep-list.json)\n\nSteps:\n1. Look at the project first to see its framework and where components, styles and static files live. Follow its conventions.\n2. Fetch https://enrichr.dev/templates/studio-portfolio-hero.json if you can read URLs (fields: source.markup, source.css, source.js, params); otherwise use the source at the end of this message.\n3. Add the files, mount it where I tell you (default: the top of the home page), and pass the settings below as the opts.\n4. Keep the behaviour of the source unchanged. Do not add dependencies. Respect prefers-reduced-motion. Keep text as real HTML.\n5. Run the dev server and check it. with reduced motion on, nothing moves; it works at 375px wide and with touch only; there are no console errors; scrolling stays smooth; destroy() is called when it unmounts.\n\nSettings:\n{{SETTINGS}}\n\nSource:\n{{CODE}}",
    "chatgpt": "I want the \"Studio portfolio hero\" template (first screen) on my website. Below is its complete source. Please:\n1. Build one self-contained index.html that I can open locally to see it working (put the CSS in a <style> tag and the JavaScript in a <script> tag, with the markup in the body).\n2. Then explain, step by step, which parts go where in my own site, and how to mount it. My stack is: [tell me yours, or say \"plain HTML\"].\n3. Keep the behaviour of the source unchanged. Do not add dependencies. Respect prefers-reduced-motion. Keep text as real HTML.\n\nThis is the \"Studio portfolio hero\" template (first screen) from the Enrichr Library: A bold intro for a design studio or freelancer: popping title, running ticker and an indexed work list.\nPage: https://enrichr.dev/templates/studio-portfolio-hero.html\nMachine-readable spec: https://enrichr.dev/templates/studio-portfolio-hero.json\n\nTemplate contract: this is a composition of Enrichr elements. Each element follows mount(root, opts):\n- root is an empty container; set root.innerHTML to the element's markup, then call mount(root, opts). It returns { update(partialOpts), destroy() }.\n- The slots below say which container gets which element. Colour tokens: --lt-bg (background), --lt-fg (text), --lt-ac (accent), set on the stage from the palette.\n- slot \"hero\": Letter pop intro (https://enrichr.dev/elements/letter-pop-intro.json)\n- slot \"band\": Marquee ticker (https://enrichr.dev/elements/marquee-ticker.json)\n- slot \"body\": Rule sweep list (https://enrichr.dev/elements/rule-sweep-list.json)\n\nSettings:\n{{SETTINGS}}\n\nSource:\n{{CODE}}\n\nVerify: with reduced motion on, nothing moves; it works at 375px wide and with touch only; there are no console errors; scrolling stays smooth; destroy() is called when it unmounts.",
    "cursor": "Add the \"Studio portfolio hero\" template (first screen) to this codebase.\n\nThis is the \"Studio portfolio hero\" template (first screen) from the Enrichr Library: A bold intro for a design studio or freelancer: popping title, running ticker and an indexed work list.\nPage: https://enrichr.dev/templates/studio-portfolio-hero.html\nMachine-readable spec: https://enrichr.dev/templates/studio-portfolio-hero.json\n\nTemplate contract: this is a composition of Enrichr elements. Each element follows mount(root, opts):\n- root is an empty container; set root.innerHTML to the element's markup, then call mount(root, opts). It returns { update(partialOpts), destroy() }.\n- The slots below say which container gets which element. Colour tokens: --lt-bg (background), --lt-fg (text), --lt-ac (accent), set on the stage from the palette.\n- slot \"hero\": Letter pop intro (https://enrichr.dev/elements/letter-pop-intro.json)\n- slot \"band\": Marquee ticker (https://enrichr.dev/elements/marquee-ticker.json)\n- slot \"body\": Rule sweep list (https://enrichr.dev/elements/rule-sweep-list.json)\n\nUse Composer / agent mode. First search the repo for how components, styles and scripts are organised, then add the files in the matching places, mount it on the page I name, and run the app to confirm it works. Keep the behaviour of the source unchanged. Do not add dependencies. Respect prefers-reduced-motion. Keep text as real HTML.\n\nSettings:\n{{SETTINGS}}\n\nSource:\n{{CODE}}\n\nVerify: with reduced motion on, nothing moves; it works at 375px wide and with touch only; there are no console errors; scrolling stays smooth; destroy() is called when it unmounts.\n\nOptional: save this as .cursor/rules/enrichr-studio-portfolio-hero.mdc so the rule stays with the project:\n---\ndescription: How to use the Enrichr Studio portfolio hero template\nalwaysApply: false\n---\nEach slot is an Enrichr element: set the slot container's innerHTML to the element markup, then call mount(container, opts). Call destroy() on every instance on unmount.",
    "v0": "Create a Next.js (App Router) client component for the \"Studio portfolio hero\" template (first screen). Tailwind is available but this component needs no utility classes.\n\nThis is the \"Studio portfolio hero\" template (first screen) from the Enrichr Library: A bold intro for a design studio or freelancer: popping title, running ticker and an indexed work list.\nPage: https://enrichr.dev/templates/studio-portfolio-hero.html\nMachine-readable spec: https://enrichr.dev/templates/studio-portfolio-hero.json\n\nTemplate contract: this is a composition of Enrichr elements. Each element follows mount(root, opts):\n- root is an empty container; set root.innerHTML to the element's markup, then call mount(root, opts). It returns { update(partialOpts), destroy() }.\n- The slots below say which container gets which element. Colour tokens: --lt-bg (background), --lt-fg (text), --lt-ac (accent), set on the stage from the palette.\n- slot \"hero\": Letter pop intro (https://enrichr.dev/elements/letter-pop-intro.json)\n- slot \"band\": Marquee ticker (https://enrichr.dev/elements/marquee-ticker.json)\n- slot \"body\": Rule sweep list (https://enrichr.dev/elements/rule-sweep-list.json)\n\nFiles to create:\n- one <element-id>.js per element in the code below, each with  export { mount };  appended and  export const markup = \"<its markup string>\";  (add // @ts-nocheck on the first line under TypeScript).\n- every element's CSS goes in your global stylesheet (class names are global and start with ef-).\n\nUse this component as the wrapper (adjust the import paths):\n```tsx\n\"use client\";\nimport { useEffect, useRef } from \"react\";\nimport { markup as markup_letter_pop_intro, mount as mount_letter_pop_intro } from \"./letter-pop-intro\";\nimport { markup as markup_marquee_ticker, mount as mount_marquee_ticker } from \"./marquee-ticker\";\nimport { markup as markup_rule_sweep_list, mount as mount_rule_sweep_list } from \"./rule-sweep-list\";\n\nconst SLOTS = [\n  { slot: \"hero\", element: \"letter-pop-intro\", opts: {\"text\":\"$headline\",\"color\":\"$fg\",\"delay\":70} },\n  { slot: \"band\", element: \"marquee-ticker\", opts: {\"text\":\"Brand • Motion • Web •\",\"color\":\"$ac\",\"speed\":70} },\n  { slot: \"body\", element: \"rule-sweep-list\", opts: {\"items\":\"Selected work, Studio, Journal, Contact\",\"color\":\"$fg\",\"line\":\"$ac\"} },\n];\nconst REGISTRY: Record<string, { markup: string; mount: (root: HTMLElement, o: object) => { destroy: () => void } }> = {\n  \"letter-pop-intro\": { markup: markup_letter_pop_intro, mount: mount_letter_pop_intro },\n  \"marquee-ticker\": { markup: markup_marquee_ticker, mount: mount_marquee_ticker },\n  \"rule-sweep-list\": { markup: markup_rule_sweep_list, mount: mount_rule_sweep_list },\n};\n\n// Replace $headline, $fg, $ac and the like with your values and the palette before mounting.\nexport default function StudioPortfolioHero({ values }: { values: Record<string, string> }) {\n  const stage = useRef<HTMLDivElement>(null);\n  useEffect(() => {\n    const live: { destroy: () => void }[] = [];\n    stage.current?.querySelectorAll(\"[data-slot]\").forEach((host) => {\n      const s = SLOTS.find((x) => x.slot === host.getAttribute(\"data-slot\"));\n      if (!s) return;\n      const opts = Object.fromEntries(Object.entries(s.opts).map(([k, v]) => [k, typeof v === \"string\" ? v.replace(/\\$(\\w+)/g, (m, key) => values[key] ?? m) : v]));\n      host.innerHTML = REGISTRY[s.element].markup;\n      live.push(REGISTRY[s.element].mount(host as HTMLElement, opts));\n    });\n    return () => live.forEach((i) => i.destroy());\n  }, [JSON.stringify(values)]);\n  return (\n    <div ref={stage} style={{ background: values.bg, color: values.fg, position: \"relative\", overflow: \"hidden\" }}>\n      <div data-slot=\"hero\" />\n      <div data-slot=\"band\" />\n      <div data-slot=\"body\" />\n    </div>\n  );\n}\n```\n\nRender it on the home page so I can see it. Keep the behaviour of the source unchanged. Do not add dependencies. Respect prefers-reduced-motion. Keep text as real HTML.\n\nSettings:\n{{SETTINGS}}\n\nSource:\n{{CODE}}",
    "lovable": "Add the \"Studio portfolio hero\" template (first screen) to this React + Vite + TypeScript + Tailwind project. Do not install any packages.\n\nThis is the \"Studio portfolio hero\" template (first screen) from the Enrichr Library: A bold intro for a design studio or freelancer: popping title, running ticker and an indexed work list.\nPage: https://enrichr.dev/templates/studio-portfolio-hero.html\nMachine-readable spec: https://enrichr.dev/templates/studio-portfolio-hero.json\n\nTemplate contract: this is a composition of Enrichr elements. Each element follows mount(root, opts):\n- root is an empty container; set root.innerHTML to the element's markup, then call mount(root, opts). It returns { update(partialOpts), destroy() }.\n- The slots below say which container gets which element. Colour tokens: --lt-bg (background), --lt-fg (text), --lt-ac (accent), set on the stage from the palette.\n- slot \"hero\": Letter pop intro (https://enrichr.dev/elements/letter-pop-intro.json)\n- slot \"band\": Marquee ticker (https://enrichr.dev/elements/marquee-ticker.json)\n- slot \"body\": Rule sweep list (https://enrichr.dev/elements/rule-sweep-list.json)\n\nFiles to create:\n- one <element-id>.js per element in the code below, each with  export { mount };  appended and  export const markup = \"<its markup string>\";  (add // @ts-nocheck on the first line under TypeScript).\n- every element's CSS goes in your global stylesheet (class names are global and start with ef-).\n\nWrapper component (src/components/StudioPortfolioHero.tsx):\n```tsx\n\"use client\";\nimport { useEffect, useRef } from \"react\";\nimport { markup as markup_letter_pop_intro, mount as mount_letter_pop_intro } from \"./letter-pop-intro\";\nimport { markup as markup_marquee_ticker, mount as mount_marquee_ticker } from \"./marquee-ticker\";\nimport { markup as markup_rule_sweep_list, mount as mount_rule_sweep_list } from \"./rule-sweep-list\";\n\nconst SLOTS = [\n  { slot: \"hero\", element: \"letter-pop-intro\", opts: {\"text\":\"$headline\",\"color\":\"$fg\",\"delay\":70} },\n  { slot: \"band\", element: \"marquee-ticker\", opts: {\"text\":\"Brand • Motion • Web •\",\"color\":\"$ac\",\"speed\":70} },\n  { slot: \"body\", element: \"rule-sweep-list\", opts: {\"items\":\"Selected work, Studio, Journal, Contact\",\"color\":\"$fg\",\"line\":\"$ac\"} },\n];\nconst REGISTRY: Record<string, { markup: string; mount: (root: HTMLElement, o: object) => { destroy: () => void } }> = {\n  \"letter-pop-intro\": { markup: markup_letter_pop_intro, mount: mount_letter_pop_intro },\n  \"marquee-ticker\": { markup: markup_marquee_ticker, mount: mount_marquee_ticker },\n  \"rule-sweep-list\": { markup: markup_rule_sweep_list, mount: mount_rule_sweep_list },\n};\n\n// Replace $headline, $fg, $ac and the like with your values and the palette before mounting.\nexport default function StudioPortfolioHero({ values }: { values: Record<string, string> }) {\n  const stage = useRef<HTMLDivElement>(null);\n  useEffect(() => {\n    const live: { destroy: () => void }[] = [];\n    stage.current?.querySelectorAll(\"[data-slot]\").forEach((host) => {\n      const s = SLOTS.find((x) => x.slot === host.getAttribute(\"data-slot\"));\n      if (!s) return;\n      const opts = Object.fromEntries(Object.entries(s.opts).map(([k, v]) => [k, typeof v === \"string\" ? v.replace(/\\$(\\w+)/g, (m, key) => values[key] ?? m) : v]));\n      host.innerHTML = REGISTRY[s.element].markup;\n      live.push(REGISTRY[s.element].mount(host as HTMLElement, opts));\n    });\n    return () => live.forEach((i) => i.destroy());\n  }, [JSON.stringify(values)]);\n  return (\n    <div ref={stage} style={{ background: values.bg, color: values.fg, position: \"relative\", overflow: \"hidden\" }}>\n      <div data-slot=\"hero\" />\n      <div data-slot=\"band\" />\n      <div data-slot=\"body\" />\n    </div>\n  );\n}\n```\n\nRemove the \"use client\" line if it is not needed. Show it on the home page. Keep the behaviour of the source unchanged. Do not add dependencies. Respect prefers-reduced-motion. Keep text as real HTML.\n\nSettings:\n{{SETTINGS}}\n\nSource:\n{{CODE}}",
    "bolt": "Create a small Vite project (vanilla JavaScript, no framework unless I already have one) that shows the \"Studio portfolio hero\" template (first screen).\n\nThis is the \"Studio portfolio hero\" template (first screen) from the Enrichr Library: A bold intro for a design studio or freelancer: popping title, running ticker and an indexed work list.\nPage: https://enrichr.dev/templates/studio-portfolio-hero.html\nMachine-readable spec: https://enrichr.dev/templates/studio-portfolio-hero.json\n\nTemplate contract: this is a composition of Enrichr elements. Each element follows mount(root, opts):\n- root is an empty container; set root.innerHTML to the element's markup, then call mount(root, opts). It returns { update(partialOpts), destroy() }.\n- The slots below say which container gets which element. Colour tokens: --lt-bg (background), --lt-fg (text), --lt-ac (accent), set on the stage from the palette.\n- slot \"hero\": Letter pop intro (https://enrichr.dev/elements/letter-pop-intro.json)\n- slot \"band\": Marquee ticker (https://enrichr.dev/elements/marquee-ticker.json)\n- slot \"body\": Rule sweep list (https://enrichr.dev/elements/rule-sweep-list.json)\n\nFiles: index.html (a container element, then a script tag), style.css (the CSS below), studio-portfolio-hero.js (the JavaScript below) and main.js that sets the container's innerHTML to the markup and calls mount(container, opts) with the settings below. Keep the behaviour of the source unchanged. Do not add dependencies. Respect prefers-reduced-motion. Keep text as real HTML.\n\nSettings:\n{{SETTINGS}}\n\nSource:\n{{CODE}}\n\nVerify: with reduced motion on, nothing moves; it works at 375px wide and with touch only; there are no console errors; scrolling stays smooth; destroy() is called when it unmounts.",
    "replit": "Create a new HTML, CSS and JavaScript Repl that shows the \"Studio portfolio hero\" template (first screen). No packages, no server code.\n\nThis is the \"Studio portfolio hero\" template (first screen) from the Enrichr Library: A bold intro for a design studio or freelancer: popping title, running ticker and an indexed work list.\nPage: https://enrichr.dev/templates/studio-portfolio-hero.html\nMachine-readable spec: https://enrichr.dev/templates/studio-portfolio-hero.json\n\nTemplate contract: this is a composition of Enrichr elements. Each element follows mount(root, opts):\n- root is an empty container; set root.innerHTML to the element's markup, then call mount(root, opts). It returns { update(partialOpts), destroy() }.\n- The slots below say which container gets which element. Colour tokens: --lt-bg (background), --lt-fg (text), --lt-ac (accent), set on the stage from the palette.\n- slot \"hero\": Letter pop intro (https://enrichr.dev/elements/letter-pop-intro.json)\n- slot \"band\": Marquee ticker (https://enrichr.dev/elements/marquee-ticker.json)\n- slot \"body\": Rule sweep list (https://enrichr.dev/elements/rule-sweep-list.json)\n\nFiles: index.html (a container element, link style.css, load studio-portfolio-hero.js and then main.js), style.css (the CSS below), studio-portfolio-hero.js (the JavaScript below), main.js (sets the container's innerHTML to the markup, then calls mount(container, opts) with the settings below). Press Run to preview. Keep the behaviour of the source unchanged. Do not add dependencies. Respect prefers-reduced-motion. Keep text as real HTML.\n\nSettings:\n{{SETTINGS}}\n\nSource:\n{{CODE}}",
    "figma": "Designer handoff notes for the \"Studio portfolio hero\" template (first screen) (Enrichr Library). Figma cannot run this JavaScript inside a design file, so use it as a motion reference and hand the code to a developer.\n\nThis is the \"Studio portfolio hero\" template (first screen) from the Enrichr Library: A bold intro for a design studio or freelancer: popping title, running ticker and an indexed work list.\nPage: https://enrichr.dev/templates/studio-portfolio-hero.html\nMachine-readable spec: https://enrichr.dev/templates/studio-portfolio-hero.json\n\nWhat it does: A bold intro for a design studio or freelancer: popping title, running ticker and an indexed work list.\n\nTunable settings:\n- Headline: text, default Studio North\n\nCurrent settings:\n{{SETTINGS}}\n\nFor the developer: Template contract: this is a composition of Enrichr elements. Each element follows mount(root, opts):\n- root is an empty container; set root.innerHTML to the element's markup, then call mount(root, opts). It returns { update(partialOpts), destroy() }.\n- The slots below say which container gets which element. Colour tokens: --lt-bg (background), --lt-fg (text), --lt-ac (accent), set on the stage from the palette.\n- slot \"hero\": Letter pop intro (https://enrichr.dev/elements/letter-pop-intro.json)\n- slot \"band\": Marquee ticker (https://enrichr.dev/elements/marquee-ticker.json)\n- slot \"body\": Rule sweep list (https://enrichr.dev/elements/rule-sweep-list.json)\n\nIn Figma:\n- Draw the resting state as a frame and the end state as a second frame; link them with Smart Animate to show the motion in a prototype.\n- Put the settings above in the frame's notes or Dev Mode annotations so the developer matches them.\n- Link https://enrichr.dev/templates/studio-portfolio-hero.html in the handoff: the live demo and the copy-ready code are there. Developers can paste the prompts for Claude, Cursor or v0 from the Export menu.\nNothing is copied from another designer's file; this is original code from Enrichr.",
    "framer": "Add the \"Studio portfolio hero\" template (first screen) to Framer as a code component. Framer code components are React, so wrap the vanilla code like this. Check it in the Framer editor, as Framer's component API can change.\n\nThis is the \"Studio portfolio hero\" template (first screen) from the Enrichr Library: A bold intro for a design studio or freelancer: popping title, running ticker and an indexed work list.\nPage: https://enrichr.dev/templates/studio-portfolio-hero.html\nMachine-readable spec: https://enrichr.dev/templates/studio-portfolio-hero.json\n\nTemplate contract: this is a composition of Enrichr elements. Each element follows mount(root, opts):\n- root is an empty container; set root.innerHTML to the element's markup, then call mount(root, opts). It returns { update(partialOpts), destroy() }.\n- The slots below say which container gets which element. Colour tokens: --lt-bg (background), --lt-fg (text), --lt-ac (accent), set on the stage from the palette.\n- slot \"hero\": Letter pop intro (https://enrichr.dev/elements/letter-pop-intro.json)\n- slot \"band\": Marquee ticker (https://enrichr.dev/elements/marquee-ticker.json)\n- slot \"body\": Rule sweep list (https://enrichr.dev/elements/rule-sweep-list.json)\n\n1. In Framer: Assets > Code > New component. Name it StudioPortfolioHero.\n2. Paste the JavaScript below into a separate code file named studio-portfolio-hero.js in the same project, with  export { mount };  and  export const markup = \"<the markup string>\";  added. Put the CSS into the component as a <style> tag.\n3. Component:\n```tsx\nimport { addPropertyControls, ControlType } from \"framer\"\nimport { useEffect, useRef } from \"react\";\nimport { markup as markup_letter_pop_intro, mount as mount_letter_pop_intro } from \"./letter-pop-intro\";\nimport { markup as markup_marquee_ticker, mount as mount_marquee_ticker } from \"./marquee-ticker\";\nimport { markup as markup_rule_sweep_list, mount as mount_rule_sweep_list } from \"./rule-sweep-list\";\n\nconst SLOTS = [\n  { slot: \"hero\", element: \"letter-pop-intro\", opts: {\"text\":\"$headline\",\"color\":\"$fg\",\"delay\":70} },\n  { slot: \"band\", element: \"marquee-ticker\", opts: {\"text\":\"Brand • Motion • Web •\",\"color\":\"$ac\",\"speed\":70} },\n  { slot: \"body\", element: \"rule-sweep-list\", opts: {\"items\":\"Selected work, Studio, Journal, Contact\",\"color\":\"$fg\",\"line\":\"$ac\"} },\n];\nconst REGISTRY: Record<string, { markup: string; mount: (root: HTMLElement, o: object) => { destroy: () => void } }> = {\n  \"letter-pop-intro\": { markup: markup_letter_pop_intro, mount: mount_letter_pop_intro },\n  \"marquee-ticker\": { markup: markup_marquee_ticker, mount: mount_marquee_ticker },\n  \"rule-sweep-list\": { markup: markup_rule_sweep_list, mount: mount_rule_sweep_list },\n};\n\n// Replace $headline, $fg, $ac and the like with your values and the palette before mounting.\nexport default function StudioPortfolioHero({ values }: { values: Record<string, string> }) {\n  const stage = useRef<HTMLDivElement>(null);\n  useEffect(() => {\n    const live: { destroy: () => void }[] = [];\n    stage.current?.querySelectorAll(\"[data-slot]\").forEach((host) => {\n      const s = SLOTS.find((x) => x.slot === host.getAttribute(\"data-slot\"));\n      if (!s) return;\n      const opts = Object.fromEntries(Object.entries(s.opts).map(([k, v]) => [k, typeof v === \"string\" ? v.replace(/\\$(\\w+)/g, (m, key) => values[key] ?? m) : v]));\n      host.innerHTML = REGISTRY[s.element].markup;\n      live.push(REGISTRY[s.element].mount(host as HTMLElement, opts));\n    });\n    return () => live.forEach((i) => i.destroy());\n  }, [JSON.stringify(values)]);\n  return (\n    <div ref={stage} style={{ background: values.bg, color: values.fg, position: \"relative\", overflow: \"hidden\" }}>\n      <div data-slot=\"hero\" />\n      <div data-slot=\"band\" />\n      <div data-slot=\"body\" />\n    </div>\n  );\n}\n\n// Template: expose headline and palette colours as property controls the same way.\n```\n4. Keep the behaviour of the source unchanged. Do not add dependencies. Respect prefers-reduced-motion. Keep text as real HTML.\n\nSettings:\n{{SETTINGS}}\n\nSource:\n{{CODE}}",
    "webflow": "Add the \"Studio portfolio hero\" template (first screen) to a Webflow site with an Embed element. Test it on the published or preview site: scripts in embeds may not run inside the Designer canvas.\n\nThis is the \"Studio portfolio hero\" template (first screen) from the Enrichr Library: A bold intro for a design studio or freelancer: popping title, running ticker and an indexed work list.\nPage: https://enrichr.dev/templates/studio-portfolio-hero.html\nMachine-readable spec: https://enrichr.dev/templates/studio-portfolio-hero.json\n\nTemplate contract: this is a composition of Enrichr elements. Each element follows mount(root, opts):\n- root is an empty container; set root.innerHTML to the element's markup, then call mount(root, opts). It returns { update(partialOpts), destroy() }.\n- The slots below say which container gets which element. Colour tokens: --lt-bg (background), --lt-fg (text), --lt-ac (accent), set on the stage from the palette.\n- slot \"hero\": Letter pop intro (https://enrichr.dev/elements/letter-pop-intro.json)\n- slot \"band\": Marquee ticker (https://enrichr.dev/elements/marquee-ticker.json)\n- slot \"body\": Rule sweep list (https://enrichr.dev/elements/rule-sweep-list.json)\n\n1. Add an Embed element where it should appear. Paste a <style> block with the CSS, one container <div id=\"enrichr-studio-portfolio-hero\"></div>, and a <script> block with the JavaScript followed by:\n   mount(document.getElementById(\"enrichr-studio-portfolio-hero\"), { ...your settings... });\n   (set the container's innerHTML to the markup first, as in the contract).\n2. Embed elements have a size limit (check Webflow's current number). If the code is longer, host the JS and CSS as files and link them from Custom code in the page settings, then keep only the container and the mount call in the Embed.\n3. Keep the behaviour of the source unchanged. Do not add dependencies. Respect prefers-reduced-motion. Keep text as real HTML.\n\nSettings:\n{{SETTINGS}}\n\nSource:\n{{CODE}}"
  },
  "exportTools": [
    "claude",
    "chatgpt",
    "cursor",
    "v0",
    "lovable",
    "bolt",
    "replit",
    "figma",
    "framer",
    "webflow"
  ],
  "palette": "ink",
  "palettes": {
    "forest": {
      "label": "Forest",
      "bg": "#10261f",
      "fg": "#f2f6f0",
      "ac": "#c6f26b",
      "ac2": "#2f7d5b"
    },
    "ink": {
      "label": "Ink",
      "bg": "#0b0b10",
      "fg": "#f4f1ea",
      "ac": "#ff5a36",
      "ac2": "#6a5cff"
    },
    "paper": {
      "label": "Paper",
      "bg": "#f3efe6",
      "fg": "#16140f",
      "ac": "#d6361f",
      "ac2": "#1f4fd6"
    }
  },
  "slots": [
    {
      "slot": "hero",
      "element": "letter-pop-intro",
      "opts": {
        "text": "$headline",
        "color": "$fg",
        "delay": 70
      },
      "spec": "https://enrichr.dev/elements/letter-pop-intro.json"
    },
    {
      "slot": "band",
      "element": "marquee-ticker",
      "opts": {
        "text": "Brand • Motion • Web •",
        "color": "$ac",
        "speed": 70
      },
      "spec": "https://enrichr.dev/elements/marquee-ticker.json"
    },
    {
      "slot": "body",
      "element": "rule-sweep-list",
      "opts": {
        "items": "Selected work, Studio, Journal, Contact",
        "color": "$fg",
        "line": "$ac"
      },
      "spec": "https://enrichr.dev/elements/rule-sweep-list.json"
    }
  ]
}