> ## Documentation Index
> Fetch the complete documentation index at: https://docs.replit.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Canvas

> Agent와 함께 Canvas를 사용하여 디자인을 탐색하고 반복하며, 아티팩트가 프레임에 표시되는 방법을 알아보세요.

export const YouTubeEmbed = ({videoId, title = "YouTube video", startAt}) => {
  if (!videoId) {
    return null;
  }
  let url = "https://www.youtube.com/embed/" + videoId;
  if (startAt) {
    url = url + "?start=" + startAt;
  }
  return <Frame>
      <iframe src={url} title={title} allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowFullScreen></iframe>
    </Frame>;
};

export const AgentCarousel = ({correctChoice = ""}) => {
  const outputTypes = [{
    name: "Web",
    iconSvg: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M12 1.25c5.937 0 10.75 4.813 10.75 10.75S17.937 22.75 12 22.75 1.25 17.937 1.25 12 6.063 1.25 12 1.25Zm-9.217 11.5a9.25 9.25 0 0 0 7.468 8.333 15.25 15.25 0 0 1-2.982-8.333H2.783Zm13.948 0a15.249 15.249 0 0 1-2.983 8.333 9.25 9.25 0 0 0 7.469-8.333H16.73Zm-7.958 0A13.748 13.748 0 0 0 12 20.876a13.748 13.748 0 0 0 3.227-8.126H8.773Zm1.478-9.834a9.251 9.251 0 0 0-7.468 8.334H7.27a15.251 15.251 0 0 1 2.982-8.334ZM12 3.123a13.747 13.747 0 0 0-3.227 8.127h6.454A13.748 13.748 0 0 0 12 3.123Zm1.748-.207a15.25 15.25 0 0 1 2.983 8.334h4.486a9.251 9.251 0 0 0-7.469-8.334Z" clip-rule="evenodd" /></svg>'
  }, {
    name: "Mobile",
    iconSvg: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M7 2.75c-.69 0-1.25.56-1.25 1.25v16c0 .69.56 1.25 1.25 1.25h10c.69 0 1.25-.56 1.25-1.25V4c0-.69-.56-1.25-1.25-1.25H7ZM4.25 4A2.75 2.75 0 0 1 7 1.25h10A2.75 2.75 0 0 1 19.75 4v16A2.75 2.75 0 0 1 17 22.75H7A2.75 2.75 0 0 1 4.25 20V4Zm7 14a.75.75 0 0 1 .75-.75h.01a.75.75 0 0 1 0 1.5H12a.75.75 0 0 1-.75-.75Z" clip-rule="evenodd" /></svg>'
  }, {
    name: "Slides",
    iconSvg: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M20 2.25A2.75 2.75 0 0 1 22.75 5v14A2.75 2.75 0 0 1 20 21.75h-8A2.75 2.75 0 0 1 9.25 19V5A2.75 2.75 0 0 1 12 2.25h8Zm-8 1.5c-.69 0-1.25.56-1.25 1.25v14c0 .69.56 1.25 1.25 1.25h8c.69 0 1.25-.56 1.25-1.25V5c0-.69-.56-1.25-1.25-1.25h-8Z" clip-rule="evenodd" /><path d="M6 4.25a.75.75 0 0 1 .75.75v14a.75.75 0 0 1-1.5 0V5A.75.75 0 0 1 6 4.25ZM2 6.25a.75.75 0 0 1 .75.75v10a.75.75 0 0 1-1.5 0V7A.75.75 0 0 1 2 6.25Z" /></svg>'
  }, {
    name: "Animation",
    iconSvg: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M10.024 7.25c.31.004.613.091.878.251l4.996 2.996a1.752 1.752 0 0 1 .625 2.367 1.75 1.75 0 0 1-.625.639v-.001l-4.995 2.995.001.001a1.75 1.75 0 0 1-2.654-1.505v-5.99a1.75 1.75 0 0 1 1.774-1.753Zm-.02 1.5a.252.252 0 0 0-.22.124.253.253 0 0 0-.034.127v5.998a.252.252 0 0 0 .127.219.253.253 0 0 0 .252-.004l.002-.001 4.997-2.997.002-.001a.252.252 0 0 0 .122-.215.25.25 0 0 0-.122-.215h-.002L10.13 8.786h-.002a.25.25 0 0 0-.125-.037Z" clip-rule="evenodd" /><path fill-rule="evenodd" d="M12 1.25c5.937 0 10.75 4.813 10.75 10.75S17.937 22.75 12 22.75 1.25 17.937 1.25 12 6.063 1.25 12 1.25Zm0 1.5a9.25 9.25 0 1 0 0 18.5 9.25 9.25 0 0 0 0-18.5Z" clip-rule="evenodd" /></svg>'
  }, {
    name: "Design",
    iconSvg: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M6.5 11.25a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5ZM17.5 9.25a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5ZM8.5 6.25a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5ZM13.5 5.25a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5Z" /><path fill-rule="evenodd" d="M12 1.25c2.827 0 5.553 1.01 7.573 2.828C21.596 5.9 22.75 8.388 22.75 11A5.749 5.749 0 0 1 17 16.75h-2.25a1 1 0 0 0-.8 1.6l.3.4.1.143a2.5 2.5 0 0 1-2.1 3.857H12a10.75 10.75 0 1 1 0-21.5Zm0 1.5a9.25 9.25 0 1 0 0 18.5h.25a1 1 0 0 0 .8-1.6l-.3-.4a2.5 2.5 0 0 1 2-4H17l.21-.005A4.25 4.25 0 0 0 21.25 11c0-2.161-.953-4.252-2.68-5.807C16.84 3.636 14.476 2.75 12 2.75Z" clip-rule="evenodd" /></svg>'
  }, {
    name: "Data Visualization",
    iconSvg: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M5 14.25a.75.75 0 0 1 .75.75v6a.75.75 0 0 1-1.5 0v-6a.75.75 0 0 1 .75-.75ZM12 8.25a.75.75 0 0 1 .75.75v12a.75.75 0 0 1-1.5 0V9a.75.75 0 0 1 .75-.75ZM19 2.25a.75.75 0 0 1 .75.75v18a.75.75 0 0 1-1.5 0V3a.75.75 0 0 1 .75-.75Z" /></svg>'
  }, {
    name: "Automation",
    iconSvg: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M13.376 1.253c.21-.02.422.012.616.096l.095.046.091.053c.178.115.323.274.423.46l.045.096.038.099a1.25 1.25 0 0 1 .01.755l-1.92 6.02c-.003.011-.007.023-.012.034a.253.253 0 0 0 .03.23.25.25 0 0 0 .206.108H20l.123.004a1.752 1.752 0 0 1 1.24 2.849.73.73 0 0 1-.045.05l-9.9 10.199v-.001a1.25 1.25 0 0 1-2.122-1.18l.01-.03 1.92-6.019.012-.035a.251.251 0 0 0-.12-.309.255.255 0 0 0-.056-.02l-.06-.008H4a1.752 1.752 0 0 1-1.363-2.852l.045-.05 9.9-10.2a1.25 1.25 0 0 1 .689-.38l.104-.015Zm-9.582 11.6a.252.252 0 0 0-.023.255.25.25 0 0 0 .227.142h7.001l.21.013a1.75 1.75 0 0 1 1.53 1.518c.034.269.003.54-.086.795l.002.001-1.591 4.986 9.14-9.418a.249.249 0 0 0 .047-.116.252.252 0 0 0-.115-.24.249.249 0 0 0-.064-.03l-.07-.009H13a1.753 1.753 0 0 1-1.74-1.531 1.752 1.752 0 0 1 .086-.797l1.588-4.985-9.14 9.417Z" clip-rule="evenodd" /></svg>'
  }, {
    name: "3D Game",
    iconSvg: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M11.25 9.675A3.751 3.751 0 0 1 12 2.25a3.75 3.75 0 0 1 .75 7.425v4.575H19A2.75 2.75 0 0 1 21.75 17v2A2.75 2.75 0 0 1 19 21.75H5A2.75 2.75 0 0 1 2.25 19v-2A2.75 2.75 0 0 1 5 14.25h.25V13a.75.75 0 0 1 1.5 0v1.25h4.5V9.675ZM9.75 6a2.25 2.25 0 1 0 4.5 0 2.25 2.25 0 0 0-4.5 0ZM4.116 16.116A1.25 1.25 0 0 1 5 15.75h14A1.25 1.25 0 0 1 20.25 17v2A1.25 1.25 0 0 1 19 20.25H5a1.25 1.25 0 0 1-1.244-1.126L3.75 19v-2c0-.331.132-.65.366-.884Z" clip-rule="evenodd" /></svg>'
  }, {
    name: "Document",
    iconSvg: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M11.88 11.251a2.873 2.873 0 0 1 2.028 4.904L8.89 21.168a2.75 2.75 0 0 1-1.174.694l-2.867.838a1.255 1.255 0 0 1-1.234-.316 1.251 1.251 0 0 1-.316-1.235l.836-2.868c.13-.443.37-.847.696-1.174l5.017-5.015a2.875 2.875 0 0 1 2.032-.841Zm-.001 1.5c-.319 0-.626.11-.87.31l-.1.091L5.89 18.17a1.251 1.251 0 0 0-.315.532l-.709 2.43 2.43-.708a1.25 1.25 0 0 0 .533-.317l5.019-5.012a1.372 1.372 0 0 0-.97-2.343Z" clip-rule="evenodd" /><path fill-rule="evenodd" d="M14.038 1.251a3.148 3.148 0 0 1 2.198.925l3.587 3.587A3.152 3.152 0 0 1 20.75 8v12A2.75 2.75 0 0 1 18 22.75h-5.341a.75.75 0 0 1 0-1.5h5.34A1.25 1.25 0 0 0 19.25 20V8.75H15A1.75 1.75 0 0 1 13.25 7V2.75H6A1.25 1.25 0 0 0 4.75 4v9.34a.75.75 0 1 1-1.5 0V4A2.75 2.75 0 0 1 6 1.25h8l.039.001ZM14.75 7a.25.25 0 0 0 .25.25h4.071a1.65 1.65 0 0 0-.306-.425l-3.59-3.59a1.655 1.655 0 0 0-.425-.307V7Z" clip-rule="evenodd" /></svg>'
  }, {
    name: "Spreadsheet",
    iconSvg: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M21.75 6A3.75 3.75 0 0 0 18 2.25H6A3.75 3.75 0 0 0 2.25 6v12A3.75 3.75 0 0 0 6 21.75h12A3.75 3.75 0 0 0 21.75 18V6ZM18 3.75A2.25 2.25 0 0 1 20.25 6v2.25H9.75v-4.5H18Zm-9.75 0v4.5h-4.5V6A2.25 2.25 0 0 1 6 3.75h2.25Zm-4.5 6h4.5v4.5h-4.5v-4.5Zm0 6h4.5v4.5H6A2.25 2.25 0 0 1 3.75 18v-2.25Zm6 4.5v-4.5h10.5V18A2.25 2.25 0 0 1 18 20.25H9.75Zm10.5-6H9.75v-4.5h10.5v4.5Z" clip-rule="evenodd" /></svg>'
  }];
  const ITEMS_PER_PAGE = 5;
  const ITEM_WIDTH = 96;
  const VISIBLE_WIDTH = ITEMS_PER_PAGE * ITEM_WIDTH;
  const trackId = "ac-carousel-track";
  const checkSvg = '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M20.53 5.47a.75.75 0 0 1 0 1.06l-11 11a.75.75 0 0 1-1.06 0l-5-5a.75.75 0 1 1 1.06-1.06L9 15.94 19.47 5.47a.75.75 0 0 1 1.06 0Z" clip-rule="evenodd" /></svg>';
  const updateHint = selectedName => {
    const hintEl = document.getElementById("ac-carousel-hint");
    if (!hintEl || !correctChoice) return;
    if (!selectedName) {
      hintEl.innerHTML = "";
      return;
    }
    if (selectedName === correctChoice) {
      hintEl.innerHTML = `<span class="ac-hint ac-hint-correct"><svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" style="vertical-align:-2px;margin-right:4px"><path fill-rule="evenodd" d="M20.53 5.47a.75.75 0 0 1 0 1.06l-11 11a.75.75 0 0 1-1.06 0l-5-5a.75.75 0 1 1 1.06-1.06L9 15.94 19.47 5.47a.75.75 0 0 1 1.06 0Z" clip-rule="evenodd" /></svg>Great choice!</span>`;
    } else {
      hintEl.innerHTML = `<span class="ac-hint ac-hint-nudge">You can build anything you want! For this quickstart, try selecting <strong>${correctChoice}</strong>.</span>`;
    }
  };
  const toggleOutputType = name => {
    const btn = document.querySelector(`.agent-carousel-wrap [data-option-name="${name}"]`);
    const pillsContainer = document.getElementById("agent-input-pills");
    if (!btn) return;
    const isSelected = btn.dataset.selected === "true";
    const type = outputTypes.find(t => t.name === name);
    if (isSelected) {
      btn.dataset.selected = "false";
      btn.style.background = "var(--ai-option-bg)";
      const iconEl = btn.querySelector(".option-icon");
      if (iconEl && type) iconEl.innerHTML = type.iconSvg;
      if (pillsContainer) {
        const pill = document.getElementById(`pill-${name}`);
        if (pill) pill.remove();
      }
      updateHint(null);
    } else {
      document.querySelectorAll('[data-option-name][data-selected="true"]').forEach(prevBtn => {
        const prevName = prevBtn.dataset.optionName;
        prevBtn.dataset.selected = "false";
        prevBtn.style.background = "var(--ai-option-bg)";
        const prevIconEl = prevBtn.querySelector(".option-icon");
        const prevType = outputTypes.find(t => t.name === prevName);
        if (prevIconEl && prevType) prevIconEl.innerHTML = prevType.iconSvg;
        if (pillsContainer) {
          const prevPill = document.getElementById(`pill-${prevName}`);
          if (prevPill) prevPill.remove();
        }
      });
      btn.dataset.selected = "true";
      btn.style.background = "var(--ai-option-selected-bg)";
      const iconEl = btn.querySelector(".option-icon");
      if (iconEl) iconEl.innerHTML = checkSvg;
      if (pillsContainer && type) {
        const pill = document.createElement("span");
        pill.id = `pill-${name}`;
        pill.style.cssText = "display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 8px 0 8px;border-radius:32px;background:var(--ai-pill-bg);color:var(--ai-pill-text);font-size:14px;white-space:nowrap;cursor:default;";
        pill.innerHTML = `<span style="display:flex;align-items:center"><svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor">${type.iconSvg.replace(/<svg[^>]*>/, "").replace("</svg>", "")}</svg></span><span>${name}</span><span class="ai-pill-close" style="display:flex;align-items:center;cursor:pointer;margin-left:2px" data-pill-remove="${name}"><svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M18.3 5.71a1 1 0 0 0-1.42 0L12 10.59 7.12 5.7A1 1 0 0 0 5.7 7.12L10.59 12 5.7 16.88a1 1 0 1 0 1.42 1.42L12 13.41l4.88 4.89a1 1 0 0 0 1.42-1.42L13.41 12l4.89-4.88a1 1 0 0 0 0-1.41Z"/></svg></span>`;
        pill.querySelector(`[data-pill-remove="${name}"]`).addEventListener("click", () => toggleOutputType(name));
        pillsContainer.appendChild(pill);
      }
      updateHint(name);
    }
  };
  const slideCarousel = direction => {
    const track = document.getElementById(trackId);
    if (!track) return;
    const currentPage = parseInt(track.dataset.page || "0", 10);
    const totalPages = Math.ceil(outputTypes.length / ITEMS_PER_PAGE);
    let newPage = currentPage + direction;
    if (newPage < 0) newPage = totalPages - 1;
    if (newPage >= totalPages) newPage = 0;
    track.dataset.page = String(newPage);
    track.style.transform = `translateX(-${newPage * ITEMS_PER_PAGE * ITEM_WIDTH}px)`;
  };
  if (typeof document !== "undefined" && !document.getElementById("agent-carousel-styles")) {
    const style = document.createElement("style");
    style.id = "agent-carousel-styles";
    style.textContent = `
      .agent-carousel-wrap {
        --ai-option-bg: var(--replit-docs-bg-muted, #F1F1EE);
        --ai-option-border: var(--replit-docs-border, #DEDAD5);
        --ai-option-hover-bg: var(--replit-docs-bg-elevated, #F1F1EE);
        --ai-option-selected-bg: var(--replit-docs-bg-elevated, #F1F1EE);
        --ai-text-secondary: var(--replit-docs-text-muted, #5C5C5C);
        --ai-icon-default: var(--replit-docs-text-subtle, #858585);
        --ai-icon-hover: var(--replit-docs-text-muted, #5C5C5C);
      }
      .dark .agent-carousel-wrap,
      html.dark .agent-carousel-wrap,
      [data-theme="dark"] .agent-carousel-wrap {
        --ai-option-bg: var(--replit-docs-bg-elevated, #222223);
        --ai-option-border: var(--replit-docs-border, #39393D);
        --ai-option-hover-bg: var(--replit-docs-bg-muted, #222223);
        --ai-option-selected-bg: var(--replit-docs-bg-muted, #222223);
        --ai-text-secondary: var(--replit-docs-text-muted, #B8B8BE);
        --ai-icon-default: var(--replit-docs-text-subtle, #8E8F97);
        --ai-icon-hover: var(--replit-docs-text-muted, #B8B8BE);
      }
      @keyframes agent-carousel-fade-in {
        from { transform: translateY(10px); opacity: 0; }
        to { transform: translateY(0); opacity: 1; }
      }
      .agent-carousel-wrap .ac-option-btn[data-selected="true"] {
        background: var(--ai-option-selected-bg) !important;
      }
      .agent-carousel-wrap .ac-option-btn[data-correct="true"][data-selected="true"] {
        border-color: #22c55e !important;
        background: rgba(34, 197, 94, 0.08) !important;
      }
      @keyframes ac-hint-fade-in {
        from { opacity: 0; transform: translateY(-4px); }
        to { opacity: 1; transform: translateY(0); }
      }
      .agent-carousel-wrap .ac-hint {
        text-align: center;
        font-size: 13px;
        margin-top: 12px;
        animation: ac-hint-fade-in 200ms ease-out;
      }
      .agent-carousel-wrap .ac-hint-correct {
        color: #22c55e;
      }
      .agent-carousel-wrap .ac-hint-nudge {
        color: var(--ai-text-secondary);
      }
      @media (hover: hover) {
        .agent-carousel-wrap .ac-option-btn:not([data-selected="true"]):hover {
          background: var(--ai-option-hover-bg);
        }
        .agent-carousel-wrap .ac-nav-btn:hover svg {
          color: var(--ai-icon-hover);
        }
      }
      .agent-carousel-wrap {
        overflow: hidden;
        box-sizing: border-box;
      }
    `;
    document.head.appendChild(style);
  }
  const ArrowLeftIcon = <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
      <path fillRule="evenodd" d="M4.47 11.47a.75.75 0 0 0 0 1.06l7 7a.75.75 0 1 0 1.06-1.06l-5.72-5.72H19a.75.75 0 0 0 0-1.5H6.81l5.72-5.72a.75.75 0 0 0-1.06-1.06l-7 7Z" clipRule="evenodd" />
    </svg>;
  const ArrowRightIcon = <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
      <path fillRule="evenodd" d="M19.53 11.47a.75.75 0 0 1 0 1.06l-7 7a.75.75 0 1 1-1.06-1.06l5.72-5.72H5a.75.75 0 0 1 0-1.5h12.19l-5.72-5.72a.75.75 0 0 1 1.06-1.06l7 7Z" clipRule="evenodd" />
    </svg>;
  const optionIconStyle = {
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    width: "48px",
    height: "48px",
    border: "1px solid var(--ai-option-border)",
    borderRadius: "12px",
    background: "var(--ai-option-bg)",
    cursor: "pointer",
    color: "var(--ai-text-secondary)",
    padding: 0,
    transition: "background 120ms ease-out",
    flexShrink: 0
  };
  return <div className="agent-carousel-wrap" style={{
    fontFamily: "'IBM Plex Sans', sans-serif",
    width: "100%",
    maxWidth: "734px",
    alignSelf: "center",
    margin: "48px auto",
    opacity: 0,
    animation: "agent-carousel-fade-in 300ms ease-out forwards"
  }}>
      <div style={{
    display: "flex",
    justifyContent: "center"
  }}>
        <div style={{
    display: "flex",
    alignItems: "flex-start",
    gap: "16px",
    maxWidth: "100%",
    minWidth: 0
  }}>
          <button className="ac-nav-btn" style={{
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    width: "24px",
    height: "48px",
    border: "none",
    background: "none",
    cursor: "pointer",
    color: "var(--ai-icon-default)",
    padding: 0,
    flexShrink: 0
  }} aria-label="Previous" type="button" onClick={() => slideCarousel(-1)}>
            {ArrowLeftIcon}
          </button>
          <div style={{
    display: "flex",
    overflow: "hidden",
    width: `${VISIBLE_WIDTH}px`,
    maxWidth: "calc(100vw - 140px)"
  }}>
            <div id={trackId} data-page="0" style={{
    display: "flex",
    transition: "transform 300ms ease-out",
    willChange: "transform"
  }}>
              {outputTypes.map(type => <div key={type.name} style={{
    display: "flex",
    flexDirection: "column",
    alignItems: "center",
    gap: "6px",
    width: `${ITEM_WIDTH}px`,
    flexShrink: 0
  }}>
                  <button className="ac-option-btn" data-option-name={type.name} data-correct={correctChoice && type.name === correctChoice ? "true" : undefined} style={optionIconStyle} type="button" onClick={() => toggleOutputType(type.name)}>
                    <span className="option-icon" style={{
    display: "flex",
    alignItems: "center",
    justifyContent: "center"
  }} dangerouslySetInnerHTML={{
    __html: type.iconSvg
  }} />
                  </button>
                  <span style={{
    fontSize: "12px",
    color: "var(--ai-text-secondary)",
    textAlign: "center"
  }}>
                    {type.name}
                  </span>
                </div>)}
            </div>
          </div>
          <button className="ac-nav-btn" style={{
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    width: "24px",
    height: "48px",
    border: "none",
    background: "none",
    cursor: "pointer",
    color: "var(--ai-icon-default)",
    padding: 0,
    flexShrink: 0
  }} aria-label="Next" type="button" onClick={() => slideCarousel(1)}>
            {ArrowRightIcon}
          </button>
        </div>
      </div>
      {correctChoice && <div id="ac-carousel-hint" style={{
    minHeight: "24px"
  }}></div>}
    </div>;
};

export const AgentInput = ({defaultPrompt = "", highlightPlan = false, highlightStart = false, showTypewriter = true}) => {
  const AGENT_INPUT_TYPEWRITER_SCRIPT_ID = "replit-docs-typewriter-core";
  const AGENT_INPUT_TYPEWRITER_SRC = "https://unpkg.com/typewriter-effect@2.18.2/dist/core.js";
  const AGENT_INPUT_TYPEWRITER_PROMPTS = ["Build a project tracker for my team", "Design a landing page for my coffee shop", "Add Stripe payments to my app"];
  const AGENT_INPUT_TYPING_SPEED = 40;
  const AGENT_INPUT_DELETE_SPEED = 20;
  const AGENT_INPUT_PAUSE_AFTER = 2000;
  const AGENT_INPUT_START_DELAY = 500;
  const getAgentInputTypewriterLoader = () => {
    if (typeof window === "undefined") {
      return null;
    }
    if (!window.__replitDocsAgentInputTypewriterLoader) {
      window.__replitDocsAgentInputTypewriterLoader = {};
    }
    return window.__replitDocsAgentInputTypewriterLoader;
  };
  const ensureAgentInputTypewriterCore = () => {
    if (typeof window === "undefined" || typeof document === "undefined") {
      return Promise.resolve(null);
    }
    if (window.Typewriter) {
      return Promise.resolve(window.Typewriter);
    }
    const loader = getAgentInputTypewriterLoader();
    if (loader.promise) {
      return loader.promise;
    }
    loader.promise = new Promise((resolve, reject) => {
      const handleLoad = () => {
        if (window.Typewriter) {
          resolve(window.Typewriter);
          return;
        }
        loader.promise = null;
        reject(new Error("Typewriter core loaded without a global Typewriter export."));
      };
      const handleError = () => {
        loader.promise = null;
        reject(new Error("Failed to load typewriter core."));
      };
      const existingScript = document.getElementById(AGENT_INPUT_TYPEWRITER_SCRIPT_ID);
      if (existingScript) {
        existingScript.addEventListener("load", handleLoad, {
          once: true
        });
        existingScript.addEventListener("error", handleError, {
          once: true
        });
        return;
      }
      const script = document.createElement("script");
      script.id = AGENT_INPUT_TYPEWRITER_SCRIPT_ID;
      script.src = AGENT_INPUT_TYPEWRITER_SRC;
      script.async = true;
      script.addEventListener("load", handleLoad, {
        once: true
      });
      script.addEventListener("error", handleError, {
        once: true
      });
      document.head.appendChild(script);
    });
    return loader.promise;
  };
  const getAgentInputTypewriterRegistry = () => {
    if (typeof window === "undefined") {
      return null;
    }
    if (!window.__replitDocsAgentInputTypewriters) {
      window.__replitDocsAgentInputTypewriters = new WeakMap();
    }
    return window.__replitDocsAgentInputTypewriters;
  };
  const findAgentInputContainer = node => node?.closest?.("[data-agent-input-container]") || null;
  const getAgentInputElements = container => ({
    textarea: container?.querySelector?.('[data-agent-input-role="textarea"]') || null,
    startButton: container?.querySelector?.('[data-agent-input-role="start-button"]') || null,
    pillsContainer: container?.querySelector?.('[data-agent-input-role="pills"]') || null
  });
  const getAgentInputPromptValue = container => {
    const {textarea} = getAgentInputElements(container);
    return textarea?.value?.trim() || "";
  };
  const updateAgentInputButtonState = container => {
    const {startButton} = getAgentInputElements(container);
    if (!startButton) {
      return;
    }
    const hasText = getAgentInputPromptValue(container).length > 0;
    startButton.style.opacity = hasText ? "1" : "0.4";
    startButton.style.cursor = hasText ? "pointer" : "not-allowed";
  };
  const stopAgentInputTypewriter = (textarea, {placeholder, clearDemo = false} = {}) => {
    if (typeof window === "undefined" || !textarea) {
      return;
    }
    const registry = getAgentInputTypewriterRegistry();
    const record = registry?.get(textarea);
    if (!record) {
      if (placeholder) {
        textarea.setAttribute("placeholder", placeholder);
      }
      return;
    }
    record.stopped = true;
    if (record.startTimer) {
      window.clearTimeout(record.startTimer);
    }
    if (record.writeFrame) {
      window.cancelAnimationFrame(record.writeFrame);
    }
    if (record.typewriter?.stop) {
      record.typewriter.stop();
    }
    textarea.removeEventListener("focus", record.handleFocus);
    textarea.removeEventListener("pointerdown", record.handlePointerDown);
    textarea.removeEventListener("input", record.handleInput);
    if (clearDemo && textarea.value === record.pendingValue) {
      textarea.value = "";
    }
    textarea.setAttribute("placeholder", placeholder || "");
    updateAgentInputButtonState(record.container);
    registry.delete(textarea);
  };
  const startAgentInputTypewriter = (container, {defaultPrompt, placeholder, showTypewriter}) => {
    if (typeof window === "undefined" || typeof document === "undefined" || !container) {
      return;
    }
    const {textarea} = getAgentInputElements(container);
    if (!textarea) {
      return;
    }
    if (!showTypewriter || defaultPrompt) {
      stopAgentInputTypewriter(textarea, {
        placeholder
      });
      textarea.setAttribute("placeholder", placeholder);
      updateAgentInputButtonState(container);
      return;
    }
    const registry = getAgentInputTypewriterRegistry();
    const existingRecord = registry.get(textarea);
    if (existingRecord && !existingRecord.stopped) {
      updateAgentInputButtonState(container);
      return;
    }
    textarea.setAttribute("placeholder", "");
    if (textarea.value) {
      textarea.value = "";
    }
    updateAgentInputButtonState(container);
    const record = {
      container,
      element: textarea,
      pendingValue: "",
      renderedValue: "",
      stopped: false,
      startTimer: null,
      writeFrame: null,
      typewriter: null,
      handleFocus: null,
      handlePointerDown: null,
      handleInput: null
    };
    const queueValue = nextValue => {
      record.pendingValue = nextValue;
      if (record.writeFrame) {
        return;
      }
      record.writeFrame = window.requestAnimationFrame(() => {
        record.writeFrame = null;
        if (record.stopped || registry.get(textarea) !== record || !textarea.isConnected) {
          return;
        }
        if (textarea.value !== record.pendingValue) {
          textarea.value = record.pendingValue;
        }
        updateAgentInputButtonState(container);
      });
    };
    const stopDemo = () => {
      stopAgentInputTypewriter(textarea, {
        placeholder,
        clearDemo: true
      });
    };
    record.handleFocus = stopDemo;
    record.handlePointerDown = stopDemo;
    record.handleInput = stopDemo;
    registry.set(textarea, record);
    textarea.addEventListener("focus", record.handleFocus, {
      once: true
    });
    textarea.addEventListener("pointerdown", record.handlePointerDown, {
      once: true
    });
    textarea.addEventListener("input", record.handleInput, {
      once: true
    });
    record.startTimer = window.setTimeout(() => {
      ensureAgentInputTypewriterCore().then(Typewriter => {
        if (!Typewriter || record.stopped || registry.get(textarea) !== record || !textarea.isConnected) {
          return;
        }
        const typewriter = new Typewriter(null, {
          loop: true,
          delay: AGENT_INPUT_TYPING_SPEED,
          deleteSpeed: AGENT_INPUT_DELETE_SPEED,
          cursor: "",
          skipAddStyles: true,
          wrapperClassName: "",
          cursorClassName: "",
          onCreateTextNode: character => {
            record.renderedValue += character;
            queueValue(record.renderedValue);
            return null;
          },
          onRemoveNode: () => {
            record.renderedValue = record.renderedValue.slice(0, -1);
            queueValue(record.renderedValue);
          }
        });
        AGENT_INPUT_TYPEWRITER_PROMPTS.forEach(prompt => {
          typewriter.typeString(prompt).pauseFor(AGENT_INPUT_PAUSE_AFTER).deleteAll(AGENT_INPUT_DELETE_SPEED).pauseFor(400);
        });
        record.typewriter = typewriter;
        typewriter.start();
      }).catch(() => {
        stopAgentInputTypewriter(textarea, {
          placeholder
        });
      });
    }, AGENT_INPUT_START_DELAY);
  };
  if (typeof document !== "undefined" && !window.LZString) {
    const script = document.createElement("script");
    script.src = "https://cdnjs.cloudflare.com/ajax/libs/lz-string/1.5.0/lz-string.min.js";
    document.head.appendChild(script);
  }
  const placeholder = "Describe your idea, Replit will bring it to life...";
  const outputTypes = [{
    name: "Web",
    iconSvg: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M12 1.25c5.937 0 10.75 4.813 10.75 10.75S17.937 22.75 12 22.75 1.25 17.937 1.25 12 6.063 1.25 12 1.25Zm-9.217 11.5a9.25 9.25 0 0 0 7.468 8.333 15.25 15.25 0 0 1-2.982-8.333H2.783Zm13.948 0a15.249 15.249 0 0 1-2.983 8.333 9.25 9.25 0 0 0 7.469-8.333H16.73Zm-7.958 0A13.748 13.748 0 0 0 12 20.876a13.748 13.748 0 0 0 3.227-8.126H8.773Zm1.478-9.834a9.251 9.251 0 0 0-7.468 8.334H7.27a15.251 15.251 0 0 1 2.982-8.334ZM12 3.123a13.747 13.747 0 0 0-3.227 8.127h6.454A13.748 13.748 0 0 0 12 3.123Zm1.748-.207a15.25 15.25 0 0 1 2.983 8.334h4.486a9.251 9.251 0 0 0-7.469-8.334Z" clip-rule="evenodd" /></svg>',
    icon: <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
          <path fillRule="evenodd" d="M12 1.25c5.937 0 10.75 4.813 10.75 10.75S17.937 22.75 12 22.75 1.25 17.937 1.25 12 6.063 1.25 12 1.25Zm-9.217 11.5a9.25 9.25 0 0 0 7.468 8.333 15.25 15.25 0 0 1-2.982-8.333H2.783Zm13.948 0a15.249 15.249 0 0 1-2.983 8.333 9.25 9.25 0 0 0 7.469-8.333H16.73Zm-7.958 0A13.748 13.748 0 0 0 12 20.876a13.748 13.748 0 0 0 3.227-8.126H8.773Zm1.478-9.834a9.251 9.251 0 0 0-7.468 8.334H7.27a15.251 15.251 0 0 1 2.982-8.334ZM12 3.123a13.747 13.747 0 0 0-3.227 8.127h6.454A13.748 13.748 0 0 0 12 3.123Zm1.748-.207a15.25 15.25 0 0 1 2.983 8.334h4.486a9.251 9.251 0 0 0-7.469-8.334Z" clipRule="evenodd" />
        </svg>
  }, {
    name: "Mobile",
    iconSvg: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M7 2.75c-.69 0-1.25.56-1.25 1.25v16c0 .69.56 1.25 1.25 1.25h10c.69 0 1.25-.56 1.25-1.25V4c0-.69-.56-1.25-1.25-1.25H7ZM4.25 4A2.75 2.75 0 0 1 7 1.25h10A2.75 2.75 0 0 1 19.75 4v16A2.75 2.75 0 0 1 17 22.75H7A2.75 2.75 0 0 1 4.25 20V4Zm7 14a.75.75 0 0 1 .75-.75h.01a.75.75 0 0 1 0 1.5H12a.75.75 0 0 1-.75-.75Z" clip-rule="evenodd" /></svg>',
    icon: <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
          <path fillRule="evenodd" d="M7 2.75c-.69 0-1.25.56-1.25 1.25v16c0 .69.56 1.25 1.25 1.25h10c.69 0 1.25-.56 1.25-1.25V4c0-.69-.56-1.25-1.25-1.25H7ZM4.25 4A2.75 2.75 0 0 1 7 1.25h10A2.75 2.75 0 0 1 19.75 4v16A2.75 2.75 0 0 1 17 22.75H7A2.75 2.75 0 0 1 4.25 20V4Zm7 14a.75.75 0 0 1 .75-.75h.01a.75.75 0 0 1 0 1.5H12a.75.75 0 0 1-.75-.75Z" clipRule="evenodd" />
        </svg>
  }, {
    name: "Slides",
    iconSvg: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M20 2.25A2.75 2.75 0 0 1 22.75 5v14A2.75 2.75 0 0 1 20 21.75h-8A2.75 2.75 0 0 1 9.25 19V5A2.75 2.75 0 0 1 12 2.25h8Zm-8 1.5c-.69 0-1.25.56-1.25 1.25v14c0 .69.56 1.25 1.25 1.25h8c.69 0 1.25-.56 1.25-1.25V5c0-.69-.56-1.25-1.25-1.25h-8Z" clip-rule="evenodd" /><path d="M6 4.25a.75.75 0 0 1 .75.75v14a.75.75 0 0 1-1.5 0V5A.75.75 0 0 1 6 4.25ZM2 6.25a.75.75 0 0 1 .75.75v10a.75.75 0 0 1-1.5 0V7A.75.75 0 0 1 2 6.25Z" /></svg>',
    icon: <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
          <path fillRule="evenodd" d="M20 2.25A2.75 2.75 0 0 1 22.75 5v14A2.75 2.75 0 0 1 20 21.75h-8A2.75 2.75 0 0 1 9.25 19V5A2.75 2.75 0 0 1 12 2.25h8Zm-8 1.5c-.69 0-1.25.56-1.25 1.25v14c0 .69.56 1.25 1.25 1.25h8c.69 0 1.25-.56 1.25-1.25V5c0-.69-.56-1.25-1.25-1.25h-8Z" clipRule="evenodd" />
          <path d="M6 4.25a.75.75 0 0 1 .75.75v14a.75.75 0 0 1-1.5 0V5A.75.75 0 0 1 6 4.25ZM2 6.25a.75.75 0 0 1 .75.75v10a.75.75 0 0 1-1.5 0V7A.75.75 0 0 1 2 6.25Z" />
        </svg>
  }, {
    name: "Animation",
    iconSvg: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M10.024 7.25c.31.004.613.091.878.251l4.996 2.996a1.752 1.752 0 0 1 .625 2.367 1.75 1.75 0 0 1-.625.639v-.001l-4.995 2.995.001.001a1.75 1.75 0 0 1-2.654-1.505v-5.99a1.75 1.75 0 0 1 1.774-1.753Zm-.02 1.5a.252.252 0 0 0-.22.124.253.253 0 0 0-.034.127v5.998a.252.252 0 0 0 .127.219.253.253 0 0 0 .252-.004l.002-.001 4.997-2.997.002-.001a.252.252 0 0 0 .122-.215.25.25 0 0 0-.122-.215h-.002L10.13 8.786h-.002a.25.25 0 0 0-.125-.037Z" clip-rule="evenodd" /><path fill-rule="evenodd" d="M12 1.25c5.937 0 10.75 4.813 10.75 10.75S17.937 22.75 12 22.75 1.25 17.937 1.25 12 6.063 1.25 12 1.25Zm0 1.5a9.25 9.25 0 1 0 0 18.5 9.25 9.25 0 0 0 0-18.5Z" clip-rule="evenodd" /></svg>',
    icon: <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
          <path fillRule="evenodd" d="M10.024 7.25c.31.004.613.091.878.251l4.996 2.996a1.752 1.752 0 0 1 .625 2.367 1.75 1.75 0 0 1-.625.639v-.001l-4.995 2.995.001.001a1.75 1.75 0 0 1-2.654-1.505v-5.99a1.75 1.75 0 0 1 1.774-1.753Zm-.02 1.5a.252.252 0 0 0-.22.124.253.253 0 0 0-.034.127v5.998a.252.252 0 0 0 .127.219.253.253 0 0 0 .252-.004l.002-.001 4.997-2.997.002-.001a.252.252 0 0 0 .122-.215.25.25 0 0 0-.122-.215h-.002L10.13 8.786h-.002a.25.25 0 0 0-.125-.037Z" clipRule="evenodd" />
          <path fillRule="evenodd" d="M12 1.25c5.937 0 10.75 4.813 10.75 10.75S17.937 22.75 12 22.75 1.25 17.937 1.25 12 6.063 1.25 12 1.25Zm0 1.5a9.25 9.25 0 1 0 0 18.5 9.25 9.25 0 0 0 0-18.5Z" clipRule="evenodd" />
        </svg>
  }, {
    name: "Design",
    iconSvg: '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M6.5 11.25a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5ZM17.5 9.25a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5ZM8.5 6.25a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5ZM13.5 5.25a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5Z" /><path fill-rule="evenodd" d="M12 1.25c2.827 0 5.553 1.01 7.573 2.828C21.596 5.9 22.75 8.388 22.75 11A5.749 5.749 0 0 1 17 16.75h-2.25a1 1 0 0 0-.8 1.6l.3.4.1.143a2.5 2.5 0 0 1-2.1 3.857H12a10.75 10.75 0 1 1 0-21.5Zm0 1.5a9.25 9.25 0 1 0 0 18.5h.25a1 1 0 0 0 .8-1.6l-.3-.4a2.5 2.5 0 0 1 2-4H17l.21-.005A4.25 4.25 0 0 0 21.25 11c0-2.161-.953-4.252-2.68-5.807C16.84 3.636 14.476 2.75 12 2.75Z" clip-rule="evenodd" /></svg>',
    icon: <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
          <path d="M6.5 11.25a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5ZM17.5 9.25a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5ZM8.5 6.25a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5ZM13.5 5.25a1.25 1.25 0 1 1 0 2.5 1.25 1.25 0 0 1 0-2.5Z" />
          <path fillRule="evenodd" d="M12 1.25c2.827 0 5.553 1.01 7.573 2.828C21.596 5.9 22.75 8.388 22.75 11A5.749 5.749 0 0 1 17 16.75h-2.25a1 1 0 0 0-.8 1.6l.3.4.1.143a2.5 2.5 0 0 1-2.1 3.857H12a10.75 10.75 0 1 1 0-21.5Zm0 1.5a9.25 9.25 0 1 0 0 18.5h.25a1 1 0 0 0 .8-1.6l-.3-.4a2.5 2.5 0 0 1 2-4H17l.21-.005A4.25 4.25 0 0 0 21.25 11c0-2.161-.953-4.252-2.68-5.807C16.84 3.636 14.476 2.75 12 2.75Z" clipRule="evenodd" />
        </svg>
  }];
  const checkSvg = '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path fill-rule="evenodd" d="M20.53 5.47a.75.75 0 0 1 0 1.06l-11 11a.75.75 0 0 1-1.06 0l-5-5a.75.75 0 1 1 1.06-1.06L9 15.94 19.47 5.47a.75.75 0 0 1 1.06 0Z" clip-rule="evenodd" /></svg>';
  if (typeof document !== "undefined" && !document.getElementById("agent-input-styles")) {
    const style = document.createElement("style");
    style.id = "agent-input-styles";
    style.textContent = `
      /* Theme variables - light mode */
      [data-agent-input-container] {
        --ai-surface-bg: var(--replit-docs-bg, #F6F6F4);
        --ai-surface-higher: var(--replit-docs-bg-elevated, #F1F1EE);
        --ai-border-default: var(--replit-docs-border, #DEDAD5);
        --ai-border-strong: var(--replit-docs-border-strong, #CAC4BE);
        --ai-text-secondary: var(--replit-docs-text-muted, #5C5C5C);
        --ai-text-tertiary: var(--replit-docs-text-subtle, #858585);
        --ai-text-primary: var(--replit-docs-text, #1D1D1D);
        --ai-button-bg: var(--replit-docs-bg-muted, #F1F1EE);
        --ai-button-bg-hover: var(--replit-docs-bg-elevated, #F1F1EE);
        --ai-icon-default: var(--replit-docs-text-subtle, #858585);
        --ai-icon-hover: var(--replit-docs-text-muted, #5C5C5C);
        --ai-shadow: 0 2px 6px #00000005;
        --ai-option-bg: var(--replit-docs-bg-elevated, #F1F1EE);
        --ai-option-border: var(--replit-docs-border, #DEDAD5);
        --ai-option-hover-bg: var(--replit-docs-bg-muted, #F1F1EE);
        --ai-option-selected-bg: var(--replit-docs-bg-muted, #F1F1EE);
        --ai-pill-bg: #CDDCF1;
        --ai-pill-text: var(--replit-docs-text-muted, #5C5C5C);
      }

      /* Theme variables - dark mode */
      .dark [data-agent-input-container],
      html.dark [data-agent-input-container],
      [data-theme="dark"] [data-agent-input-container] {
        --ai-surface-bg: var(--replit-docs-bg, #1E1E1F);
        --ai-surface-higher: var(--replit-docs-bg-elevated, #222223);
        --ai-border-default: var(--replit-docs-border, #39393D);
        --ai-border-strong: var(--replit-docs-border-strong, #4A4A50);
        --ai-text-secondary: var(--replit-docs-text-muted, #B8B8BE);
        --ai-text-tertiary: var(--replit-docs-text-subtle, #8E8F97);
        --ai-text-primary: var(--replit-docs-text, #F5F5F5);
        --ai-button-bg: var(--replit-docs-bg-elevated, #222223);
        --ai-button-bg-hover: var(--replit-docs-bg-muted, #222223);
        --ai-icon-default: var(--replit-docs-text-subtle, #8E8F97);
        --ai-icon-hover: var(--replit-docs-text-muted, #B8B8BE);
        --ai-shadow: 0 2px 6px #00000020;
        --ai-option-bg: var(--replit-docs-bg-elevated, #222223);
        --ai-option-border: var(--replit-docs-border, #39393D);
        --ai-option-hover-bg: var(--replit-docs-bg-muted, #222223);
        --ai-option-selected-bg: var(--replit-docs-bg-muted, #222223);
        --ai-pill-bg: #2A3A4D;
        --ai-pill-text: #D0D8E4;
      }

      .agent-input-container {
        box-sizing: border-box;
      }

      /* Entry animation */
      @keyframes agent-input-fade-in-up {
        from { transform: translateY(10px); opacity: 0; }
        to { transform: translateY(0); opacity: 1; }
      }

      /* Hover state for input box */
      [data-agent-input-container]:has([data-agent-input-role="inner"]:hover) [data-agent-input-role="inner"] {
        border-color: #85C7FF !important;
      }

      /* Focus state for input box */
      [data-agent-input-container]:has([data-agent-input-role="inner"]:focus-within) [data-agent-input-role="inner"] {
        border-color: #0079F2 !important;
      }

      /* Icon button hover */
      @media (hover: hover) {
        [data-agent-input-container] .ai-icon-btn:hover {
          background: var(--ai-button-bg-hover);
        }
        [data-agent-input-container] .ai-icon-btn:hover svg {
          color: var(--ai-icon-hover);
        }
        [data-agent-input-container] .ai-option-btn:not([data-selected="true"]):hover {
          background: var(--ai-option-hover-bg);
        }
        [data-agent-input-container] .ai-plan-btn:hover {
          background: var(--ai-button-bg-hover);
        }
        [data-agent-input-container] .ai-nav-btn:hover svg {
          color: var(--ai-icon-hover);
        }
        [data-agent-input-container] .ai-pill-close:hover {
          opacity: 0.7;
        }
      }
      @keyframes plan-border-spin {
        0% { transform: rotate(0deg); }
        100% { transform: rotate(360deg); }
      }
      [data-agent-input-container] .ai-plan-wrap {
        position: relative;
        border-radius: 32px;
        padding: 2px;
        overflow: hidden;
      }
      [data-agent-input-container] .ai-plan-wrap::before {
        content: '';
        position: absolute;
        inset: -50%;
        background: conic-gradient(
          #3b82f6, #8b5cf6, #ec4899, #f59e0b, #10b981, #3b82f6
        );
        animation: plan-border-spin 1s linear infinite;
      }
      [data-agent-input-container] .ai-plan-wrap .ai-plan-btn-highlight {
        position: relative;
        background: var(--ai-surface-higher);
        color: var(--ai-text-primary);
        font-weight: 400;
        border: none;
        border-radius: 32px;
        z-index: 1;
      }
      [data-agent-input-container] .ai-plan-wrap.ai-plan-off::before {
        animation: none;
        background: transparent;
      }
      [data-agent-input-container] .ai-plan-wrap.ai-plan-off .ai-plan-btn-highlight {
        background: var(--ai-button-bg);
        color: var(--ai-text-secondary);
      }
      /* Plan checkbox styles */
      [data-agent-input-container] .ai-plan-checkbox-label {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        height: 32px;
        padding: 0 8px;
        border-radius: var(--border-radius-6, 6px);
        background: var(--ai-button-bg);
        cursor: pointer;
        font-size: 12px;
        font-family: inherit;
        color: var(--ai-text-secondary);
        transition: background 120ms ease-out;
        user-select: none;
      }
      @media (hover: hover) {
        [data-agent-input-container] .ai-plan-checkbox-label:hover {
          background: var(--ai-button-bg-hover);
        }
      }
      [data-agent-input-container] .ai-plan-checkbox-input {
        width: 20px;
        height: 20px;
        margin: 0;
        accent-color: #0079F2;
        cursor: pointer;
      }
      [data-agent-input-container] .ai-start-wrap {
        position: relative;
        display: inline-flex;
        padding: 3px;
        border-radius: 8px;
        overflow: hidden;
      }
      [data-agent-input-container] .ai-start-wrap::before {
        content: '';
        position: absolute;
        inset: -50%;
        background: conic-gradient(
          #3b82f6, #8b5cf6, #ec4899, #f59e0b, #10b981, #3b82f6
        );
        animation: plan-border-spin 1s linear infinite;
      }
      [data-agent-input-container] .ai-start-wrap .ai-start-btn-highlight {
        position: relative;
        background: var(--ai-surface-higher);
        border: none;
        border-radius: 6px;
        z-index: 1;
      }
    `;
    document.head.appendChild(style);
  }
  const getLink = (container, promptOverride) => {
    if (typeof document === "undefined" || !window.LZString) return "";
    const prompt = promptOverride || getAgentInputPromptValue(container);
    if (!prompt) return "";
    const encoded = window.LZString.compressToEncodedURIComponent(prompt);
    const utm = "utm_source=replit-docs&utm_medium=docs&utm_campaign=docs-intro-agent-input&utm_content=homepage-prompt-box";
    return `https://replit.com/?prompt=${encoded}&referrer=replit-docs&${utm}`;
  };
  const handleStartClick = e => {
    e.preventDefault();
    const container = findAgentInputContainer(e.currentTarget);
    const link = getLink(container);
    if (link) window.open(link, "_blank");
  };
  const toggleOutputType = name => {
    const btn = document.querySelector(`[data-option-name="${name}"]`);
    const pillsContainer = document.getElementById("agent-input-pills");
    if (!btn || !pillsContainer) return;
    const isSelected = btn.dataset.selected === "true";
    if (isSelected) {
      btn.dataset.selected = "false";
      btn.style.background = "var(--ai-option-bg)";
      const iconEl = btn.querySelector(".option-icon");
      const type = outputTypes.find(t => t.name === name);
      if (iconEl && type) iconEl.innerHTML = type.iconSvg;
      const pill = document.getElementById(`pill-${name}`);
      if (pill) pill.remove();
    } else {
      document.querySelectorAll('[data-option-name][data-selected="true"]').forEach(prevBtn => {
        const prevName = prevBtn.dataset.optionName;
        prevBtn.dataset.selected = "false";
        prevBtn.style.background = "var(--ai-option-bg)";
        const prevIconEl = prevBtn.querySelector(".option-icon");
        const prevType = outputTypes.find(t => t.name === prevName);
        if (prevIconEl && prevType) prevIconEl.innerHTML = prevType.iconSvg;
        const prevPill = document.getElementById(`pill-${prevName}`);
        if (prevPill) prevPill.remove();
      });
      btn.dataset.selected = "true";
      btn.style.background = "var(--ai-option-selected-bg)";
      const iconEl = btn.querySelector(".option-icon");
      if (iconEl) iconEl.innerHTML = checkSvg;
      const type = outputTypes.find(t => t.name === name);
      if (type) {
        const pill = document.createElement("span");
        pill.id = `pill-${name}`;
        pill.style.cssText = "display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 8px 0 8px;border-radius:32px;background:var(--ai-pill-bg);color:var(--ai-pill-text);font-size:14px;white-space:nowrap;cursor:default;";
        pill.innerHTML = `<span style="display:flex;align-items:center"><svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor">${type.iconSvg.replace(/<svg[^>]*>/, "").replace("</svg>", "")}</svg></span><span>${name}</span><span class="ai-pill-close" style="display:flex;align-items:center;cursor:pointer;margin-left:2px" data-pill-remove="${name}"><svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M18.3 5.71a1 1 0 0 0-1.42 0L12 10.59 7.12 5.7A1 1 0 0 0 5.7 7.12L10.59 12 5.7 16.88a1 1 0 1 0 1.42 1.42L12 13.41l4.88 4.89a1 1 0 0 0 1.42-1.42L13.41 12l4.89-4.88a1 1 0 0 0 0-1.41Z"/></svg></span>`;
        pill.querySelector(`[data-pill-remove="${name}"]`).addEventListener("click", () => toggleOutputType(name));
        pillsContainer.appendChild(pill);
      }
    }
  };
  const PlusIcon = <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
      <path d="M12 4.25a.75.75 0 0 1 .75.75v6.25H19a.75.75 0 0 1 0 1.5h-6.25V19a.75.75 0 0 1-1.5 0v-6.25H5a.75.75 0 0 1 0-1.5h6.25V5a.75.75 0 0 1 .75-.75Z" />
    </svg>;
  const MicIcon = <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
      <path d="M19 9.25a.75.75 0 0 1 .75.75v2a7.75 7.75 0 0 1-7 7.713V22a.75.75 0 0 1-1.5 0v-2.287a7.75 7.75 0 0 1-6.99-7.328L4.25 12v-2a.75.75 0 0 1 1.5 0v2l.008.31A6.25 6.25 0 0 0 12 18.25l.31-.008a6.249 6.249 0 0 0 5.932-5.932l.008-.31v-2a.75.75 0 0 1 .75-.75Z" />
      <path fillRule="evenodd" d="M12 1.25A3.75 3.75 0 0 1 15.75 5v7a3.75 3.75 0 1 1-7.5 0V5A3.75 3.75 0 0 1 12 1.25Zm0 1.5A2.25 2.25 0 0 0 9.75 5v7a2.25 2.25 0 0 0 4.5 0V5A2.25 2.25 0 0 0 12 2.75Z" clipRule="evenodd" />
    </svg>;
  const ArrowUpIcon = <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
      <path fillRule="evenodd" d="M11.47 4.47a.75.75 0 0 1 1.06 0l7 7a.75.75 0 1 1-1.06 1.06l-5.72-5.72V19a.75.75 0 0 1-1.5 0V6.81l-5.72 5.72a.75.75 0 0 1-1.06-1.06l7-7Z" clipRule="evenodd" />
    </svg>;
  const ArrowLeftIcon = <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
      <path fillRule="evenodd" d="M4.47 11.47a.75.75 0 0 0 0 1.06l7 7a.75.75 0 1 0 1.06-1.06l-5.72-5.72H19a.75.75 0 0 0 0-1.5H6.81l5.72-5.72a.75.75 0 0 0-1.06-1.06l-7 7Z" clipRule="evenodd" />
    </svg>;
  const ArrowRightIcon = <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
      <path fillRule="evenodd" d="M19.53 11.47a.75.75 0 0 1 0 1.06l-7 7a.75.75 0 1 1-1.06-1.06l5.72-5.72H5a.75.75 0 0 1 0-1.5h12.19l-5.72-5.72a.75.75 0 0 1 1.06-1.06l7 7Z" clipRule="evenodd" />
    </svg>;
  const iconBtnStyle = {
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    width: "28px",
    height: "28px",
    border: "none",
    borderRadius: "6px",
    background: "transparent",
    cursor: "pointer",
    color: "var(--ai-icon-default)",
    padding: 0,
    transition: "background 120ms ease-out"
  };
  const optionIconStyle = {
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    width: "48px",
    height: "48px",
    border: "1px solid var(--ai-option-border)",
    borderRadius: "12px",
    background: "var(--ai-option-bg)",
    cursor: "pointer",
    color: "var(--ai-text-secondary)",
    padding: 0,
    transition: "background 120ms ease-out",
    flexShrink: 0
  };
  const initAgentInput = container => {
    if (!container) {
      return;
    }
    updateAgentInputButtonState(container);
    startAgentInputTypewriter(container, {
      defaultPrompt,
      placeholder,
      showTypewriter
    });
    const ta = container.querySelector('[data-agent-input-role="textarea"]');
    if (ta && ta.value) {
      requestAnimationFrame(() => {
        ta.style.height = "auto";
        ta.style.height = ta.scrollHeight + "px";
      });
    }
  };
  return <div ref={initAgentInput} data-agent-input-container className="agent-input-container" style={{
    fontFamily: "'IBM Plex Sans', sans-serif",
    width: "100%",
    maxWidth: "734px",
    alignSelf: "center",
    margin: "48px auto",
    opacity: 0,
    animation: "agent-input-fade-in-up 300ms ease-out forwards"
  }}>
      <div style={{
    display: "flex",
    flexDirection: "column",
    gap: "24px"
  }}>
        {}
        <div data-agent-input-role="inner" style={{
    position: "relative",
    borderRadius: "6px",
    border: "1px solid var(--ai-border-strong)",
    background: "var(--ai-surface-bg)",
    transition: "border-color 120ms ease-out",
    boxShadow: "var(--ai-shadow)"
  }}>
          {}
          <div style={{
    padding: "12px 12px 48px 12px"
  }}>
            <textarea data-agent-input-role="textarea" placeholder={placeholder} defaultValue={defaultPrompt} rows={1} onInput={e => {
    const ta = e.currentTarget;
    ta.style.height = "auto";
    ta.style.height = ta.scrollHeight + "px";
    updateAgentInputButtonState(findAgentInputContainer(ta));
  }} style={{
    display: "block",
    width: "100%",
    minHeight: "21px",
    maxHeight: "calc(14px * 1.5 * 10)",
    padding: 0,
    margin: 0,
    border: "none",
    outline: "none",
    resize: "none",
    fontSize: "14px",
    lineHeight: "1.5",
    color: "var(--ai-text-primary)",
    background: "transparent",
    fontFamily: "inherit",
    boxSizing: "border-box",
    overflowY: "auto"
  }} />
          </div>
          {}
          <div style={{
    position: "absolute",
    left: "8px",
    right: "8px",
    bottom: "8px",
    display: "flex",
    justifyContent: "space-between",
    alignItems: "center"
  }}>
            {}
            <div style={{
    display: "flex",
    alignItems: "center",
    gap: "8px",
    overflow: "hidden",
    minWidth: 0
  }}>
              <button className="ai-icon-btn" style={iconBtnStyle} aria-label="Add attachment" type="button">
                {PlusIcon}
              </button>
              <div id="agent-input-pills" data-agent-input-role="pills" style={{
    display: "flex",
    alignItems: "center",
    gap: "6px",
    overflow: "hidden"
  }}></div>
            </div>
            {}
            <div style={{
    display: "flex",
    alignItems: "center",
    gap: "8px",
    flexShrink: 0
  }}>
              {highlightPlan ? <div className="ai-plan-wrap" onClick={e => {
    const wrap = e.currentTarget;
    wrap.classList.toggle("ai-plan-off");
  }}>
                  <label className="ai-plan-btn-highlight" style={{
    display: "flex",
    alignItems: "center",
    gap: "6px",
    height: "32px",
    padding: "0 8px",
    cursor: "pointer",
    fontSize: "12px",
    fontFamily: "inherit",
    transition: "background 120ms ease-out"
  }}>
                    <input className="ai-plan-checkbox-input" type="checkbox" aria-label="Plan mode" name="Plan mode" defaultChecked />
                    <span>Plan</span>
                  </label>
                </div> : <label className="ai-plan-checkbox-label">
                  <input className="ai-plan-checkbox-input" type="checkbox" aria-label="Plan mode" name="Plan mode" />
                  <span>Plan</span>
                </label>}
              <button className="ai-icon-btn" style={iconBtnStyle} aria-label="Start voice input" type="button">
                {MicIcon}
              </button>
              {highlightStart ? <div className="ai-start-wrap">
                  <button data-agent-input-role="start-button" className="ai-icon-btn ai-start-btn-highlight" onClick={handleStartClick} type="button" aria-label="Start" style={{
    ...iconBtnStyle,
    borderRadius: "6px",
    background: "#0079F2",
    color: "#fff",
    opacity: defaultPrompt ? "1" : "0.4",
    cursor: defaultPrompt ? "pointer" : "not-allowed"
  }}>
                    {ArrowUpIcon}
                  </button>
                </div> : <button data-agent-input-role="start-button" className="ai-icon-btn" onClick={handleStartClick} type="button" aria-label="Start" style={{
    ...iconBtnStyle,
    background: "#0079F2",
    color: "#fff",
    opacity: defaultPrompt ? "1" : "0.4",
    cursor: defaultPrompt ? "pointer" : "not-allowed"
  }}>
                  {ArrowUpIcon}
                </button>}
            </div>
          </div>
        </div>
      </div>
    </div>;
};

<YouTubeEmbed videoId="Qv9cREjl9vQ" title="Replit Canvas 개요" />

## Canvas란?

Canvas는 Agent와 함께 디자인을 탐색하고 반복하는 공간입니다. 여기서 앱, 비디오, 슬라이드 같은 아티팩트가 프레임에 표시됩니다. 하나의 시각적 보드에서 Agent와 함께 목업을 만들고, 디자인 방향을 비교하고, 변경사항을 앱에 적용할 수 있습니다.

<Frame>
  <img src="https://mintcdn.com/replit/H-TDTs94BJ7lxH24/images/replitai/canvas-desktop.png?fit=max&auto=format&n=H-TDTs94BJ7lxH24&q=85&s=0df55dbeffbe8039069e990fbd3ffc07" alt="Agent 채팅과 작업 업데이트가 있는 앱 미리보기를 나란히 보여주는 Canvas" width="3452" height="2006" data-path="images/replitai/canvas-desktop.png" />
</Frame>

## Canvas의 구성 요소

Canvas는 모든 것을 시각적으로 보고 작업할 수 있는 무한한 보드입니다.

<Frame>
  <img src="https://mintcdn.com/replit/oJ1dYuTDBrvuslEj/images/replitai/canvas-mockups.png?fit=max&auto=format&n=oJ1dYuTDBrvuslEj&q=85&s=ef0f0cbde2c8685772a84dc07c10ac24" alt="다크 테마, 모바일 뷰, 세부 페이지 등 여러 디자인 목업이 나란히 배치된 Canvas" width="3452" height="1620" data-path="images/replitai/canvas-mockups.png" />
</Frame>

* **앱**: 실행 중인 앱이 Canvas에서 라이브 인터랙티브 미리보기로 나타납니다. 브라우저에서처럼 클릭하고 사용할 수 있습니다.
* **디자인 목업**: Agent가 생성하는 시각적 프로토타입. 실제 페이지처럼 보이고 느껴집니다 — 상호작용하고, 크기를 조정하고, Agent에게 수정을 요청할 수 있습니다 — 하지만 라이브 앱과 별개여서 자유롭게 실험할 수 있습니다.
* **도형과 그림**: 직사각형, 원, 별, 화살표, 하트 등. 대략적인 아이디어를 스케치하거나, 디자인에 주석을 달거나, 화면이 어떻게 연결되는지 매핑하는 데 사용하세요.
* **텍스트와 스티커 메모**: Canvas 어디에나 레이블이나 메모를 추가하여 생각을 정리하세요.
* **이미지**: Canvas에 스크린샷이나 참조 이미지를 드롭하세요. Agent가 보이는 것을 다시 만들거나 변형할 수 있습니다.
* **비디오**: 다른 콘텐츠 옆에 비디오 파일을 Canvas에 배치하세요.

### Canvas에서 디자인 시작하기

디자인을 시작하는 몇 가지 방법이 있습니다. 가장 자연스러운 것을 선택하세요.

<Steps>
  <Step title="채팅에서 Agent에게 요청하기">
    채팅 입력창에 원하는 것을 입력하면 Agent가 Canvas에 인터랙티브 프레임으로 배치합니다.

    <AgentInput defaultPrompt="캔버스에 랜딩 페이지 목업을 보여줘" showTypewriter={true} />
  </Step>

  <Step title="출력 유형 선택하기">
    원하는 출력 종류 — 웹, 모바일, 슬라이드, 디자인 등 — 를 선택할 수도 있습니다. 캐러셀을 사용하여 프롬프트를 보내기 전에 선택하세요.

    <AgentCarousel />
  </Step>

  <Step title="기존 페이지를 Canvas로 가져오기">
    이미 라이브 앱이 있나요? Agent에게 페이지를 Canvas로 가져와 재디자인하도록 요청하세요 — 예: "내 대시보드를 캔버스에 올려줘." Agent가 사본을 만들어 라이브 앱은 영향을 받지 않습니다.
  </Step>
</Steps>

## 변경하기

Canvas에 디자인이 있으면 여러 방법으로 반복할 수 있습니다.

### Agent에게 업데이트 요청하기

Canvas에서 프레임을 선택하고 아래 나타나는 입력창에 변경사항을 입력하세요. 엔터를 누르면 Agent가 요청을 받아 업데이트를 실행하고 Canvas에서 목업을 새로고침합니다.

<Frame>
  <video autoPlay muted loop playsInline style={{ width: '100%', borderRadius: '8px' }}>
    <source src="https://mintcdn.com/replit/H-TDTs94BJ7lxH24/images/replitai/canvas-update.mp4?fit=max&auto=format&n=H-TDTs94BJ7lxH24&q=85&s=39c0b6f3185e51d8119e6caa3f2fd5d2" type="video/mp4" data-path="images/replitai/canvas-update.mp4" />
  </video>
</Frame>

### 그리기 및 주석 달기

하단 도구 모음의 그리기 도구를 사용하여 Canvas에 직접 스케치하세요. 변경하고 싶은 곳을 가리키는 화살표를 그리거나, 문제 영역에 원을 그리거나, 피드백이 담긴 텍스트 메모를 추가하세요. 그런 다음 Agent에게 주석을 기반으로 변경하도록 요청하세요.

<Frame>
  <video autoPlay muted loop playsInline style={{ width: '100%', borderRadius: '8px' }}>
    <source src="https://mintcdn.com/replit/H-TDTs94BJ7lxH24/images/replitai/canvas-draw.mp4?fit=max&auto=format&n=H-TDTs94BJ7lxH24&q=85&s=042d1489c439b42d568fb40d88418bc0" type="video/mp4" data-path="images/replitai/canvas-draw.mp4" />
  </video>
</Frame>

### 다양한 기기에서 미리보기

다양한 화면 크기에서 디자인이 어떻게 보이는지 확인하세요. Agent에게 모바일, 태블릿, 또는 데스크톱 버전을 보여달라고 요청하세요:

* **모바일** — 390 × 844
* **태블릿** — 768 × 1024
* **데스크톱** — 1280 × 720

예: "이 페이지의 모바일 버전을 보여줘"라고 하면 Agent가 해당 크기로 렌더링합니다.

<Frame>
  <video autoPlay muted loop playsInline style={{ width: '100%', borderRadius: '8px' }}>
    <source src="https://mintcdn.com/replit/H-TDTs94BJ7lxH24/images/replitai/canvas-preview.mp4?fit=max&auto=format&n=H-TDTs94BJ7lxH24&q=85&s=013e4c6d0b2e991ef68fca9212c01bbb" type="video/mp4" data-path="images/replitai/canvas-preview.mp4" />
  </video>
</Frame>

### 앱에 변경사항 적용하기

디자인에 만족하면 변경사항을 메인 버전에 적용하세요. Agent가 수행된 내용의 요약을 보여주고 적용하거나 취소할 수 있는 옵션을 제공합니다.

<Frame>
  <video autoPlay muted loop playsInline style={{ width: '100%', borderRadius: '8px' }}>
    <source src="https://mintcdn.com/replit/H-TDTs94BJ7lxH24/images/replitai/canvas-apply.mp4?fit=max&auto=format&n=H-TDTs94BJ7lxH24&q=85&s=6ec69132d43f5b8fa6e4fcf2d7dac003" type="video/mp4" data-path="images/replitai/canvas-apply.mp4" />
  </video>
</Frame>

### 프레임을 PNG로 내보내기

Canvas의 모든 아티팩트 또는 디자인 프레임을 PNG 이미지로 저장할 수 있습니다. 이는 문서나 채팅에서 미리보기를 공유하거나, 더 반복하기 전에 스냅샷을 캡처하거나, 팀원에게 스크린샷을 보낼 때 유용합니다.

<Steps>
  <Step title="프레임 메뉴 열기">
    내보낼 아티팩트 또는 디자인 프레임을 우클릭합니다. 사용 가능한 작업이 있는 메뉴가 나타납니다.
  </Step>

  <Step title="Export PNG 선택">
    **Export** > **PNG**를 선택합니다. 이미지가 프레임 이름을 기반으로 한 파일명으로 컴퓨터에 다운로드됩니다.
  </Step>
</Steps>

<Frame>
  <img src="https://mintcdn.com/replit/ML4eWCPykwd8PoWM/images/replitai/canvas-export-png.png?fit=max&auto=format&n=ML4eWCPykwd8PoWM&q=85&s=78e1960f497826b6080ef4283f9c8594" alt="Export 서브메뉴가 열린 Canvas 프레임 우클릭 컨텍스트 메뉴, PNG가 내보내기 옵션으로 표시됨" width="1740" height="1160" data-path="images/replitai/canvas-export-png.png" />
</Frame>

<Note>내보낸 PNG는 Canvas에서 현재 프레임이 표시하는 것과 일치합니다. 앱이나 디자인이 아직 로딩 중이라면 내보내기 전에 완전히 렌더링될 때까지 기다리세요.</Note>

## 디자인 방향 비교하기

어떤 방향으로 갈지 확실하지 않을 때, Agent에게 여러 버전을 생성하여 나란히 비교하도록 요청하세요.

<Frame>
  <video autoPlay muted loop playsInline style={{ width: '100%', borderRadius: '8px' }}>
    <source src="https://mintcdn.com/replit/H-TDTs94BJ7lxH24/images/replitai/canvas-compare.mp4?fit=max&auto=format&n=H-TDTs94BJ7lxH24&q=85&s=b2d8eb92ea1330fc729fe1a118bea0b9" type="video/mp4" data-path="images/replitai/canvas-compare.mp4" />
  </video>
</Frame>

* **한 페이지의 여러 버전**: "이 랜딩 페이지의 다섯 가지 버전을 보여줘." Agent가 각각을 만들어 나란히 배치합니다.
* **다중 페이지 흐름**: "완전한 온보딩 흐름 디자인: 환영, 프로필 설정, 환경 설정, 확인." Agent가 각 화면을 빌드하여 순서대로 배열합니다.
* **혼합 및 매칭**: "미니멀과 볼드 스타일로 랜딩 페이지와 가격 페이지를 보여줘." Agent가 모든 조합을 만들어 전체 그림을 볼 수 있게 합니다.

## 사용자 흐름 매핑하기

Canvas에서 완전한 사용자 여정 — 가입, 온보딩, 대시보드, 설정 — 을 배치하고 모든 것이 어떻게 연결되는지 보세요.

* 각 화면을 별도의 프레임으로 배치
* Agent에게 전체 흐름 생성 요청: "내 앱의 완전한 온보딩 흐름을 그려줘"
* 화살표와 도형을 사용하여 사용자가 화면 간에 이동하는 방법 표시
* Agent에게 대략적인 스케치를 완성된 디자인으로 변환하도록 요청

## 디자인을 실제 앱으로 변환하기

디자인에 만족하고 실제로 만들고 싶을 때 두 가지 방법이 있습니다:

### 완전한 앱으로 만들기

디자인에 데이터 저장, 사용자 계정, 다른 서비스 연결 같은 실제 기능이 필요하면 Agent에게 완전한 앱으로 변환하도록 요청하세요. "이것을 실제 앱으로 만들어줘" 또는 "백엔드를 추가해줘"라고 말하세요. Agent가 실제 게시 가능한 앱으로 작동하는 데 필요한 모든 것을 빌드합니다.

<Note>
  디자인을 완전한 앱으로 변환하려면 유료 플랜이 필요합니다.
</Note>

### 특정 유형으로 변환하기

디자인 프레임을 특정 아티팩트 유형으로 변환할 수도 있습니다:

<Steps>
  <Step title="프레임 선택">
    변환할 프레임을 클릭합니다.
  </Step>

  <Step title="Agent에게 변환 요청">
    원하는 것을 Agent에게 말합니다 — 예: "이것을 웹 앱으로 변환해줘" 또는 "이것을 슬라이드로 바꿔줘."
  </Step>

  <Step title="유형 선택">
    웹 앱, 모바일 앱, 슬라이드, 데이터 시각화 등에서 선택합니다.
  </Step>
</Steps>

## 자주 묻는 질문

<Accordion title="디자인 프레임이 실행 중인 앱과 같은 건가요?">
  아닙니다. 디자인 프레임은 시각적 프로토타입입니다 — 실제처럼 보이고 느껴지지만, 그 뒤에 작동하는 백엔드나 데이터베이스가 없습니다. Canvas의 앱 미리보기는 실제 실행 중인 앱입니다.
</Accordion>

<Accordion title="라이브 앱을 망가뜨리지 않고 페이지를 재디자인할 수 있나요?">
  예. Agent에게 페이지를 Canvas로 가져오도록 요청하세요 — 예: "내 대시보드를 캔버스에 올려줘." Agent가 실험할 수 있는 사본을 만듭니다. 변경사항을 적용하기로 선택할 때까지 라이브 앱은 영향을 받지 않습니다.
</Accordion>

<Accordion title="디자인을 실제 앱으로 어떻게 변환하나요?">
  Agent에게 완전한 앱으로 만들어달라고 요청하세요("이것을 실제로 만들어줘") 또는 특정 유형으로 변환하도록 요청하세요("이것을 웹 앱으로 변환해줘"). Agent가 작동하고 게시 가능한 앱이 되는 데 필요한 모든 것을 빌드합니다.
</Accordion>

<Accordion title="웹 앱 이외의 유형으로도 변환할 수 있나요?">
  예. Canvas 프레임을 웹 앱, 모바일 앱, 슬라이드, 데이터 시각화 등으로 변환할 수 있습니다.
</Accordion>

<Accordion title="Figma나 다른 도구에서 디자인을 가져올 수 있나요?">
  예. Figma 디자인을 Replit으로 가져오는 몇 가지 방법이 있습니다:

  * **Figma에서 가져오기**: [replit.com/import](https://replit.com/import)로 이동하여 Figma 계정을 연결하고 프레임 URL을 붙여넣어 디자인을 작동하는 React 앱으로 변환합니다. 자세한 내용은 [Figma에서 앱으로 빠른 시작](/build/figma-to-app)을 참조하세요.
  * **Agent 채팅의 Figma MCP**: Agent 채팅에 Figma 링크를 직접 붙여넣고 코드 생성, 디자인 데이터 추출, 또는 디자인에서 컴포넌트 빌드를 요청합니다. [Figma MCP 통합](/references/mcp/figma) 가이드를 참조하세요.
  * **스크린샷 참조**: Canvas에 스크린샷을 드롭하고 Agent에게 그로부터 디자인을 다시 만들도록 요청합니다.
</Accordion>

<Accordion title="Canvas에 무엇을 더 놓을 수 있나요?">
  디자인 목업과 앱 미리보기 외에도, 아이디어 스케치, 디자인 주석 달기, 또는 생각 정리에 유용한 도형, 화살표, 텍스트 레이블, 스티커 메모, 이미지, 비디오를 추가할 수 있습니다.
</Accordion>

## 사용 가능 여부

Canvas는 프레임 생성, 인라인 편집, 변형 생성, 아티팩트 변환을 포함하여 모든 플랜에서 사용할 수 있습니다. 디자인을 완전한 앱으로 변환하려면 유료 플랜이 필요합니다.
